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}