From 8b81103a50137edd06b4b82785b8b48648abbff5 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Fri, 24 Mar 2023 14:27:47 +1100 Subject: [PATCH 1/2] parameterize MultiPartServletTest for complianceModes and add extra test Signed-off-by: Lachlan Roberts --- .../jetty/servlet/MultiPartServletTest.java | 93 ++++++++++++++++--- 1 file changed, 79 insertions(+), 14 deletions(-) diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/MultiPartServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/MultiPartServletTest.java index bc65cfd2a09f..007f3a235a84 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/MultiPartServletTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/MultiPartServletTest.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; import java.util.zip.GZIPInputStream; import javax.servlet.MultipartConfigElement; import javax.servlet.ServletException; @@ -46,6 +47,8 @@ import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.logging.StacklessLogging; import org.eclipse.jetty.server.HttpChannel; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.MultiPartFormDataCompliance; import org.eclipse.jetty.server.MultiPartFormInputStream; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; @@ -53,7 +56,9 @@ import org.eclipse.jetty.util.IO; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; @@ -75,6 +80,14 @@ public class MultiPartServletTest private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 8; private static final int LARGE_MESSAGE_SIZE = 1024 * 1024; + public static Stream complianceModes() + { + return Stream.of( + Arguments.of(MultiPartFormDataCompliance.RFC7578), + Arguments.of(MultiPartFormDataCompliance.LEGACY) + ); + } + public static class RequestParameterServlet extends HttpServlet { @Override @@ -175,9 +188,13 @@ public void stop() throws Exception IO.delete(tmpDir.toFile()); } - @Test - public void testLargePart() throws Exception + @ParameterizedTest + @MethodSource("complianceModes") + public void testLargePart(MultiPartFormDataCompliance compliance) throws Exception { + connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() + .setMultiPartFormDataCompliance(compliance); + OutputStreamRequestContent content = new OutputStreamRequestContent(); MultiPartRequestContent multiPart = new MultiPartRequestContent(); multiPart.addFieldPart("param", content, null); @@ -200,21 +217,57 @@ public void testLargePart() throws Exception } content.close(); - Response response = listener.get(30, TimeUnit.SECONDS); + Response response = listener.get(2, TimeUnit.MINUTES); assertThat(response.getStatus(), equalTo(HttpStatus.BAD_REQUEST_400)); String responseContent = IO.toString(listener.getInputStream()); assertThat(responseContent, containsString("Unable to parse form content")); assertThat(responseContent, containsString("Form is larger than max length")); } - @Test - public void testManyParts() throws Exception + @ParameterizedTest + @MethodSource("complianceModes") + public void testManyParts(MultiPartFormDataCompliance compliance) throws Exception + { + connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() + .setMultiPartFormDataCompliance(compliance); + + byte[] byteArray = new byte[10]; + Arrays.fill(byteArray, (byte)1); + + MultiPartRequestContent multiPart = new MultiPartRequestContent(); + for (int i = 0; i < 1000; i++) + { + BytesRequestContent content = new BytesRequestContent(byteArray); + multiPart.addFieldPart("part" + i, content, null); + } + multiPart.close(); + + InputStreamResponseListener listener = new InputStreamResponseListener(); + client.newRequest("localhost", connector.getLocalPort()) + .path("/defaultConfig") + .scheme(HttpScheme.HTTP.asString()) + .method(HttpMethod.POST) + .body(multiPart) + .send(listener); + + Response response = listener.get(30, TimeUnit.SECONDS); + assertThat(response.getStatus(), equalTo(HttpStatus.OK_200)); + String responseContent = IO.toString(listener.getInputStream()); + assertThat(responseContent, containsString("success")); + } + + @ParameterizedTest + @MethodSource("complianceModes") + public void testTooManyParts(MultiPartFormDataCompliance compliance) throws Exception { - byte[] byteArray = new byte[1024]; + connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() + .setMultiPartFormDataCompliance(compliance); + + byte[] byteArray = new byte[5]; Arrays.fill(byteArray, (byte)1); MultiPartRequestContent multiPart = new MultiPartRequestContent(); - for (int i = 0; i < 1024 * 1024; i++) + for (int i = 0; i < 1001; i++) { BytesRequestContent content = new BytesRequestContent(byteArray); multiPart.addFieldPart("part" + i, content, null); @@ -236,9 +289,13 @@ public void testManyParts() throws Exception assertThat(responseContent, containsString("Form with too many parts")); } - @Test - public void testMaxRequestSize() throws Exception + @ParameterizedTest + @MethodSource("complianceModes") + public void testMaxRequestSize(MultiPartFormDataCompliance compliance) throws Exception { + connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() + .setMultiPartFormDataCompliance(compliance); + OutputStreamRequestContent content = new OutputStreamRequestContent(); MultiPartRequestContent multiPart = new MultiPartRequestContent(); multiPart.addFieldPart("param", content, null); @@ -276,9 +333,13 @@ public void testMaxRequestSize() throws Exception assertThat(response.getStatus(), equalTo(HttpStatus.BAD_REQUEST_400)); } - @Test - public void testTempFilesDeletedOnError() throws Exception + @ParameterizedTest + @MethodSource("complianceModes") + public void testTempFilesDeletedOnError(MultiPartFormDataCompliance compliance) throws Exception { + connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() + .setMultiPartFormDataCompliance(compliance); + byte[] byteArray = new byte[LARGE_MESSAGE_SIZE]; Arrays.fill(byteArray, (byte)1); BytesRequestContent content = new BytesRequestContent(byteArray); @@ -305,9 +366,13 @@ public void testTempFilesDeletedOnError() throws Exception assertThat(fileList.length, is(0)); } - @Test - public void testMultiPartGzip() throws Exception + @ParameterizedTest + @MethodSource("complianceModes") + public void testMultiPartGzip(MultiPartFormDataCompliance compliance) throws Exception { + connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() + .setMultiPartFormDataCompliance(compliance); + String contentString = "the quick brown fox jumps over the lazy dog, " + "the quick brown fox jumps over the lazy dog"; StringRequestContent content = new StringRequestContent(contentString); From 0abf51c7124e81f03088e6423cd340e235cb06c7 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Thu, 30 Mar 2023 14:34:22 +1100 Subject: [PATCH 2/2] explicitly specify maxFormKeys for MultiPartServletTest Signed-off-by: Lachlan Roberts --- .../eclipse/jetty/servlet/MultiPartServletTest.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/MultiPartServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/MultiPartServletTest.java index 007f3a235a84..01faf9e623de 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/MultiPartServletTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/MultiPartServletTest.java @@ -75,6 +75,7 @@ public class MultiPartServletTest private ServerConnector connector; private HttpClient client; private Path tmpDir; + private ServletContextHandler contextHandler; private static final int MAX_FILE_SIZE = 512 * 1024; private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 8; @@ -155,7 +156,7 @@ public void start() throws Exception MultipartConfigElement defaultConfig = new MultipartConfigElement(tmpDir.toAbsolutePath().toString(), -1, -1, 1); - ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); + contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); contextHandler.setContextPath("/"); ServletHolder servletHolder = contextHandler.addServlet(MultiPartServlet.class, "/"); servletHolder.getRegistration().setMultipartConfig(config); @@ -228,6 +229,8 @@ public void testLargePart(MultiPartFormDataCompliance compliance) throws Excepti @MethodSource("complianceModes") public void testManyParts(MultiPartFormDataCompliance compliance) throws Exception { + int maxParts = 1000; + contextHandler.setMaxFormKeys(maxParts); connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() .setMultiPartFormDataCompliance(compliance); @@ -235,7 +238,7 @@ public void testManyParts(MultiPartFormDataCompliance compliance) throws Excepti Arrays.fill(byteArray, (byte)1); MultiPartRequestContent multiPart = new MultiPartRequestContent(); - for (int i = 0; i < 1000; i++) + for (int i = 0; i < maxParts; i++) { BytesRequestContent content = new BytesRequestContent(byteArray); multiPart.addFieldPart("part" + i, content, null); @@ -260,6 +263,8 @@ public void testManyParts(MultiPartFormDataCompliance compliance) throws Excepti @MethodSource("complianceModes") public void testTooManyParts(MultiPartFormDataCompliance compliance) throws Exception { + int maxParts = 1000; + contextHandler.setMaxFormKeys(maxParts); connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() .setMultiPartFormDataCompliance(compliance); @@ -267,7 +272,7 @@ public void testTooManyParts(MultiPartFormDataCompliance compliance) throws Exce Arrays.fill(byteArray, (byte)1); MultiPartRequestContent multiPart = new MultiPartRequestContent(); - for (int i = 0; i < 1001; i++) + for (int i = 0; i < maxParts + 1; i++) { BytesRequestContent content = new BytesRequestContent(byteArray); multiPart.addFieldPart("part" + i, content, null);