codeconsole opened a new pull request, #16152:
URL: https://github.com/apache/grails-core/pull/16152

   Closes #16145.
   
   An oversized multipart upload never reaches the application. Grails reads 
request parameters
   before the `DispatcherServlet` runs — `HiddenHttpMethodFilter` looks for 
`_method`, and
   `GrailsWebRequestFilter` builds `GrailsParameterMap` — and reading any 
parameter of a
   `multipart/form-data` request makes the container parse the body. A body 
past the configured
   limit fails that parse, inside the filter chain, where no 
`HandlerExceptionResolver` can see it.
   
   Spring resolves multipart in `DispatcherServlet.checkMultipart`, inside 
`doDispatch`, which is
   why a plain Spring MVC application handles this correctly out of the box. 
Grails only differs
   because it reads parameters first.
   
   So the framework's parameter reads now tolerate a multipart body the 
container refuses to parse,
   and the failure is left for `checkMultipart` to raise during dispatch, where 
Spring routes it to
   the exception resolvers and the application's error handling runs. Any 
non-multipart parameter
   failure still propagates unchanged.
   
   ## Measured
   
   Same 200 KB upload against a 128000-byte limit, same probe, on three 
containers:
   
   | Container | Before | After |
   |---|---|---|
   | Tomcat 11 | `500`, raw Tomcat HTML page | `413`, `{"error":"Content Too 
Large","handledBy":"errors.tooLarge"}` |
   | Jetty 12 | `400` "Bad Request" — indistinguishable from a malformed 
request | `413`, handled by the application |
   | Undertow 2.4 | `413`, empty body | `413`, empty body — **unchanged** |
   
   Undertow applies the limit while reading the request entity, so no filter or 
servlet runs and
   there is nothing the framework can influence. That limitation is documented 
and pinned by a spec
   so a change in it is noticed.
   
   ## Also fixed
   
   An error handler that itself fails was forwarded to indefinitely. With a 
`"413"` or `"500"`
   controller mapping, the error dispatch re-entered `DispatcherServlet`, 
resolved the same mapping,
   faulted on the same unreadable request and forwarded again — 78,120 nested 
frames,
   `StackOverflowError`, then `OutOfMemoryError` while logging the unwind. 
`GrailsExceptionResolver`
   no longer forwards to an error handler while a forward to it is already in 
progress. This is
   independent of multipart: any error handler that throws would have looped.
   
   ## Notes
   
   - `<g:uploadForm method="PUT">` (multipart plus `_method`) keeps working; 
there is a test.
   - During an error dispatch for this failure the action sees 
`dispatcherType=ERROR`, empty `params`
     and no `request.getFile(..)`, since the body was never readable. 
Documented.
   - Covers Tomcat, Jetty and Undertow with integration tests in 
`grails-test-examples`.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to