@@ -30,7 +30,7 @@ use native_tls::TlsConnector;
|
|||||||
use super::request::{Request, RequestBuilder};
|
use super::request::{Request, RequestBuilder};
|
||||||
use super::response::Response;
|
use super::response::Response;
|
||||||
use connect::Connector;
|
use connect::Connector;
|
||||||
use into_url::to_uri;
|
use into_url::{expect_uri, try_uri};
|
||||||
use redirect::{self, RedirectPolicy, remove_sensitive_headers};
|
use redirect::{self, RedirectPolicy, remove_sensitive_headers};
|
||||||
use {IntoUrl, Method, Proxy, StatusCode, Url};
|
use {IntoUrl, Method, Proxy, StatusCode, Url};
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "tls")]
|
||||||
@@ -520,7 +520,7 @@ impl Client {
|
|||||||
headers.insert(ACCEPT_ENCODING, HeaderValue::from_static("gzip"));
|
headers.insert(ACCEPT_ENCODING, HeaderValue::from_static("gzip"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let uri = to_uri(&url);
|
let uri = expect_uri(&url);
|
||||||
|
|
||||||
let (reusable, body) = match body {
|
let (reusable, body) = match body {
|
||||||
Some(body) => {
|
Some(body) => {
|
||||||
@@ -709,6 +709,17 @@ impl Future for PendingRequest {
|
|||||||
self.url.join(str::from_utf8(val.as_bytes()).ok()?).ok()
|
self.url.join(str::from_utf8(val.as_bytes()).ok()?).ok()
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// Check that the `url` is also a valid `http::Uri`.
|
||||||
|
//
|
||||||
|
// If not, just log it and skip the redirect.
|
||||||
|
let loc = loc.and_then(|url| {
|
||||||
|
if try_uri(&url).is_some() {
|
||||||
|
Some(url)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if loc.is_none() {
|
if loc.is_none() {
|
||||||
debug!("Location header had invalid URI: {:?}", val);
|
debug!("Location header had invalid URI: {:?}", val);
|
||||||
}
|
}
|
||||||
@@ -733,7 +744,7 @@ impl Future for PendingRequest {
|
|||||||
|
|
||||||
remove_sensitive_headers(&mut self.headers, &self.url, &self.urls);
|
remove_sensitive_headers(&mut self.headers, &self.url, &self.urls);
|
||||||
debug!("redirecting to {:?} '{}'", self.method, self.url);
|
debug!("redirecting to {:?} '{}'", self.method, self.url);
|
||||||
let uri = to_uri(&self.url);
|
let uri = expect_uri(&self.url);
|
||||||
let body = match self.body {
|
let body = match self.body {
|
||||||
Some(Some(ref body)) => ::hyper::Body::from(body.clone()),
|
Some(Some(ref body)) => ::hyper::Body::from(body.clone()),
|
||||||
_ => ::hyper::Body::empty(),
|
_ => ::hyper::Body::empty(),
|
||||||
|
|||||||
@@ -38,10 +38,14 @@ impl<'a> PolyfillTryInto for &'a String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn to_uri(url: &Url) -> ::hyper::Uri {
|
pub(crate) fn expect_uri(url: &Url) -> ::hyper::Uri {
|
||||||
url.as_str().parse().expect("a parsed Url should always be a valid Uri")
|
url.as_str().parse().expect("a parsed Url should always be a valid Uri")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn try_uri(url: &Url) -> Option<::hyper::Uri> {
|
||||||
|
url.as_str().parse().ok()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ impl Proxy {
|
|||||||
/// # fn main() {}
|
/// # fn main() {}
|
||||||
/// ```
|
/// ```
|
||||||
pub fn http<U: IntoUrl>(url: U) -> ::Result<Proxy> {
|
pub fn http<U: IntoUrl>(url: U) -> ::Result<Proxy> {
|
||||||
let uri = ::into_url::to_uri(&url.into_url()?);
|
let uri = ::into_url::expect_uri(&url.into_url()?);
|
||||||
Ok(Proxy::new(Intercept::Http(uri)))
|
Ok(Proxy::new(Intercept::Http(uri)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ impl Proxy {
|
|||||||
/// # fn main() {}
|
/// # fn main() {}
|
||||||
/// ```
|
/// ```
|
||||||
pub fn https<U: IntoUrl>(url: U) -> ::Result<Proxy> {
|
pub fn https<U: IntoUrl>(url: U) -> ::Result<Proxy> {
|
||||||
let uri = ::into_url::to_uri(&url.into_url()?);
|
let uri = ::into_url::expect_uri(&url.into_url()?);
|
||||||
Ok(Proxy::new(Intercept::Https(uri)))
|
Ok(Proxy::new(Intercept::Https(uri)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ impl Proxy {
|
|||||||
/// # fn main() {}
|
/// # fn main() {}
|
||||||
/// ```
|
/// ```
|
||||||
pub fn all<U: IntoUrl>(url: U) -> ::Result<Proxy> {
|
pub fn all<U: IntoUrl>(url: U) -> ::Result<Proxy> {
|
||||||
let uri = ::into_url::to_uri(&url.into_url()?);
|
let uri = ::into_url::expect_uri(&url.into_url()?);
|
||||||
Ok(Proxy::new(Intercept::All(uri)))
|
Ok(Proxy::new(Intercept::All(uri)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ impl Proxy {
|
|||||||
.parse()
|
.parse()
|
||||||
.expect("should be valid Url")
|
.expect("should be valid Url")
|
||||||
)
|
)
|
||||||
.map(|u| into_url::to_uri(&u) )
|
.map(|u| into_url::expect_uri(&u) )
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -358,3 +358,32 @@ fn test_referer_is_not_set_if_disabled() {
|
|||||||
.send()
|
.send()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_invalid_location_stops_redirect_gh484() {
|
||||||
|
let server = server! {
|
||||||
|
request: b"\
|
||||||
|
GET /yikes HTTP/1.1\r\n\
|
||||||
|
user-agent: $USERAGENT\r\n\
|
||||||
|
accept: */*\r\n\
|
||||||
|
accept-encoding: gzip\r\n\
|
||||||
|
host: $HOST\r\n\
|
||||||
|
\r\n\
|
||||||
|
",
|
||||||
|
response: b"\
|
||||||
|
HTTP/1.1 302 Found\r\n\
|
||||||
|
Server: test-yikes\r\n\
|
||||||
|
Location: http://www.yikes{KABOOM}\r\n\
|
||||||
|
Content-Length: 0\r\n\
|
||||||
|
\r\n\
|
||||||
|
"
|
||||||
|
};
|
||||||
|
|
||||||
|
let url = format!("http://{}/yikes", server.addr());
|
||||||
|
|
||||||
|
let res = reqwest::get(&url).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(res.url().as_str(), url);
|
||||||
|
assert_eq!(res.status(), reqwest::StatusCode::FOUND);
|
||||||
|
assert_eq!(res.headers().get(reqwest::header::SERVER).unwrap(), &"test-yikes");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user