Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breaking change from 0.9.10 to 0.9.11 due to #240 (presumably) #250

Closed
passcod opened this issue Nov 10, 2020 · 7 comments · Fixed by #251 or #255
Closed

Breaking change from 0.9.10 to 0.9.11 due to #240 (presumably) #250

passcod opened this issue Nov 10, 2020 · 7 comments · Fixed by #251 or #255
Assignees
Labels
bug Something is borken

Comments

@passcod
Copy link

passcod commented Nov 10, 2020

#240 rewrote the redirect implementation away from curl. I noticed that this broke redirects in my use case.

Test code:

use isahc::{
    config::{Configurable, RedirectPolicy},
    http::request::Request,
    HttpClient,
};
use std::error::Error;

#[async_std::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
    let client = HttpClient::builder()
        .redirect_policy(RedirectPolicy::Limit(8))
        .build()
        .expect("FATAL: failed to create http client");

    let req = Request::post("http://localhost:8265/command/help").body(())?;
    let res = client.send_async(req).await?;
    dbg!(res);
    Ok(())
}

The URL issues a 302 redirect.

Output with isahc 0.9.10

[src/bin/isahc-test.rs:21] res = Response {
    status: 200,
    version: HTTP/1.1,
    headers: {
        "server": "nginx/1.18.0",
        "date": "Tue, 10 Nov 2020 08:09:31 GMT",
        "content-type": "text/plain",
        "content-length": "614",
        "last-modified": "Thu, 05 Nov 2020 10:51:25 GMT",
        "connection": "keep-alive",
        "etag": "\"5fa3d92d-266\"",
        "accept-ranges": "bytes",
    },
    body: Body(614),
}

Output with isahc 0.9.11

[src/bin/isahc-test.rs:21] res = Response {
    status: 302,
    version: HTTP/1.1,
    headers: {
        "server": "nginx/1.18.0",
        "date": "Tue, 10 Nov 2020 08:04:33 GMT",
        "content-type": "text/html",
        "content-length": "145",
        "location": "http://localhost:8265/static/help.txt",
        "connection": "keep-alive",
    },
    body: Body(145),
}
@sagebind
Copy link
Owner

Thanks for filing such a detailed reproduction of the issue! I'll take a look as soon as I can. You're right that this is almost certainly a regression from #240.

@sagebind sagebind added the bug Something is borken label Nov 10, 2020
@sagebind sagebind self-assigned this Nov 10, 2020
sagebind added a commit that referenced this issue Nov 11, 2020
Fix a regression from #240 that caused redirect policies to be ignored if being set client-wide instead of per-request.

Fixes #250.
@sagebind
Copy link
Owner

Found the issue -- calling redirect_policy on an individual request builder works, but the configuration wasn't reaching the redirect interceptor when being called on the client builder. I've added a test for this to ensure this mistake isn't made again in the future. Fix is in #251.

Again, thanks for bringing this to my attention quickly. I will push a patch release tonight with the fix.

@passcod
Copy link
Author

passcod commented Nov 11, 2020 via email

sagebind added a commit that referenced this issue Nov 11, 2020
Fix a regression from #240 that caused redirect policies to be ignored if being set client-wide instead of per-request.

Fixes #250.
@passcod
Copy link
Author

passcod commented Nov 14, 2020

Erm. I'm sorry to report that it doesn't seem to have been fixed:

[Running 'cargo run --bin isahc-test']
   Compiling isahc v0.9.12
   Compiling passcod-accord v0.0.6 (/home/code/rust/accord)
    Finished dev [unoptimized + debuginfo] target(s) in 8.95s
     Running `target/debug/isahc-test`
[src/bin/isahc-test.rs:17] res = Response {
    status: 302,
    version: HTTP/1.1,
    headers: {
        "server": "nginx/1.18.0",
        "date": "Sat, 14 Nov 2020 00:31:48 GMT",
        "content-type": "text/html",
        "content-length": "145",
        "location": "http://localhost:8265/static/help.txt",
        "connection": "keep-alive",
    },
    body: Body(145),
}
[Finished running. Exit status: 0]

Same test code.

@sagebind sagebind reopened this Nov 14, 2020
@sagebind
Copy link
Owner

Hmm, I added a test case to ensure that it was fixed. Perhaps the test case isn't quite the same as your example. I will take another look.

@sagebind
Copy link
Owner

OK, it looks like I did fix a bug in #251 that was affecting this, but there is also a separate bug at work here. The key is that the first 302 response includes a non-zero response body. In my test it did not. If the first response that returns a redirect location returns a body, it looks like that CURLINFO_REDIRECT_URL actually returns null until you consume the entire response body. This strikes me as odd behavior on the part of curl, but after doing some research it seems like this is expected.

I will fix this by having Isahc parse the Location header itself instead of relying on curl to do it, since we don't want to have to consume the entire response body before deciding whether to redirect or not.

sagebind added a commit that referenced this issue Nov 14, 2020
Previously we were relying on curl to resolve the redirect location with `CURLINFO_REDIRECT_URL`, but this value is only populated once the response body stream has been consumed and the handle is complete. This means that redirects were working properly if the response containing the redirect had an empty body, but not if a nonempty body is included.

Since we don't really want to wait for the response body to be consumed before we decide whether we should redirect or not, change the redirect interceptor to derive the redirect location ourselves. Since the algorithm is nontrivial, pull in the `url` crate to do this resolution.

Also add a test for following redirects when response bodies are present to catch this bug.

Fixes #250.
sagebind added a commit that referenced this issue Nov 14, 2020
Previously we were relying on curl to resolve the redirect location with `CURLINFO_REDIRECT_URL`, but this value is only populated once the response body stream has been consumed and the handle is complete. This means that redirects were working properly if the response containing the redirect had an empty body, but not if a nonempty body is included.

Since we don't really want to wait for the response body to be consumed before we decide whether we should redirect or not, change the redirect interceptor to derive the redirect location ourselves. Since the algorithm is nontrivial, pull in the `url` crate to do this resolution.

Also add a test for following redirects when response bodies are present to catch this bug.

Fixes #250.
@sagebind
Copy link
Owner

Alright, this should now be fixed for real this time in 0.9.13! @passcod Please give it a try and don't hesitate to let me know if you have any more problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something is borken
Projects
None yet
2 participants