http/uri/
authority.rs
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 = 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 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 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 colon_cnt = 0;
107 has_percent = false;
108 }
109 b'@' => {
110 at_sign_pos = Some(i);
111
112 colon_cnt = 0;
115 has_percent = false;
116 }
117 0 if b == b'%' => {
118 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 return Err(ErrorKind::InvalidAuthority.into());
144 }
145
146 if end > 0 && at_sign_pos == Some(end - 1) {
147 return Err(ErrorKind::InvalidAuthority.into());
149 }
150
151 if has_percent {
152 return Err(ErrorKind::InvalidAuthority.into());
154 }
155
156 Ok(end)
157 }
158
159 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 #[inline]
195 pub fn host(&self) -> &str {
196 host(self.as_str())
197 }
198
199 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 pub fn port_u16(&self) -> Option<u16> {
252 self.port().and_then(|p| Some(p.as_u16()))
253 }
254
255 #[inline]
257 pub fn as_str(&self) -> &str {
258 &self.data[..]
259 }
260}
261
262impl AsRef<str> for Authority {
266 fn as_ref(&self) -> &str {
267 self.as_str()
268 }
269}
270
271impl PartialEq for Authority {
272 fn eq(&self, other: &Authority) -> bool {
273 self.data.eq_ignore_ascii_case(&other.data)
274 }
275}
276
277impl Eq for Authority {}
278
279impl PartialEq<str> for Authority {
290 fn eq(&self, other: &str) -> bool {
291 self.data.eq_ignore_ascii_case(other)
292 }
293}
294
295impl PartialEq<Authority> for str {
296 fn eq(&self, other: &Authority) -> bool {
297 self.eq_ignore_ascii_case(other.as_str())
298 }
299}
300
301impl<'a> PartialEq<Authority> for &'a str {
302 fn eq(&self, other: &Authority) -> bool {
303 self.eq_ignore_ascii_case(other.as_str())
304 }
305}
306
307impl<'a> PartialEq<&'a str> for Authority {
308 fn eq(&self, other: &&'a str) -> bool {
309 self.data.eq_ignore_ascii_case(other)
310 }
311}
312
313impl PartialEq<String> for Authority {
314 fn eq(&self, other: &String) -> bool {
315 self.data.eq_ignore_ascii_case(other.as_str())
316 }
317}
318
319impl PartialEq<Authority> for String {
320 fn eq(&self, other: &Authority) -> bool {
321 self.as_str().eq_ignore_ascii_case(other.as_str())
322 }
323}
324
325impl PartialOrd for Authority {
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
343impl PartialOrd<str> for Authority {
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
351impl PartialOrd<Authority> for str {
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
359impl<'a> PartialOrd<Authority> for &'a str {
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
367impl<'a> PartialOrd<&'a str> for Authority {
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
375impl PartialOrd<String> for Authority {
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
383impl PartialOrd<Authority> for String {
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
391impl Hash for Authority {
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
425impl<'a> TryFrom<&'a [u8]> for Authority {
426 type Error = InvalidUri;
427 #[inline]
428 fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
429 create_authority(s, |s| Bytes::copy_from_slice(s))
434 }
435}
436
437impl<'a> TryFrom<&'a str> for Authority {
438 type Error = InvalidUri;
439 #[inline]
440 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
441 TryFrom::try_from(s.as_bytes())
442 }
443}
444
445impl FromStr for Authority {
446 type Err = InvalidUri;
447
448 fn from_str(s: &str) -> Result<Self, InvalidUri> {
449 TryFrom::try_from(s)
450 }
451}
452
453impl fmt::Debug for Authority {
454 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455 f.write_str(self.as_str())
456 }
457}
458
459impl fmt::Display for Authority {
460 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461 f.write_str(self.as_str())
462 }
463}
464
465fn host(auth: &str) -> &str {
466 let host_port = auth
467 .rsplitn(2, '@')
468 .next()
469 .expect("split always has at least 1 item");
470
471 if host_port.as_bytes()[0] == b'[' {
472 let i = host_port
473 .find(']')
474 .expect("parsing should validate brackets");
475 &host_port[0..i + 1]
477 } else {
478 host_port
479 .split(':')
480 .next()
481 .expect("split always has at least 1 item")
482 }
483}
484
485fn create_authority<B, F>(b: B, f: F) -> Result<Authority, InvalidUri>
488where
489 B: AsRef<[u8]>,
490 F: FnOnce(B) -> Bytes,
491{
492 let s = b.as_ref();
493 let authority_end = Authority::parse_non_empty(s)?;
494
495 if authority_end != s.len() {
496 return Err(ErrorKind::InvalidUriChar.into());
497 }
498
499 let bytes = f(b);
500
501 Ok(Authority {
502 data: unsafe { ByteStr::from_utf8_unchecked(bytes) },
506 })
507}
508
509#[cfg(test)]
510mod tests {
511 use super::*;
512
513 #[test]
514 fn parse_empty_string_is_error() {
515 let err = Authority::parse_non_empty(b"").unwrap_err();
516 assert_eq!(err.0, ErrorKind::Empty);
517 }
518
519 #[test]
520 fn equal_to_self_of_same_authority() {
521 let authority1: Authority = "example.com".parse().unwrap();
522 let authority2: Authority = "EXAMPLE.COM".parse().unwrap();
523 assert_eq!(authority1, authority2);
524 assert_eq!(authority2, authority1);
525 }
526
527 #[test]
528 fn not_equal_to_self_of_different_authority() {
529 let authority1: Authority = "example.com".parse().unwrap();
530 let authority2: Authority = "test.com".parse().unwrap();
531 assert_ne!(authority1, authority2);
532 assert_ne!(authority2, authority1);
533 }
534
535 #[test]
536 fn equates_with_a_str() {
537 let authority: Authority = "example.com".parse().unwrap();
538 assert_eq!(&authority, "EXAMPLE.com");
539 assert_eq!("EXAMPLE.com", &authority);
540 assert_eq!(authority, "EXAMPLE.com");
541 assert_eq!("EXAMPLE.com", authority);
542 }
543
544 #[test]
545 fn from_static_equates_with_a_str() {
546 let authority = Authority::from_static("example.com");
547 assert_eq!(authority, "example.com");
548 }
549
550 #[test]
551 fn not_equal_with_a_str_of_a_different_authority() {
552 let authority: Authority = "example.com".parse().unwrap();
553 assert_ne!(&authority, "test.com");
554 assert_ne!("test.com", &authority);
555 assert_ne!(authority, "test.com");
556 assert_ne!("test.com", authority);
557 }
558
559 #[test]
560 fn equates_with_a_string() {
561 let authority: Authority = "example.com".parse().unwrap();
562 assert_eq!(authority, "EXAMPLE.com".to_string());
563 assert_eq!("EXAMPLE.com".to_string(), authority);
564 }
565
566 #[test]
567 fn equates_with_a_string_of_a_different_authority() {
568 let authority: Authority = "example.com".parse().unwrap();
569 assert_ne!(authority, "test.com".to_string());
570 assert_ne!("test.com".to_string(), authority);
571 }
572
573 #[test]
574 fn compares_to_self() {
575 let authority1: Authority = "abc.com".parse().unwrap();
576 let authority2: Authority = "def.com".parse().unwrap();
577 assert!(authority1 < authority2);
578 assert!(authority2 > authority1);
579 }
580
581 #[test]
582 fn compares_with_a_str() {
583 let authority: Authority = "def.com".parse().unwrap();
584 assert!(&authority < "ghi.com");
586 assert!("ghi.com" > &authority);
587 assert!(&authority > "abc.com");
588 assert!("abc.com" < &authority);
589
590 assert!(authority < "ghi.com");
592 assert!("ghi.com" > authority);
593 assert!(authority > "abc.com");
594 assert!("abc.com" < authority);
595 }
596
597 #[test]
598 fn compares_with_a_string() {
599 let authority: Authority = "def.com".parse().unwrap();
600 assert!(authority < "ghi.com".to_string());
601 assert!("ghi.com".to_string() > authority);
602 assert!(authority > "abc.com".to_string());
603 assert!("abc.com".to_string() < authority);
604 }
605
606 #[test]
607 fn allows_percent_in_userinfo() {
608 let authority_str = "a%2f:b%2f@example.com";
609 let authority: Authority = authority_str.parse().unwrap();
610 assert_eq!(authority, authority_str);
611 }
612
613 #[test]
614 fn rejects_percent_in_hostname() {
615 let err = Authority::parse_non_empty(b"example%2f.com").unwrap_err();
616 assert_eq!(err.0, ErrorKind::InvalidAuthority);
617
618 let err = Authority::parse_non_empty(b"a%2f:b%2f@example%2f.com").unwrap_err();
619 assert_eq!(err.0, ErrorKind::InvalidAuthority);
620 }
621
622 #[test]
623 fn allows_percent_in_ipv6_address() {
624 let authority_str = "[fe80::1:2:3:4%25eth0]";
625 let result: Authority = authority_str.parse().unwrap();
626 assert_eq!(result, authority_str);
627 }
628
629 #[test]
630 fn rejects_percent_outside_ipv6_address() {
631 let err = Authority::parse_non_empty(b"1234%20[fe80::1:2:3:4]").unwrap_err();
632 assert_eq!(err.0, ErrorKind::InvalidAuthority);
633
634 let err = Authority::parse_non_empty(b"[fe80::1:2:3:4]%20").unwrap_err();
635 assert_eq!(err.0, ErrorKind::InvalidAuthority);
636 }
637
638 #[test]
639 fn rejects_invalid_utf8() {
640 let err = Authority::try_from([0xc0u8].as_ref()).unwrap_err();
641 assert_eq!(err.0, ErrorKind::InvalidUriChar);
642
643 let err = Authority::from_shared(Bytes::from_static([0xc0u8].as_ref()))
644 .unwrap_err();
645 assert_eq!(err.0, ErrorKind::InvalidUriChar);
646 }
647
648 #[test]
649 fn rejects_invalid_use_of_brackets() {
650 let err = Authority::parse_non_empty(b"[]@[").unwrap_err();
651 assert_eq!(err.0, ErrorKind::InvalidAuthority);
652 }
653}