blob: 8240fd07dca08d16b91d8b43dff89cacc49f626e [file] [log] [blame]
//! 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_part().map(|s| s.as_str()), Some("https"));
//! assert_eq!(uri.host(), Some("www.rust-lang.org"));
//! assert_eq!(uri.path(), "/install.html");
//! ```
use HttpTryFrom;
use byte_str::ByteStr;
use bytes::Bytes;
use std::{fmt, u8, u16};
// Deprecated in 1.26, needed until our minimum version is >=1.23.
#[allow(unused, deprecated)]
use std::ascii::AsciiExt;
use std::hash::{Hash, Hasher};
use std::str::{self, FromStr};
use std::error::Error;
use self::scheme::Scheme2;
pub use self::authority::Authority;
pub use self::path::PathAndQuery;
pub use self::scheme::Scheme;
mod authority;
mod path;
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_part().map(|s| s.as_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 InvalidUriBytes(InvalidUri);
/// 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,
InvalidFormat,
SchemeMissing,
AuthorityMissing,
PathAndQueryMissing,
TooLong,
Empty,
SchemeTooLong,
}
// u16::MAX is reserved for None
const MAX_LEN: usize = (u16::MAX - 1) as usize;
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 {
/// Attempt to convert a `Uri` from `Parts`
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: scheme,
authority: authority,
path_and_query: path_and_query,
})
}
/// Attempt to convert a `Uri` from `Bytes`
///
/// This function will be replaced by a `TryFrom` implementation once the
/// trait lands in stable.
///
/// # Examples
///
/// ```
/// # extern crate http;
/// # use http::uri::*;
/// extern crate bytes;
///
/// use bytes::Bytes;
///
/// # pub fn main() {
/// let bytes = Bytes::from("http://example.com/foo");
/// let uri = Uri::from_shared(bytes).unwrap();
///
/// assert_eq!(uri.host().unwrap(), "example.com");
/// assert_eq!(uri.path(), "/foo");
/// # }
/// ```
pub fn from_shared(s: Bytes) -> Result<Uri, InvalidUriBytes> {
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: 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;
/// let uri: Uri = "http://example.org/hello/world".parse().unwrap();
///
/// assert_eq!(uri.scheme_part().map(|s| s.as_str()), Some("http"));
/// ```
///
///
/// Relative URI
///
/// ```
/// # use http::Uri;
/// let uri: Uri = "/hello/world".parse().unwrap();
///
/// assert!(uri.scheme_part().is_none());
/// ```
#[inline]
pub fn scheme_part(&self) -> Option<&Scheme> {
if self.scheme.inner.is_none() {
None
} else {
Some(&self.scheme)
}
}
#[deprecated(since = "0.1.2", note = "use scheme_part instead")]
#[doc(hidden)]
#[inline]
pub fn scheme(&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
/// ```
///
/// This function will be renamed to `authority` in the next semver release.
///
/// # Examples
///
/// Absolute URI
///
/// ```
/// # use http::Uri;
/// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap();
///
/// assert_eq!(uri.authority_part().map(|a| a.as_str()), Some("example.org:80"));
/// ```
///
///
/// Relative URI
///
/// ```
/// # use http::Uri;
/// let uri: Uri = "/hello/world".parse().unwrap();
///
/// assert!(uri.authority_part().is_none());
/// ```
#[inline]
pub fn authority_part(&self) -> Option<&Authority> {
if self.authority.data.is_empty() {
None
} else {
Some(&self.authority)
}
}
#[deprecated(since = "0.1.1", note = "use authority_part instead")]
#[doc(hidden)]
#[inline]
pub fn authority(&self) -> Option<&str> {
if self.authority.data.is_empty() {
None
} else {
Some(self.authority.as_str())
}
}
/// 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_part().map(|a| a.host())
}
/// Get the port of this `Uri`.
///
/// The port subcomponent of authority is designated by an optional port
/// number in decimal following the host and delimited from it by a single
/// colon (":") character. A value is only returned if one is specified in
/// the URI string, i.e., default port values are **not** returned.
///
/// ```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();
///
/// assert_eq!(uri.port(), Some(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<u16> {
self.authority_part()
.and_then(|a| a.port())
}
/// 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> HttpTryFrom<&'a str> for Uri {
type Error = InvalidUri;
#[inline]
fn try_from(t: &'a str) -> Result<Self, Self::Error> {
t.parse()
}
}
impl<'a> HttpTryFrom<&'a String> for Uri {
type Error = InvalidUri;
#[inline]
fn try_from(t: &'a String) -> Result<Self, Self::Error> {
t.parse()
}
}
impl HttpTryFrom<String> for Uri {
type Error = InvalidUriBytes;
#[inline]
fn try_from(t: String) -> Result<Self, Self::Error> {
Uri::from_shared(Bytes::from(t))
}
}
impl HttpTryFrom<Bytes> for Uri {
type Error = InvalidUriBytes;
#[inline]
fn try_from(t: Bytes) -> Result<Self, Self::Error> {
Uri::from_shared(t)
}
}
impl HttpTryFrom<Parts> for Uri {
type Error = InvalidUriParts;
#[inline]
fn try_from(src: Parts) -> Result<Self, Self::Error> {
Uri::from_parts(src)
}
}
impl<'a> HttpTryFrom<&'a Uri> for Uri {
type Error = ::Error;
#[inline]
fn try_from(src: &'a Uri) -> Result<Self, Self::Error> {
Ok(src.clone())
}
}
/// Convert a `Uri` from parts
///
/// # 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_part().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_part().unwrap().as_str(), "http");
/// assert_eq!(uri.authority().unwrap(), "foo.com");
/// assert_eq!(uri.path(), "/foo");
/// ```
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: scheme,
authority: authority,
path_and_query: path_and_query,
_priv: (),
}
}
}
fn parse_full(mut s: Bytes) -> Result<Uri, InvalidUriBytes> {
// Parse the scheme
let scheme = match Scheme2::parse(&s[..]).map_err(InvalidUriBytes)? {
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[..]).map_err(InvalidUriBytes)?;
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: 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: 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::from_shared(s.into()).map_err(|e| e.0)
}
}
impl PartialEq for Uri {
fn eq(&self, other: &Uri) -> bool {
if self.scheme_part() != other.scheme_part() {
return false;
}
if self.authority_part() != other.authority_part() {
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_part() {
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_part() {
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 ommitted, fall through
} else {
return false;
}
} else {
other = &other[path.len()..];
}
if let Some(query) = self.query() {
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_part() {
write!(f, "{}://", scheme)?;
}
if let Some(authority) = self.authority_part() {
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 InvalidUriBytes {
fn from(src: ErrorKind) -> InvalidUriBytes {
InvalidUriBytes(src.into())
}
}
impl From<ErrorKind> for InvalidUriParts {
fn from(src: ErrorKind) -> InvalidUriParts {
InvalidUriParts(src.into())
}
}
impl fmt::Display for InvalidUri {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.description().fmt(f)
}
}
impl Error for InvalidUri {
fn description(&self) -> &str {
match self.0 {
ErrorKind::InvalidUriChar => "invalid uri character",
ErrorKind::InvalidScheme => "invalid scheme",
ErrorKind::InvalidAuthority => "invalid authority",
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 InvalidUriBytes {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl fmt::Display for InvalidUriParts {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl Error for InvalidUriBytes {
fn description(&self) -> &str {
self.0.description()
}
}
impl Error for InvalidUriParts {
fn description(&self) -> &str {
self.0.description()
}
}
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_part() {
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);
}
}
}