1 use std::fmt::{self, Display}; 2 use std::borrow::Cow; 3 4 use crate::ext::IntoOwned; 5 use crate::parse::{Indexed, IndexedStr}; 6 use crate::uri::{as_utf8_unchecked, Error}; 7 8 /// A URI with an authority only: `user:pass@host:8000`. 9 /// 10 /// # Structure 11 /// 12 /// The following diagram illustrates the syntactic structure of an authority 13 /// URI: 14 /// 15 /// ```text 16 /// username:password@some.host:8088 17 /// |---------------| |-------| |--| 18 /// user info host port 19 /// ``` 20 /// 21 /// Only the host part of the URI is required. 22 #[derive(Debug, Clone)] 23 pub struct Authority<'a> { 24 source: Option<Cow<'a, str>>, 25 user_info: Option<IndexedStr<'a>>, 26 host: Host<IndexedStr<'a>>, 27 port: Option<u16>, 28 } 29 30 #[derive(Debug, Clone)] 31 pub(crate) enum Host<T> { 32 Bracketed(T), 33 Raw(T) 34 } 35 36 impl<T: IntoOwned> IntoOwned for Host<T> { 37 type Owned = Host<T::Owned>; 38 into_owned(self) -> Self::Owned39 fn into_owned(self) -> Self::Owned { 40 self.map_inner(IntoOwned::into_owned) 41 } 42 } 43 44 impl IntoOwned for Authority<'_> { 45 type Owned = Authority<'static>; 46 into_owned(self) -> Authority<'static>47 fn into_owned(self) -> Authority<'static> { 48 Authority { 49 source: self.source.into_owned(), 50 user_info: self.user_info.into_owned(), 51 host: self.host.into_owned(), 52 port: self.port 53 } 54 } 55 } 56 57 impl<'a> Authority<'a> { raw( source: Cow<'a, [u8]>, user_info: Option<Indexed<'a, [u8]>>, host: Host<Indexed<'a, [u8]>>, port: Option<u16> ) -> Authority<'a>58 pub(crate) unsafe fn raw( 59 source: Cow<'a, [u8]>, 60 user_info: Option<Indexed<'a, [u8]>>, 61 host: Host<Indexed<'a, [u8]>>, 62 port: Option<u16> 63 ) -> Authority<'a> { 64 Authority { 65 source: Some(as_utf8_unchecked(source)), 66 user_info: user_info.map(|u| u.coerce()), 67 host: host.map_inner(|inner| inner.coerce()), 68 port: port 69 } 70 } 71 72 #[cfg(test)] new( user_info: Option<&'a str>, host: Host<&'a str>, port: Option<u16> ) -> Authority<'a>73 pub(crate) fn new( 74 user_info: Option<&'a str>, 75 host: Host<&'a str>, 76 port: Option<u16> 77 ) -> Authority<'a> { 78 Authority { 79 source: None, 80 user_info: user_info.map(|u| u.into()), 81 host: host.map_inner(|inner| inner.into()), 82 port: port 83 } 84 } 85 86 /// Parses the string `string` into an `Authority`. Parsing will never 87 /// allocate. Returns an `Error` if `string` is not a valid authority URI. 88 /// 89 /// # Example 90 /// 91 /// ```rust 92 /// # extern crate rocket; 93 /// use rocket::http::uri::Authority; 94 /// 95 /// // Parse a valid authority URI. 96 /// let uri = Authority::parse("user:pass@host").expect("valid URI"); 97 /// assert_eq!(uri.user_info(), Some("user:pass")); 98 /// assert_eq!(uri.host(), "host"); 99 /// assert_eq!(uri.port(), None); 100 /// 101 /// // Invalid authority URIs fail to parse. 102 /// Authority::parse("http://google.com").expect_err("invalid authority"); 103 /// ``` parse(string: &'a str) -> Result<Authority<'a>, Error<'a>>104 pub fn parse(string: &'a str) -> Result<Authority<'a>, Error<'a>> { 105 crate::parse::uri::authority_from_str(string) 106 } 107 108 /// Returns the user info part of the authority URI, if there is one. 109 /// 110 /// # Example 111 /// 112 /// ```rust 113 /// # extern crate rocket; 114 /// use rocket::http::uri::Authority; 115 /// 116 /// let uri = Authority::parse("username:password@host").unwrap(); 117 /// assert_eq!(uri.user_info(), Some("username:password")); 118 /// ``` user_info(&self) -> Option<&str>119 pub fn user_info(&self) -> Option<&str> { 120 self.user_info.as_ref().map(|u| u.from_cow_source(&self.source)) 121 } 122 123 /// Returns the host part of the authority URI. 124 /// 125 /// 126 /// If the host was provided in brackets (such as for IPv6 addresses), the 127 /// brackets will not be part of the returned string. 128 /// 129 /// # Example 130 /// 131 /// ```rust 132 /// # extern crate rocket; 133 /// use rocket::http::uri::Authority; 134 /// 135 /// let uri = Authority::parse("domain.com:123").unwrap(); 136 /// assert_eq!(uri.host(), "domain.com"); 137 /// 138 /// let uri = Authority::parse("username:password@host:123").unwrap(); 139 /// assert_eq!(uri.host(), "host"); 140 /// 141 /// let uri = Authority::parse("username:password@[1::2]:123").unwrap(); 142 /// assert_eq!(uri.host(), "1::2"); 143 /// ``` 144 #[inline(always)] host(&self) -> &str145 pub fn host(&self) -> &str { 146 self.host.inner().from_cow_source(&self.source) 147 } 148 149 /// Returns the port part of the authority URI, if there is one. 150 /// 151 /// # Example 152 /// 153 /// ```rust 154 /// # extern crate rocket; 155 /// use rocket::http::uri::Authority; 156 /// 157 /// // With a port. 158 /// let uri = Authority::parse("username:password@host:123").unwrap(); 159 /// assert_eq!(uri.port(), Some(123)); 160 /// 161 /// let uri = Authority::parse("domain.com:8181").unwrap(); 162 /// assert_eq!(uri.port(), Some(8181)); 163 /// 164 /// // Without a port. 165 /// let uri = Authority::parse("username:password@host").unwrap(); 166 /// assert_eq!(uri.port(), None); 167 /// ``` 168 #[inline(always)] port(&self) -> Option<u16>169 pub fn port(&self) -> Option<u16> { 170 self.port 171 } 172 } 173 174 impl<'b> PartialEq<Authority<'b>> for Authority<'_> { eq(&self, other: &Authority<'b>) -> bool175 fn eq(&self, other: &Authority<'b>) -> bool { 176 self.user_info() == other.user_info() 177 && self.host() == other.host() 178 && self.host.is_bracketed() == other.host.is_bracketed() 179 && self.port() == other.port() 180 } 181 } 182 183 impl Display for Authority<'_> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 185 if let Some(user_info) = self.user_info() { 186 write!(f, "{}@", user_info)?; 187 } 188 189 match self.host { 190 Host::Bracketed(_) => write!(f, "[{}]", self.host())?, 191 Host::Raw(_) => write!(f, "{}", self.host())? 192 } 193 194 if let Some(port) = self.port { 195 write!(f, ":{}", port)?; 196 } 197 198 Ok(()) 199 } 200 } 201 202 impl<T> Host<T> { 203 #[inline] inner(&self) -> &T204 fn inner(&self) -> &T { 205 match *self { 206 Host::Bracketed(ref inner) | Host::Raw(ref inner) => inner 207 } 208 } 209 210 #[inline] is_bracketed(&self) -> bool211 fn is_bracketed(&self) -> bool { 212 match *self { 213 Host::Bracketed(_) => true, 214 _ => false 215 } 216 } 217 218 #[inline] map_inner<F, U>(self, f: F) -> Host<U> where F: FnOnce(T) -> U219 fn map_inner<F, U>(self, f: F) -> Host<U> 220 where F: FnOnce(T) -> U 221 { 222 match self { 223 Host::Bracketed(inner) => Host::Bracketed(f(inner)), 224 Host::Raw(inner) => Host::Raw(f(inner)) 225 } 226 } 227 } 228