Skip to content

Download resume can silently corrupt files if server ignores Range header #4710

@kim-em

Description

@kim-em

When resuming a partial download (resume_from > 0), rustup sends a Range: bytes=N- header and appends the response to the existing partial file. However, it doesn't verify that the server actually honored the Range request.

If the server ignores the Range header and returns 200 OK with the full file (instead of 206 Partial Content), the full file content gets appended to the partial file, producing a corrupted result.

The response code check accepts any 2xx:

rustup/src/download/mod.rs

Lines 302 to 307 in b3fdca3

cb(Event::DownloadDataReceived(&buf[..n]))?;
}
downloaded_so_far
} else {
let file_info = partial.metadata()?;

match code {
    0 | 200..=299 => {}
    _ => {
        return Err(DownloadError::HttpStatus(code).into());
    }
};

When resume_from > 0, this should verify that the response is 206 Partial Content. If the server returns 200, the download should either restart from scratch (truncating the partial file) or return an error.

The reqwest backend has the same issue — it checks res.status().is_success() without distinguishing 200 from 206.

Found while porting rustup's download resume logic to elan.

This issue has been assigned to @FranciscoTGouveia via this comment.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions