1use super::*;
17use core::fmt::Display;
18
19pub trait AnyUriRef {
22 #[must_use]
28 fn components(&self) -> UriRawComponents<'_>;
29
30 fn write_to<T: core::fmt::Write + ?Sized>(
49 &self,
50 write: &mut T,
51 ) -> Result<(), core::fmt::Error> {
52 self.components().write_to(write)
53 }
54
55 #[must_use]
78 fn display(&self) -> UriDisplay<'_, Self> {
79 UriDisplay(self)
80 }
81
82 #[must_use]
84 fn is_empty(&self) -> bool {
85 self.components().is_empty()
86 }
87
88 #[must_use]
92 fn uri_type(&self) -> UriType {
93 self.components().uri_type()
94 }
95
96 #[cfg(feature = "std")]
101 #[must_use]
102 fn to_uri_ref_buf(&self) -> UriRefBuf {
103 unsafe { UriRefBuf::from_string_unchecked(self.display().to_string()) }
104 }
105
106 fn write_resolved<T: core::fmt::Write + ?Sized, D: AnyUriRef + ?Sized>(
110 &self,
111 target: &D,
112 f: &mut T,
113 ) -> Result<(), ResolveError> {
114 if target.is_empty() {
120 self.write_to(f)?;
121 return Ok(());
122 }
123
124 let target_type = target.uri_type();
125
126 let target_components = target.components();
127
128 let base_type = self.uri_type();
129
130 if base_type.cannot_be_a_base() {
132 match target_type {
133 UriType::Fragment => {
134 self.components().trim_fragment().write_to(f)?;
135 target.write_to(f)?;
136 return Ok(());
137 }
138 UriType::Query => {
139 self.components().trim_query().write_to(f)?;
140 target.write_to(f)?;
141 return Ok(());
142 }
143 x if x.is_ietf_rfc3986_relative_reference() => {
144 return Err(ResolveError::CannotBeABase);
145 }
146 _ => (),
147 }
148 }
149
150 if target_components.scheme.is_some() {
151 target.write_to(f)?;
152 return Ok(());
153 }
154
155 let mut components = self.components();
156
157 if target_components.authority.is_some() {
158 components.authority = target_components.authority;
159 }
160
161 components.fragment = target_components.fragment;
163 if target_components.query.is_some() {
164 components.query = target_components.query;
165 } else if !target_components.path.is_empty() || target_components.authority.is_some() {
166 components.query = None;
167 }
168
169 if let Some(scheme) = components.scheme {
170 f.write_str(scheme)?;
171 f.write_char(':')?;
172 }
173
174 if let Some(authority) = components.authority {
175 f.write_str("//")?;
176 f.write_str(authority)?;
177 }
178
179 let mut base_path = components.path_as_rel_ref();
180 let target_path = target_components.path_as_rel_ref();
181
182 if !target_path.is_empty() || !target_type.has_absolute_path() {
183 let target_starts_with_slash = target_path.starts_with("/");
184 let base_starts_with_slash = base_path.starts_with("/");
185
186 if target_type.has_absolute_path() {
187 if base_starts_with_slash {
188 base_path = rel_ref!("");
189 } else {
190 base_path = rel_ref!("/");
191 }
192 } else if !target_path.is_empty() {
193 base_path = base_path.trim_resource();
194 }
195
196 let mut out_path_vec = Vec::new();
197
198 let seg_iter = base_path
199 .raw_path_segments()
200 .chain(target_path.raw_path_segments());
201
202 let path_will_be_absolute = target_starts_with_slash
203 || base_starts_with_slash
204 || (base_type.has_absolute_path() && !target_path.is_empty());
205
206 for seg in seg_iter {
207 match seg {
208 "." => {
209 let last = out_path_vec.last().map(|x| *x);
210
211 if last.map(str::is_empty) == Some(false) {
212 out_path_vec.push("");
213 }
214 continue;
215 }
216 ".." => {
217 let mut last = out_path_vec.pop();
218
219 if last == Some("") {
220 last = out_path_vec.pop();
221 }
222
223 match (last, path_will_be_absolute, out_path_vec.is_empty()) {
224 (Some("."), false, _) => out_path_vec.push(".."),
225 (Some(".."), false, _) => {
226 out_path_vec.push("..");
227 out_path_vec.push("..");
228 }
229 (Some(_), true, _) => out_path_vec.push(""),
230 (Some(_), false, false) => out_path_vec.push(""),
231 (Some(_), false, true) => out_path_vec.push("."),
232 (None, _, _) => (),
233 };
234 }
235 seg => {
236 match out_path_vec.last().map(|x| *x) {
237 Some(".") if seg.is_empty() => continue,
238 Some(".") | Some("") => {
239 out_path_vec.pop();
240 }
241 _ => (),
242 };
243 out_path_vec.push(seg)
244 }
245 }
246 }
247
248 if path_will_be_absolute {
249 f.write_char('/')?;
250 }
251
252 for (n, seg) in out_path_vec.into_iter().enumerate() {
253 if n != 0 {
254 f.write_char('/')?;
255 }
256 f.write_str(seg)?;
257 }
258 }
259
260 if let Some(query) = components.query {
261 f.write_char('?')?;
262 f.write_str(query)?;
263 }
264
265 if let Some(fragment) = components.fragment {
266 f.write_char('#')?;
267 f.write_str(fragment)?;
268 }
269
270 Ok(())
271 }
272
273 #[cfg(feature = "std")]
276 #[must_use]
277 fn resolved<T: AnyUriRef + ?Sized>(&self, dest: &T) -> Result<UriRefBuf, ResolveError> {
278 if dest.is_empty() {
279 return Ok(self.to_uri_ref_buf());
280 }
281
282 let mut ret = String::new();
283
284 self.write_resolved(dest, &mut ret)?;
285
286 Ok(unsafe { UriRefBuf::from_string_unchecked(ret) })
288 }
289}
290
291use core::ops::Deref;
292
293impl<'a, T: AnyUriRef + Clone + ?Sized> AnyUriRef for Cow<'a, T> {
295 fn components(&self) -> UriRawComponents<'_> {
296 self.deref().components()
297 }
298
299 fn write_to<W: core::fmt::Write + ?Sized>(
300 &self,
301 write: &mut W,
302 ) -> Result<(), core::fmt::Error> {
303 self.deref().write_to(write)
304 }
305
306 fn is_empty(&self) -> bool {
307 self.deref().is_empty()
308 }
309
310 fn uri_type(&self) -> UriType {
311 self.deref().uri_type()
312 }
313
314 #[cfg(feature = "std")]
315 fn to_uri_ref_buf(&self) -> UriRefBuf {
316 self.deref().to_uri_ref_buf()
317 }
318
319 fn write_resolved<W: core::fmt::Write + ?Sized, D: AnyUriRef + ?Sized>(
320 &self,
321 dest: &D,
322 output: &mut W,
323 ) -> Result<(), ResolveError> {
324 self.deref().write_resolved(dest, output)
325 }
326
327 fn resolved<W: AnyUriRef + ?Sized>(&self, dest: &W) -> Result<UriRefBuf, ResolveError> {
328 self.deref().resolved(dest)
329 }
330}
331
332#[derive(Debug, Copy, Clone)]
337pub struct UriDisplay<'a, T: AnyUriRef + ?Sized>(&'a T);
338
339impl<'a, T: AnyUriRef + ?Sized> Display for UriDisplay<'a, T> {
340 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
341 self.0.write_to(f)
342 }
343}
344
345#[cfg(test)]
346mod test {
347 use super::*;
348
349 #[test]
350 fn resolve_simple() {
351 let uri_test_table = vec![
352 (
353 "http://x/a/b/c",
354 "/abs-path",
355 Some(uri_ref!("http://x/abs-path")),
356 ),
357 (
358 "http://x/a/b/c",
359 "f/s?c",
360 Some(uri_ref!("http://x/a/b/f/s?c")),
361 ),
362 (
363 "http://x/a/b/c",
364 "/abs-path",
365 Some(uri_ref!("http://x/abs-path")),
366 ),
367 (
368 "http://x/a/b/c",
369 "path",
370 Some(uri_ref!("http://x/a/b/path")),
371 ),
372 (
373 "http://x/a/b/c/",
374 "path",
375 Some(uri_ref!("http://x/a/b/c/path")),
376 ),
377 (
378 "http://x/a/b/c/",
379 "//y/d/e/f/",
380 Some(uri_ref!("http://y/d/e/f/")),
381 ),
382 ("http://x/a/b/c", "?", Some(uri_ref!("http://x/a/b/c?"))),
383 ("http://x", "a/b/c", Some(uri_ref!("http://x/a/b/c"))),
384 ("http://x", "/a/b/c", Some(uri_ref!("http://x/a/b/c"))),
385 ("http://x/", "a/b/c", Some(uri_ref!("http://x/a/b/c"))),
386 ("http://x/a/b/c", "coap://x", Some(uri_ref!("coap://x"))),
387 ];
388
389 for (a, b, c) in uri_test_table {
390 let uri_a = UriRef::from_str(a).expect(a);
391 let uri_b = UriRef::from_str(b).expect(b);
392 assert_eq!(
393 uri_a.resolved(uri_b).ok(),
394 c.map(|x| x.to_owned()),
395 "uri_a.resolved(): a:{} b:{} c:{:?}",
396 a,
397 b,
398 c
399 );
400 }
401 }
402
403 #[test]
404 fn resolve_relative_base() {
405 let uri_test_table = vec![
406 ("b/c/d;p?q", "g:h", Some(uri_ref!("g:h"))),
407 ("b/c/d;p?q", "g", Some(uri_ref!("b/c/g"))),
408 ("b/c/d;p?q", "./g", Some(uri_ref!("b/c/g"))),
409 ("b/c/d;p?q", "g/", Some(uri_ref!("b/c/g/"))),
410 ("b/c/d;p?q", "/g", Some(uri_ref!("/g"))),
411 ("b/c/d;p?q", "//g", Some(uri_ref!("//g"))),
412 ("b/c/d;p?q", "?y", Some(uri_ref!("b/c/d;p?y"))),
413 ("b/c/d;p?q", "g?y", Some(uri_ref!("b/c/g?y"))),
414 ("b/c/d;p?q", "#s", Some(uri_ref!("b/c/d;p?q#s"))),
415 ("b/c/d;p?q", "g#s", Some(uri_ref!("b/c/g#s"))),
416 ("b/c/d;p?q", "g?y#s", Some(uri_ref!("b/c/g?y#s"))),
417 ("b/c/d;p?q", ";x", Some(uri_ref!("b/c/;x"))),
418 ("b/c/d;p?q", "g;x", Some(uri_ref!("b/c/g;x"))),
419 ("b/c/d;p?q", "g;x?y#s", Some(uri_ref!("b/c/g;x?y#s"))),
420 ("b/c/d;p?q", "", Some(uri_ref!("b/c/d;p?q"))),
421 ("b/c/d;p?q", ".", Some(uri_ref!("b/c/"))),
422 ("b/c/d;p?q", "./", Some(uri_ref!("b/c/"))),
423 ("b/c/d;p?q", "/./g", Some(uri_ref!("/g"))),
424 ("b/c/d;p?q", "g.", Some(uri_ref!("b/c/g."))),
425 ("b/c/d;p?q", ".g", Some(uri_ref!("b/c/.g"))),
426 ("b/c/d;p?q", "g..", Some(uri_ref!("b/c/g.."))),
427 ("b/c/d;p?q", "..g", Some(uri_ref!("b/c/..g"))),
428 ("b/c/d;p?q", "g?y/./x", Some(uri_ref!("b/c/g?y/./x"))),
429 ("b/c/d;p?q", "g?y/../x", Some(uri_ref!("b/c/g?y/../x"))),
430 ("b/c/d;p?q", "g#s/./x", Some(uri_ref!("b/c/g#s/./x"))),
431 ("b/c/d;p?q", "g#s/../x", Some(uri_ref!("b/c/g#s/../x"))),
432 ("b/c/d;p?q", "..", Some(uri_ref!("b/"))),
433 ("b/c/d;p?q", "../", Some(uri_ref!("b/"))),
434 ("b/c/d;p?q", "../g", Some(uri_ref!("b/g"))),
435 ("b/c/d;p?q", "../..", Some(uri_ref!("."))),
436 ("b/c/d;p?q", "../../", Some(uri_ref!("."))),
437 ("b/c/d;p?q", "../../g", Some(uri_ref!("g"))),
438 ("b/c/d;p?q", "../../../g", Some(uri_ref!("../g"))),
439 ("b/c/d;p?q", "../../../../g", Some(uri_ref!("../../g"))),
440 ("b/c/d;p?q", "/../g", Some(uri_ref!("/g"))),
441 ("b/c/d;p?q", "./../g", Some(uri_ref!("b/g"))),
442 ("b/c/d;p?q", "./g/.", Some(uri_ref!("b/c/g/"))),
443 ("b/c/d;p?q", "g/./h", Some(uri_ref!("b/c/g/h"))),
444 ("b/c/d;p?q", "g/../h", Some(uri_ref!("b/c/h"))),
445 ("b/c/d;p?q", "g;x=1/./y", Some(uri_ref!("b/c/g;x=1/y"))),
446 ("b/c/d;p?q", "g;x=1/../y", Some(uri_ref!("b/c/y"))),
447 ];
448
449 for (a, b, c) in uri_test_table {
450 let uri_a = UriRef::from_str(a).expect(a);
451 let uri_b = UriRef::from_str(b).expect(b);
452 assert_eq!(
453 uri_a.resolved(uri_b).ok(),
454 c.map(|x| x.to_owned()),
455 "uri_a.resolved(): a:{} b:{} c:{:?}",
456 a,
457 b,
458 c
459 );
460 }
461 }
462
463 #[test]
464 fn resolve_cannot_be_a_base() {
465 let uri_test_table = vec![
466 ("s:123", "/a/b/c", None),
467 ("s:123", "//a/b/c", None),
468 ("s:123", ".", None),
469 ("s:123", "", Some(uri_ref!("s:123"))),
470 ("s:123", "?q=123", Some(uri_ref!("s:123?q=123"))),
471 ("s:123", "#frag", Some(uri_ref!("s:123#frag"))),
472 ("s:123", "#frag", Some(uri_ref!("s:123#frag"))),
473 ("s:123", "file:/d/e/f", Some(uri_ref!("file:/d/e/f"))),
474 ];
475
476 for (a, b, c) in uri_test_table {
477 let uri_a = UriRef::from_str(a).expect(a);
478 let uri_b = UriRef::from_str(b).expect(b);
479 assert_eq!(
480 uri_a.resolved(uri_b).ok(),
481 c.map(|x| x.to_owned()),
482 "uri_a.resolved(): a:{} b:{} c:{:?}",
483 a,
484 b,
485 c
486 );
487 }
488 }
489
490 #[test]
491 fn resolve_no_authority() {
492 let uri_test_table = vec![
493 ("file:/d/e/f", "//a/b/c", Some(uri_ref!("file://a/b/c"))),
494 ("file:/d/e/f", "g", Some(uri_ref!("file:/d/e/g"))),
495 ];
496
497 for (a, b, c) in uri_test_table {
498 let uri_a = UriRef::from_str(a).expect(a);
499 let uri_b = UriRef::from_str(b).expect(b);
500 assert_eq!(
501 uri_a.resolved(uri_b).ok(),
502 c.map(|x| x.to_owned()),
503 "uri_a.resolved(): a:{} b:{} c:{:?}",
504 a,
505 b,
506 c
507 );
508 }
509 }
510
511 #[test]
512 fn resolve_rfc3986_simple() {
513 let uri_test_table = vec![
514 ("http://a/b/c/d;p?q", "g:h", Some(uri_ref!("g:h"))),
516 ("http://a/b/c/d;p?q", "g", Some(uri_ref!("http://a/b/c/g"))),
517 (
518 "http://a/b/c/d;p?q",
519 "./g",
520 Some(uri_ref!("http://a/b/c/g")),
521 ),
522 (
523 "http://a/b/c/d;p?q",
524 "g/",
525 Some(uri_ref!("http://a/b/c/g/")),
526 ),
527 ("http://a/b/c/d;p?q", "/g", Some(uri_ref!("http://a/g"))),
528 ("http://a/b/c/d;p?q", "//g", Some(uri_ref!("http://g"))),
529 (
530 "http://a/b/c/d;p?q",
531 "?y",
532 Some(uri_ref!("http://a/b/c/d;p?y")),
533 ),
534 (
535 "http://a/b/c/d;p?q",
536 "g?y",
537 Some(uri_ref!("http://a/b/c/g?y")),
538 ),
539 (
540 "http://a/b/c/d;p?q",
541 "#s",
542 Some(uri_ref!("http://a/b/c/d;p?q#s")),
543 ),
544 (
545 "http://a/b/c/d;p?q",
546 "g#s",
547 Some(uri_ref!("http://a/b/c/g#s")),
548 ),
549 (
550 "http://a/b/c/d;p?q",
551 "g?y#s",
552 Some(uri_ref!("http://a/b/c/g?y#s")),
553 ),
554 (
555 "http://a/b/c/d;p?q",
556 ";x",
557 Some(uri_ref!("http://a/b/c/;x")),
558 ),
559 (
560 "http://a/b/c/d;p?q",
561 "g;x",
562 Some(uri_ref!("http://a/b/c/g;x")),
563 ),
564 (
565 "http://a/b/c/d;p?q",
566 "g;x?y#s",
567 Some(uri_ref!("http://a/b/c/g;x?y#s")),
568 ),
569 (
570 "http://a/b/c/d;p?q",
571 "",
572 Some(uri_ref!("http://a/b/c/d;p?q")),
573 ),
574 ("http://a/b/c/d;p?q", ".", Some(uri_ref!("http://a/b/c/"))),
575 ("http://a/b/c/d;p?q", "./", Some(uri_ref!("http://a/b/c/"))),
576 ("http://a/b/c/d;p?q", "/./g", Some(uri_ref!("http://a/g"))),
577 (
578 "http://a/b/c/d;p?q",
579 "g.",
580 Some(uri_ref!("http://a/b/c/g.")),
581 ),
582 (
583 "http://a/b/c/d;p?q",
584 ".g",
585 Some(uri_ref!("http://a/b/c/.g")),
586 ),
587 (
588 "http://a/b/c/d;p?q",
589 "g..",
590 Some(uri_ref!("http://a/b/c/g..")),
591 ),
592 (
593 "http://a/b/c/d;p?q",
594 "..g",
595 Some(uri_ref!("http://a/b/c/..g")),
596 ),
597 (
598 "http://a/b/c/d;p?q",
599 "g?y/./x",
600 Some(uri_ref!("http://a/b/c/g?y/./x")),
601 ),
602 (
603 "http://a/b/c/d;p?q",
604 "g?y/../x",
605 Some(uri_ref!("http://a/b/c/g?y/../x")),
606 ),
607 (
608 "http://a/b/c/d;p?q",
609 "g#s/./x",
610 Some(uri_ref!("http://a/b/c/g#s/./x")),
611 ),
612 (
613 "http://a/b/c/d;p?q",
614 "g#s/../x",
615 Some(uri_ref!("http://a/b/c/g#s/../x")),
616 ),
617 ];
618
619 for (a, b, c) in uri_test_table {
620 let uri_a = UriRef::from_str(a).expect(a);
621 let uri_b = UriRef::from_str(b).expect(b);
622 assert_eq!(
623 uri_a.resolved(uri_b).ok(),
624 c.map(|x| x.to_owned()),
625 "uri_a.resolved(): a:{} b:{} c:{:?}",
626 a,
627 b,
628 c
629 );
630 }
631 }
632
633 #[test]
634 fn resolve_rfc3986_dot_dot() {
635 let uri_test_table = vec![
636 ("http://a/b/c/d;p?q", "..", Some(uri_ref!("http://a/b/"))),
638 ("http://a/b/c/d;p?q", "../", Some(uri_ref!("http://a/b/"))),
639 ("http://a/b/c/d;p?q", "../g", Some(uri_ref!("http://a/b/g"))),
640 ("http://a/b/c/d;p?q", "../..", Some(uri_ref!("http://a/"))),
641 ("http://a/b/c/d;p?q", "../../", Some(uri_ref!("http://a/"))),
642 (
643 "http://a/b/c/d;p?q",
644 "../../g",
645 Some(uri_ref!("http://a/g")),
646 ),
647 (
648 "http://a/b/c/d;p?q",
649 "../../../g",
650 Some(uri_ref!("http://a/g")),
651 ),
652 (
653 "http://a/b/c/d;p?q",
654 "../../../../g",
655 Some(uri_ref!("http://a/g")),
656 ),
657 ("http://a/b/c/d;p?q", "/../g", Some(uri_ref!("http://a/g"))),
658 (
659 "http://a/b/c/d;p?q",
660 "./../g",
661 Some(uri_ref!("http://a/b/g")),
662 ),
663 (
664 "http://a/b/c/d;p?q",
665 "./g/.",
666 Some(uri_ref!("http://a/b/c/g/")),
667 ),
668 (
669 "http://a/b/c/d;p?q",
670 "g/./h",
671 Some(uri_ref!("http://a/b/c/g/h")),
672 ),
673 (
674 "http://a/b/c/d;p?q",
675 "g/../h",
676 Some(uri_ref!("http://a/b/c/h")),
677 ),
678 (
679 "http://a/b/c/d;p?q",
680 "g;x=1/./y",
681 Some(uri_ref!("http://a/b/c/g;x=1/y")),
682 ),
683 (
684 "http://a/b/c/d;p?q",
685 "g;x=1/../y",
686 Some(uri_ref!("http://a/b/c/y")),
687 ),
688 ];
689
690 for (a, b, c) in uri_test_table {
691 let uri_a = UriRef::from_str(a).expect(a);
692 let uri_b = UriRef::from_str(b).expect(b);
693 assert_eq!(
694 uri_a.resolved(uri_b).ok(),
695 c.map(|x| x.to_owned()),
696 "uri_a.resolved(): a:{} b:{} c:{:?}",
697 a,
698 b,
699 c
700 );
701 }
702 }
703}