1 use std::convert::TryFrom;
2 use std::hash::{Hash, Hasher};
3 use std::str::FromStr;
4 use std::{cmp, fmt, str};
5 
6 use bytes::Bytes;
7 
8 use super::{ErrorKind, InvalidUri, Port, URI_CHARS};
9 use crate::byte_str::ByteStr;
10 
11 /// Represents the authority component of a URI.
12 #[derive(Clone)]
13 pub struct Authority {
14     pub(super) data: ByteStr,
15 }
16 
17 impl Authority {
empty() -> Self18     pub(super) fn empty() -> Self {
19         Authority {
20             data: ByteStr::new(),
21         }
22     }
23 
24     // Not public while `bytes` is unstable.
from_shared(s: Bytes) -> Result<Self, InvalidUri>25     pub(super) fn from_shared(s: Bytes) -> Result<Self, InvalidUri> {
26         // Precondition on create_authority: trivially satisfied by the
27         // identity clousre
28         create_authority(s, |s| s)
29     }
30 
31     /// Attempt to convert an `Authority` from a static string.
32     ///
33     /// This function will not perform any copying, and the string will be
34     /// checked if it is empty or contains an invalid character.
35     ///
36     /// # Panics
37     ///
38     /// This function panics if the argument contains invalid characters or
39     /// is empty.
40     ///
41     /// # Examples
42     ///
43     /// ```
44     /// # use http::uri::Authority;
45     /// let authority = Authority::from_static("example.com");
46     /// assert_eq!(authority.host(), "example.com");
47     /// ```
from_static(src: &'static str) -> Self48     pub fn from_static(src: &'static str) -> Self {
49         Authority::from_shared(Bytes::from_static(src.as_bytes()))
50             .expect("static str is not valid authority")
51     }
52 
53     /// Attempt to convert a `Bytes` buffer to a `Authority`.
54     ///
55     /// This will try to prevent a copy if the type passed is the type used
56     /// internally, and will copy the data if it is not.
from_maybe_shared<T>(src: T) -> Result<Self, InvalidUri> where T: AsRef<[u8]> + 'static,57     pub fn from_maybe_shared<T>(src: T) -> Result<Self, InvalidUri>
58     where
59         T: AsRef<[u8]> + 'static,
60     {
61         if_downcast_into!(T, Bytes, src, {
62             return Authority::from_shared(src);
63         });
64 
65         Authority::try_from(src.as_ref())
66     }
67 
68     // Note: this may return an *empty* Authority. You might want `parse_non_empty`.
69     // Postcondition: for all Ok() returns, s[..ret.unwrap()] is valid UTF-8 where
70     // ret is the return value.
parse(s: &[u8]) -> Result<usize, InvalidUri>71     pub(super) fn parse(s: &[u8]) -> Result<usize, InvalidUri> {
72         let mut colon_cnt = 0;
73         let mut start_bracket = false;
74         let mut end_bracket = false;
75         let mut has_percent = false;
76         let mut end = s.len();
77         let mut at_sign_pos = None;
78 
79         // Among other things, this loop checks that every byte in s up to the
80         // first '/', '?', or '#' is a valid URI character (or in some contexts,
81         // a '%'). This means that each such byte is a valid single-byte UTF-8
82         // code point.
83         for (i, &b) in s.iter().enumerate() {
84             match URI_CHARS[b as usize] {
85                 b'/' | b'?' | b'#' => {
86                     end = i;
87                     break;
88                 }
89                 b':' => {
90                     colon_cnt += 1;
91                 }
92                 b'[' => {
93                     if has_percent || start_bracket {
94                         // Something other than the userinfo has a `%`, so reject it.
95                         return Err(ErrorKind::InvalidAuthority.into());
96                     }
97                     start_bracket = true;
98                 }
99                 b']' => {
100                     if end_bracket {
101                         return Err(ErrorKind::InvalidAuthority.into());
102                     }
103                     end_bracket = true;
104 
105                     // Those were part of an IPv6 hostname, so forget them...
106                     colon_cnt = 0;
107                     has_percent = false;
108                 }
109                 b'@' => {
110                     at_sign_pos = Some(i);
111 
112                     // Those weren't a port colon, but part of the
113                     // userinfo, so it needs to be forgotten.
114                     colon_cnt = 0;
115                     has_percent = false;
116                 }
117                 0 if b == b'%' => {
118                     // Per https://tools.ietf.org/html/rfc3986#section-3.2.1 and
119                     // https://url.spec.whatwg.org/#authority-state
120                     // the userinfo can have a percent-encoded username and password,
121                     // so record that a `%` was found. If this turns out to be
122                     // part of the userinfo, this flag will be cleared.
123                     // Also per https://tools.ietf.org/html/rfc6874, percent-encoding can
124                     // be used to indicate a zone identifier.
125                     // If the flag hasn't been cleared at the end, that means this
126                     // was part of the hostname (and not part of an IPv6 address), and
127                     // will fail with an error.
128                     has_percent = true;
129                 }
130                 0 => {
131                     return Err(ErrorKind::InvalidUriChar.into());
132                 }
133                 _ => {}
134             }
135         }
136 
137         if start_bracket ^ end_bracket {
138             return Err(ErrorKind::InvalidAuthority.into());
139         }
140 
141         if colon_cnt > 1 {
142             // Things like 'localhost:8080:3030' are rejected.
143             return Err(ErrorKind::InvalidAuthority.into());
144         }
145 
146         if end > 0 && at_sign_pos == Some(end - 1) {
147             // If there's nothing after an `@`, this is bonkers.
148             return Err(ErrorKind::InvalidAuthority.into());
149         }
150 
151         if has_percent {
152             // Something after the userinfo has a `%`, so reject it.
153             return Err(ErrorKind::InvalidAuthority.into());
154         }
155 
156         Ok(end)
157     }
158 
159     // Parse bytes as an Authority, not allowing an empty string.
160     //
161     // This should be used by functions that allow a user to parse
162     // an `Authority` by itself.
163     //
164     // Postcondition: for all Ok() returns, s[..ret.unwrap()] is valid UTF-8 where
165     // ret is the return value.
parse_non_empty(s: &[u8]) -> Result<usize, InvalidUri>166     fn parse_non_empty(s: &[u8]) -> Result<usize, InvalidUri> {
167         if s.is_empty() {
168             return Err(ErrorKind::Empty.into());
169         }
170         Authority::parse(s)
171     }
172 
173     /// Get the host of this `Authority`.
174     ///
175     /// The host subcomponent of authority is identified by an IP literal
176     /// encapsulated within square brackets, an IPv4 address in dotted- decimal
177     /// form, or a registered name.  The host subcomponent is **case-insensitive**.
178     ///
179     /// ```notrust
180     /// abc://username:[email protected]:123/path/data?key=value&key2=value2#fragid1
181     ///                         |---------|
182     ///                              |
183     ///                             host
184     /// ```
185     ///
186     /// # Examples
187     ///
188     /// ```
189     /// # use http::uri::*;
190     /// let authority: Authority = "example.org:80".parse().unwrap();
191     ///
192     /// assert_eq!(authority.host(), "example.org");
193     /// ```
194     #[inline]
host(&self) -> &str195     pub fn host(&self) -> &str {
196         host(self.as_str())
197     }
198 
199     /// Get the port part of this `Authority`.
200     ///
201     /// The port subcomponent of authority is designated by an optional port
202     /// number following the host and delimited from it by a single colon (":")
203     /// character. It can be turned into a decimal port number with the `as_u16`
204     /// method or as a `str` with the `as_str` method.
205     ///
206     /// ```notrust
207     /// abc://username:[email protected]:123/path/data?key=value&key2=value2#fragid1
208     ///                                     |-|
209     ///                                      |
210     ///                                     port
211     /// ```
212     ///
213     /// # Examples
214     ///
215     /// Authority with port
216     ///
217     /// ```
218     /// # use http::uri::Authority;
219     /// let authority: Authority = "example.org:80".parse().unwrap();
220     ///
221     /// let port = authority.port().unwrap();
222     /// assert_eq!(port.as_u16(), 80);
223     /// assert_eq!(port.as_str(), "80");
224     /// ```
225     ///
226     /// Authority without port
227     ///
228     /// ```
229     /// # use http::uri::Authority;
230     /// let authority: Authority = "example.org".parse().unwrap();
231     ///
232     /// assert!(authority.port().is_none());
233     /// ```
port(&self) -> Option<Port<&str>>234     pub fn port(&self) -> Option<Port<&str>> {
235         let bytes = self.as_str();
236         bytes
237             .rfind(":")
238             .and_then(|i| Port::from_str(&bytes[i + 1..]).ok())
239     }
240 
241     /// Get the port of this `Authority` as a `u16`.
242     ///
243     /// # Example
244     ///
245     /// ```
246     /// # use http::uri::Authority;
247     /// let authority: Authority = "example.org:80".parse().unwrap();
248     ///
249     /// assert_eq!(authority.port_u16(), Some(80));
250     /// ```
port_u16(&self) -> Option<u16>251     pub fn port_u16(&self) -> Option<u16> {
252         self.port().and_then(|p| Some(p.as_u16()))
253     }
254 
255     /// Return a str representation of the authority
256     #[inline]
as_str(&self) -> &str257     pub fn as_str(&self) -> &str {
258         &self.data[..]
259     }
260 }
261 
262 // Purposefully not public while `bytes` is unstable.
263 // impl TryFrom<Bytes> for Authority
264 
265 impl AsRef<str> for Authority {
as_ref(&self) -> &str266     fn as_ref(&self) -> &str {
267         self.as_str()
268     }
269 }
270 
271 impl PartialEq for Authority {
eq(&self, other: &Authority) -> bool272     fn eq(&self, other: &Authority) -> bool {
273         self.data.eq_ignore_ascii_case(&other.data)
274     }
275 }
276 
277 impl Eq for Authority {}
278 
279 /// Case-insensitive equality
280 ///
281 /// # Examples
282 ///
283 /// ```
284 /// # use http::uri::Authority;
285 /// let authority: Authority = "HELLO.com".parse().unwrap();
286 /// assert_eq!(authority, "hello.coM");
287 /// assert_eq!("hello.com", authority);
288 /// ```
289 impl PartialEq<str> for Authority {
eq(&self, other: &str) -> bool290     fn eq(&self, other: &str) -> bool {
291         self.data.eq_ignore_ascii_case(other)
292     }
293 }
294 
295 impl PartialEq<Authority> for str {
eq(&self, other: &Authority) -> bool296     fn eq(&self, other: &Authority) -> bool {
297         self.eq_ignore_ascii_case(other.as_str())
298     }
299 }
300 
301 impl<'a> PartialEq<Authority> for &'a str {
eq(&self, other: &Authority) -> bool302     fn eq(&self, other: &Authority) -> bool {
303         self.eq_ignore_ascii_case(other.as_str())
304     }
305 }
306 
307 impl<'a> PartialEq<&'a str> for Authority {
eq(&self, other: &&'a str) -> bool308     fn eq(&self, other: &&'a str) -> bool {
309         self.data.eq_ignore_ascii_case(other)
310     }
311 }
312 
313 impl PartialEq<String> for Authority {
eq(&self, other: &String) -> bool314     fn eq(&self, other: &String) -> bool {
315         self.data.eq_ignore_ascii_case(other.as_str())
316     }
317 }
318 
319 impl PartialEq<Authority> for String {
eq(&self, other: &Authority) -> bool320     fn eq(&self, other: &Authority) -> bool {
321         self.as_str().eq_ignore_ascii_case(other.as_str())
322     }
323 }
324 
325 /// Case-insensitive ordering
326 ///
327 /// # Examples
328 ///
329 /// ```
330 /// # use http::uri::Authority;
331 /// let authority: Authority = "DEF.com".parse().unwrap();
332 /// assert!(authority < "ghi.com");
333 /// assert!(authority > "abc.com");
334 /// ```
335 impl PartialOrd for Authority {
partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering>336     fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
337         let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
338         let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
339         left.partial_cmp(right)
340     }
341 }
342 
343 impl PartialOrd<str> for Authority {
partial_cmp(&self, other: &str) -> Option<cmp::Ordering>344     fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
345         let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
346         let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
347         left.partial_cmp(right)
348     }
349 }
350 
351 impl PartialOrd<Authority> for str {
partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering>352     fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
353         let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
354         let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
355         left.partial_cmp(right)
356     }
357 }
358 
359 impl<'a> PartialOrd<Authority> for &'a str {
partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering>360     fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
361         let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
362         let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
363         left.partial_cmp(right)
364     }
365 }
366 
367 impl<'a> PartialOrd<&'a str> for Authority {
partial_cmp(&self, other: &&'a str) -> Option<cmp::Ordering>368     fn partial_cmp(&self, other: &&'a str) -> Option<cmp::Ordering> {
369         let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
370         let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
371         left.partial_cmp(right)
372     }
373 }
374 
375 impl PartialOrd<String> for Authority {
partial_cmp(&self, other: &String) -> Option<cmp::Ordering>376     fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
377         let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
378         let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
379         left.partial_cmp(right)
380     }
381 }
382 
383 impl PartialOrd<Authority> for String {
partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering>384     fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
385         let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
386         let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
387         left.partial_cmp(right)
388     }
389 }
390 
391 /// Case-insensitive hashing
392 ///
393 /// # Examples
394 ///
395 /// ```
396 /// # use http::uri::Authority;
397 /// # use std::hash::{Hash, Hasher};
398 /// # use std::collections::hash_map::DefaultHasher;
399 ///
400 /// let a: Authority = "HELLO.com".parse().unwrap();
401 /// let b: Authority = "hello.coM".parse().unwrap();
402 ///
403 /// let mut s = DefaultHasher::new();
404 /// a.hash(&mut s);
405 /// let a = s.finish();
406 ///
407 /// let mut s = DefaultHasher::new();
408 /// b.hash(&mut s);
409 /// let b = s.finish();
410 ///
411 /// assert_eq!(a, b);
412 /// ```
413 impl Hash for Authority {
hash<H>(&self, state: &mut H) where H: Hasher,414     fn hash<H>(&self, state: &mut H)
415     where
416         H: Hasher,
417     {
418         self.data.len().hash(state);
419         for &b in self.data.as_bytes() {
420             state.write_u8(b.to_ascii_lowercase());
421         }
422     }
423 }
424 
425 impl<'a> TryFrom<&'a [u8]> for Authority {
426     type Error = InvalidUri;
427     #[inline]
try_from(s: &'a [u8]) -> Result<Self, Self::Error>428     fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
429         // parse first, and only turn into Bytes if valid
430 
431         // Preconditon on create_authority: copy_from_slice() copies all of
432         // bytes from the [u8] parameter into a new Bytes
433         create_authority(s, |s| Bytes::copy_from_slice(s))
434     }
435 }
436 
437 impl<'a> TryFrom<&'a str> for Authority {
438     type Error = InvalidUri;
439     #[inline]
try_from(s: &'a str) -> Result<Self, Self::Error>440     fn try_from(s: &'a str) -> Result<Self, Self::Error> {
441         TryFrom::try_from(s.as_bytes())
442     }
443 }
444 
445 impl TryFrom<Vec<u8>> for Authority {
446     type Error = InvalidUri;
447 
448     #[inline]
try_from(vec: Vec<u8>) -> Result<Self, Self::Error>449     fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
450         Authority::from_shared(vec.into())
451     }
452 }
453 
454 impl TryFrom<String> for Authority {
455     type Error = InvalidUri;
456 
457     #[inline]
try_from(t: String) -> Result<Self, Self::Error>458     fn try_from(t: String) -> Result<Self, Self::Error> {
459         Authority::from_shared(t.into())
460     }
461 }
462 
463 impl FromStr for Authority {
464     type Err = InvalidUri;
465 
from_str(s: &str) -> Result<Self, InvalidUri>466     fn from_str(s: &str) -> Result<Self, InvalidUri> {
467         TryFrom::try_from(s)
468     }
469 }
470 
471 impl fmt::Debug for Authority {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result472     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
473         f.write_str(self.as_str())
474     }
475 }
476 
477 impl fmt::Display for Authority {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result478     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
479         f.write_str(self.as_str())
480     }
481 }
482 
host(auth: &str) -> &str483 fn host(auth: &str) -> &str {
484     let host_port = auth
485         .rsplitn(2, '@')
486         .next()
487         .expect("split always has at least 1 item");
488 
489     if host_port.as_bytes()[0] == b'[' {
490         let i = host_port
491             .find(']')
492             .expect("parsing should validate brackets");
493         // ..= ranges aren't available in 1.20, our minimum Rust version...
494         &host_port[0..i + 1]
495     } else {
496         host_port
497             .split(':')
498             .next()
499             .expect("split always has at least 1 item")
500     }
501 }
502 
503 // Precondition: f converts all of the bytes in the passed in B into the
504 // returned Bytes.
create_authority<B, F>(b: B, f: F) -> Result<Authority, InvalidUri> where B: AsRef<[u8]>, F: FnOnce(B) -> Bytes,505 fn create_authority<B, F>(b: B, f: F) -> Result<Authority, InvalidUri>
506 where
507     B: AsRef<[u8]>,
508     F: FnOnce(B) -> Bytes,
509 {
510     let s = b.as_ref();
511     let authority_end = Authority::parse_non_empty(s)?;
512 
513     if authority_end != s.len() {
514         return Err(ErrorKind::InvalidUriChar.into());
515     }
516 
517     let bytes = f(b);
518 
519     Ok(Authority {
520         // Safety: the postcondition on parse_non_empty() and the check against
521         // s.len() ensure that b is valid UTF-8. The precondition on f ensures
522         // that this is carried through to bytes.
523         data: unsafe { ByteStr::from_utf8_unchecked(bytes) },
524     })
525 }
526 
527 #[cfg(test)]
528 mod tests {
529     use super::*;
530 
531     #[test]
parse_empty_string_is_error()532     fn parse_empty_string_is_error() {
533         let err = Authority::parse_non_empty(b"").unwrap_err();
534         assert_eq!(err.0, ErrorKind::Empty);
535     }
536 
537     #[test]
equal_to_self_of_same_authority()538     fn equal_to_self_of_same_authority() {
539         let authority1: Authority = "example.com".parse().unwrap();
540         let authority2: Authority = "EXAMPLE.COM".parse().unwrap();
541         assert_eq!(authority1, authority2);
542         assert_eq!(authority2, authority1);
543     }
544 
545     #[test]
not_equal_to_self_of_different_authority()546     fn not_equal_to_self_of_different_authority() {
547         let authority1: Authority = "example.com".parse().unwrap();
548         let authority2: Authority = "test.com".parse().unwrap();
549         assert_ne!(authority1, authority2);
550         assert_ne!(authority2, authority1);
551     }
552 
553     #[test]
equates_with_a_str()554     fn equates_with_a_str() {
555         let authority: Authority = "example.com".parse().unwrap();
556         assert_eq!(&authority, "EXAMPLE.com");
557         assert_eq!("EXAMPLE.com", &authority);
558         assert_eq!(authority, "EXAMPLE.com");
559         assert_eq!("EXAMPLE.com", authority);
560     }
561 
562     #[test]
from_static_equates_with_a_str()563     fn from_static_equates_with_a_str() {
564         let authority = Authority::from_static("example.com");
565         assert_eq!(authority, "example.com");
566     }
567 
568     #[test]
not_equal_with_a_str_of_a_different_authority()569     fn not_equal_with_a_str_of_a_different_authority() {
570         let authority: Authority = "example.com".parse().unwrap();
571         assert_ne!(&authority, "test.com");
572         assert_ne!("test.com", &authority);
573         assert_ne!(authority, "test.com");
574         assert_ne!("test.com", authority);
575     }
576 
577     #[test]
equates_with_a_string()578     fn equates_with_a_string() {
579         let authority: Authority = "example.com".parse().unwrap();
580         assert_eq!(authority, "EXAMPLE.com".to_string());
581         assert_eq!("EXAMPLE.com".to_string(), authority);
582     }
583 
584     #[test]
equates_with_a_string_of_a_different_authority()585     fn equates_with_a_string_of_a_different_authority() {
586         let authority: Authority = "example.com".parse().unwrap();
587         assert_ne!(authority, "test.com".to_string());
588         assert_ne!("test.com".to_string(), authority);
589     }
590 
591     #[test]
compares_to_self()592     fn compares_to_self() {
593         let authority1: Authority = "abc.com".parse().unwrap();
594         let authority2: Authority = "def.com".parse().unwrap();
595         assert!(authority1 < authority2);
596         assert!(authority2 > authority1);
597     }
598 
599     #[test]
compares_with_a_str()600     fn compares_with_a_str() {
601         let authority: Authority = "def.com".parse().unwrap();
602         // with ref
603         assert!(&authority < "ghi.com");
604         assert!("ghi.com" > &authority);
605         assert!(&authority > "abc.com");
606         assert!("abc.com" < &authority);
607 
608         // no ref
609         assert!(authority < "ghi.com");
610         assert!("ghi.com" > authority);
611         assert!(authority > "abc.com");
612         assert!("abc.com" < authority);
613     }
614 
615     #[test]
compares_with_a_string()616     fn compares_with_a_string() {
617         let authority: Authority = "def.com".parse().unwrap();
618         assert!(authority < "ghi.com".to_string());
619         assert!("ghi.com".to_string() > authority);
620         assert!(authority > "abc.com".to_string());
621         assert!("abc.com".to_string() < authority);
622     }
623 
624     #[test]
allows_percent_in_userinfo()625     fn allows_percent_in_userinfo() {
626         let authority_str = "a%2f:b%[email protected]";
627         let authority: Authority = authority_str.parse().unwrap();
628         assert_eq!(authority, authority_str);
629     }
630 
631     #[test]
rejects_percent_in_hostname()632     fn rejects_percent_in_hostname() {
633         let err = Authority::parse_non_empty(b"example%2f.com").unwrap_err();
634         assert_eq!(err.0, ErrorKind::InvalidAuthority);
635 
636         let err = Authority::parse_non_empty(b"a%2f:b%2f@example%2f.com").unwrap_err();
637         assert_eq!(err.0, ErrorKind::InvalidAuthority);
638     }
639 
640     #[test]
allows_percent_in_ipv6_address()641     fn allows_percent_in_ipv6_address() {
642         let authority_str = "[fe80::1:2:3:4%25eth0]";
643         let result: Authority = authority_str.parse().unwrap();
644         assert_eq!(result, authority_str);
645     }
646 
647     #[test]
rejects_percent_outside_ipv6_address()648     fn rejects_percent_outside_ipv6_address() {
649         let err = Authority::parse_non_empty(b"1234%20[fe80::1:2:3:4]").unwrap_err();
650         assert_eq!(err.0, ErrorKind::InvalidAuthority);
651 
652         let err = Authority::parse_non_empty(b"[fe80::1:2:3:4]%20").unwrap_err();
653         assert_eq!(err.0, ErrorKind::InvalidAuthority);
654     }
655 
656     #[test]
rejects_invalid_utf8()657     fn rejects_invalid_utf8() {
658         let err = Authority::try_from([0xc0u8].as_ref()).unwrap_err();
659         assert_eq!(err.0, ErrorKind::InvalidUriChar);
660 
661         let err = Authority::from_shared(Bytes::from_static([0xc0u8].as_ref()))
662             .unwrap_err();
663         assert_eq!(err.0, ErrorKind::InvalidUriChar);
664     }
665 
666     #[test]
rejects_invalid_use_of_brackets()667     fn rejects_invalid_use_of_brackets() {
668         let err = Authority::parse_non_empty(b"[]@[").unwrap_err();
669         assert_eq!(err.0, ErrorKind::InvalidAuthority);
670     }
671 }
672