diff --git a/src/redirect.rs b/src/redirect.rs index 5ebaccda..bf76ff43 100644 --- a/src/redirect.rs +++ b/src/redirect.rs @@ -51,11 +51,15 @@ impl Middleware for RedirectFollower { // See https://github.com/seanmonstar/reqwest/blob/bbeb1ede4e8098481c3de6f2cafb8ecca1db4ede/src/async_impl/client.rs#L1500-L1607 fn get_next_request(mut request: Request, response: &Response) -> Option { let get_next_url = |request: &Request| { - response - .headers() - .get(LOCATION) - .and_then(|location| location.to_utf8_str().ok()) - .and_then(|location| request.url().join(location).ok()) + let location = response.headers().get(LOCATION)?; + let url = location + .to_utf8_str() + .ok() + .and_then(|location| request.url().join(location).ok()); + if url.is_none() { + log::warn!("Redirect to invalid URL: {location:?}"); + } + url }; match response.status() { diff --git a/tests/cases/logging.rs b/tests/cases/logging.rs index 348aaa73..da2609e2 100644 --- a/tests/cases/logging.rs +++ b/tests/cases/logging.rs @@ -1,3 +1,4 @@ +use hyper::header::HeaderValue; use predicates::str::contains; use crate::prelude::*; @@ -91,3 +92,35 @@ fn checked_status_is_not_printed_with_double_quiet() { .stdout("") .stderr(""); } + +#[test] +fn warning_for_invalid_redirect() { + let server = server::http(|_req| async move { + hyper::Response::builder() + .status(302) + .header("location", "//") + .body("".into()) + .unwrap() + }); + + get_command() + .args(["--follow", &server.base_url()]) + .assert() + .stderr("xh: warning: Redirect to invalid URL: \"//\"\n"); +} + +#[test] +fn warning_for_non_utf8_redirect() { + let server = server::http(|_req| async move { + hyper::Response::builder() + .status(302) + .header("location", HeaderValue::from_bytes(b"\xFF").unwrap()) + .body("".into()) + .unwrap() + }); + + get_command() + .args(["--follow", &server.base_url()]) + .assert() + .stderr("xh: warning: Redirect to invalid URL: \"\\xff\"\n"); +}