uriparse/uri_reference.rs
1use std::convert::{Infallible, TryFrom};
2use std::error::Error;
3use std::fmt::{self, Display, Formatter, Write};
4use std::mem;
5
6use crate::authority::{parse_authority, Authority, AuthorityError, Host, Password, Username};
7use crate::fragment::{Fragment, FragmentError};
8use crate::path::{parse_path, Path, PathError};
9use crate::query::{parse_query, Query, QueryError};
10use crate::scheme::{parse_scheme, Scheme, SchemeError};
11
12/// A URI reference as defined in
13/// [[RFC3986, Section 4.1]](https://tools.ietf.org/html/rfc3986#section-4.1).
14///
15/// Specifically, a URI reference is either a URI or a relative reference (a schemeless URI).
16#[derive(Clone, Debug, Eq, Hash, PartialEq)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18pub struct URIReference<'uri> {
19 /// The authority component of the URI reference as defined in
20 /// [[RFC3986, Section 3.2]](https://tools.ietf.org/html/rfc3986#section-3.2).
21 authority: Option<Authority<'uri>>,
22
23 /// The fragment component of the URI reference as defined in
24 /// [[RFC3986, Section 3.5]](https://tools.ietf.org/html/rfc3986#section-3.5).
25 fragment: Option<Fragment<'uri>>,
26
27 /// The path component of the URI reference as defined in
28 /// [[RFC3986, Section 3.3]](https://tools.ietf.org/html/rfc3986#section-3.3).
29 path: Path<'uri>,
30
31 /// The query component of the URI reference as defined in
32 /// [[RFC3986, Section 3.4]](https://tools.ietf.org/html/rfc3986#section-3.4).
33 query: Option<Query<'uri>>,
34
35 /// The scheme component of the URI reference as defined in
36 /// [[RFC3986, Section 3.1](https://tools.ietf.org/html/rfc3986#section-3.1).
37 scheme: Option<Scheme<'uri>>,
38}
39
40impl<'uri> URIReference<'uri> {
41 /// Returns the authority, if present, of the URI reference.
42 ///
43 /// # Examples
44 ///
45 /// ```
46 /// use std::convert::TryFrom;
47 ///
48 /// use uriparse::URIReference;
49 ///
50 /// let reference = URIReference::try_from("//example.com/my/path").unwrap();
51 /// assert_eq!(reference.authority().unwrap().to_string(), "example.com");
52 /// ```
53 pub fn authority(&self) -> Option<&Authority<'uri>> {
54 self.authority.as_ref()
55 }
56
57 /// Constructs a default builder for a URI reference.
58 ///
59 /// This provides an alternative means of constructing a URI reference besides parsing and
60 /// [`URIReference::from_parts`].
61 ///
62 /// # Examples
63 ///
64 /// ```
65 /// use std::convert::TryFrom;
66 ///
67 /// use uriparse::{Authority, Path, Scheme, URIReference};
68 ///
69 /// let reference = URIReference::builder()
70 /// .with_scheme(Some(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!(reference.to_string(), "http://example.com/my/path");
76 /// ```
77 pub fn builder<'new_uri>() -> URIReferenceBuilder<'new_uri> {
78 URIReferenceBuilder::default()
79 }
80
81 /// Returns whether the URI reference 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::URIReference;
91 ///
92 /// let reference = URIReference::try_from("http://example.com/my/path").unwrap();
93 /// assert!(reference.can_be_a_base());
94 ///
95 /// let reference = URIReference::try_from("ftp://127.0.0.1#fragment").unwrap();
96 /// assert!(!reference.can_be_a_base());
97 /// ```
98 pub fn can_be_a_base(&self) -> bool {
99 self.has_scheme() && !self.has_fragment()
100 }
101
102 /// Constructs a new [`URIReference`] from the individual parts: scheme, authority, path, query,
103 /// and 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::{Scheme, URIReference};
114 ///
115 /// let reference = URIReference::from_parts(
116 /// None::<Scheme>,
117 /// Some("example.com"),
118 /// "/my/path",
119 /// Some("query"),
120 /// Some("fragment")
121 /// ).unwrap();
122 /// assert_eq!(reference.to_string(), "//example.com/my/path?query#fragment");
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: Option<TScheme>,
138 authority: Option<TAuthority>,
139 path: TPath,
140 query: Option<TQuery>,
141 fragment: Option<TFragment>,
142 ) -> Result<URIReference<'new_uri>, URIReferenceError>
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 scheme = match scheme {
156 Some(scheme) => Some(Scheme::try_from(scheme)?),
157 None => None,
158 };
159
160 let authority = match authority {
161 Some(authority) => Some(Authority::try_from(authority)?),
162 None => None,
163 };
164
165 let mut path = Path::try_from(path)?;
166
167 if authority.is_some() {
168 path.set_absolute(true);
169 }
170
171 validate_absolute_path(authority.as_ref(), &path)?;
172 validate_schemeless_path(scheme.as_ref(), authority.as_ref(), &path)?;
173
174 let query = match query {
175 Some(query) => Some(Query::try_from(query)?),
176 None => None,
177 };
178
179 let fragment = match fragment {
180 Some(fragment) => Some(Fragment::try_from(fragment)?),
181 None => None,
182 };
183
184 Ok(URIReference {
185 authority,
186 fragment,
187 path,
188 query,
189 scheme,
190 })
191 }
192
193 /// Returns the fragment, if present, of the URI reference.
194 ///
195 /// # Examples
196 ///
197 /// ```
198 /// use std::convert::TryFrom;
199 ///
200 /// use uriparse::URIReference;
201 ///
202 /// let reference = URIReference::try_from("http://example.com#fragment").unwrap();
203 /// assert_eq!(reference.fragment().unwrap(), "fragment");
204 /// ```
205 pub fn fragment(&self) -> Option<&Fragment<'uri>> {
206 self.fragment.as_ref()
207 }
208
209 /// Returns whether the URI reference has an authority component.
210 ///
211 /// # Examples
212 ///
213 /// ```
214 /// use std::convert::TryFrom;
215 ///
216 /// use uriparse::URIReference;
217 ///
218 /// let reference = URIReference::try_from("http://example.com").unwrap();
219 /// assert!(reference.has_authority());
220 ///
221 /// let reference = URIReference::try_from("").unwrap();
222 /// assert!(!reference.has_authority());
223 /// ```
224 pub fn has_authority(&self) -> bool {
225 self.authority.is_some()
226 }
227
228 /// Returns whether the URI reference has a fragment component.
229 ///
230 /// # Examples
231 ///
232 /// ```
233 /// use std::convert::TryFrom;
234 ///
235 /// use uriparse::URIReference;
236 ///
237 /// let reference = URIReference::try_from("#test").unwrap();
238 /// assert!(reference.has_fragment());
239 ///
240 /// let reference = URIReference::try_from("http://example.com").unwrap();
241 /// assert!(!reference.has_fragment());
242 /// ```
243 pub fn has_fragment(&self) -> bool {
244 self.fragment.is_some()
245 }
246
247 /// Returns whether the URI reference has a password component.
248 ///
249 /// # Examples
250 ///
251 /// ```
252 /// use std::convert::TryFrom;
253 ///
254 /// use uriparse::URIReference;
255 ///
256 /// let reference = URIReference::try_from("http://user:pass@127.0.0.1").unwrap();
257 /// assert!(reference.has_password());
258 ///
259 /// let reference = URIReference::try_from("http://user@127.0.0.1").unwrap();
260 /// assert!(!reference.has_password());
261 /// ```
262 pub fn has_password(&self) -> bool {
263 if let Some(ref authority) = self.authority {
264 authority.has_password()
265 } else {
266 false
267 }
268 }
269
270 /// Returns whether the URI reference has a port.
271 ///
272 /// # Examples
273 ///
274 /// ```
275 /// use std::convert::TryFrom;
276 ///
277 /// use uriparse::URIReference;
278 ///
279 /// let reference = URIReference::try_from("http://127.0.0.1:8080").unwrap();
280 /// assert!(reference.has_port());
281 ///
282 /// let reference = URIReference::try_from("http://127.0.0.1").unwrap();
283 /// assert!(!reference.has_port());
284 /// ```
285 pub fn has_port(&self) -> bool {
286 if let Some(ref authority) = self.authority {
287 authority.has_port()
288 } else {
289 false
290 }
291 }
292
293 /// Returns whether the URI reference has a query component.
294 ///
295 /// # Examples
296 ///
297 /// ```
298 /// use std::convert::TryFrom;
299 ///
300 /// use uriparse::URIReference;
301 ///
302 /// let reference = URIReference::try_from("/?my=query").unwrap();
303 /// assert!(reference.has_query());
304 ///
305 /// let reference = URIReference::try_from("http://example.com/my/path").unwrap();
306 /// assert!(!reference.has_query());
307 /// ```
308 pub fn has_query(&self) -> bool {
309 self.query.is_some()
310 }
311
312 /// Returns whether the URI reference has a scheme component.
313 ///
314 /// # Examples
315 ///
316 /// ```
317 /// use std::convert::TryFrom;
318 ///
319 /// use uriparse::URIReference;
320 ///
321 /// let reference = URIReference::try_from("http://example.com?my=query").unwrap();
322 /// assert!(reference.has_scheme());
323 ///
324 /// let reference = URIReference::try_from("/my/path").unwrap();
325 /// assert!(!reference.has_scheme());
326 /// ```
327 pub fn has_scheme(&self) -> bool {
328 self.scheme.is_some()
329 }
330
331 /// Returns whether the URI reference has a username component.
332 ///
333 /// # Examples
334 ///
335 /// ```
336 /// use std::convert::TryFrom;
337 ///
338 /// use uriparse::URIReference;
339 ///
340 /// let reference = URIReference::try_from("//username@example.com").unwrap();
341 /// assert!(reference.has_username());
342 ///
343 /// let reference = URIReference::try_from("http://example.com").unwrap();
344 /// assert!(!reference.has_username());
345 /// ```
346 pub fn has_username(&self) -> bool {
347 if let Some(ref authority) = self.authority {
348 authority.has_username()
349 } else {
350 false
351 }
352 }
353
354 /// Returns the host, if present, of the URI reference.
355 ///
356 /// # Examples
357 ///
358 /// ```
359 /// use std::convert::TryFrom;
360 ///
361 /// use uriparse::URIReference;
362 ///
363 /// let reference = URIReference::try_from("http://username@example.com").unwrap();
364 /// assert_eq!(reference.host().unwrap().to_string(), "example.com");
365 /// ```
366 pub fn host(&self) -> Option<&Host<'uri>> {
367 if let Some(ref authority) = self.authority {
368 Some(authority.host())
369 } else {
370 None
371 }
372 }
373
374 /// Consumes the URI reference and converts it into a builder with the same values.
375 ///
376 /// # Examples
377 ///
378 /// ```
379 /// use std::convert::TryFrom;
380 ///
381 /// use uriparse::{Fragment, Query, URIReference};
382 ///
383 /// let reference = URIReference::try_from("//example.com/path?query#fragment").unwrap();
384 /// let mut builder = reference.into_builder();
385 /// builder.query(None::<Query>).fragment(None::<Fragment>);
386 /// let reference = builder.build().unwrap();
387 /// assert_eq!(reference.to_string(), "//example.com/path");
388 /// ```
389 pub fn into_builder(self) -> URIReferenceBuilder<'uri> {
390 let mut builder = URIReferenceBuilder::new();
391 builder
392 .scheme(self.scheme)
393 .authority(self.authority)
394 .path(self.path)
395 .query(self.query)
396 .fragment(self.fragment);
397 builder
398 }
399
400 /// Converts the [`URIReference`] into an owned copy.
401 ///
402 /// If you construct the URI reference from a source with a non-static lifetime, you may run
403 /// into lifetime problems due to the way the struct is designed. Calling this function will
404 /// ensure that the returned value has a static lifetime.
405 ///
406 /// This is different from just cloning. Cloning the URI reference will just copy the
407 /// references, and thus the lifetime will remain the same.
408 pub fn into_owned(self) -> URIReference<'static> {
409 let scheme = self.scheme.map(Scheme::into_owned);
410 let authority = self.authority.map(Authority::into_owned);
411 let path = self.path.into_owned();
412 let query = self.query.map(Query::into_owned);
413 let fragment = self.fragment.map(Fragment::into_owned);
414
415 URIReference {
416 authority,
417 fragment,
418 path,
419 query,
420 scheme,
421 }
422 }
423
424 /// Consumes the [`URIReference`] and returns its parts: scheme, authority, path, query, and
425 /// fragment.
426 ///
427 /// # Examples
428 ///
429 /// ```
430 /// use std::convert::TryFrom;
431 ///
432 /// use uriparse::URIReference;
433 ///
434 /// let reference = URIReference::try_from(
435 /// "http://username:password@example.com:80/my/path?my=query#fragment",
436 /// ).unwrap();
437 /// let (scheme, authority, path, query, fragment) = reference.into_parts();
438 ///
439 /// assert_eq!(scheme.unwrap(), "http");
440 /// assert_eq!(authority.unwrap().to_string(), "username:password@example.com:80");
441 /// assert_eq!(path, "/my/path");
442 /// assert_eq!(query.unwrap(), "my=query");
443 /// assert_eq!(fragment.unwrap(), "fragment");
444 /// ```
445 pub fn into_parts(
446 self,
447 ) -> (
448 Option<Scheme<'uri>>,
449 Option<Authority<'uri>>,
450 Path<'uri>,
451 Option<Query<'uri>>,
452 Option<Fragment<'uri>>,
453 ) {
454 (
455 self.scheme,
456 self.authority,
457 self.path,
458 self.query,
459 self.fragment,
460 )
461 }
462
463 /// Returns whether the URI reference is an absolute path reference.
464 ///
465 /// A URI reference is an absolute path reference if it is a relative reference that begins with
466 /// a single `'/'`.
467 ///
468 /// # Examples
469 ///
470 /// ```
471 /// use std::convert::TryFrom;
472 ///
473 /// use uriparse::URIReference;
474 ///
475 /// let reference = URIReference::try_from("/my/path").unwrap();
476 /// assert!(reference.is_absolute_path_reference());
477 /// ```
478 pub fn is_absolute_path_reference(&self) -> bool {
479 self.scheme.is_none() && self.authority.is_none() && self.path.is_absolute()
480 }
481
482 /// Returns whether the URI reference is a network path reference.
483 ///
484 /// A URI reference is a network path reference if it is a relative reference that begins with
485 /// two `'/'`.
486 ///
487 /// # Examples
488 ///
489 /// ```
490 /// use std::convert::TryFrom;
491 ///
492 /// use uriparse::URIReference;
493 ///
494 /// let reference = URIReference::try_from("//example.com").unwrap();
495 /// assert!(reference.is_network_path_reference());
496 /// ```
497 pub fn is_network_path_reference(&self) -> bool {
498 self.scheme.is_none() && self.authority.is_some()
499 }
500
501 /// Returns whether the URI reference is normalized.
502 ///
503 /// A normalized URI reference will have all of its components normalized.
504 ///
505 /// # Examples
506 ///
507 /// ```
508 /// use std::convert::TryFrom;
509 ///
510 /// use uriparse::URIReference;
511 ///
512 /// let reference = URIReference::try_from("http://example.com/?a=b").unwrap();
513 /// assert!(reference.is_normalized());
514 ///
515 /// let mut reference = URIReference::try_from("http://EXAMPLE.com/?a=b").unwrap();
516 /// assert!(!reference.is_normalized());
517 /// reference.normalize();
518 /// assert!(reference.is_normalized());
519 /// ```
520 pub fn is_normalized(&self) -> bool {
521 if let Some(scheme) = self.scheme.as_ref() {
522 if !scheme.is_normalized() {
523 return false;
524 }
525 }
526
527 if let Some(authority) = self.authority.as_ref() {
528 if !authority.is_normalized() {
529 return false;
530 }
531 }
532
533 if !self.path.is_normalized(self.scheme.is_none()) {
534 return false;
535 }
536
537 if let Some(query) = self.query.as_ref() {
538 if !query.is_normalized() {
539 return false;
540 }
541 }
542
543 if let Some(fragment) = self.fragment.as_ref() {
544 if !fragment.is_normalized() {
545 return false;
546 }
547 }
548
549 true
550 }
551
552 /// Returns whether the URI reference is a relative path reference.
553 ///
554 /// A URI reference is a relative path reference if it is a relative reference that does not
555 /// begin with a `'/'`.
556 ///
557 /// # Examples
558 ///
559 /// ```
560 /// use std::convert::TryFrom;
561 ///
562 /// use uriparse::URIReference;
563 ///
564 /// let reference = URIReference::try_from("my/path").unwrap();
565 /// assert!(reference.is_relative_path_reference());
566 /// ```
567 pub fn is_relative_path_reference(&self) -> bool {
568 self.scheme.is_none() && self.authority.is_none() && !self.path.is_absolute()
569 }
570
571 /// Returns whether the URI reference is a relative reference.
572 ///
573 /// A URI reference is a relative reference if it has no scheme.
574 ///
575 /// # Examples
576 ///
577 /// ```
578 /// use std::convert::TryFrom;
579 ///
580 /// use uriparse::URIReference;
581 ///
582 /// let reference = URIReference::try_from("/my/path").unwrap();
583 /// assert!(reference.is_relative_reference());
584 /// ```
585 pub fn is_relative_reference(&self) -> bool {
586 self.scheme.is_none()
587 }
588
589 /// Returns whether the URI reference is a URI.
590 ///
591 /// A URI reference is a URI if it has a scheme.
592 ///
593 /// # Examples
594 ///
595 /// ```
596 /// use std::convert::TryFrom;
597 ///
598 /// use uriparse::URIReference;
599 ///
600 /// let reference = URIReference::try_from("http://example.com").unwrap();
601 /// assert!(reference.is_uri());
602 /// ```
603 pub fn is_uri(&self) -> bool {
604 self.scheme.is_some()
605 }
606
607 /// Maps the authority using the given map function.
608 ///
609 /// This function will panic if, as a result of the authority change, the URI reference becomes
610 /// invalid.
611 ///
612 /// # Examples
613 ///
614 /// ```
615 /// use std::convert::TryFrom;
616 ///
617 /// use uriparse::{Authority, URIReference};
618 ///
619 /// let mut reference = URIReference::try_from("http://example.com").unwrap();
620 /// reference.map_authority(|_| Some(Authority::try_from("127.0.0.1").unwrap()));
621 /// assert_eq!(reference.to_string(), "http://127.0.0.1/");
622 /// ```
623 pub fn map_authority<TMapper>(&mut self, mapper: TMapper) -> Option<&Authority<'uri>>
624 where
625 TMapper: FnOnce(Option<Authority<'uri>>) -> Option<Authority<'uri>>,
626 {
627 let authority = mapper(self.authority.take());
628 self.set_authority(authority)
629 .expect("mapped authority resulted in invalid state")
630 }
631
632 /// Maps the fragment using the given map function.
633 ///
634 /// # Examples
635 ///
636 /// ```
637 /// use std::convert::TryFrom;
638 ///
639 /// use uriparse::{Fragment, URIReference};
640 ///
641 /// let mut reference = URIReference::try_from("http://example.com").unwrap();
642 /// reference.map_fragment(|_| Some(Fragment::try_from("fragment").unwrap()));
643 /// assert_eq!(reference.to_string(), "http://example.com/#fragment");
644 /// ```
645 pub fn map_fragment<TMapper>(&mut self, mapper: TMapper) -> Option<&Fragment<'uri>>
646 where
647 TMapper: FnOnce(Option<Fragment<'uri>>) -> Option<Fragment<'uri>>,
648 {
649 let fragment = mapper(self.fragment.take());
650 self.set_fragment(fragment)
651 .expect("mapped fragment resulted in invalid state")
652 }
653
654 /// Maps the path using the given map function.
655 ///
656 /// This function will panic if, as a result of the path change, the URI reference becomes
657 /// invalid.
658 ///
659 /// # Examples
660 ///
661 /// ```
662 /// use std::convert::TryFrom;
663 ///
664 /// use uriparse::{Authority, URIReference};
665 ///
666 /// let mut reference = URIReference::try_from("http://example.com").unwrap();
667 /// reference.map_path(|mut path| {
668 /// path.push("test").unwrap();
669 /// path.push("path").unwrap();
670 /// path
671 /// });
672 /// assert_eq!(reference.to_string(), "http://example.com/test/path");
673 /// ```
674 pub fn map_path<TMapper>(&mut self, mapper: TMapper) -> &Path<'uri>
675 where
676 TMapper: FnOnce(Path<'uri>) -> Path<'uri>,
677 {
678 // Unsafe: We're creating an invalid path just as a temporary sentinel value, but it is
679 // replaced shortly after.
680 let temp_path = unsafe { Path::new_with_no_segments(true) };
681 let path = mapper(mem::replace(&mut self.path, temp_path));
682 self.set_path(path)
683 .expect("mapped path resulted in invalid state")
684 }
685
686 /// Maps the query using the given map function.
687 ///
688 /// # Examples
689 ///
690 /// ```
691 /// use std::convert::TryFrom;
692 ///
693 /// use uriparse::{Query, URIReference};
694 ///
695 /// let mut reference = URIReference::try_from("http://example.com").unwrap();
696 /// reference.map_query(|_| Some(Query::try_from("query").unwrap()));
697 /// assert_eq!(reference.to_string(), "http://example.com/?query");
698 /// ```
699 pub fn map_query<TMapper>(&mut self, mapper: TMapper) -> Option<&Query<'uri>>
700 where
701 TMapper: FnOnce(Option<Query<'uri>>) -> Option<Query<'uri>>,
702 {
703 let query = mapper(self.query.take());
704 self.set_query(query)
705 .expect("mapped query resulted in invalid state")
706 }
707
708 /// Maps the scheme using the given map function.
709 ///
710 /// This function will panic if, as a result of the scheme change, the URI reference becomes
711 /// invalid.
712 ///
713 /// # Examples
714 ///
715 /// ```
716 /// use std::convert::TryFrom;
717 ///
718 /// use uriparse::{Scheme, URIReference};
719 ///
720 /// let mut reference = URIReference::try_from("http://example.com").unwrap();
721 /// reference.map_scheme(|_| Some(Scheme::try_from("https").unwrap()));
722 /// assert_eq!(reference.to_string(), "https://example.com/");
723 /// ```
724 pub fn map_scheme<TMapper>(&mut self, mapper: TMapper) -> Option<&Scheme<'uri>>
725 where
726 TMapper: FnOnce(Option<Scheme<'uri>>) -> Option<Scheme<'uri>>,
727 {
728 let scheme = mapper(self.scheme.take());
729 self.set_scheme(scheme)
730 .expect("mapped scheme resulted in invalid state")
731 }
732
733 /// Normalizes the URI reference.
734 ///
735 /// A normalized URI reference will have all of its components normalized.
736 ///
737 /// # Examples
738 ///
739 /// ```
740 /// use std::convert::TryFrom;
741 ///
742 /// use uriparse::URIReference;
743 ///
744 /// let mut reference = URIReference::try_from("http://example.com/?a=b").unwrap();
745 /// reference.normalize();
746 /// assert_eq!(reference.to_string(), "http://example.com/?a=b");
747 ///
748 /// let mut reference = URIReference::try_from("http://EXAMPLE.com/?a=b").unwrap();
749 /// assert_eq!(reference.to_string(), "http://EXAMPLE.com/?a=b");
750 /// reference.normalize();
751 /// assert_eq!(reference.to_string(), "http://example.com/?a=b");
752 /// ```
753 pub fn normalize(&mut self) {
754 if let Some(scheme) = self.scheme.as_mut() {
755 scheme.normalize();
756 }
757
758 if let Some(authority) = self.authority.as_mut() {
759 authority.normalize();
760 }
761
762 self.path.normalize(self.scheme.is_none());
763
764 if let Some(query) = self.query.as_mut() {
765 query.normalize();
766 }
767
768 if let Some(fragment) = self.fragment.as_mut() {
769 fragment.normalize();
770 }
771 }
772
773 /// Returns the path of the URI reference.
774 ///
775 /// # Examples
776 ///
777 /// ```
778 /// use std::convert::TryFrom;
779 ///
780 /// use uriparse::URIReference;
781 ///
782 /// let reference = URIReference::try_from("http://127.0.0.1/my/path").unwrap();
783 /// assert_eq!(reference.path(), "/my/path");
784 /// ```
785 pub fn path(&self) -> &Path<'uri> {
786 &self.path
787 }
788
789 /// Returns the password, if present, of the URI reference.
790 ///
791 /// Usage of a password in URI and URI references is deprecated.
792 ///
793 /// # Examples
794 ///
795 /// ```
796 /// use std::convert::TryFrom;
797 ///
798 /// use uriparse::URIReference;
799 ///
800 /// let reference = URIReference::try_from("http://user:pass@example.com").unwrap();
801 /// assert_eq!(reference.password().unwrap(), "pass");
802 /// ```
803 pub fn password(&self) -> Option<&Password<'uri>> {
804 if let Some(ref authority) = self.authority {
805 authority.password()
806 } else {
807 None
808 }
809 }
810
811 /// Returns the port, if present, of the URI reference.
812 ///
813 /// # Examples
814 ///
815 /// ```
816 /// use std::convert::TryFrom;
817 ///
818 /// use uriparse::URIReference;
819 ///
820 /// let reference = URIReference::try_from("http://example.com:8080/").unwrap();
821 /// assert_eq!(reference.port().unwrap(), 8080);
822 /// ```
823 pub fn port(&self) -> Option<u16> {
824 if let Some(ref authority) = self.authority {
825 authority.port()
826 } else {
827 None
828 }
829 }
830
831 /// Returns the query, if present, of the URI reference.
832 ///
833 /// # Examples
834 ///
835 /// ```
836 /// use std::convert::TryFrom;
837 ///
838 /// use uriparse::URIReference;
839 ///
840 /// let reference = URIReference::try_from("http://127.0.0.1?my=query").unwrap();
841 /// assert_eq!(reference.query().unwrap(), "my=query");
842 /// ```
843 pub fn query(&self) -> Option<&Query<'uri>> {
844 self.query.as_ref()
845 }
846
847 /// Returns the scheme, if present, of the URI reference.
848 ///
849 /// # Examples
850 ///
851 /// ```
852 /// use std::convert::TryFrom;
853 ///
854 /// use uriparse::URIReference;
855 ///
856 /// let reference = URIReference::try_from("http://127.0.0.1/").unwrap();
857 /// assert_eq!(reference.scheme().unwrap(), "http");
858 /// ```
859 pub fn scheme(&self) -> Option<&Scheme<'uri>> {
860 self.scheme.as_ref()
861 }
862
863 /// Sets the authority of the URI reference.
864 ///
865 /// An error will be returned if the conversion to an [`Authority`] fails.
866 ///
867 /// The existing path will be set to absolute (i.e. starts with a `'/'`).
868 ///
869 /// # Examples
870 ///
871 /// ```
872 /// use std::convert::TryFrom;
873 ///
874 /// use uriparse::URIReference;
875 ///
876 /// let mut reference = URIReference::try_from("http://example.com").unwrap();
877 /// reference.set_authority(Some("user@example.com:80"));
878 /// assert_eq!(reference.to_string(), "http://user@example.com:80/");
879 /// ```
880 pub fn set_authority<TAuthority, TAuthorityError>(
881 &mut self,
882 authority: Option<TAuthority>,
883 ) -> Result<Option<&Authority<'uri>>, URIReferenceError>
884 where
885 Authority<'uri>: TryFrom<TAuthority, Error = TAuthorityError>,
886 URIReferenceError: From<TAuthorityError>,
887 {
888 self.authority = match authority {
889 Some(authority) => {
890 self.path.set_absolute(true);
891 Some(Authority::try_from(authority)?)
892 }
893 None => {
894 validate_absolute_path(None, &self.path)?;
895 None
896 }
897 };
898 Ok(self.authority())
899 }
900
901 /// Sets the fragment of the URI reference.
902 ///
903 /// An error will be returned if the conversion to a [`Fragment`] fails.
904 ///
905 /// # Examples
906 ///
907 /// ```
908 /// use std::convert::TryFrom;
909 ///
910 /// use uriparse::URIReference;
911 ///
912 /// let mut reference = URIReference::try_from("http://example.com").unwrap();
913 /// reference.set_fragment(Some("fragment"));
914 /// assert_eq!(reference.to_string(), "http://example.com/#fragment");
915 /// ```
916 pub fn set_fragment<TFragment, TFragmentError>(
917 &mut self,
918 fragment: Option<TFragment>,
919 ) -> Result<Option<&Fragment<'uri>>, URIReferenceError>
920 where
921 Fragment<'uri>: TryFrom<TFragment, Error = TFragmentError>,
922 URIReferenceError: From<TFragmentError>,
923 {
924 self.fragment = match fragment {
925 Some(fragment) => Some(Fragment::try_from(fragment)?),
926 None => None,
927 };
928 Ok(self.fragment())
929 }
930
931 /// Sets the path of the URI reference.
932 ///
933 /// An error will be returned in one of two cases:
934 /// - The conversion to [`Path`] failed.
935 /// - The path was set to a value that resulted in an invalid URI reference.
936 ///
937 /// Regardless of whether the given path was set as absolute or relative, if the URI
938 /// reference currently has an authority, the path will be forced to be absolute.
939 ///
940 /// # Examples
941 ///
942 /// ```
943 /// use std::convert::TryFrom;
944 ///
945 /// use uriparse::URIReference;
946 ///
947 /// let mut reference = URIReference::try_from("http://example.com").unwrap();
948 /// reference.set_path("my/path");
949 /// assert_eq!(reference.to_string(), "http://example.com/my/path");
950 /// ```
951 pub fn set_path<TPath, TPathError>(
952 &mut self,
953 path: TPath,
954 ) -> Result<&Path<'uri>, URIReferenceError>
955 where
956 Path<'uri>: TryFrom<TPath, Error = TPathError>,
957 URIReferenceError: From<TPathError>,
958 {
959 let mut path = Path::try_from(path)?;
960 validate_absolute_path(self.authority.as_ref(), &path)?;
961 validate_schemeless_path(self.scheme.as_ref(), self.authority.as_ref(), &path)?;
962
963 if self.authority.is_some() {
964 path.set_absolute(true);
965 }
966
967 self.path = path;
968 Ok(self.path())
969 }
970
971 /// Sets the query of the URI reference.
972 ///
973 /// An error will be returned if the conversion to a [`Query`] fails.
974 ///
975 /// # Examples
976 ///
977 /// ```
978 /// use std::convert::TryFrom;
979 ///
980 /// use uriparse::URIReference;
981 ///
982 /// let mut reference = URIReference::try_from("http://example.com").unwrap();
983 /// reference.set_query(Some("myquery"));
984 /// assert_eq!(reference.to_string(), "http://example.com/?myquery");
985 /// ```
986 pub fn set_query<TQuery, TQueryError>(
987 &mut self,
988 query: Option<TQuery>,
989 ) -> Result<Option<&Query<'uri>>, URIReferenceError>
990 where
991 Query<'uri>: TryFrom<TQuery, Error = TQueryError>,
992 URIReferenceError: From<TQueryError>,
993 {
994 self.query = match query {
995 Some(query) => Some(Query::try_from(query)?),
996 None => None,
997 };
998 Ok(self.query())
999 }
1000
1001 /// Sets the scheme of the URI reference.
1002 ///
1003 /// An error will be returned in one of two cases:
1004 /// - The conversion to [`Scheme`] failed.
1005 /// - The scheme was set to `None`, but the resulting URI reference has an invalid schemeless
1006 /// path.
1007 ///
1008 /// # Examples
1009 ///
1010 /// ```
1011 /// use std::convert::TryFrom;
1012 ///
1013 /// use uriparse::URIReference;
1014 ///
1015 /// let mut reference = URIReference::try_from("http://example.com").unwrap();
1016 /// reference.set_scheme(Some("https"));
1017 /// assert_eq!(reference.to_string(), "https://example.com/");
1018 /// ```
1019 pub fn set_scheme<TScheme, TSchemeError>(
1020 &mut self,
1021 scheme: Option<TScheme>,
1022 ) -> Result<Option<&Scheme<'uri>>, URIReferenceError>
1023 where
1024 Scheme<'uri>: TryFrom<TScheme, Error = TSchemeError>,
1025 URIReferenceError: From<TSchemeError>,
1026 {
1027 self.scheme = match scheme {
1028 Some(scheme) => Some(Scheme::try_from(scheme)?),
1029 None => {
1030 validate_schemeless_path(None, self.authority.as_ref(), &self.path)?;
1031 None
1032 }
1033 };
1034 Ok(self.scheme())
1035 }
1036
1037 /// Returns a new URI reference which is identical but has a lifetime tied to this URI
1038 /// reference.
1039 ///
1040 /// This function will perform a memory allocation.
1041 pub fn to_borrowed(&self) -> URIReference {
1042 let scheme = self.scheme.as_ref().map(Scheme::as_borrowed);
1043 let authority = self.authority.as_ref().map(Authority::as_borrowed);
1044 let path = self.path.to_borrowed();
1045 let query = self.query.as_ref().map(Query::as_borrowed);
1046 let fragment = self.fragment.as_ref().map(Fragment::as_borrowed);
1047
1048 URIReference {
1049 authority,
1050 fragment,
1051 path,
1052 query,
1053 scheme,
1054 }
1055 }
1056
1057 /// Returns the username, if present, of the URI reference.
1058 ///
1059 /// # Examples
1060 ///
1061 /// ```
1062 /// use std::convert::TryFrom;
1063 ///
1064 /// use uriparse::URIReference;
1065 ///
1066 /// let reference = URIReference::try_from("http://username@example.com").unwrap();
1067 /// assert_eq!(reference.username().unwrap(), "username");
1068 /// ```
1069 pub fn username(&self) -> Option<&Username<'uri>> {
1070 if let Some(ref authority) = self.authority {
1071 authority.username()
1072 } else {
1073 None
1074 }
1075 }
1076}
1077
1078impl Display for URIReference<'_> {
1079 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1080 if let Some(ref scheme) = self.scheme {
1081 formatter.write_str(scheme.as_str())?;
1082 formatter.write_char(':')?;
1083 }
1084
1085 if let Some(ref authority) = self.authority {
1086 formatter.write_str("//")?;
1087 formatter.write_str(&authority.to_string())?;
1088 }
1089
1090 formatter.write_str(&self.path.to_string())?;
1091
1092 if let Some(ref query) = self.query {
1093 formatter.write_char('?')?;
1094 formatter.write_str(query.as_str())?;
1095 }
1096
1097 if let Some(ref fragment) = self.fragment {
1098 formatter.write_char('#')?;
1099 formatter.write_str(fragment.as_str())?;
1100 }
1101
1102 Ok(())
1103 }
1104}
1105
1106impl<'uri> From<URIReference<'uri>> for String {
1107 fn from(value: URIReference<'uri>) -> Self {
1108 value.to_string()
1109 }
1110}
1111
1112impl<'uri> TryFrom<&'uri [u8]> for URIReference<'uri> {
1113 type Error = URIReferenceError;
1114
1115 fn try_from(value: &'uri [u8]) -> Result<Self, Self::Error> {
1116 let (scheme, value) = match parse_scheme(value) {
1117 Ok((scheme, rest)) => {
1118 if rest.starts_with(b":") {
1119 (Some(scheme), &rest[1..])
1120 } else {
1121 (None, value)
1122 }
1123 }
1124 _ => (None, value),
1125 };
1126
1127 let (authority, value) = match value.get(0..2) {
1128 Some(b"//") => {
1129 let (authority, value) = parse_authority(&value[2..])?;
1130 (Some(authority), value)
1131 }
1132 _ => (None, value),
1133 };
1134
1135 let (mut path, value) = parse_path(value)?;
1136
1137 if authority.is_some() {
1138 path.set_absolute(true);
1139 }
1140
1141 validate_schemeless_path(scheme.as_ref(), authority.as_ref(), &path)?;
1142
1143 let (query, value) = if value.starts_with(b"?") {
1144 let (query, value) = parse_query(&value[1..])?;
1145 (Some(query), value)
1146 } else {
1147 (None, value)
1148 };
1149
1150 let fragment = if value.starts_with(b"#") {
1151 Some(Fragment::try_from(&value[1..])?)
1152 } else {
1153 None
1154 };
1155
1156 Ok(URIReference {
1157 authority,
1158 fragment,
1159 path,
1160 query,
1161 scheme,
1162 })
1163 }
1164}
1165
1166impl<'uri> TryFrom<&'uri str> for URIReference<'uri> {
1167 type Error = URIReferenceError;
1168
1169 fn try_from(value: &'uri str) -> Result<Self, Self::Error> {
1170 URIReference::try_from(value.as_bytes())
1171 }
1172}
1173
1174/// A builder type for [`URIReference]`.
1175///
1176/// You must use the [`URIReference::path`] function before building as URI references always have
1177/// have a path. Everything else is optional.
1178#[derive(Clone, Debug, Default, Eq, PartialEq)]
1179pub struct URIReferenceBuilder<'uri> {
1180 /// The authority component of the URI reference as defined in
1181 /// [[RFC3986, Section 3.2]](https://tools.ietf.org/html/rfc3986#section-3.2).
1182 authority: Option<Authority<'uri>>,
1183
1184 /// The fragment component of the URI reference as defined in
1185 /// [[RFC3986, Section 3.5]](https://tools.ietf.org/html/rfc3986#section-3.5).
1186 fragment: Option<Fragment<'uri>>,
1187
1188 /// The path component of the URI reference as defined in
1189 /// [[RFC3986, Section 3.3]](https://tools.ietf.org/html/rfc3986#section-3.3).
1190 path: Option<Path<'uri>>,
1191
1192 /// The query component of the URI reference as defined in
1193 /// [[RFC3986, Section 3.4]](https://tools.ietf.org/html/rfc3986#section-3.4).
1194 query: Option<Query<'uri>>,
1195
1196 /// The scheme component of the URI reference as defined in
1197 /// [[RFC3986, Section 3.1]](https://tools.ietf.org/html/rfc3986#section-3.1).
1198 scheme: Option<Scheme<'uri>>,
1199}
1200
1201impl<'uri> URIReferenceBuilder<'uri> {
1202 /// Sets the authority part of the URI reference.
1203 ///
1204 /// It is optional to specify a authority.
1205 ///
1206 /// # Examples
1207 ///
1208 /// ```
1209 /// use std::convert::TryFrom;
1210 ///
1211 /// use uriparse::{Authority, Path, URIReferenceBuilder};
1212 ///
1213 /// let mut builder = URIReferenceBuilder::new();
1214 /// builder
1215 /// .authority(Some(Authority::try_from("example.com").unwrap()))
1216 /// .path(Path::try_from("/my/path").unwrap());
1217 /// let reference = builder.build().unwrap();
1218 /// assert_eq!(reference.to_string(), "//example.com/my/path");
1219 /// ```
1220 pub fn authority(&mut self, authority: Option<Authority<'uri>>) -> &mut Self {
1221 self.authority = authority;
1222 self
1223 }
1224
1225 /// Consumes the builder and tries to build a [`URIReference`].
1226 ///
1227 /// This function will error in one of two situations:
1228 /// - A path was not specified in the builder.
1229 /// - While all individual components were valid, their combination as a URI reference was
1230 /// invalid.
1231 ///
1232 /// # Examples
1233 ///
1234 /// First error type (path not specified):
1235 ///
1236 /// ```
1237 /// use uriparse::URIReferenceBuilder;
1238 ///
1239 /// let result = URIReferenceBuilder::new().build();
1240 /// assert!(result.is_err());
1241 /// ```
1242 ///
1243 /// Second error type (first segment in schemeless path cannot contain a `':'`):
1244 ///
1245 /// ```
1246 /// use std::convert::TryFrom;
1247 ///
1248 /// use uriparse::{Path, URIReferenceBuilder};
1249 ///
1250 /// let result = URIReferenceBuilder::new()
1251 /// .with_path(Path::try_from("my:/path").unwrap())
1252 /// .build();
1253 /// assert!(result.is_err());
1254 /// ```
1255 pub fn build(self) -> Result<URIReference<'uri>, URIReferenceError> {
1256 let path = match self.path {
1257 Some(path) => path,
1258 None => return Err(URIReferenceError::MissingPath),
1259 };
1260
1261 URIReference::from_parts(self.scheme, self.authority, path, self.query, self.fragment)
1262 }
1263
1264 /// Sets the fragment part of the URI reference.
1265 ///
1266 /// It is optional to specify a fragment.
1267 ///
1268 /// # Examples
1269 ///
1270 /// ```
1271 /// use std::convert::TryFrom;
1272 ///
1273 /// use uriparse::{Fragment, Path, URIReferenceBuilder};
1274 ///
1275 /// let mut builder = URIReferenceBuilder::new();
1276 /// builder
1277 /// .path(Path::try_from("/my/path").unwrap())
1278 /// .fragment(Some(Fragment::try_from("fragment").unwrap()));
1279 /// let reference = builder.build().unwrap();
1280 /// assert_eq!(reference.to_string(), "/my/path#fragment");
1281 /// ```
1282 pub fn fragment(&mut self, fragment: Option<Fragment<'uri>>) -> &mut Self {
1283 self.fragment = fragment;
1284 self
1285 }
1286
1287 /// Constructs a new builder with nothing set.
1288 pub fn new() -> Self {
1289 URIReferenceBuilder::default()
1290 }
1291
1292 /// Sets the path part of the URI reference.
1293 ///
1294 /// It is required to specify a path. Not doing so will result in an error during the
1295 /// [`URIReferenceBuilder::build`] function.
1296 ///
1297 /// # Examples
1298 ///
1299 /// ```
1300 /// use std::convert::TryFrom;
1301 ///
1302 /// use uriparse::{Path, URIReferenceBuilder};
1303 ///
1304 /// let mut builder = URIReferenceBuilder::new();
1305 /// builder
1306 /// .path(Path::try_from("/my/path").unwrap());
1307 /// let reference = builder.build().unwrap();
1308 /// assert_eq!(reference.to_string(), "/my/path");
1309 /// ```
1310 pub fn path(&mut self, path: Path<'uri>) -> &mut Self {
1311 self.path = Some(path);
1312 self
1313 }
1314
1315 /// Sets the query part of the URI reference.
1316 ///
1317 /// It is optional to specify a query.
1318 ///
1319 /// # Examples
1320 ///
1321 /// ```
1322 /// use std::convert::TryFrom;
1323 ///
1324 /// use uriparse::{Path, Query, URIReferenceBuilder};
1325 ///
1326 /// let mut builder = URIReferenceBuilder::new();
1327 /// builder
1328 /// .path(Path::try_from("/my/path").unwrap())
1329 /// .query(Some(Query::try_from("query").unwrap()));
1330 /// let reference = builder.build().unwrap();
1331 /// assert_eq!(reference.to_string(), "/my/path?query");
1332 /// ```
1333 pub fn query(&mut self, query: Option<Query<'uri>>) -> &mut Self {
1334 self.query = query;
1335 self
1336 }
1337
1338 /// Sets the scheme part of the URI reference.
1339 ///
1340 /// It is optional to specify a scheme.
1341 ///
1342 /// # Examples
1343 ///
1344 /// ```
1345 /// use std::convert::TryFrom;
1346 ///
1347 /// use uriparse::{Authority, Path, Scheme, URIReferenceBuilder};
1348 ///
1349 /// let mut builder = URIReferenceBuilder::new();
1350 /// builder
1351 /// .scheme(Some(Scheme::HTTP))
1352 /// .authority(Some(Authority::try_from("example.com").unwrap()))
1353 /// .path(Path::try_from("/my/path").unwrap());
1354 /// let reference = builder.build().unwrap();
1355 /// assert_eq!(reference.to_string(), "http://example.com/my/path");
1356 /// ```
1357 pub fn scheme(&mut self, scheme: Option<Scheme<'uri>>) -> &mut Self {
1358 self.scheme = scheme;
1359 self
1360 }
1361
1362 /// Sets the authority part of the URI reference.
1363 ///
1364 /// If the given authority is not a valid authority (i.e. the conversion fails), an error is
1365 /// return.
1366 ///
1367 /// It is optional to specify an authority.
1368 ///
1369 /// # Examples
1370 ///
1371 /// ```
1372 /// use uriparse::URIReferenceBuilder;
1373 ///
1374 /// let mut builder = URIReferenceBuilder::new();
1375 /// builder
1376 /// .try_authority(Some("example.com"))
1377 /// .unwrap()
1378 /// .try_path("/my/path")
1379 /// .unwrap();
1380 /// let reference = builder.build().unwrap();
1381 /// assert_eq!(reference.to_string(), "//example.com/my/path");
1382 /// ```
1383 pub fn try_authority<TAuthority, TAuthorityError>(
1384 &mut self,
1385 authority: Option<TAuthority>,
1386 ) -> Result<&mut Self, TAuthorityError>
1387 where
1388 Authority<'uri>: TryFrom<TAuthority, Error = TAuthorityError>,
1389 AuthorityError: From<TAuthorityError>,
1390 {
1391 self.authority = match authority {
1392 Some(authority) => Some(Authority::try_from(authority).map_err(|error| error)?),
1393 None => None,
1394 };
1395 Ok(self)
1396 }
1397
1398 /// Sets the fragment part of the URI reference.
1399 ///
1400 /// If the given fragment is not a valid fragment (i.e. the conversion fails), an error is
1401 /// returned.
1402 ///
1403 /// It is optional to specify a fragment.
1404 ///
1405 /// # Examples
1406 ///
1407 /// ```
1408 /// use uriparse::URIReferenceBuilder;
1409 ///
1410 /// let mut builder = URIReferenceBuilder::new();
1411 /// builder
1412 /// .try_path("/my/path")
1413 /// .unwrap()
1414 /// .try_fragment(Some("fragment"))
1415 /// .unwrap();
1416 /// let reference = builder.build().unwrap();
1417 /// assert_eq!(reference.to_string(), "/my/path#fragment");
1418 /// ```
1419 pub fn try_fragment<TFragment, TFragmentError>(
1420 &mut self,
1421 fragment: Option<TFragment>,
1422 ) -> Result<&mut Self, FragmentError>
1423 where
1424 Fragment<'uri>: TryFrom<TFragment, Error = TFragmentError>,
1425 FragmentError: From<TFragmentError>,
1426 {
1427 self.fragment = match fragment {
1428 Some(fragment) => Some(Fragment::try_from(fragment).map_err(|error| error)?),
1429 None => None,
1430 };
1431 Ok(self)
1432 }
1433
1434 /// Sets the path part of the URI reference.
1435 ///
1436 /// If the given path is not a valid path (i.e. the conversion fails), an error is returned.
1437 ///
1438 /// It is required to specify a path. Not doing so will result in an error during the
1439 /// [`URIReferenceBuilder::build`] function.
1440 ///
1441 /// # Examples
1442 ///
1443 /// ```
1444 /// use uriparse::URIReferenceBuilder;
1445 ///
1446 /// let mut builder = URIReferenceBuilder::new();
1447 /// builder
1448 /// .try_path("/my/path")
1449 /// .unwrap();
1450 /// let reference = builder.build().unwrap();
1451 /// assert_eq!(reference.to_string(), "/my/path");
1452 /// ```
1453 pub fn try_path<TPath, TPathError>(&mut self, path: TPath) -> Result<&mut Self, PathError>
1454 where
1455 Path<'uri>: TryFrom<TPath, Error = TPathError>,
1456 PathError: From<TPathError>,
1457 {
1458 self.path = Some(Path::try_from(path).map_err(|error| error)?);
1459 Ok(self)
1460 }
1461
1462 /// Sets the query part of the URI reference.
1463 ///
1464 /// If the given query is not a valid query (i.e. the conversion fails), an error is returned.
1465 ///
1466 /// It is optional to specify a query.
1467 ///
1468 /// # Examples
1469 ///
1470 /// ```
1471 /// use uriparse::URIReferenceBuilder;
1472 ///
1473 /// let mut builder = URIReferenceBuilder::new();
1474 /// builder
1475 /// .try_path("/my/path")
1476 /// .unwrap()
1477 /// .try_query(Some("query"))
1478 /// .unwrap();
1479 /// let reference = builder.build().unwrap();
1480 /// assert_eq!(reference.to_string(), "/my/path?query");
1481 /// ```
1482 pub fn try_query<TQuery, TQueryError>(
1483 &mut self,
1484 query: Option<TQuery>,
1485 ) -> Result<&mut Self, QueryError>
1486 where
1487 Query<'uri>: TryFrom<TQuery, Error = TQueryError>,
1488 QueryError: From<TQueryError>,
1489 {
1490 self.query = match query {
1491 Some(query) => Some(Query::try_from(query).map_err(|error| error)?),
1492 None => None,
1493 };
1494 Ok(self)
1495 }
1496
1497 /// Sets the scheme part of the URI reference.
1498 ///
1499 /// If the given scheme is not a valid scheme (i.e. the conversion fails), an error is returned.
1500 ///
1501 /// It is optional to specify a scheme.
1502 ///
1503 /// # Examples
1504 ///
1505 /// ```
1506 /// use uriparse::URIReferenceBuilder;
1507 ///
1508 /// let mut builder = URIReferenceBuilder::new();
1509 /// builder
1510 /// .try_scheme(Some("urn"))
1511 /// .unwrap()
1512 /// .try_path("path")
1513 /// .unwrap();
1514 /// let uri = builder.build().unwrap();
1515 /// assert_eq!(uri.to_string(), "urn:path");
1516 /// ```
1517 pub fn try_scheme<TScheme, TSchemeError>(
1518 &mut self,
1519 scheme: Option<TScheme>,
1520 ) -> Result<&mut Self, SchemeError>
1521 where
1522 Scheme<'uri>: TryFrom<TScheme, Error = TSchemeError>,
1523 SchemeError: From<TSchemeError>,
1524 {
1525 self.scheme = match scheme {
1526 Some(scheme) => Some(Scheme::try_from(scheme).map_err(|error| error)?),
1527 None => None,
1528 };
1529 Ok(self)
1530 }
1531
1532 /// Consumes the builder and sets the authority part of the URI reference.
1533 ///
1534 /// It is optional to specify an authority.
1535 ///
1536 /// # Examples
1537 ///
1538 /// ```
1539 /// use std::convert::TryFrom;
1540 ///
1541 /// use uriparse::{Authority, Path, URIReferenceBuilder};
1542 ///
1543 /// let reference = URIReferenceBuilder::new()
1544 /// .with_authority(Some(Authority::try_from("example.com").unwrap()))
1545 /// .with_path(Path::try_from("/").unwrap())
1546 /// .build()
1547 /// .unwrap();
1548 /// assert_eq!(reference.to_string(), "//example.com/")
1549 /// ```
1550 pub fn with_authority(mut self, authority: Option<Authority<'uri>>) -> Self {
1551 self.authority(authority);
1552 self
1553 }
1554
1555 /// Consumes the builder and sets the fragment part of the URI reference.
1556 ///
1557 /// It is optional to specify a fragment.
1558 ///
1559 /// # Examples
1560 ///
1561 /// ```
1562 /// use std::convert::TryFrom;
1563 ///
1564 /// use uriparse::{Fragment, Path, URIReferenceBuilder};
1565 ///
1566 /// let reference = URIReferenceBuilder::new()
1567 /// .with_path(Path::try_from("/").unwrap())
1568 /// .with_fragment(Some(Fragment::try_from("fragment").unwrap()))
1569 /// .build()
1570 /// .unwrap();
1571 /// assert_eq!(reference.to_string(), "/#fragment")
1572 /// ```
1573 pub fn with_fragment(mut self, fragment: Option<Fragment<'uri>>) -> Self {
1574 self.fragment(fragment);
1575 self
1576 }
1577
1578 /// Consumes the builder and sets the path part of the URI reference.
1579 ///
1580 /// It is required to specify a path. Not doing so will result in an error during the
1581 /// [`URIReferenceBuilder::build`] function.
1582 ///
1583 /// # Examples
1584 ///
1585 /// ```
1586 /// use std::convert::TryFrom;
1587 ///
1588 /// use uriparse::{Path, URIReferenceBuilder};
1589 ///
1590 /// let reference = URIReferenceBuilder::new()
1591 /// .with_path(Path::try_from("/").unwrap())
1592 /// .build()
1593 /// .unwrap();
1594 /// assert_eq!(reference.to_string(), "/")
1595 /// ```
1596 pub fn with_path(mut self, path: Path<'uri>) -> Self {
1597 self.path(path);
1598 self
1599 }
1600
1601 /// Consumes the builder and sets the query part of the URI reference.
1602 ///
1603 /// It is optional to specify a query.
1604 ///
1605 /// # Examples
1606 ///
1607 /// ```
1608 /// use std::convert::TryFrom;
1609 ///
1610 /// use uriparse::{Path, Query, URIReferenceBuilder};
1611 ///
1612 /// let reference = URIReferenceBuilder::new()
1613 /// .with_path(Path::try_from("/").unwrap())
1614 /// .with_query(Some(Query::try_from("query").unwrap()))
1615 /// .build()
1616 /// .unwrap();
1617 /// assert_eq!(reference.to_string(), "/?query")
1618 /// ```
1619 pub fn with_query(mut self, query: Option<Query<'uri>>) -> Self {
1620 self.query(query);
1621 self
1622 }
1623
1624 /// Consumes the builder and sets the scheme part of the URI reference.
1625 ///
1626 /// It is optional to specify a scheme.
1627 ///
1628 /// # Examples
1629 ///
1630 /// ```
1631 /// use std::convert::TryFrom;
1632 ///
1633 /// use uriparse::{Authority, Path, Scheme, URIReferenceBuilder};
1634 ///
1635 /// let reference = URIReferenceBuilder::new()
1636 /// .with_scheme(Some(Scheme::HTTP))
1637 /// .with_authority(Some(Authority::try_from("example.com").unwrap()))
1638 /// .with_path(Path::try_from("/").unwrap())
1639 /// .build()
1640 /// .unwrap();
1641 /// assert_eq!(reference.to_string(), "http://example.com/")
1642 /// ```
1643 pub fn with_scheme(mut self, scheme: Option<Scheme<'uri>>) -> Self {
1644 self.scheme(scheme);
1645 self
1646 }
1647}
1648
1649/// An error representing an invalid URI reference.
1650#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1651#[non_exhaustive]
1652pub enum URIReferenceError {
1653 /// Represents the case when there is no authority, but the first path segment starts with
1654 /// `"//"`. This is not allowed because it would be interpreted as an authority component.
1655 ///
1656 /// This can only occur when using creation functions that act on individual parts (e.g.
1657 /// [`URIReference::from_parts`]).
1658 AbsolutePathStartsWithTwoSlashes,
1659
1660 /// The authority component of the relative reference was invalid.
1661 Authority(AuthorityError),
1662
1663 /// The fragment component of the relative reference was invalid.
1664 Fragment(FragmentError),
1665
1666 /// This error occurs when you do not specify a path component on the builder.
1667 ///
1668 /// This can only occur when using [`URIReferenceBuilder`].
1669 MissingPath,
1670
1671 /// The path component of the relative reference was invalid.
1672 Path(PathError),
1673
1674 /// The query component of the relative reference was invalid.
1675 Query(QueryError),
1676
1677 /// The scheme component of the relative reference was invalid.
1678 Scheme(SchemeError),
1679
1680 /// Represents the case when there is no authority, but the first path segment starts with
1681 /// `"//"`. This is not allowed because it would be interpreted as an authority component.
1682 ///
1683 /// This can only occur when using creation functions that act on individual parts (e.g.
1684 /// [`URIReference::from_parts`]).
1685 SchemelessPathStartsWithColonSegment,
1686}
1687
1688impl Display for URIReferenceError {
1689 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
1690 use self::URIReferenceError::*;
1691
1692 match self {
1693 AbsolutePathStartsWithTwoSlashes => write!(
1694 formatter,
1695 "absolute path URI reference starts with two slashes"
1696 ),
1697 Authority(error) => error.fmt(formatter),
1698 Fragment(error) => error.fmt(formatter),
1699 Path(error) => error.fmt(formatter),
1700 Query(error) => error.fmt(formatter),
1701 Scheme(error) => error.fmt(formatter),
1702 MissingPath => write!(formatter, "URI reference missing path"),
1703 SchemelessPathStartsWithColonSegment => write!(
1704 formatter,
1705 "schemeless path URI reference starts with colon segment"
1706 ),
1707 }
1708 }
1709}
1710
1711impl Error for URIReferenceError {}
1712
1713impl From<Infallible> for URIReferenceError {
1714 fn from(_: Infallible) -> Self {
1715 URIReferenceError::AbsolutePathStartsWithTwoSlashes
1716 }
1717}
1718
1719impl From<AuthorityError> for URIReferenceError {
1720 fn from(value: AuthorityError) -> Self {
1721 URIReferenceError::Authority(value)
1722 }
1723}
1724
1725impl From<FragmentError> for URIReferenceError {
1726 fn from(value: FragmentError) -> Self {
1727 URIReferenceError::Fragment(value)
1728 }
1729}
1730
1731impl From<PathError> for URIReferenceError {
1732 fn from(value: PathError) -> Self {
1733 URIReferenceError::Path(value)
1734 }
1735}
1736
1737impl From<QueryError> for URIReferenceError {
1738 fn from(value: QueryError) -> Self {
1739 URIReferenceError::Query(value)
1740 }
1741}
1742
1743impl From<SchemeError> for URIReferenceError {
1744 fn from(value: SchemeError) -> Self {
1745 URIReferenceError::Scheme(value)
1746 }
1747}
1748
1749fn validate_absolute_path(
1750 authority: Option<&Authority>,
1751 path: &Path,
1752) -> Result<(), URIReferenceError> {
1753 if authority.is_some()
1754 || path.is_relative()
1755 || path.segments().len() == 1
1756 || !path.segments().first().unwrap().is_empty()
1757 {
1758 Ok(())
1759 } else {
1760 Err(URIReferenceError::AbsolutePathStartsWithTwoSlashes)
1761 }
1762}
1763
1764fn validate_schemeless_path(
1765 scheme: Option<&Scheme>,
1766 authority: Option<&Authority>,
1767 path: &Path,
1768) -> Result<(), URIReferenceError> {
1769 if scheme.is_some()
1770 || authority.is_some()
1771 || !path
1772 .segments()
1773 .first()
1774 .unwrap()
1775 .bytes()
1776 .any(|byte| byte == b':')
1777 {
1778 Ok(())
1779 } else {
1780 Err(URIReferenceError::SchemelessPathStartsWithColonSegment)
1781 }
1782}
1783
1784#[cfg(test)]
1785mod test {
1786 use super::*;
1787
1788 #[test]
1789 fn test_parse_uri_reference() {
1790 let actual = URIReference::try_from("http://example.com").unwrap();
1791 let expected = URIReference::from_parts(
1792 Some(Scheme::HTTP),
1793 Some("example.com"),
1794 "/",
1795 None::<Query>,
1796 None::<Fragment>,
1797 )
1798 .unwrap();
1799 assert_eq!(actual, expected);
1800
1801 let actual = URIReference::try_from("http://example.com/").unwrap();
1802 let expected = URIReference::from_parts(
1803 Some(Scheme::HTTP),
1804 Some("example.com"),
1805 "/",
1806 None::<Query>,
1807 None::<Fragment>,
1808 )
1809 .unwrap();
1810 assert_eq!(actual, expected);
1811
1812 let actual = URIReference::try_from("http://example.com").unwrap();
1813 let expected = URIReference::from_parts(
1814 Some(Scheme::HTTP),
1815 Some("example.com"),
1816 "",
1817 None::<Query>,
1818 None::<Fragment>,
1819 )
1820 .unwrap();
1821 assert_eq!(actual, expected);
1822
1823 let actual = URIReference::try_from("http://example.com/").unwrap();
1824 let expected = URIReference::from_parts(
1825 Some(Scheme::HTTP),
1826 Some("example.com"),
1827 "",
1828 None::<Query>,
1829 None::<Fragment>,
1830 )
1831 .unwrap();
1832 assert_eq!(actual, expected);
1833
1834 let actual = URIReference::try_from("http:").unwrap();
1835 let expected = URIReference::from_parts(
1836 Some(Scheme::HTTP),
1837 None::<Authority>,
1838 "",
1839 None::<Query>,
1840 None::<Fragment>,
1841 )
1842 .unwrap();
1843 assert_eq!(actual, expected);
1844
1845 let actual = URIReference::try_from("http:/").unwrap();
1846 let expected = URIReference::from_parts(
1847 Some(Scheme::HTTP),
1848 None::<Authority>,
1849 "/",
1850 None::<Query>,
1851 None::<Fragment>,
1852 )
1853 .unwrap();
1854 assert_eq!(actual, expected);
1855
1856 let actual = URIReference::try_from("http:/path").unwrap();
1857 let expected = URIReference::from_parts(
1858 Some(Scheme::HTTP),
1859 None::<Authority>,
1860 "/path",
1861 None::<Query>,
1862 None::<Fragment>,
1863 )
1864 .unwrap();
1865 assert_eq!(actual, expected);
1866
1867 let actual = URIReference::try_from("//example.com/").unwrap();
1868 let expected = URIReference::from_parts(
1869 None::<Scheme>,
1870 Some("example.com"),
1871 "/",
1872 None::<Query>,
1873 None::<Fragment>,
1874 )
1875 .unwrap();
1876 assert_eq!(actual, expected);
1877
1878 let actual = URIReference::try_from("").unwrap();
1879 let expected = URIReference::from_parts(
1880 None::<Scheme>,
1881 None::<Authority>,
1882 "",
1883 None::<Query>,
1884 None::<Fragment>,
1885 )
1886 .unwrap();
1887 assert_eq!(actual, expected);
1888
1889 let actual = URIReference::try_from("*").unwrap();
1890 let expected = URIReference::from_parts(
1891 None::<Scheme>,
1892 None::<Authority>,
1893 "*",
1894 None::<Query>,
1895 None::<Fragment>,
1896 )
1897 .unwrap();
1898 assert_eq!(actual, expected);
1899
1900 let actual = URIReference::try_from("/").unwrap();
1901 let expected = URIReference::from_parts(
1902 None::<Scheme>,
1903 None::<Authority>,
1904 "/",
1905 None::<Query>,
1906 None::<Fragment>,
1907 )
1908 .unwrap();
1909 assert_eq!(actual, expected);
1910
1911 let actual = URIReference::try_from("test/path").unwrap();
1912 let expected = URIReference::from_parts(
1913 None::<Scheme>,
1914 None::<Authority>,
1915 "test/path",
1916 None::<Query>,
1917 None::<Fragment>,
1918 )
1919 .unwrap();
1920 assert_eq!(actual, expected);
1921 }
1922
1923 #[test]
1924 fn test_parse_uri_reference_error() {
1925 assert_eq!(
1926 URIReference::try_from("://www.example.com/"),
1927 Err(URIReferenceError::SchemelessPathStartsWithColonSegment)
1928 );
1929 }
1930}