1 use std::borrow::Cow;
2 use std::fmt::{self, Display};
3 
4 use crate::ext::IntoOwned;
5 use crate::parse::{Indexed, IndexedStr};
6 use crate::uri::{Authority, Origin, Error, as_utf8_unchecked};
7 
8 /// A URI with a scheme, authority, path, and query:
9 /// `http://user:pass@domain.com:4444/path?query`.
10 ///
11 /// # Structure
12 ///
13 /// The following diagram illustrates the syntactic structure of an absolute
14 /// URI with all optional parts:
15 ///
16 /// ```text
17 ///  http://user:pass@domain.com:4444/path?query
18 ///  |--|   |-----------------------||---------|
19 /// scheme          authority          origin
20 /// ```
21 ///
22 /// The scheme part of the absolute URI and at least one of authority or origin
23 /// are required.
24 #[derive(Debug, Clone)]
25 pub struct Absolute<'a> {
26     source: Option<Cow<'a, str>>,
27     scheme: IndexedStr<'a>,
28     authority: Option<Authority<'a>>,
29     origin: Option<Origin<'a>>,
30 }
31 
32 impl IntoOwned for Absolute<'_> {
33     type Owned = Absolute<'static>;
34 
into_owned(self) -> Self::Owned35     fn into_owned(self) -> Self::Owned {
36         Absolute {
37             source: self.source.into_owned(),
38             scheme: self.scheme.into_owned(),
39             authority: self.authority.into_owned(),
40             origin: self.origin.into_owned(),
41         }
42     }
43 }
44 
45 impl<'a> Absolute<'a> {
46     #[inline]
raw( source: Cow<'a, [u8]>, scheme: Indexed<'a, [u8]>, authority: Option<Authority<'a>>, origin: Option<Origin<'a>>, ) -> Absolute<'a>47     pub(crate) unsafe fn raw(
48         source: Cow<'a, [u8]>,
49         scheme: Indexed<'a, [u8]>,
50         authority: Option<Authority<'a>>,
51         origin: Option<Origin<'a>>,
52     ) -> Absolute<'a> {
53         Absolute {
54             source: Some(as_utf8_unchecked(source)),
55             scheme: scheme.coerce(),
56             authority: authority,
57             origin: origin,
58         }
59     }
60 
61     #[cfg(test)]
new( scheme: &'a str, authority: Option<Authority<'a>>, origin: Option<Origin<'a>> ) -> Absolute<'a>62     pub(crate) fn new(
63         scheme: &'a str,
64         authority: Option<Authority<'a>>,
65         origin: Option<Origin<'a>>
66     ) -> Absolute<'a> {
67         Absolute {
68             source: None, scheme: scheme.into(), authority, origin
69         }
70     }
71 
72     /// Parses the string `string` into an `Absolute`. Parsing will never
73     /// allocate. Returns an `Error` if `string` is not a valid absolute URI.
74     ///
75     /// # Example
76     ///
77     /// ```rust
78     /// # extern crate rocket;
79     /// use rocket::http::uri::Absolute;
80     ///
81     /// // Parse a valid authority URI.
82     /// let uri = Absolute::parse("http://google.com").expect("valid URI");
83     /// assert_eq!(uri.scheme(), "http");
84     /// assert_eq!(uri.authority().unwrap().host(), "google.com");
85     /// assert_eq!(uri.origin(), None);
86     /// ```
parse(string: &'a str) -> Result<Absolute<'a>, Error<'a>>87     pub fn parse(string: &'a str) -> Result<Absolute<'a>, Error<'a>> {
88         crate::parse::uri::absolute_from_str(string)
89     }
90 
91     /// Returns the scheme part of the absolute URI.
92     ///
93     /// # Example
94     ///
95     /// ```rust
96     /// # extern crate rocket;
97     /// use rocket::http::uri::Absolute;
98     ///
99     /// let uri = Absolute::parse("ftp://127.0.0.1").expect("valid URI");
100     /// assert_eq!(uri.scheme(), "ftp");
101     /// ```
102     #[inline(always)]
scheme(&self) -> &str103     pub fn scheme(&self) -> &str {
104         self.scheme.from_cow_source(&self.source)
105     }
106 
107     /// Returns the authority part of the absolute URI, if there is one.
108     ///
109     /// # Example
110     ///
111     /// ```rust
112     /// # extern crate rocket;
113     /// use rocket::http::uri::Absolute;
114     ///
115     /// let uri = Absolute::parse("https://rocket.rs:80").expect("valid URI");
116     /// assert_eq!(uri.scheme(), "https");
117     /// let authority = uri.authority().unwrap();
118     /// assert_eq!(authority.host(), "rocket.rs");
119     /// assert_eq!(authority.port(), Some(80));
120     ///
121     /// let uri = Absolute::parse("file:/web/home").expect("valid URI");
122     /// assert_eq!(uri.authority(), None);
123     /// ```
124     #[inline(always)]
authority(&self) -> Option<&Authority<'a>>125     pub fn authority(&self) -> Option<&Authority<'a>> {
126         self.authority.as_ref()
127     }
128 
129     /// Returns the origin part of the absolute URI, if there is one.
130     ///
131     /// # Example
132     ///
133     /// ```rust
134     /// # extern crate rocket;
135     /// use rocket::http::uri::Absolute;
136     ///
137     /// let uri = Absolute::parse("file:/web/home.html?new").expect("valid URI");
138     /// assert_eq!(uri.scheme(), "file");
139     /// let origin = uri.origin().unwrap();
140     /// assert_eq!(origin.path(), "/web/home.html");
141     /// assert_eq!(origin.query(), Some("new"));
142     ///
143     /// let uri = Absolute::parse("https://rocket.rs").expect("valid URI");
144     /// assert_eq!(uri.origin(), None);
145     /// ```
146     #[inline(always)]
origin(&self) -> Option<&Origin<'a>>147     pub fn origin(&self) -> Option<&Origin<'a>> {
148         self.origin.as_ref()
149     }
150 }
151 
152 impl<'b> PartialEq<Absolute<'b>> for Absolute<'_> {
eq(&self, other: &Absolute<'b>) -> bool153     fn eq(&self, other: &Absolute<'b>) -> bool {
154         self.scheme() == other.scheme()
155             && self.authority() == other.authority()
156             && self.origin() == other.origin()
157     }
158 }
159 
160 impl Display for Absolute<'_> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result161     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162         write!(f, "{}", self.scheme())?;
163         match self.authority {
164             Some(ref authority) => write!(f, "://{}", authority)?,
165             None => write!(f, ":")?
166         }
167 
168         if let Some(ref origin) = self.origin {
169             write!(f, "{}", origin)?;
170         }
171 
172         Ok(())
173     }
174 }
175 
176