This is an automated email from the ASF dual-hosted git repository. markt-asf pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 34bb364cf1aefa4bb2bc594ef21b5feff73eefff Author: Mark Thomas <[email protected]> AuthorDate: Fri Jun 5 19:15:37 2026 +0100 Add tests for trailing header size limit written by CoPilot / GPT-5.4 --- .../http11/filters/TestChunkedInputFilter.java | 108 +++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java b/test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java index 6e72520cd1..cc595a31e0 100644 --- a/test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java +++ b/test/org/apache/coyote/http11/filters/TestChunkedInputFilter.java @@ -46,6 +46,7 @@ import org.apache.catalina.startup.TomcatBaseTest; public class TestChunkedInputFilter extends TomcatBaseTest { private static final int EXT_SIZE_LIMIT = 10; + private static final int TRAILER_SIZE_LIMIT = 8 * 1024; @Test public void testChunkHeaderCRLF() throws Exception { @@ -187,6 +188,71 @@ public class TestChunkedInputFilter extends TomcatBaseTest { } + @Test + public void testTrailingHeadersSizeLimitReadByServletOver8k() throws Exception { + Tomcat tomcat = getTomcatInstance(); + + Context ctx = getProgrammaticRootContext(); + + BodyReadServlet servlet = new BodyReadServlet(false, Integer.MAX_VALUE); + Tomcat.addServlet(ctx, "servlet", servlet); + ctx.addServletMappingDecoded("/", "servlet"); + + tomcat.start(); + + TrailerClient client = new TrailerClient(tomcat.getConnector().getLocalPort()); + client.setRequest(createChunkedRequest(createTrailerHeader(TRAILER_SIZE_LIMIT + 1), true)); + + client.connect(); + Exception processException = null; + try { + client.processRequest(); + } catch (Exception e) { + processException = e; + } + + Assert.assertEquals(7, servlet.getCountRead()); + Assert.assertTrue(servlet.getExceptionDuringRead()); + if (processException == null) { + Assert.assertTrue(client.getResponseLine(), client.isResponse500()); + } + } + + + @Test + public void testTrailingHeadersSizeLimitSwallowedOver8k() throws Exception { + Tomcat tomcat = getTomcatInstance(); + + Context ctx = getProgrammaticRootContext(); + + Tomcat.addServlet(ctx, "servlet", new CommitResponseServlet()); + ctx.addServletMappingDecoded("/", "servlet"); + + tomcat.start(); + + TrailerClient client = new TrailerClient(tomcat.getConnector().getLocalPort()); + client.setUseContentLength(true); + client.setRequest(createChunkedRequest(createTrailerHeader(TRAILER_SIZE_LIMIT + 1), false)); + + client.connect(); + client.sendRequest(); + client.readResponse(true); + + Assert.assertTrue(client.getResponseLine(), client.isResponse200()); + Assert.assertEquals("OK", client.getResponseBody()); + + client.resetResponse(); + try { + client.sendRequest(); + client.readResponse(true); + } catch (IOException ioe) { + // Ignore - in case the read fails due to a closed connection + } + + Assert.assertNull(client.getResponseLine()); + } + + /* * 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. @@ -263,6 +329,35 @@ public class TestChunkedInputFilter extends TomcatBaseTest { } + private String[] createChunkedRequest(String trailerHeader, boolean closeConnection) { + String connectionHeader = closeConnection ? "Connection: close" + CRLF : ""; + + // @formatter:off + return new String[] { + "POST / HTTP/1.1" + CRLF + + "Host: localhost" + CRLF + + "Transfer-encoding: chunked" + CRLF + + SimpleHttpClient.HTTP_HEADER_CONTENT_TYPE_FORM_URL_ENCODING + + connectionHeader + + CRLF + + "3" + CRLF + + "a=0" + CRLF + + "4" + CRLF + + "&b=1" + CRLF + + "0" + CRLF + + trailerHeader + CRLF + + CRLF + }; + // @formatter:on + } + + + private String createTrailerHeader(int totalTrailerSize) { + int valueSize = totalTrailerSize - "x-trailer: ".length() - (2 * CRLF.length()); + return "x-trailer: " + "x".repeat(valueSize); + } + + @Test public void testExtensionSizeLimitOneBelow() throws Exception { doTestExtensionSizeLimit(EXT_SIZE_LIMIT - 1, true); @@ -577,6 +672,19 @@ public class TestChunkedInputFilter extends TomcatBaseTest { } } + private static class CommitResponseServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setContentType("text/plain"); + resp.setContentLength(2); + resp.getWriter().write("OK"); + resp.flushBuffer(); + } + } + private static class EchoHeaderServlet extends HttpServlet { private static final long serialVersionUID = 1L; --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
