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: [email protected]
For additional commands, e-mail: [email protected]