rocket_http_community/uri/authority.rs
1use std::borrow::Cow;
2use std::fmt::{self, Display};
3
4use crate::ext::IntoOwned;
5use crate::parse::{Extent, IndexedStr};
6use crate::uri::{as_utf8_unchecked, error::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///
23/// # (De)serialization
24///
25/// `Authority` is both `Serialize` and `Deserialize`:
26///
27/// ```rust
28/// # #[cfg(feature = "serde")] mod serde_impl {
29/// # use serde as serde;
30/// use serde::{Serialize, Deserialize};
31/// use rocket::http::uri::Authority;
32///
33/// #[derive(Deserialize, Serialize)]
34/// # #[serde(crate = "serde")]
35/// struct UriOwned {
36/// uri: Authority<'static>,
37/// }
38///
39/// #[derive(Deserialize, Serialize)]
40/// # #[serde(crate = "serde")]
41/// struct UriBorrowed<'a> {
42/// uri: Authority<'a>,
43/// }
44/// # }
45/// ```
46#[derive(Debug, Clone)]
47pub struct Authority<'a> {
48 pub(crate) source: Option<Cow<'a, str>>,
49 pub(crate) user_info: Option<IndexedStr<'a>>,
50 host: IndexedStr<'a>,
51 port: Option<u16>,
52}
53
54impl<'a> Authority<'a> {
55 // SAFETY: `source` must be valid UTF-8.
56 // CORRECTNESS: `host` must be non-empty.
57 pub(crate) unsafe fn raw(
58 source: Cow<'a, [u8]>,
59 user_info: Option<Extent<&'a [u8]>>,
60 host: Extent<&'a [u8]>,
61 port: Option<u16>,
62 ) -> Authority<'a> {
63 Authority {
64 source: Some(as_utf8_unchecked(source)),
65 user_info: user_info.map(IndexedStr::from),
66 host: IndexedStr::from(host),
67 port,
68 }
69 }
70
71 /// PRIVATE. Used by core.
72 #[doc(hidden)]
73 pub fn new(
74 user_info: impl Into<Option<&'a str>>,
75 host: &'a str,
76 port: impl Into<Option<u16>>,
77 ) -> Self {
78 Authority::const_new(user_info.into(), host, port.into())
79 }
80
81 /// PRIVATE. Used by codegen.
82 #[doc(hidden)]
83 pub const fn const_new(user_info: Option<&'a str>, host: &'a str, port: Option<u16>) -> Self {
84 Authority {
85 source: None,
86 user_info: match user_info {
87 Some(info) => Some(IndexedStr::Concrete(Cow::Borrowed(info))),
88 None => None,
89 },
90 host: IndexedStr::Concrete(Cow::Borrowed(host)),
91 port,
92 }
93 }
94
95 /// Parses the string `string` into an `Authority`. Parsing will never
96 /// allocate. Returns an `Error` if `string` is not a valid authority URI.
97 ///
98 /// # Example
99 ///
100 /// ```rust
101 /// # #[macro_use] extern crate rocket;
102 /// use rocket::http::uri::Authority;
103 ///
104 /// // Parse a valid authority URI.
105 /// let uri = Authority::parse("user:pass@host").expect("valid URI");
106 /// assert_eq!(uri.user_info(), Some("user:pass"));
107 /// assert_eq!(uri.host(), "host");
108 /// assert_eq!(uri.port(), None);
109 ///
110 /// // Invalid authority URIs fail to parse.
111 /// Authority::parse("https://rocket.rs").expect_err("invalid authority");
112 ///
113 /// // Prefer to use `uri!()` when the input is statically known:
114 /// let uri = uri!("user:pass@host");
115 /// assert_eq!(uri.user_info(), Some("user:pass"));
116 /// assert_eq!(uri.host(), "host");
117 /// assert_eq!(uri.port(), None);
118 /// ```
119 pub fn parse(string: &'a str) -> Result<Authority<'a>, Error<'a>> {
120 crate::parse::uri::authority_from_str(string)
121 }
122
123 /// Parses the string `string` into an `Authority`. Parsing never allocates
124 /// on success. May allocate on error.
125 ///
126 /// This method should be used instead of [`Authority::parse()`] when
127 /// the source URI is already a `String`. Returns an `Error` if `string` is
128 /// not a valid authority URI.
129 ///
130 /// # Example
131 ///
132 /// ```rust
133 /// # extern crate rocket;
134 /// use rocket::http::uri::Authority;
135 ///
136 /// let source = format!("rocket.rs:8000");
137 /// let uri = Authority::parse_owned(source).expect("valid URI");
138 /// assert!(uri.user_info().is_none());
139 /// assert_eq!(uri.host(), "rocket.rs");
140 /// assert_eq!(uri.port(), Some(8000));
141 /// ```
142 pub fn parse_owned(string: String) -> Result<Authority<'static>, Error<'static>> {
143 let authority = Authority::parse(&string).map_err(|e| e.into_owned())?;
144 debug_assert!(authority.source.is_some(), "Authority parsed w/o source");
145
146 let authority = Authority {
147 host: authority.host.into_owned(),
148 user_info: authority.user_info.into_owned(),
149 port: authority.port,
150 source: Some(Cow::Owned(string)),
151 };
152
153 Ok(authority)
154 }
155
156 /// Returns the user info part of the authority URI, if there is one.
157 ///
158 /// # Example
159 /// ```rust
160 /// # #[macro_use] extern crate rocket;
161 /// let uri = uri!("username:password@host");
162 /// assert_eq!(uri.user_info(), Some("username:password"));
163 /// ```
164 pub fn user_info(&self) -> Option<&str> {
165 self.user_info
166 .as_ref()
167 .map(|u| u.from_cow_source(&self.source))
168 }
169
170 /// Returns the host part of the authority URI.
171 ///
172 /// # Example
173 ///
174 /// ```rust
175 /// # #[macro_use] extern crate rocket;
176 /// let uri = uri!("domain.com:123");
177 /// assert_eq!(uri.host(), "domain.com");
178 ///
179 /// let uri = uri!("username:password@host:123");
180 /// assert_eq!(uri.host(), "host");
181 ///
182 /// let uri = uri!("username:password@[1::2]:123");
183 /// assert_eq!(uri.host(), "[1::2]");
184 /// ```
185 #[inline(always)]
186 pub fn host(&self) -> &str {
187 self.host.from_cow_source(&self.source)
188 }
189
190 /// Returns the `port` part of the authority URI, if there is one.
191 ///
192 /// # Example
193 ///
194 /// ```rust
195 /// # #[macro_use] extern crate rocket;
196 /// // With a port.
197 /// let uri = uri!("username:password@host:123");
198 /// assert_eq!(uri.port(), Some(123));
199 ///
200 /// let uri = uri!("domain.com:8181");
201 /// assert_eq!(uri.port(), Some(8181));
202 ///
203 /// // Without a port.
204 /// let uri = uri!("username:password@host");
205 /// assert_eq!(uri.port(), None);
206 /// ```
207 #[inline(always)]
208 pub fn port(&self) -> Option<u16> {
209 self.port
210 }
211
212 /// Set the `port` of the authority URI.
213 ///
214 /// # Example
215 ///
216 /// ```rust
217 /// # #[macro_use] extern crate rocket;
218 /// let mut uri = uri!("username:password@host:123");
219 /// assert_eq!(uri.port(), Some(123));
220 ///
221 /// uri.set_port(1024);
222 /// assert_eq!(uri.port(), Some(1024));
223 /// assert_eq!(uri, "username:password@host:1024");
224 ///
225 /// uri.set_port(None);
226 /// assert_eq!(uri.port(), None);
227 /// assert_eq!(uri, "username:password@host");
228 /// ```
229 #[inline(always)]
230 pub fn set_port<T: Into<Option<u16>>>(&mut self, port: T) {
231 self.port = port.into();
232 }
233}
234
235impl_serde!(Authority<'a>, "an authority-form URI");
236
237impl_traits!(Authority, user_info, host, port);
238
239impl Display for Authority<'_> {
240 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241 if let Some(user_info) = self.user_info() {
242 write!(f, "{}@", user_info)?;
243 }
244
245 self.host().fmt(f)?;
246 if let Some(port) = self.port {
247 write!(f, ":{}", port)?;
248 }
249
250 Ok(())
251 }
252}