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-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org