Bug report
Bug description:
http.client.HTTPResponse doesn't handle negative reads the same as other readers, for example the following code will hang for a significant amount of time:
con = http.client.HTTPConnection("httpbin.org") con.request("GET", "/get") resp = con.getresponse() # "connection: close" doesn't trigger this assert resp.headers["connection"] == "keep-alive" while chunk := resp.read(-1): print(chunk)
The negative parameter is passed onto the underlying socket which will cause it to try and read to the end-of-stream. For keep-alive connections this just blocks until the connection is closed by the server due to inactivity.
I think this is a bug with not checking for negative amt values in:
| if self.length is not None and amt > self.length: | |
| # clip the read to the "end of response" | |
| amt = self.length |
Changing the call to read1 causes the above to display the response promptly as I'd expect. This is due to it correctly checking for negative sizes.
| if self.length is not None and (n < 0 or n > self.length): | |
| n = self.length |
Note that in earlier Python versions, e.g. 3.9, the above fails with ValueError: negative count which seems better than timing out, but I think reading to the end of the response makes more sense.
CPython versions tested on:
3.11, 3.12
Operating systems tested on:
Linux
Linked PRs
- gh-112064: fix incorrect handling of negative read sizes in
HTTPResponse.read()#128270 - [3.13] gh-112064: Fix incorrect handling of negative read sizes in
HTTPResponse.read()(GH-128270) #129395 - [3.12] gh-112064: Fix incorrect handling of negative read sizes in
HTTPResponse.read()(GH-128270) #129396