Przeglądaj źródła

fixed range requests

Tobias Hagemann 8 lat temu
rodzic
commit
8a6265658e

+ 12 - 13
main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/DavFileWithRange.java

@@ -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);

+ 0 - 50
main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/DavFileWithUnsatisfiableRange.java

@@ -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));
-		}
-	}
-
-}

+ 11 - 13
main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/FilesystemResourceFactory.java

@@ -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 {
+	}
+
 }