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>`</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}