rocket_http/uri/
uri.rs

1use std::fmt::{self, Display};
2use std::borrow::Cow;
3
4use crate::ext::IntoOwned;
5use crate::uri::{Origin, Authority, Absolute, Reference, Asterisk};
6use crate::uri::error::{Error, TryFromUriError};
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<'_>>
83        where T: Into<Uri<'a>> + TryFrom<&'a str, Error = Error<'a>>
84    {
85        T::try_from(string).map(|v| v.into())
86    }
87
88    /// Parse `string` into a the "best fit" URI type.
89    ///
90    /// Always prefer to use `uri!()` for statically known inputs.
91    ///
92    /// Because URI parsing is ambiguous (that is, there isn't a one-to-one
93    /// mapping between strings and a URI type), the internal type returned by
94    /// this method _may_ not be the desired type. This method chooses the "best
95    /// fit" type for a given string by preferring to parse in the following
96    /// order:
97    ///
98    ///   * `Asterisk`
99    ///   * `Origin`
100    ///   * `Authority`
101    ///   * `Absolute`
102    ///   * `Reference`
103    ///
104    /// Thus, even though `*` is a valid `Asterisk` _and_ `Reference` URI, it
105    /// will parse as an `Asterisk`.
106    ///
107    /// # Example
108    ///
109    /// ```rust
110    /// # #[macro_use] extern crate rocket;
111    /// use rocket::http::uri::{Uri, Origin, Reference};
112    ///
113    /// // An absolute path is an origin _unless_ it contains a fragment.
114    /// let uri = Uri::parse_any("/a/b/c?query").expect("valid URI");
115    /// let origin = uri.origin().expect("origin URI");
116    /// assert_eq!(origin.path(), "/a/b/c");
117    /// assert_eq!(origin.query().unwrap(), "query");
118    ///
119    /// let uri = Uri::parse_any("/a/b/c?query#fragment").expect("valid URI");
120    /// let reference = uri.reference().expect("reference URI");
121    /// assert_eq!(reference.path(), "/a/b/c");
122    /// assert_eq!(reference.query().unwrap(), "query");
123    /// assert_eq!(reference.fragment().unwrap(), "fragment");
124    ///
125    /// // Prefer to use the `uri!()` macro for static inputs. The return type
126    /// // is the internal type, not `Uri`. The explicit type is not required.
127    /// let uri: Origin = uri!("/a/b/c?query");
128    /// let uri: Reference = uri!("/a/b/c?query#fragment");
129    /// ```
130    pub fn parse_any(string: &'a str) -> Result<Uri<'a>, Error<'_>> {
131        crate::parse::uri::from_str(string)
132    }
133
134    /// Returns the internal instance of `Origin` if `self` is a `Uri::Origin`.
135    /// Otherwise, returns `None`.
136    ///
137    /// # Example
138    ///
139    /// ```rust
140    /// # #[macro_use] extern crate rocket;
141    /// use rocket::http::uri::{Uri, Absolute, Origin};
142    ///
143    /// let uri = Uri::parse::<Origin>("/a/b/c?query").expect("valid URI");
144    /// assert!(uri.origin().is_some());
145    ///
146    /// let uri = Uri::from(uri!("/a/b/c?query"));
147    /// assert!(uri.origin().is_some());
148    ///
149    /// let uri = Uri::parse::<Absolute>("https://rocket.rs").expect("valid URI");
150    /// assert!(uri.origin().is_none());
151    ///
152    /// let uri = Uri::from(uri!("https://rocket.rs"));
153    /// assert!(uri.origin().is_none());
154    /// ```
155    pub fn origin(&self) -> Option<&Origin<'a>> {
156        match self {
157            Uri::Origin(ref inner) => Some(inner),
158            _ => None
159        }
160    }
161
162    /// Returns the internal instance of `Authority` if `self` is a
163    /// `Uri::Authority`. Otherwise, returns `None`.
164    ///
165    /// # Example
166    ///
167    /// ```rust
168    /// # #[macro_use] extern crate rocket;
169    /// use rocket::http::uri::{Uri, Absolute, Authority};
170    ///
171    /// let uri = Uri::parse::<Authority>("user:pass@domain.com").expect("valid URI");
172    /// assert!(uri.authority().is_some());
173    ///
174    /// let uri = Uri::from(uri!("user:pass@domain.com"));
175    /// assert!(uri.authority().is_some());
176    ///
177    /// let uri = Uri::parse::<Absolute>("https://rocket.rs").expect("valid URI");
178    /// assert!(uri.authority().is_none());
179    ///
180    /// let uri = Uri::from(uri!("https://rocket.rs"));
181    /// assert!(uri.authority().is_none());
182    /// ```
183    pub fn authority(&self) -> Option<&Authority<'a>> {
184        match self {
185            Uri::Authority(ref inner) => Some(inner),
186            _ => None
187        }
188    }
189
190    /// Returns the internal instance of `Absolute` if `self` is a
191    /// `Uri::Absolute`. Otherwise, returns `None`.
192    ///
193    /// # Example
194    ///
195    /// ```rust
196    /// # #[macro_use] extern crate rocket;
197    /// use rocket::http::uri::{Uri, Absolute, Origin};
198    ///
199    /// let uri = Uri::parse::<Absolute>("http://rocket.rs").expect("valid URI");
200    /// assert!(uri.absolute().is_some());
201    ///
202    /// let uri = Uri::from(uri!("http://rocket.rs"));
203    /// assert!(uri.absolute().is_some());
204    ///
205    /// let uri = Uri::parse::<Origin>("/path").expect("valid URI");
206    /// assert!(uri.absolute().is_none());
207    ///
208    /// let uri = Uri::from(uri!("/path"));
209    /// assert!(uri.absolute().is_none());
210    /// ```
211    pub fn absolute(&self) -> Option<&Absolute<'a>> {
212        match self {
213            Uri::Absolute(ref inner) => Some(inner),
214            _ => None
215        }
216    }
217
218    /// Returns the internal instance of `Reference` if `self` is a
219    /// `Uri::Reference`. Otherwise, returns `None`.
220    ///
221    /// # Example
222    ///
223    /// ```rust
224    /// # #[macro_use] extern crate rocket;
225    /// use rocket::http::uri::{Uri, Absolute, Reference};
226    ///
227    /// let uri = Uri::parse::<Reference>("foo/bar").expect("valid URI");
228    /// assert!(uri.reference().is_some());
229    ///
230    /// let uri = Uri::from(uri!("foo/bar"));
231    /// assert!(uri.reference().is_some());
232    ///
233    /// let uri = Uri::parse::<Absolute>("https://rocket.rs").expect("valid URI");
234    /// assert!(uri.reference().is_none());
235    ///
236    /// let uri = Uri::from(uri!("https://rocket.rs"));
237    /// assert!(uri.reference().is_none());
238    /// ```
239    pub fn reference(&self) -> Option<&Reference<'a>> {
240        match self {
241            Uri::Reference(ref inner) => Some(inner),
242            _ => None
243        }
244    }
245}
246
247pub(crate) unsafe fn as_utf8_unchecked(input: Cow<'_, [u8]>) -> Cow<'_, str> {
248    match input {
249        Cow::Borrowed(bytes) => Cow::Borrowed(std::str::from_utf8_unchecked(bytes)),
250        Cow::Owned(bytes) => Cow::Owned(String::from_utf8_unchecked(bytes))
251    }
252}
253
254// impl<'a> TryFrom<&'a str> for Uri<'a> {
255//     type Error = Error<'a>;
256//
257//     #[inline]
258//     fn try_from(string: &'a str) -> Result<Uri<'a>, Self::Error> {
259//         Uri::parse(string)
260//     }
261// }
262//
263// impl TryFrom<String> for Uri<'static> {
264//     type Error = Error<'static>;
265//
266//     #[inline]
267//     fn try_from(string: String) -> Result<Uri<'static>, Self::Error> {
268//         // TODO: Potentially optimize this like `Origin::parse_owned`.
269//         Uri::parse(&string)
270//             .map(|u| u.into_owned())
271//             .map_err(|e| e.into_owned())
272//     }
273// }
274
275impl IntoOwned for Uri<'_> {
276    type Owned = Uri<'static>;
277
278    fn into_owned(self) -> Uri<'static> {
279        match self {
280            Uri::Origin(origin) => Uri::Origin(origin.into_owned()),
281            Uri::Authority(authority) => Uri::Authority(authority.into_owned()),
282            Uri::Absolute(absolute) => Uri::Absolute(absolute.into_owned()),
283            Uri::Reference(reference) => Uri::Reference(reference.into_owned()),
284            Uri::Asterisk(asterisk) => Uri::Asterisk(asterisk)
285        }
286    }
287}
288
289impl Display for Uri<'_> {
290    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291        match *self {
292            Uri::Origin(ref origin) => write!(f, "{}", origin),
293            Uri::Authority(ref authority) => write!(f, "{}", authority),
294            Uri::Absolute(ref absolute) => write!(f, "{}", absolute),
295            Uri::Reference(ref reference) => write!(f, "{}", reference),
296            Uri::Asterisk(ref asterisk) => write!(f, "{}", asterisk)
297        }
298    }
299}
300
301macro_rules! impl_uri_from {
302    ($T:ident $(<$lt:lifetime>)?) => (
303        impl<'a> From<$T $(<$lt>)?> for Uri<'a> {
304            fn from(other: $T $(<$lt>)?) -> Uri<'a> {
305                Uri::$T(other)
306            }
307        }
308
309        impl<'a> TryFrom<Uri<'a>> for $T $(<$lt>)? {
310            type Error = TryFromUriError;
311
312            fn try_from(uri: Uri<'a>) -> Result<Self, Self::Error> {
313                match uri {
314                    Uri::$T(inner) => Ok(inner),
315                    _ => Err(TryFromUriError(()))
316                }
317            }
318        }
319
320        impl<'b, $($lt)?> PartialEq<$T $(<$lt>)?> for Uri<'b> {
321            fn eq(&self, other: &$T $(<$lt>)?) -> bool {
322                match self {
323                    Uri::$T(inner) => inner == other,
324                    _ => false
325                }
326            }
327        }
328
329        impl<'b, $($lt)?> PartialEq<Uri<'b>> for $T $(<$lt>)? {
330            fn eq(&self, other: &Uri<'b>) -> bool {
331                match other {
332                    Uri::$T(inner) => inner == self,
333                    _ => false
334                }
335            }
336        }
337    )
338}
339
340impl_uri_from!(Origin<'a>);
341impl_uri_from!(Authority<'a>);
342impl_uri_from!(Absolute<'a>);
343impl_uri_from!(Reference<'a>);
344impl_uri_from!(Asterisk);
345
346/// Implements Serialize and Deserialize for any 'URI' looking type.
347macro_rules! impl_serde {
348    ($T:ty, $expected:literal) => {
349        #[cfg(feature = "serde")]
350        mod serde {
351            use std::fmt;
352            use std::marker::PhantomData;
353            use super::*;
354
355            use serde_::ser::{Serialize, Serializer};
356            use serde_::de::{Deserialize, Deserializer, Error, Visitor};
357
358            impl<'a> Serialize for $T {
359                fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
360                    serializer.serialize_str(&self.to_string())
361                }
362            }
363
364            struct DeVisitor<'a>(PhantomData<&'a $T>);
365
366            impl<'de, 'a> Visitor<'de> for DeVisitor<'a> {
367                type Value = $T;
368
369                fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
370                    write!(formatter, $expected)
371                }
372
373                fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
374                    <$T>::parse_owned(v.to_string()).map_err(Error::custom)
375                }
376
377                fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
378                    <$T>::parse_owned(v).map_err(Error::custom)
379                }
380            }
381
382            impl<'a, 'de> Deserialize<'de> for $T {
383                fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
384                    deserializer.deserialize_str(DeVisitor(PhantomData))
385                }
386            }
387        }
388    };
389}
390
391/// Implements traits from `impl_base_traits` and IntoOwned for a URI.
392macro_rules! impl_traits {
393    ($T:ident, $($field:ident),* $(,)?) => {
394        impl_base_traits!($T, $($field),*);
395
396        impl crate::ext::IntoOwned for $T<'_> {
397            type Owned = $T<'static>;
398
399            fn into_owned(self) -> $T<'static> {
400                $T {
401                    source: self.source.into_owned(),
402                    $($field: self.$field.into_owned()),*
403                }
404            }
405        }
406    }
407}
408
409/// Implements PartialEq, Eq, Hash, and TryFrom.
410macro_rules! impl_base_traits {
411    ($T:ident, $($field:ident),* $(,)?) => {
412        impl std::convert::TryFrom<String> for $T<'static> {
413            type Error = Error<'static>;
414
415            fn try_from(value: String) -> Result<Self, Self::Error> {
416                $T::parse_owned(value)
417            }
418        }
419
420        // Because inference doesn't take `&String` to `&str`.
421        impl<'a> std::convert::TryFrom<&'a String> for $T<'a> {
422            type Error = Error<'a>;
423
424            fn try_from(value: &'a String) -> Result<Self, Self::Error> {
425                $T::parse(value.as_str())
426            }
427        }
428
429        impl<'a> std::convert::TryFrom<&'a str> for $T<'a> {
430            type Error = Error<'a>;
431
432            fn try_from(value: &'a str) -> Result<Self, Self::Error> {
433                $T::parse(value)
434            }
435        }
436
437        impl<'a, 'b> PartialEq<$T<'b>> for $T<'a> {
438            fn eq(&self, other: &$T<'b>) -> bool {
439                true $(&& self.$field() == other.$field())*
440            }
441        }
442
443        impl PartialEq<str> for $T<'_> {
444            fn eq(&self, string: &str) -> bool {
445                $T::parse(string).map_or(false, |v| &v == self)
446            }
447        }
448
449        impl PartialEq<&str> for $T<'_> {
450            fn eq(&self, other: &&str) -> bool {
451                self.eq(*other)
452            }
453        }
454
455        impl PartialEq<$T<'_>> for str {
456            fn eq(&self, other: &$T<'_>) -> bool {
457                other.eq(self)
458            }
459        }
460
461        impl Eq for $T<'_> { }
462
463        impl std::hash::Hash for $T<'_> {
464            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
465                $(self.$field().hash(state);)*
466            }
467        }
468    }
469}