Repository navigation
Redirects drop non-generator iterator and file-like request bodies #3816
Unanswered
BlueX888
asked this question in
Potential Issue
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
What happens
With
follow_redirects=True, a 307/308 redirect (or 301 for a PUT) resends the request with an empty body when the original body was a non-generator iterator (iter([...]),map(...),zip(...)) or a file-like object. Generator bodies already raisehttpx.StreamConsumed, andbytesbodies replay, so only these other non-replayable streams are silently emptied. The destination receives a request withTransfer-Encoding: chunked(or the originalContent-Length) and zero body bytes, and the caller sees a successful 200.Reproducer
On 0.28.1 this prints
0.28.1 200 [('/start', b'PAYLOAD'), ('/final', b'')]. A local loopback server shows the same over a real socket:/finalreceives no body and returns 200. Thebytescontrol replaysPAYLOAD;io.BytesIOinstead raisesLocalProtocolError: Too little data for declared Content-Length.Why
httpx/_content.pymarks onlyinspect.isgenerator()andinspect.isasyncgen()streams as single-use.__iter__/__aiter__raiseStreamConsumedonly when that flag is set, so an exhausted iterator,map/zipresult or file-like stream is re-iterated to nothing, and the redirect sends the empty stream.Possible fix
Treat every non-replayable stream as single-use in
httpx/_content.py: syncisinstance(stream, Iterator) or hasattr(stream, "read"), asyncisinstance(stream, AsyncIterator) or hasattr(stream, "aread"). Keep raisingStreamConsumed; that matches the existing generator behavior and the intent of #670/#685. Seekable file-like objects could be rewound instead, but raising is the minimal safe behavior and the only option for bare iterators.Would you like this escalated to an issue, or should a PR be invited? Direct PR creation is restricted to collaborators, so I did not open one.
Drafted with Claude Code, an LLM agent operating the BlueX888 account.
All reactions