Added delay for requests on invalid vault ids. Issue #319

This commit is contained in:
Markus Kreusch
2016-08-10 13:37:13 +02:00
parent 3ae8327300
commit 429b26f3d8
5 changed files with 82 additions and 16 deletions

View File

@@ -11,6 +11,8 @@ package org.cryptomator.frontend.webdav;
import java.io.IOException;
import java.util.EnumSet;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.DispatcherType;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
@@ -21,12 +23,24 @@ import org.cryptomator.frontend.webdav.filters.LoopbackFilter;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
/**
* The server needs to respond to requests to the root resource, because Windows is stupid.
*/
public class WindowsCompatibilityServlet extends HttpServlet {
@Singleton
class DefaultServlet extends HttpServlet {
private static final String ROOT_PATH = "/";
private static final String WILDCARD = "/*";
private final Tarpit tarpit;
@Inject
public DefaultServlet(Tarpit tarpit) {
this.tarpit = tarpit;
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
tarpit.handle(req);
super.service(req, resp);
}
@Override
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
@@ -36,11 +50,11 @@ public class WindowsCompatibilityServlet extends HttpServlet {
resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
public static ServletContextHandler createServletContextHandler() {
public ServletContextHandler createServletContextHandler() {
final ServletContextHandler servletContext = new ServletContextHandler(null, ROOT_PATH, ServletContextHandler.NO_SESSIONS);
final ServletHolder servletHolder = new ServletHolder(ROOT_PATH, WindowsCompatibilityServlet.class);
final ServletHolder servletHolder = new ServletHolder(ROOT_PATH, this);
servletContext.addServlet(servletHolder, ROOT_PATH);
servletContext.addFilter(LoopbackFilter.class, ROOT_PATH, EnumSet.of(DispatcherType.REQUEST));
servletContext.addFilter(LoopbackFilter.class, WILDCARD, EnumSet.of(DispatcherType.REQUEST));
return servletContext;
}

View File

@@ -0,0 +1,46 @@
/*******************************************************************************
* Copyright (c) 2016 Markus Kreusch
* This file is licensed under the terms of the MIT license.
* See the LICENSE.txt file for more info.
*******************************************************************************/
package org.cryptomator.frontend.webdav;
import static java.lang.Math.max;
import static java.lang.System.currentTimeMillis;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.servlet.http.HttpServletRequest;
@Singleton
class Tarpit {
private static final long DELAY_MS = 10000;
@Inject
public Tarpit() {}
public void handle(HttpServletRequest req) {
if (isRequestWithVaultId(req)) {
delayExecutionUninterruptibly();
}
}
private void delayExecutionUninterruptibly() {
long expected = currentTimeMillis() + DELAY_MS;
long sleepTime = DELAY_MS;
while (expected > currentTimeMillis()) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
sleepTime = max(0, currentTimeMillis() - expected + 10);
}
}
}
private boolean isRequestWithVaultId(HttpServletRequest req) {
String path = req.getServletPath();
return path.matches("^/[a-zA-Z0-9_-]{12}/.*$");
}
}

View File

@@ -47,7 +47,7 @@ public class WebDavServer implements FrontendFactory {
private final WebDavMounterProvider webdavMounterProvider;
@Inject
WebDavServer(WebDavServletContextFactory servletContextFactory, WebDavMounterProvider webdavMounterProvider) {
WebDavServer(WebDavServletContextFactory servletContextFactory, WebDavMounterProvider webdavMounterProvider, DefaultServlet defaultServlet) {
final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(MAX_PENDING_REQUESTS);
final ThreadPool tp = new QueuedThreadPool(MAX_THREADS, MIN_THREADS, THREAD_IDLE_SECONDS, queue);
this.server = new Server(tp);
@@ -56,7 +56,7 @@ public class WebDavServer implements FrontendFactory {
this.servletContextFactory = servletContextFactory;
this.webdavMounterProvider = webdavMounterProvider;
servletCollection.addHandler(WindowsCompatibilityServlet.createServletContextHandler());
servletCollection.addHandler(defaultServlet.createServletContextHandler());
server.setConnectors(new Connector[] {localConnector});
server.setHandler(servletCollection);
}

View File

@@ -35,10 +35,9 @@ import org.eclipse.jetty.servlet.ServletHolder;
class WebDavServletContextFactory {
private static final String WILDCARD = "/*";
@Inject
public WebDavServletContextFactory() {
}
public WebDavServletContextFactory() {}
/**
* Creates a new Jetty ServletContextHandler, that can be be added to a servletCollection as follows:

View File

@@ -8,6 +8,8 @@
*******************************************************************************/
package org.cryptomator.frontend.webdav;
import static org.mockito.Mockito.mock;
import java.io.IOException;
import javax.servlet.Servlet;
@@ -21,21 +23,26 @@ import org.junit.Test;
import org.mockito.Mockito;
public class WindowsCompatibilityServletTest {
public class DefaultServletTest {
private Tarpit tarpit = mock(Tarpit.class);
private DefaultServlet inTest = new DefaultServlet(tarpit);
@Test
public void testFactory() throws ServletException {
ServletHolder[] holders = WindowsCompatibilityServlet.createServletContextHandler().getServletHandler().getServlets();
ServletHolder[] holders = inTest.createServletContextHandler().getServletHandler().getServlets();
Assert.assertEquals(1, holders.length);
ServletHolder holder = holders[0];
Servlet servlet = holder.getServlet();
Assert.assertTrue(servlet instanceof WindowsCompatibilityServlet);
Assert.assertTrue(servlet instanceof DefaultServlet);
}
@Test
public void testResponse() throws IOException, ServletException {
final WindowsCompatibilityServlet servlet = new WindowsCompatibilityServlet();
final DefaultServlet servlet = inTest;
final HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
final HttpServletResponse response = Mockito.mock(HttpServletResponse.class);