This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 7e8fd4350e2922c282d92787b08392d1e2949992
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Apr 26 16:02:09 2024 +0100

    Additional tests for non-blocking chunked reads
---
 .../catalina/nonblocking/TestNonBlockingAPI.java   | 442 ++++++++++++++++++++-
 .../http11/filters/TestChunkedInputFilter.java     | 176 +++++++-
 2 files changed, 587 insertions(+), 31 deletions(-)

diff --git a/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java 
b/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java
index 1df7859c2d..e451835a72 100644
--- a/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java
+++ b/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java
@@ -72,6 +72,9 @@ public class TestNonBlockingAPI extends TomcatBaseTest {
 
     private static final Log log = LogFactory.getLog(TestNonBlockingAPI.class);
 
+    private static String TRAILER_HEADER_NAME = "x-test";
+    private static String TRAILER_HEADER_VALUE = "abcde";
+
     private static final int CHUNK_SIZE = 1024 * 1024;
     private static final int WRITE_SIZE  = CHUNK_SIZE * 10;
     private static final byte[] DATA = new byte[WRITE_SIZE];
@@ -130,7 +133,7 @@ public class TestNonBlockingAPI extends TomcatBaseTest {
         // No file system docBase required
         Context ctx = getProgrammaticRootContext();
 
-        NBReadServlet servlet = new NBReadServlet(ignoreIsReady, async);
+        NBReadServlet servlet = new NBReadServlet(ignoreIsReady, async, null);
         String servletName = NBReadServlet.class.getName();
         Tomcat.addServlet(ctx, servletName, servlet);
         ctx.addServletMappingDecoded("/", servletName);
@@ -154,31 +157,416 @@ public class TestNonBlockingAPI extends TomcatBaseTest {
 
 
     @Test
-    public void testNonBlockingReadChunked() throws Exception {
+    public void testNonBlockingReadChunkedNoSplits() throws Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitBeforeChunkHeader() throws 
Exception {
+        String[] requestBody = new String[] {
+                "",
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitInChunkHeader() throws 
Exception {
+        String[] requestBody = new String[] {
+                "1",
+                "4" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitAfterChunkHeader() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14",
+                SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitInHeaderCrlf() throws Exception 
{
+        String[] requestBody = new String[] {
+                "14\r",
+                "\n" +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitAfterHeaderCrlf() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF,
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitBeforeExtensionDelimter() 
throws Exception {
+        String[] requestBody = new String[] {
+                "14",
+                ";a=b" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitAfterExtensionDelimter() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14;",
+                "a=b" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitInExtension() throws Exception {
+        String[] requestBody = new String[] {
+                "14;a",
+                "=b" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitAfterExtension() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14;a=b",
+                SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitInChunkBody() throws Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345",
+                "678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitBeforeChunkBodyCrlf() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED",
+                SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitInChunkBodyCrlf() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED\r",
+                "\n" +
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitAfterChunkBodyCrlf() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF,
+                "0" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitBeforeEndChunkCrlf() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0",
+                SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitInEndChunkCrlf() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" +
+                "\r",
+                "\n" +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitAfterEndChunkCrlf() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" +
+                SimpleHttpClient.CRLF,
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitBeforeTrailer() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF,
+                TRAILER_HEADER_NAME + ": " + TRAILER_HEADER_VALUE + 
SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody, TRAILER_HEADER_VALUE);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitInTrailerName() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                "x-te",
+                "st" + ": " + TRAILER_HEADER_VALUE + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody, TRAILER_HEADER_VALUE);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitAfterTrailerName() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                TRAILER_HEADER_NAME,
+                ": " + TRAILER_HEADER_VALUE + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody, TRAILER_HEADER_VALUE);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitAfterTrailerDelimter() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                TRAILER_HEADER_NAME + ":",
+                " " + TRAILER_HEADER_VALUE + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody, TRAILER_HEADER_VALUE);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitBeforeTrailerValue() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                TRAILER_HEADER_NAME + ": ",
+                TRAILER_HEADER_VALUE + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody, TRAILER_HEADER_VALUE);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitInTrailerValue() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                TRAILER_HEADER_NAME + ": abc",
+                "de" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody, TRAILER_HEADER_VALUE);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitAfterTrailerValue() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                TRAILER_HEADER_NAME + ": " + TRAILER_HEADER_VALUE,
+                SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody, TRAILER_HEADER_VALUE);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitInTrailerCrlf() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                TRAILER_HEADER_NAME + ": " + TRAILER_HEADER_VALUE + "\r",
+                "\n" +
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody, TRAILER_HEADER_VALUE);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitAfterTrailerCrlf() throws 
Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                TRAILER_HEADER_NAME + ": " + TRAILER_HEADER_VALUE + 
SimpleHttpClient.CRLF,
+                SimpleHttpClient.CRLF};
+
+        doTestNonBlockingReadChunked(requestBody, TRAILER_HEADER_VALUE);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitInFinalCrlf() throws Exception {
+        String[] requestBody = new String[] {
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" +
+                SimpleHttpClient.CRLF +
+                "\r",
+                "\n"};
+
+        doTestNonBlockingReadChunked(requestBody);
+    }
+
+
+    @Test
+    public void testNonBlockingReadChunkedSplitMaximum() throws Exception {
+        String requestBody = new String(
+                "14" + SimpleHttpClient.CRLF +
+                "012345678901FINISHED" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                TRAILER_HEADER_NAME + ": " + TRAILER_HEADER_VALUE + 
SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF);
+
+        String[] requestBodySplit = new String[requestBody.length()];
+        for (int i = 0; i < requestBody.length(); i++) {
+            requestBodySplit[i] = Character.toString(requestBody.charAt(i));
+        }
+
+        doTestNonBlockingReadChunked(requestBodySplit, TRAILER_HEADER_VALUE);
+    }
+
+
+    private void doTestNonBlockingReadChunked(String[] requestBody) throws 
Exception {
+        doTestNonBlockingReadChunked(requestBody, null);
+    }
+
+
+    private void doTestNonBlockingReadChunked(String[] requestBody, String 
expectedTrailerFieldValue) throws Exception {
         Tomcat tomcat = getTomcatInstance();
 
         // No file system docBase required
         Context ctx = getProgrammaticRootContext();
 
-        NBReadServlet servlet = new NBReadServlet(false, true);
+        NBReadServlet servlet = new NBReadServlet(false, true, 
expectedTrailerFieldValue);
         String servletName = NBReadServlet.class.getName();
         Tomcat.addServlet(ctx, servletName, servlet);
         ctx.addServletMappingDecoded("/", servletName);
 
+        tomcat.getConnector().setProperty("allowedTrailerHeaders", 
TRAILER_HEADER_NAME);
+
         tomcat.start();
 
+        // Add the headers to the first part of the chunked body
+        requestBody[0] =
+                "GET / HTTP/1.1" + SimpleHttpClient.CRLF +
+                "Host: localhost" + getPort() + SimpleHttpClient.CRLF +
+                "Transfer-Encoding: chunked" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF +
+                requestBody[0];
+
         Client client = new Client();
         client.setPort(getPort());
-        client.setRequest(new String[] { "GET / HTTP/1.1" + 
SimpleHttpClient.CRLF +
-                                         "Host: localhost:" + getPort() + 
SimpleHttpClient.CRLF +
-                                         "Transfer-Encoding: chunked" + 
SimpleHttpClient.CRLF +
-                                         SimpleHttpClient.CRLF +
-                                         "14" + SimpleHttpClient.CRLF +
-                                         "01234567890123456789" + 
SimpleHttpClient.CRLF +
-                                         "14" + SimpleHttpClient.CRLF +
-                                         "012345678901FINISHED" + 
SimpleHttpClient.CRLF +
-                                         "0" + SimpleHttpClient.CRLF +
-                                         SimpleHttpClient.CRLF});
+        client.setRequest(requestBody);
+        /*
+         *  Reduce default pause to speed up test execution. Pause only needs 
to be long enough that each part of the
+         *  request is read separately.
+         */
+        client.setRequestPause(200);
         client.connect();
         client.sendRequest();
 
@@ -575,11 +963,13 @@ public class TestNonBlockingAPI extends TomcatBaseTest {
         private static final long serialVersionUID = 1L;
         private final boolean async;
         private final boolean ignoreIsReady;
+        private final String expectedTrailerFieldValue;
         transient TestReadListener listener;
 
-        public NBReadServlet(boolean ignoreIsReady, boolean async) {
+        public NBReadServlet(boolean ignoreIsReady, boolean async, String 
expectedTrailerFieldValue) {
             this.async = async;
             this.ignoreIsReady = ignoreIsReady;
+            this.expectedTrailerFieldValue = expectedTrailerFieldValue;
         }
 
         @Override
@@ -616,9 +1006,9 @@ public class TestNonBlockingAPI extends TomcatBaseTest {
             // step 2 - notify on read
             ServletInputStream in = req.getInputStream();
             if (async) {
-                listener = new TestAsyncReadListener(actx, false, 
ignoreIsReady);
+                listener = new TestAsyncReadListener(actx, false, 
ignoreIsReady, expectedTrailerFieldValue);
             } else {
-                listener = new TestReadListener(actx, false, ignoreIsReady);
+                listener = new TestReadListener(actx, false, ignoreIsReady, 
expectedTrailerFieldValue);
             }
             in.setReadListener(listener);
         }
@@ -707,15 +1097,18 @@ public class TestNonBlockingAPI extends TomcatBaseTest {
         protected final AsyncContext ctx;
         protected final boolean usingNonBlockingWrite;
         protected final boolean ignoreIsReady;
+        protected final String expectedTrailerFieldValue;
         protected final StringBuilder body = new StringBuilder();
 
 
         TestReadListener(AsyncContext ctx,
                 boolean usingNonBlockingWrite,
-                boolean ignoreIsReady) {
+                boolean ignoreIsReady,
+                String expectedTrailerFieldValue) {
             this.ctx = ctx;
             this.usingNonBlockingWrite = usingNonBlockingWrite;
             this.ignoreIsReady = ignoreIsReady;
+            this.expectedTrailerFieldValue = expectedTrailerFieldValue;
         }
 
         @Override
@@ -743,7 +1136,14 @@ public class TestNonBlockingAPI extends TomcatBaseTest {
             if (!usingNonBlockingWrite) {
                 String msg;
                 if (body.toString().endsWith("FINISHED")) {
-                    msg = "OK";
+                    String trailerFieldValue = ((HttpServletRequest) 
ctx.getRequest()).getTrailerFields().get("x-test");
+                    if (trailerFieldValue == null && expectedTrailerFieldValue 
== null ||
+                            trailerFieldValue != null && 
trailerFieldValue.equals(expectedTrailerFieldValue)) {
+                        msg = "OK";
+                    } else {
+                        System.out.println("Trailer value was [" + 
trailerFieldValue + "]");
+                        msg = "FAILED";
+                    }
                 } else {
                     msg = "FAILED";
                 }
@@ -770,9 +1170,9 @@ public class TestNonBlockingAPI extends TomcatBaseTest {
         AtomicInteger containerThreadCount = new AtomicInteger(0);
         AtomicInteger nonContainerThreadCount = new AtomicInteger(0);
 
-        TestAsyncReadListener(AsyncContext ctx,
-                boolean usingNonBlockingWrite, boolean ignoreIsReady) {
-            super(ctx, usingNonBlockingWrite, ignoreIsReady);
+        TestAsyncReadListener(AsyncContext ctx, boolean usingNonBlockingWrite, 
boolean ignoreIsReady,
+                String expectedTrailerFieldValue) {
+            super(ctx, usingNonBlockingWrite, ignoreIsReady, 
expectedTrailerFieldValue);
         }
 
         @Override
diff --git a/test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java 
b/test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java
index 4cb41304df..9a0d41eff6 100644
--- a/test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java
+++ b/test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java
@@ -30,6 +30,7 @@ import org.junit.Test;
 
 import org.apache.catalina.Context;
 import org.apache.catalina.startup.SimpleHttpClient;
+import org.apache.catalina.startup.TesterServlet;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
 
@@ -65,7 +66,7 @@ public class TestChunkedInputFilter extends TomcatBaseTest {
 
     @Test
     public void testFirstTrailingHeadersLF() throws Exception {
-        doTestChunkingCRLF(true, true, false, true, true, true);
+        doTestChunkingCRLF(true, true, false, true, true, false);
     }
 
     @Test
@@ -75,7 +76,7 @@ public class TestChunkedInputFilter extends TomcatBaseTest {
 
     @Test
     public void testSecondTrailingHeadersLF() throws Exception {
-        doTestChunkingCRLF(true, true, true, false, true, true);
+        doTestChunkingCRLF(true, true, true, false, true, false);
     }
 
     @Test
@@ -157,8 +158,54 @@ public class TestChunkedInputFilter extends TomcatBaseTest 
{
         }
     }
 
+
+    @Test
+    public void testTrailingHeadersSizeLimitBelowLimit() throws Exception {
+        doTestTrailingHeadersSizeLimit(17, "x-trailer: Test", false);
+    }
+
+
+    @Test
+    public void testTrailingHeadersSizeLimitAtLimit() throws Exception {
+        doTestTrailingHeadersSizeLimit(18, "x-trailer: Test", false);
+    }
+
+
+    @Test
+    public void testTrailingHeadersSizeLimitAboveLimit() throws Exception {
+        doTestTrailingHeadersSizeLimit(19, "x-trailer: Test", true);
+    }
+
+
+    /*
+     * This test uses the fact that the header is simply concatenated to 
insert a pipelined request. The pipelined
+     * request should not trigger the trailing header size limit. Note that 19 
is just enough for the first request.
+     */
     @Test
-    public void testTrailingHeadersSizeLimit() throws Exception {
+    public void testTrailingHeadersSizeLimitPipelining() throws Exception {
+        doTestTrailingHeadersSizeLimit(19,
+                "x-trailer: Test" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF +
+                "POST /echo-params.jsp HTTP/1.1" + SimpleHttpClient.CRLF +
+                "Host: any" + SimpleHttpClient.CRLF +
+                "Transfer-encoding: chunked" + SimpleHttpClient.CRLF +
+                "Content-Type: application/x-www-form-urlencoded" + 
SimpleHttpClient.CRLF +
+                "Connection: close" + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF +
+                "3" + SimpleHttpClient.CRLF +
+                "a=0" + SimpleHttpClient.CRLF +
+                "4" + SimpleHttpClient.CRLF +
+                "&b=1" + SimpleHttpClient.CRLF +
+                "0" + SimpleHttpClient.CRLF +
+                "x-trailer: Test",
+                true);
+    }
+
+
+    /*
+     * Since limit includes CRLF at end of trailer and final CRLF
+     */
+    private void doTestTrailingHeadersSizeLimit(int trailerSizeLimit, String 
trailerHeader, boolean pass) throws Exception {
         // Setup Tomcat instance
         Tomcat tomcat = getTomcatInstance();
 
@@ -169,15 +216,14 @@ public class TestChunkedInputFilter extends 
TomcatBaseTest {
         ctx.addServletMappingDecoded("/", "servlet");
 
         // Limit the size of the trailing header
-        Assert.assertTrue(tomcat.getConnector().setProperty("maxTrailerSize", 
"10"));
+        Assert.assertTrue(tomcat.getConnector().setProperty("maxTrailerSize", 
Integer.toString(trailerSizeLimit)));
         tomcat.start();
 
         String[] request = new String[]{
             "POST /echo-params.jsp HTTP/1.1" + SimpleHttpClient.CRLF +
             "Host: any" + SimpleHttpClient.CRLF +
             "Transfer-encoding: chunked" + SimpleHttpClient.CRLF +
-            "Content-Type: application/x-www-form-urlencoded" +
-                    SimpleHttpClient.CRLF +
+            "Content-Type: application/x-www-form-urlencoded" + 
SimpleHttpClient.CRLF +
             "Connection: close" + SimpleHttpClient.CRLF +
             SimpleHttpClient.CRLF +
             "3" + SimpleHttpClient.CRLF +
@@ -185,7 +231,7 @@ public class TestChunkedInputFilter extends TomcatBaseTest {
             "4" + SimpleHttpClient.CRLF +
             "&b=1" + SimpleHttpClient.CRLF +
             "0" + SimpleHttpClient.CRLF +
-            "x-trailer: Test" + SimpleHttpClient.CRLF +
+            trailerHeader + SimpleHttpClient.CRLF +
             SimpleHttpClient.CRLF };
 
         TrailerClient client =
@@ -194,9 +240,11 @@ public class TestChunkedInputFilter extends TomcatBaseTest 
{
 
         client.connect();
         client.processRequest();
-        // Expected to fail because the trailers are longer
-        // than the set limit of 10 bytes
-        Assert.assertTrue(client.isResponse500());
+        if (pass) {
+            Assert.assertTrue(client.isResponse200());
+        } else {
+            Assert.assertTrue(client.isResponse500());
+        }
     }
 
 
@@ -621,4 +669,112 @@ public class TestChunkedInputFilter extends 
TomcatBaseTest {
             return getResponseBody().contains("TestTestTest");
         }
     }
+
+
+    @Test
+    public void doTestIncompleteChunkedBody() throws Exception {
+
+        // Setup Tomcat instance
+        Tomcat tomcat = getTomcatInstance();
+
+        // No file system docBase required
+        Context ctx = getProgrammaticRootContext();
+
+        Tomcat.addServlet(ctx, "servlet", new SwallowBodyServlet(false));
+        ctx.addServletMappingDecoded("/", "servlet");
+
+        tomcat.start();
+
+        String[] request = new String[]{
+            "POST / HTTP/1.1" + SimpleHttpClient.CRLF +
+            "Host: localhost" + SimpleHttpClient.CRLF +
+            "Transfer-encoding: chunked" + SimpleHttpClient.CRLF +
+            SimpleHttpClient.CRLF +
+            "3" + SimpleHttpClient.CRLF };
+
+        TrailerClient client = new 
TrailerClient(tomcat.getConnector().getLocalPort());
+        client.setUseContentLength(true);
+
+        client.setRequest(request);
+        client.connect();
+        try {
+            client.processRequest();
+        } catch (IOException ioe) {
+            // Ignore - Triggered by connection being dropped after error
+        }
+        // NIO2 may (will?) return null here
+        String responseLine = client.getResponseLine();
+        if (responseLine == null) {
+            // 400 response not read(/written?) before connection was dropped.
+        } else {
+            Assert.assertTrue(client.getResponseLine(), 
client.isResponse400());
+        }
+    }
+
+
+    @Test
+    public void doTestMaxSwallowSizeBelow() throws Exception {
+        doTestMaxSwallowSize(1000, true);
+    }
+
+
+    @Test
+    public void doTestMaxSwallowSizeAbove() throws Exception {
+        doTestMaxSwallowSize(10, false);
+    }
+
+
+    private void doTestMaxSwallowSize(int maxSwallowSize, boolean pass) throws 
Exception {
+
+        // Setup Tomcat instance
+        Tomcat tomcat = getTomcatInstance();
+
+        tomcat.getConnector().setProperty("connectionTimeout", "300000");
+        // Reduce limits to facilitate testing
+        tomcat.getConnector().setProperty("maxSwallowSize", 
Integer.toString(maxSwallowSize));
+
+        // No file system docBase required
+        Context ctx = getProgrammaticRootContext();
+
+        Tomcat.addServlet(ctx, "servlet", new TesterServlet(false));
+        ctx.addServletMappingDecoded("/", "servlet");
+
+        tomcat.start();
+
+        String[] request = new String[]{
+            "GET / HTTP/1.1" + SimpleHttpClient.CRLF +
+            "Host: localhost" + SimpleHttpClient.CRLF +
+            "Transfer-encoding: chunked" + SimpleHttpClient.CRLF +
+            SimpleHttpClient.CRLF +
+            "20" + SimpleHttpClient.CRLF +
+            "01234567890123456789012345678901" + SimpleHttpClient.CRLF +
+            "0" + SimpleHttpClient.CRLF +
+            SimpleHttpClient.CRLF };
+
+        TrailerClient client = new 
TrailerClient(tomcat.getConnector().getLocalPort());
+        client.setUseContentLength(true);
+
+        client.setRequest(request);
+        client.connect();
+        client.sendRequest();
+        client.readResponse(true);
+
+        // Response is committed before connection is closed.
+        Assert.assertTrue(client.getResponseLine(), client.isResponse200());
+
+        // Repeat request - should fail
+        client.resetResponse();
+        client.sendRequest();
+        try {
+            client.readResponse(true);
+        } catch (IOException ioe) {
+            // Ignore - in case the read fails due to a closed connection
+        }
+        if (pass) {
+            Assert.assertTrue(client.getResponseLine(), 
client.isResponse200());
+        } else {
+            // Connection reset
+            Assert.assertNull(client.getResponseLine());
+        }
+    }
 }


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

Reply via email to