From c9f91796df920daf56ad87f31279b1260cf6088f Mon Sep 17 00:00:00 2001 From: liushuyu Date: Wed, 24 Aug 2022 20:12:58 -0600 Subject: [PATCH] awc: correctly handle redirections that begins with `//` (#2840) --- awc/CHANGES.md | 5 ++++ awc/src/middleware/redirect.rs | 45 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/awc/CHANGES.md b/awc/CHANGES.md index e229a6d96..9cf294616 100644 --- a/awc/CHANGES.md +++ b/awc/CHANGES.md @@ -4,6 +4,11 @@ ### Changed - Minimum supported Rust version (MSRV) is now 1.57 due to transitive `time` dependency. +### Fixed +- Fixed handling of redirection requests that begin with `//`. [#2840] + +[#2840]: https://github.com/actix/actix-web/pull/2840 + ## 3.0.0 - 2022-03-07 ### Dependencies diff --git a/awc/src/middleware/redirect.rs b/awc/src/middleware/redirect.rs index d48822168..67ef5d76f 100644 --- a/awc/src/middleware/redirect.rs +++ b/awc/src/middleware/redirect.rs @@ -257,6 +257,16 @@ fn build_next_uri(res: &ClientResponse, prev_uri: &Uri) -> Result = scheme.as_bytes().to_vec(); + full_url.push(b':'); + full_url.extend(location.as_bytes()); + + return Uri::try_from(full_url) + .map_err(|_| SendRequestError::Url(InvalidUrl::MissingScheme)); + } // when scheme or authority is missing treat the location value as path and query // recover error where location does not have leading slash let path = if location.as_bytes().starts_with(b"/") { @@ -588,6 +598,41 @@ mod tests { assert_eq!(res.status().as_u16(), 200); } + #[actix_rt::test] + async fn test_double_slash_redirect() { + let client = ClientBuilder::new() + .disable_redirects() + .wrap(Redirect::new().max_redirect_times(10)) + .finish(); + + let srv = actix_test::start(|| { + App::new() + .service(web::resource("/test").route(web::to(|| async { + Ok::<_, Error>(HttpResponse::BadRequest()) + }))) + .service( + web::resource("/").route(web::to(|req: HttpRequest| async move { + Ok::<_, Error>( + HttpResponse::Found() + .append_header(( + "location", + format!( + "//localhost:{}/test", + req.app_config().local_addr().port() + ) + .as_str(), + )) + .finish(), + ) + })), + ) + }); + + let res = client.get(srv.url("/")).send().await.unwrap(); + + assert_eq!(res.status().as_u16(), 400); + } + #[actix_rt::test] async fn test_remove_sensitive_headers() { fn gen_headers() -> header::HeaderMap {