uriparse/uri.rs
1//! URIs, Relative References, and URI References
2//!
3//! See [RFC3986](https://tools.ietf.org/html/rfc3986).
4//!
5//! This module is composed of three primary types [`URI`], [`RelativeReference`], and
6//! [`URIReference`] that are all very similar. The first thing to note is that URIs and relative
7//! references are types of URI references. They differ in only one way: URIs have schemes, while
8//! relative references do not.
9//!
10//! As a result, choose the type that best fits your use case. If you need absolute URIs, you should
11//! use [`URI`], but if you want relative references (e.g. `"/"` in a GET request) use
12//! [`RelativeReference`]. If you can accept both, then use [`URIReference`].
13
14use std::convert::{Infallible, TryFrom};
15use std::error::Error;
16use std::fmt::{self, Display, Formatter};
17
18use crate::authority::{Authority, AuthorityError, Host, Password, Username};
19use crate::fragment::{Fragment, FragmentError};
20use crate::path::{Path, PathError};
21use crate::query::{Query, QueryError};
22use crate::scheme::{Scheme, SchemeError};
23use crate::uri_reference::{URIReference, URIReferenceBuilder, URIReferenceError};
24
25/// A Uniform Resource Identifier (URI) as defined in
26/// [RFC3986](https://tools.ietf.org/html/rfc3986).
27///
28/// A URI is a URI reference, one with a scheme.
29#[derive(Clone, Debug, Eq, Hash, PartialEq)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31pub struct URI<'uri> {
32 /// All URIs are also URI references, so we just maintain a [`URIReference`] underneath.
33 uri_reference: URIReference<'uri>,
34}
35
36impl<'uri> URI<'uri> {
37 pub fn as_uri_reference(&self) -> &URIReference<'uri> {
38 &self.uri_reference
39 }
40
41 /// Returns the authority, if present, of the URI.
42 ///
43 /// # Examples
44 ///
45 /// ```
46 /// use std::convert::TryFrom;
47 ///
48 /// use uriparse::URI;
49 ///
50 /// let uri = URI::try_from("http://example.com:80/my/path").unwrap();
51 /// assert_eq!(uri.authority().unwrap().to_string(), "example.com:80");
52 /// ```
53 pub fn authority(&self) -> Option<&Authority<'uri>> {
54 self.uri_reference.authority()
55 }
56
57 /// Constructs a default builder for a URI.
58 ///
59 /// This provides an alternative means of constructing a URI besides parsing and
60 /// [`URI::from_parts`].
61 ///
62 /// # Examples
63 ///
64 /// ```
65 /// use std::convert::TryFrom;
66 ///
67 /// use uriparse::{Authority, Path, Scheme, URI};
68 ///
69 /// let uri = URI::builder()
70 /// .with_scheme(Scheme::HTTP)
71 /// .with_authority(Some(Authority::try_from("example.com").unwrap()))
72 /// .with_path(Path::try_from("/my/path").unwrap())
73 /// .build()
74 /// .unwrap();
75 /// assert_eq!(uri.to_string(), "http://example.com/my/path");
76 /// ```
77 pub fn builder<'new_uri>() -> URIBuilder<'new_uri> {
78 URIBuilder::new()
79 }
80
81 /// Returns whether the URI can act as a base URI.
82 ///
83 /// A URI can be a base if it is absolute (i.e. it has no fragment component).
84 ///
85 /// # Examples
86 ///
87 /// ```
88 /// use std::convert::TryFrom;
89 ///
90 /// use uriparse::URI;
91 ///
92 /// let uri = URI::try_from("http://example.com/my/path").unwrap();
93 /// assert!(uri.can_be_a_base());
94 ///
95 /// let uri = URI::try_from("ftp://127.0.0.1#fragment").unwrap();
96 /// assert!(!uri.can_be_a_base());
97 /// ```
98 pub fn can_be_a_base(&self) -> bool {
99 !self.uri_reference.has_fragment()
100 }
101
102 /// Constructs a new [`URI`] from the individual parts: scheme, authority, path, query, and
103 /// fragment.
104 ///
105 /// The lifetime used by the resulting value will be the lifetime of the part that is most
106 /// restricted in scope.
107 ///
108 /// # Examples
109 ///
110 /// ```
111 /// use std::convert::TryFrom;
112 ///
113 /// use uriparse::{Fragment, URI};
114 ///
115 /// let uri = URI::from_parts(
116 /// "http",
117 /// Some("example.com"),
118 /// "",
119 /// Some("query"),
120 /// None::<Fragment>
121 /// ).unwrap();
122 /// assert_eq!(uri.to_string(), "http://example.com/?query");
123 /// ```
124 pub fn from_parts<
125 'new_uri,
126 TScheme,
127 TAuthority,
128 TPath,
129 TQuery,
130 TFragment,
131 TSchemeError,
132 TAuthorityError,
133 TPathError,
134 TQueryError,
135 TFragmentError,
136 >(
137 scheme: TScheme,
138 authority: Option<TAuthority>,
139 path: TPath,
140 query: Option<TQuery>,
141 fragment: Option<TFragment>,
142 ) -> Result<URI<'new_uri>, URIError>
143 where
144 Scheme<'new_uri>: TryFrom<TScheme, Error = TSchemeError>,
145 Authority<'new_uri>: TryFrom<TAuthority, Error = TAuthorityError>,
146 Path<'new_uri>: TryFrom<TPath, Error = TPathError>,
147 Query<'new_uri>: TryFrom<TQuery, Error = TQueryError>,
148 Fragment<'new_uri>: TryFrom<TFragment, Error = TFragmentError>,
149 URIReferenceError: From<TSchemeError>
150 + From<TAuthorityError>
151 + From<TPathError>
152 + From<TQueryError>
153 + From<TFragmentError>,
154 {
155 let uri_reference =
156 URIReference::from_parts(Some(scheme), authority, path, query, fragment)
157 .map_err(|error| URIError::try_from(error).unwrap())?;
158 Ok(URI { uri_reference })
159 }
160
161 /// Returns the fragment, if present, of the URI.
162 ///
163 /// # Examples
164 ///
165 /// ```
166 /// use std::convert::TryFrom;
167 ///
168 /// use uriparse::URI;
169 ///
170 /// let uri = URI::try_from("http://example.com#fragment").unwrap();
171 /// assert_eq!(uri.fragment().unwrap(), "fragment");
172 /// ```
173 pub fn fragment(&self) -> Option<&Fragment<'uri>> {
174 self.uri_reference.fragment()
175 }
176
177 /// Returns whether the URI has an authority component.
178 ///
179 /// # Examples
180 ///
181 /// ```
182 /// use std::convert::TryFrom;
183 ///
184 /// use uriparse::URI;
185 ///
186 /// let uri = URI::try_from("http://example.com").unwrap();
187 /// assert!(uri.has_authority());
188 ///
189 /// let uri = URI::try_from("urn:test").unwrap();
190 /// assert!(!uri.has_authority());
191 /// ```
192 pub fn has_authority(&self) -> bool {
193 self.uri_reference.has_authority()
194 }
195
196 /// Returns whether the URI has a fragment component.
197 ///
198 /// # Examples
199 ///
200 /// ```
201 /// use std::convert::TryFrom;
202 ///
203 /// use uriparse::URI;
204 ///
205 /// let uri = URI::try_from("http://example.com#test").unwrap();
206 /// assert!(uri.has_fragment());
207 ///
208 /// let uri = URI::try_from("http://example.com").unwrap();
209 /// assert!(!uri.has_fragment());
210 /// ```
211 pub fn has_fragment(&self) -> bool {
212 self.uri_reference.has_fragment()
213 }
214
215 /// Returns whether the URI has a password component.
216 ///
217 /// # Examples
218 ///
219 /// ```
220 /// use std::convert::TryFrom;
221 ///
222 /// use uriparse::URI;
223 ///
224 /// let uri = URI::try_from("http://user:pass@127.0.0.1").unwrap();
225 /// assert!(uri.has_password());
226 ///
227 /// let uri = URI::try_from("http://user@127.0.0.1").unwrap();
228 /// assert!(!uri.has_password());
229 /// ```
230 pub fn has_password(&self) -> bool {
231 self.uri_reference.has_password()
232 }
233
234 /// Returns whether the URI has a port.
235 ///
236 /// # Examples
237 ///
238 /// ```
239 /// use std::convert::TryFrom;
240 ///
241 /// use uriparse::URI;
242 ///
243 /// let uri = URI::try_from("http://127.0.0.1:8080").unwrap();
244 /// assert!(uri.has_port());
245 ///
246 /// let uri = URI::try_from("http://127.0.0.1").unwrap();
247 /// assert!(!uri.has_port());
248 /// ```
249 pub fn has_port(&self) -> bool {
250 self.uri_reference.has_port()
251 }
252
253 /// Returns whether the URI has a query component.
254 ///
255 /// # Examples
256 ///
257 /// ```
258 /// use std::convert::TryFrom;
259 ///
260 /// use uriparse::URI;
261 ///
262 /// let uri = URI::try_from("http://example.com/my/path?my=query").unwrap();
263 /// assert!(uri.has_query());
264 ///
265 /// let uri = URI::try_from("http://example.com/my/path").unwrap();
266 /// assert!(!uri.has_query());
267 /// ```
268 pub fn has_query(&self) -> bool {
269 self.uri_reference.has_query()
270 }
271
272 /// Returns whether the URI has a username component.
273 ///
274 /// # Examples
275 ///
276 /// ```
277 /// use std::convert::TryFrom;
278 ///
279 /// use uriparse::URI;
280 ///
281 /// let uri = URI::try_from("http://username@example.com").unwrap();
282 /// assert!(uri.has_username());
283 ///
284 /// let uri = URI::try_from("http://example.com").unwrap();
285 /// assert!(!uri.has_username());
286 /// ```
287 pub fn has_username(&self) -> bool {
288 self.uri_reference.has_username()
289 }
290
291 /// Returns the host, if present, of the URI.
292 ///
293 /// # Examples
294 ///
295 /// ```
296 /// use std::convert::TryFrom;
297 ///
298 /// use uriparse::URI;
299 ///
300 /// let uri = URI::try_from("http://username@example.com").unwrap();
301 /// assert_eq!(uri.host().unwrap().to_string(), "example.com");
302 /// ```
303 pub fn host(&self) -> Option<&Host<'uri>> {
304 self.uri_reference.host()
305 }
306
307 /// Converts the URI into a base URI (i.e. the fragment component is removed).
308 ///
309 /// # Examples
310 ///
311 /// ```
312 /// use std::convert::TryFrom;
313 ///
314 /// use uriparse::URI;
315 ///
316 /// let uri = URI::try_from("http://example.com#fragment").unwrap();
317 /// assert_eq!(uri.to_string(), "http://example.com/#fragment");
318 /// let uri = uri.into_base_uri();
319 /// assert_eq!(uri.to_string(), "http://example.com/");
320 /// ```
321 pub fn into_base_uri(self) -> URI<'uri> {
322 let (scheme, authority, path, query, _) = self.uri_reference.into_parts();
323 let uri_reference =
324 URIReference::from_parts(scheme, authority, path, query, None::<Fragment>).unwrap();
325 URI { uri_reference }
326 }
327
328 /// Consumes the URI and converts it into a builder with the same values.
329 ///
330 /// # Examples
331 ///
332 /// ```
333 /// use std::convert::TryFrom;
334 ///
335 /// use uriparse::{Fragment, Query, URI};
336 ///
337 /// let uri = URI::try_from("http://example.com/path?query#fragment").unwrap();
338 /// let mut builder = uri.into_builder();
339 /// builder.query(None::<Query>).fragment(None::<Fragment>);
340 /// let uri = builder.build().unwrap();
341 /// assert_eq!(uri.to_string(), "http://example.com/path");
342 /// ```
343 pub fn into_builder(self) -> URIBuilder<'uri> {
344 let (scheme, authority, path, query, fragment) = self.uri_reference.into_parts();
345 let mut builder = URIBuilder::new();
346 builder
347 .scheme(scheme.unwrap())
348 .authority(authority)
349 .path(path)
350 .query(query)
351 .fragment(fragment);
352 builder
353 }
354
355 /// Converts the [`URI`] into an owned copy.
356 ///
357 /// If you construct the URI from a source with a non-static lifetime, you may run into
358 /// lifetime problems due to the way the struct is designed. Calling this function will ensure
359 /// that the returned value has a static lifetime.
360 ///
361 /// This is different from just cloning. Cloning the URI will just copy the references, and thus
362 /// the lifetime will remain the same.
363 pub fn into_owned(self) -> URI<'static> {
364 URI {
365 uri_reference: self.uri_reference.into_owned(),
366 }
367 }
368
369 /// Consumes the [`URI`] and returns its parts: scheme, authority, path, query, and fragment.
370 ///
371 /// # Examples
372 ///
373 /// ```
374 /// use std::convert::TryFrom;
375 ///
376 /// use uriparse::URI;
377 ///
378 /// let uri = URI::try_from(
379 /// "http://username:password@example.com:80/my/path?my=query#fragment",
380 /// ).unwrap();
381 /// let (scheme, authority, path, query, fragment) = uri.into_parts();
382 ///
383 /// assert_eq!(scheme, "http");
384 /// assert_eq!(authority.unwrap().to_string(), "username:password@example.com:80");
385 /// assert_eq!(path, "/my/path");
386 /// assert_eq!(query.unwrap(), "my=query");
387 /// assert_eq!(fragment.unwrap(), "fragment");
388 /// ```
389 pub fn into_parts(
390 self,
391 ) -> (
392 Scheme<'uri>,
393 Option<Authority<'uri>>,
394 Path<'uri>,
395 Option<Query<'uri>>,
396 Option<Fragment<'uri>>,
397 ) {
398 let (scheme, authority, path, query, fragment) = self.uri_reference.into_parts();
399 (scheme.unwrap(), authority, path, query, fragment)
400 }
401
402 /// Returns whether the URI is normalized.
403 ///
404 /// A normalized URI will have all of its components normalized.
405 ///
406 /// # Examples
407 ///
408 /// ```
409 /// use std::convert::TryFrom;
410 ///
411 /// use uriparse::URI;
412 ///
413 /// let uri = URI::try_from("http://example.com/?a=b").unwrap();
414 /// assert!(uri.is_normalized());
415 ///
416 /// let mut uri = URI::try_from("http://EXAMPLE.com/?a=b").unwrap();
417 /// assert!(!uri.is_normalized());
418 /// uri.normalize();
419 /// assert!(uri.is_normalized());
420 /// ```
421 pub fn is_normalized(&self) -> bool {
422 self.uri_reference.is_normalized()
423 }
424
425 /// Maps the authority using the given map function.
426 ///
427 /// This function will panic if, as a result of the authority change, the URI reference becomes
428 /// invalid.
429 ///
430 /// # Examples
431 ///
432 /// ```
433 /// use std::convert::TryFrom;
434 ///
435 /// use uriparse::{Authority, URI};
436 ///
437 /// let mut uri = URI::try_from("http://example.com").unwrap();
438 /// uri.map_authority(|_| Some(Authority::try_from("127.0.0.1").unwrap()));
439 /// assert_eq!(uri.to_string(), "http://127.0.0.1/");
440 /// ```
441 pub fn map_authority<TMapper>(&mut self, mapper: TMapper) -> Option<&Authority<'uri>>
442 where
443 TMapper: FnOnce(Option<Authority<'uri>>) -> Option<Authority<'uri>>,
444 {
445 self.uri_reference.map_authority(mapper)
446 }
447
448 /// Maps the fragment using the given map function.
449 ///
450 /// # Examples
451 ///
452 /// ```
453 /// use std::convert::TryFrom;
454 ///
455 /// use uriparse::{Fragment, URI};
456 ///
457 /// let mut uri = URI::try_from("http://example.com").unwrap();
458 /// uri.map_fragment(|_| Some(Fragment::try_from("fragment").unwrap()));
459 /// assert_eq!(uri.to_string(), "http://example.com/#fragment");
460 /// ```
461 pub fn map_fragment<TMapper>(&mut self, mapper: TMapper) -> Option<&Fragment<'uri>>
462 where
463 TMapper: FnOnce(Option<Fragment<'uri>>) -> Option<Fragment<'uri>>,
464 {
465 self.uri_reference.map_fragment(mapper)
466 }
467
468 /// Maps the path using the given map function.
469 ///
470 /// This function will panic if, as a result of the path change, the URI becomes invalid.
471 ///
472 /// # Examples
473 ///
474 /// ```
475 /// use std::convert::TryFrom;
476 ///
477 /// use uriparse::URI;
478 ///
479 /// let mut uri = URI::try_from("http://example.com").unwrap();
480 /// uri.map_path(|mut path| {
481 /// path.push("test").unwrap();
482 /// path.push("path").unwrap();
483 /// path
484 /// });
485 /// assert_eq!(uri.to_string(), "http://example.com/test/path");
486 /// ```
487 pub fn map_path<TMapper>(&mut self, mapper: TMapper) -> &Path<'uri>
488 where
489 TMapper: FnOnce(Path<'uri>) -> Path<'uri>,
490 {
491 self.uri_reference.map_path(mapper)
492 }
493
494 /// Maps the query using the given map function.
495 ///
496 /// # Examples
497 ///
498 /// ```
499 /// use std::convert::TryFrom;
500 ///
501 /// use uriparse::{Query, URI};
502 ///
503 /// let mut uri = URI::try_from("http://example.com").unwrap();
504 /// uri.map_query(|_| Some(Query::try_from("query").unwrap()));
505 /// assert_eq!(uri.to_string(), "http://example.com/?query");
506 /// ```
507 pub fn map_query<TMapper>(&mut self, mapper: TMapper) -> Option<&Query<'uri>>
508 where
509 TMapper: FnOnce(Option<Query<'uri>>) -> Option<Query<'uri>>,
510 {
511 self.uri_reference.map_query(mapper)
512 }
513
514 /// Maps the scheme using the given map function.
515 ///
516 /// # Examples
517 ///
518 /// ```
519 /// use std::convert::TryFrom;
520 ///
521 /// use uriparse::{Scheme, URI};
522 ///
523 /// let mut uri = URI::try_from("http://example.com").unwrap();
524 /// uri.map_scheme(|_| Scheme::try_from("https").unwrap());
525 /// assert_eq!(uri.to_string(), "https://example.com/");
526 /// ```
527 pub fn map_scheme<TMapper>(&mut self, mapper: TMapper) -> Option<&Scheme<'uri>>
528 where
529 TMapper: FnOnce(Scheme<'uri>) -> Scheme<'uri>,
530 {
531 self.uri_reference
532 .map_scheme(|scheme| Some(mapper(scheme.unwrap())))
533 }
534
535 /// Normalizes the URI.
536 ///
537 /// A normalized URI will have all of its components normalized.
538 ///
539 /// # Examples
540 ///
541 /// ```
542 /// use std::convert::TryFrom;
543 ///
544 /// use uriparse::URI;
545 ///
546 /// let mut uri = URI::try_from("http://example.com/?a=b").unwrap();
547 /// uri.normalize();
548 /// assert_eq!(uri.to_string(), "http://example.com/?a=b");
549 ///
550 /// let mut uri = URI::try_from("http://EXAMPLE.com/?a=b").unwrap();
551 /// assert_eq!(uri.to_string(), "http://EXAMPLE.com/?a=b");
552 /// uri.normalize();
553 /// assert_eq!(uri.to_string(), "http://example.com/?a=b");
554 /// ```
555 pub fn normalize(&mut self) {
556 self.uri_reference.normalize();
557 }
558
559 /// Returns the path of the URI.
560 ///
561 /// # Examples
562 ///
563 /// ```
564 /// use std::convert::TryFrom;
565 ///
566 /// use uriparse::URI;
567 ///
568 /// let uri = URI::try_from("http://127.0.0.1/my/path").unwrap();
569 /// assert_eq!(uri.path(), "/my/path");
570 /// ```
571 pub fn path(&self) -> &Path<'uri> {
572 self.uri_reference.path()
573 }
574
575 /// Returns the password, if present, of the URI.
576 ///
577 /// Usage of a password in URIs is deprecated.
578 ///
579 /// # Examples
580 ///
581 /// ```
582 /// use std::convert::TryFrom;
583 ///
584 /// use uriparse::URI;
585 ///
586 /// let uri = URI::try_from("http://user:pass@example.com").unwrap();
587 /// assert_eq!(uri.password().unwrap(), "pass");
588 /// ```
589 pub fn password(&self) -> Option<&Password<'uri>> {
590 self.uri_reference.password()
591 }
592
593 /// Returns the port, if present, of the URI.
594 ///
595 /// # Examples
596 ///
597 /// ```
598 /// use std::convert::TryFrom;
599 ///
600 /// use uriparse::URI;
601 ///
602 /// let uri = URI::try_from("http://example.com:8080/").unwrap();
603 /// assert_eq!(uri.port().unwrap(), 8080);
604 /// ```
605 pub fn port(&self) -> Option<u16> {
606 self.uri_reference.port()
607 }
608
609 /// Returns the query, if present, of the URI.
610 ///
611 /// # Examples
612 ///
613 /// ```
614 /// use std::convert::TryFrom;
615 ///
616 /// use uriparse::URI;
617 ///
618 /// let uri = URI::try_from("http://127.0.0.1?my=query").unwrap();
619 /// assert_eq!(uri.query().unwrap(), "my=query");
620 /// ```
621 pub fn query(&self) -> Option<&Query<'uri>> {
622 self.uri_reference.query()
623 }
624
625 /// Creates a new URI which is created by resolving the given reference against this URI.
626 ///
627 /// The algorithm used for resolving the reference is described in
628 /// [[RFC3986, Section 5.2.2](https://tools.ietf.org/html/rfc3986#section-5.2.2)].
629 pub fn resolve(&self, reference: &'uri URIReference<'uri>) -> URI<'uri> {
630 let mut builder = URIBuilder::new();
631
632 if let Some(scheme) = reference.scheme() {
633 let mut path = reference.path().clone();
634 path.remove_dot_segments();
635
636 builder
637 .scheme(scheme.clone())
638 .authority(reference.authority().cloned())
639 .path(path)
640 .query(reference.query().cloned());
641 } else {
642 if reference.authority().is_some() {
643 let mut path = reference.path().clone();
644 path.remove_dot_segments();
645
646 builder
647 .authority(reference.authority().cloned())
648 .path(path)
649 .query(reference.query().cloned());
650 } else {
651 if reference.path().is_relative()
652 && reference.path().segments().len() == 1
653 && reference.path().segments()[0].is_empty()
654 {
655 let mut path = self.path().clone();
656 path.remove_dot_segments();
657 builder.path(path);
658
659 if reference.query().is_some() {
660 builder.query(reference.query().cloned());
661 } else {
662 builder.query(self.query().cloned());
663 }
664 } else {
665 if reference.path().is_absolute() {
666 let mut path = reference.path().clone();
667 path.remove_dot_segments();
668 builder.path(path);
669 } else {
670 let mut path = if self.authority().is_some()
671 && self.path().segments().len() == 1
672 && self.path().segments()[0].is_empty()
673 {
674 let mut path = reference.path().clone();
675 path.set_absolute(true);
676 path
677 } else {
678 let mut path = self.path().clone();
679 path.pop();
680
681 for segment in reference.path().segments() {
682 path.push(segment.clone()).unwrap();
683 }
684
685 path
686 };
687
688 path.remove_dot_segments();
689 builder.path(path);
690 }
691
692 builder.query(reference.query().cloned());
693 }
694
695 builder.authority(self.authority().cloned());
696 }
697
698 builder.scheme(self.scheme().clone());
699 }
700
701 builder.fragment(reference.fragment().cloned());
702 builder.build().unwrap()
703 }
704
705 /// Returns the scheme of the URI.
706 ///
707 /// # Examples
708 ///
709 /// ```
710 /// use std::convert::TryFrom;
711 ///
712 /// use uriparse::URI;
713 ///
714 /// let uri = URI::try_from("http://127.0.0.1/").unwrap();
715 /// assert_eq!(uri.scheme(), "http");
716 /// ```
717 pub fn scheme(&self) -> &Scheme<'uri> {
718 self.uri_reference.scheme().unwrap()
719 }
720
721 /// Sets the authority of the URI.
722 ///
723 /// An error will be returned if the conversion to an [`Authority`] fails.
724 ///
725 /// The existing path will be set to absolute (i.e. starts with a `'/'`).
726 ///
727 /// # Examples
728 ///
729 /// ```
730 /// use std::convert::TryFrom;
731 ///
732 /// use uriparse::URI;
733 ///
734 /// let mut uri = URI::try_from("http://example.com").unwrap();
735 /// uri.set_authority(Some("user@example.com:80"));
736 /// assert_eq!(uri.to_string(), "http://user@example.com:80/");
737 /// ```
738 pub fn set_authority<TAuthority, TAuthorityError>(
739 &mut self,
740 authority: Option<TAuthority>,
741 ) -> Result<Option<&Authority<'uri>>, URIError>
742 where
743 Authority<'uri>: TryFrom<TAuthority, Error = TAuthorityError>,
744 URIReferenceError: From<TAuthorityError>,
745 {
746 self.uri_reference
747 .set_authority(authority)
748 .map_err(|error| URIError::try_from(error).unwrap())
749 }
750
751 /// Sets the fragment of the URI.
752 ///
753 /// An error will be returned if the conversion to a [`Fragment`] fails.
754 ///
755 /// # Examples
756 ///
757 /// ```
758 /// use std::convert::TryFrom;
759 ///
760 /// use uriparse::URI;
761 ///
762 /// let mut uri = URI::try_from("http://example.com").unwrap();
763 /// uri.set_fragment(Some("fragment"));
764 /// assert_eq!(uri.to_string(), "http://example.com/#fragment");
765 /// ```
766 pub fn set_fragment<TFragment, TFragmentError>(
767 &mut self,
768 fragment: Option<TFragment>,
769 ) -> Result<Option<&Fragment<'uri>>, URIError>
770 where
771 Fragment<'uri>: TryFrom<TFragment, Error = TFragmentError>,
772 URIReferenceError: From<TFragmentError>,
773 {
774 self.uri_reference
775 .set_fragment(fragment)
776 .map_err(|error| URIError::try_from(error).unwrap())
777 }
778
779 /// Sets the path of the URI.
780 ///
781 /// An error will be returned in one of two cases:
782 /// - The conversion to [`Path`] failed.
783 /// - The path was set to a value that resulted in an invalid URI.
784 ///
785 /// Regardless of whether the given path was set as absolute or relative, if the URI
786 /// reference currently has an authority, the path will be forced to be absolute.
787 ///
788 /// # Examples
789 ///
790 /// ```
791 /// use std::convert::TryFrom;
792 ///
793 /// use uriparse::URI;
794 ///
795 /// let mut uri = URI::try_from("http://example.com").unwrap();
796 /// uri.set_path("my/path");
797 /// assert_eq!(uri.to_string(), "http://example.com/my/path");
798 /// ```
799 pub fn set_path<TPath, TPathError>(&mut self, path: TPath) -> Result<&Path<'uri>, URIError>
800 where
801 Path<'uri>: TryFrom<TPath, Error = TPathError>,
802 URIReferenceError: From<TPathError>,
803 {
804 self.uri_reference
805 .set_path(path)
806 .map_err(|error| URIError::try_from(error).unwrap())
807 }
808
809 /// Sets the query of the URI.
810 ///
811 /// An error will be returned if the conversion to a [`Query`] fails.
812 ///
813 /// # Examples
814 ///
815 /// ```
816 /// use std::convert::TryFrom;
817 ///
818 /// use uriparse::URI;
819 ///
820 /// let mut uri = URI::try_from("http://example.com").unwrap();
821 /// uri.set_query(Some("myquery"));
822 /// assert_eq!(uri.to_string(), "http://example.com/?myquery");
823 /// ```
824 pub fn set_query<TQuery, TQueryError>(
825 &mut self,
826 query: Option<TQuery>,
827 ) -> Result<Option<&Query<'uri>>, URIError>
828 where
829 Query<'uri>: TryFrom<TQuery, Error = TQueryError>,
830 URIReferenceError: From<TQueryError>,
831 {
832 self.uri_reference
833 .set_query(query)
834 .map_err(|error| URIError::try_from(error).unwrap())
835 }
836
837 /// Sets the scheme of the URI.
838 ///
839 /// An error will be returned if the conversion to a [`Scheme`] fails.
840 ///
841 /// # Examples
842 ///
843 /// ```
844 /// use std::convert::TryFrom;
845 ///
846 /// use uriparse::URI;
847 ///
848 /// let mut uri = URI::try_from("http://example.com").unwrap();
849 /// uri.set_scheme("https");
850 /// assert_eq!(uri.to_string(), "https://example.com/");
851 /// ```
852 pub fn set_scheme<TScheme, TSchemeError>(
853 &mut self,
854 scheme: TScheme,
855 ) -> Result<&Scheme<'uri>, URIError>
856 where
857 Scheme<'uri>: TryFrom<TScheme, Error = TSchemeError>,
858 URIReferenceError: From<TSchemeError>,
859 {
860 self.uri_reference
861 .set_scheme(Some(scheme))
862 .map_err(|error| URIError::try_from(error).unwrap())?;
863 Ok(self.scheme())
864 }
865
866 /// Returns a new URI which is identical but has a lifetime tied to this URI.
867 ///
868 /// This function will perform a memory allocation.
869 pub fn to_borrowed(&self) -> URI {
870 URI {
871 uri_reference: self.uri_reference.to_borrowed(),
872 }
873 }
874
875 /// Returns the username, if present, of the URI.
876 ///
877 /// # Examples
878 ///
879 /// ```
880 /// use std::convert::TryFrom;
881 ///
882 /// use uriparse::URI;
883 ///
884 /// let uri = URI::try_from("http://username@example.com").unwrap();
885 /// assert_eq!(uri.username().unwrap(), "username");
886 /// ```
887 pub fn username(&self) -> Option<&Username<'uri>> {
888 self.uri_reference.username()
889 }
890}
891
892impl Display for URI<'_> {
893 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
894 self.uri_reference.fmt(formatter)
895 }
896}
897
898impl<'uri> From<URI<'uri>> for String {
899 fn from(value: URI<'uri>) -> Self {
900 value.to_string()
901 }
902}
903
904impl<'uri> From<URI<'uri>> for URIReference<'uri> {
905 fn from(value: URI<'uri>) -> Self {
906 value.uri_reference
907 }
908}
909
910impl<'uri> TryFrom<&'uri [u8]> for URI<'uri> {
911 type Error = URIError;
912
913 fn try_from(value: &'uri [u8]) -> Result<Self, Self::Error> {
914 let uri_reference =
915 URIReference::try_from(value).map_err(|error| URIError::try_from(error).unwrap())?;
916
917 if uri_reference.is_relative_reference() {
918 Err(URIError::NotURI)
919 } else {
920 Ok(URI { uri_reference })
921 }
922 }
923}
924
925impl<'uri> TryFrom<&'uri str> for URI<'uri> {
926 type Error = URIError;
927
928 fn try_from(value: &'uri str) -> Result<Self, Self::Error> {
929 URI::try_from(value.as_bytes())
930 }
931}
932
933impl<'uri> TryFrom<URIReference<'uri>> for URI<'uri> {
934 type Error = URIError;
935
936 fn try_from(value: URIReference<'uri>) -> Result<Self, Self::Error> {
937 if value.is_uri() {
938 Ok(URI {
939 uri_reference: value,
940 })
941 } else {
942 Err(URIError::NotURI)
943 }
944 }
945}
946
947/// A builder type for [`URI]`.
948///
949/// You must use the [`URI::scheme`] and [`URI::path`] functions before building as URIs always
950/// have a scheme and path. Everything else is optional.
951#[derive(Clone, Debug, Default, Eq, PartialEq)]
952pub struct URIBuilder<'uri> {
953 /// All URIs are also URI references, so we just maintain a [`URIReferenceBuilder`] underneath.
954 uri_reference_builder: URIReferenceBuilder<'uri>,
955}
956
957impl<'uri> URIBuilder<'uri> {
958 /// Sets the authority part of the URI.
959 ///
960 /// It is optional to specify a authority.
961 ///
962 /// # Examples
963 ///
964 /// ```
965 /// use std::convert::TryFrom;
966 ///
967 /// use uriparse::{Authority, Path, Scheme, URIBuilder};
968 ///
969 /// let mut builder = URIBuilder::new();
970 /// builder
971 /// .scheme(Scheme::HTTP)
972 /// .authority(Some(Authority::try_from("example.com").unwrap()))
973 /// .path(Path::try_from("/my/path").unwrap());
974 /// let reference = builder.build().unwrap();
975 /// assert_eq!(reference.to_string(), "http://example.com/my/path");
976 /// ```
977 pub fn authority(&mut self, authority: Option<Authority<'uri>>) -> &mut Self {
978 self.uri_reference_builder.authority(authority);
979 self
980 }
981
982 /// Consumes the builder and tries to build a [`URI`].
983 ///
984 /// This function will error in one of three situations:
985 /// - A scheme and path were not specified in the builder.
986 /// - While all individual components were valid, their combination as a URI was invalid.
987 ///
988 /// # Examples
989 ///
990 /// First error type (scheme and/or path were not specified):
991 ///
992 /// ```
993 /// use std::convert::TryFrom;
994 ///
995 /// use uriparse::{Authority, Path, URIBuilder};
996 ///
997 /// let result = URIBuilder::new()
998 /// .with_authority(Some(Authority::try_from("example.com").unwrap()))
999 /// .with_path(Path::try_from("/my/path").unwrap())
1000 /// .build();
1001 /// assert!(result.is_err());
1002 /// ```
1003 ///
1004 /// Second error type (URI with no authority cannot have path starting with `"//"`):
1005 ///
1006 /// ```
1007 /// use std::convert::TryFrom;
1008 ///
1009 /// use uriparse::{Scheme, Path, URIBuilder};
1010 ///
1011 /// let result = URIBuilder::new()
1012 /// .with_scheme(Scheme::URN)
1013 /// .with_path(Path::try_from("//path").unwrap())
1014 /// .build();
1015 /// assert!(result.is_err());
1016 /// ```
1017 pub fn build(self) -> Result<URI<'uri>, URIError> {
1018 let uri_reference = self
1019 .uri_reference_builder
1020 .build()
1021 .map_err(|error| URIError::try_from(error).unwrap())?;
1022
1023 if !uri_reference.has_scheme() {
1024 return Err(URIError::MissingScheme);
1025 }
1026
1027 Ok(URI { uri_reference })
1028 }
1029
1030 /// Sets the fragment part of the URI.
1031 ///
1032 /// It is optional to specify a fragment.
1033 ///
1034 /// # Examples
1035 ///
1036 /// ```
1037 /// use std::convert::TryFrom;
1038 ///
1039 /// use uriparse::{Fragment, Path, Scheme, URIBuilder};
1040 ///
1041 /// let mut builder = URIBuilder::new();
1042 /// builder
1043 /// .scheme(Scheme::URN)
1044 /// .path(Path::try_from("path").unwrap())
1045 /// .fragment(Some(Fragment::try_from("fragment").unwrap()));
1046 /// let uri = builder.build().unwrap();
1047 /// assert_eq!(uri.to_string(), "urn:path#fragment");
1048 /// ```
1049 pub fn fragment(&mut self, fragment: Option<Fragment<'uri>>) -> &mut Self {
1050 self.uri_reference_builder.fragment(fragment);
1051 self
1052 }
1053
1054 /// Constructs a new builder with nothing set.
1055 pub fn new() -> Self {
1056 URIBuilder::default()
1057 }
1058
1059 /// Sets the path part of the URI.
1060 ///
1061 /// It is required to specify a path. Not doing so will result in an error during the
1062 /// [`URIBuilder::build`] function.
1063 ///
1064 /// # Examples
1065 ///
1066 /// ```
1067 /// use std::convert::TryFrom;
1068 ///
1069 /// use uriparse::{Path, Scheme, URIBuilder};
1070 ///
1071 /// let mut builder = URIBuilder::new();
1072 /// builder
1073 /// .scheme(Scheme::URN)
1074 /// .path(Path::try_from("path").unwrap());
1075 /// let uri = builder.build().unwrap();
1076 /// assert_eq!(uri.to_string(), "urn:path");
1077 /// ```
1078 pub fn path(&mut self, path: Path<'uri>) -> &mut Self {
1079 self.uri_reference_builder.path(path);
1080 self
1081 }
1082
1083 /// Sets the query part of the URI reference.
1084 ///
1085 /// It is optional to specify a query.
1086 ///
1087 /// # Examples
1088 ///
1089 /// ```
1090 /// use std::convert::TryFrom;
1091 ///
1092 /// use uriparse::{Path, Query, Scheme, URIBuilder};
1093 ///
1094 /// let mut builder = URIBuilder::new();
1095 /// builder
1096 /// .scheme(Scheme::URN)
1097 /// .path(Path::try_from("path").unwrap())
1098 /// .query(Some(Query::try_from("query").unwrap()));
1099 /// let uri = builder.build().unwrap();
1100 /// assert_eq!(uri.to_string(), "urn:path?query");
1101 /// ```
1102 pub fn query(&mut self, query: Option<Query<'uri>>) -> &mut Self {
1103 self.uri_reference_builder.query(query);
1104 self
1105 }
1106
1107 /// Sets the scheme part of the URI reference.
1108 ///
1109 /// It is required to specify a scheme. Not doing so will result in an error during the
1110 /// [`URIBuilder::build`] function.
1111 ///
1112 /// # Examples
1113 ///
1114 /// ```
1115 /// use std::convert::TryFrom;
1116 ///
1117 /// use uriparse::{Authority, Path, Scheme, URIBuilder};
1118 ///
1119 /// let mut builder = URIBuilder::new();
1120 /// builder
1121 /// .scheme(Scheme::HTTP)
1122 /// .authority(Some(Authority::try_from("example.com").unwrap()))
1123 /// .path(Path::try_from("/my/path").unwrap());
1124 /// let uri = builder.build().unwrap();
1125 /// assert_eq!(uri.to_string(), "http://example.com/my/path");
1126 /// ```
1127 pub fn scheme(&mut self, scheme: Scheme<'uri>) -> &mut Self {
1128 self.uri_reference_builder.scheme(Some(scheme));
1129 self
1130 }
1131
1132 /// Sets the authority part of the URI.1
1133 ///
1134 /// If the given authority is not a valid authority (i.e. the conversion fails), an error is
1135 /// stored internally and checked during the [`URIBuilder::build`] function. The error state
1136 /// will be rewritten for any following calls to this function.
1137 ///
1138 /// It is optional to specify an authority.
1139 ///
1140 /// # Examples
1141 ///
1142 /// ```
1143 /// use uriparse::URIBuilder;
1144 ///
1145 /// let mut builder = URIBuilder::new();
1146 /// builder
1147 /// .try_scheme("http")
1148 /// .unwrap()
1149 /// .try_authority(Some("example.com"))
1150 /// .unwrap()
1151 /// .try_path("/my/path")
1152 /// .unwrap();
1153 /// let uri = builder.build().unwrap();
1154 /// assert_eq!(uri.to_string(), "http://example.com/my/path");
1155 /// ```
1156 pub fn try_authority<TAuthority, TAuthorityError>(
1157 &mut self,
1158 authority: Option<TAuthority>,
1159 ) -> Result<&mut Self, AuthorityError>
1160 where
1161 Authority<'uri>: TryFrom<TAuthority, Error = TAuthorityError>,
1162 AuthorityError: From<TAuthorityError>,
1163 {
1164 self.uri_reference_builder.try_authority(authority)?;
1165 Ok(self)
1166 }
1167
1168 /// Sets the fragment part of the URI.
1169 ///
1170 /// If the given fragment is not a valid fragment (i.e. the conversion fails), an error is
1171 /// stored internally and checked during the [`URIBuilder::build`] function. The error state
1172 /// will be rewritten for any following calls to this function.
1173 ///
1174 /// It is optional to specify a fragment.
1175 ///
1176 /// # Examples
1177 ///
1178 /// ```
1179 /// use uriparse::URIBuilder;
1180 ///
1181 /// let mut builder = URIBuilder::new();
1182 /// builder
1183 /// .try_scheme("urn")
1184 /// .unwrap()
1185 /// .try_path("path")
1186 /// .unwrap()
1187 /// .try_fragment(Some("fragment"))
1188 /// .unwrap();
1189 /// let uri = builder.build().unwrap();
1190 /// assert_eq!(uri.to_string(), "urn:path#fragment");
1191 /// ```
1192 pub fn try_fragment<TFragment, TFragmentError>(
1193 &mut self,
1194 fragment: Option<TFragment>,
1195 ) -> Result<&mut Self, FragmentError>
1196 where
1197 Fragment<'uri>: TryFrom<TFragment, Error = TFragmentError>,
1198 FragmentError: From<TFragmentError>,
1199 {
1200 self.uri_reference_builder.try_fragment(fragment)?;
1201 Ok(self)
1202 }
1203
1204 /// Sets the path part of the URI.
1205 ///
1206 /// If the given path is not a valid path (i.e. the conversion fails), an error is stored
1207 /// internally and checked during the [`URIBuilder::build`] function. The error state will be
1208 /// rewritten for any following calls to this function.
1209 ///
1210 /// It is required to specify a path.
1211 ///
1212 /// # Examples
1213 ///
1214 /// ```
1215 /// use uriparse::URIBuilder;
1216 ///
1217 /// let mut builder = URIBuilder::new();
1218 /// builder
1219 /// .try_scheme("urn")
1220 /// .unwrap()
1221 /// .try_path("path")
1222 /// .unwrap();
1223 /// let uri = builder.build().unwrap();
1224 /// assert_eq!(uri.to_string(), "urn:path");
1225 /// ```
1226 pub fn try_path<TPath, TPathError>(&mut self, path: TPath) -> Result<&mut Self, PathError>
1227 where
1228 Path<'uri>: TryFrom<TPath, Error = TPathError>,
1229 PathError: From<TPathError>,
1230 {
1231 self.uri_reference_builder.try_path(path)?;
1232 Ok(self)
1233 }
1234
1235 /// Sets the query part of the URI.
1236 ///
1237 /// If the given query is not a valid query (i.e. the conversion fails), an error is stored
1238 /// internally and checked during the [`URIBuilder::build`] function. The error state will be
1239 /// rewritten for any following calls to this function.
1240 ///
1241 /// It is optional to specify a query.
1242 ///
1243 /// # Examples
1244 ///
1245 /// ```
1246 /// use uriparse::URIBuilder;
1247 ///
1248 /// let mut builder = URIBuilder::new();
1249 /// builder
1250 /// .try_scheme("urn")
1251 /// .unwrap()
1252 /// .try_path("path")
1253 /// .unwrap()
1254 /// .try_query(Some("query"))
1255 /// .unwrap();
1256 /// let uri = builder.build().unwrap();
1257 /// assert_eq!(uri.to_string(), "urn:path?query");
1258 /// ```
1259 pub fn try_query<TQuery, TQueryError>(
1260 &mut self,
1261 query: Option<TQuery>,
1262 ) -> Result<&mut Self, QueryError>
1263 where
1264 Query<'uri>: TryFrom<TQuery, Error = TQueryError>,
1265 QueryError: From<TQueryError>,
1266 {
1267 self.uri_reference_builder.try_query(query)?;
1268 Ok(self)
1269 }
1270
1271 /// Sets the scheme part of the URI.
1272 ///
1273 /// If the given scheme is not a valid scheme (i.e. the conversion fails), an error is stored
1274 /// internally and checked during the [`URIBuilder::build`] function. The error state will be
1275 /// rewritten for any following calls to this function.
1276 ///
1277 /// It is required to specify a scheme. Not doing so will result in an error during the
1278 /// [`URIBuilder::build`] function.
1279 ///
1280 /// # Examples
1281 ///
1282 /// ```
1283 /// use std::convert::TryFrom;
1284 ///
1285 /// use uriparse::{Path, Scheme, URIBuilder};
1286 ///
1287 /// let mut builder = URIBuilder::new();
1288 /// builder
1289 /// .try_scheme("urn")
1290 /// .unwrap()
1291 /// .try_path("path")
1292 /// .unwrap();
1293 /// let uri = builder.build().unwrap();
1294 /// assert_eq!(uri.to_string(), "urn:path");
1295 /// ```
1296 pub fn try_scheme<TScheme, TSchemeError>(
1297 &mut self,
1298 scheme: TScheme,
1299 ) -> Result<&mut Self, SchemeError>
1300 where
1301 Scheme<'uri>: TryFrom<TScheme, Error = TSchemeError>,
1302 SchemeError: From<TSchemeError>,
1303 {
1304 self.uri_reference_builder.try_scheme(Some(scheme))?;
1305 Ok(self)
1306 }
1307
1308 /// Consumes the builder and sets the authority part of the URI.
1309 ///
1310 /// It is optional to specify an authority.
1311 ///
1312 /// # Examples
1313 ///
1314 /// ```
1315 /// use std::convert::TryFrom;
1316 ///
1317 /// use uriparse::{Authority, Path, Scheme, URIBuilder};
1318 ///
1319 /// let uri = URIBuilder::new()
1320 /// .with_scheme(Scheme::HTTP)
1321 /// .with_authority(Some(Authority::try_from("example.com").unwrap()))
1322 /// .with_path(Path::try_from("/").unwrap())
1323 /// .build()
1324 /// .unwrap();
1325 /// assert_eq!(uri.to_string(), "http://example.com/")
1326 /// ```
1327 pub fn with_authority(mut self, authority: Option<Authority<'uri>>) -> Self {
1328 self.authority(authority);
1329 self
1330 }
1331
1332 /// Consumes the builder and sets the fragment part of the URI.
1333 ///
1334 /// It is optional to specify a fragment.
1335 ///
1336 /// # Examples
1337 ///
1338 /// ```
1339 /// use std::convert::TryFrom;
1340 ///
1341 /// use uriparse::{Fragment, Path, Scheme, URIBuilder};
1342 ///
1343 /// let uri = URIBuilder::new()
1344 /// .with_scheme(Scheme::URN)
1345 /// .with_path(Path::try_from("").unwrap())
1346 /// .with_fragment(Some(Fragment::try_from("fragment").unwrap()))
1347 /// .build()
1348 /// .unwrap();
1349 /// assert_eq!(uri.to_string(), "urn:#fragment")
1350 /// ```
1351 pub fn with_fragment(mut self, fragment: Option<Fragment<'uri>>) -> Self {
1352 self.fragment(fragment);
1353 self
1354 }
1355
1356 /// Consumes the builder and sets the path part of the URI.
1357 ///
1358 /// It is required to specify a path. Not doing so will result in an error during the
1359 /// [`URIBuilder::build`] function.
1360 ///
1361 /// # Examples
1362 ///
1363 /// ```
1364 /// use std::convert::TryFrom;
1365 ///
1366 /// use uriparse::{Authority, Path, Scheme, URIBuilder};
1367 ///
1368 /// let reference = URIBuilder::new()
1369 /// .with_scheme(Scheme::HTTP)
1370 /// .with_authority(Some(Authority::try_from("example.com").unwrap()))
1371 /// .with_path(Path::try_from("/").unwrap())
1372 /// .build()
1373 /// .unwrap();
1374 /// assert_eq!(reference.to_string(), "http://example.com/")
1375 /// ```
1376 pub fn with_path(mut self, path: Path<'uri>) -> Self {
1377 self.path(path);
1378 self
1379 }
1380
1381 /// Consumes the builder and sets the query part of the URI.
1382 ///
1383 /// It is optional to specify a query.
1384 ///
1385 /// # Examples
1386 ///
1387 /// ```
1388 /// use std::convert::TryFrom;
1389 ///
1390 /// use uriparse::{Path, Query, Scheme, URIBuilder};
1391 ///
1392 /// let uri = URIBuilder::new()
1393 /// .with_scheme(Scheme::URN)
1394 /// .with_path(Path::try_from("").unwrap())
1395 /// .with_query(Some(Query::try_from("query").unwrap()))
1396 /// .build()
1397 /// .unwrap();
1398 /// assert_eq!(uri.to_string(), "urn:?query")
1399 /// ```
1400 pub fn with_query(mut self, query: Option<Query<'uri>>) -> Self {
1401 self.query(query);
1402 self
1403 }
1404
1405 /// Consumes the builder and sets the scheme part of the URI.
1406 ///
1407 /// It is required to specify a scheme. Not doing so will result in an error during the
1408 /// [`URIBuilder::build`] function.
1409 ///
1410 /// # Examples
1411 ///
1412 /// ```
1413 /// use std::convert::TryFrom;
1414 ///
1415 /// use uriparse::{Authority, Path, Scheme, URIBuilder};
1416 ///
1417 /// let reference = URIBuilder::new()
1418 /// .with_scheme(Scheme::HTTP)
1419 /// .with_authority(Some(Authority::try_from("example.com").unwrap()))
1420 /// .with_path(Path::try_from("/").unwrap())
1421 /// .build()
1422 /// .unwrap();
1423 /// assert_eq!(reference.to_string(), "http://example.com/")
1424 /// ```
1425 pub fn with_scheme(mut self, scheme: Scheme<'uri>) -> Self {
1426 self.scheme(scheme);
1427 self
1428 }
1429}
1430
1431/// An error representing an invalid URI.
1432#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1433#[non_exhaustive]
1434pub enum URIError {
1435 /// Represents the case when there is no authority, but the first path segment starts with
1436 /// `"//"`. This is not allowed because it would be interpreted as an authority component.
1437 ///
1438 /// This can only occur when using creation functions that act on individual parts (e.g.
1439 /// [`URI::from_parts`]).
1440 AbsolutePathStartsWithTwoSlashes,
1441
1442 /// The authority component of the relative reference was invalid.
1443 Authority(AuthorityError),
1444
1445 /// The fragment component of the relative reference was invalid.
1446 Fragment(FragmentError),
1447
1448 /// This error occurs when you do not specify a path component on the builder.
1449 ///
1450 /// This can only occur when using [`URIBuilder`].
1451 MissingPath,
1452
1453 /// This error occurs when you do not specify a scheme component on the builder.
1454 ///
1455 /// This can only occur when using [`URIBuilder`].
1456 MissingScheme,
1457
1458 /// When parsing from some byte string source, if the source ends up being a relative reference,
1459 /// then it is obviously not a URI.
1460 ///
1461 /// This can only occur when parsing from a byte string source.
1462 NotURI,
1463
1464 /// The path component of the relative reference was invalid.
1465 Path(PathError),
1466
1467 /// The query component of the relative reference was invalid.
1468 Query(QueryError),
1469
1470 /// The scheme component of the relative reference was invalid.
1471 Scheme(SchemeError),
1472}
1473
1474impl Display for URIError {
1475 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1476 use self::URIError::*;
1477
1478 match self {
1479 AbsolutePathStartsWithTwoSlashes => {
1480 write!(formatter, "absolute path URI starts with two slashes")
1481 }
1482 Authority(error) => error.fmt(formatter),
1483 Fragment(error) => error.fmt(formatter),
1484 MissingPath => write!(formatter, "missing path"),
1485 MissingScheme => write!(formatter, "missing scheme"),
1486 NotURI => write!(formatter, "not URI"),
1487 Path(error) => error.fmt(formatter),
1488 Query(error) => error.fmt(formatter),
1489 Scheme(error) => error.fmt(formatter),
1490 }
1491 }
1492}
1493
1494impl Error for URIError {}
1495
1496impl From<Infallible> for URIError {
1497 fn from(_: Infallible) -> Self {
1498 URIError::AbsolutePathStartsWithTwoSlashes
1499 }
1500}
1501
1502impl From<AuthorityError> for URIError {
1503 fn from(value: AuthorityError) -> Self {
1504 URIError::Authority(value)
1505 }
1506}
1507
1508impl From<FragmentError> for URIError {
1509 fn from(value: FragmentError) -> Self {
1510 URIError::Fragment(value)
1511 }
1512}
1513
1514impl From<PathError> for URIError {
1515 fn from(value: PathError) -> Self {
1516 URIError::Path(value)
1517 }
1518}
1519
1520impl From<QueryError> for URIError {
1521 fn from(value: QueryError) -> Self {
1522 URIError::Query(value)
1523 }
1524}
1525
1526impl From<SchemeError> for URIError {
1527 fn from(value: SchemeError) -> Self {
1528 URIError::Scheme(value)
1529 }
1530}
1531
1532impl TryFrom<URIReferenceError> for URIError {
1533 type Error = ();
1534
1535 fn try_from(value: URIReferenceError) -> Result<Self, Self::Error> {
1536 use self::URIError::*;
1537
1538 match value {
1539 URIReferenceError::AbsolutePathStartsWithTwoSlashes => {
1540 Ok(AbsolutePathStartsWithTwoSlashes)
1541 }
1542 URIReferenceError::Authority(error) => Ok(Authority(error)),
1543 URIReferenceError::Fragment(error) => Ok(Fragment(error)),
1544 URIReferenceError::MissingPath => Ok(MissingPath),
1545 URIReferenceError::Path(error) => Ok(Path(error)),
1546 URIReferenceError::Query(error) => Ok(Query(error)),
1547 URIReferenceError::Scheme(error) => Ok(Scheme(error)),
1548 URIReferenceError::SchemelessPathStartsWithColonSegment => Err(()),
1549 }
1550 }
1551}
1552
1553#[cfg(test)]
1554mod test {
1555 use super::*;
1556
1557 #[test]
1558 fn test_resolve() {
1559 fn test_case(value: &str, expected: &str) {
1560 let base_uri = URI::try_from("http://a/b/c/d;p?q").unwrap();
1561 let reference = URIReference::try_from(value).unwrap();
1562 assert_eq!(base_uri.resolve(&reference).to_string(), expected);
1563 }
1564
1565 test_case("g:h", "g:h");
1566 test_case("g", "http://a/b/c/g");
1567 test_case("./g", "http://a/b/c/g");
1568 test_case("g/", "http://a/b/c/g/");
1569 test_case("/g", "http://a/g");
1570 test_case("//g", "http://g/");
1571 test_case("?y", "http://a/b/c/d;p?y");
1572 test_case("g?y", "http://a/b/c/g?y");
1573 test_case("#s", "http://a/b/c/d;p?q#s");
1574 test_case("g#s", "http://a/b/c/g#s");
1575 test_case("g?y#s", "http://a/b/c/g?y#s");
1576 test_case(";x", "http://a/b/c/;x");
1577 test_case("g;x", "http://a/b/c/g;x");
1578 test_case("g;x?y#s", "http://a/b/c/g;x?y#s");
1579 test_case("", "http://a/b/c/d;p?q");
1580 test_case(".", "http://a/b/c/");
1581 test_case("./", "http://a/b/c/");
1582 test_case("..", "http://a/b/");
1583 test_case("../", "http://a/b/");
1584 test_case("../g", "http://a/b/g");
1585 test_case("../..", "http://a/");
1586 test_case("../../", "http://a/");
1587 test_case("../../g", "http://a/g");
1588 test_case("../../../g", "http://a/g");
1589 test_case("../../../g", "http://a/g");
1590 test_case("/./g", "http://a/g");
1591 test_case("/../g", "http://a/g");
1592 test_case("g.", "http://a/b/c/g.");
1593 test_case(".g", "http://a/b/c/.g");
1594 test_case("g..", "http://a/b/c/g..");
1595 test_case("..g", "http://a/b/c/..g");
1596 test_case("./../g", "http://a/b/g");
1597 test_case("./g/.", "http://a/b/c/g/");
1598 test_case("g/./h", "http://a/b/c/g/h");
1599 test_case("g/../h", "http://a/b/c/h");
1600 test_case("g;x=1/./y", "http://a/b/c/g;x=1/y");
1601 test_case("g;x=1/../y", "http://a/b/c/y");
1602 test_case("g?y/./x", "http://a/b/c/g?y/./x");
1603 test_case("g?y/../x", "http://a/b/c/g?y/../x");
1604 test_case("g#s/./x", "http://a/b/c/g#s/./x");
1605 test_case("g#s/../x", "http://a/b/c/g#s/../x");
1606 test_case("http:g", "http:g");
1607 }
1608
1609 #[cfg(feature = "serde")]
1610 #[test]
1611 fn test_serde() {
1612 let uri = URI::try_from("http://a/b/c/d;p?q").unwrap();
1613
1614 // Perform serialization
1615 let json_string = serde_json::to_string(&uri).unwrap();
1616
1617 // Perform deserialization
1618 let uri2 = serde_json::from_str(&json_string).unwrap();
1619
1620 assert_eq!(
1621 uri, uri2,
1622 "Information lost in serialization/deserialization"
1623 );
1624 }
1625}