Skip to content

fix: _range() log spam, Content-Length clamping, multipart terminator off-by-one#11

Draft
troglodyne-bot wants to merge 1 commit into
Troglodyne-Internet-Widgets:masterfrom
troglodyne-bot:koan/fix-range-response-bugs
Draft

fix: _range() log spam, Content-Length clamping, multipart terminator off-by-one#11
troglodyne-bot wants to merge 1 commit into
Troglodyne-Internet-Widgets:masterfrom
troglodyne-bot:koan/fix-range-response-bugs

Conversation

@troglodyne-bot

Copy link
Copy Markdown
Contributor

What

Three bugs in _range(), none addressed by open PRs #4#10.

Why

  1. INFO "GET 416" log spam$self->INFO("GET 416 $fullpath") fired unconditionally before the range validation check, meaning every valid byte-range request logged a false 416. Fail2ban rules watching for 416s would incorrectly ban clients making legitimate ranged GETs.

  2. Content-Length not clamped to file size — When a client requests bytes=0-9999 on a 5-byte file, RFC 7233 §2.1 says to silently cap the range end. The streaming write already used List::Util::min($sz, ...) so the actual bytes sent were correct, but Content-Length was computed from the unclamped $range->[1]. Clients received a header promising 10,000 bytes and then only 5 — hanging indefinitely waiting for data that would never come. Content-Range in the response was also wrong (claimed bytes 0-9999/5 instead of bytes 0-4/5).

  3. Multipart terminator Content-Length off by one — The Content-Length calculation used length("\n--$CHUNK_SEP\--\n") where \- in a double-quoted Perl string passes through as a literal backslash. The streaming write (fixed separately by PR Fix multipart boundary, HTTP::Body dep, NYTProf overhead, error fallback #4) uses "\n--$CHUNK_SEP--\n" without the backslash. The mismatch made declared Content-Length one byte larger than the actual body for every multipart range response.

How

  • Moved INFO("GET 416") inside the failure branch
  • Added $range->[1] = $sz - 1 if $range->[1] >= $sz immediately after the //= default, before the Content-Length sum and Content-Range header — one clamp fixes all three header values
  • Changed length("\n--$CHUNK_SEP\--\n")length("\n--$CHUNK_SEP--\n") in the Content-Length accumulation

Testing

t/01-range-response.t — 19 tests:

  • 416 for out-of-bounds start and inverted range
  • 206 + correct Content-Length/body for single range
  • Overlong range: Content-Length clamped, body correct, Content-Range header correct
  • Suffix range (bytes=N- with no end): defaults to last byte
  • Multipart: Content-Length matches actual body length (regression for terminator off-by-one)

…nator length

Three bugs in _range(), none covered by open PRs:

1. INFO("GET 416") was called unconditionally before the range validation
   check, so every valid range request logged "GET 416 <path>". Besides
   filling logs with false 416 entries, any fail2ban rule on 416 responses
   would ban clients making legitimate ranged requests. Moved the INFO call
   inside the failure branch.

2. When a Range header specifies an end byte past the file size (e.g.
   bytes=0-9999 on a 5-byte file), RFC 7233 §2.1 says to clamp to the last
   byte. The Content-Length calculation used the unclamped $range->[1],
   producing a declared length far larger than the actual bytes sent. Clients
   would stall waiting for data that never arrives. Added an explicit clamp
   before the Content-Length sum. The streaming write already used
   List::Util::min($sz, ...) so actual output was correct — only the header
   was wrong. Content-Range in the response is also now correct.

3. The multipart terminator Content-Length calculation used "\--" (with a
   literal backslash, length N+1) while the streaming write already uses
   "--" (N). The off-by-one made declared Content-Length one byte larger
   than the actual response body for every multipart range response.

Tests: t/01-range-response.t — 19 tests covering 416 validation, single and
multipart range bodies, suffix ranges, overlong range clamping (Content-Length,
body, Content-Range header), and multipart Content-Length accuracy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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