serde_querystring/parsers/
urlencoded.rs

1use std::{borrow::Cow, collections::BTreeMap};
2
3use crate::decode::{parse_bytes, Reference};
4
5struct Key<'a>(&'a [u8]);
6
7impl<'a> Key<'a> {
8    fn parse(slice: &'a [u8]) -> Self {
9        let mut index = 0;
10        while index < slice.len() {
11            match slice[index] {
12                b'&' | b'=' => break,
13                _ => index += 1,
14            }
15        }
16
17        Self(&slice[..index])
18    }
19
20    fn len(&self) -> usize {
21        self.0.len()
22    }
23
24    fn decode<'s>(&self, scratch: &'s mut Vec<u8>) -> Reference<'a, 's, [u8]> {
25        parse_bytes(self.0, scratch)
26    }
27}
28
29struct Value<'a>(&'a [u8]);
30
31impl<'a> Value<'a> {
32    fn parse(slice: &'a [u8]) -> Option<Self> {
33        if *slice.first()? == b'&' {
34            return None;
35        }
36
37        let mut index = 1;
38        while index < slice.len() {
39            match slice[index] {
40                b'&' => break,
41                _ => index += 1,
42            }
43        }
44
45        Some(Self(&slice[1..index]))
46    }
47
48    fn len(&self) -> usize {
49        self.0.len()
50    }
51
52    fn decode_to<'s>(&self, scratch: &'s mut Vec<u8>) -> Reference<'a, 's, [u8]> {
53        parse_bytes(self.0, scratch)
54    }
55}
56
57struct Pair<'a>(Key<'a>, Option<Value<'a>>);
58
59impl<'a> Pair<'a> {
60    fn parse(slice: &'a [u8]) -> Self {
61        let key = Key::parse(slice);
62        let value = Value::parse(&slice[key.len()..]);
63
64        Self(key, value)
65    }
66
67    /// It report how many chars we should move forward after this pair, to see a new one.
68    /// It might report invalid result at the end of the slice,
69    /// so calling site should check the validity of resulting index
70    fn skip_len(&self) -> usize {
71        match &self.1 {
72            // plus 2 for when there was a value, so 2 for b'=' and b'&'
73            Some(v) => self.0.len() + v.len() + 2,
74            // plus 1 for when there was no value so 1 for b'&'
75            None => self.0.len() + 1,
76        }
77    }
78}
79
80/// The simplest parser for querystring
81/// It parses the whole querystring, and overwrites each repeated key's value.
82/// it does not support vectors, maps nor tuples, but provides the best performance.
83///
84/// # Note
85/// Keys are decoded when calling the `parse` method, but values are lazily decoded when you
86/// call the `value` method for their keys.
87///
88/// # Example
89/// ```rust
90///# use std::borrow::Cow;
91/// use serde_querystring::UrlEncodedQS;
92///
93/// let slice = b"key=value";
94///
95/// let parser = UrlEncodedQS::parse(slice);
96///
97/// assert_eq!(parser.keys(), vec![&Cow::Borrowed(b"key")]);
98/// assert_eq!(
99///     parser.value(b"key"),
100///     Some(Some(Cow::Borrowed("value".as_bytes())))
101/// );
102/// ```
103pub struct UrlEncodedQS<'a> {
104    pairs: BTreeMap<Cow<'a, [u8]>, Pair<'a>>,
105}
106
107impl<'a> UrlEncodedQS<'a> {
108    /// Parse a slice of bytes into a `UrlEncodedQS`
109    pub fn parse(slice: &'a [u8]) -> Self {
110        let mut pairs = BTreeMap::new();
111        let mut scratch = Vec::new();
112
113        let mut index = 0;
114
115        while index < slice.len() {
116            let pair = Pair::parse(&slice[index..]);
117            index += pair.skip_len();
118
119            let decoded_key = pair.0.decode(&mut scratch);
120
121            if let Some(old_pair) = pairs.get_mut(decoded_key.as_ref()) {
122                *old_pair = pair;
123            } else {
124                pairs.insert(decoded_key.into_cow(), pair);
125            }
126        }
127
128        Self { pairs }
129    }
130
131    /// Returns a vector containing all the keys in querystring.
132    pub fn keys(&self) -> Vec<&Cow<'a, [u8]>> {
133        self.pairs.keys().collect()
134    }
135
136    /// Returns the last value assigned to a key.
137    ///
138    /// It returns `None` if the **key doesn't exist** in the querystring,
139    /// and returns `Some(None)` if the last assignment to a **key doesn't have a value**, ex `"&key&"`
140    ///
141    /// # Note
142    /// Percent decoding the value is done on-the-fly **every time** this function is called.
143    pub fn value(&self, key: &'a [u8]) -> Option<Option<Cow<'a, [u8]>>> {
144        let mut scratch = Vec::new();
145        self.pairs
146            .get(key)
147            .map(|p| p.1.as_ref().map(|v| v.decode_to(&mut scratch).into_cow()))
148    }
149}
150
151#[cfg(feature = "serde")]
152mod de {
153    use _serde::Deserialize;
154
155    use crate::de::{
156        Error, QSDeserializer,
157        __implementors::{DecodedSlice, RawSlice},
158    };
159
160    use super::UrlEncodedQS;
161
162    impl<'a> UrlEncodedQS<'a> {
163        /// Deserialize the parsed slice into T
164        pub fn deserialize<T: Deserialize<'a>>(self) -> Result<T, Error> {
165            T::deserialize(QSDeserializer::new(self.into_iter()))
166        }
167
168        pub(crate) fn into_iter(
169            self,
170        ) -> impl Iterator<Item = (DecodedSlice<'a>, Option<RawSlice<'a>>)> {
171            self.pairs
172                .into_iter()
173                .map(|(key, pair)| (DecodedSlice(key), pair.1.map(|v| RawSlice(v.0))))
174        }
175    }
176}
177
178#[cfg(test)]
179mod tests {
180    use std::borrow::Cow;
181
182    use super::UrlEncodedQS;
183
184    #[test]
185    fn parse_pair() {
186        let slice = b"key=value";
187
188        let parser = UrlEncodedQS::parse(slice);
189
190        assert_eq!(parser.keys(), vec![&Cow::Borrowed(b"key")]);
191        assert_eq!(
192            parser.value(b"key"),
193            Some(Some(Cow::Borrowed("value".as_bytes())))
194        );
195    }
196
197    #[test]
198    fn parse_multiple_pairs() {
199        let slice = b"foo=bar&foobar=baz&qux=box";
200
201        let parser = UrlEncodedQS::parse(slice);
202
203        assert_eq!(parser.value(b"foo"), Some(Some("bar".as_bytes().into())));
204        assert_eq!(parser.value(b"foobar"), Some(Some("baz".as_bytes().into())));
205        assert_eq!(parser.value(b"qux"), Some(Some("box".as_bytes().into())));
206    }
207
208    #[test]
209    fn parse_no_value() {
210        let slice = b"foo&foobar=&foo2";
211
212        let parser = UrlEncodedQS::parse(slice);
213
214        assert_eq!(parser.value(b"foo3"), None);
215        assert_eq!(parser.value(b"foo2"), Some(None));
216        assert_eq!(parser.value(b"foo"), Some(None));
217        assert_eq!(parser.value(b"foobar"), Some(Some("".as_bytes().into())));
218    }
219
220    #[test]
221    fn parse_multiple_values() {
222        let slice = b"foo=bar&foo=baz&foo=foobar&foo&foo=";
223
224        let parser = UrlEncodedQS::parse(slice);
225
226        assert_eq!(parser.value(b"foo"), Some(Some("".as_bytes().into())));
227    }
228}