[
https://issues.apache.org/jira/browse/WW-5723?focusedWorklogId=1040900&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1040900
]
ASF GitHub Bot logged work on WW-5723:
--------------------------------------
Author: ASF GitHub Bot
Created on: 11/Sep/26 10:59
Start Date: 11/Sep/26 10:59
Worklog Time Spent: 10m
Work Description: 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
Issue Time Tracking
-------------------
Worklog Id: (was: 1040900)
Remaining Estimate: 0h
Time Spent: 10m
> REST plugin does not bound the request body read in ContentTypeInterceptor
> --------------------------------------------------------------------------
>
> Key: WW-5723
> URL: https://issues.apache.org/jira/browse/WW-5723
> Project: Struts 2
> Issue Type: Improvement
> Reporter: Lukasz Lenart
> Priority: Major
> Fix For: 6.12.0, 7.4.0
>
> Time Spent: 10m
> Remaining Estimate: 0h
>
> h2. Summary
> {{ContentTypeInterceptor}} reads the request body with no length limit, while
> the two sibling body reads in the framework are bounded. This issue applies
> the same limit to the REST plugin.
> h2. Current behaviour
> {{ContentTypeInterceptor.intercept}} checks {{request.getContentLength() >
> 0}} and then hands {{request.getInputStream()}} to the selected
> {{ContentTypeHandler}}, which reads it to the end. Neither the interceptor
> nor {{RestConstants}} defines a maximum length.
> The JSON plugin bounds its equivalent read with {{struts.json.maxLength}}
> (default 2 MB), and {{CspReportAction}} bounds its read with
> {{struts.csp.report.maxSize}}. The REST plugin has no counterpart.
> h2. Proposed change
> Add {{struts.rest.content.maxLength}}, defaulting to 2 MB to match the JSON
> plugin, injected into {{ContentTypeInterceptor}} as a framework constant.
> Enforce it on the read itself by wrapping the reader handed to the handler,
> so a body exceeding the limit is rejected while being read, independent of
> the declared Content-Length.
> A configured value outside a sane range is ignored with a warning and the
> default kept, as {{CspReportAction}} does.
> The existing {{getContentLength() > 0}} condition is unchanged.
> h2. Compatibility notes
> A request whose body exceeds the configured limit is rejected rather than
> processed. Applications that accept larger bodies through the REST plugin
> need to raise {{struts.rest.content.maxLength}}.
> Applies to both maintenance lines.
> Reported by n0mi1k.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)