[ 
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)

Reply via email to