From e8c62650ce36bddbbcb429dc011199fb9c114499 Mon Sep 17 00:00:00 2001 From: Julian Reschke Date: Fri, 12 Jun 2026 18:51:22 +0100 Subject: [PATCH 1/2] JCR-5233: commons-fileupload (1.6) restricts header size in upload parts - bump up the default and a system property knob --- .../jackrabbit/server/util/HttpMultipartPost.java | 3 +++ .../jackrabbit/server/util/RequestDataTest.java | 12 ++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/util/HttpMultipartPost.java b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/util/HttpMultipartPost.java index ac9c44b2930..9d71f38baab 100644 --- a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/util/HttpMultipartPost.java +++ b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/util/HttpMultipartPost.java @@ -69,6 +69,9 @@ private void extractMultipart(HttpServletRequest request, File tmpDir) ServletFileUpload upload = new ServletFileUpload(getFileItemFactory(tmpDir)); if (PARTHEADERSIZEMAX > 0) { upload.setPartHeaderSizeMax(PARTHEADERSIZEMAX); + } else { + // override the default limit of 512 in commons-fileupload 1.6 + upload.setPartHeaderSizeMax(4096); } // make sure the content disposition headers are read with the charset // specified in the request content type (or UTF-8 if no charset is specified). diff --git a/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/util/RequestDataTest.java b/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/util/RequestDataTest.java index bb86153d1f2..0efe422fc6e 100755 --- a/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/util/RequestDataTest.java +++ b/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/util/RequestDataTest.java @@ -34,7 +34,6 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.*; - import javax.servlet.ServletInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -212,12 +211,13 @@ public void testMultipartPostWithShorterFilename() throws Exception { @Test(expected=IOException.class) public void testMultipartPostWithExtremelyLongFilename() throws Exception { - buildRequestWithFilenameOfVaryingLength(1000); + // tests against the new default value of 4096 + buildRequestWithFilenameOfVaryingLength(5000); File testTmpDir = tempFolder.newFolder("jackrabbit_long_filename"); RequestData requestData = new RequestData(mockRequest, testTmpDir); try { assertTrue( - requestData.getParameter("fileUpload").length() > 950); + requestData.getParameter("fileUpload").length() > 4900); } finally { requestData.dispose(); } @@ -226,13 +226,13 @@ public void testMultipartPostWithExtremelyLongFilename() throws Exception { @Test public void testMultipartPostWithExtremelyLongFilenameNButHigherConfig() throws Exception { try { - System.setProperty("jackrabbit-server-PartHeaderSizeMax", "2048"); - buildRequestWithFilenameOfVaryingLength(1000); + System.setProperty("jackrabbit-server-PartHeaderSizeMax", "8192"); + buildRequestWithFilenameOfVaryingLength(7500); File testTmpDir = tempFolder.newFolder("jackrabbit_long_filename"); RequestData requestData = new RequestData(mockRequest, testTmpDir); try { assertTrue( - requestData.getParameter("fileUpload").length() > 950); + requestData.getParameter("fileUpload").length() > 7500); } finally { requestData.dispose(); } From a4a5bcf629c0d1057d1cda586a147201f7ea69c4 Mon Sep 17 00:00:00 2001 From: Julian Reschke Date: Wed, 24 Jun 2026 14:24:24 +0100 Subject: [PATCH 2/2] JCR-5233: commons-fileupload (1.6) restricts header size in upload parts - bump up the default and a system property knob --- .../server/util/HttpMultipartPost.java | 2 + .../server/util/RequestDataTest.java | 52 ++++--------------- 2 files changed, 13 insertions(+), 41 deletions(-) diff --git a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/util/HttpMultipartPost.java b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/util/HttpMultipartPost.java index 9d71f38baab..30ca4e831d0 100644 --- a/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/util/HttpMultipartPost.java +++ b/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/util/HttpMultipartPost.java @@ -45,6 +45,8 @@ class HttpMultipartPost { private final Map> nameToItems = new LinkedHashMap>(); private final Set fileParamNames = new HashSet(); + // <= 0 (default -1) -> Jackrabbit applies 4096 (overrides cfup 1.6's current 512-byte default); + // positive -> exact value in bytes. Set to 512 to restore the library's own default. private final int PARTHEADERSIZEMAX = Integer.getInteger("jackrabbit-server-PartHeaderSizeMax", -1); private boolean initialized; diff --git a/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/util/RequestDataTest.java b/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/util/RequestDataTest.java index 0efe422fc6e..36d59c55a3c 100755 --- a/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/util/RequestDataTest.java +++ b/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/util/RequestDataTest.java @@ -209,22 +209,28 @@ public void testMultipartPostWithShorterFilename() throws Exception { } } - @Test(expected=IOException.class) + @Test(expected = IOException.class) public void testMultipartPostWithExtremelyLongFilename() throws Exception { - // tests against the new default value of 4096 + // header bytes ~= filename length + ~107; at 5000 chars this far exceeds the 4096 default buildRequestWithFilenameOfVaryingLength(5000); File testTmpDir = tempFolder.newFolder("jackrabbit_long_filename"); + new RequestData(mockRequest, testTmpDir); // must throw IOException + } + + @Test + public void testMultipartPostWithLongFilenameUnderNewDefault() throws Exception { + buildRequestWithFilenameOfVaryingLength(3800); // above 512, below 4096 + File testTmpDir = tempFolder.newFolder("jackrabbit_medium_filename"); RequestData requestData = new RequestData(mockRequest, testTmpDir); try { - assertTrue( - requestData.getParameter("fileUpload").length() > 4900); + assertTrue(requestData.getParameter("fileUpload").length() > 3800); } finally { requestData.dispose(); } } @Test - public void testMultipartPostWithExtremelyLongFilenameNButHigherConfig() throws Exception { + public void testMultipartPostWithExtremelyLongFilenameWithHigherConfig() throws Exception { try { System.setProperty("jackrabbit-server-PartHeaderSizeMax", "8192"); buildRequestWithFilenameOfVaryingLength(7500); @@ -240,40 +246,4 @@ public void testMultipartPostWithExtremelyLongFilenameNButHigherConfig() throws System.clearProperty("jackrabbit-server-PartHeaderSizeMax"); } } - - /** - * Assures special Unicode (Non-ASCII) symbols preserve structural state during text decoding. - */ - // @Test - public void testMultipartPostWithNonAsciiCharacters() throws Exception { - File testTmpDir = tempFolder.newFolder("jackrabbit_non_ascii"); - String boundary = "----MockBoundaryNonAscii"; - String nonAsciiValue = "テスト_ü_é_ñ_value"; - String nonAsciiFilename = "マニュアル_doc.pdf"; - - String body = "--" + boundary + "\r\n" + - "Content-Disposition: form-data; name=\"unicodeField\"\r\n\r\n" + - nonAsciiValue + "\r\n" + - "--" + boundary + "\r\n" + - "Content-Disposition: form-data; name=\"unicodeFile\"; filename=\"" + nonAsciiFilename + "\"\r\n" + - "Content-Type: application/pdf\r\n\r\n" + - "%PDF-Mock-Bytes\r\n" + - "--" + boundary + "--\r\n"; - - byte[] payloadBytes = body.getBytes(StandardCharsets.UTF_8); - - when(mockRequest.getMethod()).thenReturn("POST"); - when(mockRequest.getContentType()).thenReturn("multipart/form-data; boundary=" + boundary); - lenient().when(mockRequest.getCharacterEncoding()).thenReturn("UTF-8"); - when(mockRequest.getInputStream()).thenReturn(createServletInputStream(payloadBytes)); - - RequestData requestData = new RequestData(mockRequest, testTmpDir); - try { - String parsedValue = requestData.getParameter("unicodeField"); - assertEquals("Unicode decoding was corrupted inside the parsing sequence", nonAsciiValue, parsedValue); - assertNotNull("Non-ASCII file part metadata parsing must complete successfully", requestData.getParameter("unicodeFile")); - } finally { - requestData.dispose(); - } - } } \ No newline at end of file