diff --git a/src/async_impl/client.rs b/src/async_impl/client.rs index e069a68..2e88c0e 100644 --- a/src/async_impl/client.rs +++ b/src/async_impl/client.rs @@ -1634,8 +1634,15 @@ impl Future for PendingRequest { match action { redirect::ActionKind::Follow => { debug!("redirecting '{}' to '{}'", self.url, loc); - self.url = loc; + if self.client.https_only && loc.scheme() != "https" { + return Poll::Ready(Err(error::redirect( + error::url_bad_scheme(loc.clone()), + loc, + ))); + } + + self.url = loc; let mut headers = std::mem::replace(self.as_mut().headers(), HeaderMap::new()); diff --git a/tests/redirect.rs b/tests/redirect.rs index 16f7712..5124b4a 100644 --- a/tests/redirect.rs +++ b/tests/redirect.rs @@ -316,3 +316,31 @@ async fn test_redirect_302_with_set_cookies() { assert_eq!(res.url().as_str(), dst); assert_eq!(res.status(), reqwest::StatusCode::OK); } + +#[cfg(feature = "__rustls")] +#[tokio::test] +#[ignore = "Needs TLS support in the test server"] +async fn test_redirect_https_only_enforced_gh1312() { + let server = server::http(move |_req| async move { + http::Response::builder() + .status(302) + .header("location", "http://insecure") + .body(Default::default()) + .unwrap() + }); + + let url = format!("https://{}/yikes", server.addr()); + + let res = reqwest::Client::builder() + .danger_accept_invalid_certs(true) + .use_rustls_tls() + .https_only(true) + .build() + .expect("client builder") + .get(&url) + .send() + .await; + + let err = res.unwrap_err(); + assert!(err.is_redirect()); +}