Skip to content

fix(http): serve 0-0 and suffix byte ranges from the static handler - #913

Open
wleeaf wants to merge 1 commit into
ithewei:masterfrom
wleeaf:static-byte-ranges
Open

wleeaf wants to merge 1 commit into
ithewei:masterfrom
wleeaf:static-byte-ranges

Conversation

@wleeaf

@wleeaf wleeaf commented Oct 25, 2026

Copy link
Copy Markdown

The static file handler reads Range with sscanf("bytes=%ld-%ld") (HttpRequest::GetRange) and treats a last position of 0 as "to the end of the file". With httpd serving a 1000-byte file:

  • Range: bytes=0-0 returns the whole file as 206 with Content-Range: bytes 0-999/1000. Clients often send bytes=0-0 to probe for range support and the file size, and they get 1000 bytes instead of 1.
  • Suffix ranges (bytes=-10, bytes=-2000) always get 416, while bytes=-0 returns the whole file.
  • When sscanf doesn't match (for example items=0-5 or bytes=abc), from is left uninitialized, and the response depends on whatever value it held.

defaultStaticHandler now parses the first range itself, following RFC 9110 section 14.1.2:

  • It accepts first-last, first- and -length.
  • A last position or a suffix that goes past the end is clamped to the file.
  • A range that starts past the end still gets 416 with Content-Range: bytes */size.
  • A Range header with another unit or an invalid range (for example 5-2) is ignored, and the whole file is sent with 200.

The small-range path now reads exactly the selected bytes, because HFile::readrange treats to = 0 as "to the end" as well. HttpRequest::GetRange and HFile::readrange are unchanged.

The new unittest/http_static_range_test (added to the Makefile, CMake and scripts/unittest.sh) serves a 10-byte file and checks 0-0, 5-, -3, -20, 10- and items=0-1. Without the change it fails on 0-0 (bytes 0-9/10). With the change it passes. Results with httpd for a 1000-byte file:

Range before after
bytes=0-0 206 0-999 206 0-0
bytes=-10 416 206 990-999
bytes=-2000 416 206 0-999
bytes=-0 206 0-999 416
items=0-5 416 200
Bytes=0-1 416 206 0-1

The static file handler read Range with sscanf("bytes=%ld-%ld") and
treated a last position of 0 as "to the end of the file", so
"bytes=0-0" returned the whole file as "bytes 0-999/1000". Suffix ranges
("bytes=-500") were always answered with 416, "bytes=-0" got the whole
file, and a value sscanf could not match left `from` uninitialized.

The handler now parses the first range itself (RFC 9110 section
14.1.2): "first-last", "first-" and "-length", with a last position or a
suffix past the end clamped to the file. A Range header with another
unit or an invalid range is ignored and the whole file is sent; a range
starting past the end still gets 416. The small-range path reads exactly
the selected bytes, since HFile::readrange also treats to = 0 as "to the
end".

unittest/http_static_range_test serves a 10 byte file and checks 0-0,
5-, -3, -20, 10- and a non-bytes unit.
Copilot AI balanced review requested due to automatic review settings October 25, 2026 19:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

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