Debug a POST With a Stream Body That Hangs After a 307 Redirect in Python Requests
Company: Stripe
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Technical Screen
You are given a working copy of **Requests**, the widely used Python HTTP client library, into which a bug has been planted. One bug is reported for this repository, though the report is not certain it is the only one. Assume a reproduction shows the following.
A client sends a `POST` whose body is a file-like object, such as `io.BytesIO(b"amount=100")`, to a URL that answers `307 Temporary Redirect` with a `Location` header. Requests follows the redirect automatically, but the request to the new location never completes: it waits until the client's read timeout fires, or forever if no timeout is set. The same `POST` with a plain `bytes` body completes normally, and so does the file-like body when the server does not redirect.
Explain exactly why the redirected request hangs, find the root cause in the library, fix it, and prove the fix with a regression test.
```hint Look at what goes over the wire
Compare what the redirected request's headers promise with the bytes the client actually sends after them, and ask what each side is waiting for.
```
```hint Same request, second send
Ask what a file-like body remembers between two sends that a bytes body does not, and which part of the library is responsible for it before the request goes out again.
```
### Constraints and Clarifications
- Change only the library and its tests; the redirecting server behaves correctly.
- Requests follows redirects for `POST` by default; keep that behavior.
- The body in the reproduction is seekable and its length is known up front, so it is sent with a `Content-Length` header.
### Clarifying Questions
- Does the same hang occur for `308 Permanent Redirect`, and for `301`, `302` and `303`?
- What should happen on a redirect when the body cannot be rewound, for example a generator or a pipe?
- If the stream was not at its start when the request was made, which bytes should the redirected request send?
- Should a redirect to a different host re-send the body at all?
### What a Strong Answer Covers
- A precise explanation of the hang: what each side sends and waits for, and why it ends in a timeout instead of an error
- How the body's state was traced through preparing, copying and re-sending the request
- A fix at the layer that re-sends the request, covering streams that start mid-way and streams that cannot be restored
- Why only some redirect status codes expose the bug
- A regression test that reproduces the original failure quickly and deterministically, without hanging the test suite
### Follow-up Questions
- The body is a generator that yields chunks. What should Requests do when the server answers `307`?
- A teammate proposes recomputing `Content-Length` from the stream before re-sending. It stops the hang. Why is it still wrong?
- On a `307` to a different host, which headers should Requests keep, and which must it drop?
- How would you test this without opening sockets, and what would that test no longer prove?
Overview: A debugging exercise in the Python Requests library: a POST with a file-like body hangs after a 307 Temporary Redirect until the client times out. It tests reasoning about the bytes on the wire, HTTP redirect semantics, stream state across a re-sent request, and writing a deterministic regression test.
Read the full Stripe Software Engineer interview experience this question came from