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