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]