Skip to content

fix(download): answer Range on an empty cache entry the same way on every storage driver - #291

Merged
LouisHaftmann merged 2 commits into
devfrom
fix/investigate-issue-290
Oct 24, 2026
Merged

LouisHaftmann merged 2 commits into
devfrom
fix/investigate-issue-290

Conversation

@LouisHaftmann

@LouisHaftmann LouisHaftmann commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

📝 Summary

A Range request on an empty Cache Entry got a different answer depending on the storage driver: 416 on filesystem and GCS, 200 or 416 on Azure depending on the start, and an empty 200 on S3. Now every driver answers with an empty 200. RFC 9110 §14.2 allows ignoring Range, and the route already does that for unmerged entries.

 download = storage.download(locationId, range)
 catch RangeNotSatisfiableError
+  if entry is empty
+    return 200, content-length: 0
   return 416, content-range: bytes */size

This also adds the missing test for the client-abort half of #282: if the client hangs up mid-download, the route destroys the storage stream, which releases the Storage Reader Lease.

Both commits are by @peter-svensson, cherry-picked unchanged from their fork.

✅ Verification

sqlite + filesystem, tests/range-download.test.ts and tests/proxy-backpressure.test.ts:

  • Before: an empty merged entry answers bytes=0- / bytes=5- with an empty 200 fails with expected 416 to be 200
    After: passes
  • Before: with sendStream in place of pipeline, download destroys the storage stream when the client hangs up fails with expected false to be true
    After: passes with pipeline (13/13 tests pass in both files)

S3, GCS, and Azure Blob were not run locally; CI's matrix covers them.

🔗 Issues

Closes #290

💥 Merge danger

Door: two-way

Blast Radius: small

Only affects Range requests on empty Cache Entries, which used to get a 416 on some drivers.

🤖 Generated with Claude Code

An empty entry has no satisfiable range. The filesystem and GCS adapters raise
RangeNotSatisfiable for any Range on one, Azure for any start past 0, while
RustFS (the S3 backend in CI) answers bytes=0- with an empty 200. The response
therefore depended on the configured storage driver.

The route now ignores Range when the entry is empty and sends an empty 200,
which RFC 9110 section 14.2 allows.

Claude-Session: https://claude.ai/code/session_01RdsMKiGYJmUC1RdLmCBsN2
(cherry picked from commit f053636)
… hangs up

Guards the client-abort half of #282: with sendStream an aborted download kept
reading the backend and held its reader lease until it expired.

Claude-Session: https://claude.ai/code/session_01RdsMKiGYJmUC1RdLmCBsN2
(cherry picked from commit c8f7c93)
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.

Two follow-ups to #270/#282: empty-entry Range handling and a client-abort test

2 participants