rocket_http_community/uri/
uri.rs

1use std::borrow::Cow;
2use std::fmt::{self, Display};
3
4use crate::ext::IntoOwned;
5use crate::uri::error::{Error, TryFromUriError};
6use crate::uri::{Absolute, Asterisk, Authority, Origin, Reference};
7
8/// An `enum` encapsulating any of the possible URI variants.
9///
10/// # Usage
11///
12/// In Rocket, this type will rarely be used directly. Instead, you will
13/// typically encounter URIs via the [`Origin`] type. This is because all
14/// incoming requests accepted by Rocket contain URIs in origin-form.
15///
16/// ## Parsing
17///
18/// The `Uri` type implements a full, zero-allocation, zero-copy [RFC 7230]
19/// compliant "request target" parser with limited liberties for real-world
20/// deviations. In particular, the parser deviates as follows:
21///
22///   * It accepts `%` characters without two trailing hex-digits.
23///
24///   * It accepts the following additional unencoded characters in query parts,
25///     to match real-world browser behavior:
26///
27///     `{`, `}`, `[`,  `]`, `\`,  `^`,  <code>&#96;</code>, `|`
28///
29/// To parse an `&str` into a `Uri`, use [`Uri::parse()`]. Alternatively, you
30/// may also use the `TryFrom<&str>` and `TryFrom<String>` trait implementation.
31/// To inspect the parsed type, match on the resulting `enum` and use the
32/// methods of the internal structure.
33///
34/// [RFC 7230]: https://tools.ietf.org/html/rfc7230
35#[derive(Debug, PartialEq, Clone)]
36pub enum Uri<'a> {
37    /// An asterisk: exactly `*`.
38    Asterisk(Asterisk),
39    /// An origin URI.
40    Origin(Origin<'a>),
41    /// An authority URI.
42    Authority(Authority<'a>),
43    /// An absolute URI.
44    Absolute(Absolute<'a>),
45    /// A URI reference.
46    Reference(Reference<'a>),
47}
48
49impl<'a> Uri<'a> {
50    /// Parses the string `string` into a `Uri` of kind `T`.
51    ///
52    /// This is identical to `T::parse(string).map(Uri::from)`.
53    ///
54    /// `T` is typically one of [`Asterisk`], [`Origin`], [`Authority`],
55    /// [`Absolute`], or [`Reference`]. Parsing never allocates. Returns an
56    /// `Error` if `string` is not a valid URI of kind `T`.
57    ///
58    /// To perform an ambiguous parse into _any_ valid URI type, use
59    /// [`Uri::parse_any()`].
60    ///
61    /// # Example
62    ///
63    /// ```rust
64    /// # #[macro_use] extern crate rocket;
65    /// use rocket::http::uri::{Uri, Origin};
66    ///
67    /// // Parse a valid origin URI (note: in practice, use `Origin::parse()`).
68    /// let uri = Uri::parse::<Origin>("/a/b/c?query").expect("valid URI");
69    /// let origin = uri.origin().expect("origin URI");
70    /// assert_eq!(origin.path(), "/a/b/c");
71    /// assert_eq!(origin.query().unwrap(), "query");
72    ///
73    /// // Prefer to use the `uri!()` macro for static inputs. The return value
74    /// // is of the specific type, not `Uri`.
75    /// let origin = uri!("/a/b/c?query");
76    /// assert_eq!(origin.path(), "/a/b/c");
77    /// assert_eq!(origin.query().unwrap(), "query");
78    ///
79    /// // Invalid URIs fail to parse.
80    /// Uri::parse::<Origin>("foo bar").expect_err("invalid URI");
81    /// ```
82    pub fn parse<T>(string: &'a str) -> Result<Uri<'a>, Error<'a>>
83    where
84        T: Into<Uri<'a>> + TryFrom<&'a str, Error = Error<'a>>,
85    {
86        T::try_from(string).map(|v| v.into())
87    }
88
89    /// Parse `string` into a the "best fit" URI type.
90    ///
91    /// Always prefer to use `uri!()` for statically known inputs.
92    ///
93    /// Because URI parsing is ambiguous (that is, there isn't a one-to-one
94    /// mapping between strings and a URI type), the internal type returned by
95    /// this method _may_ not be the desired type. This method chooses the "best
96    /// fit" type for a given string by preferring to parse in the following
97    /// order:
98    ///
99    ///   * `Asterisk`
100    ///   * `Origin`
101    ///   * `Authority`
102    ///   * `Absolute`
103    ///   * `Reference`
104    ///
105    /// Thus, even though `*` is a valid `Asterisk` _and_ `Reference` URI, it
106    /// will parse as an `Asterisk`.
107    ///
108    /// # Example
109    ///
110    /// ```rust
111    /// # #[macro_use] extern crate rocket;
112    /// use rocket::http::uri::{Uri, Origin, Reference};
113    ///
114    /// // An absolute path is an origin _unless_ it contains a fragment.
115    /// let uri = Uri::parse_any("/a/b/c?query").expect("valid URI");
116    /// let origin = uri.origin().expect("origin URI");
117    /// assert_eq!(origin.path(), "/a/b/c");
118    /// assert_eq!(origin.query().unwrap(), "query");
119    ///
120    /// let uri = Uri::parse_any("/a/b/c?query#fragment").expect("valid URI");
121    /// let reference = uri.reference().expect("reference URI");
122    /// assert_eq!(reference.path(), "/a/b/c");
123    /// assert_eq!(reference.query().unwrap(), "query");
124    /// assert_eq!(reference.fragment().unwrap(), "fragment");
125    ///
126    /// // Prefer to use the `uri!()` macro for static inputs. The return type
127    /// // is the internal type, not `Uri`. The explicit type is not required.
128    /// let uri: Origin = uri!("/a/b/c?query");
129    /// let uri: Reference = uri!("/a/b/c?query#fragment");
130    /// ```
131    pub fn parse_any(string: &'a str) -> Result<Uri<'a>, Error<'a>> {
132        crate::parse::uri::from_str(string)
133    }
134
135    /// Returns the internal instance of `Origin` if `self` is a `Uri::Origin`.
136    /// Otherwise, returns `None`.
137    ///
138    /// # Example
139    ///
140    /// ```rust
141    /// # #[macro_use] extern crate rocket;
142    /// use rocket::http::uri::{Uri, Absolute, Origin};
143    ///
144    /// let uri = Uri::parse::<Origin>("/a/b/c?query").expect("valid URI");
145    /// assert!(uri.origin().is_some());
146    ///
147    /// let uri = Uri::from(uri!("/a/b/c?query"));
148    /// assert!(uri.origin().is_some());
149    ///
150    /// let uri = Uri::parse::<Absolute>("https://rocket.rs").expect("valid URI");
151    /// assert!(uri.origin().is_none());
152    ///
153    /// let uri = Uri::from(uri!("https://rocket.rs"));
154    /// assert!(uri.origin().is_none());
155    /// ```
156    pub fn origin(&self) -> Option<&Origin<'a>> {
157        match self {
158            Uri::Origin(ref inner) => Some(inner),
159            _ => None,
160        }
161    }
162
163    /// Returns the internal instance of `Authority` if `self` is a
164    /// `Uri::Authority`. Otherwise, returns `None`.
165    ///
166    /// # Example
167    ///
168    /// ```rust
169    /// # #[macro_use] extern crate rocket;
170    /// use rocket::http::uri::{Uri, Absolute, Authority};
171    ///
172    /// let uri = Uri::parse::<Authority>("user:pass@domain.com").expect("valid URI");
173    /// assert!(uri.authority().is_some());
174    ///
175    /// let uri = Uri::from(uri!("user:pass@domain.com"));
176    /// assert!(uri.authority().is_some());
177    ///
178    /// let uri = Uri::parse::<Absolute>("https://rocket.rs").expect("valid URI");
179    /// assert!(uri.authority().is_none());
180    ///
181    /// let uri = Uri::from(uri!("https://rocket.rs"));
182    /// assert!(uri.authority().is_none());
183    /// ```
184    pub fn authority(&self) -> Option<&Authority<'a>> {
185        match self {
186            Uri::Authority(ref inner) => Some(inner),
187            _ => None,
188        }
189    }
190
191    /// Returns the internal instance of `Absolute` if `self` is a
192    /// `Uri::Absolute`. Otherwise, returns `None`.
193    ///
194    /// # Example
195    ///
196    /// ```rust
197    /// # #[macro_use] extern crate rocket;
198    /// use rocket::http::uri::{Uri, Absolute, Origin};
199    ///
200    /// let uri = Uri::parse::<Absolute>("http://rocket.rs").expect("valid URI");
201    /// assert!(uri.absolute().is_some());
202    ///
203    /// let uri = Uri::from(uri!("http://rocket.rs"));
204    /// assert!(uri.absolute().is_some());
205    ///
206    /// let uri = Uri::parse::<Origin>("/path").expect("valid URI");
207    /// assert!(uri.absolute().is_none());
208    ///
209    /// let uri = Uri::from(uri!("/path"));
210    /// assert!(uri.absolute().is_none());
211    /// ```
212    pub fn absolute(&self) -> Option<&Absolute<'a>> {
213        match self {
214            Uri::Absolute(ref inner) => Some(inner),
215            _ => None,
216        }
217    }
218
219    /// Returns the internal instance of `Reference` if `self` is a
220    /// `Uri::Reference`. Otherwise, returns `None`.
221    ///
222    /// # Example
223    ///
224    /// ```rust
225    /// # #[macro_use] extern crate rocket;
226    /// use rocket::http::uri::{Uri, Absolute, Reference};
227    ///
228    /// let uri = Uri::parse::<Reference>("foo/bar").expect("valid URI");
229    /// assert!(uri.reference().is_some());
230    ///
231    /// let uri = Uri::from(uri!("foo/bar"));
232    /// assert!(uri.reference().is_some());
233    ///
234    /// let uri = Uri::parse::<Absolute>("https://rocket.rs").expect("valid URI");
235    /// assert!(uri.reference().is_none());
236    ///
237    /// let uri = Uri::from(uri!("https://rocket.rs"));
238    /// assert!(uri.reference().is_none());
239    /// ```
240    pub fn reference(&self) -> Option<&Reference<'a>> {
241        match self {
242            Uri::Reference(ref inner) => Some(inner),
243            _ => None,
244        }
245    }
246}
247
248pub(crate) unsafe fn as_utf8_unchecked(input: Cow<'_, [u8]>) -> Cow<'_, str> {
249    match input {
250        Cow::Borrowed(bytes) => Cow::Borrowed(std::str::from_utf8_unchecked(bytes)),
251        Cow::Owned(bytes) => Cow::Owned(String::from_utf8_unchecked(bytes)),
252    }
253}
254
255// impl<'a> TryFrom<&'a str> for Uri<'a> {
256//     type Error = Error<'a>;
257//
258//     #[inline]
259//     fn try_from(string: &'a str) -> Result<Uri<'a>, Self::Error> {
260//         Uri::parse(string)
261//     }
262// }
263//
264// impl TryFrom<String> for Uri<'static> {
265//     type Error = Error<'static>;
266//
267//     #[inline]
268//     fn try_from(string: String) -> Result<Uri<'static>, Self::Error> {
269//         // TODO: Potentially optimize this like `Origin::parse_owned`.
270//         Uri::parse(&string)
271//             .map(|u| u.into_owned())
272//             .map_err(|e| e.into_owned())
273//     }
274// }
275
276impl IntoOwned for Uri<'_> {
277    type Owned = Uri<'static>;
278
279    fn into_owned(self) -> Uri<'static> {
280        match self {
281            Uri::Origin(origin) => Uri::Origin(origin.into_owned()),
282            Uri::Authority(authority) => Uri::Authority(authority.into_owned()),
283            Uri::Absolute(absolute) => Uri::Absolute(absolute.into_owned()),
284            Uri::Reference(reference) => Uri::Reference(reference.into_owned()),
285            Uri::Asterisk(asterisk) => Uri::Asterisk(asterisk),
286        }
287    }
288}
289
290impl Display for Uri<'_> {
291    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292        match *self {
293            Uri::Origin(ref origin) => write!(f, "{}", origin),
294            Uri::Authority(ref authority) => write!(f, "{}", authority),
295            Uri::Absolute(ref absolute) => write!(f, "{}", absolute),
296            Uri::Reference(ref reference) => write!(f, "{}", reference),
297            Uri::Asterisk(ref asterisk) => write!(f, "{}", asterisk),
298        }
299    }
300}
301
302macro_rules! impl_uri_from {
303    ($T:ident $(<$lt:lifetime>)?) => (
304        impl<'a> From<$T $(<$lt>)?> for Uri<'a> {
305            fn from(other: $T $(<$lt>)?) -> Uri<'a> {
306                Uri::$T(other)
307            }
308        }
309
310        impl<'a> TryFrom<Uri<'a>> for $T $(<$lt>)? {
311            type Error = TryFromUriError;
312
313            fn try_from(uri: Uri<'a>) -> Result<Self, Self::Error> {
314                match uri {
315                    Uri::$T(inner) => Ok(inner),
316                    _ => Err(TryFromUriError(()))
317                }
318            }
319        }
320
321        impl<'b, $($lt)?> PartialEq<$T $(<$lt>)?> for Uri<'b> {
322            fn eq(&self, other: &$T $(<$lt>)?) -> bool {
323                match self {
324                    Uri::$T(inner) => inner == other,
325                    _ => false
326                }
327            }
328        }
329
330        impl<'b, $($lt)?> PartialEq<Uri<'b>> for $T $(<$lt>)? {
331            fn eq(&self, other: &Uri<'b>) -> bool {
332                match other {
333                    Uri::$T(inner) => inner == self,
334                    _ => false
335                }
336            }
337        }
338
339        impl<'b, $($lt)?> PartialEq<&$T $(<$lt>)?> for Uri<'b> {
340            fn eq(&self, other: &&$T $(<$lt>)?) -> bool {
341                match self {
342                    Uri::$T(inner) => inner == *other,
343                    _ => false
344                }
345            }
346        }
347
348        impl<'b, $($lt)?> PartialEq<Uri<'b>> for &$T $(<$lt>)? {
349            fn eq(&self, other: &Uri<'b>) -> bool {
350                match other {
351                    Uri::$T(inner) => inner == *self,
352                    _ => false
353                }
354            }
355        }
356    )
357}
358
359impl_uri_from!(Origin<'a>);
360impl_uri_from!(Authority<'a>);
361impl_uri_from!(Absolute<'a>);
362impl_uri_from!(Reference<'a>);
363impl_uri_from!(Asterisk);
364
365/// Implements Serialize and Deserialize for any 'URI' looking type.
366macro_rules! impl_serde {
367    ($T:ty, $expected:literal) => {
368        #[cfg(feature = "serde")]
369        mod serde_impl {
370            use super::*;
371            use std::fmt;
372            use std::marker::PhantomData;
373
374            use serde::de::{Deserialize, Deserializer, Error, Visitor};
375            use serde::ser::{Serialize, Serializer};
376
377            impl<'a> Serialize for $T {
378                fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
379                    serializer.serialize_str(&self.to_string())
380                }
381            }
382
383            struct DeVisitor<'a>(PhantomData<&'a $T>);
384
385            impl<'de, 'a> Visitor<'de> for DeVisitor<'a> {
386                type Value = $T;
387
388                fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
389                    write!(formatter, $expected)
390                }
391
392                fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
393                    <$T>::parse_owned(v.to_string()).map_err(Error::custom)
394                }
395
396                fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
397                    <$T>::parse_owned(v).map_err(Error::custom)
398                }
399            }
400
401            impl<'a, 'de> Deserialize<'de> for $T {
402                fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
403                    deserializer.deserialize_str(DeVisitor(PhantomData))
404                }
405            }
406        }
407    };
408}
409
410/// Implements traits from `impl_base_traits` and IntoOwned for a URI.
411macro_rules! impl_traits {
412    ($T:ident, $($field:ident),* $(,)?) => {
413        impl_traits!($T [parse], $($field),*);
414    };
415    ($T:ident [$partial_eq_parse:ident], $($field:ident),* $(,)?) => {
416        impl_base_traits!($T [$partial_eq_parse], $($field),*);
417
418        impl crate::ext::IntoOwned for $T<'_> {
419            type Owned = $T<'static>;
420
421            fn into_owned(self) -> $T<'static> {
422                $T {
423                    source: self.source.into_owned(),
424                    $($field: self.$field.into_owned()),*
425                }
426            }
427        }
428    }
429}
430
431/// Implements PartialEq, Eq, Hash, and TryFrom.
432macro_rules! impl_base_traits {
433    ($T:ident, $($field:ident),* $(,)?) => {
434        impl_base_traits!($T [parse], $($field),*);
435    };
436    ($T:ident [$partial_eq_parse:ident], $($field:ident),* $(,)?) => {
437        impl std::convert::TryFrom<String> for $T<'static> {
438            type Error = Error<'static>;
439
440            fn try_from(value: String) -> Result<Self, Self::Error> {
441                $T::parse_owned(value)
442            }
443        }
444
445        // Because inference doesn't take `&String` to `&str`.
446        impl<'a> std::convert::TryFrom<&'a String> for $T<'a> {
447            type Error = Error<'a>;
448
449            fn try_from(value: &'a String) -> Result<Self, Self::Error> {
450                $T::parse(value.as_str())
451            }
452        }
453
454        impl<'a> std::convert::TryFrom<&'a str> for $T<'a> {
455            type Error = Error<'a>;
456
457            fn try_from(value: &'a str) -> Result<Self, Self::Error> {
458                $T::parse(value)
459            }
460        }
461
462        impl<'a, 'b> PartialEq<$T<'b>> for $T<'a> {
463            fn eq(&self, other: &$T<'b>) -> bool {
464                true $(&& self.$field() == other.$field())*
465            }
466        }
467
468        impl PartialEq<str> for $T<'_> {
469            fn eq(&self, string: &str) -> bool {
470                $T::$partial_eq_parse(string).map_or(false, |v| &v == self)
471            }
472        }
473
474        impl PartialEq<&str> for $T<'_> {
475            fn eq(&self, other: &&str) -> bool {
476                self.eq(*other)
477            }
478        }
479
480        impl PartialEq<$T<'_>> for str {
481            fn eq(&self, other: &$T<'_>) -> bool {
482                other.eq(self)
483            }
484        }
485
486        impl Eq for $T<'_> { }
487
488        impl std::hash::Hash for $T<'_> {
489            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
490                $(self.$field().hash(state);)*
491            }
492        }
493    }
494}
495
496mod tests {
497    #[test]
498    fn normalization() {
499        fn normalize(uri: &str) -> String {
500            use crate::uri::Uri;
501
502            match Uri::parse_any(uri).unwrap() {
503                Uri::Origin(uri) => uri.into_normalized().to_string(),
504                Uri::Absolute(uri) => uri.into_normalized().to_string(),
505                Uri::Reference(uri) => uri.into_normalized().to_string(),
506                uri => uri.to_string(),
507            }
508        }
509
510        assert_eq!(normalize("/#"), "/#");
511
512        assert_eq!(normalize("/"), "/");
513        assert_eq!(normalize("//"), "/");
514        assert_eq!(normalize("//////a/"), "/a/");
515        assert_eq!(normalize("//ab"), "/ab");
516        assert_eq!(normalize("//a"), "/a");
517        assert_eq!(normalize("/a/b///c"), "/a/b/c");
518        assert_eq!(normalize("/a/b///c/"), "/a/b/c/");
519        assert_eq!(normalize("/a///b/c/d///"), "/a/b/c/d/");
520
521        assert_eq!(normalize("/?"), "/?");
522        assert_eq!(normalize("/?foo"), "/?foo");
523        assert_eq!(normalize("/a/?"), "/a/?");
524        assert_eq!(normalize("/a/?foo"), "/a/?foo");
525    }
526}