rocket_http/
raw_str.rs

1use std::borrow::{Borrow, Cow};
2use std::convert::AsRef;
3use std::cmp::Ordering;
4use std::str::Utf8Error;
5use std::fmt;
6
7use ref_cast::RefCast;
8use stable_pattern::{Pattern, Searcher, ReverseSearcher, Split, SplitInternal};
9use crate::uri::fmt::{DEFAULT_ENCODE_SET, percent_encode, percent_encode_bytes};
10
11use crate::uncased::UncasedStr;
12
13/// A reference to a string inside of a raw HTTP message.
14///
15/// A `RawStr` is an unsanitized, unvalidated, and undecoded raw string from an
16/// HTTP message. It exists to separate validated string inputs, represented by
17/// the `String`, `&str`, and `Cow<str>` types, from unvalidated inputs,
18/// represented by `&RawStr`.
19///
20/// # Validation
21///
22/// An `&RawStr` should be converted into one of the validated string input
23/// types through methods on `RawStr`. These methods are summarized below:
24///
25///   * **[`url_decode()`]** - used to decode a raw string in a form value
26///     context
27///   * **[`percent_decode()`], [`percent_decode_lossy()`]** - used to
28///     percent-decode a raw string, typically in a URL context
29///   * **[`html_escape()`]** - used to decode a string for use in HTML
30///     templates
31///   * **[`as_str()`]** - used when the `RawStr` is known to be safe in the
32///     context of its intended use. Use sparingly and with care!
33///   * **[`as_uncased_str()`]** - used when the `RawStr` is known to be safe in
34///     the context of its intended, uncased use
35///
36/// **Note:** Template engines like Tera and Handlebars all functions like
37/// [`html_escape()`] on all rendered template outputs by default.
38///
39/// [`as_str()`]: RawStr::as_str()
40/// [`as_uncased_str()`]: RawStr::as_uncased_str()
41/// [`url_decode()`]: RawStr::url_decode()
42/// [`html_escape()`]: RawStr::html_escape()
43/// [`percent_decode()`]: RawStr::percent_decode()
44/// [`percent_decode_lossy()`]: RawStr::percent_decode_lossy()
45///
46/// # Usage
47///
48/// A `RawStr` is a dynamically sized type (just like `str`). It is always used
49/// through a reference an as `&RawStr` (just like &str).
50#[repr(transparent)]
51#[derive(RefCast, PartialEq, Eq, PartialOrd, Ord, Hash)]
52pub struct RawStr(str);
53
54impl ToOwned for RawStr {
55    type Owned = RawStrBuf;
56
57    fn to_owned(&self) -> Self::Owned {
58        RawStrBuf(self.to_string())
59    }
60}
61
62/// An owned version of [`RawStr`].
63#[repr(transparent)]
64#[derive(RefCast, PartialEq, Eq, PartialOrd, Ord, Hash)]
65pub struct RawStrBuf(String);
66
67impl RawStrBuf {
68    /// Cost-free conversion from `self` into a `String`.
69    ///
70    /// # Example
71    ///
72    /// ```rust
73    /// # extern crate rocket;
74    /// use rocket::http::RawStrBuf;
75    ///
76    /// let raw = RawStrBuf::from(format!("hello {}", "world"));
77    /// let string = raw.into_string();
78    /// ```
79    pub fn into_string(self) -> String {
80        self.0
81    }
82}
83
84impl RawStr {
85    /// Constructs an `&RawStr` from a string-like type at no cost.
86    ///
87    /// # Example
88    ///
89    /// ```rust
90    /// # extern crate rocket;
91    /// use rocket::http::RawStr;
92    ///
93    /// let raw_str = RawStr::new("Hello, world!");
94    ///
95    /// // `into` can also be used; note that the type must be specified
96    /// let raw_str: &RawStr = "Hello, world!".into();
97    /// ```
98    pub fn new<S: AsRef<str> + ?Sized>(string: &S) -> &RawStr {
99        RawStr::ref_cast(string.as_ref())
100    }
101
102    /// Construct a `Cow<RawStr>` from a `Cow<Str>`. Does not allocate.
103    ///
104    /// See [`RawStr::into_cow_str()`] for the inverse operation.
105    ///
106    /// # Example
107    ///
108    /// ```rust
109    /// # extern crate rocket;
110    /// use std::borrow::Cow;
111    /// use rocket::http::RawStr;
112    ///
113    /// let cow_str = Cow::from("hello!");
114    /// let cow_raw = RawStr::from_cow_str(cow_str);
115    /// assert_eq!(cow_raw.as_str(), "hello!");
116    /// ```
117    pub fn from_cow_str(cow: Cow<'_, str>) -> Cow<'_, RawStr> {
118        match cow {
119            Cow::Borrowed(b) => Cow::Borrowed(b.into()),
120            Cow::Owned(b) => Cow::Owned(b.into()),
121        }
122    }
123
124    /// Construct a `Cow<str>` from a `Cow<RawStr>`. Does not allocate.
125    ///
126    /// See [`RawStr::from_cow_str()`] for the inverse operation.
127    ///
128    /// # Example
129    ///
130    /// ```rust
131    /// # extern crate rocket;
132    /// use std::borrow::Cow;
133    /// use rocket::http::RawStr;
134    ///
135    /// let cow_raw = Cow::from(RawStr::new("hello!"));
136    /// let cow_str = RawStr::into_cow_str(cow_raw);
137    /// assert_eq!(&*cow_str, "hello!");
138    /// ```
139    pub fn into_cow_str(cow: Cow<'_, RawStr>) -> Cow<'_, str> {
140        match cow {
141            Cow::Borrowed(b) => Cow::Borrowed(b.as_str()),
142            Cow::Owned(b) => Cow::Owned(b.into_string()),
143        }
144    }
145
146    /// Percent-decodes `self`.
147    fn _percent_decode(&self) -> percent_encoding::PercentDecode<'_> {
148        percent_encoding::percent_decode(self.as_bytes())
149    }
150
151    /// Returns a percent-decoded version of the string.
152    ///
153    /// # Errors
154    ///
155    /// Returns an `Err` if the percent encoded values are not valid UTF-8.
156    ///
157    /// # Example
158    ///
159    /// With a valid string:
160    ///
161    /// ```rust
162    /// # extern crate rocket;
163    /// use rocket::http::RawStr;
164    ///
165    /// let raw_str = RawStr::new("Hello%21");
166    /// let decoded = raw_str.percent_decode();
167    /// assert_eq!(decoded, Ok("Hello!".into()));
168    /// ```
169    ///
170    /// With an invalid string:
171    ///
172    /// ```rust
173    /// # extern crate rocket;
174    /// use rocket::http::RawStr;
175    ///
176    /// let bad_raw_str = RawStr::new("%FF");
177    /// assert!(bad_raw_str.percent_decode().is_err());
178    /// ```
179    #[inline(always)]
180    pub fn percent_decode(&self) -> Result<Cow<'_, str>, Utf8Error> {
181        self._percent_decode().decode_utf8()
182    }
183
184    /// Returns a percent-decoded version of the string. Any invalid UTF-8
185    /// percent-encoded byte sequences will be replaced � U+FFFD, the
186    /// replacement character.
187    ///
188    /// # Example
189    ///
190    /// With a valid string:
191    ///
192    /// ```rust
193    /// # extern crate rocket;
194    /// use rocket::http::RawStr;
195    ///
196    /// let raw_str = RawStr::new("Hello%21");
197    /// let decoded = raw_str.percent_decode_lossy();
198    /// assert_eq!(decoded, "Hello!");
199    /// ```
200    ///
201    /// With an invalid string:
202    ///
203    /// ```rust
204    /// # extern crate rocket;
205    /// use rocket::http::RawStr;
206    ///
207    /// let bad_raw_str = RawStr::new("a=%FF");
208    /// assert_eq!(bad_raw_str.percent_decode_lossy(), "a=�");
209    /// ```
210    #[inline(always)]
211    pub fn percent_decode_lossy(&self) -> Cow<'_, str> {
212        self._percent_decode().decode_utf8_lossy()
213    }
214
215    /// Replaces '+' with ' ' in `self`, allocating only when necessary.
216    fn _replace_plus(&self) -> Cow<'_, str> {
217        let string = self.as_str();
218        let mut allocated = String::new(); // this is allocation free
219        for i in memchr::memchr_iter(b'+', string.as_bytes()) {
220            if allocated.is_empty() {
221                allocated = string.into();
222            }
223
224            // SAFETY:
225            //
226            // 1. The caller must ensure that the content of the slice is valid
227            //    UTF-8 before the borrow ends and the underlying `str` is used.
228            //
229            //    `allocated[i]` is `+` since that is what we searched for. The
230            //    `+` char is ASCII => the character is one byte wide. ' ' is
231            //    also one byte and ASCII => UTF-8. The replacement of `+` with
232            //    ` ` thus yields a valid UTF-8 string.
233            unsafe { allocated.as_bytes_mut()[i] = b' '; }
234        }
235
236        match allocated.is_empty() {
237            true => Cow::Borrowed(string),
238            false => Cow::Owned(allocated)
239        }
240    }
241
242    /// Returns a percent-encoded version of the string.
243    ///
244    /// # Example
245    ///
246    /// With a valid string:
247    ///
248    /// ```rust
249    /// # extern crate rocket;
250    /// use rocket::http::RawStr;
251    ///
252    /// let raw_str = RawStr::new("Hello%21");
253    /// let decoded = raw_str.percent_decode();
254    /// assert_eq!(decoded, Ok("Hello!".into()));
255    /// ```
256    ///
257    /// With an invalid string:
258    ///
259    /// ```rust
260    /// # extern crate rocket;
261    /// use rocket::http::RawStr;
262    ///
263    /// let bad_raw_str = RawStr::new("%FF");
264    /// assert!(bad_raw_str.percent_decode().is_err());
265    /// ```
266    #[inline(always)]
267    pub fn percent_encode(&self) -> Cow<'_, RawStr> {
268        Self::from_cow_str(percent_encode::<DEFAULT_ENCODE_SET>(self))
269    }
270
271    /// Returns a percent-encoded version of `bytes`.
272    ///
273    /// # Example
274    ///
275    /// ```rust
276    /// # extern crate rocket;
277    /// use rocket::http::RawStr;
278    ///
279    /// // Note: Rocket should never hand you a bad `&RawStr`.
280    /// let bytes = &[93, 12, 0, 13, 1];
281    /// let encoded = RawStr::percent_encode_bytes(&bytes[..]);
282    /// ```
283    #[inline(always)]
284    pub fn percent_encode_bytes(bytes: &[u8]) -> Cow<'_, RawStr> {
285        Self::from_cow_str(percent_encode_bytes::<DEFAULT_ENCODE_SET>(bytes))
286    }
287
288    /// Returns a URL-decoded version of the string. This is identical to
289    /// percent decoding except that `+` characters are converted into spaces.
290    /// This is the encoding used by form values.
291    ///
292    /// # Errors
293    ///
294    /// Returns an `Err` if the percent encoded values are not valid UTF-8.
295    ///
296    /// # Example
297    ///
298    /// ```rust
299    /// # extern crate rocket;
300    /// use rocket::http::RawStr;
301    ///
302    /// let raw_str = RawStr::new("Hello%2C+world%21");
303    /// let decoded = raw_str.url_decode();
304    /// assert_eq!(decoded.unwrap(), "Hello, world!");
305    /// ```
306    pub fn url_decode(&self) -> Result<Cow<'_, str>, Utf8Error> {
307        let string = self._replace_plus();
308        match percent_encoding::percent_decode(string.as_bytes()).decode_utf8()? {
309            Cow::Owned(s) => Ok(Cow::Owned(s)),
310            Cow::Borrowed(_) => Ok(string)
311        }
312    }
313
314    /// Returns a URL-decoded version of the string.
315    ///
316    /// Any invalid UTF-8 percent-encoded byte sequences will be replaced �
317    /// U+FFFD, the replacement character. This is identical to lossy percent
318    /// decoding except that `+` characters are converted into spaces. This is
319    /// the encoding used by form values.
320    ///
321    /// # Example
322    ///
323    /// With a valid string:
324    ///
325    /// ```rust
326    /// # extern crate rocket;
327    /// use rocket::http::RawStr;
328    ///
329    /// let raw_str: &RawStr = "Hello%2C+world%21".into();
330    /// let decoded = raw_str.url_decode_lossy();
331    /// assert_eq!(decoded, "Hello, world!");
332    /// ```
333    ///
334    /// With an invalid string:
335    ///
336    /// ```rust
337    /// # extern crate rocket;
338    /// use rocket::http::RawStr;
339    ///
340    /// let bad_raw_str = RawStr::new("a+b=%FF");
341    /// assert_eq!(bad_raw_str.url_decode_lossy(), "a b=�");
342    /// ```
343    pub fn url_decode_lossy(&self) -> Cow<'_, str> {
344        let string = self._replace_plus();
345        match percent_encoding::percent_decode(string.as_bytes()).decode_utf8_lossy() {
346            Cow::Owned(s) => Cow::Owned(s),
347            Cow::Borrowed(_) => string
348        }
349    }
350
351    /// Returns an HTML escaped version of `self`. Allocates only when
352    /// characters need to be escaped.
353    ///
354    /// The following characters are escaped: `&`, `<`, `>`, `"`, `'`, `/`,
355    /// <code>`</code>. **This suffices as long as the escaped string is not
356    /// used in an execution context such as inside of &lt;script> or &lt;style>
357    /// tags!** See the [OWASP XSS Prevention Rules] for more information.
358    ///
359    /// [OWASP XSS Prevention Rules]: https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet#XSS_Prevention_Rules
360    ///
361    /// # Example
362    ///
363    /// Strings with HTML sequences are escaped:
364    ///
365    /// ```rust
366    /// # extern crate rocket;
367    /// use rocket::http::RawStr;
368    ///
369    /// let raw_str: &RawStr = "<b>Hi!</b>".into();
370    /// let escaped = raw_str.html_escape();
371    /// assert_eq!(escaped, "&lt;b&gt;Hi!&lt;&#x2F;b&gt;");
372    ///
373    /// let raw_str: &RawStr = "Hello, <i>world!</i>".into();
374    /// let escaped = raw_str.html_escape();
375    /// assert_eq!(escaped, "Hello, &lt;i&gt;world!&lt;&#x2F;i&gt;");
376    /// ```
377    ///
378    /// Strings without HTML sequences remain untouched:
379    ///
380    /// ```rust
381    /// # extern crate rocket;
382    /// use rocket::http::RawStr;
383    ///
384    /// let raw_str: &RawStr = "Hello!".into();
385    /// let escaped = raw_str.html_escape();
386    /// assert_eq!(escaped, "Hello!");
387    ///
388    /// let raw_str: &RawStr = "大阪".into();
389    /// let escaped = raw_str.html_escape();
390    /// assert_eq!(escaped, "大阪");
391    /// ```
392    // NOTE: This is the ~fastest (a table-based implementation is slightly
393    // faster) implementation benchmarked for dense-ish escaping. For sparser
394    // texts, a regex-based-find solution is much faster.
395    pub fn html_escape(&self) -> Cow<'_, str> {
396        let mut escaped = false;
397        let mut allocated = Vec::new(); // this is allocation free
398        for c in self.as_bytes() {
399            match *c {
400                b'&' | b'<' | b'>' | b'"' | b'\'' | b'/' | b'`' => {
401                    if !escaped {
402                        let i = (c as *const u8 as usize) - (self.as_ptr() as usize);
403                        allocated = Vec::with_capacity(self.len() * 2);
404                        allocated.extend_from_slice(&self.as_bytes()[..i]);
405                    }
406
407                    match *c {
408                        b'&' => allocated.extend_from_slice(b"&amp;"),
409                        b'<' => allocated.extend_from_slice(b"&lt;"),
410                        b'>' => allocated.extend_from_slice(b"&gt;"),
411                        b'"' => allocated.extend_from_slice(b"&quot;"),
412                        b'\'' => allocated.extend_from_slice(b"&#x27;"),
413                        b'/' => allocated.extend_from_slice(b"&#x2F;"),
414                        // Old versions of IE treat a ` as a '.
415                        b'`' => allocated.extend_from_slice(b"&#96;"),
416                        _ => unreachable!()
417                    }
418
419                    escaped = true;
420                }
421                _ if escaped => allocated.push(*c),
422                _ => {  }
423            }
424        }
425
426        if escaped {
427            // This use of `unsafe` is only correct if the bytes in `allocated`
428            // form a valid UTF-8 string. We prove this by cases:
429            //
430            // 1. In the `!escaped` branch, capacity for the vector is first
431            //    allocated. No characters are pushed to `allocated` prior to
432            //    this branch running since the `escaped` flag isn't set. To
433            //    enter this branch, the current byte must be a valid ASCII
434            //    character. This implies that every byte preceding forms a
435            //    valid UTF-8 string since ASCII characters in UTF-8 are never
436            //    part of a multi-byte sequence. Thus, extending the `allocated`
437            //    vector with these bytes results in a valid UTF-8 string in
438            //    `allocated`.
439            //
440            // 2. After the `!escaped` branch, `allocated` is extended with a
441            //    byte string of valid ASCII characters. Thus, `allocated` is
442            //    still a valid UTF-8 string.
443            //
444            // 3. In the `_ if escaped` branch, the byte is simply pushed into
445            //    the `allocated` vector. At this point, `allocated` may contain
446            //    an invalid UTF-8 string as we are not a known boundary.
447            //    However, note that this byte is part of a known valid string
448            //    (`self`). If the byte is not part of a multi-byte sequence, it
449            //    is ASCII, and no further justification is needed. If the byte
450            //    _is_ part of a multi-byte sequence, it is _not_ ASCII, and
451            //    thus will not fall into the escaped character set and it will
452            //    be pushed into `allocated` subsequently, resulting in a valid
453            //    UTF-8 string in `allocated`.
454            unsafe { Cow::Owned(String::from_utf8_unchecked(allocated)) }
455        } else {
456            Cow::Borrowed(self.as_str())
457        }
458    }
459
460    /// Returns the length of `self`.
461    ///
462    /// This length is in bytes, not [`char`]s or graphemes. In other words,
463    /// it may not be what a human considers the length of the string.
464    ///
465    /// # Example
466    ///
467    /// ```rust
468    /// # extern crate rocket;
469    /// use rocket::http::RawStr;
470    ///
471    /// let raw_str = RawStr::new("Hello, world!");
472    /// assert_eq!(raw_str.len(), 13);
473    /// ```
474    #[inline]
475    pub const fn len(&self) -> usize {
476        self.0.len()
477    }
478
479    /// Returns `true` if `self` has a length of zero bytes.
480    ///
481    /// # Example
482    ///
483    /// ```rust
484    /// # extern crate rocket;
485    /// use rocket::http::RawStr;
486    ///
487    /// let raw_str = RawStr::new("Hello, world!");
488    /// assert!(!raw_str.is_empty());
489    ///
490    /// let raw_str = RawStr::new("");
491    /// assert!(raw_str.is_empty());
492    /// ```
493    #[inline]
494    pub const fn is_empty(&self) -> bool {
495        self.len() == 0
496    }
497
498    /// Converts `self` into an `&str`.
499    ///
500    /// This method should be used sparingly. **Only use this method when you
501    /// are absolutely certain that doing so is safe.**
502    ///
503    /// # Example
504    ///
505    /// ```rust
506    /// # extern crate rocket;
507    /// use rocket::http::RawStr;
508    ///
509    /// let raw_str = RawStr::new("Hello, world!");
510    /// assert_eq!(raw_str.as_str(), "Hello, world!");
511    /// ```
512    #[inline(always)]
513    pub const fn as_str(&self) -> &str {
514        &self.0
515    }
516
517    /// Converts `self` into an `&[u8]`.
518    ///
519    /// # Example
520    ///
521    /// ```rust
522    /// # extern crate rocket;
523    /// use rocket::http::RawStr;
524    ///
525    /// let raw_str = RawStr::new("hi");
526    /// assert_eq!(raw_str.as_bytes(), &[0x68, 0x69]);
527    /// ```
528    #[inline(always)]
529    pub const fn as_bytes(&self) -> &[u8] {
530        self.0.as_bytes()
531    }
532
533    /// Converts a string slice to a raw pointer.
534    ///
535    /// As string slices are a slice of bytes, the raw pointer points to a
536    /// [`u8`]. This pointer will be pointing to the first byte of the string
537    /// slice.
538    ///
539    /// The caller must ensure that the returned pointer is never written to.
540    /// If you need to mutate the contents of the string slice, use [`as_mut_ptr`].
541    ///
542    /// [`as_mut_ptr`]: str::as_mut_ptr
543    ///
544    /// # Examples
545    ///
546    /// Basic usage:
547    ///
548    /// ```
549    /// # extern crate rocket;
550    /// use rocket::http::RawStr;
551    ///
552    /// let raw_str = RawStr::new("hi");
553    /// let ptr = raw_str.as_ptr();
554    /// ```
555    pub const fn as_ptr(&self) -> *const u8 {
556        self.as_str().as_ptr()
557    }
558
559    /// Converts `self` into an `&UncasedStr`.
560    ///
561    /// This method should be used sparingly. **Only use this method when you
562    /// are absolutely certain that doing so is safe.**
563    ///
564    /// # Example
565    ///
566    /// ```rust
567    /// # extern crate rocket;
568    /// use rocket::http::RawStr;
569    ///
570    /// let raw_str = RawStr::new("Content-Type");
571    /// assert!(raw_str.as_uncased_str() == "content-TYPE");
572    /// ```
573    #[inline(always)]
574    pub fn as_uncased_str(&self) -> &UncasedStr {
575        self.as_str().into()
576    }
577
578    /// Returns `true` if the given pattern matches a sub-slice of
579    /// this string slice.
580    ///
581    /// Returns `false` if it does not.
582    ///
583    /// The pattern can be a `&str`, [`char`], a slice of [`char`]s, or a
584    /// function or closure that determines if a character matches.
585    ///
586    /// [`char`]: prim@char
587    ///
588    /// # Examples
589    ///
590    /// Basic usage:
591    ///
592    /// ```
593    /// # extern crate rocket;
594    /// use rocket::http::RawStr;
595    ///
596    /// let bananas = RawStr::new("bananas");
597    ///
598    /// assert!(bananas.contains("nana"));
599    /// assert!(!bananas.contains("apples"));
600    /// ```
601    #[inline]
602    pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
603        pat.is_contained_in(self.as_str())
604    }
605
606    /// Returns `true` if the given pattern matches a prefix of this
607    /// string slice.
608    ///
609    /// Returns `false` if it does not.
610    ///
611    /// The pattern can be a `&str`, [`char`], a slice of [`char`]s, or a
612    /// function or closure that determines if a character matches.
613    ///
614    /// [`char`]: prim@char
615    ///
616    /// # Examples
617    ///
618    /// Basic usage:
619    ///
620    /// ```
621    /// # extern crate rocket;
622    /// use rocket::http::RawStr;
623    ///
624    /// let bananas = RawStr::new("bananas");
625    ///
626    /// assert!(bananas.starts_with("bana"));
627    /// assert!(!bananas.starts_with("nana"));
628    /// ```
629    pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
630        pat.is_prefix_of(self.as_str())
631    }
632
633    /// Returns `true` if the given pattern matches a suffix of this
634    /// string slice.
635    ///
636    /// Returns `false` if it does not.
637    ///
638    /// The pattern can be a `&str`, [`char`], a slice of [`char`]s, or a
639    /// function or closure that determines if a character matches.
640    ///
641    /// [`char`]: prim@char
642    ///
643    /// # Examples
644    ///
645    /// Basic usage:
646    ///
647    /// ```
648    /// # extern crate rocket;
649    /// use rocket::http::RawStr;
650    ///
651    /// let bananas = RawStr::new("bananas");
652    ///
653    /// assert!(bananas.ends_with("anas"));
654    /// assert!(!bananas.ends_with("nana"));
655    /// ```
656    pub fn ends_with<'a, P>(&'a self, pat: P) -> bool
657        where P: Pattern<'a>, <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>
658    {
659        pat.is_suffix_of(self.as_str())
660    }
661
662
663    /// Returns the byte index of the first character of this string slice that
664    /// matches the pattern.
665    ///
666    /// Returns [`None`] if the pattern doesn't match.
667    ///
668    /// The pattern can be a `&str`, [`char`], a slice of [`char`]s, or a
669    /// function or closure that determines if a character matches.
670    ///
671    /// [`char`]: prim@char
672    ///
673    /// # Example
674    ///
675    /// ```
676    /// # extern crate rocket;
677    /// use rocket::http::RawStr;
678    ///
679    /// let s = RawStr::new("Löwe 老虎 Léopard Gepardi");
680    ///
681    /// assert_eq!(s.find('L'), Some(0));
682    /// assert_eq!(s.find('é'), Some(14));
683    /// assert_eq!(s.find("pard"), Some(17));
684    /// ```
685    #[inline]
686    pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
687        pat.into_searcher(self.as_str()).next_match().map(|(i, _)| i)
688    }
689
690    /// An iterator over substrings of this string slice, separated by
691    /// characters matched by a pattern.
692    ///
693    /// The pattern can be a `&str`, [`char`], a slice of [`char`]s, or a
694    /// function or closure that determines if a character matches.
695    ///
696    /// [`char`]: prim@char
697    ///
698    /// # Examples
699    ///
700    /// Simple patterns:
701    ///
702    /// ```
703    /// # extern crate rocket;
704    /// use rocket::http::RawStr;
705    ///
706    /// let v: Vec<_> = RawStr::new("Mary had a little lamb")
707    ///     .split(' ')
708    ///     .map(|r| r.as_str())
709    ///     .collect();
710    ///
711    /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
712    /// ```
713    #[inline]
714    pub fn split<'a, P>(&'a self, pat: P) -> impl Iterator<Item = &'a RawStr>
715        where P: Pattern<'a>
716    {
717        let split: Split<'_, P> = Split(SplitInternal {
718            start: 0,
719            end: self.len(),
720            matcher: pat.into_searcher(self.as_str()),
721            allow_trailing_empty: true,
722            finished: false,
723        });
724
725        split.map(|s| s.into())
726    }
727
728    /// Splits `self` into two pieces: the piece _before_ the first byte `b` and
729    /// the piece _after_ (not including `b`). Returns the tuple (`before`,
730    /// `after`). If `b` is not in `self`, or `b` is not an ASCII characters,
731    /// returns the entire string `self` as `before` and the empty string as
732    /// `after`.
733    ///
734    /// # Example
735    ///
736    /// ```rust
737    /// # extern crate rocket;
738    /// use rocket::http::RawStr;
739    ///
740    /// let haystack = RawStr::new("a good boy!");
741    ///
742    /// let (before, after) = haystack.split_at_byte(b'a');
743    /// assert_eq!(before, "");
744    /// assert_eq!(after, " good boy!");
745    ///
746    /// let (before, after) = haystack.split_at_byte(b' ');
747    /// assert_eq!(before, "a");
748    /// assert_eq!(after, "good boy!");
749    ///
750    /// let (before, after) = haystack.split_at_byte(b'o');
751    /// assert_eq!(before, "a g");
752    /// assert_eq!(after, "od boy!");
753    ///
754    /// let (before, after) = haystack.split_at_byte(b'!');
755    /// assert_eq!(before, "a good boy");
756    /// assert_eq!(after, "");
757    ///
758    /// let (before, after) = haystack.split_at_byte(b'?');
759    /// assert_eq!(before, "a good boy!");
760    /// assert_eq!(after, "");
761    ///
762    /// let haystack = RawStr::new("");
763    /// let (before, after) = haystack.split_at_byte(b' ');
764    /// assert_eq!(before, "");
765    /// assert_eq!(after, "");
766    /// ```
767    #[inline]
768    pub fn split_at_byte(&self, b: u8) -> (&RawStr, &RawStr) {
769        if !b.is_ascii() {
770            return (self, &self[0..0]);
771        }
772
773        match memchr::memchr(b, self.as_bytes()) {
774            // SAFETY: `b` is a character boundary since it's ASCII, `i` is in
775            // bounds in `self` (or else None), and i is at most len - 1, so i +
776            // 1 is at most len.
777            Some(i) => unsafe {
778                let s = self.as_str();
779                let start = s.get_unchecked(0..i);
780                let end = s.get_unchecked((i + 1)..self.len());
781                (start.into(), end.into())
782            },
783            None => (self, &self[0..0])
784        }
785    }
786
787    /// Returns a string slice with the prefix removed.
788    ///
789    /// If the string starts with the pattern `prefix`, returns substring after
790    /// the prefix, wrapped in `Some`. This method removes the prefix exactly
791    /// once.
792    ///
793    /// If the string does not start with `prefix`, returns `None`.
794    ///
795    /// The pattern can be a `&str`, `char`, a slice of `char`s, or a function
796    /// or closure that determines if a character matches.
797    ///
798    /// # Examples
799    ///
800    /// ```
801    /// # extern crate rocket;
802    /// use rocket::http::RawStr;
803    ///
804    /// assert_eq!(RawStr::new("foo:bar").strip_prefix("foo:").unwrap(), "bar");
805    /// assert_eq!(RawStr::new("foofoo").strip_prefix("foo").unwrap(), "foo");
806    /// assert!(RawStr::new("foo:bar").strip_prefix("bar").is_none());
807    /// ```
808    #[inline]
809    pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<&'a RawStr> {
810        prefix.strip_prefix_of(self.as_str()).map(RawStr::new)
811    }
812
813    /// Returns a string slice with the suffix removed.
814    ///
815    /// If the string ends with the pattern `suffix`, returns the substring
816    /// before the suffix, wrapped in `Some`.  Unlike `trim_end_matches`, this
817    /// method removes the suffix exactly once.
818    ///
819    /// If the string does not end with `suffix`, returns `None`.
820    ///
821    /// The pattern can be a `&str`, `char`, a slice of `char`s, or a function
822    /// or closure that determines if a character matches.
823    ///
824    /// # Examples
825    ///
826    /// ```
827    /// # extern crate rocket;
828    /// use rocket::http::RawStr;
829    ///
830    /// assert_eq!(RawStr::new("bar:foo").strip_suffix(":foo").unwrap(), "bar");
831    /// assert_eq!(RawStr::new("foofoo").strip_suffix("foo").unwrap(), "foo");
832    /// assert!(RawStr::new("bar:foo").strip_suffix("bar").is_none());
833    /// ```
834    #[inline]
835    pub fn strip_suffix<'a, P>(&'a self, suffix: P) -> Option<&'a RawStr>
836        where P: Pattern<'a>,<P as Pattern<'a>>::Searcher: ReverseSearcher<'a>,
837    {
838        suffix.strip_suffix_of(self.as_str()).map(RawStr::new)
839    }
840
841    /// Parses this string slice into another type.
842    ///
843    /// Because `parse` is so general, it can cause problems with type
844    /// inference. As such, `parse` is one of the few times you'll see
845    /// the syntax affectionately known as the 'turbofish': `::<>`. This
846    /// helps the inference algorithm understand specifically which type
847    /// you're trying to parse into.
848    ///
849    /// # Errors
850    ///
851    /// Will return `Err` if it's not possible to parse this string slice into
852    /// the desired type.
853    ///
854    /// # Examples
855    ///
856    /// Basic usage
857    ///
858    /// ```
859    /// # extern crate rocket;
860    /// use rocket::http::RawStr;
861    ///
862    /// let four: u32 = RawStr::new("4").parse().unwrap();
863    ///
864    /// assert_eq!(4, four);
865    /// ```
866    #[inline]
867    pub fn parse<F: std::str::FromStr>(&self) -> Result<F, F::Err> {
868        std::str::FromStr::from_str(self.as_str())
869    }
870}
871
872#[cfg(feature = "serde")]
873mod serde {
874    use serde_::{ser, de, Serialize, Deserialize};
875
876    use super::*;
877
878    impl Serialize for RawStr {
879        fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
880            where S: ser::Serializer
881        {
882            self.as_str().serialize(ser)
883        }
884    }
885
886    impl<'de: 'a, 'a> Deserialize<'de> for &'a RawStr {
887        fn deserialize<D>(de: D) -> Result<Self, D::Error>
888            where D: de::Deserializer<'de>
889        {
890            <&'a str as Deserialize<'de>>::deserialize(de).map(RawStr::new)
891        }
892    }
893
894}
895
896impl fmt::Debug for RawStr {
897    #[inline(always)]
898    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
899        self.0.fmt(f)
900    }
901}
902
903impl<'a> From<&'a str> for &'a RawStr {
904    #[inline(always)]
905    fn from(string: &'a str) -> &'a RawStr {
906        RawStr::new(string)
907    }
908}
909
910impl<'a> From<&'a RawStr> for Cow<'a, RawStr> {
911    fn from(raw: &'a RawStr) -> Self {
912        Cow::Borrowed(raw)
913    }
914}
915
916impl From<RawStrBuf> for Cow<'_, RawStr> {
917    fn from(raw: RawStrBuf) -> Self {
918        Cow::Owned(raw)
919    }
920}
921
922macro_rules! impl_partial {
923    ($A:ty : $B:ty as $T:ty) => (
924        impl PartialEq<$A> for $B {
925            #[inline(always)]
926            fn eq(&self, other: &$A) -> bool {
927                let left: $T = self.as_ref();
928                let right: $T = other.as_ref();
929                left == right
930            }
931        }
932
933        impl PartialOrd<$A> for $B {
934            #[inline(always)]
935            fn partial_cmp(&self, other: &$A) -> Option<Ordering> {
936                let left: $T = self.as_ref();
937                let right: $T = other.as_ref();
938                left.partial_cmp(right)
939            }
940        }
941    );
942    ($A:ty : $B:ty) => (impl_partial!($A : $B as &str);)
943}
944
945impl_partial!(RawStr : &RawStr);
946impl_partial!(&RawStr : RawStr);
947
948impl_partial!(str : RawStr);
949impl_partial!(str : &RawStr);
950impl_partial!(&str : RawStr);
951impl_partial!(&&str : RawStr);
952
953impl_partial!(Cow<'_, str> : RawStr);
954impl_partial!(Cow<'_, str> : &RawStr);
955impl_partial!(RawStr : Cow<'_, str>);
956impl_partial!(&RawStr : Cow<'_, str>);
957
958impl_partial!(Cow<'_, RawStr> : RawStr as &RawStr);
959impl_partial!(Cow<'_, RawStr> : &RawStr as &RawStr);
960impl_partial!(RawStr : Cow<'_, RawStr> as &RawStr);
961impl_partial!(&RawStr : Cow<'_, RawStr> as &RawStr);
962
963impl_partial!(String : RawStr);
964impl_partial!(String : &RawStr);
965
966impl_partial!(RawStr : String);
967impl_partial!(&RawStr : String);
968
969impl_partial!(RawStr : str);
970impl_partial!(RawStr : &str);
971impl_partial!(RawStr : &&str);
972impl_partial!(&RawStr : str);
973
974impl AsRef<str> for RawStr {
975    #[inline(always)]
976    fn as_ref(&self) -> &str {
977        self.as_str()
978    }
979}
980
981impl AsRef<RawStr> for str {
982    #[inline(always)]
983    fn as_ref(&self) -> &RawStr {
984        RawStr::new(self)
985    }
986}
987
988impl AsRef<RawStr> for RawStr {
989    #[inline(always)]
990    fn as_ref(&self) -> &RawStr {
991        self
992    }
993}
994
995impl AsRef<[u8]> for RawStr {
996    #[inline(always)]
997    fn as_ref(&self) -> &[u8] {
998        self.as_bytes()
999    }
1000}
1001
1002impl<I: core::slice::SliceIndex<str, Output=str>> core::ops::Index<I> for RawStr {
1003    type Output = RawStr;
1004
1005    #[inline]
1006    fn index(&self, index: I) -> &Self::Output {
1007        self.as_str()[index].into()
1008    }
1009}
1010
1011impl std::borrow::Borrow<str> for RawStr {
1012    #[inline(always)]
1013    fn borrow(&self) -> &str {
1014        self.as_str()
1015    }
1016}
1017
1018impl std::borrow::Borrow<RawStr> for &str {
1019    #[inline(always)]
1020    fn borrow(&self) -> &RawStr {
1021        (*self).into()
1022    }
1023}
1024
1025impl fmt::Display for RawStr {
1026    #[inline(always)]
1027    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1028        self.0.fmt(f)
1029    }
1030}
1031
1032impl AsRef<RawStr> for RawStrBuf {
1033    #[inline(always)]
1034    fn as_ref(&self) -> &RawStr {
1035        RawStr::new(self.0.as_str())
1036    }
1037}
1038
1039impl Borrow<RawStr> for RawStrBuf {
1040    #[inline(always)]
1041    fn borrow(&self) -> &RawStr {
1042        self.as_ref()
1043    }
1044}
1045
1046impl std::ops::Deref for RawStrBuf {
1047    type Target = RawStr;
1048
1049    #[inline(always)]
1050    fn deref(&self) -> &Self::Target {
1051        self.as_ref()
1052    }
1053}
1054
1055impl fmt::Display for RawStrBuf {
1056    #[inline(always)]
1057    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1058        self.0.fmt(f)
1059    }
1060}
1061
1062impl fmt::Debug for RawStrBuf {
1063    #[inline(always)]
1064    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1065        self.0.fmt(f)
1066    }
1067}
1068
1069impl From<String> for RawStrBuf {
1070    #[inline(always)]
1071    fn from(string: String) -> Self {
1072        RawStrBuf(string)
1073    }
1074}
1075
1076impl From<&str> for RawStrBuf {
1077    #[inline(always)]
1078    fn from(string: &str) -> Self {
1079        string.to_string().into()
1080    }
1081}
1082
1083impl From<&RawStr> for RawStrBuf {
1084    #[inline(always)]
1085    fn from(raw: &RawStr) -> Self {
1086        raw.to_string().into()
1087    }
1088}
1089
1090#[cfg(test)]
1091mod tests {
1092    use super::RawStr;
1093
1094    #[test]
1095    fn can_compare() {
1096        let raw_str = RawStr::new("abc");
1097        assert_eq!(raw_str, "abc");
1098        assert_eq!("abc", raw_str.as_str());
1099        assert_eq!(raw_str, RawStr::new("abc"));
1100        assert_eq!(raw_str, "abc".to_string());
1101        assert_eq!("abc".to_string(), raw_str.as_str());
1102    }
1103}