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

rzo1 pushed a commit to branch tomee-10.x
in repository https://gitbox.apache.org/repos/asf/tomee.git

commit 62b760424408b4c7ead8834e1165143c97996701
Author: Markus Jung <[email protected]>
AuthorDate: Fri Aug 21 21:21:31 2026 +0200

    align embedded http request body handling with Tomcat
    
    (cherry picked from commit 672e32f6c61537142bc114c75a89259ee7b8f116)
---
 .../openejb/server/httpd/HttpRequestImpl.java      | 47 +++++++++++++++++++---
 .../openejb/server/httpd/HttpRequestImplTest.java  | 39 ++++++++++++++++++
 2 files changed, 80 insertions(+), 6 deletions(-)

diff --git 
a/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java
 
b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java
index 910cd184cd..401877d696 100644
--- 
a/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java
+++ 
b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java
@@ -76,6 +76,8 @@ public class HttpRequestImpl implements HttpRequest {
     private static final String MULTIPART_FORM_DATA = "multipart/form-data";
     private static final String TRANSFER_ENCODING = "Transfer-Encoding";
     private static final String CHUNKED = "chunked";
+    private static final String MAX_BODY_SIZE_PROPERTY = 
"openejb.http.request.max-body-size";
+    private static final int DEFAULT_MAX_BODY_SIZE = 2 * 1024 * 1024; // 
bytes, aligned with Tomcat's maxPostSize default
 
     public static final Class<?>[] SERVLET_CONTEXT_INTERFACES = new 
Class<?>[]{ServletContext.class};
     public static final InvocationHandler SERVLET_CONTEXT_HANDLER = (proxy, 
method, args) -> null;
@@ -684,6 +686,12 @@ public class HttpRequestImpl implements HttpRequest {
         // or multipart/form-data
         length = parseContentLength();
 
+        final int maxBodySize = getMaxBodySize();
+        if (length > maxBodySize) {
+            throw new IOException("Content-Length " + length + " exceeds the 
maximum allowed request body size (" +
+                maxBodySize + " bytes), set the '" + MAX_BODY_SIZE_PROPERTY + 
"' property to raise the limit");
+        }
+
         contentType = getHeader(HttpRequest.HEADER_CONTENT_TYPE);
 
         final boolean hasBody = hasBody();
@@ -725,6 +733,7 @@ public class HttpRequestImpl implements HttpRequest {
         } else if (hasBody && CHUNKED.equals(getHeader(TRANSFER_ENCODING))) {
             try {
                 ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
+                final byte[] buffer = new byte[4096];
                 for (String line = in.readLine(); line != null; line = 
in.readLine()) {
                     // read the size line which is in hex
                     String sizeString = line.split(";", 2)[0];
@@ -733,10 +742,19 @@ public class HttpRequestImpl implements HttpRequest {
                     // if size is 0 we are done
                     if (size == 0) break;
 
+                    if (size < 0 || size > maxBodySize - out.size()) {
+                        throw new IOException("Chunked request body exceeds 
the maximum allowed request body size (" +
+                            maxBodySize + " bytes), set the '" + 
MAX_BODY_SIZE_PROPERTY + "' property to raise the limit");
+                    }
+
                     // read the chunk and append to byte array
-                    byte[] chunk = new byte[size];
-                    in.readFully(chunk);
-                    out.write(chunk);
+                    int remaining = size;
+                    while (remaining > 0) {
+                        final int len = Math.min(remaining, buffer.length);
+                        in.readFully(buffer, 0, len);
+                        out.write(buffer, 0, len);
+                        remaining -= len;
+                    }
 
                     // read off the trailing new line characters after the 
chunk
                     in.readLine();
@@ -759,10 +777,18 @@ public class HttpRequestImpl implements HttpRequest {
 
     private byte[] readContent(DataInput in) throws IOException {
         if (length >= 0) {
-            byte[] body = new byte[length];
-            in.readFully(body);
-            return body;
+            final ByteArrayOutputStream out = new 
ByteArrayOutputStream(Math.min(length, 4096));
+            final byte[] buffer = new byte[4096];
+            int remaining = length;
+            while (remaining > 0) {
+                final int len = Math.min(remaining, buffer.length);
+                in.readFully(buffer, 0, len);
+                out.write(buffer, 0, len);
+                remaining -= len;
+            }
+            return out.toByteArray();
         } else {
+            final int maxBodySize = getMaxBodySize();
             ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
             try {
                 boolean atLineStart = true;
@@ -785,6 +811,11 @@ public class HttpRequestImpl implements HttpRequest {
                         atLineStart = false;
                     }
                     out.write(b);
+
+                    if (out.size() > maxBodySize) {
+                        throw new IOException("Request body exceeds the 
maximum allowed request body size (" +
+                            maxBodySize + " bytes), set the '" + 
MAX_BODY_SIZE_PROPERTY + "' property to raise the limit");
+                    }
                 }
             } catch (EOFException e) {
                 // done reading
@@ -794,6 +825,10 @@ public class HttpRequestImpl implements HttpRequest {
         }
     }
 
+    private static int getMaxBodySize() {
+        return SystemInstance.get().getOptions().get(MAX_BODY_SIZE_PROPERTY, 
DEFAULT_MAX_BODY_SIZE);
+    }
+
     private int parseContentLength() {
         // Content-length: 384
         String len = getHeader(HttpRequest.HEADER_CONTENT_LENGTH);
diff --git 
a/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/HttpRequestImplTest.java
 
b/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/HttpRequestImplTest.java
index dac71bd841..afc33490da 100644
--- 
a/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/HttpRequestImplTest.java
+++ 
b/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/HttpRequestImplTest.java
@@ -22,12 +22,17 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 public class HttpRequestImplTest {
     @Before
@@ -63,4 +68,38 @@ public class HttpRequestImplTest {
         req.initPathFromContext("/api/bar"); // that's too late we tolerate a 
wrong context only if its value is "/"
         assertEquals("/foo/bar", req.getServletPath());
     }
+
+    @Test
+    public void oversizedContentLengthRejected() throws Exception {
+        final HttpRequestImpl req = new HttpRequestImpl(new 
URI("http://localhost:1234/foo";));
+        final String message = "POST /foo HTTP/1.1\r\nContent-Length: 
2147483647\r\n\r\n";
+        try {
+            req.readMessage(new 
ByteArrayInputStream(message.getBytes(StandardCharsets.ISO_8859_1)));
+            fail("Should have rejected the oversized Content-Length");
+        } catch (final IOException expected) {
+            assertTrue(expected.getMessage(), 
expected.getMessage().contains("maximum allowed request body size"));
+        }
+    }
+
+    @Test
+    public void oversizedChunkRejected() throws Exception {
+        final HttpRequestImpl req = new HttpRequestImpl(new 
URI("http://localhost:1234/foo";));
+        final String message = "POST /foo HTTP/1.1\r\nTransfer-Encoding: 
chunked\r\n\r\n7fffffff\r\n";
+        try {
+            req.readMessage(new 
ByteArrayInputStream(message.getBytes(StandardCharsets.ISO_8859_1)));
+            fail("Should have rejected the oversized chunk");
+        } catch (final IOException expected) {
+            assertTrue(expected.getMessage(), expected.getCause() instanceof 
IOException
+                && expected.getCause().getMessage().contains("maximum allowed 
request body size"));
+        }
+    }
+
+    @Test
+    public void smallBodyStillRead() throws Exception {
+        final HttpRequestImpl req = new HttpRequestImpl(new 
URI("http://localhost:1234/foo";));
+        final String message = "POST /foo HTTP/1.1\r\nContent-Type: 
application/x-www-form-urlencoded\r\nContent-Length: 7\r\n\r\na=1&b=2";
+        assertTrue(req.readMessage(new 
ByteArrayInputStream(message.getBytes(StandardCharsets.ISO_8859_1))));
+        assertEquals("1", req.getParameter("a"));
+        assertEquals("2", req.getParameter("b"));
+    }
 }

Reply via email to