From face3b35841f42716f6c55d751d96600bbb2752d Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 8 Mar 2013 09:28:21 +1100 Subject: [PATCH] 392129 fixed handling of timeouts after startAsync --- .../jetty/server/AbstractHttpConnection.java | 12 +- .../jetty/server/AsyncContinuation.java | 29 +- .../org/eclipse/jetty/server/Request.java | 4 +- .../jetty/server/handler/ContextHandler.java | 2 +- .../jetty/servlet/AsyncServletTest.java | 651 ++++++++++++++++++ .../jetty/servlet/DefaultServletTest.java | 1 - .../org/eclipse/jetty/servlets/DoSFilter.java | 5 +- .../jetty/servlets/AbstractDoSFilterTest.java | 3 +- 8 files changed, 692 insertions(+), 15 deletions(-) create mode 100644 jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java index 5bb6c7325c8..bd75041bb94 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java @@ -443,6 +443,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection // within the call to unhandle(). final Server server=_server; + boolean was_continuation=_request._async.isContinuation(); boolean handling=_request._async.handling() && server!=null && server.isRunning(); while (handling) { @@ -489,7 +490,15 @@ public abstract class AbstractHttpConnection extends AbstractConnection } else { - _request.setDispatcherType(DispatcherType.ASYNC); + if (_request._async.isExpired()&&!was_continuation) + { + _response.setStatus(500,"Async Timeout"); + _request.setAttribute(Dispatcher.ERROR_STATUS_CODE,new Integer(500)); + _request.setAttribute(Dispatcher.ERROR_MESSAGE, "Async Timeout"); + _request.setDispatcherType(DispatcherType.ERROR); + } + else + _request.setDispatcherType(DispatcherType.ASYNC); server.handleAsync(this); } } @@ -530,6 +539,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection } finally { + was_continuation=_request._async.isContinuation(); handling = !_request._async.unhandle() && server.isRunning() && _server!=null; } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java index 002feca497e..ed6dfcc6038 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java @@ -43,6 +43,7 @@ import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Timeout; +import org.omg.CosNaming.IstringHelper; /* ------------------------------------------------------------ */ /** Implementation of Continuation and AsyncContext interfaces @@ -200,6 +201,11 @@ public class AsyncContinuation implements AsyncContext, Continuation } } + public boolean isContinuation() + { + return _continuation; + } + /* ------------------------------------------------------------ */ /* (non-Javadoc) * @see javax.servlet.ServletRequest#isSuspended() @@ -525,8 +531,6 @@ public class AsyncContinuation implements AsyncContext, Continuation } } } - - synchronized (this) { @@ -534,11 +538,12 @@ public class AsyncContinuation implements AsyncContext, Continuation { case __ASYNCSTARTED: case __ASYNCWAIT: - if (_continuation) - dispatch(); - else - // TODO maybe error dispatch? - complete(); + dispatch(); + break; + + default: + if (!_continuation) + _expired=false; } } @@ -937,7 +942,7 @@ public class AsyncContinuation implements AsyncContext, Continuation /* ------------------------------------------------------------ */ - protected void suspend(final ServletContext context, + protected void startAsync(final ServletContext context, final ServletRequest request, final ServletResponse response) { @@ -952,6 +957,14 @@ public class AsyncContinuation implements AsyncContext, Continuation } } + /* ------------------------------------------------------------ */ + protected void startAsync() + { + _responseWrapped=false; + _continuation=false; + doSuspend(_connection.getRequest().getServletContext(),_connection.getRequest(),_connection.getResponse()); + } + /* ------------------------------------------------------------ */ /** diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index b3a298490ac..1b6387bd3d4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -1980,7 +1980,7 @@ public class Request implements HttpServletRequest { if (!_asyncSupported) throw new IllegalStateException("!asyncSupported"); - _async.suspend(); + _async.startAsync(); return _async; } @@ -1989,7 +1989,7 @@ public class Request implements HttpServletRequest { if (!_asyncSupported) throw new IllegalStateException("!asyncSupported"); - _async.suspend(_context,servletRequest,servletResponse); + _async.startAsync(_context,servletRequest,servletResponse); return _async; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index db61bf26771..6ad42d3fd86 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -946,7 +946,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. if (old_context != _scontext) { // check the target. - if (DispatcherType.REQUEST.equals(dispatch) || DispatcherType.ASYNC.equals(dispatch)) + if (DispatcherType.REQUEST.equals(dispatch) || DispatcherType.ASYNC.equals(dispatch) || (DispatcherType.ERROR.equals(dispatch) && baseRequest.getAsyncContinuation().isExpired())) { if (_compactPath) target = URIUtil.compactPath(target); diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java new file mode 100644 index 00000000000..9d03a008e24 --- /dev/null +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java @@ -0,0 +1,651 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.servlet; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; +import java.util.Timer; +import java.util.TimerTask; + +import javax.servlet.AsyncContext; +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import javax.servlet.DispatcherType; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.util.IO; +import org.hamcrest.Matchers; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class AsyncServletTest +{ + + protected AsyncServlet _servlet=new AsyncServlet(); + protected int _port; + + protected Server _server = new Server(); + protected ServletHandler _servletHandler; + protected SelectChannelConnector _connector; + + @Before + public void setUp() throws Exception + { + _connector = new SelectChannelConnector(); + _server.setConnectors(new Connector[]{ _connector }); + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SECURITY|ServletContextHandler.NO_SESSIONS); + context.setContextPath("/ctx"); + _server.setHandler(context); + _servletHandler=context.getServletHandler(); + ServletHolder holder=new ServletHolder(_servlet); + holder.setAsyncSupported(true); + _servletHandler.addServletWithMapping(holder,"/path/*"); + _server.start(); + _port=_connector.getLocalPort(); + } + + @After + public void tearDown() throws Exception + { + _server.stop(); + } + + @Test + public void testNormal() throws Exception + { + String response=process(null,null); + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n",response); + assertContains("NORMAL",response); + assertNotContains("history: onTimeout",response); + assertNotContains("history: onComplete",response); + } + + @Test + public void testSleep() throws Exception + { + String response=process("sleep=200",null); + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n",response); + assertContains("SLEPT",response); + assertNotContains("history: onTimeout",response); + assertNotContains("history: onComplete",response); + } + + @Test + public void testSuspend() throws Exception + { + String response=process("suspend=200",null); + assertEquals("HTTP/1.1 500 Async Timeout",response.substring(0,26)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: onTimeout\r\n"+ + "history: ERROR\r\n"+ + "history: !initial\r\n"+ + "history: onComplete\r\n",response); + + assertContains("ERROR: /ctx/path/info",response); + } + + @Test + public void testSuspendOnTimeoutDispatch() throws Exception + { + String response=process("suspend=200&timeout=dispatch",null); + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: onTimeout\r\n"+ + "history: dispatch\r\n"+ + "history: ASYNC\r\n"+ + "history: !initial\r\n"+ + "history: onComplete\r\n",response); + + assertContains("DISPATCHED",response); + } + + @Test + public void testSuspendOnTimeoutComplete() throws Exception + { + String response=process("suspend=200&timeout=complete",null); + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: onTimeout\r\n"+ + "history: complete\r\n"+ + "history: onComplete\r\n",response); + + assertContains("COMPLETED",response); + } + + @Test + public void testSuspendWaitResume() throws Exception + { + String response=process("suspend=200&resume=10",null); + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: resume\r\n"+ + "history: ASYNC\r\n"+ + "history: !initial\r\n"+ + "history: onComplete\r\n",response); + assertNotContains("history: onTimeout",response); + } + + @Test + public void testSuspendResume() throws Exception + { + String response=process("suspend=200&resume=0",null); + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: resume\r\n"+ + "history: ASYNC\r\n"+ + "history: !initial\r\n"+ + "history: onComplete\r\n",response); + assertContains("history: onComplete",response); + } + + @Test + public void testSuspendWaitComplete() throws Exception + { + String response=process("suspend=200&complete=50",null); + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: complete\r\n"+ + "history: onComplete\r\n",response); + assertContains("COMPLETED",response); + assertNotContains("history: onTimeout",response); + assertNotContains("history: !initial",response); + } + + @Test + public void testSuspendComplete() throws Exception + { + String response=process("suspend=200&complete=0",null); + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: complete\r\n"+ + "history: onComplete\r\n",response); + assertContains("COMPLETED",response); + assertNotContains("history: onTimeout",response); + assertNotContains("history: !initial",response); + } + + @Test + public void testSuspendWaitResumeSuspendWaitResume() throws Exception + { + String response=process("suspend=1000&resume=10&suspend2=1000&resume2=10",null); + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: resume\r\n"+ + "history: ASYNC\r\n"+ + "history: !initial\r\n"+ + "history: suspend\r\n"+ + "history: resume\r\n"+ + "history: ASYNC\r\n"+ + "history: !initial\r\n"+ + "history: onComplete\r\n",response); + assertContains("DISPATCHED",response); + } + + @Test + public void testSuspendWaitResumeSuspendComplete() throws Exception + { + String response=process("suspend=1000&resume=10&suspend2=1000&complete2=10",null); + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: resume\r\n"+ + "history: ASYNC\r\n"+ + "history: !initial\r\n"+ + "history: suspend\r\n"+ + "history: complete\r\n"+ + "history: onComplete\r\n",response); + assertContains("COMPLETED",response); + } + + @Test + public void testSuspendWaitResumeSuspend() throws Exception + { + String response=process("suspend=1000&resume=10&suspend2=10",null); + assertEquals("HTTP/1.1 500 Async Timeout",response.substring(0,26)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: resume\r\n"+ + "history: ASYNC\r\n"+ + "history: !initial\r\n"+ + "history: suspend\r\n"+ + "history: onTimeout\r\n"+ + "history: ERROR\r\n"+ + "history: !initial\r\n"+ + "history: onComplete\r\n",response); + assertContains("ERROR: /ctx/path/info",response); + } + + @Test + public void testSuspendTimeoutSuspendResume() throws Exception + { + String response=process("suspend=10&suspend2=1000&resume2=10",null); + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: onTimeout\r\n"+ + "history: ERROR\r\n"+ + "history: !initial\r\n"+ + "history: suspend\r\n"+ + "history: resume\r\n"+ + "history: ASYNC\r\n"+ + "history: !initial\r\n"+ + "history: onComplete\r\n",response); + assertContains("DISPATCHED",response); + } + + @Test + public void testSuspendTimeoutSuspendComplete() throws Exception + { + String response=process("suspend=10&suspend2=1000&complete2=10",null); + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: onTimeout\r\n"+ + "history: ERROR\r\n"+ + "history: !initial\r\n"+ + "history: suspend\r\n"+ + "history: complete\r\n"+ + "history: onComplete\r\n",response); + assertContains("COMPLETED",response); + } + + @Test + public void testSuspendTimeoutSuspend() throws Exception + { + String response=process("suspend=10&suspend2=10",null); + assertContains( + "history: REQUEST\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: onTimeout\r\n"+ + "history: ERROR\r\n"+ + "history: !initial\r\n"+ + "history: suspend\r\n"+ + "history: onTimeout\r\n"+ + "history: ERROR\r\n"+ + "history: !initial\r\n"+ + "history: onComplete\r\n",response); + assertContains("ERROR: /ctx/path/info",response); + } + + + protected void assertContains(String content,String response) + { + Assert.assertThat(response,Matchers.containsString(content)); + } + + protected void assertNotContains(String content,String response) + { + Assert.assertThat(response,Matchers.not(Matchers.containsString(content))); + } + + public synchronized String process(String query,String content) throws Exception + { + String request = "GET /ctx/path/info"; + + if (query!=null) + request+="?"+query; + request+=" HTTP/1.1\r\n"+ + "Host: localhost\r\n"+ + "Connection: close\r\n"; + if (content==null) + request+="\r\n"; + else + { + request+="Content-Length: "+content.length()+"\r\n"; + request+="\r\n" + content; + } + + int port=_port; + String response=null; + try + { + Socket socket = new Socket("localhost",port); + socket.setSoTimeout(1000000); + socket.getOutputStream().write(request.getBytes("UTF-8")); + + response = IO.toString(socket.getInputStream()); + } + catch(Exception e) + { + System.err.println("failed on port "+port); + e.printStackTrace(); + throw e; + } + return response; + } + + + + private static class AsyncServlet extends HttpServlet + { + private static final long serialVersionUID = -8161977157098646562L; + private Timer _timer=new Timer(); + + public AsyncServlet() + {} + + /* ------------------------------------------------------------ */ + @Override + public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException + { + response.addHeader("history",request.getDispatcherType().toString()); + + int read_before=0; + long sleep_for=-1; + long suspend_for=-1; + long suspend2_for=-1; + long resume_after=-1; + long resume2_after=-1; + long complete_after=-1; + long complete2_after=-1; + + if (request.getParameter("read")!=null) + read_before=Integer.parseInt(request.getParameter("read")); + if (request.getParameter("sleep")!=null) + sleep_for=Integer.parseInt(request.getParameter("sleep")); + if (request.getParameter("suspend")!=null) + suspend_for=Integer.parseInt(request.getParameter("suspend")); + if (request.getParameter("suspend2")!=null) + suspend2_for=Integer.parseInt(request.getParameter("suspend2")); + if (request.getParameter("resume")!=null) + resume_after=Integer.parseInt(request.getParameter("resume")); + if (request.getParameter("resume2")!=null) + resume2_after=Integer.parseInt(request.getParameter("resume2")); + if (request.getParameter("complete")!=null) + complete_after=Integer.parseInt(request.getParameter("complete")); + if (request.getParameter("complete2")!=null) + complete2_after=Integer.parseInt(request.getParameter("complete2")); + + if (request.getDispatcherType()==DispatcherType.REQUEST) + { + ((HttpServletResponse)response).addHeader("history","initial"); + if (read_before>0) + { + byte[] buf=new byte[read_before]; + request.getInputStream().read(buf); + } + else if (read_before<0) + { + InputStream in = request.getInputStream(); + int b=in.read(); + while(b!=-1) + b=in.read(); + } + + if (suspend_for>=0) + { + final AsyncContext async=request.startAsync(); + if (suspend_for>0) + async.setTimeout(suspend_for); + async.addListener(__listener); + ((HttpServletResponse)response).addHeader("history","suspend"); + + if (complete_after>0) + { + TimerTask complete = new TimerTask() + { + @Override + public void run() + { + try + { + response.setStatus(200); + response.getOutputStream().println("COMPLETED\n"); + response.addHeader("history","complete"); + async.complete(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + }; + synchronized (_timer) + { + _timer.schedule(complete,complete_after); + } + } + else if (complete_after==0) + { + response.setStatus(200); + response.getOutputStream().println("COMPLETED\n"); + response.addHeader("history","complete"); + async.complete(); + } + else if (resume_after>0) + { + TimerTask resume = new TimerTask() + { + @Override + public void run() + { + ((HttpServletResponse)async.getResponse()).addHeader("history","resume"); + async.dispatch(); + } + }; + synchronized (_timer) + { + _timer.schedule(resume,resume_after); + } + } + else if (resume_after==0) + { + ((HttpServletResponse)async.getResponse()).addHeader("history","resume"); + async.dispatch(); + } + + } + else if (sleep_for>=0) + { + try + { + Thread.sleep(sleep_for); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + response.setStatus(200); + response.getOutputStream().println("SLEPT\n"); + } + else + { + response.setStatus(200); + response.getOutputStream().println("NORMAL\n"); + } + } + else + { + ((HttpServletResponse)response).addHeader("history","!initial"); + + if (suspend2_for>=0 && request.getAttribute("2nd")==null) + { + final AsyncContext async=request.startAsync(); + async.addListener(__listener); + request.setAttribute("2nd","cycle"); + + if (suspend2_for>0) + { + async.setTimeout(suspend2_for); + } + // continuation.addContinuationListener(__listener); + ((HttpServletResponse)response).addHeader("history","suspend"); + + if (complete2_after>0) + { + TimerTask complete = new TimerTask() + { + @Override + public void run() + { + try + { + response.setStatus(200); + response.getOutputStream().println("COMPLETED\n"); + response.addHeader("history","complete"); + async.complete(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + }; + synchronized (_timer) + { + _timer.schedule(complete,complete2_after); + } + } + else if (complete2_after==0) + { + response.setStatus(200); + response.getOutputStream().println("COMPLETED\n"); + response.addHeader("history","complete"); + async.complete(); + } + else if (resume2_after>0) + { + TimerTask resume = new TimerTask() + { + @Override + public void run() + { + ((HttpServletResponse)response).addHeader("history","resume"); + async.dispatch(); + } + }; + synchronized (_timer) + { + _timer.schedule(resume,resume2_after); + } + } + else if (resume2_after==0) + { + ((HttpServletResponse)response).addHeader("history","dispatch"); + async.dispatch(); + } + } + else if(request.getDispatcherType()==DispatcherType.ERROR) + { + response.getOutputStream().println("ERROR: "+request.getContextPath()+request.getServletPath()+request.getPathInfo()); + } + else + { + response.setStatus(200); + response.getOutputStream().println("DISPATCHED"); + } + } + } + } + + + private static AsyncListener __listener = new AsyncListener() + { + @Override + public void onTimeout(AsyncEvent event) throws IOException + { + ((HttpServletResponse)event.getSuppliedResponse()).addHeader("history","onTimeout"); + String action=((HttpServletRequest)event.getSuppliedRequest()).getParameter("timeout"); + if (action!=null) + { + ((HttpServletResponse)event.getSuppliedResponse()).addHeader("history",action); + if ("dispatch".equals(action)) + event.getAsyncContext().dispatch(); + if ("complete".equals(action)) + { + ((HttpServletResponse)event.getSuppliedResponse()).getOutputStream().println("COMPLETED\n"); + event.getAsyncContext().complete(); + } + } + } + + @Override + public void onStartAsync(AsyncEvent event) throws IOException + { + // TODO Auto-generated method stub + + } + + @Override + public void onError(AsyncEvent event) throws IOException + { + // TODO Auto-generated method stub + + } + + @Override + public void onComplete(AsyncEvent event) throws IOException + { + ((HttpServletResponse)event.getSuppliedResponse()).addHeader("history","onComplete"); + } + }; + +} diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java index 843ec1747f2..277bf4823b9 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java @@ -43,7 +43,6 @@ import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.OS; import org.eclipse.jetty.toolchain.test.TestingDir; -import org.eclipse.jetty.util.DateCache; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.StringUtil; import org.hamcrest.Matchers; diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java index 027eb6dcfac..01f3eeb960e 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java @@ -343,7 +343,6 @@ public class DoSFilter implements Filter } // We are over the limit. - LOG.warn("DOS ALERT: ip=" + request.getRemoteAddr() + ",session=" + request.getRequestedSessionId() + ",user=" + request.getUserPrincipal()); // So either reject it, delay it or throttle it long delayMs = getDelayMs(); @@ -353,6 +352,7 @@ public class DoSFilter implements Filter case -1: { // Reject this request + LOG.warn("DOS ALERT: Request rejected ip=" + request.getRemoteAddr() + ",session=" + request.getRequestedSessionId() + ",user=" + request.getUserPrincipal()); if (insertHeaders) response.addHeader("DoSFilter", "unavailable"); response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); @@ -361,12 +361,14 @@ public class DoSFilter implements Filter case 0: { // fall through to throttle code + LOG.warn("DOS ALERT: Request throttled ip=" + request.getRemoteAddr() + ",session=" + request.getRequestedSessionId() + ",user=" + request.getUserPrincipal()); request.setAttribute(__TRACKER, tracker); break; } default: { // insert a delay before throttling the request + LOG.warn("DOS ALERT: Request delayed="+delayMs+"ms ip=" + request.getRemoteAddr() + ",session=" + request.getRequestedSessionId() + ",user=" + request.getUserPrincipal()); if (insertHeaders) response.addHeader("DoSFilter", "delayed"); Continuation continuation = ContinuationSupport.getContinuation(request); @@ -647,6 +649,7 @@ public class DoSFilter implements Filter public void destroy() { + LOG.debug("Destroy {}",this); _running = false; _timerThread.interrupt(); _requestTimeoutQ.cancelAll(); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java index 5dc0b1bc5a7..e15bb9a2ab3 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java @@ -36,6 +36,7 @@ import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.testing.ServletTester; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.log.Log; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -179,8 +180,8 @@ public abstract class AbstractDoSFilterTest String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; String responses = doRequests(request+request+request+request+request,2,1100,1100,last); - assertEquals(11,count(responses,"HTTP/1.1 200 OK")); assertEquals(2,count(responses,"DoSFilter: delayed")); + assertEquals(11,count(responses,"HTTP/1.1 200 OK")); } @Test