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]
