accept case-insensitive range units in http_range - #13584
Conversation
RFC 9110 sec. 14.1.1 states that range unit names are case-insensitive, but BaseRequest.http_range matched the Range header with a case-sensitive pattern. A request sending "Range: Bytes=0-3" raised ValueError, which FileResponse turns into 416 Range Not Satisfiable even though the range is satisfiable. re.IGNORECASE is added alongside the existing re.ASCII rather than replacing it. That matters: with IGNORECASE alone, Unicode case folding would also accept "byteſ=0-3" (LATIN SMALL LETTER LONG S), since U+017F folds to "s". Keeping re.ASCII confines folding to ASCII, so the only newly accepted spellings are the ASCII case variants of "bytes". Tests cover the accepted variants and add a regression test asserting the long-s spelling is still rejected.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #13584 +/- ##
=======================================
Coverage 99.02% 99.02%
=======================================
Files 135 135
Lines 50500 50509 +9
Branches 2652 2652
=======================================
+ Hits 50007 50016 +9
Misses 370 370
Partials 123 123
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
|
Confidence Score: 5/5The PR appears safe to merge with no actionable correctness, compatibility, or security issues identified. The regex now accepts precisely the intended ASCII case variants, preserves existing range parsing semantics and non-ASCII rejection, and is covered by focused regression tests. Reviews (1): Last reviewed commit: "add PR-numbered changelog symlink" | Re-trigger Greptile |
What do these changes do?
BaseRequest.http_rangematched theRangeheader with a case-sensitive pattern,so a range unit written with any uppercase letters was rejected. RFC 9110
sec. 14.1.1 states that range unit names are case-insensitive.
re.IGNORECASEis added alongside the existingre.ASCIIrather than replacingit. That distinction matters: with
re.IGNORECASEalone, Unicode case folding alsoaccepts
byteſ=0-3(U+017FLATIN SMALL LETTER LONG S, which folds tos), whichis not a valid spelling of the
bytesunit. Keepingre.ASCIIconfines folding toASCII, so the only newly accepted spellings are ASCII case variants of
bytes.A regression test asserts the long-s spelling is still rejected, alongside the
existing
test_range_non_ascii.Are there changes in behavior for the user?
Yes, and only in the permissive direction. A
Rangeheader whose unit is spelledwith uppercase letters is now honoured instead of rejected. Previously
:class:
~aiohttp.web.FileResponseturned the resultingValueErrorinto416 Range Not Satisfiablefor a range that was in fact satisfiable:Nothing that was previously accepted changes meaning, and no header that should be
invalid becomes valid.
Is it a substantial burden for the maintainers to support this?
No. It is a one-flag change to an existing regex in a single property, with no new
API, no new dependency, and no configuration. The added tests pin both directions —
the ASCII case variants that must be accepted, and the Unicode look-alike that must
not be — so the ASCII-only constraint cannot be dropped later without a test failing.
Related issue number
Fixes #13580
Checklist
docs/web_reference.rstdocumentshttp_rangewithout specifying unit case, soit already describes the corrected behaviour; no docs change was needed. N/A
CONTRIBUTORS.txtCHANGES/folderCHANGES/13580.bugfix.rstAgent run output — test logs
Pure-Python mode, macOS arm64, Python 3.12.
Targeted tests, with the fix applied:
Reverting only
aiohttp/web_request.py(tests untouched), to confirm the newtests actually exercise the fix:
Wider sweep:
End-to-end against a live
web.FileResponseserver over TCP, which is where the416 is user-visible (output quoted in the behaviour section above).
Lint, compared against the unmodified
origin/mastercopies of the same two filesso that pre-existing findings are not attributed to this change:
Not tested with Cython extensions: this change is in
web_request.pyand does nottouch the llhttp parser or websocket code.
Drafted with Claude Opus 5 (Claude Code); reviewed by @LALITH0110.