1 use url::Url;
2 
3 /// A trait to try to convert some type into a `Url`.
4 ///
5 /// This trait is "sealed", such that only types within reqwest can
6 /// implement it.
7 pub trait IntoUrl: IntoUrlSealed {}
8 
9 impl IntoUrl for Url {}
10 impl IntoUrl for String {}
11 impl<'a> IntoUrl for &'a str {}
12 impl<'a> IntoUrl for &'a String {}
13 
14 pub trait IntoUrlSealed {
15     // Besides parsing as a valid `Url`, the `Url` must be a valid
16     // `http::Uri`, in that it makes sense to use in a network request.
into_url(self) -> crate::Result<Url>17     fn into_url(self) -> crate::Result<Url>;
18 
as_str(&self) -> &str19     fn as_str(&self) -> &str;
20 }
21 
22 impl IntoUrlSealed for Url {
into_url(self) -> crate::Result<Url>23     fn into_url(self) -> crate::Result<Url> {
24         if self.has_host() {
25             Ok(self)
26         } else {
27             Err(crate::error::url_bad_scheme(self))
28         }
29     }
30 
as_str(&self) -> &str31     fn as_str(&self) -> &str {
32         self.as_ref()
33     }
34 }
35 
36 impl<'a> IntoUrlSealed for &'a str {
into_url(self) -> crate::Result<Url>37     fn into_url(self) -> crate::Result<Url> {
38         Url::parse(self).map_err(crate::error::builder)?.into_url()
39     }
40 
as_str(&self) -> &str41     fn as_str(&self) -> &str {
42         self
43     }
44 }
45 
46 impl<'a> IntoUrlSealed for &'a String {
into_url(self) -> crate::Result<Url>47     fn into_url(self) -> crate::Result<Url> {
48         (&**self).into_url()
49     }
50 
as_str(&self) -> &str51     fn as_str(&self) -> &str {
52         self.as_ref()
53     }
54 }
55 
56 impl<'a> IntoUrlSealed for String {
into_url(self) -> crate::Result<Url>57     fn into_url(self) -> crate::Result<Url> {
58         (&*self).into_url()
59     }
60 
as_str(&self) -> &str61     fn as_str(&self) -> &str {
62         self.as_ref()
63     }
64 }
65 
66 if_hyper! {
67     pub(crate) fn expect_uri(url: &Url) -> http::Uri {
68         url.as_str()
69             .parse()
70             .expect("a parsed Url should always be a valid Uri")
71     }
72 
73     pub(crate) fn try_uri(url: &Url) -> Option<http::Uri> {
74         url.as_str().parse().ok()
75     }
76 }
77 
78 #[cfg(test)]
79 mod tests {
80     use super::*;
81 
82     #[test]
into_url_file_scheme()83     fn into_url_file_scheme() {
84         let err = "file:///etc/hosts".into_url().unwrap_err();
85         assert_eq!(
86             err.to_string(),
87             "builder error for url (file:///etc/hosts): URL scheme is not allowed"
88         );
89     }
90 }
91