From cd166f5fd0505ba90a3af620f5c7322337a55d88 Mon Sep 17 00:00:00 2001 From: Jeremy Lempereur Date: Thu, 18 Jul 2019 22:49:31 +0200 Subject: [PATCH 1/2] Add url.includes_credentials() and url.is_special(). --- src/lib.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2ad421d08..7410719e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -477,7 +477,7 @@ impl Url { assert_eq!(host_str, h.to_string()) } HostInternal::Domain => { - if SchemeType::from(self.scheme()).is_special() { + if self.is_special() { assert!(!host_str.is_empty()) } } @@ -1635,7 +1635,7 @@ impl Url { } if let Some(host) = host { - if host == "" && SchemeType::from(self.scheme()).is_special() { + if host == "" && self.is_special() { return Err(ParseError::EmptyHost); } let mut host_substr = host; @@ -1653,14 +1653,13 @@ impl Url { None => {} } } - if SchemeType::from(self.scheme()).is_special() { + if self.is_special() { self.set_host_internal(Host::parse(host_substr)?, None); } else { self.set_host_internal(Host::parse_opaque(host_substr)?, None); } } else if self.has_host() { - let scheme_type = SchemeType::from(self.scheme()); - if scheme_type.is_special() { + if self.is_special() { return Err(ParseError::EmptyHost); } else { if self.serialization.len() == self.path_start as usize { @@ -2103,6 +2102,68 @@ impl Url { Ok(()) } + /// Return whether the URL is special. + /// + /// A URL is special if its scheme is one of the following: + /// + /// "http" | "https" | "ws" | "wss" | "ftp" | "gopher" | "file" + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("ftp://rms@example.com")?; + /// assert!(url.is_special()); + /// + /// let url = Url::parse("file://foo.bar")?; + /// assert!(url.is_special()); + /// + /// let url = Url::parse("unix:/run/foo.socket")?; + /// assert!(!url.is_special()); + /// + /// let url = Url::parse("data:text/plain,Stuff")?; + /// assert!(!url.is_special()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn is_special(&self) -> bool { + SchemeType::from(self.scheme()).is_special() + } + + /// Return whether the URL includes credentials. + /// + /// A URL includes credentials if its username or password is not the empty string. + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("https://username:password@www.my_site.com")?; + /// assert!(url.includes_credentials()); + /// + /// let url = Url::parse("https://username@www.my_site.com")?; + /// assert!(url.includes_credentials()); + /// + /// let url = Url::parse("https://www.my_site.com")?; + /// assert!(!url.includes_credentials()); + /// + /// let url = Url::parse("https://@www.my_site.com")?; + /// assert!(!url.includes_credentials()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn includes_credentials(&self) -> bool { + self.username() != "" || self.password().unwrap_or(&"") != "" + } + /// Convert a file name as `std::path::Path` into an URL in the `file` scheme. /// /// This returns `Err` if the given path is not absolute or, From 8123a11098aa9bf20aa426181ebf93483d955b79 Mon Sep 17 00:00:00 2001 From: Jeremy Lempereur Date: Fri, 19 Jul 2019 11:46:25 +0200 Subject: [PATCH 2/2] Add cannot_have_username_password_port to URL. --- src/lib.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7410719e0..ec09d61ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1497,8 +1497,7 @@ impl Url { /// # run().unwrap(); /// ``` pub fn set_port(&mut self, mut port: Option) -> Result<(), ()> { - // has_host implies !cannot_be_a_base - if !self.has_host() || self.host() == Some(Host::Domain("")) || self.scheme() == "file" { + if self.cannot_have_username_password_port() { return Err(()); } if port.is_some() && port == parser::default_port(self.scheme()) { @@ -1807,8 +1806,7 @@ impl Url { /// # run().unwrap(); /// ``` pub fn set_password(&mut self, password: Option<&str>) -> Result<(), ()> { - // has_host implies !cannot_be_a_base - if !self.has_host() || self.host() == Some(Host::Domain("")) || self.scheme() == "file" { + if self.cannot_have_username_password_port() { return Err(()); } if let Some(password) = password { @@ -1899,8 +1897,7 @@ impl Url { /// # run().unwrap(); /// ``` pub fn set_username(&mut self, username: &str) -> Result<(), ()> { - // has_host implies !cannot_be_a_base - if !self.has_host() || self.host() == Some(Host::Domain("")) || self.scheme() == "file" { + if self.cannot_have_username_password_port() { return Err(()); } let username_start = self.scheme_end + 3; @@ -2361,6 +2358,12 @@ impl Url { // Private helper methods: + fn cannot_have_username_password_port(&self) -> bool { + self.host().unwrap_or(Host::Domain("")) == Host::Domain("") + || self.cannot_be_a_base() + || self.scheme() == "file" + } + #[inline] fn slice(&self, range: R) -> &str where