Skip to content

Conversation

@felipedmesquita
Copy link
Member

Context

PR #221 introduced the ability to abort a request from the on_headers user defined callbacks.
Before this PR , on_headers callbacks were called exactly one time and only once all headers are in, including from multiple redirects. This is the expected value for response_headers inside a on_headers callback for a request that followed a redirect:

HTTP/1.1 302 Found
Location: http://localhost:3001/
Content-Type: text/html;charset=utf-8
Content-Length: 0
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Server: WEBrick/1.9.1 (Ruby/3.4.5/2025-07-16)
Date: Wed, 27 Aug 2025 13:31:38 GMT
Connection: Keep-Alive

HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: 653
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Server: WEBrick/1.9.1 (Ruby/3.4.5/2025-07-16)
Date: Wed, 27 Aug 2025 13:31:38 GMT
Connection: Keep-Alive

Since we wanted all headers to be available to the callback, on_headers was actually called when the body write function started receiving data - and from the complete callback to handle requests without a body. This approach was endorsed by libcurl's author in response to a question about detecting the end of headers [0].

Problem

PR #221 moved the execution of on_headers to the actual header write function. I think this was done to allow aborting early, before starting to download the body and before following redirects. The problem is that libcurl calls the header write function once per header line, so when the user code in on_headers runs, response_headers contains only the status line (ex: HTTP/1.1 200 OK).
Since Typhoeus trims out the status line, when the callback ran, the headers were empty (#229, typhoeus/typhoeus#705, typhoeus/typhoeus#710).

Additionally, when following redirects, the change made so the callback was called immediately on the first line of headers received from the initial request, which is not the expected behavior (#231).

Solution

This PR reverts the change in #221 that made on_headers be called before receiving all headers, and keeps support for aborting from the callback by checking it's return value in the body write function.

Testing

We had a test that should have caught the unintended change in #221, but the test itself had a bug (fixed in a7af5c2). I've also modified the test for returning :abort from on_headers so that it checks that the request gets cancelled from the body write function.

Future improvements

We could offer a way for users to cancel an in-flight request right when they receive the header they need, which was the intention behind #221. This would require creating an new "raw" headers callback, to preserve the current expected on_headers behavior.

[0] https://curl.se/mail/lib-2009-02/0243.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

When Following Redirects on_headers Only Emits On First Response 0.16.0 broke a test in typhoeus

1 participant