Conversation
A server can advertise byte ranges, then return the full file with status 200 to a resumed request. The downloader previously appended that body to the partial file and reported success. The regression test checks the response is rejected and the destination is not published.
A resumed request must return HTTP 206. If a server ignores Range and returns 200, close the response and raise ChunkedEncodingError so the partial data cannot be combined with a full file.
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/poetry/utils/download.py" line_range="102-106" />
<code_context>
)
try:
response.raise_for_status()
+ if start > 0 and response.status_code != 206:
+ raise ChunkedEncodingError(
+ f"Server ignored the Range request while resuming {self._url}."
</code_context>
<issue_to_address>
**issue (bug_risk):** A resumed response with an HTTP error status such as 416 or 500 raises requests' HTTPError before the new status check runs, so it does not raise the promised ChunkedEncodingError for every non-206 resumed response.
**Triggers:** When the server responds to the resume request with a non-206 error status.
**Suggested fix:** Check `response.status_code != 206` before `raise_for_status()` (or convert the resulting HTTPError to ChunkedEncodingError) while still closing the response.
```suggestion
if start > 0 and response.status_code != 206:
raise ChunkedEncodingError(
f"Server ignored the Range request while resuming {self._url}."
)
response.raise_for_status()
```
</issue_to_address>Sourcery assessment
Approval pending. 1 finding to address first.
Blocking findings: src/poetry/utils/download.py:106
| response.raise_for_status() | ||
| if start > 0 and response.status_code != 206: | ||
| raise ChunkedEncodingError( | ||
| f"Server ignored the Range request while resuming {self._url}." | ||
| ) |
There was a problem hiding this comment.
issue (bug_risk): A resumed response with an HTTP error status such as 416 or 500 raises requests' HTTPError before the new status check runs, so it does not raise the promised ChunkedEncodingError for every non-206 resumed response.
Triggers: When the server responds to the resume request with a non-206 error status.
Suggested fix: Check response.status_code != 206 before raise_for_status() (or convert the resulting HTTPError to ChunkedEncodingError) while still closing the response.
| response.raise_for_status() | |
| if start > 0 and response.status_code != 206: | |
| raise ChunkedEncodingError( | |
| f"Server ignored the Range request while resuming {self._url}." | |
| ) | |
| if start > 0 and response.status_code != 206: | |
| raise ChunkedEncodingError( | |
| f"Server ignored the Range request while resuming {self._url}." | |
| ) | |
| response.raise_for_status() |
|
What servers advertise support for ranges and do not support ranges? Did you raise a bug against them? |
|
Good question. No, I don't have a specific server that did this, and I haven't filed a bug against one. I added the check because RFC 9110 (section 14.2) lets a server ignore a To be fair about the impact: poetry checks the archive hash after downloading, so a file stitched together like this would still fail the install. It would fail with a hash mismatch though, which points at the wrong problem. This change makes it fail at the download step, with an error that says what actually happened. If you don't think that's worth the extra code, I'm happy to close it. |
Summary
Poetry resumes a partial download when the first response advertises
Accept-Ranges: bytes. Some servers still ignore the laterRangerequest and return200with the full file. Poetry then appends that full body to the partial body and reports a successful download.For example, if the first request yields
abcdfrom an eight byte file, the retry asks forbytes=4-. If the server returns the fullabcdefghwith status200, the old code writesabcdabcdefgh.The downloader now requires status
206for a resumed request. It closes a response with any other status and raisesChunkedEncodingError. The existingatomic_opencontext leaves the destination unpublished on failure.Tests
The new test models a server that advertises ranges on the first response and ignores the range on the retry. It failed on
mainbecause no error was raised. The two existing retry stubs now expose the HTTP status for their initial and resumed responses.pytest tests/utils/test_download.py tests/installation/test_executor.py -q -o addopts='': 106 passed, 1 skipped.Checklist