lukaszlenart opened a new pull request, #1912: URL: https://github.com/apache/struts/pull/1912
Fixes [WW-5723](https://issues.apache.org/jira/browse/WW-5723) `ContentTypeInterceptor` handed `request.getInputStream()` to the content-type handler with no length limit, while the JSON plugin bounds the same read with `struts.json.maxLength` and `CspReportAction` with `struts.csp.report.maxSize`. This applies the same limit to the REST plugin. ## What changes - New constant `struts.rest.content.maxLength`, default `2097152` (matching the JSON plugin), declared in the plugin's `struts-plugin.xml` and injected into `ContentTypeInterceptor` via `@Inject(required = false)`. Blank, non-numeric or sub-1 values are ignored with a warning and the default kept, as `CspReportAction` does. - The handler now receives a `BoundedReader` — a `FilterReader` that counts characters and fails once the limit is passed. On overflow the interceptor throws the new `RequestBodyTooLargeException` (a `StrutsException`), and the action is never invoked. - `applyRequestBody` and the two authorization paths take a `Reader` instead of an `InputStreamReader`; `ContentTypeHandler.toObject` already declared `Reader`. - The `getContentLength() > 0` gate is unchanged. ## Design notes **Bound the read, not the header.** The limit is enforced on characters actually consumed, so it holds regardless of the declared `Content-Length`. **Lazy rather than buffered.** An earlier shape read the body into a buffer before calling the handler. That drained the stream even for handlers that never read it (`HtmlHandler`, `FormUrlEncodedHandler`, `MultipartFormDataHandler`), which would have broken an action reading the raw body itself behind one of them. Wrapping the reader instead means those handlers leave the body untouched exactly as before, and Jackson keeps streaming rather than parsing from a buffer. **One exception type regardless of handler.** Handlers wrap the reader's `IOException` in their own types — Jackson passes it through, XStream wraps in `StreamException`, Juneau in `ParseException`. Rather than depend on what propagates, `intercept()` consults the reader's flag after the call and throws `RequestBodyTooLargeException` either way. A handler that swallows the failure still fails closed: the flag is checked on the normal return path too. The dedicated type lets an application map this to 413 via `<exception-mapping>` without catching every `StrutsException`. **Framework constant, not an action property.** Matches both siblings and behaves identically on 6.x, where interceptor ordering differs. **No upper cap on the configured value.** `CspReportAction` caps because it pre-allocates a buffer of that size; nothing is pre-allocated here, so a large value costs nothing until a body that size arrives. **Authorization context.** The read now happens inside `applyWithAuthorizationContext`'s bind/unbind window. `ParameterAuthorizationContext.unbind()` removes all three thread-locals unconditionally in `finally`, and the Jackson handlers clear their dynamic-key scope in their own `finally`, so an abort mid-parse leaves nothing on the thread. Properties bound before the limit trips have each passed authorization individually — the outcome is the same as a malformed body truncated at that offset, and `invoke()` does not run. ## Tests Six new tests in `ContentTypeInterceptorTest`: over-limit body rejected before the action runs, body exactly at the limit passed in full, over-limit body not read to the end, non-numeric and sub-1 configuration keep the default, and a handler that ignores the reader leaves the body unread. Two existing tests asserted the handler received an `InputStreamReader` and read its encoding from it, i.e. an implementation type. They now assert the decoded content, and the ASCII case becomes ISO-8859-1 so the assertion discriminates between honouring the request charset and ignoring it — an ASCII body decodes the same under any charset. REST plugin suite: 155 tests, 0 failures. ## Follow-ups - 6.x port under the same ticket, once this lands. - Document `struts.rest.content.maxLength` on the REST plugin page in struts-site. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01QmdzKqRSSMyCsdgnv2ubiy -- 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]
