mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-19 19:21:27 +00:00
fixed range requests
This commit is contained in:
@@ -16,7 +16,6 @@ import java.util.Objects;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.jackrabbit.webdav.DavException;
|
||||
import org.apache.jackrabbit.webdav.DavServletResponse;
|
||||
import org.apache.jackrabbit.webdav.DavSession;
|
||||
import org.apache.jackrabbit.webdav.io.OutputContext;
|
||||
@@ -36,7 +35,7 @@ class DavFileWithRange extends DavFile {
|
||||
|
||||
private final Pair<String, String> requestRange;
|
||||
|
||||
public DavFileWithRange(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, FileLocator node, Pair<String, String> requestRange) throws DavException {
|
||||
public DavFileWithRange(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, FileLocator node, Pair<String, String> requestRange) {
|
||||
super(factory, lockManager, session, node);
|
||||
this.requestRange = Objects.requireNonNull(requestRange);
|
||||
}
|
||||
@@ -48,18 +47,18 @@ class DavFileWithRange extends DavFile {
|
||||
return;
|
||||
}
|
||||
final long contentLength = node.size();
|
||||
final Pair<Long, Long> range = getEffectiveRange(contentLength);
|
||||
if (range.getLeft() < 0 || range.getLeft() > range.getRight() || range.getRight() > contentLength) {
|
||||
outputContext.setProperty(HttpHeader.CONTENT_RANGE.asString(), "bytes */" + contentLength);
|
||||
throw new UncheckedDavException(DavServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE, "Valid Range would be in [0, " + contentLength + "]");
|
||||
}
|
||||
final Long rangeLength = range.getRight() - range.getLeft() + 1;
|
||||
outputContext.setContentLength(rangeLength);
|
||||
outputContext.setProperty(HttpHeader.CONTENT_RANGE.asString(), contentRangeResponseHeader(range.getLeft(), range.getRight(), contentLength));
|
||||
outputContext.setContentType(CONTENT_TYPE_VALUE);
|
||||
outputContext.setProperty(CONTENT_DISPOSITION_HEADER, CONTENT_DISPOSITION_VALUE);
|
||||
outputContext.setProperty(X_CONTENT_TYPE_OPTIONS_HEADER, X_CONTENT_TYPE_OPTIONS_VALUE);
|
||||
try (ReadableFile src = node.openReadable(); OutputStream out = outputContext.getOutputStream()) {
|
||||
final Pair<Long, Long> range = getEffectiveRange(contentLength);
|
||||
if (range.getLeft() < 0 || range.getLeft() > range.getRight() || range.getRight() > contentLength) {
|
||||
outputContext.setProperty(HttpHeader.CONTENT_RANGE.asString(), "bytes */" + contentLength);
|
||||
throw new UncheckedDavException(DavServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE, "Valid Range would be in [0, " + contentLength + "]");
|
||||
}
|
||||
final Long rangeLength = range.getRight() - range.getLeft() + 1;
|
||||
outputContext.setContentLength(rangeLength);
|
||||
outputContext.setProperty(HttpHeader.CONTENT_RANGE.asString(), contentRangeResponseHeader(range.getLeft(), range.getRight(), contentLength));
|
||||
outputContext.setContentType(CONTENT_TYPE_VALUE);
|
||||
outputContext.setProperty(CONTENT_DISPOSITION_HEADER, CONTENT_DISPOSITION_VALUE);
|
||||
outputContext.setProperty(X_CONTENT_TYPE_OPTIONS_HEADER, X_CONTENT_TYPE_OPTIONS_VALUE);
|
||||
src.position(range.getLeft());
|
||||
InputStream limitedIn = ByteStreams.limit(Channels.newInputStream(src), rangeLength);
|
||||
ByteStreams.copy(limitedIn, out);
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Sebastian Stenzel and others.
|
||||
* This file is licensed under the terms of the MIT license.
|
||||
* See the LICENSE.txt file for more info.
|
||||
*
|
||||
* Contributors:
|
||||
* Sebastian Stenzel - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.frontend.webdav.jackrabbitservlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.channels.Channels;
|
||||
|
||||
import org.apache.jackrabbit.webdav.DavException;
|
||||
import org.apache.jackrabbit.webdav.DavSession;
|
||||
import org.apache.jackrabbit.webdav.io.OutputContext;
|
||||
import org.apache.jackrabbit.webdav.lock.LockManager;
|
||||
import org.cryptomator.filesystem.ReadableFile;
|
||||
import org.cryptomator.filesystem.jackrabbit.FileLocator;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
/**
|
||||
* Sends the full file in reaction to an unsatisfiable range.
|
||||
*
|
||||
* @see {@link https://tools.ietf.org/html/rfc7233#section-4.2}
|
||||
*/
|
||||
class DavFileWithUnsatisfiableRange extends DavFile {
|
||||
|
||||
public DavFileWithUnsatisfiableRange(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, FileLocator node) throws DavException {
|
||||
super(factory, lockManager, session, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spool(OutputContext outputContext) throws IOException {
|
||||
outputContext.setModificationTime(node.lastModified().toEpochMilli());
|
||||
if (!outputContext.hasStream()) {
|
||||
return;
|
||||
}
|
||||
final long contentLength = node.size();
|
||||
outputContext.setContentLength(contentLength);
|
||||
outputContext.setProperty(HttpHeader.CONTENT_RANGE.asString(), "bytes */" + contentLength);
|
||||
try (ReadableFile src = node.openReadable(); OutputStream out = outputContext.getOutputStream()) {
|
||||
ByteStreams.copy(src, Channels.newChannel(out));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -85,17 +85,11 @@ class FilesystemResourceFactory implements DavResourceFactory {
|
||||
final String rangeHeader = request.getHeader(HttpHeader.RANGE.asString());
|
||||
try {
|
||||
// 206 for ranged resources:
|
||||
final Pair<String, String> parsedRange = parseRangeRequestHeader(rangeHeader);
|
||||
final Pair<String, String> parsedRange = parseSingleByteRange(rangeHeader);
|
||||
response.setStatus(DavServletResponse.SC_PARTIAL_CONTENT);
|
||||
return new DavFileWithRange(this, lockManager, session, file, parsedRange);
|
||||
} catch (DavException ex) {
|
||||
if (ex.getErrorCode() == DavServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE) {
|
||||
// 416 for unsatisfiable ranges:
|
||||
response.setStatus(DavServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
|
||||
return new DavFileWithUnsatisfiableRange(this, lockManager, session, file);
|
||||
} else {
|
||||
throw new DavException(ex.getErrorCode(), ex);
|
||||
}
|
||||
} catch (NotASingleByteRangeException ex) {
|
||||
return createFile(file, session);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,17 +102,18 @@ class FilesystemResourceFactory implements DavResourceFactory {
|
||||
* </code>
|
||||
*
|
||||
* @return Tuple of lower and upper range.
|
||||
* @throws DavException HTTP statuscode 400 for malformed requests. 416 if requested range is not supported.
|
||||
* @throws DavException HTTP statuscode 400 for malformed requests.
|
||||
* @throws NotASingleByteRangeException Indicating a range that is not supported by this server, i.e. range header should be ignored.
|
||||
*/
|
||||
private Pair<String, String> parseRangeRequestHeader(String rangeHeader) throws DavException {
|
||||
private Pair<String, String> parseSingleByteRange(String rangeHeader) throws DavException, NotASingleByteRangeException {
|
||||
assert rangeHeader != null;
|
||||
if (!rangeHeader.startsWith(RANGE_BYTE_PREFIX)) {
|
||||
throw new DavException(DavServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
|
||||
throw new NotASingleByteRangeException();
|
||||
}
|
||||
final String byteRangeSet = StringUtils.removeStartIgnoreCase(rangeHeader, RANGE_BYTE_PREFIX);
|
||||
final String[] byteRanges = StringUtils.split(byteRangeSet, RANGE_SET_SEP);
|
||||
if (byteRanges.length != 1) {
|
||||
throw new DavException(DavServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
|
||||
throw new NotASingleByteRangeException();
|
||||
}
|
||||
final String byteRange = byteRanges[0];
|
||||
final String[] bytePos = StringUtils.splitPreserveAllTokens(byteRange, RANGE_SEP);
|
||||
@@ -146,4 +141,7 @@ class FilesystemResourceFactory implements DavResourceFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private static class NotASingleByteRangeException extends Exception {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user