Summary
The snapshot downloader supports resumable downloads by keeping a .part file and retrying with a Range request starting at the existing partial file size.
However, when the server returns HTTP 206 Partial Content, the downloader does not verify that the response Content-Range start offset matches the local .part file size before appending the response body.
This means a server, CDN, cache, or proxy that returns a mismatched partial response can cause the downloader to append bytes from the wrong offset to the existing .part file. The resulting snapshot file can be corrupted while still being treated as a successful download.
Affected File
crates/snapshots/src/download.rs
Observed Behavior
When a partial file already exists, the downloader sends a request like:
Range: bytes=7-
If the server responds with:
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-3/11
the response starts at byte 0, not byte 7.
The current implementation still appends the returned body to the existing .part file instead of rejecting the response or restarting the download.
Expected Behavior
For resumable downloads, when a local .part file exists and the downloader requests:
Range: bytes=<existing_size>-
then a 206 response should only be accepted if the Content-Range start offset is exactly <existing_size>.
If the Content-Range start does not match the requested/local offset, the downloader should either:
- return an error, or
- discard the stale
.part file and restart the download from byte 0.
It should not append mismatched bytes to the existing partial file.
Reproduction
I verified this with a focused regression test against the current code.
The test creates a partial file containing:
prefix-
The partial file size is 7 bytes, so the downloader sends:
Range: bytes=7-
The mock server intentionally responds with a mismatched Content-Range:
Content-Range: bytes 0-3/11
and body:
pref
The expected behavior is for the downloader to reject this response. Instead, the current code accepts it and appends the bytes, so the regression test fails.
Test command used:
cargo +1.94.0 test -p arc-snapshots resumable_download_rejects_mismatched_content_range_start -- --nocapture
Result on current code:
test download::tests::resumable_download_rejects_mismatched_content_range_start ... FAILED
Failure message:
mismatched Content-Range should not append to the existing .part file
Why This Matters
A resumed snapshot download relies on the server returning exactly the missing byte range. If the response starts at a different offset, appending it to the local .part file produces a corrupted snapshot.
This can happen due to:
- a buggy origin server,
- a misbehaving proxy/cache/CDN,
- stale cached partial responses,
- or any server-side issue that returns an incorrect 206 response.
The downloader already tracks the local partial size and sends a precise Range request, so validating the returned Content-Range start would prevent accepting corrupted resumed downloads.
Suggested Fix
When resuming from an existing .part file:
- Parse the
Content-Range header on HTTP 206 responses.
- Extract the start offset.
- Compare it with the local partial file size / requested
Range start.
- If they differ, reject the response or restart from scratch.
For example:
- existing
.part size: 7
- request:
Range: bytes=7-
- valid response:
Content-Range: bytes 7-10/11
- invalid response:
Content-Range: bytes 0-3/11
The invalid response should not be appended to the existing .part file.
Potential Regression Test
A regression test can be added near the existing resumable download tests in crates/snapshots/src/download.rs.
Test idea:
- seed a
.part file with b"prefix-"
- configure the mock server to expect
Range: bytes=7-
- return HTTP 206 with
Content-Range: bytes 0-3/11
- assert that
run_resumable_download(...) returns an error
- assert that mismatched data is not accepted as a completed snapshot
Summary
The snapshot downloader supports resumable downloads by keeping a
.partfile and retrying with aRangerequest starting at the existing partial file size.However, when the server returns HTTP 206 Partial Content, the downloader does not verify that the response
Content-Rangestart offset matches the local.partfile size before appending the response body.This means a server, CDN, cache, or proxy that returns a mismatched partial response can cause the downloader to append bytes from the wrong offset to the existing
.partfile. The resulting snapshot file can be corrupted while still being treated as a successful download.Affected File
crates/snapshots/src/download.rsObserved Behavior
When a partial file already exists, the downloader sends a request like:
Range: bytes=7-
If the server responds with:
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-3/11
the response starts at byte 0, not byte 7.
The current implementation still appends the returned body to the existing
.partfile instead of rejecting the response or restarting the download.Expected Behavior
For resumable downloads, when a local
.partfile exists and the downloader requests:Range: bytes=<existing_size>-
then a 206 response should only be accepted if the
Content-Rangestart offset is exactly<existing_size>.If the
Content-Rangestart does not match the requested/local offset, the downloader should either:.partfile and restart the download from byte 0.It should not append mismatched bytes to the existing partial file.
Reproduction
I verified this with a focused regression test against the current code.
The test creates a partial file containing:
prefix-
The partial file size is 7 bytes, so the downloader sends:
Range: bytes=7-
The mock server intentionally responds with a mismatched
Content-Range:Content-Range: bytes 0-3/11
and body:
pref
The expected behavior is for the downloader to reject this response. Instead, the current code accepts it and appends the bytes, so the regression test fails.
Test command used:
cargo +1.94.0 test -p arc-snapshots resumable_download_rejects_mismatched_content_range_start -- --nocapture
Result on current code:
test download::tests::resumable_download_rejects_mismatched_content_range_start ... FAILED
Failure message:
mismatched Content-Range should not append to the existing .part file
Why This Matters
A resumed snapshot download relies on the server returning exactly the missing byte range. If the response starts at a different offset, appending it to the local
.partfile produces a corrupted snapshot.This can happen due to:
The downloader already tracks the local partial size and sends a precise
Rangerequest, so validating the returnedContent-Rangestart would prevent accepting corrupted resumed downloads.Suggested Fix
When resuming from an existing
.partfile:Content-Rangeheader on HTTP 206 responses.Rangestart.For example:
.partsize: 7Range: bytes=7-Content-Range: bytes 7-10/11Content-Range: bytes 0-3/11The invalid response should not be appended to the existing
.partfile.Potential Regression Test
A regression test can be added near the existing resumable download tests in
crates/snapshots/src/download.rs.Test idea:
.partfile withb"prefix-"Range: bytes=7-Content-Range: bytes 0-3/11run_resumable_download(...)returns an error