Просмотр исходного кода

- fixed #19 (again): vault-specific prefix is now handled by the servlet context instead of jackrabbit.
- simplified webdav locator, as workspaces and pathPrefixes are not relevant to jackrabbit any longer

Sebastian Stenzel 10 лет назад
Родитель
Сommit
432beb2a17

+ 12 - 12
main/core/src/main/java/org/cryptomator/webdav/WebDavServer.java

@@ -20,6 +20,7 @@ import org.cryptomator.webdav.jackrabbit.WebDavServlet;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.handler.ContextHandlerCollection;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
 import org.eclipse.jetty.util.component.LifeCycle;
@@ -39,7 +40,7 @@ public final class WebDavServer {
 	private static final WebDavServer INSTANCE = new WebDavServer();
 	private final Server server;
 	private final ServerConnector localConnector;
-	private final ServletContextHandler servletContext;
+	private final ContextHandlerCollection servletCollection;
 
 	public static WebDavServer getInstance() {
 		return INSTANCE;
@@ -51,10 +52,9 @@ public final class WebDavServer {
 		server = new Server(tp);
 		localConnector = new ServerConnector(server);
 		localConnector.setHost(LOCALHOST);
-		servletContext = new ServletContextHandler(ServletContextHandler.SESSIONS);
-		servletContext.setContextPath("/");
+		servletCollection = new ContextHandlerCollection();
 		server.setConnectors(new Connector[] {localConnector});
-		server.setHandler(servletContext);
+		server.setHandler(servletCollection);
 	}
 
 	public synchronized void start() {
@@ -87,22 +87,22 @@ public final class WebDavServer {
 		try {
 			final URI uri = new URI(null, null, localConnector.getHost(), localConnector.getLocalPort(), "/" + UUID.randomUUID().toString(), null, null);
 
-			final String pathPrefix = uri.getRawPath() + "/";
-			final String pathSpec = pathPrefix + "*";
-			final ServletHolder servlet = getWebDavServletHolder(workDir.toString(), pathPrefix, checkFileIntegrity, cryptor);
-			servletContext.addServlet(servlet, pathSpec);
+			final ServletContextHandler servletContext = new ServletContextHandler(servletCollection, uri.getRawPath(), ServletContextHandler.SESSIONS);
+			final ServletHolder servlet = getWebDavServletHolder(workDir.toString(), checkFileIntegrity, cryptor);
+			servletContext.addServlet(servlet, "/*");
 
-			LOG.info("{} available on http:{}", workDir, uri.getRawSchemeSpecificPart());
-			return new ServletLifeCycleAdapter(servlet, uri);
+			servletCollection.mapContexts();
+
+			LOG.debug("{} available on http:{}", workDir, uri.getRawSchemeSpecificPart());
+			return new ServletLifeCycleAdapter(servletContext, uri);
 		} catch (URISyntaxException e) {
 			throw new IllegalStateException("Invalid hard-coded URI components.", e);
 		}
 	}
 
-	private ServletHolder getWebDavServletHolder(final String workDir, final String contextPath, final boolean checkFileIntegrity, final Cryptor cryptor) {
+	private ServletHolder getWebDavServletHolder(final String workDir, final boolean checkFileIntegrity, final Cryptor cryptor) {
 		final ServletHolder result = new ServletHolder("Cryptomator-WebDAV-Servlet", new WebDavServlet(cryptor));
 		result.setInitParameter(WebDavServlet.CFG_FS_ROOT, workDir);
-		result.setInitParameter(WebDavServlet.CFG_HTTP_ROOT, contextPath);
 		result.setInitParameter(WebDavServlet.CFG_CHECK_FILE_INTEGRITY, Boolean.toString(checkFileIntegrity));
 		return result;
 	}

+ 135 - 26
main/core/src/main/java/org/cryptomator/webdav/jackrabbit/DavLocatorFactoryImpl.java

@@ -15,31 +15,59 @@ import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 
 import org.apache.commons.collections4.BidiMap;
-import org.apache.jackrabbit.webdav.AbstractLocatorFactory;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.jackrabbit.webdav.DavLocatorFactory;
 import org.apache.jackrabbit.webdav.DavResourceLocator;
+import org.apache.jackrabbit.webdav.util.EncodeUtil;
 import org.cryptomator.crypto.Cryptor;
 import org.cryptomator.crypto.CryptorIOSupport;
 import org.cryptomator.crypto.SensitiveDataSwipeListener;
 
-class DavLocatorFactoryImpl extends AbstractLocatorFactory implements SensitiveDataSwipeListener, CryptorIOSupport {
+class DavLocatorFactoryImpl implements DavLocatorFactory, SensitiveDataSwipeListener, CryptorIOSupport {
 
 	private static final int MAX_CACHED_PATHS = 10000;
 	private final Path fsRoot;
 	private final Cryptor cryptor;
 	private final BidiMap<String, String> pathCache = new BidiLRUMap<>(MAX_CACHED_PATHS); // <decryptedPath, encryptedPath>
 
-	DavLocatorFactoryImpl(String fsRoot, String httpRoot, Cryptor cryptor) {
-		super(httpRoot);
+	DavLocatorFactoryImpl(String fsRoot, Cryptor cryptor) {
 		this.fsRoot = FileSystems.getDefault().getPath(fsRoot);
 		this.cryptor = cryptor;
 		cryptor.addSensitiveDataSwipeListener(this);
 	}
 
+	/* DavLocatorFactory */
+
+	@Override
+	public DavResourceLocator createResourceLocator(String prefix, String href) {
+		final String fullPrefix = prefix.endsWith("/") ? prefix : prefix + "/";
+		final String relativeHref = StringUtils.removeStart(href, fullPrefix);
+
+		final String resourcePath = EncodeUtil.unescape(StringUtils.removeStart(relativeHref, "/"));
+		return new DavResourceLocatorImpl(fullPrefix, resourcePath);
+	}
+
+	@Override
+	public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String path, boolean isResourcePath) {
+		final String fullPrefix = prefix.endsWith("/") ? prefix : prefix + "/";
+
+		final String resourcePath = (isResourcePath) ? path : getResourcePath(path);
+		return new DavResourceLocatorImpl(fullPrefix, resourcePath);
+	}
+
+	@Override
+	public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String resourcePath) {
+		return createResourceLocator(prefix, workspacePath, resourcePath, true);
+	}
+
+	/* Encryption/Decryption */
+
 	/**
 	 * @return Encrypted absolute paths on the file system.
 	 */
-	@Override
-	protected String getRepositoryPath(String resourcePath, String wspPath) {
+	private String getRepositoryPath(String resourcePath) {
 		String encryptedPath = pathCache.get(resourcePath);
 		if (encryptedPath == null) {
 			encryptedPath = encryptRepositoryPath(resourcePath);
@@ -59,8 +87,7 @@ class DavLocatorFactoryImpl extends AbstractLocatorFactory implements SensitiveD
 	/**
 	 * @return Decrypted path for use in URIs.
 	 */
-	@Override
-	protected String getResourcePath(String repositoryPath, String wspPath) {
+	private String getResourcePath(String repositoryPath) {
 		String decryptedPath = pathCache.getKey(repositoryPath);
 		if (decryptedPath == null) {
 			decryptedPath = decryptResourcePath(repositoryPath);
@@ -80,24 +107,7 @@ class DavLocatorFactoryImpl extends AbstractLocatorFactory implements SensitiveD
 		}
 	}
 
-	@Override
-	public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String path, boolean isResourcePath) {
-		// we don't support workspaces
-		return super.createResourceLocator(prefix, "", path, isResourcePath);
-	}
-
-	@Override
-	public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String resourcePath) {
-		// we don't support workspaces
-		return super.createResourceLocator(prefix, "", resourcePath);
-	}
-
-	@Override
-	public void swipeSensitiveData() {
-		pathCache.clear();
-	}
-
-	/* Cryptor I/O Support */
+	/* CryptorIOSupport */
 
 	@Override
 	public void writePathSpecificMetadata(String encryptedPath, byte[] encryptedMetadata) throws IOException {
@@ -115,4 +125,103 @@ class DavLocatorFactoryImpl extends AbstractLocatorFactory implements SensitiveD
 		}
 	}
 
+	/* SensitiveDataSwipeListener */
+
+	@Override
+	public void swipeSensitiveData() {
+		pathCache.clear();
+	}
+
+	/* Locator */
+
+	private class DavResourceLocatorImpl implements DavResourceLocator {
+
+		private final String prefix;
+		private final String resourcePath;
+
+		private DavResourceLocatorImpl(String prefix, String resourcePath) {
+			this.prefix = prefix;
+			this.resourcePath = resourcePath;
+		}
+
+		@Override
+		public String getPrefix() {
+			return prefix;
+		}
+
+		@Override
+		public String getResourcePath() {
+			return resourcePath;
+		}
+
+		@Override
+		public String getWorkspacePath() {
+			return isRootLocation() ? null : "";
+		}
+
+		@Override
+		public String getWorkspaceName() {
+			return getPrefix();
+		}
+
+		@Override
+		public boolean isSameWorkspace(DavResourceLocator locator) {
+			return (locator == null) ? false : isSameWorkspace(locator.getWorkspaceName());
+		}
+
+		@Override
+		public boolean isSameWorkspace(String workspaceName) {
+			return getWorkspaceName().equals(workspaceName);
+		}
+
+		@Override
+		public String getHref(boolean isCollection) {
+			final String href = getPrefix().concat(getResourcePath());
+			if (isCollection && !href.endsWith("/")) {
+				return href.concat("/");
+			} else if (!isCollection && href.endsWith("/")) {
+				return href.substring(0, href.length() - 1);
+			} else {
+				return href;
+			}
+		}
+
+		@Override
+		public boolean isRootLocation() {
+			return getResourcePath() == null;
+		}
+
+		@Override
+		public DavLocatorFactory getFactory() {
+			return DavLocatorFactoryImpl.this;
+		}
+
+		@Override
+		public String getRepositoryPath() {
+			return DavLocatorFactoryImpl.this.getRepositoryPath(getResourcePath());
+		}
+
+		@Override
+		public int hashCode() {
+			final HashCodeBuilder builder = new HashCodeBuilder();
+			builder.append(prefix);
+			builder.append(resourcePath);
+			return builder.toHashCode();
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if (obj instanceof DavResourceLocatorImpl) {
+				final DavResourceLocatorImpl other = (DavResourceLocatorImpl) obj;
+				final EqualsBuilder builder = new EqualsBuilder();
+				builder.append(this.prefix, other.prefix);
+				builder.append(this.resourcePath, other.resourcePath);
+				return builder.isEquals();
+			} else {
+				return false;
+			}
+		}
+
+	}
+
 }

+ 1 - 3
main/core/src/main/java/org/cryptomator/webdav/jackrabbit/WebDavServlet.java

@@ -23,7 +23,6 @@ public class WebDavServlet extends AbstractWebdavServlet {
 
 	private static final long serialVersionUID = 7965170007048673022L;
 	public static final String CFG_FS_ROOT = "cfg.fs.root";
-	public static final String CFG_HTTP_ROOT = "cfg.http.root";
 	public static final String CFG_CHECK_FILE_INTEGRITY = "cfg.checkFileIntegrity";
 	private DavSessionProvider davSessionProvider;
 	private DavLocatorFactory davLocatorFactory;
@@ -42,9 +41,8 @@ public class WebDavServlet extends AbstractWebdavServlet {
 		davSessionProvider = new DavSessionProviderImpl();
 
 		final String fsRoot = config.getInitParameter(CFG_FS_ROOT);
-		final String httpRoot = config.getInitParameter(CFG_HTTP_ROOT);
 		final boolean checkFileIntegrity = Boolean.parseBoolean(config.getInitParameter(CFG_CHECK_FILE_INTEGRITY));
-		this.davLocatorFactory = new DavLocatorFactoryImpl(fsRoot, httpRoot, cryptor);
+		this.davLocatorFactory = new DavLocatorFactoryImpl(fsRoot, cryptor);
 
 		this.davResourceFactory = new DavResourceFactoryImpl(cryptor, checkFileIntegrity);
 	}