reqwest icon indicating copy to clipboard operation
reqwest copied to clipboard

Redirects no longer have url fragments

Open kamack38 opened this issue 8 months ago • 6 comments

There's a regression introduced in d9cf60e8f69bcabf9df3d69a8c0216409e7835a1 (last good commit 75f62f2) that makes redirected URLs no longer keep the URL fragments.

For example: Before this location with a URL fragment was preserved https://example.com/subsite#var=something And after this commit, the URL is: https://example.com/subsite (doesn't have the URL fragment).

The client is built in the following way:

let client = ClientBuilder::new()
                .use_rustls_tls()
                .cookie_store(true)
                .redirect(redirect::Policy::custom(|attempt| {
                    println!("Redirecting to: {}", attempt.url());
                    attempt.follow()
                }))
                .build()
                .unwrap();

Here's a minimal reproducible example:

// [dependencies]
// axum = "0.8"
// tokio = { version = "1", features = ["full"] }
use axum::{Router, response::Redirect, routing::get};
#[tokio::main]
async fn main() {
    let app = Router::new()
        .route(
            "/",
            get(|| async { Redirect::permanent("/redirect#frag=sdafsa") }),
        )
        .route("/redirect", get(final_page));
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
        .await
        .unwrap();
    println!("Listening on http://127.0.0.1:3000");
    axum::serve(listener, app).await.unwrap();
}
async fn final_page() -> &'static str {
    "Final destination reached!"
}

EDIT: Removed a user agent because it doesn't matter.

kamack38 avatar Jun 29 '25 14:06 kamack38

After that refactor PR, reqwest uses tower-http to handle the redirect loop, so the redirection url is retrievaled from the tower-http uri. The cause is that tower-http uri doesn't keep the fragement.

linyihai avatar Jun 30 '25 10:06 linyihai

See this https://github.com/hyperium/http/issues/127, if http::uri could support parse fragment, then this issuse will be fixed automatically. Otherwise, we need to trace LOCATION as URL in tower-http also.

linyihai avatar Jun 30 '25 10:06 linyihai

Hm, were you inspecting the fragment in a custom policy? Or checking the Response::url() at the end?

I put together a small test at the good commit, and while the response url does have the fragment, the fragment is never transmitted to the server in any of the HTTP requests.

seanmonstar avatar Jun 30 '25 14:06 seanmonstar

Hm, were you inspecting the fragment in a custom policy? Or checking the Response::url() at the end?

I put together a small test at the good commit, and while the response url does have the fragment, the fragment is never transmitted to the server in any of the HTTP requests.

I was just checking the URL at the end and the println output (in the custom policy). The server is just an example and I use reqwest with a site over which I have no control. I just created it to provide a better example.

It seems that neither axum nor actix are capable of that.

kamack38 avatar Jun 30 '25 18:06 kamack38

It looks like HTTP protocol doesn't even allow sending URL fragment (the server will generally just leave it out).

kamack38 avatar Jun 30 '25 18:06 kamack38

I suppose that everything works as intended and my code was just based on a bug. The final request URL shouldn't contain the fragment, since it doesn't make a request to it (as browsers also don't send such requests) and the attempt in a redirect policy also doesn't have the fragment, since it won't be the URL the next request will be made to.

Then I just have a question left. Would you consider adding a per-request redirect policy? So the first (let's say GET) request and each subsequent (until the last one which doesn't redirect) requests would have a specified redirect policy. This would allow a user to disable redirects just for this one request, while retaining the redirect policy for others.

Example:

client.get(url).redirect(redirect::Policy::none()).send()?;

kamack38 avatar Jun 30 '25 19:06 kamack38