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