You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2016/06/02 22:37:49 UTC

svn commit: r1746649 - in /tomcat/trunk: java/org/apache/coyote/http11/Http11Processor.java test/org/apache/coyote/http11/TestHttp11Processor.java webapps/docs/changelog.xml

Author: markt
Date: Thu Jun  2 22:37:48 2016
New Revision: 1746649

URL: http://svn.apache.org/viewvc?rev=1746649&view=rev
Log:
If an async dispatch results in the completion of request processing, ensure that any remaining requets body is swallowed before starting the processing of the next request else the remaining body may be read as the start of the next request leading to a 400 response.

Modified:
    tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java
    tomcat/trunk/test/org/apache/coyote/http11/TestHttp11Processor.java
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java?rev=1746649&r1=1746648&r2=1746649&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java Thu Jun  2 22:37:48 2016
@@ -1727,6 +1727,7 @@ public class Http11Processor extends Abs
         if (!keepAlive) {
             return SocketState.CLOSED;
         } else {
+            endRequest();
             inputBuffer.nextRequest();
             outputBuffer.nextRequest();
             if (socketWrapper.isReadPending()) {

Modified: tomcat/trunk/test/org/apache/coyote/http11/TestHttp11Processor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http11/TestHttp11Processor.java?rev=1746649&r1=1746648&r2=1746649&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/coyote/http11/TestHttp11Processor.java (original)
+++ tomcat/trunk/test/org/apache/coyote/http11/TestHttp11Processor.java Thu Jun  2 22:37:48 2016
@@ -16,11 +16,18 @@
  */
 package org.apache.coyote.http11;
 
+import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
+import java.io.Reader;
 import java.io.Writer;
+import java.net.InetSocketAddress;
 import java.net.Socket;
+import java.net.SocketAddress;
 import java.nio.CharBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
@@ -31,6 +38,7 @@ import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 
 import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
 import javax.servlet.ServletException;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServlet;
@@ -842,4 +850,99 @@ public class TestHttp11Processor extends
                 throws ServletException, IOException {
         }
     }
+
+
+    /*
+     * Tests what happens if a request is completed during a dispatch but the
+     * request body has not been fully read.
+     */
+    @Test
+    public void testRequestBodySwallowing() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        // No file system docBase required
+        Context ctx = tomcat.addContext("", null);
+
+        SempahoreServlet servlet = new SempahoreServlet();
+        Wrapper w = Tomcat.addServlet(ctx, "Test", servlet);
+        w.setAsyncSupported(true);
+        ctx.addServletMapping("/test", "Test");
+
+        tomcat.start();
+
+        // Hand-craft the client so we have complete control over the timing
+        SocketAddress addr = new InetSocketAddress("localhost", getPort());
+        Socket socket = new Socket();
+        socket.setSoTimeout(300000);
+        socket.connect(addr,300000);
+        OutputStream os = socket.getOutputStream();
+        Writer writer = new OutputStreamWriter(os, "ISO-8859-1");
+        InputStream is = socket.getInputStream();
+        Reader r = new InputStreamReader(is, "ISO-8859-1");
+        BufferedReader reader = new BufferedReader(r);
+
+        // Write the headers
+        writer.write("POST /test HTTP/1.1\r\n");
+        writer.write("Host: localhost:8080\r\n");
+        writer.write("Transfer-Encoding: chunked\r\n");
+        writer.write("\r\n");
+        writer.flush();
+
+        validateResponse(reader);
+
+        // Write the request body
+        writer.write("2\r\n");
+        writer.write("AB\r\n");
+        writer.write("0\r\n");
+        writer.write("\r\n");
+        writer.flush();
+
+        // Write the 2nd request
+        writer.write("POST /test HTTP/1.1\r\n");
+        writer.write("Host: localhost:8080\r\n");
+        writer.write("Transfer-Encoding: chunked\r\n");
+        writer.write("\r\n");
+        writer.flush();
+
+        // Read the 2nd response
+        validateResponse(reader);
+
+        // Write the 2nd request body
+        writer.write("2\r\n");
+        writer.write("AB\r\n");
+        writer.write("0\r\n");
+        writer.write("\r\n");
+        writer.flush();
+
+        // Done
+        socket.close();
+    }
+
+
+    private void validateResponse(BufferedReader reader) throws IOException {
+        // First line has the response code and should always be 200
+        String line = reader.readLine();
+        Assert.assertEquals("HTTP/1.1 200 ", line);
+        while (!"OK".equals(line)) {
+            line = reader.readLine();
+        }
+    }
+
+
+    private static class SempahoreServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+            if (DispatcherType.ASYNC.equals(req.getDispatcherType())) {
+                resp.setContentType("text/plain");
+                resp.setCharacterEncoding("UTF-8");
+                resp.getWriter().write("OK\n");
+            } else {
+                req.startAsync().dispatch();
+            }
+        }
+    }
 }

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1746649&r1=1746648&r2=1746649&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Thu Jun  2 22:37:48 2016
@@ -109,6 +109,12 @@
         <code>WriteListener.onError()</code> or
         <code>AsycnListener.onError()</code>) is called. (markt)
       </fix>
+      <fix>
+       If an async dispatch results in the completion of request processing,
+       ensure that any remaining requets body is swallowed before starting the
+       processing of the next request else the remaining body may be read as the
+       start of the next request leading to a 400 response. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Jasper">



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