lukaszlenart opened a new pull request, #1806:
URL: https://github.com/apache/struts/pull/1806

   Fixes [WW-5474](https://issues.apache.org/jira/browse/WW-5474)
   
   ## Problem
   
   `struts.multipart.maxFiles` (default `256`) is documented as a cap on the 
**number of uploaded files**, but it did not behave that way, and the two 
Jakarta parsers disagreed:
   
   - **`jakarta` parser (default)** passed the value to commons-fileupload2 
`setMaxFileCount`, whose `parseRequest` counts **every** part — form fields 
*and* files. So `maxFiles` actually limited the **total number of parameters**, 
firing spuriously on forms with many normal fields and few (or zero) files. 
This is the reported bug.
   - **`jakarta-stream` parser** never received commons enforcement (its 
streaming iterator ignores `maxFileCount`) and counted **distinct field names** 
via its own `exceedsMaxFiles`, so multiple files under one field name collapsed 
to one.
   
   ## Change
   
   - `struts.multipart.maxFiles` now counts **file parts only**, identically in 
both parsers.
   - New `struts.multipart.maxParameterCount` (default `256`) caps **non-file 
form fields**, restoring the DoS guard the old accidental total-part cap 
incidentally provided. The two limits are orthogonal.
   - Breaching either limit is **fail-closed**: the request is rejected with a 
recorded upload error and the action receives **no** partial parameters or 
files.
   - A negative value (`-1`) or unset limit means *unlimited*, following the 
commons-fileupload2 convention.
   - The `jakarta` parser keeps a coarse total-parts backstop (`maxFiles + 
maxParameterCount`, only when both are finite) so gross floods abort early 
inside commons.
   
   Design: 
`docs/superpowers/specs/2026-07-22-WW-5474-multipart-maxfiles-semantics-design.md`
   
   ## Behavior changes to be aware of (please review)
   
   1. **`jakarta-stream` gains a parameter-count cap it never had.** A 
`jakarta-stream` app legitimately posting **more than 256 form fields** will 
now fail at field 257 unless it raises `struts.multipart.maxParameterCount`. 
The default `jakarta` parser is strictly *more* permissive than before 
(previously fields+files shared one 256 budget; now 256 each).
   2. **Fail-closed now discards partial data on `maxSize`/`maxFileSize` 
breaches too** (not only the new limits). Previously the stream parser could 
expose parts collected before a size breach; now a rejected request exposes 
nothing. This is intentional hardening.
   3. **Gross-flood message differs by parser** (spec §6, accepted tradeoff): 
an all-fields flood exceeding the combined `512` total on the `jakarta` parser 
surfaces the generic `FileUploadFileCountLimitException` via the commons 
backstop, while the stream parser reports the precise 
`FileUploadParameterCountLimitException`. Both fail closed.
   
   ## Tests
   
   New/updated unit tests in `JakartaMultiPartRequestTest`, 
`JakartaStreamMultiPartRequestTest`, `AbstractMultiPartRequestTest` cover: many 
fields + few files accepted (the reported regression), over-`maxFiles` and 
over-`maxParameterCount` fail-closed, multiple files under one field name 
counted individually, and `maxFiles=-1` not clamped by the backstop. Full 
`core` module suite green (3003 tests); `ActionFileUploadInterceptorTest` 
regression green.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


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