@@ -34,6 +34,7 @@ public class NettyHandler extends ChannelInboundHandlerAdapter {
3434 private final int bufferSize ;
3535 private final boolean defaultHeaders ;
3636 private final long maxRequestSize ;
37+ private final int maxFormFields ;
3738 private long contentLength ;
3839 private long chunkSize ;
3940 private final boolean http2 ;
@@ -43,13 +44,15 @@ public NettyHandler(
4344 NettyDateService dateService ,
4445 List <Jooby > applications ,
4546 long maxRequestSize ,
47+ int maxFormFields ,
4648 int bufferSize ,
4749 boolean defaultHeaders ,
4850 boolean http2 ) {
4951 this .serverDate = dateService ;
5052 this .applications = applications ;
5153 this .ctxSelector = Context .Selector .create (applications );
5254 this .maxRequestSize = maxRequestSize ;
55+ this .maxFormFields = maxFormFields ;
5356 this .bufferSize = bufferSize ;
5457 this .defaultHeaders = defaultHeaders ;
5558 this .http2 = http2 ;
@@ -79,7 +82,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
7982 if (contentLength > 0 || isTransferEncodingChunked (req )) {
8083 context .httpDataFactory = new DefaultHttpDataFactory (bufferSize );
8184 context .httpDataFactory .setBaseDir (app .getTmpdir ().toString ());
82- context .decoder = newDecoder (req , context .httpDataFactory );
85+ context .decoder = newDecoder (req , context .httpDataFactory , maxFormFields );
8386 } else {
8487 // no body, move on
8588 router .match (context ).execute (context );
@@ -90,10 +93,11 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
9093 try {
9194 // when decoder == null, chunk is always a LastHttpContent.EMPTY, ignore it
9295 if (context .decoder != null ) {
93- offer (context , chunk );
94- Router .Match route = router .match (context );
95- resetDecoderState (context , !route .matches ());
96- route .execute (context );
96+ if (offer (context , chunk )) {
97+ Router .Match route = router .match (context );
98+ resetDecoderState (context , !route .matches ());
99+ route .execute (context );
100+ }
97101 }
98102 } finally {
99103 release (chunk );
@@ -172,14 +176,16 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
172176 }
173177 }
174178
175- private void offer (NettyContext context , HttpContent chunk ) {
179+ private boolean offer (NettyContext context , HttpContent chunk ) {
176180 try {
177181 context .decoder .offer (chunk );
178- } catch (HttpPostRequestDecoder .ErrorDataDecoderException
179- | HttpPostRequestDecoder .TooLongFormFieldException
180- | HttpPostRequestDecoder .TooManyFormFieldsException x ) {
181- resetDecoderState (context , true );
182- context .sendError (x , StatusCode .BAD_REQUEST );
182+ return true ;
183+ } catch (Exception x ) {
184+ if (x instanceof HttpPostRequestDecoder .TooManyFormFieldsException ) {
185+ context .setAttribute ("__too_many_fields" , x );
186+ }
187+ router .match (context ).execute (context , Route .FORM_DECODER_HANDLER );
188+ return false ;
183189 }
184190 }
185191
@@ -197,14 +203,16 @@ private void resetDecoderState(NettyContext context, boolean destroy) {
197203 }
198204
199205 private static InterfaceHttpPostRequestDecoder newDecoder (
200- HttpRequest request , HttpDataFactory factory ) {
206+ HttpRequest request , HttpDataFactory factory , int maxFormFields ) {
201207 String contentType = request .headers ().get (HttpHeaderNames .CONTENT_TYPE );
202208 if (contentType != null ) {
203209 String lowerContentType = contentType .toLowerCase ();
204210 if (lowerContentType .startsWith (MediaType .MULTIPART_FORMDATA )) {
205- return new HttpPostMultipartRequestDecoder (factory , request , StandardCharsets .UTF_8 );
211+ return new HttpPostMultipartRequestDecoder (
212+ factory , request , StandardCharsets .UTF_8 , maxFormFields , -1 );
206213 } else if (lowerContentType .startsWith (MediaType .FORM_URLENCODED )) {
207- return new HttpPostStandardRequestDecoder (factory , request , StandardCharsets .UTF_8 );
214+ return new HttpPostStandardRequestDecoder (
215+ factory , request , StandardCharsets .UTF_8 , maxFormFields , -1 );
208216 }
209217 }
210218 return new HttpRawPostRequestDecoder (factory , request );
0 commit comments