2121import java .util .Arrays ;
2222import java .util .List ;
2323import java .util .concurrent .TimeUnit ;
24+ import java .util .stream .Stream ;
2425import java .util .zip .GZIPInputStream ;
2526
2627import jakarta .servlet .MultipartConfigElement ;
4647import org .eclipse .jetty .io .EofException ;
4748import org .eclipse .jetty .logging .StacklessLogging ;
4849import org .eclipse .jetty .server .HttpChannel ;
50+ import org .eclipse .jetty .server .HttpConnectionFactory ;
51+ import org .eclipse .jetty .server .MultiPartFormDataCompliance ;
4952import org .eclipse .jetty .server .MultiPartFormInputStream ;
5053import org .eclipse .jetty .server .Server ;
5154import org .eclipse .jetty .server .ServerConnector ;
5255import org .eclipse .jetty .server .handler .gzip .GzipHandler ;
5356import org .eclipse .jetty .util .IO ;
5457import org .junit .jupiter .api .AfterEach ;
5558import org .junit .jupiter .api .BeforeEach ;
56- import org .junit .jupiter .api .Test ;
59+ import org .junit .jupiter .params .ParameterizedTest ;
60+ import org .junit .jupiter .params .provider .Arguments ;
61+ import org .junit .jupiter .params .provider .MethodSource ;
5762
5863import static org .hamcrest .MatcherAssert .assertThat ;
5964import static org .hamcrest .Matchers .containsString ;
@@ -70,11 +75,20 @@ public class MultiPartServletTest
7075 private ServerConnector connector ;
7176 private HttpClient client ;
7277 private Path tmpDir ;
78+ private ServletContextHandler contextHandler ;
7379
7480 private static final int MAX_FILE_SIZE = 512 * 1024 ;
7581 private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 8 ;
7682 private static final int LARGE_MESSAGE_SIZE = 1024 * 1024 ;
7783
84+ public static Stream <Arguments > complianceModes ()
85+ {
86+ return Stream .of (
87+ Arguments .of (MultiPartFormDataCompliance .RFC7578 ),
88+ Arguments .of (MultiPartFormDataCompliance .LEGACY )
89+ );
90+ }
91+
7892 public static class RequestParameterServlet extends HttpServlet
7993 {
8094 @ Override
@@ -142,7 +156,7 @@ public void start() throws Exception
142156 MultipartConfigElement defaultConfig = new MultipartConfigElement (tmpDir .toAbsolutePath ().toString (),
143157 -1 , -1 , 1 );
144158
145- ServletContextHandler contextHandler = new ServletContextHandler (ServletContextHandler .SESSIONS );
159+ contextHandler = new ServletContextHandler (ServletContextHandler .SESSIONS );
146160 contextHandler .setContextPath ("/" );
147161 ServletHolder servletHolder = contextHandler .addServlet (MultiPartServlet .class , "/" );
148162 servletHolder .getRegistration ().setMultipartConfig (config );
@@ -175,9 +189,13 @@ public void stop() throws Exception
175189 IO .delete (tmpDir .toFile ());
176190 }
177191
178- @ Test
179- public void testLargePart () throws Exception
192+ @ ParameterizedTest
193+ @ MethodSource ("complianceModes" )
194+ public void testLargePart (MultiPartFormDataCompliance compliance ) throws Exception
180195 {
196+ connector .getConnectionFactory (HttpConnectionFactory .class ).getHttpConfiguration ()
197+ .setMultiPartFormDataCompliance (compliance );
198+
181199 OutputStreamRequestContent content = new OutputStreamRequestContent ();
182200 MultiPartRequestContent multiPart = new MultiPartRequestContent ();
183201 multiPart .addFieldPart ("param" , content , null );
@@ -200,21 +218,61 @@ public void testLargePart() throws Exception
200218 }
201219 content .close ();
202220
203- Response response = listener .get (30 , TimeUnit .SECONDS );
221+ Response response = listener .get (2 , TimeUnit .MINUTES );
204222 assertThat (response .getStatus (), equalTo (HttpStatus .BAD_REQUEST_400 ));
205223 String responseContent = IO .toString (listener .getInputStream ());
206224 assertThat (responseContent , containsString ("Unable to parse form content" ));
207225 assertThat (responseContent , containsString ("Form is larger than max length" ));
208226 }
209227
210- @ Test
211- public void testManyParts () throws Exception
228+ @ ParameterizedTest
229+ @ MethodSource ("complianceModes" )
230+ public void testManyParts (MultiPartFormDataCompliance compliance ) throws Exception
231+ {
232+ int maxParts = 1000 ;
233+ contextHandler .setMaxFormKeys (maxParts );
234+ connector .getConnectionFactory (HttpConnectionFactory .class ).getHttpConfiguration ()
235+ .setMultiPartFormDataCompliance (compliance );
236+
237+ byte [] byteArray = new byte [10 ];
238+ Arrays .fill (byteArray , (byte )1 );
239+
240+ MultiPartRequestContent multiPart = new MultiPartRequestContent ();
241+ for (int i = 0 ; i < maxParts ; i ++)
242+ {
243+ BytesRequestContent content = new BytesRequestContent (byteArray );
244+ multiPart .addFieldPart ("part" + i , content , null );
245+ }
246+ multiPart .close ();
247+
248+ InputStreamResponseListener listener = new InputStreamResponseListener ();
249+ client .newRequest ("localhost" , connector .getLocalPort ())
250+ .path ("/defaultConfig" )
251+ .scheme (HttpScheme .HTTP .asString ())
252+ .method (HttpMethod .POST )
253+ .body (multiPart )
254+ .send (listener );
255+
256+ Response response = listener .get (30 , TimeUnit .SECONDS );
257+ assertThat (response .getStatus (), equalTo (HttpStatus .OK_200 ));
258+ String responseContent = IO .toString (listener .getInputStream ());
259+ assertThat (responseContent , containsString ("success" ));
260+ }
261+
262+ @ ParameterizedTest
263+ @ MethodSource ("complianceModes" )
264+ public void testTooManyParts (MultiPartFormDataCompliance compliance ) throws Exception
212265 {
213- byte [] byteArray = new byte [1024 ];
266+ int maxParts = 1000 ;
267+ contextHandler .setMaxFormKeys (maxParts );
268+ connector .getConnectionFactory (HttpConnectionFactory .class ).getHttpConfiguration ()
269+ .setMultiPartFormDataCompliance (compliance );
270+
271+ byte [] byteArray = new byte [5 ];
214272 Arrays .fill (byteArray , (byte )1 );
215273
216274 MultiPartRequestContent multiPart = new MultiPartRequestContent ();
217- for (int i = 0 ; i < 1024 * 1024 ; i ++)
275+ for (int i = 0 ; i < maxParts + 1 ; i ++)
218276 {
219277 BytesRequestContent content = new BytesRequestContent (byteArray );
220278 multiPart .addFieldPart ("part" + i , content , null );
@@ -236,9 +294,13 @@ public void testManyParts() throws Exception
236294 assertThat (responseContent , containsString ("Form with too many parts" ));
237295 }
238296
239- @ Test
240- public void testMaxRequestSize () throws Exception
297+ @ ParameterizedTest
298+ @ MethodSource ("complianceModes" )
299+ public void testMaxRequestSize (MultiPartFormDataCompliance compliance ) throws Exception
241300 {
301+ connector .getConnectionFactory (HttpConnectionFactory .class ).getHttpConfiguration ()
302+ .setMultiPartFormDataCompliance (compliance );
303+
242304 OutputStreamRequestContent content = new OutputStreamRequestContent ();
243305 MultiPartRequestContent multiPart = new MultiPartRequestContent ();
244306 multiPart .addFieldPart ("param" , content , null );
@@ -276,9 +338,13 @@ public void testMaxRequestSize() throws Exception
276338 assertThat (response .getStatus (), equalTo (HttpStatus .BAD_REQUEST_400 ));
277339 }
278340
279- @ Test
280- public void testTempFilesDeletedOnError () throws Exception
341+ @ ParameterizedTest
342+ @ MethodSource ("complianceModes" )
343+ public void testTempFilesDeletedOnError (MultiPartFormDataCompliance compliance ) throws Exception
281344 {
345+ connector .getConnectionFactory (HttpConnectionFactory .class ).getHttpConfiguration ()
346+ .setMultiPartFormDataCompliance (compliance );
347+
282348 byte [] byteArray = new byte [LARGE_MESSAGE_SIZE ];
283349 Arrays .fill (byteArray , (byte )1 );
284350 BytesRequestContent content = new BytesRequestContent (byteArray );
@@ -305,9 +371,13 @@ public void testTempFilesDeletedOnError() throws Exception
305371 assertThat (fileList .length , is (0 ));
306372 }
307373
308- @ Test
309- public void testMultiPartGzip () throws Exception
374+ @ ParameterizedTest
375+ @ MethodSource ("complianceModes" )
376+ public void testMultiPartGzip (MultiPartFormDataCompliance compliance ) throws Exception
310377 {
378+ connector .getConnectionFactory (HttpConnectionFactory .class ).getHttpConfiguration ()
379+ .setMultiPartFormDataCompliance (compliance );
380+
311381 String contentString = "the quick brown fox jumps over the lazy dog, " +
312382 "the quick brown fox jumps over the lazy dog" ;
313383 StringRequestContent content = new StringRequestContent (contentString );
0 commit comments