Author: markt Date: Sun Jun 3 15:54:28 2012 New Revision: 1345689 URL: http://svn.apache.org/viewvc?rev=1345689&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=53337 Fix RequestDispatcher.forward() to an async servlet. Includes a test case based on code by Rossen Stoyanchev.
Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1345688 Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java?rev=1345689&r1=1345688&r2=1345689&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/ApplicationDispatcher.java Sun Jun 3 15:54:28 2012 @@ -402,6 +402,12 @@ final class ApplicationDispatcher processRequest(request,response,state); } + if (request.getAsyncContext() != null) { + // An async request was started during the forward, don't close the + // response as it may be written to during the async handling + return; + } + // This is not a real close in order to support error processing if (wrapper.getLogger().isDebugEnabled() ) wrapper.getLogger().debug(" Disabling the response for futher output"); Modified: tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java?rev=1345689&r1=1345688&r2=1345689&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java (original) +++ tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java Sun Jun 3 15:54:28 2012 @@ -22,10 +22,13 @@ import java.io.IOException; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; +import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; @@ -1275,4 +1278,86 @@ public class TestAsyncContextImpl extend } } } + + @Test + public void testBug53337() throws Exception { + // Setup Tomcat instance + Tomcat tomcat = getTomcatInstance(); + + // Must have a real docBase - just use temp + File docBase = new File(System.getProperty("java.io.tmpdir")); + + Context ctx = tomcat.addContext("", docBase.getAbsolutePath()); + Wrapper a = Tomcat.addServlet(ctx, "ServletA", new Bug53337ServletA()); + a.setAsyncSupported(true); + Wrapper b = Tomcat.addServlet(ctx, "ServletB", new Bug53337ServletB()); + b.setAsyncSupported(true); + Tomcat.addServlet(ctx, "ServletC", new Bug53337ServletC()); + ctx.addServletMapping("/ServletA", "ServletA"); + ctx.addServletMapping("/ServletB", "ServletB"); + ctx.addServletMapping("/ServletC", "ServletC"); + + tomcat.start(); + + StringBuilder url = new StringBuilder(48); + url.append("http://localhost:"); + url.append(getPort()); + url.append("/ServletA"); + + ByteChunk body = new ByteChunk(); + int rc = getUrl(url.toString(), body, null); + + assertEquals(HttpServletResponse.SC_OK, rc); + assertEquals("OK", body.toString()); + } + + private static class Bug53337ServletA extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + RequestDispatcher rd = req.getRequestDispatcher("/ServletB"); + rd.forward(req, resp); + } + } + + private static class Bug53337ServletB extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(final HttpServletRequest req, + final HttpServletResponse resp) + throws ServletException, IOException { + + final AsyncContext async = req.startAsync(); + // Just for debugging + async.setTimeout(100000); + + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.submit(new Runnable() { + + @Override + public void run() { + async.dispatch("/ServletC"); + } + }); + executor.shutdown(); + } + } + + private static class Bug53337ServletC extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setContentType("text/plain"); + resp.getWriter().print("OK"); + } + } + } Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1345689&r1=1345688&r2=1345689&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Sun Jun 3 15:54:28 2012 @@ -181,6 +181,11 @@ patch provided by Violeta Georgieva. (markt) </fix> <fix> + <bug>53337</bug>: Forwarding via a <code>RequestDispatcher</code> to an + asynchronous Servlet always failed. Includes a test case based on code + by Rossen Stoyanchev. (markt) + </fix> + <fix> <bug>53342</bug>: To avoid BindException, make startStopThreads into a demon thread. (kfujino) </fix> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org