| 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. |
| 17 | fn into_url(self) -> crate::Result<Url>; |
| 18 | |
| 19 | fn as_str(&self) -> &str; |
| 20 | } |
| 21 | |
| 22 | impl IntoUrlSealed for Url { |
| 23 | fn into_url(self) -> crate::Result<Url> { |
| 24 | // With blob url the `self.has_host()` check is always false, so we |
| 25 | // remove the `blob:` scheme and check again if the url is valid. |
| 26 | #[cfg (target_arch = "wasm32" )] |
| 27 | if self.scheme() == "blob" |
| 28 | && self.path().starts_with("http" ) // Check if the path starts with http or https to avoid validating a `blob:blob:...` url. |
| 29 | && self.as_str()[5..].into_url().is_ok() |
| 30 | { |
| 31 | return Ok(self); |
| 32 | } |
| 33 | |
| 34 | if self.has_host() { |
| 35 | Ok(self) |
| 36 | } else { |
| 37 | Err(crate::error::url_bad_scheme(self)) |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | fn as_str(&self) -> &str { |
| 42 | self.as_ref() |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | impl<'a> IntoUrlSealed for &'a str { |
| 47 | fn into_url(self) -> crate::Result<Url> { |
| 48 | Url::parse(self).map_err(op:crate::error::builder)?.into_url() |
| 49 | } |
| 50 | |
| 51 | fn as_str(&self) -> &str { |
| 52 | self |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | impl<'a> IntoUrlSealed for &'a String { |
| 57 | fn into_url(self) -> crate::Result<Url> { |
| 58 | (&**self).into_url() |
| 59 | } |
| 60 | |
| 61 | fn as_str(&self) -> &str { |
| 62 | self.as_ref() |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | impl IntoUrlSealed for String { |
| 67 | fn into_url(self) -> crate::Result<Url> { |
| 68 | (&*self).into_url() |
| 69 | } |
| 70 | |
| 71 | fn as_str(&self) -> &str { |
| 72 | self.as_ref() |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | if_hyper! { |
| 77 | pub(crate) fn try_uri(url: &Url) -> crate::Result<http::Uri> { |
| 78 | url.as_str() |
| 79 | .parse() |
| 80 | .map_err(|_| crate::error::url_invalid_uri(url.clone())) |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | #[cfg (test)] |
| 85 | mod tests { |
| 86 | use super::*; |
| 87 | use std::error::Error; |
| 88 | |
| 89 | #[test ] |
| 90 | fn into_url_file_scheme() { |
| 91 | let err = "file:///etc/hosts" .into_url().unwrap_err(); |
| 92 | assert_eq!( |
| 93 | err.source().unwrap().to_string(), |
| 94 | "URL scheme is not allowed" |
| 95 | ); |
| 96 | } |
| 97 | |
| 98 | #[test ] |
| 99 | fn into_url_blob_scheme() { |
| 100 | let err = "blob:https://example.com" .into_url().unwrap_err(); |
| 101 | assert_eq!( |
| 102 | err.source().unwrap().to_string(), |
| 103 | "URL scheme is not allowed" |
| 104 | ); |
| 105 | } |
| 106 | |
| 107 | if_wasm! { |
| 108 | use wasm_bindgen_test::*; |
| 109 | |
| 110 | #[wasm_bindgen_test] |
| 111 | fn into_url_blob_scheme_wasm() { |
| 112 | let url = "blob:http://example.com" .into_url().unwrap(); |
| 113 | |
| 114 | assert_eq!(url.as_str(), "blob:http://example.com" ); |
| 115 | } |
| 116 | } |
| 117 | } |
| 118 | |