Skip to content

_parse_request_range: accept range unit in any case per RFC 7233#3660

Open
HrachShah wants to merge 1 commit into
tornadoweb:masterfrom
HrachShah:fix/parse-request-range-case-insensiti
Open

_parse_request_range: accept range unit in any case per RFC 7233#3660
HrachShah wants to merge 1 commit into
tornadoweb:masterfrom
HrachShah:fix/parse-request-range-case-insensiti

Conversation

@HrachShah

Copy link
Copy Markdown

Summary

The pre-fix code compared the range unit with a case-sensitive equality check (if unit != "bytes"), so an incoming Range: BYTES=1-2 (or any non-lowercase variant) was treated as an unknown unit and silently returned None.

RFC 7233 §2.1 explicitly says:

Note that all rules derived from token are to be compared case-insensitively, like range-unit and acceptable-ranges.

The fix lowercases the unit before the comparison. The actual start/end numeric values are still parsed from the same string and are unaffected.

Repro

Tests

  • test_lowercase_unit baseline (still passes).
  • test_uppercase_unit_accepted (new): BYTES=1-2(1, 3). Fails on master.
  • test_mixed_case_unit_accepted (new): Bytes=1-2 and bYtEs=1-2 both pass. Fails on master.
  • test_uppercase_unit_with_suffix_range (new): BYTES=6-(6, None), BYTES=-6(-6, None). Fails on master.
  • test_non_bytes_unit_still_rejected (new): items=1-2None (passes on master too — sanity check).

All 5 new tests pass with the fix; the three uppercase/mixed-case tests fail on master. The full tornado.test.httputil_test suite (62 tests) still passes.

Docstring

Added a doctest line demonstrating the new behaviour:

Closes the gap that a perfectly-spec-compliant Range: BYTES=1-2 header was being ignored, even though Tornado would happily serve a 206 Partial Content response to a client that had the wrong case in the request.

The pre-fix code compared the range unit with `unit != "bytes"`, which
rejected any Range header that didn't spell the unit in exactly lowercase.
RFC 7233 section 2.1 is explicit: "all rules derived from token are to
be compared case-insensitively, like range-unit and acceptable-ranges."

A conforming client that sends `Range: BYTES=1-2` was being silently
rejected, and the request was treated as having no Range header at all.
Switching the comparison to `unit.lower() != "bytes"` makes the parser
match the RFC, while still rejecting unknown units (which is the only
behaviour the rest of the function relies on downstream of this check).

Added a doctest and a small ParseRequestRangeTest class covering the
lowercase baseline, the uppercase case, the mixed-case form, the
suffix and -N range shapes, and the negative case (an unknown unit
like "items" still returns None).
@bdarnell

bdarnell commented Jul 4, 2026

Copy link
Copy Markdown
Member

LGTM. I think the test failure just needs a rebase onto #3678

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants