diff --git a/src/lib.rs b/src/lib.rs index 2ad421d08..ec09d61ef 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()) } } @@ -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()) { @@ -1635,7 +1634,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 +1652,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 { @@ -1808,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 { @@ -1900,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; @@ -2103,6 +2099,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, @@ -2300,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