Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #13640 +/- ##
=======================================
Coverage 99.02% 99.02%
=======================================
Files 135 135
Lines 50845 50865 +20
Branches 2674 2675 +1
=======================================
+ Hits 50351 50371 +20
Misses 370 370
Partials 124 124
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
Merging this PR will not alter performance
Comparing Footnotes
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What do these changes do?
MultipartReader.next()has a special case for the RFC 7578 §4.6_charset_field: when the first part of a
multipart/form-databody is named_charset_,its value is read as the default charset and the next part is returned instead.
That branch read the
_charset_part's body and then calledfetch_next_part()directly, so the delimiter line that terminates the
_charset_part was neverconsumed.
fetch_next_part()therefore fed the boundary line intoHeadersParser, which raisedInvalidHeader. These changes release the_charset_part and read its delimiter with_read_boundary()before fetchingthe next part, and return
Nonewhen that delimiter turns out to be the closingone.
Are there changes in behavior for the user?
Yes — a
multipart/form-databody containing a_charset_field is now parsedinstead of raising. Previously the boundary line was consumed as a header, so
await request.post()raisedInvalidHeaderand the server answered500 Internal Server Error for every boundary that does not itself parse as a
name: valuepair — i.e. for every realistic boundary. The existing coverageonly passed because it uses the boundary
:, which makes the delimiter line--:parse as a (bogus) header named--, silently attached to the followingpart's headers. That stray header is gone now too. No API changes.
Is it a substantial burden for the maintainers to support this?
No. It is five lines inside the existing
_charset_branch, reusingBodyPartReader.release()andMultipartReader._read_boundary()— the same twosteps the ordinary
next()path already performs between parts. No new helpers,no new public surface.
Related issue number
None — found while probing the multipart header/boundary seams. Happy to file one
if you prefer an issue on record.
Checklist
CONTRIBUTORS.txt— already listedCHANGES/folderReproducer
Before:
500 500 Internal Server Errorwithaiohttp.http_exceptions.InvalidHeader: Invalid HTTP header: b'------WebKitFormBoundaryABC'raised from
multipart.py:832 fetch_next_part→multipart.py:935 _read_headers.After:
200 {"field1": "foo"}.Agent run output — tests before and after
Environment: pure-Python mode,
AIOHTTP_NO_EXTENSIONS=1 PYTHONPATH=. python -m pytest(CPython 3.11.15). The C extension only substitutes
HttpRequestParser/HttpResponseParser/RawRequestMessage/RawResponseMessage(
http_parser.py:1241-1248);MultipartReader._read_headers()always uses the pure-PythonHeadersParser, so this change has no Cython-dependent behaviour.1. New tests fail on the unpatched tree (
aiohttp/multipart.pyrestored fromorigin/master, new tests present):2. Whole multipart suite passes with the fix:
3. No regressions in the server request path:
4. Toolchain on the touched files:
Drafted with Claude Code (Claude Opus 5 and Fable 5.1); human review by @2sumtech pending before this leaves draft.