rocket_http_community/uri/path_query.rs
1use std::borrow::Cow;
2use std::hash::Hash;
3
4use state::InitCell;
5
6use crate::parse::{Extent, IndexedStr};
7use crate::uri::fmt::{self, Part};
8use crate::uri::Segments;
9use crate::{ext::IntoOwned, RawStr};
10
11// INTERNAL DATA STRUCTURE.
12#[doc(hidden)]
13#[derive(Debug, Clone)]
14pub struct Data<'a, P: Part> {
15 pub(crate) value: IndexedStr<'a>,
16 pub(crate) decoded_segments: InitCell<Vec<P::Raw>>,
17}
18
19impl<'a, P: Part> Data<'a, P> {
20 pub(crate) fn raw(value: Extent<&'a [u8]>) -> Self {
21 Data {
22 value: value.into(),
23 decoded_segments: InitCell::new(),
24 }
25 }
26
27 // INTERNAL METHOD.
28 #[doc(hidden)]
29 pub fn new<S: Into<Cow<'a, str>>>(value: S) -> Self {
30 Data {
31 value: IndexedStr::from(value.into()),
32 decoded_segments: InitCell::new(),
33 }
34 }
35}
36
37/// A URI path: `/foo/bar`, `foo/bar`, etc.
38#[derive(Debug, Clone, Copy)]
39pub struct Path<'a> {
40 pub(crate) source: &'a Option<Cow<'a, str>>,
41 pub(crate) data: &'a Data<'a, fmt::Path>,
42}
43
44/// A URI query: `?foo&bar`.
45#[derive(Debug, Clone, Copy)]
46pub struct Query<'a> {
47 pub(crate) source: &'a Option<Cow<'a, str>>,
48 pub(crate) data: &'a Data<'a, fmt::Query>,
49}
50
51fn decode_to_indexed_str<P: fmt::Part>(
52 value: &RawStr,
53 (indexed, source): (&IndexedStr<'_>, &RawStr),
54) -> IndexedStr<'static> {
55 let decoded = match P::KIND {
56 fmt::Kind::Path => value.percent_decode_lossy(),
57 fmt::Kind::Query => value.url_decode_lossy(),
58 };
59
60 match decoded {
61 Cow::Borrowed(b) if indexed.is_indexed() => {
62 let checked = IndexedStr::checked_from(b, source.as_str());
63 debug_assert!(
64 checked.is_some(),
65 "\nunindexed {:?} in {:?} {:?}",
66 b,
67 indexed,
68 source
69 );
70 checked.unwrap_or_else(|| IndexedStr::from(Cow::Borrowed("")))
71 }
72 cow => IndexedStr::from(Cow::Owned(cow.into_owned())),
73 }
74}
75
76impl<'a> Path<'a> {
77 /// Returns the raw path value.
78 ///
79 /// # Example
80 ///
81 /// ```rust
82 /// # #[macro_use] extern crate rocket;
83 /// let uri = uri!("/foo%20bar%2dbaz");
84 /// assert_eq!(uri.path(), "/foo%20bar%2dbaz");
85 /// assert_eq!(uri.path().raw(), "/foo%20bar%2dbaz");
86 /// ```
87 pub fn raw(&self) -> &'a RawStr {
88 self.data.value.from_cow_source(self.source).into()
89 }
90
91 /// Returns the raw, undecoded path value as an `&str`.
92 ///
93 /// # Example
94 ///
95 /// ```rust
96 /// # #[macro_use] extern crate rocket;
97 /// let uri = uri!("/foo%20bar%2dbaz");
98 /// assert_eq!(uri.path(), "/foo%20bar%2dbaz");
99 /// assert_eq!(uri.path().as_str(), "/foo%20bar%2dbaz");
100 /// ```
101 pub fn as_str(&self) -> &'a str {
102 self.raw().as_str()
103 }
104
105 /// Whether `self` is normalized, i.e, it has no empty segments except the
106 /// last one.
107 ///
108 /// If `absolute`, then a starting `/` is required.
109 pub(crate) fn is_normalized(&self, absolute: bool) -> bool {
110 if absolute && !self.raw().starts_with('/') {
111 return false;
112 }
113
114 self.raw_segments().rev().skip(1).all(|s| !s.is_empty())
115 }
116
117 /// Normalizes `self`. If `absolute`, a starting `/` is required. If
118 /// `trail`, a trailing slash is allowed. Otherwise it is not.
119 pub(crate) fn to_normalized(self, absolute: bool, trail: bool) -> Data<'static, fmt::Path> {
120 let raw = self.raw().trim();
121 let mut path = String::with_capacity(raw.len());
122
123 if absolute || raw.starts_with('/') {
124 path.push('/');
125 }
126
127 for (i, segment) in self.raw_segments().filter(|s| !s.is_empty()).enumerate() {
128 if i != 0 {
129 path.push('/');
130 }
131 path.push_str(segment.as_str());
132 }
133
134 if trail && raw.len() > 1 && raw.ends_with('/') && !path.ends_with('/') {
135 path.push('/');
136 }
137
138 Data {
139 value: IndexedStr::from(Cow::Owned(path)),
140 decoded_segments: InitCell::new(),
141 }
142 }
143
144 /// Returns an iterator over the raw, undecoded segments, potentially empty
145 /// segments.
146 ///
147 /// ### Example
148 ///
149 /// ```rust
150 /// # #[macro_use] extern crate rocket;
151 /// use rocket::http::uri::Origin;
152 ///
153 /// let uri = Origin::parse("/").unwrap();
154 /// let segments: Vec<_> = uri.path().raw_segments().collect();
155 /// assert_eq!(segments, &[""]);
156 ///
157 /// let uri = Origin::parse("//").unwrap();
158 /// let segments: Vec<_> = uri.path().raw_segments().collect();
159 /// assert_eq!(segments, &["", ""]);
160 ///
161 /// let uri = Origin::parse("/foo").unwrap();
162 /// let segments: Vec<_> = uri.path().raw_segments().collect();
163 /// assert_eq!(segments, &["foo"]);
164 ///
165 /// let uri = Origin::parse("/a/").unwrap();
166 /// let segments: Vec<_> = uri.path().raw_segments().collect();
167 /// assert_eq!(segments, &["a", ""]);
168 ///
169 /// // Recall that `uri!()` normalizes static inputs.
170 /// let uri = uri!("//");
171 /// let segments: Vec<_> = uri.path().raw_segments().collect();
172 /// assert_eq!(segments, &[""]);
173 ///
174 /// let uri = Origin::parse("/a//b///c/d?query¶m").unwrap();
175 /// let segments: Vec<_> = uri.path().raw_segments().collect();
176 /// assert_eq!(segments, &["a", "", "b", "", "", "c", "d"]);
177 /// ```
178 #[inline]
179 pub fn raw_segments(&self) -> impl DoubleEndedIterator<Item = &'a RawStr> {
180 let raw = self.raw().trim();
181 raw.strip_prefix(fmt::Path::DELIMITER)
182 .unwrap_or(raw)
183 .split(fmt::Path::DELIMITER)
184 }
185
186 /// Returns a (smart) iterator over the percent-decoded segments. Empty
187 /// segments between non-empty segments are skipped. A trailing slash will
188 /// result in an empty segment emitted as the final item.
189 ///
190 /// # Example
191 ///
192 /// ```rust
193 /// # #[macro_use] extern crate rocket;
194 /// use rocket::http::uri::Origin;
195 ///
196 /// let uri = Origin::parse("/").unwrap();
197 /// let path_segs: Vec<&str> = uri.path().segments().collect();
198 /// assert_eq!(path_segs, &[""]);
199 ///
200 /// let uri = Origin::parse("/a").unwrap();
201 /// let path_segs: Vec<&str> = uri.path().segments().collect();
202 /// assert_eq!(path_segs, &["a"]);
203 ///
204 /// let uri = Origin::parse("/a/").unwrap();
205 /// let path_segs: Vec<&str> = uri.path().segments().collect();
206 /// assert_eq!(path_segs, &["a", ""]);
207 ///
208 /// let uri = Origin::parse("/foo/bar").unwrap();
209 /// let path_segs: Vec<&str> = uri.path().segments().collect();
210 /// assert_eq!(path_segs, &["foo", "bar"]);
211 ///
212 /// let uri = Origin::parse("/foo///bar").unwrap();
213 /// let path_segs: Vec<&str> = uri.path().segments().collect();
214 /// assert_eq!(path_segs, &["foo", "bar"]);
215 ///
216 /// let uri = Origin::parse("/foo///bar//").unwrap();
217 /// let path_segs: Vec<&str> = uri.path().segments().collect();
218 /// assert_eq!(path_segs, &["foo", "bar", ""]);
219 ///
220 /// let uri = Origin::parse("/a%20b/b%2Fc/d//e?query=some").unwrap();
221 /// let path_segs: Vec<&str> = uri.path().segments().collect();
222 /// assert_eq!(path_segs, &["a b", "b/c", "d", "e"]);
223 /// ```
224 pub fn segments(&self) -> Segments<'a, fmt::Path> {
225 let raw = self.raw();
226 let cached = self.data.decoded_segments.get_or_init(|| {
227 let mut segments = vec![];
228 let mut raw_segments = self.raw_segments().peekable();
229 while let Some(s) = raw_segments.next() {
230 // Only allow an empty segment if it's the last one.
231 if s.is_empty() && raw_segments.peek().is_some() {
232 continue;
233 }
234
235 segments.push(decode_to_indexed_str::<fmt::Path>(
236 s,
237 (&self.data.value, raw),
238 ));
239 }
240
241 segments
242 });
243
244 Segments::new(raw, cached)
245 }
246}
247
248impl<'a> Query<'a> {
249 /// Returns the raw, undecoded query value.
250 ///
251 /// # Example
252 ///
253 /// ```rust
254 /// # #[macro_use] extern crate rocket;
255 /// let uri = uri!("/foo?baz+bar");
256 /// assert_eq!(uri.query().unwrap(), "baz+bar");
257 /// assert_eq!(uri.query().unwrap().raw(), "baz+bar");
258 /// ```
259 pub fn raw(&self) -> &'a RawStr {
260 self.data.value.from_cow_source(self.source).into()
261 }
262
263 /// Returns the raw, undecoded query value as an `&str`.
264 ///
265 /// # Example
266 ///
267 /// ```rust
268 /// # #[macro_use] extern crate rocket;
269 /// let uri = uri!("/foo/bar?baz+bar");
270 /// assert_eq!(uri.query().unwrap(), "baz+bar");
271 /// assert_eq!(uri.query().unwrap().as_str(), "baz+bar");
272 /// ```
273 pub fn as_str(&self) -> &'a str {
274 self.raw().as_str()
275 }
276
277 /// Whether `self` is normalized, i.e, it has no empty segments.
278 pub(crate) fn is_normalized(&self) -> bool {
279 self.raw_segments().all(|s| !s.is_empty())
280 }
281
282 /// Normalizes `self`.
283 pub(crate) fn to_normalized(self) -> Data<'static, fmt::Query> {
284 let mut query = String::with_capacity(self.raw().trim().len());
285 for (i, seg) in self.raw_segments().filter(|s| !s.is_empty()).enumerate() {
286 if i != 0 {
287 query.push('&');
288 }
289 query.push_str(seg.as_str());
290 }
291
292 Data {
293 value: IndexedStr::from(Cow::Owned(query)),
294 decoded_segments: InitCell::new(),
295 }
296 }
297
298 /// Returns an iterator over the undecoded, potentially empty `(name,
299 /// value)` pairs of this query. If there is no query, the iterator is
300 /// empty.
301 ///
302 /// # Example
303 ///
304 /// ```rust
305 /// # #[macro_use] extern crate rocket;
306 /// use rocket::http::uri::Origin;
307 ///
308 /// let uri = Origin::parse("/").unwrap();
309 /// assert!(uri.query().is_none());
310 ///
311 /// let uri = Origin::parse("/?").unwrap();
312 /// let query_segs: Vec<_> = uri.query().unwrap().raw_segments().collect();
313 /// assert!(query_segs.is_empty());
314 ///
315 /// let uri = Origin::parse("/?foo").unwrap();
316 /// let query_segs: Vec<_> = uri.query().unwrap().raw_segments().collect();
317 /// assert_eq!(query_segs, &["foo"]);
318 ///
319 /// let uri = Origin::parse("/?a=b&dog").unwrap();
320 /// let query_segs: Vec<_> = uri.query().unwrap().raw_segments().collect();
321 /// assert_eq!(query_segs, &["a=b", "dog"]);
322 ///
323 /// let uri = Origin::parse("/?&").unwrap();
324 /// let query_segs: Vec<_> = uri.query().unwrap().raw_segments().collect();
325 /// assert_eq!(query_segs, &["", ""]);
326 ///
327 /// // Recall that `uri!()` normalizes, so this is equivalent to `/?`.
328 /// let uri = uri!("/?&");
329 /// let query_segs: Vec<_> = uri.query().unwrap().raw_segments().collect();
330 /// assert!(query_segs.is_empty());
331 ///
332 /// // These are raw and undecoded. Use `segments()` for decoded variant.
333 /// let uri = Origin::parse("/foo/bar?a+b%2F=some+one%40gmail.com&&%26%3D2").unwrap();
334 /// let query_segs: Vec<_> = uri.query().unwrap().raw_segments().collect();
335 /// assert_eq!(query_segs, &["a+b%2F=some+one%40gmail.com", "", "%26%3D2"]);
336 /// ```
337 #[inline]
338 pub fn raw_segments(&self) -> impl Iterator<Item = &'a RawStr> {
339 let query = match self.raw().trim() {
340 q if q.is_empty() => None,
341 q => Some(q),
342 };
343
344 query
345 .map(|p| p.split(fmt::Query::DELIMITER))
346 .into_iter()
347 .flatten()
348 }
349
350 /// Returns a (smart) iterator over the non-empty, url-decoded `(name,
351 /// value)` pairs of this query. If there is no query, the iterator is
352 /// empty.
353 ///
354 /// # Example
355 ///
356 /// ```rust
357 /// # #[macro_use] extern crate rocket;
358 /// use rocket::http::uri::Origin;
359 ///
360 /// let uri = Origin::parse("/").unwrap();
361 /// assert!(uri.query().is_none());
362 ///
363 /// let uri = Origin::parse("/foo/bar?a+b%2F=some+one%40gmail.com&&%26%3D2").unwrap();
364 /// let query_segs: Vec<_> = uri.query().unwrap().segments().collect();
365 /// assert_eq!(query_segs, &[("a b/", "some one@gmail.com"), ("&=2", "")]);
366 /// ```
367 pub fn segments(&self) -> Segments<'a, fmt::Query> {
368 let cached = self.data.decoded_segments.get_or_init(|| {
369 let (indexed, query) = (&self.data.value, self.raw());
370 self.raw_segments()
371 .filter(|s| !s.is_empty())
372 .map(|s| s.split_at_byte(b'='))
373 .map(|(k, v)| {
374 let key = decode_to_indexed_str::<fmt::Query>(k, (indexed, query));
375 let val = decode_to_indexed_str::<fmt::Query>(v, (indexed, query));
376 (key, val)
377 })
378 .collect()
379 });
380
381 Segments::new(self.raw(), cached)
382 }
383}
384
385macro_rules! impl_partial_eq {
386 ($A:ty = $B:ty) => {
387 impl PartialEq<$A> for $B {
388 #[inline(always)]
389 fn eq(&self, other: &$A) -> bool {
390 let left: &RawStr = self.as_ref();
391 let right: &RawStr = other.as_ref();
392 left == right
393 }
394 }
395 };
396}
397
398macro_rules! impl_traits {
399 ($T:ident) => (
400 impl Hash for $T<'_> {
401 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
402 self.raw().hash(state);
403 }
404 }
405
406 impl Eq for $T<'_> { }
407
408 impl IntoOwned for Data<'_, fmt::$T> {
409 type Owned = Data<'static, fmt::$T>;
410
411 fn into_owned(self) -> Self::Owned {
412 Data {
413 value: self.value.into_owned(),
414 decoded_segments: self.decoded_segments.map(|v| v.into_owned()),
415 }
416 }
417 }
418
419 impl std::ops::Deref for $T<'_> {
420 type Target = RawStr;
421
422 fn deref(&self) -> &Self::Target {
423 self.raw()
424 }
425 }
426
427 impl AsRef<RawStr> for $T<'_> {
428 fn as_ref(&self) -> &RawStr {
429 self.raw()
430 }
431 }
432
433 impl AsRef<std::ffi::OsStr> for $T<'_> {
434 fn as_ref(&self) -> &std::ffi::OsStr {
435 self.raw().as_ref()
436 }
437 }
438
439 impl std::fmt::Display for $T<'_> {
440 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
441 write!(f, "{}", self.raw())
442 }
443 }
444
445 impl_partial_eq!($T<'_> = $T<'_>);
446 impl_partial_eq!(str = $T<'_>);
447 impl_partial_eq!(&str = $T<'_>);
448 impl_partial_eq!($T<'_> = str);
449 impl_partial_eq!($T<'_> = &str);
450 impl_partial_eq!(RawStr = $T<'_>);
451 impl_partial_eq!(&RawStr = $T<'_>);
452 impl_partial_eq!($T<'_> = RawStr);
453 impl_partial_eq!($T<'_> = &RawStr);
454 )
455}
456
457impl_traits!(Path);
458impl_traits!(Query);