diff options
Diffstat (limited to 'vendor/http/src/uri/mod.rs')
| -rw-r--r-- | vendor/http/src/uri/mod.rs | 1117 |
1 files changed, 0 insertions, 1117 deletions
diff --git a/vendor/http/src/uri/mod.rs b/vendor/http/src/uri/mod.rs deleted file mode 100644 index 767f0743..00000000 --- a/vendor/http/src/uri/mod.rs +++ /dev/null @@ -1,1117 +0,0 @@ -//! URI component of request and response lines -//! -//! This module primarily contains the `Uri` type which is a component of all -//! HTTP requests and also reexports this type at the root of the crate. A URI -//! is not always a "full URL" in the sense of something you'd type into a web -//! browser, but HTTP requests may only have paths on servers but may have full -//! schemes and hostnames on clients. -//! -//! # Examples -//! -//! ``` -//! use http::Uri; -//! -//! let uri = "/foo/bar?baz".parse::<Uri>().unwrap(); -//! assert_eq!(uri.path(), "/foo/bar"); -//! assert_eq!(uri.query(), Some("baz")); -//! assert_eq!(uri.host(), None); -//! -//! let uri = "https://www.rust-lang.org/install.html".parse::<Uri>().unwrap(); -//! assert_eq!(uri.scheme_str(), Some("https")); -//! assert_eq!(uri.host(), Some("www.rust-lang.org")); -//! assert_eq!(uri.path(), "/install.html"); -//! ``` - -use crate::byte_str::ByteStr; -use std::convert::TryFrom; - -use bytes::Bytes; - -use std::error::Error; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::str::{self, FromStr}; - -use self::scheme::Scheme2; - -pub use self::authority::Authority; -pub use self::builder::Builder; -pub use self::path::PathAndQuery; -pub use self::port::Port; -pub use self::scheme::Scheme; - -mod authority; -mod builder; -mod path; -mod port; -mod scheme; -#[cfg(test)] -mod tests; - -/// The URI component of a request. -/// -/// For HTTP 1, this is included as part of the request line. From Section 5.3, -/// Request Target: -/// -/// > Once an inbound connection is obtained, the client sends an HTTP -/// > request message (Section 3) with a request-target derived from the -/// > target URI. There are four distinct formats for the request-target, -/// > depending on both the method being requested and whether the request -/// > is to a proxy. -/// > -/// > ```notrust -/// > request-target = origin-form -/// > / absolute-form -/// > / authority-form -/// > / asterisk-form -/// > ``` -/// -/// The URI is structured as follows: -/// -/// ```notrust -/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 -/// |-| |-------------------------------||--------| |-------------------| |-----| -/// | | | | | -/// scheme authority path query fragment -/// ``` -/// -/// For HTTP 2.0, the URI is encoded using pseudoheaders. -/// -/// # Examples -/// -/// ``` -/// use http::Uri; -/// -/// let uri = "/foo/bar?baz".parse::<Uri>().unwrap(); -/// assert_eq!(uri.path(), "/foo/bar"); -/// assert_eq!(uri.query(), Some("baz")); -/// assert_eq!(uri.host(), None); -/// -/// let uri = "https://www.rust-lang.org/install.html".parse::<Uri>().unwrap(); -/// assert_eq!(uri.scheme_str(), Some("https")); -/// assert_eq!(uri.host(), Some("www.rust-lang.org")); -/// assert_eq!(uri.path(), "/install.html"); -/// ``` -#[derive(Clone)] -pub struct Uri { - scheme: Scheme, - authority: Authority, - path_and_query: PathAndQuery, -} - -/// The various parts of a URI. -/// -/// This struct is used to provide to and retrieve from a URI. -#[derive(Debug, Default)] -pub struct Parts { - /// The scheme component of a URI - pub scheme: Option<Scheme>, - - /// The authority component of a URI - pub authority: Option<Authority>, - - /// The origin-form component of a URI - pub path_and_query: Option<PathAndQuery>, - - /// Allow extending in the future - _priv: (), -} - -/// An error resulting from a failed attempt to construct a URI. -#[derive(Debug)] -pub struct InvalidUri(ErrorKind); - -/// An error resulting from a failed attempt to construct a URI. -#[derive(Debug)] -pub struct InvalidUriParts(InvalidUri); - -#[derive(Debug, Eq, PartialEq)] -enum ErrorKind { - InvalidUriChar, - InvalidScheme, - InvalidAuthority, - InvalidPort, - InvalidFormat, - SchemeMissing, - AuthorityMissing, - PathAndQueryMissing, - TooLong, - Empty, - SchemeTooLong, -} - -// u16::MAX is reserved for None -const MAX_LEN: usize = (u16::MAX - 1) as usize; - -// URI_CHARS is a table of valid characters in a URI. An entry in the table is -// 0 for invalid characters. For valid characters the entry is itself (i.e. -// the entry for 33 is b'!' because b'!' == 33u8). An important characteristic -// of this table is that all entries above 127 are invalid. This makes all of the -// valid entries a valid single-byte UTF-8 code point. This means that a slice -// of such valid entries is valid UTF-8. -#[rustfmt::skip] -const URI_CHARS: [u8; 256] = [ - // 0 1 2 3 4 5 6 7 8 9 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x - 0, 0, 0, b'!', 0, b'#', b'$', 0, b'&', b'\'', // 3x - b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', b'0', b'1', // 4x - b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b':', b';', // 5x - 0, b'=', 0, b'?', b'@', b'A', b'B', b'C', b'D', b'E', // 6x - b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', // 7x - b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', // 8x - b'Z', b'[', 0, b']', 0, b'_', 0, b'a', b'b', b'c', // 9x - b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', // 10x - b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', // 11x - b'x', b'y', b'z', 0, 0, 0, b'~', 0, 0, 0, // 12x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 13x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 14x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 15x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 17x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 18x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 19x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 22x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 23x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 24x - 0, 0, 0, 0, 0, 0 // 25x -]; - -impl Uri { - /// Creates a new builder-style object to manufacture a `Uri`. - /// - /// This method returns an instance of `Builder` which can be usd to - /// create a `Uri`. - /// - /// # Examples - /// - /// ``` - /// use http::Uri; - /// - /// let uri = Uri::builder() - /// .scheme("https") - /// .authority("hyper.rs") - /// .path_and_query("/") - /// .build() - /// .unwrap(); - /// ``` - pub fn builder() -> Builder { - Builder::new() - } - - /// Attempt to convert a `Parts` into a `Uri`. - /// - /// # Examples - /// - /// Relative URI - /// - /// ``` - /// # use http::uri::*; - /// let mut parts = Parts::default(); - /// parts.path_and_query = Some("/foo".parse().unwrap()); - /// - /// let uri = Uri::from_parts(parts).unwrap(); - /// - /// assert_eq!(uri.path(), "/foo"); - /// - /// assert!(uri.scheme().is_none()); - /// assert!(uri.authority().is_none()); - /// ``` - /// - /// Absolute URI - /// - /// ``` - /// # use http::uri::*; - /// let mut parts = Parts::default(); - /// parts.scheme = Some("http".parse().unwrap()); - /// parts.authority = Some("foo.com".parse().unwrap()); - /// parts.path_and_query = Some("/foo".parse().unwrap()); - /// - /// let uri = Uri::from_parts(parts).unwrap(); - /// - /// assert_eq!(uri.scheme().unwrap().as_str(), "http"); - /// assert_eq!(uri.authority().unwrap(), "foo.com"); - /// assert_eq!(uri.path(), "/foo"); - /// ``` - pub fn from_parts(src: Parts) -> Result<Uri, InvalidUriParts> { - if src.scheme.is_some() { - if src.authority.is_none() { - return Err(ErrorKind::AuthorityMissing.into()); - } - - if src.path_and_query.is_none() { - return Err(ErrorKind::PathAndQueryMissing.into()); - } - } else if src.authority.is_some() && src.path_and_query.is_some() { - return Err(ErrorKind::SchemeMissing.into()); - } - - let scheme = match src.scheme { - Some(scheme) => scheme, - None => Scheme { - inner: Scheme2::None, - }, - }; - - let authority = match src.authority { - Some(authority) => authority, - None => Authority::empty(), - }; - - let path_and_query = match src.path_and_query { - Some(path_and_query) => path_and_query, - None => PathAndQuery::empty(), - }; - - Ok(Uri { - scheme, - authority, - path_and_query, - }) - } - - /// Attempt to convert a `Bytes` buffer to a `Uri`. - /// - /// This will try to prevent a copy if the type passed is the type used - /// internally, and will copy the data if it is not. - pub fn from_maybe_shared<T>(src: T) -> Result<Self, InvalidUri> - where - T: AsRef<[u8]> + 'static, - { - if_downcast_into!(T, Bytes, src, { - return Uri::from_shared(src); - }); - - Uri::try_from(src.as_ref()) - } - - // Not public while `bytes` is unstable. - fn from_shared(s: Bytes) -> Result<Uri, InvalidUri> { - use self::ErrorKind::*; - - if s.len() > MAX_LEN { - return Err(TooLong.into()); - } - - match s.len() { - 0 => { - return Err(Empty.into()); - } - 1 => match s[0] { - b'/' => { - return Ok(Uri { - scheme: Scheme::empty(), - authority: Authority::empty(), - path_and_query: PathAndQuery::slash(), - }); - } - b'*' => { - return Ok(Uri { - scheme: Scheme::empty(), - authority: Authority::empty(), - path_and_query: PathAndQuery::star(), - }); - } - _ => { - let authority = Authority::from_shared(s)?; - - return Ok(Uri { - scheme: Scheme::empty(), - authority, - path_and_query: PathAndQuery::empty(), - }); - } - }, - _ => {} - } - - if s[0] == b'/' { - return Ok(Uri { - scheme: Scheme::empty(), - authority: Authority::empty(), - path_and_query: PathAndQuery::from_shared(s)?, - }); - } - - parse_full(s) - } - - /// Convert a `Uri` from a static string. - /// - /// This function will not perform any copying, however the string is - /// checked to ensure that it is valid. - /// - /// # Panics - /// - /// This function panics if the argument is an invalid URI. - /// - /// # Examples - /// - /// ``` - /// # use http::uri::Uri; - /// let uri = Uri::from_static("http://example.com/foo"); - /// - /// assert_eq!(uri.host().unwrap(), "example.com"); - /// assert_eq!(uri.path(), "/foo"); - /// ``` - pub fn from_static(src: &'static str) -> Self { - let s = Bytes::from_static(src.as_bytes()); - match Uri::from_shared(s) { - Ok(uri) => uri, - Err(e) => panic!("static str is not valid URI: {}", e), - } - } - - /// Convert a `Uri` into `Parts`. - /// - /// # Note - /// - /// This is just an inherent method providing the same functionality as - /// `let parts: Parts = uri.into()` - /// - /// # Examples - /// - /// ``` - /// # use http::uri::*; - /// let uri: Uri = "/foo".parse().unwrap(); - /// - /// let parts = uri.into_parts(); - /// - /// assert_eq!(parts.path_and_query.unwrap(), "/foo"); - /// - /// assert!(parts.scheme.is_none()); - /// assert!(parts.authority.is_none()); - /// ``` - #[inline] - pub fn into_parts(self) -> Parts { - self.into() - } - - /// Returns the path & query components of the Uri - #[inline] - pub fn path_and_query(&self) -> Option<&PathAndQuery> { - if !self.scheme.inner.is_none() || self.authority.data.is_empty() { - Some(&self.path_and_query) - } else { - None - } - } - - /// Get the path of this `Uri`. - /// - /// Both relative and absolute URIs contain a path component, though it - /// might be the empty string. The path component is **case sensitive**. - /// - /// ```notrust - /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 - /// |--------| - /// | - /// path - /// ``` - /// - /// If the URI is `*` then the path component is equal to `*`. - /// - /// # Examples - /// - /// A relative URI - /// - /// ``` - /// # use http::Uri; - /// - /// let uri: Uri = "/hello/world".parse().unwrap(); - /// - /// assert_eq!(uri.path(), "/hello/world"); - /// ``` - /// - /// An absolute URI - /// - /// ``` - /// # use http::Uri; - /// let uri: Uri = "http://example.org/hello/world".parse().unwrap(); - /// - /// assert_eq!(uri.path(), "/hello/world"); - /// ``` - #[inline] - pub fn path(&self) -> &str { - if self.has_path() { - self.path_and_query.path() - } else { - "" - } - } - - /// Get the scheme of this `Uri`. - /// - /// The URI scheme refers to a specification for assigning identifiers - /// within that scheme. Only absolute URIs contain a scheme component, but - /// not all absolute URIs will contain a scheme component. Although scheme - /// names are case-insensitive, the canonical form is lowercase. - /// - /// ```notrust - /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 - /// |-| - /// | - /// scheme - /// ``` - /// - /// # Examples - /// - /// Absolute URI - /// - /// ``` - /// use http::uri::{Scheme, Uri}; - /// - /// let uri: Uri = "http://example.org/hello/world".parse().unwrap(); - /// - /// assert_eq!(uri.scheme(), Some(&Scheme::HTTP)); - /// ``` - /// - /// - /// Relative URI - /// - /// ``` - /// # use http::Uri; - /// let uri: Uri = "/hello/world".parse().unwrap(); - /// - /// assert!(uri.scheme().is_none()); - /// ``` - #[inline] - pub fn scheme(&self) -> Option<&Scheme> { - if self.scheme.inner.is_none() { - None - } else { - Some(&self.scheme) - } - } - - /// Get the scheme of this `Uri` as a `&str`. - /// - /// # Example - /// - /// ``` - /// # use http::Uri; - /// let uri: Uri = "http://example.org/hello/world".parse().unwrap(); - /// - /// assert_eq!(uri.scheme_str(), Some("http")); - /// ``` - #[inline] - pub fn scheme_str(&self) -> Option<&str> { - if self.scheme.inner.is_none() { - None - } else { - Some(self.scheme.as_str()) - } - } - - /// Get the authority of this `Uri`. - /// - /// The authority is a hierarchical element for naming authority such that - /// the remainder of the URI is delegated to that authority. For HTTP, the - /// authority consists of the host and port. The host portion of the - /// authority is **case-insensitive**. - /// - /// The authority also includes a `username:password` component, however - /// the use of this is deprecated and should be avoided. - /// - /// ```notrust - /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 - /// |-------------------------------| - /// | - /// authority - /// ``` - /// - /// # Examples - /// - /// Absolute URI - /// - /// ``` - /// # use http::Uri; - /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap(); - /// - /// assert_eq!(uri.authority().map(|a| a.as_str()), Some("example.org:80")); - /// ``` - /// - /// - /// Relative URI - /// - /// ``` - /// # use http::Uri; - /// let uri: Uri = "/hello/world".parse().unwrap(); - /// - /// assert!(uri.authority().is_none()); - /// ``` - #[inline] - pub fn authority(&self) -> Option<&Authority> { - if self.authority.data.is_empty() { - None - } else { - Some(&self.authority) - } - } - - /// Get the host of this `Uri`. - /// - /// The host subcomponent of authority is identified by an IP literal - /// encapsulated within square brackets, an IPv4 address in dotted- decimal - /// form, or a registered name. The host subcomponent is **case-insensitive**. - /// - /// ```notrust - /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 - /// |---------| - /// | - /// host - /// ``` - /// - /// # Examples - /// - /// Absolute URI - /// - /// ``` - /// # use http::Uri; - /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap(); - /// - /// assert_eq!(uri.host(), Some("example.org")); - /// ``` - /// - /// - /// Relative URI - /// - /// ``` - /// # use http::Uri; - /// let uri: Uri = "/hello/world".parse().unwrap(); - /// - /// assert!(uri.host().is_none()); - /// ``` - #[inline] - pub fn host(&self) -> Option<&str> { - self.authority().map(|a| a.host()) - } - - /// Get the port part of this `Uri`. - /// - /// The port subcomponent of authority is designated by an optional port - /// number following the host and delimited from it by a single colon (":") - /// character. It can be turned into a decimal port number with the `as_u16` - /// method or as a `str` with the `as_str` method. - /// - /// ```notrust - /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 - /// |-| - /// | - /// port - /// ``` - /// - /// # Examples - /// - /// Absolute URI with port - /// - /// ``` - /// # use http::Uri; - /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap(); - /// - /// let port = uri.port().unwrap(); - /// assert_eq!(port.as_u16(), 80); - /// ``` - /// - /// Absolute URI without port - /// - /// ``` - /// # use http::Uri; - /// let uri: Uri = "http://example.org/hello/world".parse().unwrap(); - /// - /// assert!(uri.port().is_none()); - /// ``` - /// - /// Relative URI - /// - /// ``` - /// # use http::Uri; - /// let uri: Uri = "/hello/world".parse().unwrap(); - /// - /// assert!(uri.port().is_none()); - /// ``` - pub fn port(&self) -> Option<Port<&str>> { - self.authority().and_then(|a| a.port()) - } - - /// Get the port of this `Uri` as a `u16`. - /// - /// - /// # Example - /// - /// ``` - /// # use http::{Uri, uri::Port}; - /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap(); - /// - /// assert_eq!(uri.port_u16(), Some(80)); - /// ``` - pub fn port_u16(&self) -> Option<u16> { - self.port().map(|p| p.as_u16()) - } - - /// Get the query string of this `Uri`, starting after the `?`. - /// - /// The query component contains non-hierarchical data that, along with data - /// in the path component, serves to identify a resource within the scope of - /// the URI's scheme and naming authority (if any). The query component is - /// indicated by the first question mark ("?") character and terminated by a - /// number sign ("#") character or by the end of the URI. - /// - /// ```notrust - /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 - /// |-------------------| - /// | - /// query - /// ``` - /// - /// # Examples - /// - /// Absolute URI - /// - /// ``` - /// # use http::Uri; - /// let uri: Uri = "http://example.org/hello/world?key=value".parse().unwrap(); - /// - /// assert_eq!(uri.query(), Some("key=value")); - /// ``` - /// - /// Relative URI with a query string component - /// - /// ``` - /// # use http::Uri; - /// let uri: Uri = "/hello/world?key=value&foo=bar".parse().unwrap(); - /// - /// assert_eq!(uri.query(), Some("key=value&foo=bar")); - /// ``` - /// - /// Relative URI without a query string component - /// - /// ``` - /// # use http::Uri; - /// let uri: Uri = "/hello/world".parse().unwrap(); - /// - /// assert!(uri.query().is_none()); - /// ``` - #[inline] - pub fn query(&self) -> Option<&str> { - self.path_and_query.query() - } - - fn has_path(&self) -> bool { - !self.path_and_query.data.is_empty() || !self.scheme.inner.is_none() - } -} - -impl<'a> TryFrom<&'a [u8]> for Uri { - type Error = InvalidUri; - - #[inline] - fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> { - Uri::from_shared(Bytes::copy_from_slice(t)) - } -} - -impl<'a> TryFrom<&'a str> for Uri { - type Error = InvalidUri; - - #[inline] - fn try_from(t: &'a str) -> Result<Self, Self::Error> { - t.parse() - } -} - -impl<'a> TryFrom<&'a String> for Uri { - type Error = InvalidUri; - - #[inline] - fn try_from(t: &'a String) -> Result<Self, Self::Error> { - t.parse() - } -} - -impl TryFrom<String> for Uri { - type Error = InvalidUri; - - #[inline] - fn try_from(t: String) -> Result<Self, Self::Error> { - Uri::from_shared(Bytes::from(t)) - } -} - -impl TryFrom<Vec<u8>> for Uri { - type Error = InvalidUri; - - #[inline] - fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> { - Uri::from_shared(Bytes::from(vec)) - } -} - -impl TryFrom<Parts> for Uri { - type Error = InvalidUriParts; - - #[inline] - fn try_from(src: Parts) -> Result<Self, Self::Error> { - Uri::from_parts(src) - } -} - -impl<'a> TryFrom<&'a Uri> for Uri { - type Error = crate::Error; - - #[inline] - fn try_from(src: &'a Uri) -> Result<Self, Self::Error> { - Ok(src.clone()) - } -} - -/// Convert an `Authority` into a `Uri`. -impl From<Authority> for Uri { - fn from(authority: Authority) -> Self { - Self { - scheme: Scheme::empty(), - authority, - path_and_query: PathAndQuery::empty(), - } - } -} - -/// Convert a `PathAndQuery` into a `Uri`. -impl From<PathAndQuery> for Uri { - fn from(path_and_query: PathAndQuery) -> Self { - Self { - scheme: Scheme::empty(), - authority: Authority::empty(), - path_and_query, - } - } -} - -/// Convert a `Uri` into `Parts` -impl From<Uri> for Parts { - fn from(src: Uri) -> Self { - let path_and_query = if src.has_path() { - Some(src.path_and_query) - } else { - None - }; - - let scheme = match src.scheme.inner { - Scheme2::None => None, - _ => Some(src.scheme), - }; - - let authority = if src.authority.data.is_empty() { - None - } else { - Some(src.authority) - }; - - Parts { - scheme, - authority, - path_and_query, - _priv: (), - } - } -} - -fn parse_full(mut s: Bytes) -> Result<Uri, InvalidUri> { - // Parse the scheme - let scheme = match Scheme2::parse(&s[..])? { - Scheme2::None => Scheme2::None, - Scheme2::Standard(p) => { - // TODO: use truncate - let _ = s.split_to(p.len() + 3); - Scheme2::Standard(p) - } - Scheme2::Other(n) => { - // Grab the protocol - let mut scheme = s.split_to(n + 3); - - // Strip ://, TODO: truncate - let _ = scheme.split_off(n); - - // Allocate the ByteStr - let val = unsafe { ByteStr::from_utf8_unchecked(scheme) }; - - Scheme2::Other(Box::new(val)) - } - }; - - // Find the end of the authority. The scheme will already have been - // extracted. - let authority_end = Authority::parse(&s[..])?; - - if scheme.is_none() { - if authority_end != s.len() { - return Err(ErrorKind::InvalidFormat.into()); - } - - let authority = Authority { - data: unsafe { ByteStr::from_utf8_unchecked(s) }, - }; - - return Ok(Uri { - scheme: scheme.into(), - authority, - path_and_query: PathAndQuery::empty(), - }); - } - - // Authority is required when absolute - if authority_end == 0 { - return Err(ErrorKind::InvalidFormat.into()); - } - - let authority = s.split_to(authority_end); - let authority = Authority { - data: unsafe { ByteStr::from_utf8_unchecked(authority) }, - }; - - Ok(Uri { - scheme: scheme.into(), - authority, - path_and_query: PathAndQuery::from_shared(s)?, - }) -} - -impl FromStr for Uri { - type Err = InvalidUri; - - #[inline] - fn from_str(s: &str) -> Result<Uri, InvalidUri> { - Uri::try_from(s.as_bytes()) - } -} - -impl PartialEq for Uri { - fn eq(&self, other: &Uri) -> bool { - if self.scheme() != other.scheme() { - return false; - } - - if self.authority() != other.authority() { - return false; - } - - if self.path() != other.path() { - return false; - } - - if self.query() != other.query() { - return false; - } - - true - } -} - -impl PartialEq<str> for Uri { - fn eq(&self, other: &str) -> bool { - let mut other = other.as_bytes(); - let mut absolute = false; - - if let Some(scheme) = self.scheme() { - let scheme = scheme.as_str().as_bytes(); - absolute = true; - - if other.len() < scheme.len() + 3 { - return false; - } - - if !scheme.eq_ignore_ascii_case(&other[..scheme.len()]) { - return false; - } - - other = &other[scheme.len()..]; - - if &other[..3] != b"://" { - return false; - } - - other = &other[3..]; - } - - if let Some(auth) = self.authority() { - let len = auth.data.len(); - absolute = true; - - if other.len() < len { - return false; - } - - if !auth.data.as_bytes().eq_ignore_ascii_case(&other[..len]) { - return false; - } - - other = &other[len..]; - } - - let path = self.path(); - - if other.len() < path.len() || path.as_bytes() != &other[..path.len()] { - if absolute && path == "/" { - // PathAndQuery can be omitted, fall through - } else { - return false; - } - } else { - other = &other[path.len()..]; - } - - if let Some(query) = self.query() { - if other.is_empty() { - return query.is_empty(); - } - - if other[0] != b'?' { - return false; - } - - other = &other[1..]; - - if other.len() < query.len() { - return false; - } - - if query.as_bytes() != &other[..query.len()] { - return false; - } - - other = &other[query.len()..]; - } - - other.is_empty() || other[0] == b'#' - } -} - -impl PartialEq<Uri> for str { - fn eq(&self, uri: &Uri) -> bool { - uri == self - } -} - -impl<'a> PartialEq<&'a str> for Uri { - fn eq(&self, other: &&'a str) -> bool { - self == *other - } -} - -impl<'a> PartialEq<Uri> for &'a str { - fn eq(&self, uri: &Uri) -> bool { - uri == *self - } -} - -impl Eq for Uri {} - -/// Returns a `Uri` representing `/` -impl Default for Uri { - #[inline] - fn default() -> Uri { - Uri { - scheme: Scheme::empty(), - authority: Authority::empty(), - path_and_query: PathAndQuery::slash(), - } - } -} - -impl fmt::Display for Uri { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(scheme) = self.scheme() { - write!(f, "{}://", scheme)?; - } - - if let Some(authority) = self.authority() { - write!(f, "{}", authority)?; - } - - write!(f, "{}", self.path())?; - - if let Some(query) = self.query() { - write!(f, "?{}", query)?; - } - - Ok(()) - } -} - -impl fmt::Debug for Uri { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl From<ErrorKind> for InvalidUri { - fn from(src: ErrorKind) -> InvalidUri { - InvalidUri(src) - } -} - -impl From<ErrorKind> for InvalidUriParts { - fn from(src: ErrorKind) -> InvalidUriParts { - InvalidUriParts(src.into()) - } -} - -impl InvalidUri { - fn s(&self) -> &str { - match self.0 { - ErrorKind::InvalidUriChar => "invalid uri character", - ErrorKind::InvalidScheme => "invalid scheme", - ErrorKind::InvalidAuthority => "invalid authority", - ErrorKind::InvalidPort => "invalid port", - ErrorKind::InvalidFormat => "invalid format", - ErrorKind::SchemeMissing => "scheme missing", - ErrorKind::AuthorityMissing => "authority missing", - ErrorKind::PathAndQueryMissing => "path missing", - ErrorKind::TooLong => "uri too long", - ErrorKind::Empty => "empty string", - ErrorKind::SchemeTooLong => "scheme too long", - } - } -} - -impl fmt::Display for InvalidUri { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.s().fmt(f) - } -} - -impl Error for InvalidUri {} - -impl fmt::Display for InvalidUriParts { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Error for InvalidUriParts {} - -impl Hash for Uri { - fn hash<H>(&self, state: &mut H) - where - H: Hasher, - { - if !self.scheme.inner.is_none() { - self.scheme.hash(state); - state.write_u8(0xff); - } - - if let Some(auth) = self.authority() { - auth.hash(state); - } - - Hash::hash_slice(self.path().as_bytes(), state); - - if let Some(query) = self.query() { - b'?'.hash(state); - Hash::hash_slice(query.as_bytes(), state); - } - } -} |
