Skip to content

proxy_cache: reject zero-length and unsatisfiable suffix byte ranges (RFC 9110 §14.1.2) - #975

Open
r7eam wants to merge 1 commit into
cloudflare:mainfrom
r7eam:fix-range-unsatisfiable-zero-length
Open

proxy_cache: reject zero-length and unsatisfiable suffix byte ranges (RFC 9110 §14.1.2)#975
r7eam wants to merge 1 commit into
cloudflare:mainfrom
r7eam:fix-range-unsatisfiable-zero-length

Conversation

@r7eam

@r7eam r7eam commented Aug 24, 2026

Copy link
Copy Markdown

Summary

Fixes an issue where suffix byte range requests on zero-length representations (Range: bytes=-5 on Content-Length: 0) or zero-length suffix requests (Range: bytes=-0) were evaluated as satisfiable ranges (0..0 or 10..10).

Details & RFC Conformance

Per RFC 9110 Section 14.1.2:

"A suffix-byte-range-spec is unsatisfiable if the suffix-length is zero, or if the representation has a length of zero."

Previously:

  1. Range: bytes=-5 on a 0-byte representation evaluated to 0..0, causing range_header_filter to format r.end - 1 (0usize - 1usize), emitting Content-Range: bytes 0-18446744073709551615/0.
  2. For multipart range requests on 0-byte representations (e.g. Range: bytes=-2,-5), the underflow inflated calculate_multipart_length to declare Content-Length: 246 while delivering 0 payload bytes.
  3. Range: bytes=-0 on a 10-byte resource evaluated to 10..10, emitting Content-Range: bytes 10-9/10.

Solution

Inside parse_range_header, skip ranges where range.start >= range.end. When all specified ranges are unsatisfiable or skipped, ranges.is_empty() returns RangeType::Invalid, allowing Pingora to return 416 Range Not Satisfiable with Content-Range: bytes */{length} as required by RFC 9110.

Tests

  • Added unit tests covering bytes=-0 on a 10-byte resource and bytes=-5 on a 0-byte resource in test_parse_range.
  • Added end-to-end filter test test_range_filter_zero_length_suffix asserting 416 Range Not Satisfiable with Content-Range: bytes */0.

Per RFC 9110 Section 14.1.2, a suffix-byte-range-spec is unsatisfiable
if the suffix-length is zero (e.g. bytes=-0) or if the representation
length is zero (e.g. bytes=-5 on a 0-byte body).

Previously, parse_range_header returned 0..0 or 10..10 for these cases,
treating them as satisfiable single ranges. This caused an unchecked
arithmetic underflow (r.end - 1) when formatting Content-Range and
corrupted multipart Content-Length calculations.

Skip ranges where range.start >= range.end so that empty/unsatisfiable
range sets cleanly return RangeType::Invalid (416 Range Not Satisfiable).
@r7eam
r7eam force-pushed the fix-range-unsatisfiable-zero-length branch from 11b656b to 4d0d63d Compare August 24, 2026 17:12
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.

1 participant