diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java index 4a6ad3db3ea..aa45d42d8d3 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java @@ -27,7 +27,6 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.eclipse.jetty.server.handler.ContextHandler.Context; -import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.thread.Scheduler; public class AsyncContextEvent extends AsyncEvent implements Runnable @@ -157,7 +156,7 @@ public class AsyncContextEvent extends AsyncEvent implements Runnable Scheduler.Task task=_timeoutTask; _timeoutTask=null; if (task!=null) - _state.onTimeout(); + _state.getHttpChannel().execute(() -> _state.onTimeout()); } public void addThrowable(Throwable e) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java index 5a819b8ef8d..7b7ac90010b 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java @@ -299,7 +299,7 @@ public class HttpChannelState { listener.onStartAsync(event); } - catch(Exception e) + catch(Throwable e) { // TODO Async Dispatch Error LOG.warn(e); @@ -853,7 +853,7 @@ public class HttpChannelState { listener.onComplete(event); } - catch(Exception e) + catch(Throwable e) { LOG.warn(e+" while invoking onComplete listener " + listener); LOG.debug(e); diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncListenerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncListenerTest.java index f50b2ef9417..ae9b8e36338 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncListenerTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncListenerTest.java @@ -32,12 +32,14 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.io.RuntimeIOException; +import org.eclipse.jetty.http.HttpTester; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.QuietServletException; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ErrorHandler; +import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.After; +import org.junit.Assert; import org.junit.Test; import static org.hamcrest.Matchers.containsString; @@ -45,12 +47,13 @@ import static org.junit.Assert.assertThat; public class AsyncListenerTest { + private QueuedThreadPool threadPool; private Server server; private LocalConnector connector; public void startServer(ServletContextHandler context) throws Exception { - server = new Server(); + server = threadPool == null ? new Server() : new Server(threadPool); connector = new LocalConnector(server); connector.setIdleTimeout(20 * 60 * 1000L); server.addConnector(connector); @@ -407,6 +410,42 @@ public class AsyncListenerTest assertThat(httpResponse, containsString("DATA")); } + @Test + public void test_StartAsync_OnTimeout_CalledBy_PooledThread() throws Exception + { + String threadNamePrefix = "async_listener"; + threadPool = new QueuedThreadPool(); + threadPool.setName(threadNamePrefix); + ServletContextHandler context = new ServletContextHandler(); + context.addServlet(new ServletHolder(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + AsyncContext asyncContext = request.startAsync(); + asyncContext.setTimeout(1000); + asyncContext.addListener(new AsyncListenerAdapter() + { + @Override + public void onTimeout(AsyncEvent event) throws IOException + { + if (Thread.currentThread().getName().startsWith(threadNamePrefix)) + response.setStatus(HttpStatus.OK_200); + else + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500); + asyncContext.complete(); + } + }); + } + }), "/*"); + startServer(context); + + HttpTester.Response response = HttpTester.parseResponse(connector.getResponse("" + + "GET / HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "\r\n")); + Assert.assertEquals(HttpStatus.OK_200, response.getStatus()); + } // Unique named RuntimeException to help during debugging / assertions. public static class TestRuntimeException extends RuntimeException