1 use std::borrow::Cow; 2 use std::fmt::{self, Display}; 3 4 use crate::ext::IntoOwned; 5 use crate::parse::{Indexed, IndexedStr}; 6 use crate::uri::{Authority, Origin, Error, as_utf8_unchecked}; 7 8 /// A URI with a scheme, authority, path, and query: 9 /// `http://user:pass@domain.com:4444/path?query`. 10 /// 11 /// # Structure 12 /// 13 /// The following diagram illustrates the syntactic structure of an absolute 14 /// URI with all optional parts: 15 /// 16 /// ```text 17 /// http://user:pass@domain.com:4444/path?query 18 /// |--| |-----------------------||---------| 19 /// scheme authority origin 20 /// ``` 21 /// 22 /// The scheme part of the absolute URI and at least one of authority or origin 23 /// are required. 24 #[derive(Debug, Clone)] 25 pub struct Absolute<'a> { 26 source: Option<Cow<'a, str>>, 27 scheme: IndexedStr<'a>, 28 authority: Option<Authority<'a>>, 29 origin: Option<Origin<'a>>, 30 } 31 32 impl IntoOwned for Absolute<'_> { 33 type Owned = Absolute<'static>; 34 into_owned(self) -> Self::Owned35 fn into_owned(self) -> Self::Owned { 36 Absolute { 37 source: self.source.into_owned(), 38 scheme: self.scheme.into_owned(), 39 authority: self.authority.into_owned(), 40 origin: self.origin.into_owned(), 41 } 42 } 43 } 44 45 impl<'a> Absolute<'a> { 46 #[inline] raw( source: Cow<'a, [u8]>, scheme: Indexed<'a, [u8]>, authority: Option<Authority<'a>>, origin: Option<Origin<'a>>, ) -> Absolute<'a>47 pub(crate) unsafe fn raw( 48 source: Cow<'a, [u8]>, 49 scheme: Indexed<'a, [u8]>, 50 authority: Option<Authority<'a>>, 51 origin: Option<Origin<'a>>, 52 ) -> Absolute<'a> { 53 Absolute { 54 source: Some(as_utf8_unchecked(source)), 55 scheme: scheme.coerce(), 56 authority: authority, 57 origin: origin, 58 } 59 } 60 61 #[cfg(test)] new( scheme: &'a str, authority: Option<Authority<'a>>, origin: Option<Origin<'a>> ) -> Absolute<'a>62 pub(crate) fn new( 63 scheme: &'a str, 64 authority: Option<Authority<'a>>, 65 origin: Option<Origin<'a>> 66 ) -> Absolute<'a> { 67 Absolute { 68 source: None, scheme: scheme.into(), authority, origin 69 } 70 } 71 72 /// Parses the string `string` into an `Absolute`. Parsing will never 73 /// allocate. Returns an `Error` if `string` is not a valid absolute URI. 74 /// 75 /// # Example 76 /// 77 /// ```rust 78 /// # extern crate rocket; 79 /// use rocket::http::uri::Absolute; 80 /// 81 /// // Parse a valid authority URI. 82 /// let uri = Absolute::parse("http://google.com").expect("valid URI"); 83 /// assert_eq!(uri.scheme(), "http"); 84 /// assert_eq!(uri.authority().unwrap().host(), "google.com"); 85 /// assert_eq!(uri.origin(), None); 86 /// ``` parse(string: &'a str) -> Result<Absolute<'a>, Error<'a>>87 pub fn parse(string: &'a str) -> Result<Absolute<'a>, Error<'a>> { 88 crate::parse::uri::absolute_from_str(string) 89 } 90 91 /// Returns the scheme part of the absolute URI. 92 /// 93 /// # Example 94 /// 95 /// ```rust 96 /// # extern crate rocket; 97 /// use rocket::http::uri::Absolute; 98 /// 99 /// let uri = Absolute::parse("ftp://127.0.0.1").expect("valid URI"); 100 /// assert_eq!(uri.scheme(), "ftp"); 101 /// ``` 102 #[inline(always)] scheme(&self) -> &str103 pub fn scheme(&self) -> &str { 104 self.scheme.from_cow_source(&self.source) 105 } 106 107 /// Returns the authority part of the absolute URI, if there is one. 108 /// 109 /// # Example 110 /// 111 /// ```rust 112 /// # extern crate rocket; 113 /// use rocket::http::uri::Absolute; 114 /// 115 /// let uri = Absolute::parse("https://rocket.rs:80").expect("valid URI"); 116 /// assert_eq!(uri.scheme(), "https"); 117 /// let authority = uri.authority().unwrap(); 118 /// assert_eq!(authority.host(), "rocket.rs"); 119 /// assert_eq!(authority.port(), Some(80)); 120 /// 121 /// let uri = Absolute::parse("file:/web/home").expect("valid URI"); 122 /// assert_eq!(uri.authority(), None); 123 /// ``` 124 #[inline(always)] authority(&self) -> Option<&Authority<'a>>125 pub fn authority(&self) -> Option<&Authority<'a>> { 126 self.authority.as_ref() 127 } 128 129 /// Returns the origin part of the absolute URI, if there is one. 130 /// 131 /// # Example 132 /// 133 /// ```rust 134 /// # extern crate rocket; 135 /// use rocket::http::uri::Absolute; 136 /// 137 /// let uri = Absolute::parse("file:/web/home.html?new").expect("valid URI"); 138 /// assert_eq!(uri.scheme(), "file"); 139 /// let origin = uri.origin().unwrap(); 140 /// assert_eq!(origin.path(), "/web/home.html"); 141 /// assert_eq!(origin.query(), Some("new")); 142 /// 143 /// let uri = Absolute::parse("https://rocket.rs").expect("valid URI"); 144 /// assert_eq!(uri.origin(), None); 145 /// ``` 146 #[inline(always)] origin(&self) -> Option<&Origin<'a>>147 pub fn origin(&self) -> Option<&Origin<'a>> { 148 self.origin.as_ref() 149 } 150 } 151 152 impl<'b> PartialEq<Absolute<'b>> for Absolute<'_> { eq(&self, other: &Absolute<'b>) -> bool153 fn eq(&self, other: &Absolute<'b>) -> bool { 154 self.scheme() == other.scheme() 155 && self.authority() == other.authority() 156 && self.origin() == other.origin() 157 } 158 } 159 160 impl Display for Absolute<'_> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 162 write!(f, "{}", self.scheme())?; 163 match self.authority { 164 Some(ref authority) => write!(f, "://{}", authority)?, 165 None => write!(f, ":")? 166 } 167 168 if let Some(ref origin) = self.origin { 169 write!(f, "{}", origin)?; 170 } 171 172 Ok(()) 173 } 174 } 175 176