Skip to content

Commit 5d8443d

Browse files
LucasPickeringmre
andauthored
fix panic when parsing invalid Url to Uri (#2040)
Instead propagate this parsing issue up to the calling function as a Result. See #668 Original PR: #1399 Co-authored-by: Matthias <matthias-endler@gmx.net>
1 parent e3bf090 commit 5d8443d

File tree

3 files changed

+29
-12
lines changed

3 files changed

+29
-12
lines changed

src/async_impl/client.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use crate::cookie;
3737
use crate::dns::trust_dns::TrustDnsResolver;
3838
use crate::dns::{gai::GaiResolver, DnsResolverWithOverrides, DynResolver, Resolve};
3939
use crate::error;
40-
use crate::into_url::{expect_uri, try_uri};
40+
use crate::into_url::try_uri;
4141
use crate::redirect::{self, remove_sensitive_headers};
4242
#[cfg(feature = "__tls")]
4343
use crate::tls::{self, TlsBackend};
@@ -1810,7 +1810,10 @@ impl Client {
18101810
}
18111811
}
18121812

1813-
let uri = expect_uri(&url);
1813+
let uri = match try_uri(&url) {
1814+
Ok(uri) => uri,
1815+
_ => return Pending::new_err(error::url_invalid_uri(url)),
1816+
};
18141817

18151818
let (reusable, body) = match body {
18161819
Some(body) => {
@@ -2178,7 +2181,8 @@ impl PendingRequest {
21782181
}
21792182
self.retry_count += 1;
21802183

2181-
let uri = expect_uri(&self.url);
2184+
// If it parsed once, it should parse again
2185+
let uri = try_uri(&self.url).expect("URL was already validated as URI");
21822186

21832187
*self.as_mut().in_flight().get_mut() = match *self.as_mut().in_flight().as_ref() {
21842188
#[cfg(feature = "http3")]
@@ -2358,7 +2362,7 @@ impl Future for PendingRequest {
23582362
//
23592363
// If not, just log it and skip the redirect.
23602364
let loc = loc.and_then(|url| {
2361-
if try_uri(&url).is_some() {
2365+
if try_uri(&url).is_ok() {
23622366
Some(url)
23632367
} else {
23642368
None
@@ -2403,7 +2407,7 @@ impl Future for PendingRequest {
24032407
std::mem::replace(self.as_mut().headers(), HeaderMap::new());
24042408

24052409
remove_sensitive_headers(&mut headers, &self.url, &self.urls);
2406-
let uri = expect_uri(&self.url);
2410+
let uri = try_uri(&self.url)?;
24072411
let body = match self.body {
24082412
Some(Some(ref body)) => Body::reusable(body.clone()),
24092413
_ => Body::empty(),
@@ -2503,7 +2507,7 @@ fn add_cookie_header(headers: &mut HeaderMap, cookie_store: &dyn cookie::CookieS
25032507
#[cfg(test)]
25042508
mod tests {
25052509
#[tokio::test]
2506-
async fn execute_request_rejects_invald_urls() {
2510+
async fn execute_request_rejects_invalid_urls() {
25072511
let url_str = "hxxps://www.rust-lang.org/";
25082512
let url = url::Url::parse(url_str).unwrap();
25092513
let result = crate::get(url.clone()).await;
@@ -2513,4 +2517,17 @@ mod tests {
25132517
assert!(err.is_builder());
25142518
assert_eq!(url_str, err.url().unwrap().as_str());
25152519
}
2520+
2521+
/// https://github.com/seanmonstar/reqwest/issues/668
2522+
#[tokio::test]
2523+
async fn execute_request_rejects_invalid_hostname() {
2524+
let url_str = "https://{{hostname}}/";
2525+
let url = url::Url::parse(url_str).unwrap();
2526+
let result = crate::get(url.clone()).await;
2527+
2528+
assert!(result.is_err());
2529+
let err = result.err().unwrap();
2530+
assert!(err.is_builder());
2531+
assert_eq!(url_str, err.url().unwrap().as_str());
2532+
}
25162533
}

src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,10 @@ pub(crate) fn url_bad_scheme(url: Url) -> Error {
275275
Error::new(Kind::Builder, Some(BadScheme)).with_url(url)
276276
}
277277

278+
pub(crate) fn url_invalid_uri(url: Url) -> Error {
279+
Error::new(Kind::Builder, Some("Parsed Url is not a valid Uri")).with_url(url)
280+
}
281+
278282
if_wasm! {
279283
pub(crate) fn wasm(js_val: wasm_bindgen::JsValue) -> BoxError {
280284
format!("{:?}", js_val).into()

src/into_url.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,10 @@ impl<'a> IntoUrlSealed for String {
7474
}
7575

7676
if_hyper! {
77-
pub(crate) fn expect_uri(url: &Url) -> http::Uri {
77+
pub(crate) fn try_uri(url: &Url) -> crate::Result<http::Uri> {
7878
url.as_str()
7979
.parse()
80-
.expect("a parsed Url should always be a valid Uri")
81-
}
82-
83-
pub(crate) fn try_uri(url: &Url) -> Option<http::Uri> {
84-
url.as_str().parse().ok()
80+
.map_err(|_| crate::error::url_invalid_uri(url.clone()))
8581
}
8682
}
8783

0 commit comments

Comments
 (0)