Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-11.0.x
Browse files Browse the repository at this point in the history
  • Loading branch information
lachlan-roberts committed Apr 5, 2023
2 parents 8bbde29 + 795315f commit b96a605
Showing 1 changed file with 85 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 jakarta.servlet.MultipartConfigElement;
Expand All @@ -46,14 +47,18 @@
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;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
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;
Expand All @@ -70,11 +75,20 @@ 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;
private static final int LARGE_MESSAGE_SIZE = 1024 * 1024;

public static Stream<Arguments> complianceModes()
{
return Stream.of(
Arguments.of(MultiPartFormDataCompliance.RFC7578),
Arguments.of(MultiPartFormDataCompliance.LEGACY)
);
}

public static class RequestParameterServlet extends HttpServlet
{
@Override
Expand Down Expand Up @@ -142,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);
Expand Down Expand Up @@ -175,9 +189,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);
Expand All @@ -200,21 +218,61 @@ 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
{
int maxParts = 1000;
contextHandler.setMaxFormKeys(maxParts);
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 < maxParts; 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];
int maxParts = 1000;
contextHandler.setMaxFormKeys(maxParts);
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 < maxParts + 1; i++)
{
BytesRequestContent content = new BytesRequestContent(byteArray);
multiPart.addFieldPart("part" + i, content, null);
Expand All @@ -236,9 +294,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);
Expand Down Expand Up @@ -276,9 +338,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);
Expand All @@ -305,9 +371,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);
Expand Down

0 comments on commit b96a605

Please sign in to comment.