uriparse/authority.rs
1//! Authority Component
2//!
3//! See [[RFC3986, Section 3.2](https://tools.ietf.org/html/rfc3986#section-3.2)].
4//!
5//! # Examples
6//!
7//! ```
8//! use std::convert::TryFrom;
9//!
10//! use uriparse::Authority;
11//!
12//! let authority = Authority::try_from("example.com").unwrap();
13//! let host = authority.into_parts().2;
14//! let authority =
15//! Authority::from_parts(Some("username"), Some("password"), host, Some(80)).unwrap();
16//! assert_eq!(authority.to_string(), "username:password@example.com:80");
17//! ```
18//!
19//! # Equality
20//!
21//! While many components in this library support string comparison, [`Authority`] does not. This
22//! comes down to it just being too expensive to do a proper host comparison. To do so would require
23//! conversion to [`IpAddr`], which in the case of [`Ipv6Addr`] can be expensive.
24
25use std::borrow::Cow;
26use std::convert::{Infallible, TryFrom};
27use std::error::Error;
28use std::fmt::{self, Display, Formatter, Write};
29use std::hash::{Hash, Hasher};
30use std::mem;
31use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
32use std::ops::Deref;
33use std::str;
34
35use crate::utility::{
36 get_percent_encoded_value, normalize_string, percent_encoded_equality, percent_encoded_hash,
37 UNRESERVED_CHAR_MAP,
38};
39
40/// A map of byte characters that determines if a character is a valid IPv4 or registered name
41/// character.
42#[rustfmt::skip]
43const IPV4_AND_REGISTERED_NAME_CHAR_MAP: [u8; 256] = [
44 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
46 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
47 0, b'!', 0, 0, b'$', b'%', b'&',b'\'', b'(', b')', b'*', b'+', b',', b'-', b'.', 0, // 2
48 b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', 0, b';', 0, b'=', 0, 0, // 3
49 0, b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', // 4
50 b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', 0, 0, 0, 0, b'_', // 5
51 0, b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', // 6
52 b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', 0, 0, 0, b'~', 0, // 7
53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
54 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
56 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
57 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
60 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F
61];
62
63/// A map of byte characters that determines if a character is a valid future IP literal character.
64#[rustfmt::skip]
65const IPV_FUTURE_CHAR_MAP: [u8; 256] = [
66 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
67 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
68 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
69 0, b'!', 0, 0, b'$', 0, b'&',b'\'', b'(', b')', b'*', b'+', b',', b'-', b'.', 0, // 2
70 b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b':', b';', 0, b'=', 0, 0, // 3
71 0, b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', // 4
72 b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', 0, 0, 0, 0, b'_', // 5
73 0, b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', // 6
74 b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', 0, 0, 0, b'~', 0, // 7
75 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
76 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
77 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
78 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
79 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
81 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
82 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F
83];
84
85/// A map of byte characters that determines if a character is a valid user information character.
86#[rustfmt::skip]
87const USER_INFO_CHAR_MAP: [u8; 256] = [
88 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
89 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
90 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
91 0, b'!', 0, 0, b'$', b'%', b'&',b'\'', b'(', b')', b'*', b'+', b',', b'-', b'.', 0, // 2
92 b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b':', b';', 0, b'=', 0, 0, // 3
93 0, b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', // 4
94 b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', 0, 0, 0, 0, b'_', // 5
95 0, b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', // 6
96 b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z', 0, 0, 0, b'~', 0, // 7
97 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
98 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
99 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
103 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F
105];
106
107/// The authority component as defined in
108/// [[RFC3986, Section 3.2](https://tools.ietf.org/html/rfc3986#section-3.2)].
109///
110/// Any conversions to a string will **not** hide the password component of the authority. Be
111/// careful if you decide to perform logging.
112#[derive(Clone, Debug, Eq, Hash, PartialEq)]
113#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
114pub struct Authority<'authority> {
115 /// The host component of the authority as defined in
116 /// [[RFC3986, Section 3.2.2](https://tools.ietf.org/html/rfc3986#section-3.2.2)].
117 host: Host<'authority>,
118
119 /// The password component of the authority as defined in
120 /// [[RFC3986, Section 3.2.1](https://tools.ietf.org/html/rfc3986#section-3.2.1)].
121 password: Option<Password<'authority>>,
122
123 /// The port component of the authority as defined in
124 /// [[RFC3986, Section 3.2.3](https://tools.ietf.org/html/rfc3986#section-3.2.3)].
125 port: Option<u16>,
126
127 /// The username component of the authority as defined in
128 /// [[RFC3986, Section 3.2.1](https://tools.ietf.org/html/rfc3986#section-3.2.1)].
129 username: Option<Username<'authority>>,
130}
131
132impl<'authority> Authority<'authority> {
133 pub fn as_borrowed(&self) -> Authority {
134 let host = match &self.host {
135 Host::RegisteredName(name) => Host::RegisteredName(name.as_borrowed()),
136 Host::IPv4Address(ipv4) => Host::IPv4Address(*ipv4),
137 Host::IPv6Address(ipv6) => Host::IPv6Address(*ipv6),
138 };
139 let password = self.password.as_ref().map(Password::as_borrowed);
140 let username = self.username.as_ref().map(Username::as_borrowed);
141
142 Authority {
143 host,
144 password,
145 port: self.port,
146 username,
147 }
148 }
149
150 /// Constructs a new [`Authority`] from the individual parts: username, password, host, and
151 /// port.
152 ///
153 /// The lifetime used by the resulting value will be the lifetime of the part that is most
154 /// restricted in scope.
155 ///
156 /// # Examples
157 ///
158 /// ```
159 /// use std::convert::TryFrom;
160 ///
161 /// use uriparse::Authority;
162 ///
163 /// let authority = Authority::from_parts(
164 /// Some("username"),
165 /// Some("password"),
166 /// "example.com",
167 /// Some(80)
168 /// ).unwrap();
169 /// assert_eq!(authority.to_string(), "username:password@example.com:80");
170 /// ```
171 pub fn from_parts<
172 'new_authority,
173 TUsername,
174 TPassword,
175 THost,
176 TUsernameError,
177 TPasswordError,
178 THostError,
179 >(
180 username: Option<TUsername>,
181 password: Option<TPassword>,
182 host: THost,
183 port: Option<u16>,
184 ) -> Result<Authority<'new_authority>, AuthorityError>
185 where
186 Username<'new_authority>: TryFrom<TUsername, Error = TUsernameError>,
187 Password<'new_authority>: TryFrom<TPassword, Error = TPasswordError>,
188 Host<'new_authority>: TryFrom<THost, Error = THostError>,
189 AuthorityError: From<TUsernameError> + From<TPasswordError> + From<THostError>,
190 {
191 let username = match username {
192 Some(username) => Some(Username::try_from(username)?),
193 None => None,
194 };
195
196 let password = match password {
197 Some(password) => Some(Password::try_from(password)?),
198 None => None,
199 };
200
201 let host = Host::try_from(host)?;
202
203 Ok(Authority {
204 host,
205 password,
206 port,
207 username,
208 })
209 }
210
211 /// Returns whether there is a password in the authority as defined in
212 /// [[RFC3986, Section 3.2.1](https://tools.ietf.org/html/rfc3986#section-3.2.1)].
213 ///
214 /// There will only be a password if the URI has a user information component *and* the
215 /// component contains the `':'` delimiter.
216 ///
217 /// # Examples
218 ///
219 /// ```
220 /// use std::convert::TryFrom;
221 ///
222 /// use uriparse::Authority;
223 ///
224 /// let authority = Authority::try_from("username:password@example.com").unwrap();
225 /// assert!(authority.has_password());
226 /// ```
227 pub fn has_password(&self) -> bool {
228 self.password.is_some()
229 }
230
231 /// Returns whether there is a password in the authority as defined in
232 /// [[RFC3986, Section 3.2.1](https://tools.ietf.org/html/rfc3986#section-3.2.1)].
233 ///
234 /// # Examples
235 ///
236 /// ```
237 /// use std::convert::TryFrom;
238 ///
239 /// use uriparse::Authority;
240 ///
241 /// let authority = Authority::try_from("example.com:8080").unwrap();
242 /// assert!(authority.has_port());
243 /// ```
244 pub fn has_port(&self) -> bool {
245 self.port.is_some()
246 }
247
248 /// Returns whether there is a username in the authority as defined in
249 /// [[RFC3986, Section 3.2.1](https://tools.ietf.org/html/rfc3986#section-3.2.1)].
250 ///
251 /// There will *always* be a username as long as there is a `'@'` delimiter present in the
252 /// authority.
253 ///
254 /// # Examples
255 ///
256 /// ```
257 /// use std::convert::TryFrom;
258 ///
259 /// use uriparse::Authority;
260 ///
261 /// let authority = Authority::try_from("username@example.com").unwrap();
262 /// assert!(authority.has_username());
263 /// ```
264 pub fn has_username(&self) -> bool {
265 self.username.is_some()
266 }
267
268 /// The host component of the authority as defined in
269 /// [[RFC3986, Section 3.2.2](https://tools.ietf.org/html/rfc3986#section-3.2.2)].
270 ///
271 /// An authority component always has a host, though it may be an empty registered name.
272 ///
273 ///
274 /// # Examples
275 ///
276 /// ```
277 /// use std::convert::TryFrom;
278 ///
279 /// use uriparse::Authority;
280 ///
281 /// let authority = Authority::try_from("username:password@example.com").unwrap();
282 /// assert_eq!(authority.host().to_string().as_str(), "example.com");
283 /// ```
284 pub fn host(&self) -> &Host<'authority> {
285 &self.host
286 }
287
288 /// Converts the [`Authority`] into an owned copy.
289 ///
290 /// If you construct the authority from a source with a non-static lifetime, you may run into
291 /// lifetime problems due to the way the struct is designed. Calling this function will ensure
292 /// that the returned value has a static lifetime.
293 ///
294 /// This is different from just cloning. Cloning the authority will just copy the eferences, and
295 /// thus the lifetime will remain the same.
296 pub fn into_owned(self) -> Authority<'static> {
297 let password = self.password.map(Password::into_owned);
298 let username = self.username.map(Username::into_owned);
299 let host = match self.host {
300 Host::RegisteredName(name) => Host::RegisteredName(name.into_owned()),
301 Host::IPv4Address(ipv4) => Host::IPv4Address(ipv4),
302 Host::IPv6Address(ipv6) => Host::IPv6Address(ipv6),
303 };
304
305 Authority {
306 host,
307 port: self.port,
308 password,
309 username,
310 }
311 }
312
313 /// Consumes the [`Authority`] and returns its parts: username, password, host, and port.
314 ///
315 /// # Examples
316 ///
317 /// ```
318 /// use std::convert::TryFrom;
319 ///
320 /// use uriparse::Authority;
321 ///
322 /// let authority = Authority::try_from("username:password@example.com:80").unwrap();
323 /// let (username, password, host, port) = authority.into_parts();
324 ///
325 /// assert_eq!(username.unwrap(), "username");
326 /// assert_eq!(password.unwrap(), "password");
327 /// assert_eq!(host.to_string(), "example.com");
328 /// assert_eq!(port.unwrap(), 80);
329 /// ```
330 pub fn into_parts(
331 self,
332 ) -> (
333 Option<Username<'authority>>,
334 Option<Password<'authority>>,
335 Host<'authority>,
336 Option<u16>,
337 ) {
338 (self.username, self.password, self.host, self.port)
339 }
340
341 /// Returns whether the authority is normalized.
342 ///
343 /// A normalized authority will have all of its sub-components normalized.
344 ///
345 /// This function runs in constant-time.
346 ///
347 /// # Examples
348 ///
349 /// ```
350 /// use std::convert::TryFrom;
351 ///
352 /// use uriparse::Authority;
353 ///
354 /// let authority = Authority::try_from("username:password@example.com").unwrap();
355 /// assert!(authority.is_normalized());
356 ///
357 /// let mut authority = Authority::try_from("username:p%61ssword@EXAMPLE.COM").unwrap();
358 /// assert!(!authority.is_normalized());
359 /// authority.normalize();
360 /// assert!(authority.is_normalized());
361 /// ```
362 pub fn is_normalized(&self) -> bool {
363 if let Some(username) = self.username.as_ref() {
364 if !username.is_normalized() {
365 return false;
366 }
367 }
368
369 if let Some(password) = self.password.as_ref() {
370 if !password.is_normalized() {
371 return false;
372 }
373 }
374
375 self.host.is_normalized()
376 }
377
378 /// Maps the host using the given map function.
379 ///
380 /// # Examples
381 ///
382 /// ```
383 /// use std::convert::TryFrom;
384 ///
385 /// use uriparse::{Authority, Host};
386 ///
387 /// let mut authority = Authority::try_from("example.com").unwrap();
388 /// authority.map_host(|_| Host::try_from("127.0.0.1").unwrap());
389 /// assert_eq!(authority.to_string(), "127.0.0.1");
390 /// ```
391 pub fn map_host<TMapper>(&mut self, mapper: TMapper) -> &Host<'authority>
392 where
393 TMapper: FnOnce(Host<'authority>) -> Host<'authority>,
394 {
395 let temp_host = Host::RegisteredName(RegisteredName {
396 normalized: true,
397 registered_name: Cow::from(""),
398 });
399 let host = mapper(mem::replace(&mut self.host, temp_host));
400 self.set_host(host)
401 .expect("mapped host resulted in invalid state")
402 }
403
404 /// Maps the password using the given map function.
405 ///
406 /// # Examples
407 ///
408 /// ```
409 /// use std::convert::TryFrom;
410 ///
411 /// use uriparse::{Authority, Password};
412 ///
413 /// let mut authority = Authority::try_from("example.com").unwrap();
414 /// authority.map_password(|_| Some(Password::try_from("password").unwrap()));
415 /// assert_eq!(authority.to_string(), ":password@example.com");
416 /// ```
417 pub fn map_password<TMapper>(&mut self, mapper: TMapper) -> Option<&Password<'authority>>
418 where
419 TMapper: FnOnce(Option<Password<'authority>>) -> Option<Password<'authority>>,
420 {
421 let password = mapper(self.password.take());
422 self.set_password(password)
423 .expect("mapped password resulted in invalid state")
424 }
425
426 /// Maps the port using the given map function.
427 ///
428 /// # Examples
429 ///
430 /// ```
431 /// use std::convert::TryFrom;
432 ///
433 /// use uriparse::Authority;
434 ///
435 /// let mut authority = Authority::try_from("example.com").unwrap();
436 /// authority.map_port(|_| Some(8080));
437 /// assert_eq!(authority.to_string(), "example.com:8080");
438 /// ```
439 pub fn map_port<TMapper>(&mut self, mapper: TMapper) -> Option<u16>
440 where
441 TMapper: FnOnce(Option<u16>) -> Option<u16>,
442 {
443 let port = mapper(self.port);
444 self.set_port(port)
445 }
446
447 /// Maps the username using the given map function.
448 ///
449 /// # Examples
450 ///
451 /// ```
452 /// use std::convert::TryFrom;
453 ///
454 /// use uriparse::{Authority, Username};
455 ///
456 /// let mut authority = Authority::try_from("example.com").unwrap();
457 /// authority.map_username(|_| Some(Username::try_from("username").unwrap()));
458 /// assert_eq!(authority.to_string(), "username@example.com");
459 /// ```
460 pub fn map_username<TMapper>(&mut self, mapper: TMapper) -> Option<&Username<'authority>>
461 where
462 TMapper: FnOnce(Option<Username<'authority>>) -> Option<Username<'authority>>,
463 {
464 let username = mapper(self.username.take());
465 self.set_username(username)
466 .expect("mapped username resulted in invalid state")
467 }
468
469 /// Normalizes the authority.
470 ///
471 /// A normalized authority will have all of its sub-components normalized.
472 ///
473 /// # Examples
474 ///
475 /// ```
476 /// use std::convert::TryFrom;
477 ///
478 /// use uriparse::Authority;
479 ///
480 /// let mut authority = Authority::try_from("username:password@example.com").unwrap();
481 /// authority.normalize();
482 /// assert_eq!(authority.to_string(), "username:password@example.com");
483 ///
484 /// let mut authority = Authority::try_from("username:p%61ssword@EXAMPLE.COM").unwrap();
485 /// assert_eq!(authority.to_string(), "username:p%61ssword@EXAMPLE.COM");
486 /// authority.normalize();
487 /// assert_eq!(authority.to_string(), "username:password@example.com");
488 /// ```
489 pub fn normalize(&mut self) {
490 if let Some(username) = self.username.as_mut() {
491 username.normalize();
492 }
493
494 if let Some(password) = self.password.as_mut() {
495 password.normalize();
496 }
497
498 self.host.normalize();
499 }
500
501 /// The password component of the authority as defined in
502 /// [[RFC3986, Section 3.2.1](https://tools.ietf.org/html/rfc3986#section-3.2.1)].
503 ///
504 /// The password will be `None` if the user information component of the authority did not
505 /// contain a `':'`. Otherwise, it will be whatever is after the `':'` until the `'@'`
506 /// character. It may be empty as well.
507 ///
508 /// # Examples
509 ///
510 /// ```
511 /// use std::convert::TryFrom;
512 ///
513 /// use uriparse::Authority;
514 ///
515 /// let authority = Authority::try_from("username:password@example.com").unwrap();
516 /// assert_eq!(authority.password().unwrap(), "password");
517 /// ```
518 pub fn password(&self) -> Option<&Password<'authority>> {
519 self.password.as_ref()
520 }
521
522 /// The port component of the authority as defined in
523 /// [[RFC3986, Section 3.2.3]](https://tools.ietf.org/html/rfc3986#section-3.2.3).
524 ///
525 /// The port will be `None` if a port was not specified.
526 ///
527 /// # Examples
528 ///
529 /// ```
530 /// use std::convert::TryFrom;
531 ///
532 /// use uriparse::Authority;
533 ///
534 /// let authority = Authority::try_from("example.com:80").unwrap();
535 /// assert_eq!(authority.port().unwrap(), 80);
536 /// ```
537 pub fn port(&self) -> Option<u16> {
538 self.port
539 }
540
541 /// Sets the host of the authority.
542 ///
543 /// An error will be returned if the conversion to a [`Host`] fails.
544 ///
545 /// # Examples
546 ///
547 /// ```
548 /// use std::convert::TryFrom;
549 /// use std::net::Ipv6Addr;
550 ///
551 /// use uriparse::{Authority, Host};
552 ///
553 /// let mut authority = Authority::try_from("example.com:8080").unwrap();
554 /// authority.set_host("127.0.0.1");
555 /// assert_eq!(authority.to_string(), "127.0.0.1:8080");
556 /// authority.set_host(Host::IPv6Address("::1".parse().unwrap()));
557 /// assert_eq!(authority.to_string(), "[::1]:8080");
558 /// ```
559 pub fn set_host<THost, THostError>(
560 &mut self,
561 host: THost,
562 ) -> Result<&Host<'authority>, AuthorityError>
563 where
564 Host<'authority>: TryFrom<THost, Error = THostError>,
565 AuthorityError: From<THostError>,
566 {
567 self.host = Host::try_from(host)?;
568 Ok(self.host())
569 }
570
571 /// Sets the password of the authority.
572 ///
573 /// An error will be returned if the conversion to a [`Password`] fails.
574 ///
575 /// If the given password is not `None`, then the username will be set to `""` if it is
576 /// currently not set.
577 ///
578 /// # Examples
579 ///
580 /// ```
581 /// use std::convert::TryFrom;
582 ///
583 /// use uriparse::Authority;
584 ///
585 /// let mut authority = Authority::try_from("example.com").unwrap();
586 /// authority.set_password(Some("secret"));
587 /// assert_eq!(authority.to_string(), ":secret@example.com");
588 /// ```
589 pub fn set_password<TPassword, TPasswordError>(
590 &mut self,
591 password: Option<TPassword>,
592 ) -> Result<Option<&Password<'authority>>, AuthorityError>
593 where
594 Password<'authority>: TryFrom<TPassword, Error = TPasswordError>,
595 AuthorityError: From<TPasswordError>,
596 {
597 self.password = match password {
598 Some(password) => {
599 let password = Password::try_from(password)?;
600
601 if self.username.is_none() {
602 self.username = Some(Username {
603 normalized: true,
604 username: Cow::from(""),
605 });
606 }
607
608 Some(password)
609 }
610 None => None,
611 };
612 Ok(self.password())
613 }
614
615 /// Sets the port of the authority.
616 ///
617 /// # Examples
618 ///
619 /// ```
620 /// use std::convert::TryFrom;
621 ///
622 /// use uriparse::Authority;
623 ///
624 /// let mut authority = Authority::try_from("example.com").unwrap();
625 /// authority.set_port(Some(8080));
626 /// assert_eq!(authority.to_string(), "example.com:8080");
627 /// ```
628 pub fn set_port(&mut self, port: Option<u16>) -> Option<u16> {
629 self.port = port;
630 self.port
631 }
632
633 /// Sets the username of the authority.
634 ///
635 /// An error will be returned if the conversion to a [`Username`] fails.
636 ///
637 /// If the given username is `None`, this will also remove any set password.
638 ///
639 /// # Examples
640 ///
641 /// ```
642 /// use std::convert::TryFrom;
643 ///
644 /// use uriparse::{Authority, Username};
645 ///
646 /// let mut authority = Authority::try_from("example.com").unwrap();
647 /// authority.set_username(Some("myname"));
648 /// assert_eq!(authority.to_string(), "myname@example.com");
649 ///
650 /// let mut authority = Authority::try_from("user:pass@example.com").unwrap();
651 /// authority.set_username(None::<Username>);
652 /// assert_eq!(authority.to_string(), "example.com");
653 /// ```
654 pub fn set_username<TUsername, TUsernameError>(
655 &mut self,
656 username: Option<TUsername>,
657 ) -> Result<Option<&Username<'authority>>, AuthorityError>
658 where
659 Username<'authority>: TryFrom<TUsername, Error = TUsernameError>,
660 AuthorityError: From<TUsernameError>,
661 {
662 self.username = match username {
663 Some(username) => Some(Username::try_from(username)?),
664 None => {
665 self.password = None;
666 None
667 }
668 };
669 Ok(self.username())
670 }
671
672 /// The username component of the authority as defined in
673 /// [[RFC3986, Section 3.2.1](https://tools.ietf.org/html/rfc3986#section-3.2.1)].
674 ///
675 /// The username will be `None` if the user information component of the authority did not
676 /// contain a `':'`. Otherwise, it will be whatever is after the `':'` until the `'@'`
677 /// character. It may be empty as well.
678 ///
679 /// # Examples
680 ///
681 /// ```
682 /// use std::convert::TryFrom;
683 ///
684 /// use uriparse::Authority;
685 ///
686 /// let authority = Authority::try_from("username:password@example.com").unwrap();
687 /// assert_eq!(authority.password().unwrap(), "password");
688 /// ```
689 pub fn username(&self) -> Option<&Username<'authority>> {
690 self.username.as_ref()
691 }
692}
693
694impl Display for Authority<'_> {
695 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
696 if let Some(ref username) = self.username {
697 username.fmt(formatter)?;
698
699 if let Some(ref password) = self.password {
700 formatter.write_char(':')?;
701 password.fmt(formatter)?;
702 }
703
704 formatter.write_char('@')?;
705 }
706
707 self.host.fmt(formatter)?;
708
709 if let Some(port) = self.port {
710 formatter.write_char(':')?;
711 port.fmt(formatter)?;
712 }
713
714 Ok(())
715 }
716}
717
718impl<'authority> From<Authority<'authority>> for String {
719 fn from(value: Authority<'authority>) -> String {
720 value.to_string()
721 }
722}
723
724impl<'authority> TryFrom<&'authority [u8]> for Authority<'authority> {
725 type Error = AuthorityError;
726
727 fn try_from(value: &'authority [u8]) -> Result<Self, Self::Error> {
728 let (authority, rest) = parse_authority(value)?;
729
730 if rest.is_empty() {
731 Ok(authority)
732 } else if authority.has_port() {
733 Err(AuthorityError::Port(PortError::InvalidCharacter))
734 } else if authority.host().is_ipv6_address() {
735 Err(AuthorityError::Host(HostError::InvalidIPv6Character))
736 } else {
737 Err(AuthorityError::Host(
738 HostError::InvalidIPv4OrRegisteredNameCharacter,
739 ))
740 }
741 }
742}
743
744impl<'authority> TryFrom<&'authority str> for Authority<'authority> {
745 type Error = AuthorityError;
746
747 fn try_from(value: &'authority str) -> Result<Self, Self::Error> {
748 Authority::try_from(value.as_bytes())
749 }
750}
751
752/// The host component of the authority as defined in
753/// [[RFC3986, Section 3.2.2](https://tools.ietf.org/html/rfc3986#section-3.2.2)].
754///
755/// The RFC mentions support for future IP address literals. Of course, as of this moment there
756/// exist none, so hosts of the form `"[v*...]"` where `'*'` is a hexadecimal digit and `'...'` is
757/// the actual IP literal are not considered valid.
758///
759/// Also, the host is case-insensitive meaning that `"example.com"` and `"ExAmPlE.CoM"` refer to the
760/// same host. Furthermore, percent-encoding plays no role in equality checking for characters in
761/// the unreserved character set meaning that `"example.com"` and `"ex%61mple.com"` are identical.
762/// Both of these attributes are reflected in the equality and hash functions.
763///
764/// However, be aware that just because percent-encoding plays no role in equality checking does not
765/// mean that the host is normalized. If the host needs to be normalized, use the
766/// [`Host::normalize`] function.
767#[derive(Clone, Debug, Eq, Hash, PartialEq)]
768#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
769pub enum Host<'host> {
770 /// An IPv4 address. Based on the `std`'s implementation, leading zeros for octets are allowed
771 /// for up to three digits. So for example, `"000.000.000.000"` is still considered a valid IPv4
772 /// address, but `"000.000.000.0000"` is not. Thus, it would be considered a registered name.
773 IPv4Address(Ipv4Addr),
774
775 /// An IPv6 address. This will always be encased in brackets (`'['` and `']'`).
776 IPv6Address(Ipv6Addr),
777
778 /// Any other host that does not follow the syntax of an IP address. This includes even hosts of
779 /// the form `"999.999.999.999"`. One might expect this to produce an invalid IPv4 error, but
780 /// the RFC states that it is a "first-match-wins" algorithm, and that host does not match the
781 /// IPv4 literal syntax.
782 ///
783 /// This may be changed in the future, since arguments can be made from either side.
784 RegisteredName(RegisteredName<'host>),
785}
786
787impl Host<'_> {
788 /// Returns a new host which is identical but has a lifetime tied to this host.
789 pub fn as_borrowed(&self) -> Host {
790 use self::Host::*;
791
792 match self {
793 IPv4Address(ipv4) => IPv4Address(*ipv4),
794 IPv6Address(ipv6) => IPv6Address(*ipv6),
795 RegisteredName(name) => RegisteredName(name.as_borrowed()),
796 }
797 }
798
799 /// Converts the [`Host`] into an owned copy.
800 ///
801 /// If you construct the host from a source with a non-static lifetime, you may run into
802 /// lifetime problems due to the way the struct is designed. Calling this function will ensure
803 /// that the returned value has a static lifetime.
804 ///
805 /// This is different from just cloning. Cloning the host will just copy the references, and
806 /// thus the lifetime will remain the same.
807 pub fn into_owned(self) -> Host<'static> {
808 use self::Host::*;
809
810 match self {
811 IPv4Address(ipv4) => IPv4Address(ipv4),
812 IPv6Address(ipv6) => IPv6Address(ipv6),
813 RegisteredName(name) => RegisteredName(name.into_owned()),
814 }
815 }
816
817 /// Returns whether the host is an IPv4 address.
818 ///
819 /// # Examples
820 ///
821 /// ```
822 /// use std::convert::TryFrom;
823 ///
824 /// use uriparse::Host;
825 ///
826 /// let host = Host::try_from("192.168.1.1").unwrap();
827 /// assert!(host.is_ipv4_address());
828 /// ```
829 pub fn is_ipv4_address(&self) -> bool {
830 match self {
831 Host::IPv4Address(_) => true,
832 _ => false,
833 }
834 }
835
836 /// Returns whether the host is an IPv6 address.
837 ///
838 /// # Examples
839 ///
840 /// ```
841 /// use std::convert::TryFrom;
842 ///
843 /// use uriparse::Host;
844 ///
845 /// let host = Host::try_from("[::1]").unwrap();
846 /// assert!(host.is_ipv6_address());
847 /// ```
848 pub fn is_ipv6_address(&self) -> bool {
849 match self {
850 Host::IPv6Address(_) => true,
851 _ => false,
852 }
853 }
854
855 /// Returns whether the host is normalized.
856 ///
857 /// IPv4 and IPv6 hosts will always be normalized. Registered names are considered normalized
858 /// if all characters are lowercase, no bytes that are in the unreserved character set are
859 /// percent-encoded, and all alphabetical characters in percent-encodings are uppercase.
860 ///
861 /// This function runs in constant-time.
862 ///
863 /// # Examples
864 ///
865 /// ```
866 /// use std::convert::TryFrom;
867 ///
868 /// use uriparse::Host;
869 ///
870 /// let host = Host::try_from("192.168.1.1").unwrap();
871 /// assert!(host.is_normalized());
872 ///
873 /// let mut host = Host::try_from("EXAMPLE.COM").unwrap();
874 /// assert!(!host.is_normalized());
875 /// host.normalize();
876 /// assert!(host.is_normalized());
877 /// ```
878 pub fn is_normalized(&self) -> bool {
879 match self {
880 Host::RegisteredName(name) => name.is_normalized(),
881 _ => true,
882 }
883 }
884
885 /// Returns whether the host is a registered name.
886 ///
887 /// # Examples
888 ///
889 /// ```
890 /// use std::convert::TryFrom;
891 ///
892 /// use uriparse::Host;
893 ///
894 /// let host = Host::try_from("example.com").unwrap();
895 /// assert!(host.is_registered_name());
896 /// ```
897 pub fn is_registered_name(&self) -> bool {
898 match self {
899 Host::RegisteredName(_) => true,
900 _ => false,
901 }
902 }
903
904 /// Normalizes the host such that all characters are lowercase, no bytes that are in the
905 /// unreserved character set are percent-encoded, and all alphabetical characters in
906 /// percent-encodings are uppercase.
907 ///
908 /// If the host is already normalized, the function will return immediately. Otherwise, if
909 /// the host is not owned, this function will perform an allocation to clone it. The
910 /// normalization itself though, is done in-place with no extra memory allocations required.
911 ///
912 /// IPv4 and IPv6 hosts are always considered normalized.
913 ///
914 /// # Examples
915 ///
916 /// ```
917 /// use std::convert::TryFrom;
918 ///
919 /// use uriparse::Host;
920 ///
921 /// let mut host = Host::try_from("192.168.1.1").unwrap();
922 /// host.normalize();
923 /// assert_eq!(host.to_string(), "192.168.1.1");
924 ///
925 /// let mut host = Host::try_from("%ff%41").unwrap();
926 /// assert_eq!(host.to_string(), "%ff%41");
927 /// host.normalize();
928 /// assert_eq!(host.to_string(), "%FFA");
929 /// ```
930 pub fn normalize(&mut self) {
931 if let Host::RegisteredName(name) = self {
932 name.normalize()
933 }
934 }
935}
936
937impl Display for Host<'_> {
938 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
939 use self::Host::*;
940
941 match self {
942 IPv4Address(address) => address.fmt(formatter),
943 IPv6Address(address) => {
944 formatter.write_char('[')?;
945 address.fmt(formatter)?;
946 formatter.write_char(']')
947 }
948 RegisteredName(name) => formatter.write_str(name.as_str()),
949 }
950 }
951}
952
953impl<'host> From<Host<'host>> for String {
954 fn from(value: Host<'host>) -> String {
955 value.to_string()
956 }
957}
958
959impl From<IpAddr> for Host<'static> {
960 fn from(value: IpAddr) -> Self {
961 match value {
962 IpAddr::V4(address) => Host::IPv4Address(address),
963 IpAddr::V6(address) => Host::IPv6Address(address),
964 }
965 }
966}
967
968impl From<Ipv4Addr> for Host<'static> {
969 fn from(value: Ipv4Addr) -> Self {
970 Host::IPv4Address(value)
971 }
972}
973
974impl From<Ipv6Addr> for Host<'static> {
975 fn from(value: Ipv6Addr) -> Self {
976 Host::IPv6Address(value)
977 }
978}
979
980impl<'host> TryFrom<&'host [u8]> for Host<'host> {
981 type Error = HostError;
982
983 fn try_from(value: &'host [u8]) -> Result<Self, Self::Error> {
984 if value.is_empty() {
985 let registered_name = RegisteredName {
986 normalized: true,
987 registered_name: Cow::from(""),
988 };
989 return Ok(Host::RegisteredName(registered_name));
990 }
991
992 match (value.get(0), value.get(value.len() - 1)) {
993 (Some(b'['), Some(b']')) => {
994 match value.get(1..3) {
995 Some(&[prefix, version])
996 if prefix.to_ascii_lowercase() == b'v' && version.is_ascii_hexdigit() =>
997 {
998 // IPvFuture
999
1000 let ipvfuture = &value[3..value.len() - 1];
1001
1002 if check_ipvfuture(ipvfuture) {
1003 return Err(HostError::AddressMechanismNotSupported);
1004 } else {
1005 return Err(HostError::InvalidIPvFutureCharacter);
1006 }
1007 }
1008 _ => (),
1009 }
1010
1011 // IPv6
1012
1013 let ipv6 = &value[1..value.len() - 1];
1014
1015 if !check_ipv6(ipv6) {
1016 return Err(HostError::InvalidIPv6Character);
1017 }
1018
1019 // Unsafe: The function above [`check_ipv6`] ensures this is valid ASCII-US.
1020 let ipv6: Ipv6Addr = unsafe { str::from_utf8_unchecked(ipv6) }
1021 .parse()
1022 .map_err(|_| HostError::InvalidIPv6Format)?;
1023 Ok(Host::IPv6Address(ipv6))
1024 }
1025 _ => {
1026 let (valid, normalized) = check_ipv4_or_registered_name(value);
1027
1028 if valid {
1029 // Unsafe: The function above [`check_ipv4_or_registered_name`] ensures
1030 // this is valid ASCII-US.
1031 let value_string = unsafe { str::from_utf8_unchecked(value) };
1032
1033 match value_string.parse() {
1034 Ok(ipv4) => Ok(Host::IPv4Address(ipv4)),
1035 Err(_) => Ok(Host::RegisteredName(RegisteredName {
1036 normalized,
1037 registered_name: Cow::from(value_string),
1038 })),
1039 }
1040 } else {
1041 Err(HostError::InvalidIPv4OrRegisteredNameCharacter)
1042 }
1043 }
1044 }
1045 }
1046}
1047
1048impl<'host> TryFrom<&'host str> for Host<'host> {
1049 type Error = HostError;
1050
1051 fn try_from(value: &'host str) -> Result<Self, Self::Error> {
1052 Host::try_from(value.as_bytes())
1053 }
1054}
1055
1056/// The password component of the authority as defined in
1057/// [[RFC3986, Section 3.2.1](https://tools.ietf.org/html/rfc3986#section-3.2.1)].
1058///
1059/// Even though this library supports parsing the password from the user information, it should be
1060/// noted that the format "username:password" is deprecated. Also, be careful logging this!
1061///
1062/// The password is case-sensitive. Furthermore, percent-encoding plays no role in equality checking
1063/// for characters in the unreserved character set meaning that `"password"` and `"p%61ssword"` are
1064/// identical. Both of these attributes are reflected in the equality and hash functions.
1065///
1066/// Be aware that just because percent-encoding plays no role in equality checking does not
1067/// mean that the password is normalized. If the password needs to be normalized, use the
1068/// [`Password::normalize`] function.
1069#[derive(Clone, Debug)]
1070#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1071pub struct Password<'password> {
1072 /// Whether the password is normalized.
1073 normalized: bool,
1074
1075 /// The internal password source that is either owned or borrowed.
1076 password: Cow<'password, str>,
1077}
1078
1079impl Password<'_> {
1080 /// Returns a new password which is identical but has a lifetime tied to this password.
1081 pub fn as_borrowed(&self) -> Password {
1082 use self::Cow::*;
1083
1084 let password = match &self.password {
1085 Borrowed(borrowed) => *borrowed,
1086 Owned(owned) => owned.as_str(),
1087 };
1088
1089 Password {
1090 normalized: self.normalized,
1091 password: Cow::Borrowed(password),
1092 }
1093 }
1094
1095 /// Returns a `str` representation of the password.
1096 ///
1097 /// # Examples
1098 ///
1099 /// ```
1100 /// use std::convert::TryFrom;
1101 ///
1102 /// use uriparse::Password;
1103 ///
1104 /// let password = Password::try_from("password").unwrap();
1105 /// assert_eq!(password, "password");
1106 /// ```
1107 pub fn as_str(&self) -> &str {
1108 &self.password
1109 }
1110
1111 /// Converts the [`Password`] into an owned copy.
1112 ///
1113 /// If you construct the authority from a source with a non-static lifetime, you may run into
1114 /// lifetime problems due to the way the struct is designed. Calling this function will ensure
1115 /// that the returned value has a static lifetime.
1116 ///
1117 /// This is different from just cloning. Cloning the password will just copy the references, and
1118 /// thus the lifetime will remain the same.
1119 pub fn into_owned(self) -> Password<'static> {
1120 Password {
1121 normalized: self.normalized,
1122 password: Cow::from(self.password.into_owned()),
1123 }
1124 }
1125
1126 /// Returns whether the password is normalized.
1127 ///
1128 /// A normalized password will have no bytes that are in the unreserved character set
1129 /// percent-encoded and all alphabetical characters in percent-encodings will be uppercase.
1130 ///
1131 /// This function runs in constant-time.
1132 ///
1133 /// # Examples
1134 ///
1135 /// ```
1136 /// use std::convert::TryFrom;
1137 ///
1138 /// use uriparse::Password;
1139 ///
1140 /// let password = Password::try_from("password").unwrap();
1141 /// assert!(password.is_normalized());
1142 ///
1143 /// let mut password = Password::try_from("%ff%ff").unwrap();
1144 /// assert!(!password.is_normalized());
1145 /// password.normalize();
1146 /// assert!(password.is_normalized());
1147 /// ```
1148 pub fn is_normalized(&self) -> bool {
1149 self.normalized
1150 }
1151
1152 /// Normalizes the password such that it will have no bytes that are in the unreserved character
1153 /// set percent-encoded and all alphabetical characters in percent-encodings will be uppercase.
1154 ///
1155 /// If the password is already normalized, the function will return immediately. Otherwise, if
1156 /// the password is not owned, this function will perform an allocation to clone it. The
1157 /// normalization itself though, is done in-place with no extra memory allocations required.
1158 ///
1159 /// # Examples
1160 ///
1161 /// ```
1162 /// use std::convert::TryFrom;
1163 ///
1164 /// use uriparse::Password;
1165 ///
1166 /// let mut password = Password::try_from("password").unwrap();
1167 /// password.normalize();
1168 /// assert_eq!(password, "password");
1169 ///
1170 /// let mut password = Password::try_from("%ff%41").unwrap();
1171 /// assert_eq!(password, "%ff%41");
1172 /// password.normalize();
1173 /// assert_eq!(password, "%FFA");
1174 /// ```
1175 pub fn normalize(&mut self) {
1176 if !self.normalized {
1177 // Unsafe: Passwords must be valid ASCII-US, so this is safe.
1178 unsafe { normalize_string(&mut self.password.to_mut(), true) };
1179 self.normalized = true;
1180 }
1181 }
1182}
1183
1184impl AsRef<[u8]> for Password<'_> {
1185 fn as_ref(&self) -> &[u8] {
1186 self.password.as_bytes()
1187 }
1188}
1189
1190impl AsRef<str> for Password<'_> {
1191 fn as_ref(&self) -> &str {
1192 &self.password
1193 }
1194}
1195
1196impl Deref for Password<'_> {
1197 type Target = str;
1198
1199 fn deref(&self) -> &Self::Target {
1200 &self.password
1201 }
1202}
1203
1204impl Display for Password<'_> {
1205 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1206 formatter.write_str(&self.password)
1207 }
1208}
1209
1210impl Eq for Password<'_> {}
1211
1212impl<'password> From<Password<'password>> for String {
1213 fn from(value: Password<'password>) -> String {
1214 value.to_string()
1215 }
1216}
1217
1218impl Hash for Password<'_> {
1219 fn hash<H>(&self, state: &mut H)
1220 where
1221 H: Hasher,
1222 {
1223 percent_encoded_hash(self.password.as_bytes(), state, true);
1224 }
1225}
1226
1227impl PartialEq for Password<'_> {
1228 fn eq(&self, other: &Password) -> bool {
1229 *self == *other.as_bytes()
1230 }
1231}
1232
1233impl PartialEq<[u8]> for Password<'_> {
1234 fn eq(&self, other: &[u8]) -> bool {
1235 percent_encoded_equality(self.password.as_bytes(), other, true)
1236 }
1237}
1238
1239impl<'password> PartialEq<Password<'password>> for [u8] {
1240 fn eq(&self, other: &Password<'password>) -> bool {
1241 other == self
1242 }
1243}
1244
1245impl<'a> PartialEq<&'a [u8]> for Password<'_> {
1246 fn eq(&self, other: &&'a [u8]) -> bool {
1247 self == *other
1248 }
1249}
1250
1251impl<'a, 'password> PartialEq<Password<'password>> for &'a [u8] {
1252 fn eq(&self, other: &Password<'password>) -> bool {
1253 other == *self
1254 }
1255}
1256
1257impl PartialEq<str> for Password<'_> {
1258 fn eq(&self, other: &str) -> bool {
1259 self == other.as_bytes()
1260 }
1261}
1262
1263impl<'password> PartialEq<Password<'password>> for str {
1264 fn eq(&self, other: &Password<'password>) -> bool {
1265 other == self.as_bytes()
1266 }
1267}
1268
1269impl<'a> PartialEq<&'a str> for Password<'_> {
1270 fn eq(&self, other: &&'a str) -> bool {
1271 self == other.as_bytes()
1272 }
1273}
1274
1275impl<'a, 'password> PartialEq<Password<'password>> for &'a str {
1276 fn eq(&self, other: &Password<'password>) -> bool {
1277 other == self.as_bytes()
1278 }
1279}
1280
1281impl<'password> TryFrom<&'password [u8]> for Password<'password> {
1282 type Error = PasswordError;
1283
1284 fn try_from(value: &'password [u8]) -> Result<Self, Self::Error> {
1285 let normalized = check_user_info(value, false)?;
1286
1287 // Unsafe: The function above [`check_user_info`] ensures this is valid ASCII-US.
1288 Ok(Password {
1289 normalized,
1290 password: Cow::from(unsafe { str::from_utf8_unchecked(value) }),
1291 })
1292 }
1293}
1294
1295impl<'password> TryFrom<&'password str> for Password<'password> {
1296 type Error = PasswordError;
1297
1298 fn try_from(value: &'password str) -> Result<Self, Self::Error> {
1299 Password::try_from(value.as_bytes())
1300 }
1301}
1302
1303/// A host that is a registered name (i.e. not an IP literal).
1304///
1305/// The registered name is case-insensitive meaning that `"example.com"` and `"ExAmPlE.CoM"` refer
1306/// to the same registered name. Furthermore, percent-encoding plays no role in equality checking
1307/// for characters in the unreserved character set meaning that `"example.com"` and
1308/// `"ex%61mple.com"` are identical. Both of these attributes are reflected in the equality and hash
1309/// functions.
1310///
1311/// However, be aware that just because percent-encoding plays no role in equality checking does not
1312/// mean that the host is normalized. If the registered name needs to be normalized, use the
1313/// [`RegisteredName::normalize`] function.
1314#[derive(Clone, Debug)]
1315#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1316pub struct RegisteredName<'name> {
1317 /// Whether the registered name is normalized.
1318 normalized: bool,
1319
1320 /// The internal registered name source that is either owned or borrowed.
1321 registered_name: Cow<'name, str>,
1322}
1323
1324impl RegisteredName<'_> {
1325 /// Returns a new registered name which is identical but has a lifetime tied to this registered
1326 /// name.
1327 pub fn as_borrowed(&self) -> RegisteredName {
1328 use self::Cow::*;
1329
1330 let name = match &self.registered_name {
1331 Borrowed(borrowed) => *borrowed,
1332 Owned(owned) => owned.as_str(),
1333 };
1334
1335 RegisteredName {
1336 normalized: self.normalized,
1337 registered_name: Cow::Borrowed(name),
1338 }
1339 }
1340
1341 /// Returns a `str` representation of the registered name.
1342 ///
1343 /// # Examples
1344 ///
1345 /// ```
1346 /// use std::convert::TryFrom;
1347 ///
1348 /// use uriparse::RegisteredName;
1349 ///
1350 /// let name = RegisteredName::try_from("example.com").unwrap();
1351 /// assert_eq!(name.as_str(), "example.com");
1352 /// ```
1353 pub fn as_str(&self) -> &str {
1354 &self.registered_name
1355 }
1356
1357 /// Converts the [`RegisteredName`] into an owned copy.
1358 ///
1359 /// If you construct the registered name from a source with a non-static lifetime, you may run
1360 /// into lifetime problems due to the way the struct is designed. Calling this function will
1361 /// ensure that the returned value has a static lifetime.
1362 ///
1363 /// This is different from just cloning. Cloning the registered name will just copy the
1364 /// references, and thus the lifetime will remain the same.
1365 pub fn into_owned(self) -> RegisteredName<'static> {
1366 RegisteredName {
1367 normalized: self.normalized,
1368 registered_name: Cow::from(self.registered_name.into_owned()),
1369 }
1370 }
1371
1372 /// Returns whether the registered name is normalized.
1373 ///
1374 /// Registered names are considered normalized if all characters are lowercase, no bytes that
1375 /// are in the unreserved character set are percent-encoded, and all alphabetical characters in
1376 /// percent-encodings are uppercase.
1377 ///
1378 /// This function runs in constant-time.
1379 ///
1380 /// # Examples
1381 ///
1382 /// ```
1383 /// use std::convert::TryFrom;
1384 ///
1385 /// use uriparse::RegisteredName;
1386 ///
1387 /// let name = RegisteredName::try_from("example.com").unwrap();
1388 /// assert!(name.is_normalized());
1389 ///
1390 /// let mut name = RegisteredName::try_from("EXAMPLE.COM").unwrap();
1391 /// assert!(!name.is_normalized());
1392 /// name.normalize();
1393 /// assert!(name.is_normalized());
1394 /// ```
1395 pub fn is_normalized(&self) -> bool {
1396 self.normalized
1397 }
1398
1399 /// Normalizes the registered name such that all characters are lowercase, no bytes that are in
1400 /// the unreserved character set are percent-encoded, and all alphabetical characters in
1401 /// percent-encodings are uppercase.
1402 ///
1403 /// If the registered name is already normalized, the function will return immediately.
1404 /// Otherwise, if the registered name is not owned, this function will perform an allocation to
1405 /// clone it. The normalization itself though, is done in-place with no extra memory allocations
1406 /// required.
1407 ///
1408 /// # Examples
1409 ///
1410 /// ```
1411 /// use std::convert::TryFrom;
1412 ///
1413 /// use uriparse::RegisteredName;
1414 ///
1415 /// let mut name = RegisteredName::try_from("example.com").unwrap();
1416 /// name.normalize();
1417 /// assert_eq!(name.to_string(), "example.com");
1418 ///
1419 /// let mut name = RegisteredName::try_from("%ff%41").unwrap();
1420 /// assert_eq!(name.to_string(), "%ff%41");
1421 /// name.normalize();
1422 /// assert_eq!(name.to_string(), "%FFA");
1423 /// ```
1424 pub fn normalize(&mut self) {
1425 if !self.normalized {
1426 // Unsafe: Registered names must be valid ASCII-US, so this is safe.
1427 unsafe { normalize_string(&mut self.registered_name.to_mut(), false) };
1428 self.normalized = true;
1429 }
1430 }
1431}
1432
1433impl AsRef<[u8]> for RegisteredName<'_> {
1434 fn as_ref(&self) -> &[u8] {
1435 self.registered_name.as_bytes()
1436 }
1437}
1438
1439impl AsRef<str> for RegisteredName<'_> {
1440 fn as_ref(&self) -> &str {
1441 &self.registered_name
1442 }
1443}
1444
1445impl Deref for RegisteredName<'_> {
1446 type Target = str;
1447
1448 fn deref(&self) -> &Self::Target {
1449 &self.registered_name
1450 }
1451}
1452
1453impl Display for RegisteredName<'_> {
1454 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1455 formatter.write_str(&self.registered_name)
1456 }
1457}
1458
1459impl Eq for RegisteredName<'_> {}
1460
1461impl<'name> From<RegisteredName<'name>> for String {
1462 fn from(value: RegisteredName<'name>) -> String {
1463 value.to_string()
1464 }
1465}
1466
1467impl Hash for RegisteredName<'_> {
1468 fn hash<H>(&self, state: &mut H)
1469 where
1470 H: Hasher,
1471 {
1472 percent_encoded_hash(self.registered_name.as_bytes(), state, false);
1473 }
1474}
1475
1476impl PartialEq for RegisteredName<'_> {
1477 fn eq(&self, other: &RegisteredName) -> bool {
1478 *self == *other.as_bytes()
1479 }
1480}
1481
1482impl PartialEq<[u8]> for RegisteredName<'_> {
1483 fn eq(&self, other: &[u8]) -> bool {
1484 percent_encoded_equality(self.registered_name.as_bytes(), other, false)
1485 }
1486}
1487
1488impl<'name> PartialEq<RegisteredName<'name>> for [u8] {
1489 fn eq(&self, other: &RegisteredName<'name>) -> bool {
1490 other == self
1491 }
1492}
1493
1494impl<'a> PartialEq<&'a [u8]> for RegisteredName<'_> {
1495 fn eq(&self, other: &&'a [u8]) -> bool {
1496 self == *other
1497 }
1498}
1499
1500impl<'a, 'name> PartialEq<RegisteredName<'name>> for &'a [u8] {
1501 fn eq(&self, other: &RegisteredName<'name>) -> bool {
1502 other == *self
1503 }
1504}
1505
1506impl PartialEq<str> for RegisteredName<'_> {
1507 fn eq(&self, other: &str) -> bool {
1508 self == other.as_bytes()
1509 }
1510}
1511
1512impl<'name> PartialEq<RegisteredName<'name>> for str {
1513 fn eq(&self, other: &RegisteredName<'name>) -> bool {
1514 other == self.as_bytes()
1515 }
1516}
1517
1518impl<'a> PartialEq<&'a str> for RegisteredName<'_> {
1519 fn eq(&self, other: &&'a str) -> bool {
1520 self == other.as_bytes()
1521 }
1522}
1523
1524impl<'a, 'name> PartialEq<RegisteredName<'name>> for &'a str {
1525 fn eq(&self, other: &RegisteredName<'name>) -> bool {
1526 other == self.as_bytes()
1527 }
1528}
1529
1530impl<'name> TryFrom<&'name [u8]> for RegisteredName<'name> {
1531 type Error = RegisteredNameError;
1532
1533 fn try_from(value: &'name [u8]) -> Result<Self, Self::Error> {
1534 match Host::try_from(value) {
1535 Ok(Host::RegisteredName(name)) => Ok(name),
1536 _ => Err(RegisteredNameError),
1537 }
1538 }
1539}
1540
1541impl<'name> TryFrom<&'name str> for RegisteredName<'name> {
1542 type Error = RegisteredNameError;
1543
1544 fn try_from(value: &'name str) -> Result<Self, Self::Error> {
1545 RegisteredName::try_from(value.as_bytes())
1546 }
1547}
1548
1549/// The username component of the authority as defined in
1550/// [[RFC3986, Section 3.2.1](https://tools.ietf.org/html/rfc3986#section-3.2.1)].
1551///
1552/// The username is case-sensitive. Furthermore, percent-encoding plays no role in equality checking
1553/// for characters in the unreserved character set meaning that `"username"` and `"usern%61me"` are
1554/// identical. Both of these attributes are reflected in the equality and hash functions.
1555///
1556/// Be aware that just because percent-encoding plays no role in equality checking does not
1557/// mean that the username is normalized. If the username needs to be normalized, use the
1558/// [`Username::normalize`] function.
1559#[derive(Clone, Debug)]
1560#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1561pub struct Username<'username> {
1562 /// Whether the username is normalized.
1563 normalized: bool,
1564
1565 /// The internal username source that is either owned or borrowed.
1566 username: Cow<'username, str>,
1567}
1568
1569impl Username<'_> {
1570 /// Returns a new username which is identical but has a lifetime tied to this username.
1571 pub fn as_borrowed(&self) -> Username {
1572 use self::Cow::*;
1573
1574 let username = match &self.username {
1575 Borrowed(borrowed) => *borrowed,
1576 Owned(owned) => owned.as_str(),
1577 };
1578
1579 Username {
1580 normalized: self.normalized,
1581 username: Cow::Borrowed(username),
1582 }
1583 }
1584
1585 /// Returns a `str` representation of the username.
1586 ///
1587 /// # Examples
1588 ///
1589 /// ```
1590 /// use std::convert::TryFrom;
1591 ///
1592 /// use uriparse::Username;
1593 ///
1594 /// let username = Username::try_from("username").unwrap();
1595 /// assert_eq!(username.as_str(), "username");
1596 /// ```
1597 pub fn as_str(&self) -> &str {
1598 &self.username
1599 }
1600
1601 /// Converts the [`Username`] into an owned copy.
1602 ///
1603 /// If you construct the username from a source with a non-static lifetime, you may run into
1604 /// lifetime problems due to the way the struct is designed. Calling this function will ensure
1605 /// that the returned value has a static lifetime.
1606 ///
1607 /// This is different from just cloning. Cloning the username will just copy the references, and
1608 /// thus the lifetime will remain the same.
1609 pub fn into_owned(self) -> Username<'static> {
1610 Username {
1611 normalized: self.normalized,
1612 username: Cow::from(self.username.into_owned()),
1613 }
1614 }
1615
1616 /// Returns whether the username is normalized.
1617 ///
1618 /// A normalized username will have no bytes that are in the unreserved character set
1619 /// percent-encoded and all alphabetical characters in percent-encodings will be uppercase.
1620 ///
1621 /// This function runs in constant-time.
1622 ///
1623 /// # Examples
1624 ///
1625 /// ```
1626 /// use std::convert::TryFrom;
1627 ///
1628 /// use uriparse::Username;
1629 ///
1630 /// let username = Username::try_from("username").unwrap();
1631 /// assert!(username.is_normalized());
1632 ///
1633 /// let mut username = Username::try_from("%ff%ff").unwrap();
1634 /// assert!(!username.is_normalized());
1635 /// username.normalize();
1636 /// assert!(username.is_normalized());
1637 /// ```
1638 pub fn is_normalized(&self) -> bool {
1639 self.normalized
1640 }
1641
1642 /// Normalizes the username such that it will have no bytes that are in the unreserved character
1643 /// set percent-encoded and all alphabetical characters in percent-encodings will be uppercase.
1644 ///
1645 /// If the username is already normalized, the function will return immediately. Otherwise, if
1646 /// the username is not owned, this function will perform an allocation to clone it. The
1647 /// normalization itself though, is done in-place with no extra memory allocations required.
1648 ///
1649 /// # Examples
1650 ///
1651 /// ```
1652 /// use std::convert::TryFrom;
1653 ///
1654 /// use uriparse::Username;
1655 ///
1656 /// let mut username = Username::try_from("username").unwrap();
1657 /// username.normalize();
1658 /// assert_eq!(username, "username");
1659 ///
1660 /// let mut username = Username::try_from("%ff%41").unwrap();
1661 /// assert_eq!(username, "%ff%41");
1662 /// username.normalize();
1663 /// assert_eq!(username, "%FFA");
1664 /// ```
1665 pub fn normalize(&mut self) {
1666 if !self.normalized {
1667 // Unsafe: Usernames must be valid ASCII-US, so this is safe.
1668 unsafe { normalize_string(&mut self.username.to_mut(), true) };
1669 self.normalized = true;
1670 }
1671 }
1672}
1673
1674impl AsRef<[u8]> for Username<'_> {
1675 fn as_ref(&self) -> &[u8] {
1676 self.username.as_bytes()
1677 }
1678}
1679
1680impl AsRef<str> for Username<'_> {
1681 fn as_ref(&self) -> &str {
1682 &self.username
1683 }
1684}
1685
1686impl Deref for Username<'_> {
1687 type Target = str;
1688
1689 fn deref(&self) -> &Self::Target {
1690 &self.username
1691 }
1692}
1693
1694impl Display for Username<'_> {
1695 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1696 formatter.write_str(&self.username)
1697 }
1698}
1699
1700impl<'username> Eq for Username<'username> {}
1701
1702impl<'username> From<Username<'username>> for String {
1703 fn from(value: Username<'username>) -> String {
1704 value.to_string()
1705 }
1706}
1707
1708impl Hash for Username<'_> {
1709 fn hash<H>(&self, state: &mut H)
1710 where
1711 H: Hasher,
1712 {
1713 percent_encoded_hash(self.username.as_bytes(), state, true);
1714 }
1715}
1716
1717impl PartialEq for Username<'_> {
1718 fn eq(&self, other: &Username) -> bool {
1719 *self == *other.as_bytes()
1720 }
1721}
1722
1723impl PartialEq<[u8]> for Username<'_> {
1724 fn eq(&self, other: &[u8]) -> bool {
1725 percent_encoded_equality(self.username.as_bytes(), other, true)
1726 }
1727}
1728
1729impl<'username> PartialEq<Username<'username>> for [u8] {
1730 fn eq(&self, other: &Username<'username>) -> bool {
1731 other == self
1732 }
1733}
1734
1735impl<'a> PartialEq<&'a [u8]> for Username<'_> {
1736 fn eq(&self, other: &&'a [u8]) -> bool {
1737 self == *other
1738 }
1739}
1740
1741impl<'a, 'username> PartialEq<Username<'username>> for &'a [u8] {
1742 fn eq(&self, other: &Username<'username>) -> bool {
1743 other == *self
1744 }
1745}
1746
1747impl PartialEq<str> for Username<'_> {
1748 fn eq(&self, other: &str) -> bool {
1749 self == other.as_bytes()
1750 }
1751}
1752
1753impl<'username> PartialEq<Username<'username>> for str {
1754 fn eq(&self, other: &Username<'username>) -> bool {
1755 other == self.as_bytes()
1756 }
1757}
1758
1759impl<'a> PartialEq<&'a str> for Username<'_> {
1760 fn eq(&self, other: &&'a str) -> bool {
1761 self == other.as_bytes()
1762 }
1763}
1764
1765impl<'a, 'username> PartialEq<Username<'username>> for &'a str {
1766 fn eq(&self, other: &Username<'username>) -> bool {
1767 other == self.as_bytes()
1768 }
1769}
1770
1771impl<'username> TryFrom<&'username [u8]> for Username<'username> {
1772 type Error = UsernameError;
1773
1774 fn try_from(value: &'username [u8]) -> Result<Self, Self::Error> {
1775 let normalized = check_user_info(value, true)?;
1776
1777 // Unsafe: The function above [`check_user_info`] ensure this is valid ASCII-US.
1778 Ok(Username {
1779 normalized,
1780 username: Cow::from(unsafe { str::from_utf8_unchecked(value) }),
1781 })
1782 }
1783}
1784
1785impl<'username> TryFrom<&'username str> for Username<'username> {
1786 type Error = UsernameError;
1787
1788 fn try_from(value: &'username str) -> Result<Self, Self::Error> {
1789 Username::try_from(value.as_bytes())
1790 }
1791}
1792
1793/// An error representing an invalid authority.
1794#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1795#[non_exhaustive]
1796pub enum AuthorityError {
1797 /// The host component of the authority was invalid.
1798 Host(HostError),
1799
1800 /// The password component of the authority was invalid.
1801 Password(PasswordError),
1802
1803 /// The port component of the authority was invalid.
1804 Port(PortError),
1805
1806 /// The username component of the authority was invalid.
1807 Username(UsernameError),
1808}
1809
1810impl Display for AuthorityError {
1811 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1812 use self::AuthorityError::*;
1813
1814 match self {
1815 Host(error) => error.fmt(formatter),
1816 Password(error) => error.fmt(formatter),
1817 Port(error) => error.fmt(formatter),
1818 Username(error) => error.fmt(formatter),
1819 }
1820 }
1821}
1822
1823impl Error for AuthorityError {}
1824
1825impl From<Infallible> for AuthorityError {
1826 fn from(_: Infallible) -> Self {
1827 AuthorityError::Host(HostError::InvalidIPv4OrRegisteredNameCharacter)
1828 }
1829}
1830
1831impl From<HostError> for AuthorityError {
1832 fn from(value: HostError) -> Self {
1833 AuthorityError::Host(value)
1834 }
1835}
1836
1837impl From<PasswordError> for AuthorityError {
1838 fn from(value: PasswordError) -> Self {
1839 AuthorityError::Password(value)
1840 }
1841}
1842
1843impl From<PortError> for AuthorityError {
1844 fn from(value: PortError) -> Self {
1845 AuthorityError::Port(value)
1846 }
1847}
1848
1849impl From<UserInfoError> for AuthorityError {
1850 fn from(value: UserInfoError) -> Self {
1851 use self::AuthorityError::*;
1852
1853 match value {
1854 UserInfoError::Password(error) => Password(error),
1855 UserInfoError::Username(error) => Username(error),
1856 }
1857 }
1858}
1859
1860impl From<UsernameError> for AuthorityError {
1861 fn from(value: UsernameError) -> Self {
1862 AuthorityError::Username(value)
1863 }
1864}
1865
1866/// An error representing an invalid host.
1867#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1868#[non_exhaustive]
1869pub enum HostError {
1870 /// The syntax for a future IP literal was used and is not currently supported.
1871 AddressMechanismNotSupported,
1872
1873 /// An invalid character for an IPv4 address or registered name was used. Due to the ambiguity
1874 /// of the grammar, it is not possible to say which. It is also possible that all the characters
1875 /// were valid, but there was an invalid percent encoding (e.g. `"%ZZ"`).
1876 InvalidIPv4OrRegisteredNameCharacter,
1877
1878 /// The syntax for an IPv6 literal was used (i.e. `"[...]"`), but it contained an invalid IPv6
1879 /// character.
1880 InvalidIPv6Character,
1881
1882 /// The syntax for an IPv6 literal was used (i.e. `"[...]"`) and all of the characters were
1883 /// valid IPv6 characters. However, the format of the literal was invalid.
1884 InvalidIPv6Format,
1885
1886 /// The syntax for a future IP literal was used (i.e. `"[v*...]"` where `"*"` is a hexadecimal
1887 /// digit), but it contained an invalid character.
1888 InvalidIPvFutureCharacter,
1889}
1890
1891impl Display for HostError {
1892 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1893 use self::HostError::*;
1894
1895 match self {
1896 AddressMechanismNotSupported => {
1897 write!(formatter, "host address mechanism not supported")
1898 }
1899 InvalidIPv4OrRegisteredNameCharacter => {
1900 write!(formatter, "invalid host IPv4 or registered name character")
1901 }
1902 InvalidIPv6Character => write!(formatter, "invalid host IPv6 character"),
1903 InvalidIPv6Format => write!(formatter, "invalid host IPv6 format"),
1904 InvalidIPvFutureCharacter => write!(formatter, "invalid host IPvFuture character"),
1905 }
1906 }
1907}
1908
1909impl Error for HostError {}
1910
1911impl From<Infallible> for HostError {
1912 fn from(_: Infallible) -> Self {
1913 HostError::InvalidIPv4OrRegisteredNameCharacter
1914 }
1915}
1916
1917/// An error representing an invalid password component.
1918#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1919#[non_exhaustive]
1920pub enum PasswordError {
1921 /// The password contained an invalid character.
1922 InvalidCharacter,
1923
1924 /// The password contained an invalid percent encoding (e.g. `"%ZZ"`).
1925 InvalidPercentEncoding,
1926}
1927
1928impl Display for PasswordError {
1929 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1930 use self::PasswordError::*;
1931
1932 match self {
1933 InvalidCharacter => write!(formatter, "invalid password character"),
1934 InvalidPercentEncoding => write!(formatter, "invalid password percent encoding"),
1935 }
1936 }
1937}
1938
1939impl Error for PasswordError {}
1940
1941impl From<Infallible> for PasswordError {
1942 fn from(_: Infallible) -> Self {
1943 PasswordError::InvalidCharacter
1944 }
1945}
1946
1947impl From<UserInfoError> for PasswordError {
1948 fn from(value: UserInfoError) -> Self {
1949 match value {
1950 UserInfoError::Password(error) => error,
1951 _ => panic!("unexpected user info error"),
1952 }
1953 }
1954}
1955
1956/// An error representing an invalid port.
1957#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1958#[non_exhaustive]
1959pub enum PortError {
1960 /// An invalid character was used in the port. Only decimal digits are allowed.
1961 InvalidCharacter,
1962
1963 /// The port was a valid number, but it was too large to fit in a `u16`.
1964 Overflow,
1965}
1966
1967impl Display for PortError {
1968 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1969 use self::PortError::*;
1970
1971 match self {
1972 InvalidCharacter => write!(formatter, "invalid port character"),
1973 Overflow => write!(formatter, "port overflow"),
1974 }
1975 }
1976}
1977
1978impl Error for PortError {}
1979
1980impl From<Infallible> for PortError {
1981 fn from(_: Infallible) -> Self {
1982 PortError::InvalidCharacter
1983 }
1984}
1985
1986/// An error representing an invalid registered name.
1987///
1988/// This implies that the registered name contained an invalid host character or had an invalid
1989/// percent encoding. This error is not possible from parsing an authority. It can only be returned
1990/// from directly parsing a registered name.
1991#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1992pub struct RegisteredNameError;
1993
1994impl Display for RegisteredNameError {
1995 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1996 write!(formatter, "invalid registered name")
1997 }
1998}
1999
2000impl Error for RegisteredNameError {}
2001
2002/// An error representing an invalid user information component.
2003#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2004#[non_exhaustive]
2005enum UserInfoError {
2006 /// The password component of the user information was invalid.
2007 Password(PasswordError),
2008
2009 /// The username component of the user information was invalid.
2010 Username(UsernameError),
2011}
2012
2013impl Display for UserInfoError {
2014 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
2015 use self::UserInfoError::*;
2016
2017 match self {
2018 Password(error) => error.fmt(formatter),
2019 Username(error) => error.fmt(formatter),
2020 }
2021 }
2022}
2023
2024impl Error for UserInfoError {}
2025
2026impl From<Infallible> for UserInfoError {
2027 fn from(_: Infallible) -> Self {
2028 UserInfoError::Username(UsernameError::InvalidCharacter)
2029 }
2030}
2031
2032impl From<PasswordError> for UserInfoError {
2033 fn from(value: PasswordError) -> Self {
2034 UserInfoError::Password(value)
2035 }
2036}
2037
2038impl From<UsernameError> for UserInfoError {
2039 fn from(value: UsernameError) -> Self {
2040 UserInfoError::Username(value)
2041 }
2042}
2043
2044/// An error representing an invalid username component.
2045#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2046#[non_exhaustive]
2047pub enum UsernameError {
2048 /// The username contained a `':'` which is only to be used as a delimiter between the username
2049 /// and password. This variant can only happen when trying to directly parse a username from a
2050 /// byte source.
2051 ContainsColon,
2052
2053 /// The username contained an invalid character.
2054 InvalidCharacter,
2055
2056 /// The username contained an invalid percent encoding (e.g. `"%ZZ"`).
2057 InvalidPercentEncoding,
2058}
2059
2060impl Display for UsernameError {
2061 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
2062 use self::UsernameError::*;
2063
2064 match self {
2065 ContainsColon => write!(formatter, "username contains a colon character"),
2066 InvalidCharacter => write!(formatter, "invalid username character"),
2067 InvalidPercentEncoding => write!(formatter, "invalid username percent encoding"),
2068 }
2069 }
2070}
2071
2072impl Error for UsernameError {}
2073
2074impl From<Infallible> for UsernameError {
2075 fn from(_: Infallible) -> Self {
2076 UsernameError::InvalidCharacter
2077 }
2078}
2079
2080impl From<UserInfoError> for UsernameError {
2081 fn from(value: UserInfoError) -> Self {
2082 match value {
2083 UserInfoError::Username(error) => error,
2084 _ => panic!("unexpected user info error"),
2085 }
2086 }
2087}
2088
2089/// Returns true if the byte string contains only valid IPv4 or registered name characters. This
2090/// also ensures that percent encodings are valid.
2091fn check_ipv4_or_registered_name(value: &[u8]) -> (bool, bool) {
2092 let mut bytes = value.iter();
2093 let mut normalized = true;
2094
2095 while let Some(&byte) = bytes.next() {
2096 match IPV4_AND_REGISTERED_NAME_CHAR_MAP[byte as usize] {
2097 0 => return (false, false),
2098 b'%' => match get_percent_encoded_value(bytes.next().cloned(), bytes.next().cloned()) {
2099 Ok((hex_value, uppercase)) => {
2100 if !uppercase || UNRESERVED_CHAR_MAP[hex_value as usize] != 0 {
2101 normalized = false;
2102 }
2103 }
2104 _ => return (false, false),
2105 },
2106 b'A'..=b'Z' => normalized = false,
2107 _ => (),
2108 }
2109 }
2110
2111 (true, normalized)
2112}
2113
2114/// Returns true if the byte string contains only valid IPv6 characters.
2115fn check_ipv6(value: &[u8]) -> bool {
2116 for &byte in value {
2117 if !byte.is_ascii_hexdigit() && byte != b':' && byte != b'.' {
2118 return false;
2119 }
2120 }
2121
2122 true
2123}
2124
2125/// Returns true if the byte string contains only valid future IP literal characters. This also
2126/// ensures that percent encodings are valid.
2127fn check_ipvfuture(value: &[u8]) -> bool {
2128 for &byte in value {
2129 if let 0 = IPV_FUTURE_CHAR_MAP[byte as usize] {
2130 return false;
2131 }
2132 }
2133
2134 true
2135}
2136
2137/// Checks if the user information component contains valid characters and percent encodings. If so,
2138/// it will return an `Option<usize>` indicating the separator index for the username and password.
2139fn check_user_info(value: &[u8], is_username: bool) -> Result<bool, UserInfoError> {
2140 let mut bytes = value.iter();
2141 let mut normalized = true;
2142
2143 while let Some(&byte) = bytes.next() {
2144 match USER_INFO_CHAR_MAP[byte as usize] {
2145 0 => {
2146 return if is_username {
2147 Err(UsernameError::InvalidCharacter.into())
2148 } else {
2149 Err(PasswordError::InvalidCharacter.into())
2150 };
2151 }
2152 b'%' => match get_percent_encoded_value(bytes.next().cloned(), bytes.next().cloned()) {
2153 Ok((hex_value, uppercase)) => {
2154 if !uppercase || UNRESERVED_CHAR_MAP[hex_value as usize] != 0 {
2155 normalized = false;
2156 }
2157 }
2158 Err(_) => {
2159 return if is_username {
2160 Err(UsernameError::InvalidPercentEncoding.into())
2161 } else {
2162 Err(PasswordError::InvalidPercentEncoding.into())
2163 };
2164 }
2165 },
2166 b':' if is_username => return Err(UsernameError::ContainsColon.into()),
2167 _ => (),
2168 }
2169 }
2170
2171 Ok(normalized)
2172}
2173
2174/// Parses the authority from the given byte string.
2175pub(crate) fn parse_authority(value: &[u8]) -> Result<(Authority, &[u8]), AuthorityError> {
2176 let mut at_index = None;
2177 let mut last_colon_index = None;
2178 let mut end_index = value.len();
2179
2180 for (index, &byte) in value.iter().enumerate() {
2181 match byte {
2182 b'@' => {
2183 if at_index.is_none() {
2184 at_index = Some(index);
2185 last_colon_index = None;
2186 }
2187 }
2188 b':' => last_colon_index = Some(index),
2189 b']' => last_colon_index = None,
2190 b'/' | b'?' | b'#' => {
2191 end_index = index;
2192 break;
2193 }
2194 _ => (),
2195 }
2196 }
2197
2198 let (value, rest) = value.split_at(end_index);
2199 let (username, password, host_start_index) = match at_index {
2200 Some(index) => {
2201 let (username, password) = parse_user_info(&value[..index])?;
2202 (Some(username), password, index + 1)
2203 }
2204 None => (None, None, 0),
2205 };
2206
2207 let (host, port) = match last_colon_index {
2208 Some(index) => (
2209 Host::try_from(&value[host_start_index..index])?,
2210 parse_port(&value[index + 1..])?,
2211 ),
2212 None => (Host::try_from(&value[host_start_index..])?, None),
2213 };
2214
2215 let authority = Authority {
2216 host,
2217 port,
2218 password,
2219 username,
2220 };
2221
2222 Ok((authority, rest))
2223}
2224
2225/// Parses the port from the given byte string.
2226pub fn parse_port(value: &[u8]) -> Result<Option<u16>, PortError> {
2227 if value.is_empty() {
2228 Ok(None)
2229 } else {
2230 let mut port = 0u16;
2231
2232 for &byte in value {
2233 if !byte.is_ascii_digit() {
2234 return Err(PortError::InvalidCharacter);
2235 }
2236
2237 port = port.checked_mul(10).ok_or(PortError::Overflow)?;
2238 port = port
2239 .checked_add((byte - b'0').into())
2240 .ok_or(PortError::Overflow)?;
2241 }
2242
2243 Ok(Some(port))
2244 }
2245}
2246
2247/// Parses the user information from the given byte string.
2248fn parse_user_info(value: &[u8]) -> Result<(Username, Option<Password>), UserInfoError> {
2249 let mut bytes = value.iter().enumerate();
2250 let mut first_colon_index = None;
2251 let mut password_normalized = true;
2252 let mut username_normalized = true;
2253
2254 while let Some((index, &byte)) = bytes.next() {
2255 match USER_INFO_CHAR_MAP[byte as usize] {
2256 0 => {
2257 return if first_colon_index.is_some() {
2258 Err(PasswordError::InvalidCharacter.into())
2259 } else {
2260 Err(UsernameError::InvalidCharacter.into())
2261 }
2262 }
2263 b'%' => match get_percent_encoded_value(
2264 bytes.next().map(|(_, &byte)| byte),
2265 bytes.next().map(|(_, &byte)| byte),
2266 ) {
2267 Ok((hex_value, uppercase)) => {
2268 if !uppercase || UNRESERVED_CHAR_MAP[hex_value as usize] != 0 {
2269 if first_colon_index.is_some() {
2270 password_normalized = false;
2271 } else {
2272 username_normalized = false;
2273 }
2274 }
2275 }
2276 Err(_) => {
2277 return if first_colon_index.is_some() {
2278 Err(PasswordError::InvalidPercentEncoding.into())
2279 } else {
2280 Err(UsernameError::InvalidPercentEncoding.into())
2281 }
2282 }
2283 },
2284 b':' => {
2285 if first_colon_index.is_none() {
2286 first_colon_index = Some(index);
2287 }
2288 }
2289 _ => (),
2290 }
2291 }
2292
2293 // Unsafe: All characters are ASCII-US, as checked above.
2294 Ok(match first_colon_index {
2295 Some(index) => {
2296 let username = Username {
2297 normalized: username_normalized,
2298 username: Cow::from(unsafe { str::from_utf8_unchecked(&value[..index]) }),
2299 };
2300 let password = Password {
2301 normalized: password_normalized,
2302 password: Cow::from(unsafe { str::from_utf8_unchecked(&value[index + 1..]) }),
2303 };
2304 (username, Some(password))
2305 }
2306 _ => {
2307 let username = Username {
2308 normalized: username_normalized,
2309 username: Cow::from(unsafe { str::from_utf8_unchecked(value) }),
2310 };
2311 (username, None)
2312 }
2313 })
2314}