requests: HTTP/1.1 with Content-Length and streaming raw#1124
Conversation
ESP32 hardware testingTested on device connected via
Mock tests (
|
| Test | Result |
|---|---|
GET /get with Content-Length body |
200, 11 bytes |
GET /bytes/8 via .content |
abcdefgh, socket closed after read |
GET /bytes/10 incremental .raw.read(3) + .raw.read(3) + .raw.read() |
3+3+4 bytes → 0123456789 |
GET /chunked |
ValueError: Unsupported Transfer-Encoding: chunked (expected for v1) |
Server log confirmed outbound requests use HTTP/1.1:
GET /get HTTP/1.1
GET /bytes/8 HTTP/1.1
GET /bytes/10 HTTP/1.1
GET /chunked HTTP/1.1
Notes
httpbin.orgreturned 503 from this network, so live body tests used a local test server instead.- Mock tests replace
sys.modules["socket"]; live tests reloadusocketafterwards before hitting the network.
|
Done — I moved everything from Re-ran Let me know if anything else should change before you take another look. |
|
Also re-tested on the same ESP32 as in my earlier comment (ESP32-D0WD on |
|
Thanks for the review, @dpgeorge — much appreciated. I've inlined CI should re-run shortly. Happy to adjust anything else. |
|
Re-tested after inlining the helpers and the ruff fix (commit d3c3628): Unix port - ESP32 (ESP32-D0WD,
CI re-running on d3c3628. |
| reason = l[2].rstrip() | ||
| line = s.readline() | ||
| if not line: | ||
| raise ValueError("HTTP error: empty status line") |
There was a problem hiding this comment.
I don't think this check is needed. If line is empty then the len(parts) < 2 will catch that.
|
Thanks again for the detailed review, @dpgeorge. Addressed the latest round in the new commit:
Re-tested on unix port: Happy to adjust further if needed. |
|
Thanks for the follow-up comments, @dpgeorge. Addressed in commit 8b20e5c:
Re-tested on unix port: |
|
Good question. I checked CPython 3.12 with requests 2.31 / urllib3 2.0.7 on a response with Content-Length: 10 but only 3 body bytes before close:
So streaming behaviour is: partial reads are fine; exception when you try to read past EOF with Content-Length still outstanding. That matches what BodyStream does (ValueError instead of IncompleteRead, for simplicity). Applied your suggestion in 6372c93: the check is now |
|
Thanks for updating. Looking at how Also regarding the tests: you can see in #1128 that I enhanced the mock socket so you can call (Eventually the test for |
|
Thanks for the follow-up, @dpgeorge. Added This covers the Added Left the |
baa3d77 to
51491f8
Compare
| if self._remaining == 0: | ||
| return 0 | ||
| n = min(len(buf), self._remaining) | ||
| got = self._sock.readinto(memoryview(buf)[:n]) |
There was a problem hiding this comment.
So that this doesn't unnecessarily create memoryview objects, I suggest only slicing if needed, ie:
if len(buf) > self._remaining:
buf = memoryview(buf)[:self._remaining]
got = self._sock.readinto(buf)|
Thanks for the review, @dpgeorge. Addressed the latest round in f23463f and cf1492d:
Re-tested on the unix port: |
dpgeorge
left a comment
There was a problem hiding this comment.
Thanks for updating. This looks in good shape now. I tested with mip and it seems to work well.
Changes: - Send HTTP/1.1 requests (was HTTP/1.0). - Support Content-Length response bodies without buffering in request(). - Preserve .raw as a live BodyStream wrapper; .content remains lazy. Signed-off-by: Pablo Ventura <pablogventura@gmail.com>
cf1492d to
68f8fe4
Compare
|
I squashed the commits into one. And changed the version in the manifest to 1.0.0 because this is a pretty big change to use HTTP/1.1. |
Summary
_httpmodule.Content-Lengthresponse bodies without buffering inrequest()..rawas a liveBodyStreamwrapper;.contentremains lazy.Closes the approach in #1119 (which buffered the full body and closed the socket). Chunked responses,
max_body, and relative redirects are intentionally left for follow-up PRs.Testing
micropython test_requests.py(unix port) — 13 mock tests including incremental.raw.read().Trade-offs and Alternatives
ValueError(unchanged from master until a follow-up PR).BodyStreamadds a small wrapper object (~two fields) instead of buffering the body inrequest().stream=Trueis not implemented yet (issue requests: stream parameter is noop #777).Generative AI
I used generative AI tools when creating this PR, but a human has checked the
code and is responsible for the code and the description above.