Author: markt
Date: Wed Jan  3 20:03:15 2018
New Revision: 1820003

URL: http://svn.apache.org/viewvc?rev=1820003&view=rev
Log:
Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=61932
Allow a call to AsyncContext.dispatch() to terminate non-blocking I/O.

Modified:
    tomcat/trunk/java/org/apache/coyote/AsyncStateMachine.java
    tomcat/trunk/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/org/apache/coyote/AsyncStateMachine.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/AsyncStateMachine.java?rev=1820003&r1=1820002&r2=1820003&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/AsyncStateMachine.java [UTF-8] 
(original)
+++ tomcat/trunk/java/org/apache/coyote/AsyncStateMachine.java [UTF-8] Wed Jan  
3 20:03:15 2018
@@ -350,6 +350,7 @@ public class AsyncStateMachine {
 
 
     private synchronized boolean doDispatch() {
+        clearNonBlockingListeners();
         boolean doDispatch = false;
         if (state == AsyncState.STARTING ||
                 state == AsyncState.TIMING_OUT ||

Modified: 
tomcat/trunk/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java?rev=1820003&r1=1820002&r2=1820003&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java 
(original)
+++ tomcat/trunk/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java 
Wed Jan  3 20:03:15 2018
@@ -37,6 +37,7 @@ import javax.net.SocketFactory;
 import javax.servlet.AsyncContext;
 import javax.servlet.AsyncEvent;
 import javax.servlet.AsyncListener;
+import javax.servlet.DispatcherType;
 import javax.servlet.ReadListener;
 import javax.servlet.ServletException;
 import javax.servlet.ServletInputStream;
@@ -51,7 +52,6 @@ import org.junit.Ignore;
 import org.junit.Test;
 
 import org.apache.catalina.Context;
-import org.apache.catalina.core.StandardContext;
 import org.apache.catalina.startup.BytesStreamer;
 import org.apache.catalina.startup.TesterServlet;
 import org.apache.catalina.startup.Tomcat;
@@ -100,9 +100,8 @@ public class TestNonBlockingAPI extends
     private void doTestNonBlockingRead(boolean ignoreIsReady) throws Exception 
{
         Tomcat tomcat = getTomcatInstance();
 
-        // Must have a real docBase - just use temp
-        StandardContext ctx = (StandardContext) tomcat.addContext("",
-                System.getProperty("java.io.tmpdir"));
+        // No file system docBase required
+        Context ctx = tomcat.addContext("", null);
 
         NBReadServlet servlet = new NBReadServlet(ignoreIsReady);
         String servletName = NBReadServlet.class.getName();
@@ -913,7 +912,89 @@ public class TestNonBlockingAPI extends
 
             });
         }
+    }
+
+
+    /*
+     * https://bz.apache.org/bugzilla/show_bug.cgi?id=61932
+     */
+    @Test
+    public void testNonBlockingReadWithDispathch() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
 
+        // No file system docBase required
+        Context ctx = tomcat.addContext("", null);
+
+        NBReadWithDispatchServlet servlet = new NBReadWithDispatchServlet();
+        String servletName = NBReadWithDispatchServlet.class.getName();
+        Tomcat.addServlet(ctx, servletName, servlet);
+        ctx.addServletMappingDecoded("/", servletName);
+
+        tomcat.start();
+
+        Map<String, List<String>> resHeaders = new HashMap<>();
+        int rc = postUrl(true, new DataWriter(500), "http://localhost:"; +
+                getPort() + "/", new ByteChunk(), resHeaders, null);
+
+        Assert.assertEquals(HttpServletResponse.SC_OK, rc);
     }
 
+
+    @WebServlet(asyncSupported = true)
+    private final class NBReadWithDispatchServlet extends TesterServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+
+            CountDownLatch latch = new CountDownLatch(1);
+
+            // Dispatch to "/error" will end up here
+            if (req.getDispatcherType().equals(DispatcherType.ASYNC)) {
+                // Return without writing anything. This will generate the
+                // expected 200 response.
+                return;
+            }
+
+            AsyncContext asyncCtx = req.startAsync();
+            ServletInputStream is = req.getInputStream();
+            is.setReadListener(new ReadListener() {
+
+                @Override
+                public void onDataAvailable() {
+
+                    try {
+                        byte buffer[] = new byte[1 * 1024];
+                        while (is.isReady() && !is.isFinished()) {
+                            is.read(buffer);
+                        }
+
+                    } catch (IOException ex) {
+                        ex.printStackTrace();
+                    }
+                }
+
+                @Override
+                public void onAllDataRead() {
+                    latch.countDown();
+                }
+
+                @Override
+                public void onError(Throwable t) {
+                }
+            });
+
+            new Thread(() -> {
+                try {
+                    latch.await();
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                asyncCtx.dispatch("/error");
+            }).start();
+
+        }
+    }
 }

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1820003&r1=1820002&r2=1820003&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Wed Jan  3 20:03:15 2018
@@ -84,6 +84,10 @@
         cipher mapping. (markt)
       </add>
       <fix>
+        <bug>61932</bug>: Allow a call to <code>AsyncContext.dispatch()</code>
+        to terminate non-blocking I/O. (markt)
+      </fix>
+      <fix>
         <bug>61948</bug>: Improve the handling of malformed ClientHello 
messages
         in the code that extracts the SNI information from a TLS handshake for
         the JSSE based NIO and NIO2 connectors. (markt)



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to