1use std::convert::TryFrom;
2use std::hash::{Hash, Hasher};
3use std::str::FromStr;
4use std::{cmp, fmt, str};
5
6use bytes::Bytes;
7
8use super::{ErrorKind, InvalidUri, Port, URI_CHARS};
9use crate::byte_str::ByteStr;
10
11#[derive(Clone)]
13pub struct Authority {
14 pub(super) data: ByteStr,
15}
16
17impl Authority {
18 pub(super) fn empty() -> Self {
19 Authority {
20 data: ByteStr::new(),
21 }
22 }
23
24 pub(super) fn from_shared(s: Bytes) -> Result<Self, InvalidUri> {
26 create_authority(s, |s| s)
29 }
30
31 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 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 pub(super) fn parse(s: &[u8]) -> Result<usize, InvalidUri> {
72 let mut colon_cnt = 0u32;
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 const MAX_COLONS: u32 = 8; for (i, &b) in s.iter().enumerate() {
85 match URI_CHARS[b as usize] {
86 b'/' | b'?' | b'#' => {
87 end = i;
88 break;
89 }
90 b':' => {
91 if colon_cnt >= MAX_COLONS {
92 return Err(ErrorKind::InvalidAuthority.into());
93 }
94 colon_cnt += 1;
95 }
96 b'[' => {
97 if has_percent || start_bracket {
98 return Err(ErrorKind::InvalidAuthority.into());
100 }
101 start_bracket = true;
102 }
103 b']' => {
104 if (!start_bracket) || end_bracket {
105 return Err(ErrorKind::InvalidAuthority.into());
106 }
107 end_bracket = true;
108
109 colon_cnt = 0;
111 has_percent = false;
112 }
113 b'@' => {
114 at_sign_pos = Some(i);
115
116 colon_cnt = 0;
119 has_percent = false;
120 }
121 0 if b == b'%' => {
122 has_percent = true;
133 }
134 0 => {
135 return Err(ErrorKind::InvalidUriChar.into());
136 }
137 _ => {}
138 }
139 }
140
141 if start_bracket ^ end_bracket {
142 return Err(ErrorKind::InvalidAuthority.into());
143 }
144
145 if colon_cnt > 1 {
146 return Err(ErrorKind::InvalidAuthority.into());
148 }
149
150 if end > 0 && at_sign_pos == Some(end - 1) {
151 return Err(ErrorKind::InvalidAuthority.into());
153 }
154
155 if has_percent {
156 return Err(ErrorKind::InvalidAuthority.into());
158 }
159
160 Ok(end)
161 }
162
163 fn parse_non_empty(s: &[u8]) -> Result<usize, InvalidUri> {
171 if s.is_empty() {
172 return Err(ErrorKind::Empty.into());
173 }
174 Authority::parse(s)
175 }
176
177 #[inline]
199 pub fn host(&self) -> &str {
200 host(self.as_str())
201 }
202
203 pub fn port(&self) -> Option<Port<&str>> {
239 let bytes = self.as_str();
240 bytes
241 .rfind(':')
242 .and_then(|i| Port::from_str(&bytes[i + 1..]).ok())
243 }
244
245 pub fn port_u16(&self) -> Option<u16> {
256 self.port().map(|p| p.as_u16())
257 }
258
259 #[inline]
261 pub fn as_str(&self) -> &str {
262 &self.data[..]
263 }
264}
265
266impl AsRef<str> for Authority {
270 fn as_ref(&self) -> &str {
271 self.as_str()
272 }
273}
274
275impl PartialEq for Authority {
276 fn eq(&self, other: &Authority) -> bool {
277 self.data.eq_ignore_ascii_case(&other.data)
278 }
279}
280
281impl Eq for Authority {}
282
283impl PartialEq<str> for Authority {
294 fn eq(&self, other: &str) -> bool {
295 self.data.eq_ignore_ascii_case(other)
296 }
297}
298
299impl PartialEq<Authority> for str {
300 fn eq(&self, other: &Authority) -> bool {
301 self.eq_ignore_ascii_case(other.as_str())
302 }
303}
304
305impl<'a> PartialEq<Authority> for &'a str {
306 fn eq(&self, other: &Authority) -> bool {
307 self.eq_ignore_ascii_case(other.as_str())
308 }
309}
310
311impl<'a> PartialEq<&'a str> for Authority {
312 fn eq(&self, other: &&'a str) -> bool {
313 self.data.eq_ignore_ascii_case(other)
314 }
315}
316
317impl PartialEq<String> for Authority {
318 fn eq(&self, other: &String) -> bool {
319 self.data.eq_ignore_ascii_case(other.as_str())
320 }
321}
322
323impl PartialEq<Authority> for String {
324 fn eq(&self, other: &Authority) -> bool {
325 self.as_str().eq_ignore_ascii_case(other.as_str())
326 }
327}
328
329impl PartialOrd for Authority {
340 fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
341 let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
342 let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
343 left.partial_cmp(right)
344 }
345}
346
347impl PartialOrd<str> for Authority {
348 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
349 let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
350 let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
351 left.partial_cmp(right)
352 }
353}
354
355impl PartialOrd<Authority> for str {
356 fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
357 let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
358 let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
359 left.partial_cmp(right)
360 }
361}
362
363impl<'a> PartialOrd<Authority> for &'a str {
364 fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
365 let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
366 let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
367 left.partial_cmp(right)
368 }
369}
370
371impl<'a> PartialOrd<&'a str> for Authority {
372 fn partial_cmp(&self, other: &&'a str) -> Option<cmp::Ordering> {
373 let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
374 let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
375 left.partial_cmp(right)
376 }
377}
378
379impl PartialOrd<String> for Authority {
380 fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
381 let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
382 let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
383 left.partial_cmp(right)
384 }
385}
386
387impl PartialOrd<Authority> for String {
388 fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
389 let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
390 let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
391 left.partial_cmp(right)
392 }
393}
394
395impl Hash for Authority {
418 fn hash<H>(&self, state: &mut H)
419 where
420 H: Hasher,
421 {
422 self.data.len().hash(state);
423 for &b in self.data.as_bytes() {
424 state.write_u8(b.to_ascii_lowercase());
425 }
426 }
427}
428
429impl<'a> TryFrom<&'a [u8]> for Authority {
430 type Error = InvalidUri;
431 #[inline]
432 fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
433 create_authority(s, Bytes::copy_from_slice)
438 }
439}
440
441impl<'a> TryFrom<&'a str> for Authority {
442 type Error = InvalidUri;
443 #[inline]
444 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
445 TryFrom::try_from(s.as_bytes())
446 }
447}
448
449impl TryFrom<Vec<u8>> for Authority {
450 type Error = InvalidUri;
451
452 #[inline]
453 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
454 Authority::from_shared(vec.into())
455 }
456}
457
458impl TryFrom<String> for Authority {
459 type Error = InvalidUri;
460
461 #[inline]
462 fn try_from(t: String) -> Result<Self, Self::Error> {
463 Authority::from_shared(t.into())
464 }
465}
466
467impl FromStr for Authority {
468 type Err = InvalidUri;
469
470 fn from_str(s: &str) -> Result<Self, InvalidUri> {
471 TryFrom::try_from(s)
472 }
473}
474
475impl fmt::Debug for Authority {
476 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
477 f.write_str(self.as_str())
478 }
479}
480
481impl fmt::Display for Authority {
482 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
483 f.write_str(self.as_str())
484 }
485}
486
487fn host(auth: &str) -> &str {
488 let host_port = auth
489 .rsplit('@')
490 .next()
491 .expect("split always has at least 1 item");
492
493 if host_port.as_bytes()[0] == b'[' {
494 let i = host_port
495 .find(']')
496 .expect("parsing should validate brackets");
497 &host_port[0..i + 1]
499 } else {
500 host_port
501 .split(':')
502 .next()
503 .expect("split always has at least 1 item")
504 }
505}
506
507fn create_authority<B, F>(b: B, f: F) -> Result<Authority, InvalidUri>
510where
511 B: AsRef<[u8]>,
512 F: FnOnce(B) -> Bytes,
513{
514 let s = b.as_ref();
515 let authority_end = Authority::parse_non_empty(s)?;
516
517 if authority_end != s.len() {
518 return Err(ErrorKind::InvalidUriChar.into());
519 }
520
521 let bytes = f(b);
522
523 Ok(Authority {
524 data: unsafe { ByteStr::from_utf8_unchecked(bytes) },
528 })
529}
530
531#[cfg(test)]
532mod tests {
533 use super::*;
534
535 #[test]
536 fn parse_empty_string_is_error() {
537 let err = Authority::parse_non_empty(b"").unwrap_err();
538 assert_eq!(err.0, ErrorKind::Empty);
539 }
540
541 #[test]
542 fn equal_to_self_of_same_authority() {
543 let authority1: Authority = "example.com".parse().unwrap();
544 let authority2: Authority = "EXAMPLE.COM".parse().unwrap();
545 assert_eq!(authority1, authority2);
546 assert_eq!(authority2, authority1);
547 }
548
549 #[test]
550 fn not_equal_to_self_of_different_authority() {
551 let authority1: Authority = "example.com".parse().unwrap();
552 let authority2: Authority = "test.com".parse().unwrap();
553 assert_ne!(authority1, authority2);
554 assert_ne!(authority2, authority1);
555 }
556
557 #[test]
558 fn equates_with_a_str() {
559 let authority: Authority = "example.com".parse().unwrap();
560 assert_eq!(&authority, "EXAMPLE.com");
561 assert_eq!("EXAMPLE.com", &authority);
562 assert_eq!(authority, "EXAMPLE.com");
563 assert_eq!("EXAMPLE.com", authority);
564 }
565
566 #[test]
567 fn from_static_equates_with_a_str() {
568 let authority = Authority::from_static("example.com");
569 assert_eq!(authority, "example.com");
570 }
571
572 #[test]
573 fn not_equal_with_a_str_of_a_different_authority() {
574 let authority: Authority = "example.com".parse().unwrap();
575 assert_ne!(&authority, "test.com");
576 assert_ne!("test.com", &authority);
577 assert_ne!(authority, "test.com");
578 assert_ne!("test.com", authority);
579 }
580
581 #[test]
582 fn equates_with_a_string() {
583 let authority: Authority = "example.com".parse().unwrap();
584 assert_eq!(authority, "EXAMPLE.com".to_string());
585 assert_eq!("EXAMPLE.com".to_string(), authority);
586 }
587
588 #[test]
589 fn equates_with_a_string_of_a_different_authority() {
590 let authority: Authority = "example.com".parse().unwrap();
591 assert_ne!(authority, "test.com".to_string());
592 assert_ne!("test.com".to_string(), authority);
593 }
594
595 #[test]
596 fn compares_to_self() {
597 let authority1: Authority = "abc.com".parse().unwrap();
598 let authority2: Authority = "def.com".parse().unwrap();
599 assert!(authority1 < authority2);
600 assert!(authority2 > authority1);
601 }
602
603 #[test]
604 fn compares_with_a_str() {
605 let authority: Authority = "def.com".parse().unwrap();
606 assert!(&authority < "ghi.com");
608 assert!("ghi.com" > &authority);
609 assert!(&authority > "abc.com");
610 assert!("abc.com" < &authority);
611
612 assert!(authority < "ghi.com");
614 assert!("ghi.com" > authority);
615 assert!(authority > "abc.com");
616 assert!("abc.com" < authority);
617 }
618
619 #[test]
620 fn compares_with_a_string() {
621 let authority: Authority = "def.com".parse().unwrap();
622 assert!(authority < "ghi.com".to_string());
623 assert!("ghi.com".to_string() > authority);
624 assert!(authority > "abc.com".to_string());
625 assert!("abc.com".to_string() < authority);
626 }
627
628 #[test]
629 fn allows_percent_in_userinfo() {
630 let authority_str = "a%2f:b%2f@example.com";
631 let authority: Authority = authority_str.parse().unwrap();
632 assert_eq!(authority, authority_str);
633 }
634
635 #[test]
636 fn rejects_percent_in_hostname() {
637 let err = Authority::parse_non_empty(b"example%2f.com").unwrap_err();
638 assert_eq!(err.0, ErrorKind::InvalidAuthority);
639
640 let err = Authority::parse_non_empty(b"a%2f:b%2f@example%2f.com").unwrap_err();
641 assert_eq!(err.0, ErrorKind::InvalidAuthority);
642 }
643
644 #[test]
645 fn allows_percent_in_ipv6_address() {
646 let authority_str = "[fe80::1:2:3:4%25eth0]";
647 let result: Authority = authority_str.parse().unwrap();
648 assert_eq!(result, authority_str);
649 }
650
651 #[test]
652 fn reject_obviously_invalid_ipv6_address() {
653 let err = Authority::parse_non_empty(b"[0:1:2:3:4:5:6:7:8:9:10:11:12:13:14]").unwrap_err();
654 assert_eq!(err.0, ErrorKind::InvalidAuthority);
655 }
656
657 #[test]
658 fn rejects_percent_outside_ipv6_address() {
659 let err = Authority::parse_non_empty(b"1234%20[fe80::1:2:3:4]").unwrap_err();
660 assert_eq!(err.0, ErrorKind::InvalidAuthority);
661
662 let err = Authority::parse_non_empty(b"[fe80::1:2:3:4]%20").unwrap_err();
663 assert_eq!(err.0, ErrorKind::InvalidAuthority);
664 }
665
666 #[test]
667 fn rejects_invalid_utf8() {
668 let err = Authority::try_from([0xc0u8].as_ref()).unwrap_err();
669 assert_eq!(err.0, ErrorKind::InvalidUriChar);
670
671 let err = Authority::from_shared(Bytes::from_static([0xc0u8].as_ref())).unwrap_err();
672 assert_eq!(err.0, ErrorKind::InvalidUriChar);
673 }
674
675 #[test]
676 fn rejects_invalid_use_of_brackets() {
677 let err = Authority::parse_non_empty(b"[]@[").unwrap_err();
678 assert_eq!(err.0, ErrorKind::InvalidAuthority);
679
680 let err = Authority::parse_non_empty(b"]o[").unwrap_err();
682 assert_eq!(err.0, ErrorKind::InvalidAuthority);
683 }
684}