All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cryptomator.frontend.webdav.DefaultServlet Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2016 Sebastian Stenzel and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the accompanying LICENSE.txt.
 *
 * Contributors:
 *     Sebastian Stenzel - initial API and implementation
 *******************************************************************************/
package org.cryptomator.frontend.webdav;

import java.io.IOException;
import java.util.Collection;

import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.cryptomator.frontend.webdav.WebDavServerModule.ContextPaths;

import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;

@Singleton
class DefaultServlet extends HttpServlet {

	private static final String METHOD_PROPFIND = "PROPFIND";
	private static final int TARPIT_DELAY_MS = 5000;
	private final Collection contextPaths;

	@Inject
	public DefaultServlet(@ContextPaths Collection contextPaths) {
		this.contextPaths = contextPaths;
	}

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		if (!isRequestedResourcePathPartOfValidContextPath(req.getRequestURI())) {
			try {
				Thread.sleep(TARPIT_DELAY_MS);
				resp.addHeader("X-Tarpit-Delayed", TARPIT_DELAY_MS + "ms");
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
			} catch (InterruptedException e) {
				resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Thread interrupted.");
				Thread.currentThread().interrupt();
			}
			return;
		}

		switch (req.getMethod()) {
		case METHOD_PROPFIND:
			doPropfind(req, resp);
			break;
		default:
			super.service(req, resp);
			break;
		}
	}

	@Override
	protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.addHeader("DAV", "1, 2");
		resp.addHeader("MS-Author-Via", "DAV");
		resp.addHeader("Allow", "OPTIONS, PROPFIND, GET, HEAD");
		resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
	}

	protected void doPropfind(HttpServletRequest req, HttpServletResponse resp) throws IOException {
		resp.getWriter()
				.write("\n" //
						+ "\n" //
						+ "\n" //
						+ "  " + req.getRequestURI() + "\n" //
						+ "  \n" //
						+ "    \n" //
						+ "      1\n" //
						+ "      \n" //
						+ "    \n" //
						+ "  \n" //
						+ "\n" //
						+ "");
		resp.getWriter().flush();
	}

	private boolean isRequestedResourcePathPartOfValidContextPath(String requestedResourcePath) {
		return contextPaths.stream().filter(cp -> isParentOrSamePath(cp, requestedResourcePath)).findAny().isPresent();
	}

	private boolean isParentOrSamePath(String path, String potentialParent) {
		String[] pathComponents = Iterables.toArray(Splitter.on('/').omitEmptyStrings().split(path), String.class);
		String[] parentPathComponents = Iterables.toArray(Splitter.on('/').omitEmptyStrings().split(potentialParent), String.class);
		if (pathComponents.length < parentPathComponents.length) {
			return false; // parent can not be parent of path, if it is longer than path.
		}
		assert pathComponents.length >= parentPathComponents.length;
		for (int i = 0; i < parentPathComponents.length; i++) {
			if (!pathComponents[i].equals(parentPathComponents[i])) {
				return false;
			}
		}
		return true;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy