From fee07d4e2114b6f1214948968fc4cdd523d153a5 Mon Sep 17 00:00:00 2001 From: markt Date: Mon, 22 Nov 2010 14:35:51 +0000 Subject: [PATCH] Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=50308 Allow asynchronous request processing to call AsyncContext.dispatch() once the asynchronous request has timed out. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1037735 13f79535-47bb-0310-9956-ffa450edef68 --- java/org/apache/coyote/AsyncStateMachine.java | 3 +- .../apache/catalina/core/TestAsyncContextImpl.java | 52 ++++++++++++++++------ webapps/docs/changelog.xml | 5 +++ 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/java/org/apache/coyote/AsyncStateMachine.java b/java/org/apache/coyote/AsyncStateMachine.java index fe996e238..38ece40d9 100644 --- a/java/org/apache/coyote/AsyncStateMachine.java +++ b/java/org/apache/coyote/AsyncStateMachine.java @@ -213,7 +213,8 @@ public class AsyncStateMachine { boolean doDispatch = false; if (state == AsyncState.STARTING) { state = AsyncState.MUST_DISPATCH; - } else if (state == AsyncState.STARTED) { + } else if (state == AsyncState.STARTED || + state == AsyncState.TIMING_OUT) { state = AsyncState.DISPATCHING; doDispatch = true; } else { diff --git a/test/org/apache/catalina/core/TestAsyncContextImpl.java b/test/org/apache/catalina/core/TestAsyncContextImpl.java index 2ba8902cc..dd7b02fbf 100644 --- a/test/org/apache/catalina/core/TestAsyncContextImpl.java +++ b/test/org/apache/catalina/core/TestAsyncContextImpl.java @@ -314,14 +314,20 @@ public class TestAsyncContextImpl extends TomcatBaseTest { } public void testTimeoutListenerComplete() throws Exception { - doTestTimeout(true); + doTestTimeout(true, null); } public void testTimeoutListenerNoComplete() throws Exception { - doTestTimeout(false); + doTestTimeout(false, null); + } + + public void testTimeoutListenerDispatch() throws Exception { + doTestTimeout(true, "/nonasync"); } - private void doTestTimeout(boolean completeOnTimeout) throws Exception { + + private void doTestTimeout(boolean completeOnTimeout, String dispatchUrl) + throws Exception { // Setup Tomcat instance Tomcat tomcat = getTomcatInstance(); @@ -336,12 +342,19 @@ public class TestAsyncContextImpl extends TomcatBaseTest { Context ctx = tomcat.addContext("", docBase.getAbsolutePath()); - TimeoutServlet timeout = new TimeoutServlet(completeOnTimeout); + TimeoutServlet timeout = + new TimeoutServlet(completeOnTimeout, dispatchUrl); Wrapper wrapper = Tomcat.addServlet(ctx, "time", timeout); wrapper.setAsyncSupported(true); ctx.addServletMapping("/async", "time"); + if (dispatchUrl != null) { + NonAsyncServlet nonAsync = new NonAsyncServlet(); + Tomcat.addServlet(ctx, "nonasync", nonAsync); + ctx.addServletMapping(dispatchUrl, "nonasync"); + } + tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort() + "/async"); StringBuilder expected = new StringBuilder(); @@ -349,7 +362,11 @@ public class TestAsyncContextImpl extends TomcatBaseTest { if (!completeOnTimeout) { expected.append("onError-"); } - expected.append("onComplete-"); + if (dispatchUrl == null) { + expected.append("onComplete-"); + } else { + expected.append("NonAsyncServletGet-"); + } assertEquals(expected.toString(), res.toString()); } @@ -357,9 +374,11 @@ public class TestAsyncContextImpl extends TomcatBaseTest { private static final long serialVersionUID = 1L; private boolean completeOnTimeout; - - public TimeoutServlet(boolean completeOnTimeout) { + private String dispatchUrl; + + public TimeoutServlet(boolean completeOnTimeout, String dispatchUrl) { this.completeOnTimeout = completeOnTimeout; + this.dispatchUrl = dispatchUrl; } @Override @@ -370,7 +389,8 @@ public class TestAsyncContextImpl extends TomcatBaseTest { final AsyncContext ac = req.startAsync(); ac.setTimeout(3000); - ac.addListener(new TrackingListener(false, completeOnTimeout)); + ac.addListener(new TrackingListener( + false, completeOnTimeout, dispatchUrl)); } else resp.getWriter().print("FAIL: Async unsupported"); } @@ -463,7 +483,7 @@ public class TestAsyncContextImpl extends TomcatBaseTest { final AsyncContext ctxt = req.startAsync(); if (addTrackingListener) { TrackingListener listener = - new TrackingListener(completeOnError, true); + new TrackingListener(completeOnError, true, null); ctxt.addListener(listener); } Runnable run = new Runnable() { @@ -510,7 +530,7 @@ public class TestAsyncContextImpl extends TomcatBaseTest { wrapper.setAsyncSupported(true); ctx.addServletMapping("/stage1", "tracking"); - TimeoutServlet timeout = new TimeoutServlet(true); + TimeoutServlet timeout = new TimeoutServlet(true, null); Wrapper wrapper2 = Tomcat.addServlet(ctx, "timeout", timeout); wrapper2.setAsyncSupported(true); ctx.addServletMapping("/stage2", "timeout"); @@ -546,7 +566,7 @@ public class TestAsyncContextImpl extends TomcatBaseTest { TrackingServlet.first = false; final AsyncContext ctxt = req.startAsync(); - TrackingListener listener = new TrackingListener(false, true); + TrackingListener listener = new TrackingListener(false, true, null); ctxt.addListener(listener); ctxt.setTimeout(3000); @@ -572,11 +592,13 @@ public class TestAsyncContextImpl extends TomcatBaseTest { private boolean completeOnError; private boolean completeOnTimeout; + private String dispatchUrl; public TrackingListener(boolean completeOnError, - boolean completeOnTimeout) { + boolean completeOnTimeout, String dispatchUrl) { this.completeOnError = completeOnError; this.completeOnTimeout = completeOnTimeout; + this.dispatchUrl = dispatchUrl; } @Override @@ -592,7 +614,11 @@ public class TestAsyncContextImpl extends TomcatBaseTest { resp.getWriter().write("onTimeout-"); resp.flushBuffer(); if (completeOnTimeout){ - event.getAsyncContext().complete(); + if (dispatchUrl == null) { + event.getAsyncContext().complete(); + } else { + event.getAsyncContext().dispatch(dispatchUrl); + } } } diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index f9dce07ce..9768b96eb 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -154,6 +154,11 @@ continue to use the version of the web application with which the session is associated until the session expires. (markt) + + 50308: Allow asynchronous request processing to call + AsyncContext.dispatch() once the asynchronous request has + timed out. (markt) + -- 2.11.0