//! 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"); //! ```
usecrate::byte_str::ByteStr; use std::convert::TryFrom;
use bytes::Bytes;
use std::error::Error; use std::hash::{Hash, Hasher}; use std::str::{self, FromStr}; use std::{fmt, u16, u8};
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)] pubstruct 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)] pubstruct 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)] pubstruct InvalidUri(ErrorKind);
/// An error resulting from a failed attempt to construct a URI. #[derive(Debug)] pubstruct InvalidUriParts(InvalidUri);
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(); /// ``` pubfn 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"); /// ``` pubfn 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(),
};
/// 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. pubfn 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> { useself::ErrorKind::*;
if s.len() > MAX_LEN { return Err(TooLong.into());
}
/// 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"); /// ``` pubfn 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] pubfn into_parts(self) -> Parts { self.into()
}
/// Returns the path & query components of the Uri #[inline] pubfn 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] pubfn path(&self) -> &str { ifself.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] pubfn scheme(&self) -> Option<&Scheme> { ifself.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] pubfn scheme_str(&self) -> Option<&str> { ifself.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] pubfn authority(&self) -> Option<&Authority> { ifself.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] pubfn 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()); /// ``` pubfn 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)); /// ``` pubfn port_u16(&self) -> Option<u16> { self.port().and_then(|p| Some(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] pubfn query(&self) -> Option<&str> { self.path_and_query.query()
}
/// 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)
};
if other.len() < scheme.len() + 3 { returnfalse;
}
if !scheme.eq_ignore_ascii_case(&other[..scheme.len()]) { returnfalse;
}
other = &other[scheme.len()..];
if &other[..3] != b"://" { returnfalse;
}
other = &other[3..];
}
iflet Some(auth) = self.authority() { let len = auth.data.len();
absolute = true;
if other.len() < len { returnfalse;
}
if !auth.data.as_bytes().eq_ignore_ascii_case(&other[..len]) { returnfalse;
}
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 { returnfalse;
}
} else {
other = &other[path.len()..];
}
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);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.