Skip to content

feat(static): add byte-range request support - #275

Merged
pi0 merged 3 commits into
mainfrom
feat/static-range
Jul 17, 2026
Merged

feat(static): add byte-range request support#275
pi0 merged 3 commits into
mainfrom
feat/static-range

Conversation

@pi0x

@pi0x pi0x commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Adds single-range Range: bytes= support to serveStatic, behind a new ranges option (default true).

Behavior

  • 206 Partial Content for a single-range GET: Content-Range: bytes <start>-<end>/<size>, part-length Content-Length, body streamed from the fd with createReadStream({ start, end }). Validators, Cache-Control, and Vary carry over from the 200.
  • Identity-only: a bytes= range request bypasses content negotiation — no precompressed variant, no on-the-fly compression. Range consumers (media seek, download resumption) target already-compressed types, and a range over chunked on-the-fly output is not expressible. A non-bytes unit is treated as no Range header at all.
  • Precedence (RFC 9110 §13.2.2): If-None-Match / If-Modified-Since still evaluate first, so a 304 outranks a range. If-Range is honored: the entity-tag form never matches (our ETags are weak and the comparison must be strong — clients fall back to a full 200), the date form matches on exact-second equality with Last-Modified.
  • 416 with Content-Range: bytes */<size> when nothing is satisfiable (start past EOF, bytes=-0, any range on an empty file). Malformed and multi-range headers are ignored per RFC §14.2 and answered with the full 200.
  • Accept-Ranges: bytes advertised on identity (non-encoded) responses; omitted on encoded responses and entirely when ranges: false.

Also rewords the computeETag comment whose "this middleware does not answer byte-range requests" rationale is now stale.

Tests

18 new tests in test/static.test.ts: basic/open-ended/suffix/clamped ranges, multi-range and malformed fallbacks, both 416 shapes, all three If-Range forms, HEAD ignoring Range, identity-only ranges on compressible files (on-the-fly and disk-variant paths), 304-beats-Range, ranges: false, and Accept-Ranges presence/absence. vitest run test/static.test.ts test/static-nonblock.test.ts: 160/160 passing.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added single byte-range (Range: bytes=...) support for static files with correct 206 Partial Content Content-Range and length handling.
    • Added Accept-Ranges: bytes for eligible identity 200 responses.
    • Added ranges?: boolean option to enable/disable range handling (default enabled).
  • Bug Fixes

    • Updated If-Range matching semantics and fallbacks: malformed/multi-range/non-matching cases serve full 200; unsatisfiable ranges return 416 with Content-Range: bytes */<length>.
    • Ensures HEAD ignores Range, and range responses avoid content negotiation/compressed variants.
  • Tests

    • Added fixture and coverage for range edge cases, If-Range, and disabled-range behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pi0x
pi0x requested a review from pi0 as a code owner July 17, 2026 21:46
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Static file serving now supports configurable single-byte Range requests, If-Range validation, 206 and 416 responses, identity-only range delivery, conditional Accept-Ranges, and comprehensive test coverage.

Changes

Static byte-range handling

Layer / File(s) Summary
Range entry and identity representation
src/static.ts
Adds the ranges option, detects GET byte-range requests, bypasses compression negotiation, and advertises identity range support.
Range validation and response construction
src/static.ts
Adds If-Range and range parsing behavior for 206, 416, or full responses after conditional validation.
Byte-range behavior coverage
test/static.test.ts
Adds fixture data and tests for parsing, validators, HEAD requests, disabled ranges, compression interactions, and response headers.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related issues

  • h3js/h3 issue 1267 — Directly addresses HTTP byte-range support for serveStatic.

Possibly related PRs

  • h3js/srvx#252 — Reworks precompressed variant selection in the same static-serving paths affected by range handling.
  • h3js/srvx#269 — Modifies the static-file validator logic extended here for If-Range.

Suggested reviewers: pi0

Poem

I’m a rabbit with bytes in my burrow,
Slicing files neat as a carrot row.
206 hops when ranges align,
416 thumps when bounds decline.
Validators guard the night.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: byte-range request support in static serving.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/static-range

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 17, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/srvx@275

commit: 3d6f39e

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/static.ts`:
- Around line 370-371: Update the range-header detection near rangeHeader and
the parseRange() function to accept case-insensitive “bytes” units and optional
whitespace after the equals sign, including values such as “Bytes=” and “bytes=
0-4”. Normalize the unit and trim permitted optional whitespace before parsing,
while preserving partial-content handling for valid ranges.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fc87c279-3f5f-4d60-a62f-e0d2ee28644b

📥 Commits

Reviewing files that changed from the base of the PR and between aad353f and bc6c48e.

📒 Files selected for processing (2)
  • src/static.ts
  • test/static.test.ts

Comment thread src/static.ts Outdated
pi0 and others added 2 commits July 17, 2026 21:58
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e's grammar

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/static.ts`:
- Around line 396-399: Update the Range header detection near rangeRequest
initialization in src/static.ts lines 396-399 to accept case-insensitive “bytes”
units and optional spaces or tabs after “=”, while preserving the existing
header fallback behavior. Also update the range parsing regex in src/static.ts
lines 731-738 to accept the same case variations and optional whitespace so
extracted boundaries remain correct.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 126d703b-3e6d-41d2-8631-c3d9bf8c0948

📥 Commits

Reviewing files that changed from the base of the PR and between 9f9d734 and 3d6f39e.

📒 Files selected for processing (1)
  • src/static.ts

Comment thread src/static.ts
@pi0
pi0 merged commit 0e77d9f into main Jul 17, 2026
16 checks passed
@pi0
pi0 deleted the feat/static-range branch July 17, 2026 22:20
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