1use core::{
2 cmp::Ordering,
3 hash::{Hash, Hasher},
4};
5
6use crate::{Port, Uri};
7
8#[cfg(feature = "std")]
9use crate::{InvalidUri, PathContext, UriBuf};
10
11use super::{Authority, Fragment, Host, Path, Query, Scheme, UserInfo};
12
13#[cfg(feature = "std")]
14use super::{
15 AuthorityMut, InvalidAuthority, InvalidFragment, InvalidPath, InvalidQuery, PathBuf, PathMut,
16 Segment,
17};
18
19#[derive(static_automata::Validate, str_newtype::StrNewType)]
21#[automaton(super::grammar::UriRef)]
22#[newtype(name = "URI reference", ord([u8], &[u8], str, &str))]
23#[cfg_attr(
24 feature = "std",
25 newtype(ord(Vec<u8>, String), owned(UriRefBuf, derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash)))
26)]
27#[cfg_attr(feature = "serde", newtype(serde))]
28pub struct UriRef(str);
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
36pub struct UriRefParts<'a> {
37 pub scheme: Option<&'a Scheme>,
39
40 pub authority: Option<&'a Authority>,
45
46 pub path: &'a Path,
50
51 pub query: Option<&'a Query>,
53
54 pub fragment: Option<&'a Fragment>,
56}
57
58impl Default for &UriRef {
59 fn default() -> Self {
60 <UriRef>::EMPTY
61 }
62}
63
64impl UriRef {
65 pub const EMPTY: &'static Self = unsafe { Self::new_unchecked("") };
67
68 pub fn parts(&self) -> UriRefParts<'_> {
89 let bytes = self.as_bytes();
90 let ranges = crate::common::parse::reference_parts(bytes, 0);
91
92 UriRefParts {
93 scheme: ranges
94 .scheme
95 .map(|r| unsafe { Scheme::new_unchecked_from_bytes(&bytes[r]) }),
96 authority: ranges
97 .authority
98 .map(|r| unsafe { Authority::new_unchecked(&self.0[r]) }),
99 path: unsafe { Path::new_unchecked(&self.0[ranges.path]) },
100 query: ranges
101 .query
102 .map(|r| unsafe { Query::new_unchecked(&self.0[r]) }),
103 fragment: ranges
104 .fragment
105 .map(|r| unsafe { Fragment::new_unchecked(&self.0[r]) }),
106 }
107 }
108
109 #[inline]
123 pub fn scheme(&self) -> Option<&Scheme> {
124 let bytes = self.as_bytes();
125 crate::common::parse::find_scheme(bytes, 0)
126 .map(|range| unsafe { Scheme::new_unchecked_from_bytes(&bytes[range]) })
127 }
128
129 #[cfg(feature = "std")]
142 pub fn with_scheme(&self, scheme: &Scheme) -> UriBuf {
143 self.to_owned().into_with_scheme(scheme)
144 }
145
146 #[cfg(feature = "std")]
158 pub fn with_authority(&self, authority: Option<&Authority>) -> UriRefBuf {
159 let mut buf = self.to_owned();
160 buf.set_authority(authority);
161 buf
162 }
163
164 #[cfg(feature = "std")]
176 pub fn with_path(&self, path: &Path) -> UriRefBuf {
177 let mut buf = self.to_owned();
178 buf.set_path(path);
179 buf
180 }
181
182 #[cfg(feature = "std")]
194 pub fn with_query(&self, query: Option<&Query>) -> UriRefBuf {
195 let mut buf = self.to_owned();
196 buf.set_query(query);
197 buf
198 }
199
200 #[cfg(feature = "std")]
212 pub fn with_fragment(&self, fragment: Option<&Fragment>) -> UriRefBuf {
213 let mut buf = self.to_owned();
214 buf.set_fragment(fragment);
215 buf
216 }
217
218 pub fn authority(&self) -> Option<&Authority> {
232 let bytes = self.as_bytes();
233 crate::common::parse::find_authority(bytes, 0)
234 .ok()
235 .map(|range| unsafe { Authority::new_unchecked_from_bytes(&bytes[range]) })
236 }
237
238 pub fn host(&self) -> Option<&Host> {
252 self.authority().map(Authority::host)
253 }
254
255 pub fn user_info(&self) -> Option<&UserInfo> {
269 self.authority().and_then(Authority::user_info)
270 }
271
272 pub fn port(&self) -> Option<&Port> {
286 self.authority().and_then(Authority::port)
287 }
288
289 pub fn path(&self) -> &Path {
305 let bytes = self.as_bytes();
306 let range = crate::common::parse::find_path(bytes, 0);
307 unsafe { Path::new_unchecked_from_bytes(&bytes[range]) }
308 }
309
310 pub fn query(&self) -> Option<&Query> {
312 let bytes = self.as_bytes();
313 crate::common::parse::find_query(bytes, 0)
314 .ok()
315 .map(|range| unsafe { Query::new_unchecked_from_bytes(&bytes[range]) })
316 }
317
318 pub fn fragment(&self) -> Option<&Fragment> {
320 let bytes = self.as_bytes();
321 crate::common::parse::find_fragment(bytes, 0)
322 .ok()
323 .map(|range| unsafe { Fragment::new_unchecked_from_bytes(&bytes[range]) })
324 }
325
326 pub fn without_fragment(&self) -> &Self {
344 let bytes = self.as_bytes();
345 match crate::common::parse::find_fragment(bytes, 0) {
346 Ok(range) => unsafe { Self::new_unchecked_from_bytes(&bytes[..range.start - 1]) },
347 Err(_) => self,
348 }
349 }
350
351 pub fn without_query_and_fragment(&self) -> &Self {
374 let bytes = self.as_bytes();
375 let end = match crate::common::parse::find_query(bytes, 0) {
376 Ok(range) => range.start - 1,
377 Err(i) => i,
378 };
379 unsafe { Self::new_unchecked_from_bytes(&bytes[..end]) }
380 }
381
382 #[cfg(feature = "std")]
401 #[inline]
402 pub fn relative_to(&self, other: &Self) -> UriRefBuf {
403 let mut result = <UriRefBuf>::default();
404
405 match (self.scheme(), other.scheme()) {
410 (Some(a), Some(b)) if a == b => (),
411 (None, _) => (),
412 _ => return unsafe { <UriRefBuf>::new_unchecked(self.as_bytes().to_vec()) },
413 }
414
415 match (self.authority(), other.authority()) {
416 (Some(a), Some(b)) if a == b => (),
417 (None, None) => (),
418 _ => return unsafe { <UriRefBuf>::new_unchecked(self.as_bytes().to_vec()) },
419 }
420
421 let self_path = self.path();
422 let base_path = other.path();
423
424 let mut self_segments = self_path.normalized_segments().peekable();
425 let mut base_segments = base_path.parent_or_empty().normalized_segments().peekable();
426
427 if self_path.is_absolute() == base_path.is_absolute() {
428 loop {
429 match (self_segments.peek(), base_segments.peek()) {
430 (Some(a), Some(b)) if a == b => {
431 base_segments.next();
432 self_segments.next();
433 }
434 _ => break,
435 }
436 }
437 }
438
439 for _ in base_segments {
440 result.path_mut().lazy_push(Segment::PARENT);
441 }
442
443 if self_path.is_absolute() && base_path == Path::EMPTY_RELATIVE {
444 result.set_path(Path::EMPTY_ABSOLUTE);
445 }
446
447 for segment in self_segments {
448 result.path_mut().lazy_push(segment);
449 }
450
451 if (self.query().is_some() || self.fragment().is_some())
452 && Some(result.path().as_bytes()) == other.path().last().map(|s| s.as_bytes())
453 {
454 result.path_mut().clear();
455 }
456
457 result.set_query(self.query());
458 result.set_fragment(self.fragment());
459
460 result
461 }
462
463 #[cfg(feature = "std")]
486 #[inline]
487 pub fn suffix(
488 &self,
489 prefix: impl AsRef<Self>,
490 ) -> Option<(PathBuf, Option<&Query>, Option<&Fragment>)> {
491 let prefix = prefix.as_ref();
492 if self.scheme() == prefix.scheme() && self.authority() == prefix.authority() {
493 self.path()
494 .suffix(prefix.path())
495 .map(|suffix_path| (suffix_path, self.query(), self.fragment()))
496 } else {
497 None
498 }
499 }
500
501 #[inline]
512 pub fn base(&self) -> &Self {
513 let bytes = self.as_bytes();
514 let path_range = crate::common::parse::find_path(bytes, 0);
515 let path_start = path_range.start;
516 let path = unsafe { Path::new_unchecked_from_bytes(&bytes[path_range]) };
517
518 let directory_path = path.directory();
519 let end = path_start + directory_path.len();
520 unsafe { Self::new_unchecked_from_bytes(&bytes[..end]) }
521 }
522
523 #[cfg(feature = "std")]
528 #[inline]
529 pub fn resolved(&self, base_iri: impl AsRef<Uri>) -> UriBuf {
530 let iri_ref = self.to_owned();
531 iri_ref.into_resolved(base_iri)
532 }
533
534 #[cfg(feature = "std")]
539 pub fn try_resolved<'r>(
540 &self,
541 base_iri: &'r str,
542 ) -> Result<UriBuf, <&'r Uri as TryFrom<&'r str>>::Error> {
543 Uri::new(base_iri).map(|u| self.resolved(u))
544 }
545
546 #[inline]
563 pub fn as_uri(&self) -> Option<&Uri> {
564 if self.scheme().is_some() {
565 Some(unsafe { Uri::new_unchecked(&self.0) })
566 } else {
567 None
568 }
569 }
570}
571
572#[macro_export]
574macro_rules! uri_ref {
575 ($value:literal) => {
576 match $crate::uri::UriRef::from_str($value) {
577 Ok(value) => value,
578 Err(_) => panic!("invalid URI reference"),
579 }
580 };
581}
582
583impl PartialEq for UriRef {
584 fn eq(&self, other: &Self) -> bool {
585 self.parts() == other.parts()
586 }
587}
588
589impl<'a> PartialEq<&'a UriRef> for UriRef {
590 fn eq(&self, other: &&'a Self) -> bool {
591 *self == **other
592 }
593}
594
595impl PartialEq<Uri> for UriRef {
596 fn eq(&self, other: &Uri) -> bool {
597 *self == *other.as_uri_ref()
598 }
599}
600
601impl<'a> PartialEq<&'a Uri> for UriRef {
602 fn eq(&self, other: &&'a Uri) -> bool {
603 *self == *other.as_uri_ref()
604 }
605}
606
607#[cfg(feature = "std")]
608impl PartialEq<UriBuf> for UriRef {
609 fn eq(&self, other: &UriBuf) -> bool {
610 *self == *other.as_uri_ref()
611 }
612}
613
614impl Eq for UriRef {}
615
616impl PartialOrd for UriRef {
617 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
618 Some(self.cmp(other))
619 }
620}
621
622impl<'a> PartialOrd<&'a UriRef> for UriRef {
623 fn partial_cmp(&self, other: &&'a Self) -> Option<Ordering> {
624 self.partial_cmp(*other)
625 }
626}
627
628impl PartialOrd<Uri> for UriRef {
629 fn partial_cmp(&self, other: &Uri) -> Option<Ordering> {
630 self.partial_cmp(other.as_uri_ref())
631 }
632}
633
634impl<'a> PartialOrd<&'a Uri> for UriRef {
635 fn partial_cmp(&self, other: &&'a Uri) -> Option<Ordering> {
636 self.partial_cmp(other.as_uri_ref())
637 }
638}
639
640#[cfg(feature = "std")]
641impl PartialOrd<UriBuf> for UriRef {
642 fn partial_cmp(&self, other: &UriBuf) -> Option<Ordering> {
643 self.partial_cmp(other.as_uri_ref())
644 }
645}
646
647impl Ord for UriRef {
648 fn cmp(&self, other: &Self) -> Ordering {
649 self.parts().cmp(&other.parts())
650 }
651}
652
653impl Hash for UriRef {
654 fn hash<H: Hasher>(&self, state: &mut H) {
655 self.parts().hash(state)
656 }
657}
658
659impl<'a> From<&'a Uri> for &'a UriRef {
660 fn from(value: &'a Uri) -> Self {
661 value.as_uri_ref()
662 }
663}
664
665#[cfg(feature = "std")]
666impl UriRefBuf {
667 #[inline]
668 unsafe fn replace(&mut self, range: core::ops::Range<usize>, content: &[u8]) {
669 crate::utils::replace(unsafe { self.as_mut_vec() }, range, content)
670 }
671
672 #[inline]
673 unsafe fn allocate(&mut self, range: core::ops::Range<usize>, len: usize) {
674 crate::utils::allocate_range(unsafe { self.as_mut_vec() }, range, len)
675 }
676
677 #[inline]
696 pub fn authority_mut(&mut self) -> Option<AuthorityMut<'_>> {
697 crate::common::parse::find_authority(self.as_bytes(), 0)
698 .ok()
699 .map(|range| unsafe { AuthorityMut::new_unchecked(self.as_mut_vec(), range) })
700 }
701
702 #[inline]
733 pub fn set_authority(&mut self, authority: Option<&Authority>) {
734 let bytes = self.as_bytes();
735 match authority {
736 Some(new_authority) => match crate::common::parse::find_authority(bytes, 0) {
737 Ok(range) => unsafe { self.replace(range, new_authority.as_bytes()) },
738 Err(start) => {
739 if !bytes[start..].starts_with(b"/") {
740 unsafe {
743 self.allocate(start..start, new_authority.len() + 3);
744 let bytes = self.as_mut_vec();
745 let delim_end = start + 2;
746 bytes[start..delim_end].copy_from_slice(b"//");
747 bytes[delim_end..(delim_end + new_authority.len())]
748 .copy_from_slice(new_authority.as_bytes());
749 bytes[delim_end + new_authority.len()] = b'/';
750 }
751 } else {
752 unsafe {
753 self.allocate(start..start, new_authority.len() + 2);
754 let bytes = self.as_mut_vec();
755 let delim_end = start + 2;
756 bytes[start..delim_end].copy_from_slice(b"//");
757 bytes[delim_end..(delim_end + new_authority.len())]
758 .copy_from_slice(new_authority.as_bytes())
759 }
760 }
761 }
762 },
763 None => {
764 if let Ok(range) = crate::common::parse::find_authority(bytes, 0) {
765 let value: &[u8] = if bytes[range.end..].starts_with(b"//") {
766 b"/."
771 } else {
772 b""
773 };
774
775 unsafe {
776 self.replace((range.start - 2)..range.end, value);
777 }
778 }
779 }
780 }
781 }
782
783 pub fn try_set_authority<'s>(
804 &mut self,
805 authority: Option<&'s str>,
806 ) -> Result<(), InvalidAuthority<&'s str>> {
807 self.set_authority(authority.map(TryInto::try_into).transpose()?);
808 Ok(())
809 }
810
811 #[inline]
829 pub fn path_mut(&mut self) -> PathMut<'_> {
830 let range = crate::common::parse::find_path(self.as_bytes(), 0);
831 unsafe { PathMut::new_unchecked(self.as_mut_vec(), range) }
832 }
833
834 #[inline]
875 pub fn set_path(&mut self, path: &Path) {
876 self.path_mut().replace(path);
877 }
878
879 pub fn try_set_path<'s>(&mut self, path: &'s str) -> Result<(), InvalidPath<&'s str>> {
884 self.set_path(path.try_into()?);
885 Ok(())
886 }
887
888 pub fn set_and_normalize_path(&mut self, path: &Path) {
890 self.set_path(path);
891 self.path_mut().normalize();
892 }
893
894 #[inline]
913 pub fn set_query(&mut self, query: Option<&Query>) {
914 match query {
915 Some(new_query) => match crate::common::parse::find_query(self.as_bytes(), 0) {
916 Ok(range) => unsafe { self.replace(range, new_query.as_bytes()) },
917 Err(start) => unsafe {
918 self.allocate(start..start, new_query.len() + 1);
919 let bytes = self.as_mut_vec();
920 let delim_end = start + 1;
921 bytes[start] = b'?';
922 bytes[delim_end..(delim_end + new_query.len())]
923 .copy_from_slice(new_query.as_bytes())
924 },
925 },
926 None => {
927 if let Ok(range) = crate::common::parse::find_query(self.as_bytes(), 0) {
928 unsafe {
929 self.replace((range.start - 1)..range.end, b"");
930 }
931 }
932 }
933 }
934 }
935
936 pub fn try_set_query<'s>(
941 &mut self,
942 query: Option<&'s str>,
943 ) -> Result<(), InvalidQuery<&'s str>> {
944 self.set_query(query.map(TryInto::try_into).transpose()?);
945 Ok(())
946 }
947
948 #[inline]
967 pub fn set_fragment(&mut self, fragment: Option<&Fragment>) {
968 match fragment {
969 Some(new_fragment) => match crate::common::parse::find_fragment(self.as_bytes(), 0) {
970 Ok(range) => unsafe { self.replace(range, new_fragment.as_bytes()) },
971 Err(start) => unsafe {
972 self.allocate(start..start, new_fragment.len() + 1);
973 let bytes = self.as_mut_vec();
974 let delim_end = start + 1;
975 bytes[start] = b'#';
976 bytes[delim_end..(delim_end + new_fragment.len())]
977 .copy_from_slice(new_fragment.as_bytes())
978 },
979 },
980 None => {
981 if let Ok(range) = crate::common::parse::find_fragment(self.as_bytes(), 0) {
982 unsafe {
983 self.replace((range.start - 1)..range.end, b"");
984 }
985 }
986 }
987 }
988 }
989
990 pub fn try_set_fragment<'s>(
995 &mut self,
996 fragment: Option<&'s str>,
997 ) -> Result<(), InvalidFragment<&'s str>> {
998 self.set_fragment(fragment.map(TryInto::try_into).transpose()?);
999 Ok(())
1000 }
1001
1002 #[inline]
1026 pub fn set_scheme(&mut self, scheme: Option<&Scheme>) {
1027 match scheme {
1028 Some(new_scheme) => match crate::common::parse::find_scheme(self.as_bytes(), 0) {
1029 Some(scheme_range) => unsafe {
1030 self.replace(scheme_range, new_scheme.as_bytes());
1031 },
1032 None => unsafe {
1033 self.allocate(0..0, new_scheme.len() + 1);
1034 let bytes = self.as_mut_vec();
1035 bytes[0..new_scheme.len()].copy_from_slice(new_scheme.as_bytes());
1036 bytes[new_scheme.len()] = b':'
1037 },
1038 },
1039 None => {
1040 if let Some(scheme_range) = crate::common::parse::find_scheme(self.as_bytes(), 0) {
1041 let value: &[u8] =
1042 if self.authority().is_none() && self.path().looks_like_scheme() {
1043 b"./"
1047 } else {
1048 b""
1049 };
1050
1051 unsafe { self.replace(scheme_range.start..(scheme_range.end + 1), value) }
1052 }
1053 }
1054 }
1055 }
1056
1057 pub fn try_set_scheme<'s>(
1063 &mut self,
1064 scheme: Option<&'s str>,
1065 ) -> Result<(), super::InvalidScheme<&'s str>> {
1066 self.set_scheme(scheme.map(TryInto::try_into).transpose()?);
1067 Ok(())
1068 }
1069
1070 pub fn into_with_scheme(mut self, scheme: &Scheme) -> UriBuf {
1072 self.set_scheme(Some(scheme));
1073 unsafe { UriBuf::new_unchecked(self.0) }
1074 }
1075
1076 pub fn try_into_with_scheme(
1083 mut self,
1084 scheme: &str,
1085 ) -> Result<UriBuf, (Self, super::InvalidScheme<&str>)> {
1086 match self.try_set_scheme(Some(scheme)) {
1087 Ok(_) => Ok(unsafe { UriBuf::new_unchecked(self.0) }),
1088 Err(e) => Err((self, e)),
1089 }
1090 }
1091
1092 pub fn resolve(&mut self, base_iri: impl AsRef<Uri>) {
1115 let base_iri = base_iri.as_ref();
1116 let parts = crate::common::parse::reference_parts(self.as_bytes(), 0);
1117
1118 if parts.scheme.is_some() {
1119 self.path_mut().normalize();
1120 } else {
1121 self.set_scheme(Some(base_iri.scheme()));
1122 if parts.authority.is_some() {
1123 self.path_mut().normalize();
1124 } else if self.path().is_relative() && self.path().is_empty() {
1125 self.set_authority(base_iri.authority());
1126 self.set_path(base_iri.path());
1127 if self.query().is_none() {
1128 self.set_query(base_iri.query());
1129 }
1130 } else if self.path().is_absolute() {
1131 self.set_authority(base_iri.authority());
1132 self.path_mut().normalize();
1133 } else {
1134 self.set_authority(base_iri.authority());
1135
1136 let base_path = base_iri.path();
1137 let mut path = if base_path.is_empty() && base_iri.authority().is_some() {
1138 Path::EMPTY_ABSOLUTE.to_owned()
1139 } else {
1140 base_path.parent_or_empty().to_owned()
1141 };
1142
1143 let mut path_mut = PathMut::from_path_with_context(
1144 &mut path,
1145 PathContext {
1146 has_scheme: false,
1148 has_authority: false,
1149 },
1150 );
1151
1152 for s in self.path().segments() {
1153 path_mut.lazy_push(s);
1154 }
1155
1156 path_mut.normalize();
1157
1158 self.set_path(&path);
1159 }
1160 }
1161 }
1162
1163 pub fn try_resolve<'r>(
1168 &mut self,
1169 base_iri: &'r str,
1170 ) -> Result<(), <&'r Uri as TryFrom<&'r str>>::Error> {
1171 self.resolve(Uri::new(base_iri)?);
1172 Ok(())
1173 }
1174
1175 pub fn into_resolved(mut self, base_iri: impl AsRef<Uri>) -> UriBuf {
1191 self.resolve(base_iri);
1192 unsafe { <UriBuf>::new_unchecked(self.into_bytes()) }
1193 }
1194
1195 pub fn try_into_resolved(
1200 mut self,
1201 base_iri: &str,
1202 ) -> Result<UriBuf, (Self, <&Uri as TryFrom<&str>>::Error)> {
1203 match self.try_resolve(base_iri) {
1204 Ok(_) => Ok(unsafe { <UriBuf>::new_unchecked(self.into_bytes()) }),
1205 Err(e) => Err((self, e)),
1206 }
1207 }
1208
1209 pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8> {
1217 unsafe { self.0.as_mut_vec() }
1218 }
1219
1220 pub fn try_into_uri(self) -> Result<UriBuf, InvalidUri<Self>> {
1237 if self.scheme().is_some() {
1238 unsafe { Ok(UriBuf::new_unchecked(self.0)) }
1239 } else {
1240 Err(InvalidUri(self))
1241 }
1242 }
1243}
1244
1245#[cfg(feature = "std")]
1246impl TryFrom<UriRefBuf> for UriBuf {
1247 type Error = InvalidUri<UriRefBuf>;
1248
1249 fn try_from(value: UriRefBuf) -> Result<Self, Self::Error> {
1250 value.try_into_uri()
1251 }
1252}
1253
1254#[cfg(feature = "std")]
1255impl PartialEq<Uri> for UriRefBuf {
1256 fn eq(&self, other: &Uri) -> bool {
1257 *self.as_uri_ref() == *other.as_uri_ref()
1258 }
1259}
1260
1261#[cfg(feature = "std")]
1262impl<'a> PartialEq<&'a Uri> for UriRefBuf {
1263 fn eq(&self, other: &&'a Uri) -> bool {
1264 *self.as_uri_ref() == *other.as_uri_ref()
1265 }
1266}
1267
1268#[cfg(feature = "std")]
1269impl PartialEq<UriBuf> for UriRefBuf {
1270 fn eq(&self, other: &UriBuf) -> bool {
1271 *self.as_uri_ref() == *other.as_uri_ref()
1272 }
1273}
1274
1275#[cfg(feature = "std")]
1276impl PartialOrd<Uri> for UriRefBuf {
1277 fn partial_cmp(&self, other: &Uri) -> Option<Ordering> {
1278 self.as_uri_ref().partial_cmp(other.as_uri_ref())
1279 }
1280}
1281
1282#[cfg(feature = "std")]
1283impl<'a> PartialOrd<&'a Uri> for UriRefBuf {
1284 fn partial_cmp(&self, other: &&'a Uri) -> Option<Ordering> {
1285 self.as_uri_ref().partial_cmp(other.as_uri_ref())
1286 }
1287}
1288
1289#[cfg(feature = "std")]
1290impl PartialOrd<UriBuf> for UriRefBuf {
1291 fn partial_cmp(&self, other: &UriBuf) -> Option<Ordering> {
1292 self.as_uri_ref().partial_cmp(other.as_uri_ref())
1293 }
1294}
1295
1296#[cfg(test)]
1297mod tests {
1298 use super::*;
1299
1300 const PARTS: [(
1301 &[u8],
1302 (
1303 Option<&[u8]>,
1304 Option<&[u8]>,
1305 &[u8],
1306 Option<&[u8]>,
1307 Option<&[u8]>,
1308 ),
1309 ); 38] = [
1310 (b"", (None, None, b"", None, None)),
1312 (b"a/:", (None, None, b"a/:", None, None)),
1313 (b"scheme:", (Some(b"scheme"), None, b"", None, None)),
1315 (b"//authority", (None, Some(b"authority"), b"", None, None)),
1316 (b"path", (None, None, b"path", None, None)),
1317 (b"/path", (None, None, b"/path", None, None)),
1318 (b"/", (None, None, b"/", None, None)),
1319 (b"foo//bar", (None, None, b"foo//bar", None, None)),
1320 (b"?query", (None, None, b"", Some(b"query"), None)),
1321 (b"#fragment", (None, None, b"", None, Some(b"fragment"))),
1322 (
1323 b"scheme:?query",
1324 (Some(b"scheme"), None, b"", Some(b"query"), None),
1325 ),
1326 (b"//[::]", (None, Some(b"[::]"), b"", None, None)),
1327 (
1329 b"scheme://authority",
1330 (Some(b"scheme"), Some(b"authority"), b"", None, None),
1331 ),
1332 (b"scheme:path", (Some(b"scheme"), None, b"path", None, None)),
1333 (
1334 b"scheme:/path",
1335 (Some(b"scheme"), None, b"/path", None, None),
1336 ),
1337 (
1338 b"scheme:?query",
1339 (Some(b"scheme"), None, b"", Some(b"query"), None),
1340 ),
1341 (
1342 b"scheme:#fragment",
1343 (Some(b"scheme"), None, b"", None, Some(b"fragment")),
1344 ),
1345 (
1346 b"//authority/path",
1347 (None, Some(b"authority"), b"/path", None, None),
1348 ),
1349 (
1350 b"//authority?query",
1351 (None, Some(b"authority"), b"", Some(b"query"), None),
1352 ),
1353 (
1354 b"//authority#fragment",
1355 (None, Some(b"authority"), b"", None, Some(b"fragment")),
1356 ),
1357 (b"path?query", (None, None, b"path", Some(b"query"), None)),
1358 (b"/path?query", (None, None, b"/path", Some(b"query"), None)),
1359 (
1360 b"path#fragment",
1361 (None, None, b"path", None, Some(b"fragment")),
1362 ),
1363 (
1364 b"?query#fragment",
1365 (None, None, b"", Some(b"query"), Some(b"fragment")),
1366 ),
1367 (
1369 b"scheme://authority/path",
1370 (Some(b"scheme"), Some(b"authority"), b"/path", None, None),
1371 ),
1372 (
1373 b"scheme://authority?query",
1374 (
1375 Some(b"scheme"),
1376 Some(b"authority"),
1377 b"",
1378 Some(b"query"),
1379 None,
1380 ),
1381 ),
1382 (
1383 b"scheme://authority#fragment",
1384 (
1385 Some(b"scheme"),
1386 Some(b"authority"),
1387 b"",
1388 None,
1389 Some(b"fragment"),
1390 ),
1391 ),
1392 (
1393 b"scheme:path?query",
1394 (Some(b"scheme"), None, b"path", Some(b"query"), None),
1395 ),
1396 (
1397 b"scheme:path#fragment",
1398 (Some(b"scheme"), None, b"path", None, Some(b"fragment")),
1399 ),
1400 (
1401 b"//authority/path?query",
1402 (None, Some(b"authority"), b"/path", Some(b"query"), None),
1403 ),
1404 (
1405 b"//authority/path#fragment",
1406 (None, Some(b"authority"), b"/path", None, Some(b"fragment")),
1407 ),
1408 (
1409 b"//authority?query#fragment",
1410 (
1411 None,
1412 Some(b"authority"),
1413 b"",
1414 Some(b"query"),
1415 Some(b"fragment"),
1416 ),
1417 ),
1418 (
1419 b"path?query#fragment",
1420 (None, None, b"path", Some(b"query"), Some(b"fragment")),
1421 ),
1422 (
1424 b"scheme://authority/path?query",
1425 (
1426 Some(b"scheme"),
1427 Some(b"authority"),
1428 b"/path",
1429 Some(b"query"),
1430 None,
1431 ),
1432 ),
1433 (
1434 b"scheme://authority/path#fragment",
1435 (
1436 Some(b"scheme"),
1437 Some(b"authority"),
1438 b"/path",
1439 None,
1440 Some(b"fragment"),
1441 ),
1442 ),
1443 (
1444 b"scheme://authority?query#fragment",
1445 (
1446 Some(b"scheme"),
1447 Some(b"authority"),
1448 b"",
1449 Some(b"query"),
1450 Some(b"fragment"),
1451 ),
1452 ),
1453 (
1454 b"scheme:path?query#fragment",
1455 (
1456 Some(b"scheme"),
1457 None,
1458 b"path",
1459 Some(b"query"),
1460 Some(b"fragment"),
1461 ),
1462 ),
1463 (
1465 b"scheme://authority/path?query#fragment",
1466 (
1467 Some(b"scheme"),
1468 Some(b"authority"),
1469 b"/path",
1470 Some(b"query"),
1471 Some(b"fragment"),
1472 ),
1473 ),
1474 ];
1475
1476 #[test]
1477 fn parts() {
1478 for (input, expected) in PARTS {
1479 let input = UriRef::new(input).unwrap();
1480 let parts = input.parts();
1481
1482 assert_eq!(parts.scheme.map(Scheme::as_bytes), expected.0);
1483 assert_eq!(parts.authority.map(Authority::as_bytes), expected.1);
1484 assert_eq!(parts.path.as_bytes(), expected.2);
1485 assert_eq!(parts.query.map(Query::as_bytes), expected.3);
1486 assert_eq!(parts.fragment.map(Fragment::as_bytes), expected.4)
1487 }
1488 }
1489
1490 #[test]
1491 fn scheme() {
1492 for (input, expected) in PARTS {
1493 let input = UriRef::new(input).unwrap();
1494 assert_eq!(input.scheme().map(Scheme::as_bytes), expected.0)
1495 }
1496 }
1497
1498 #[test]
1499 fn authority() {
1500 for (input, expected) in PARTS {
1501 let input = UriRef::new(input).unwrap();
1502 assert_eq!(input.authority().map(Authority::as_bytes), expected.1)
1504 }
1505 }
1506
1507 #[test]
1508 fn authority_port() {
1509 let vectors: &[(&str, Option<&str>)] = &[("//[::]", None)];
1510
1511 for (input, expected) in vectors {
1512 let uri = UriRef::new(input).unwrap();
1513 assert_eq!(
1514 uri.authority().and_then(|a| a.port()).map(|p| p.as_str()),
1515 *expected,
1516 "input: {input}"
1517 );
1518 }
1519 }
1520
1521 #[test]
1522 fn set_authority() {
1523 let vectors: [(&[u8], Option<&[u8]>, &[u8]); 3] = [
1524 (
1525 b"scheme:/path",
1526 Some(b"authority"),
1527 b"scheme://authority/path",
1528 ),
1529 (
1530 b"scheme:path",
1531 Some(b"authority"),
1532 b"scheme://authority/path",
1533 ),
1534 (b"scheme://authority//path", None, b"scheme:/.//path"),
1535 ];
1536
1537 for (input, authority, expected) in vectors {
1538 let mut buffer = UriRefBuf::new(input.to_vec()).unwrap();
1539 let authority = authority.map(Authority::new).transpose().unwrap();
1540 buffer.set_authority(authority);
1541 assert_eq!(buffer.as_bytes(), expected)
1543 }
1544 }
1545
1546 #[test]
1547 fn path() {
1548 for (input, expected) in PARTS {
1549 let input = UriRef::new(input).unwrap();
1550 assert_eq!(input.path().as_bytes(), expected.2)
1552 }
1553 }
1554
1555 #[test]
1556 fn query() {
1557 for (input, expected) in PARTS {
1558 let input = UriRef::new(input).unwrap();
1559 assert_eq!(input.query().map(Query::as_bytes), expected.3)
1561 }
1562 }
1563
1564 #[test]
1565 fn fragment() {
1566 for (input, expected) in PARTS {
1567 let input = UriRef::new(input).unwrap();
1568 assert_eq!(input.fragment().map(Fragment::as_bytes), expected.4)
1570 }
1571 }
1572
1573 #[test]
1574 fn disambiguate_scheme() {
1575 let mut uri_ref = UriRefBuf::new("scheme:a:b/c".to_string()).unwrap();
1576 uri_ref.set_scheme(None);
1577 assert_eq!(uri_ref.as_str(), "./a:b/c")
1578 }
1579
1580 #[test]
1581 fn disambiguate_authority() {
1582 let mut uri_ref = UriRefBuf::new("//host//path".to_string()).unwrap();
1583 uri_ref.set_authority(None);
1584 assert_eq!(uri_ref.as_str(), "/.//path")
1585 }
1586
1587 fn test_resolution<'a>(base: &str, vectors: impl IntoIterator<Item = (&'a str, &'a str)>) {
1588 let base_uri = Uri::new(base).unwrap();
1589 for (reference, expected) in vectors {
1590 let uri_ref = UriRef::new(reference).unwrap();
1591 let expected_uri = Uri::new(expected).unwrap();
1592
1593 assert_eq!(
1594 uri_ref.resolved(base_uri),
1595 expected_uri,
1596 "({uri_ref}).resolved({base_uri})",
1597 );
1598 assert_eq!(
1599 base_uri.joined(uri_ref),
1600 expected_uri,
1601 "({base_uri}).joined({uri_ref})",
1602 );
1603 }
1604 }
1605
1606 #[test]
1609 fn resolution_normal() {
1610 test_resolution(
1611 "http://a/b/c/d;p?q",
1612 [
1613 ("g:h", "g:h"),
1614 ("g", "http://a/b/c/g"),
1615 ("./g", "http://a/b/c/g"),
1616 ("g/", "http://a/b/c/g/"),
1617 ("/g", "http://a/g"),
1618 ("//g", "http://g"),
1619 ("?y", "http://a/b/c/d;p?y"),
1620 ("g?y", "http://a/b/c/g?y"),
1621 ("#s", "http://a/b/c/d;p?q#s"),
1622 ("g#s", "http://a/b/c/g#s"),
1623 ("g?y#s", "http://a/b/c/g?y#s"),
1624 (";x", "http://a/b/c/;x"),
1625 ("g;x", "http://a/b/c/g;x"),
1626 ("g;x?y#s", "http://a/b/c/g;x?y#s"),
1627 ("", "http://a/b/c/d;p?q"),
1628 (".", "http://a/b/c/"),
1629 ("./", "http://a/b/c/"),
1630 ("..", "http://a/b/"),
1631 ("../", "http://a/b/"),
1632 ("../g", "http://a/b/g"),
1633 ("../..", "http://a/"),
1634 ("../../", "http://a/"),
1635 ("../../g", "http://a/g"),
1636 ],
1637 );
1638 }
1639
1640 #[test]
1643 fn resolution_abnormal() {
1644 test_resolution(
1645 "http://a/b/c/d;p?q",
1646 [
1647 ("../../../g", "http://a/g"),
1648 ("../../../../g", "http://a/g"),
1649 ("/./g", "http://a/g"),
1650 ("/../g", "http://a/g"),
1651 ("g.", "http://a/b/c/g."),
1652 (".g", "http://a/b/c/.g"),
1653 ("g..", "http://a/b/c/g.."),
1654 ("..g", "http://a/b/c/..g"),
1655 ("./../g", "http://a/b/g"),
1656 ("./g/.", "http://a/b/c/g/"),
1657 ("g/./h", "http://a/b/c/g/h"),
1658 ("g/../h", "http://a/b/c/h"),
1659 ("g;x=1/./y", "http://a/b/c/g;x=1/y"),
1660 ("g;x=1/../y", "http://a/b/c/y"),
1661 ("g?y/./x", "http://a/b/c/g?y/./x"),
1662 ("g?y/../x", "http://a/b/c/g?y/../x"),
1663 ("g#s/./x", "http://a/b/c/g#s/./x"),
1664 ("g#s/../x", "http://a/b/c/g#s/../x"),
1665 ("http:g", "http:g"),
1666 ],
1667 );
1668 }
1669
1670 #[test]
1671 fn resolution_ambiguous_double_slash() {
1672 test_resolution("http:/a/b", [("../..//", "http:/.//")]);
1673 }
1674
1675 #[test]
1676 fn resolution_longer_segments() {
1677 test_resolution(
1678 "http://a/bb/ccc/d;p?q",
1679 [
1680 ("#s", "http://a/bb/ccc/d;p?q#s"),
1681 ("", "http://a/bb/ccc/d;p?q"),
1682 ],
1683 );
1684 }
1685
1686 #[test]
1687 fn resolution_dot_segments_in_base() {
1688 test_resolution(
1689 "http://a/bb/ccc/./d;p?q",
1690 [
1691 ("..", "http://a/bb/"),
1692 ("../", "http://a/bb/"),
1693 ("../g", "http://a/bb/g"),
1694 ("../..", "http://a/"),
1695 ("../../", "http://a/"),
1696 ("../../g", "http://a/g"),
1697 ],
1698 );
1699 }
1700
1701 #[test]
1702 fn resolution_double_slashes_in_base() {
1703 test_resolution(
1704 "http://ab//de//ghi",
1705 [
1706 ("xyz", "http://ab//de//xyz"),
1707 ("./xyz", "http://ab//de//xyz"),
1708 ("../xyz", "http://ab//de/xyz"),
1709 ],
1710 );
1711 }
1712
1713 #[test]
1714 fn resolution_parent_segments_in_base() {
1715 test_resolution("http://a/bb/ccc/../d;p?q", [("../../", "http://a/")]);
1716 }
1717
1718 #[test]
1720 fn resolution_scheme_no_authority() {
1721 test_resolution("scheme:a:b/", [("Foo", "scheme:a:b/Foo")]);
1722 }
1723
1724 #[test]
1726 fn resolution_empty_base_path() {
1727 test_resolution(
1728 "http://a",
1729 [
1730 (".", "http://a/"),
1731 ("./", "http://a/"),
1732 ("..", "http://a/"),
1733 ("../", "http://a/"),
1734 ("../g", "http://a/g"),
1735 ("g", "http://a/g"),
1736 ("g/", "http://a/g/"),
1737 ("g/h", "http://a/g/h"),
1738 ("?q", "http://a?q"),
1739 ("#f", "http://a#f"),
1740 ],
1741 );
1742 }
1743
1744 fn test_relative_to<'a>(base: &str, vectors: impl IntoIterator<Item = (&'a str, &'a str)>) {
1745 let base = UriRef::new(base).unwrap();
1746 for (input, expected) in vectors {
1747 let input = UriRef::new(input).unwrap();
1748 let relative = input.relative_to(base);
1749 assert_eq!(
1750 relative, expected,
1751 "({input}).relative_to({base}) != {expected}",
1752 );
1753
1754 if let (Ok(base_uri), Ok(input_uri)) =
1758 (Uri::new(base.as_str()), Uri::new(input.as_str()))
1759 {
1760 let resolved = relative.resolved(base_uri);
1761 assert_eq!(
1762 resolved, *input_uri,
1763 "({relative}).resolved({base}) != {input}",
1764 );
1765 }
1766 }
1767 }
1768
1769 #[test]
1770 fn relative_to() {
1771 test_relative_to(
1772 "https://w3c.github.io/json-ld-api/tests/compact/0066-in.jsonld",
1773 [
1774 (
1775 "https://w3c.github.io/json-ld-api/tests/compact/link",
1776 "link",
1777 ),
1778 (
1779 "https://w3c.github.io/json-ld-api/tests/compact/0066-in.jsonld#fragment-works",
1780 "#fragment-works",
1781 ),
1782 (
1783 "https://w3c.github.io/json-ld-api/tests/compact/0066-in.jsonld?query=works",
1784 "?query=works",
1785 ),
1786 ("https://w3c.github.io/json-ld-api/tests/", "../"),
1787 ("https://w3c.github.io/json-ld-api/", "../../"),
1788 ("https://w3c.github.io/json-ld-api/parent", "../../parent"),
1789 (
1790 "https://w3c.github.io/json-ld-api/parent#fragment",
1791 "../../parent#fragment",
1792 ),
1793 (
1794 "https://w3c.github.io/parent-parent-eq-root",
1795 "../../../parent-parent-eq-root",
1796 ),
1797 (
1798 "http://example.org/scheme-relative",
1799 "http://example.org/scheme-relative",
1800 ),
1801 (
1802 "https://w3c.github.io/json-ld-api/tests/compact/0066-in.jsonld",
1803 "0066-in.jsonld",
1804 ),
1805 ],
1806 );
1807 }
1808
1809 #[test]
1810 fn relative_to_empty_base_path() {
1811 test_relative_to(
1812 "http://a",
1813 [
1814 ("http://a/", "/"),
1815 ("http://a/g", "/g"),
1816 ("http://a/g/h", "/g/h"),
1817 ("http://a?q", "?q"),
1818 ("http://a#f", "#f"),
1819 ("http://a?q#f", "?q#f"),
1820 ],
1821 );
1822 }
1823
1824 #[test]
1825 fn relative_to_root_base_path() {
1826 test_relative_to(
1827 "http://a/",
1828 [
1829 ("http://a/", ""),
1830 ("http://a/g", "g"),
1831 ("http://a/g/h", "g/h"),
1832 ("http://a/?q", "?q"),
1833 ("http://a/#f", "#f"),
1834 ],
1835 );
1836 }
1837
1838 #[test]
1839 fn relative_to_different_authority() {
1840 test_relative_to(
1841 "http://a/path",
1842 [
1843 ("http://b/path", "http://b/path"),
1844 ("http://b/other", "http://b/other"),
1845 ],
1846 );
1847 }
1848
1849 #[test]
1850 fn relative_to_mismatched_scheme() {
1851 test_relative_to(
1852 "http://a/path",
1853 [
1854 ("https://a/path", "https://a/path"),
1855 ("ftp://a/path", "ftp://a/path"),
1856 ],
1857 );
1858 }
1859
1860 #[test]
1861 fn relative_to_missing_scheme() {
1862 test_relative_to(
1864 "http://a/path",
1865 [("//a/path", "path"), ("//a/other", "other")],
1866 );
1867 test_relative_to("//a/path", [("http://a/path", "http://a/path")]);
1869 }
1870
1871 #[test]
1872 fn relative_to_missing_authority() {
1873 test_relative_to("http://a/path", [("http:/path", "http:/path")]);
1875 test_relative_to("http:/path", [("http://a/path", "http://a/path")]);
1876 }
1877
1878 #[test]
1879 fn relative_to_same_uri() {
1880 test_relative_to(
1881 "http://a/b/c",
1882 [
1883 ("http://a/b/c", "c"),
1884 ("http://a/b/c?q", "?q"),
1885 ("http://a/b/c#f", "#f"),
1886 ],
1887 );
1888 }
1889
1890 #[test]
1891 fn invalid() {
1892 let vectors: [&[u8]; _] = [
1893 b"http://host name", b"http://host\0name", b"http://[::1", b"http://ho st/path", b"htt p://host", b"http://host/pa th", b"http://host?qu ery", b"http://host#fra gment", b"\xff://host", ];
1903
1904 for input in vectors {
1905 assert!(UriRef::new(input).is_err(), "should reject: {input:?}");
1906 }
1907 }
1908
1909 #[test]
1910 fn resolve_relative_to_round_trip() {
1911 let bases = ["http://a/b/c/d", "http://a/b/c/", "http://a/", "http://a"];
1912
1913 let targets = [
1914 "http://a/",
1915 "http://a/g",
1916 "http://a/b/g",
1917 "http://a/b/c/g",
1918 "http://a/b/c/g/",
1919 "http://a/b/c/?q",
1920 "http://a/b/c/#f",
1921 "http://a/b/c/g?q#f",
1922 ];
1923
1924 for base in bases {
1925 let base_uri = Uri::new(base).unwrap();
1926 for target in targets {
1927 let target_uri = UriRef::new(target).unwrap();
1928 let rel = target_uri.relative_to(base_uri.as_uri_ref());
1929 let resolved = rel.resolved(base_uri);
1930 assert_eq!(
1931 resolved.as_str(),
1932 target,
1933 "round-trip failed: ({target}).relative_to({base}).resolved({base}) = {resolved}",
1934 );
1935 }
1936 }
1937 }
1938
1939 #[test]
1940 fn valid_relative() {
1941 let vectors = [
1942 "", "/path", "../..", "?query", "#fragment", "//authority", ];
1949
1950 for input in vectors {
1951 assert!(UriRef::new(input).is_ok(), "should accept: {input:?}");
1952 }
1953 }
1954}