rocket_http/uri/authority.rs
1use std::fmt::{self, Display};
2use std::borrow::Cow;
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 {
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.as_ref().map(|u| u.from_cow_source(&self.source))
166 }
167
168 /// Returns the host part of the authority URI.
169 ///
170 /// # Example
171 ///
172 /// ```rust
173 /// # #[macro_use] extern crate rocket;
174 /// let uri = uri!("domain.com:123");
175 /// assert_eq!(uri.host(), "domain.com");
176 ///
177 /// let uri = uri!("username:password@host:123");
178 /// assert_eq!(uri.host(), "host");
179 ///
180 /// let uri = uri!("username:password@[1::2]:123");
181 /// assert_eq!(uri.host(), "[1::2]");
182 /// ```
183 #[inline(always)]
184 pub fn host(&self) -> &str {
185 self.host.from_cow_source(&self.source)
186 }
187
188 /// Returns the port part of the authority URI, if there is one.
189 ///
190 /// # Example
191 ///
192 /// ```rust
193 /// # #[macro_use] extern crate rocket;
194 /// // With a port.
195 /// let uri = uri!("username:password@host:123");
196 /// assert_eq!(uri.port(), Some(123));
197 ///
198 /// let uri = uri!("domain.com:8181");
199 /// assert_eq!(uri.port(), Some(8181));
200 ///
201 /// // Without a port.
202 /// let uri = uri!("username:password@host");
203 /// assert_eq!(uri.port(), None);
204 /// ```
205 #[inline(always)]
206 pub fn port(&self) -> Option<u16> {
207 self.port
208 }
209}
210
211impl_serde!(Authority<'a>, "an authority-form URI");
212
213impl_traits!(Authority, user_info, host, port);
214
215impl Display for Authority<'_> {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 if let Some(user_info) = self.user_info() {
218 write!(f, "{}@", user_info)?;
219 }
220
221 self.host().fmt(f)?;
222 if let Some(port) = self.port {
223 write!(f, ":{}", port)?;
224 }
225
226 Ok(())
227 }
228}