This is an automated email from the ASF dual-hosted git repository. dsoumis pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit aec8d5c6af5bab35e13cd4a07f25388aed916eef Author: Dimitris Soumis <[email protected]> AuthorDate: Thu Feb 19 20:45:24 2026 +0200 Add TestLargePayloadWithProxy and TestChunkedTransferEncodingWithProxy --- .../apache/catalina/startup/TomcatBaseTest.java | 2 +- .../TestChunkedTransferEncodingWithProxy.java | 96 ++++++++++++++++++ .../httpd/TestLargePayloadWithProxy.java | 111 +++++++++++++++++++++ 3 files changed, 208 insertions(+), 1 deletion(-) diff --git a/test/org/apache/catalina/startup/TomcatBaseTest.java b/test/org/apache/catalina/startup/TomcatBaseTest.java index eb1e320a86..10631c5af6 100644 --- a/test/org/apache/catalina/startup/TomcatBaseTest.java +++ b/test/org/apache/catalina/startup/TomcatBaseTest.java @@ -599,7 +599,7 @@ public abstract class TomcatBaseTest extends LoggingBaseTest { } int bodySize = 0; - if (Method.PUT.equals(request.getMethod())) { + if (Method.PUT.equals(request.getMethod()) || Method.POST.equals(request.getMethod())) { InputStream is = request.getInputStream(); int read = 0; byte[] buffer = new byte[8192]; diff --git a/test/org/apache/tomcat/integration/httpd/TestChunkedTransferEncodingWithProxy.java b/test/org/apache/tomcat/integration/httpd/TestChunkedTransferEncodingWithProxy.java new file mode 100644 index 0000000000..f051a4ad2c --- /dev/null +++ b/test/org/apache/tomcat/integration/httpd/TestChunkedTransferEncodingWithProxy.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.integration.httpd; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jakarta.servlet.http.HttpServletResponse; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.catalina.Valve; +import org.apache.catalina.startup.BytesStreamer; +import org.apache.tomcat.util.buf.ByteChunk; + +public class TestChunkedTransferEncodingWithProxy extends HttpdIntegrationBaseTest { + + private static final int PAYLOAD_SIZE = 10 * 1024 * 1024 * 100; + + private static final String HTTPD_CONFIG = """ + LoadModule env_module modules/mod_env.so \s + SetEnv proxy-sendchunked 1 + LoadModule proxy_module modules/mod_proxy.so + LoadModule proxy_http_module modules/mod_proxy_http.so + ProxyPass /endpoint http://localhost:%{TOMCAT_PORT}/%{SERVLET_NAME} + ProxyPassReverse /endpoint http://localhost:%{TOMCAT_PORT}/%{SERVLET_NAME} + """; + + @Override + protected List<Valve> getValveConfig() { + return new ArrayList<>(); + } + + @Override + protected String getHttpdConfig() { + return HTTPD_CONFIG; + } + + /** + * Verify that chunked transfer encoding works correctly through the httpd reverse proxy + * which sets proxy-sendchunked to minimize resource usage by using chunked encoding. + */ + @Test + public void testChunkedTransferEncoding() throws Exception { + byte[] payload = new byte[PAYLOAD_SIZE]; + Arrays.fill(payload, (byte) 'A'); + + BytesStreamer streamer = new BytesStreamer() { + private boolean sent = false; + + @Override + public int getLength() { + return -1; + } + + @Override + public int available() { + return sent ? 0 : payload.length; + } + + @Override + public byte[] next() { + sent = true; + return payload; + } + }; + + ByteChunk res = new ByteChunk(); + Map<String, List<String>> reqHead = new HashMap<>(); + reqHead.put("Content-Type", List.of("application/octet-stream")); + int rc = postUrl(true, streamer, "http://localhost:" + getHttpdPort() + "/endpoint", res, reqHead, null); + Assert.assertEquals(HttpServletResponse.SC_OK, rc); + + RequestDescriptor requestDesc = SnoopResult.parse(res.toString()); + Assert.assertEquals(String.valueOf(PAYLOAD_SIZE), requestDesc.getRequestInfo("REQUEST-BODY-SIZE")); + } +} diff --git a/test/org/apache/tomcat/integration/httpd/TestLargePayloadWithProxy.java b/test/org/apache/tomcat/integration/httpd/TestLargePayloadWithProxy.java new file mode 100644 index 0000000000..992d0ce6dd --- /dev/null +++ b/test/org/apache/tomcat/integration/httpd/TestLargePayloadWithProxy.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.integration.httpd; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jakarta.servlet.http.HttpServletResponse; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.catalina.Valve; +import org.apache.catalina.startup.BytesStreamer; +import org.apache.tomcat.util.buf.ByteChunk; + +public class TestLargePayloadWithProxy extends HttpdIntegrationBaseTest { + + private static final int PAYLOAD_SIZE = 10 * 1024 * 1024; + + private static final String HTTPD_CONFIG = """ + LoadModule proxy_module modules/mod_proxy.so + LoadModule proxy_http_module modules/mod_proxy_http.so + ProxyPass /endpoint http://localhost:%{TOMCAT_PORT}/%{SERVLET_NAME} + ProxyPassReverse /endpoint http://localhost:%{TOMCAT_PORT}/%{SERVLET_NAME} + """; + + @Override + protected List<Valve> getValveConfig() { + return new ArrayList<>(); + } + + @Override + protected String getHttpdConfig() { + return HTTPD_CONFIG; + } + + /** + * Verify that a large POST body passes through the httpd reverse proxy + */ + @Test + public void testLargePostBody() throws Exception { + byte[] payload = new byte[PAYLOAD_SIZE]; + Arrays.fill(payload, (byte) 'A'); + + ByteChunk res = new ByteChunk(); + Map<String, List<String>> reqHead = new HashMap<>(); + reqHead.put("Content-Type", List.of("application/octet-stream")); + int rc = postUrl(payload, "http://localhost:" + getHttpdPort() + "/endpoint", res, reqHead, null); + Assert.assertEquals(HttpServletResponse.SC_OK, rc); + + RequestDescriptor requestDesc = SnoopResult.parse(res.toString()); + Assert.assertEquals(String.valueOf(PAYLOAD_SIZE), requestDesc.getRequestInfo("REQUEST-BODY-SIZE")); + } + + /** + * Verify that chunked transfer encoding works correctly through the httpd reverse proxy. + */ + @Test + public void testChunkedTransferEncoding() throws Exception { + byte[] payload = new byte[PAYLOAD_SIZE]; + Arrays.fill(payload, (byte) 'A'); + + BytesStreamer streamer = new BytesStreamer() { + private boolean sent = false; + + @Override + public int getLength() { + return -1; + } + + @Override + public int available() { + return sent ? 0 : payload.length; + } + + @Override + public byte[] next() { + sent = true; + return payload; + } + }; + + ByteChunk res = new ByteChunk(); + Map<String, List<String>> reqHead = new HashMap<>(); + reqHead.put("Content-Type", List.of("application/octet-stream")); + int rc = postUrl(true, streamer, "http://localhost:" + getHttpdPort() + "/endpoint", res, reqHead, null); + Assert.assertEquals(HttpServletResponse.SC_OK, rc); + + RequestDescriptor requestDesc = SnoopResult.parse(res.toString()); + Assert.assertEquals(String.valueOf(PAYLOAD_SIZE), requestDesc.getRequestInfo("REQUEST-BODY-SIZE")); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
