Skip to main content

form_net/urlencoded/
raw.rs

1//! The allocation-free urlencoded scanner.
2
3use core::fmt;
4
5use crate::error::{FormError, Limit, Location};
6use crate::limits::{Limits, PercentPolicy};
7use crate::urlencoded::decode::decode_component;
8
9const HAS_EQUALS: u8 = 1;
10const NAME_DECODE: u8 = 2;
11const VALUE_DECODE: u8 = 4;
12
13/// Iterates the pairs of a urlencoded body without allocating or copying.
14///
15/// Budgets are checked per sequence before the sequence is handed out: body
16/// size (every byte, empty sequences included), field count, raw name and
17/// value lengths, and the running total of raw value lengths. After the
18/// first error the iterator returns `None`.
19///
20/// # Examples
21///
22/// ```
23/// use form_net::Limits;
24///
25/// let pairs: Vec<_> = form_net::raw_pairs(b"a=1&&b", &Limits::DEFAULT)
26///     .map(|p| p.map(|p| (p.name_raw(), p.value_raw(), p.has_equals())))
27///     .collect::<Result<_, _>>()?;
28/// assert_eq!(pairs, [(&b"a"[..], &b"1"[..], true), (&b"b"[..], &b""[..], false)]);
29/// # Ok::<(), form_net::FormError>(())
30/// ```
31#[must_use]
32pub fn raw_pairs<'a>(input: &'a [u8], limits: &Limits) -> RawPairs<'a> {
33    RawPairs {
34        input,
35        pos: 0,
36        fields: 0,
37        text: 0,
38        limits: *limits,
39        done: false,
40        checked_body: false,
41    }
42}
43
44/// The iterator returned by [`raw_pairs`].
45#[derive(Clone)]
46pub struct RawPairs<'a> {
47    input: &'a [u8],
48    pos: usize,
49    fields: u32,
50    text: u64,
51    limits: Limits,
52    done: bool,
53    checked_body: bool,
54}
55
56impl fmt::Debug for RawPairs<'_> {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        f.debug_struct("RawPairs")
59            .field("position", &self.pos)
60            .field("fields", &self.fields)
61            .finish_non_exhaustive()
62    }
63}
64
65impl<'a> RawPairs<'a> {
66    fn fail(&mut self, err: FormError) -> Option<Result<RawPair<'a>, FormError>> {
67        self.done = true;
68        Some(Err(err))
69    }
70}
71
72impl<'a> Iterator for RawPairs<'a> {
73    type Item = Result<RawPair<'a>, FormError>;
74
75    fn next(&mut self) -> Option<Self::Item> {
76        if self.done {
77            return None;
78        }
79        if !self.checked_body {
80            self.checked_body = true;
81            if self.input.len() > self.limits.body_usize() {
82                return self.fail(FormError::limit(
83                    Limit::Body,
84                    Location::at(self.limits.body()),
85                ));
86            }
87        }
88        loop {
89            if self.pos >= self.input.len() {
90                self.done = true;
91                return None;
92            }
93            let start = self.pos;
94            let mut flags = 0u8;
95            let mut eq = None;
96            let mut i = start;
97            let end = loop {
98                i = crate::scan::find_any(self.input, i, *b"&=%+");
99                match self.input.get(i) {
100                    None | Some(b'&') => break i,
101                    Some(b'=') if eq.is_none() => {
102                        eq = Some(i);
103                        flags |= HAS_EQUALS;
104                    }
105                    Some(b'%' | b'+') => {
106                        flags |= if eq.is_some() {
107                            VALUE_DECODE
108                        } else {
109                            NAME_DECODE
110                        };
111                    }
112                    Some(_) => {}
113                }
114                i = i.wrapping_add(1);
115            };
116            self.pos = end.saturating_add(1).min(self.input.len());
117            if end == start {
118                continue;
119            }
120            let seq = self.input.get(start..end).unwrap_or(&[]);
121            let (name, value) = match eq {
122                Some(e) => {
123                    let at = e.wrapping_sub(start);
124                    (
125                        seq.get(..at).unwrap_or(&[]),
126                        seq.get(at.wrapping_add(1)..).unwrap_or(&[]),
127                    )
128                }
129                None => (seq, &[][..]),
130            };
131            let offset = start as u64;
132            let at = Location::at(offset);
133            self.fields = self.fields.saturating_add(1);
134            if self.fields > self.limits.max_fields {
135                return self.fail(FormError::limit(Limit::Fields, at));
136            }
137            if name.len() as u64 > u64::from(self.limits.name()) {
138                return self.fail(FormError::limit(Limit::NameLength, at));
139            }
140            let value_at = Location::at(offset.saturating_add(name.len() as u64).saturating_add(1));
141            if value.len() as u64 > u64::from(self.limits.value()) {
142                return self.fail(FormError::limit(Limit::ValueLength, value_at));
143            }
144            self.text = self.text.saturating_add(value.len() as u64);
145            if self.text > self.limits.text() {
146                return self.fail(FormError::limit(Limit::TextTotal, value_at));
147            }
148            return Some(Ok(RawPair {
149                name,
150                value,
151                flags,
152                offset,
153            }));
154        }
155    }
156}
157
158impl core::iter::FusedIterator for RawPairs<'_> {}
159
160/// One `name=value` sequence, undecoded.
161///
162/// `Debug` prints the offset and the lengths only: values can be secrets.
163#[derive(Clone, Copy)]
164pub struct RawPair<'a> {
165    name: &'a [u8],
166    value: &'a [u8],
167    flags: u8,
168    offset: u64,
169}
170
171impl fmt::Debug for RawPair<'_> {
172    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173        f.debug_struct("RawPair")
174            .field("offset", &self.offset)
175            .field("name_len", &self.name.len())
176            .field("value_len", &self.value.len())
177            .finish()
178    }
179}
180
181impl<'a> RawPair<'a> {
182    /// The name as sent, before decoding.
183    ///
184    /// # Examples
185    ///
186    /// ```
187    /// let p = form_net::raw_pairs(b"a+b=1", &form_net::Limits::DEFAULT).next().unwrap()?;
188    /// assert_eq!(p.name_raw(), b"a+b");
189    /// # Ok::<(), form_net::FormError>(())
190    /// ```
191    #[must_use]
192    pub const fn name_raw(&self) -> &'a [u8] {
193        self.name
194    }
195
196    /// The value as sent, before decoding.
197    ///
198    /// # Examples
199    ///
200    /// ```
201    /// let p = form_net::raw_pairs(b"a=%41", &form_net::Limits::DEFAULT).next().unwrap()?;
202    /// assert_eq!(p.value_raw(), b"%41");
203    /// # Ok::<(), form_net::FormError>(())
204    /// ```
205    #[must_use]
206    pub const fn value_raw(&self) -> &'a [u8] {
207        self.value
208    }
209
210    /// Whether the sequence contained `=`: `a` and `a=` both have an empty
211    /// value, but only `a=` has an equals sign.
212    ///
213    /// # Examples
214    ///
215    /// ```
216    /// use form_net::Limits;
217    ///
218    /// let mut it = form_net::raw_pairs(b"a&b=", &Limits::DEFAULT);
219    /// assert!(!it.next().unwrap()?.has_equals());
220    /// assert!(it.next().unwrap()?.has_equals());
221    /// # Ok::<(), form_net::FormError>(())
222    /// ```
223    #[must_use]
224    pub const fn has_equals(&self) -> bool {
225        self.flags & HAS_EQUALS != 0
226    }
227
228    /// Whether the name contains `%` or `+`.
229    ///
230    /// # Examples
231    ///
232    /// ```
233    /// let p = form_net::raw_pairs(b"a+b=1", &form_net::Limits::DEFAULT).next().unwrap()?;
234    /// assert!(p.name_needs_decoding() && !p.value_needs_decoding());
235    /// # Ok::<(), form_net::FormError>(())
236    /// ```
237    #[must_use]
238    pub const fn name_needs_decoding(&self) -> bool {
239        self.flags & NAME_DECODE != 0
240    }
241
242    /// Whether the value contains `%` or `+`.
243    ///
244    /// # Examples
245    ///
246    /// ```
247    /// let p = form_net::raw_pairs(b"a=1%20", &form_net::Limits::DEFAULT).next().unwrap()?;
248    /// assert!(p.value_needs_decoding());
249    /// # Ok::<(), form_net::FormError>(())
250    /// ```
251    #[must_use]
252    pub const fn value_needs_decoding(&self) -> bool {
253        self.flags & VALUE_DECODE != 0
254    }
255
256    /// The name with no copy, when it needs no decoding and is valid UTF-8.
257    ///
258    /// # Examples
259    ///
260    /// ```
261    /// let p = form_net::raw_pairs(b"email=x", &form_net::Limits::DEFAULT).next().unwrap()?;
262    /// assert_eq!(p.name_str(), Some("email"));
263    /// # Ok::<(), form_net::FormError>(())
264    /// ```
265    #[must_use]
266    pub fn name_str(&self) -> Option<&'a str> {
267        if self.name_needs_decoding() {
268            None
269        } else {
270            core::str::from_utf8(self.name).ok()
271        }
272    }
273
274    /// The value with no copy, when it needs no decoding and is valid UTF-8.
275    ///
276    /// # Examples
277    ///
278    /// ```
279    /// let p = form_net::raw_pairs(b"q=a+b", &form_net::Limits::DEFAULT).next().unwrap()?;
280    /// assert_eq!(p.value_str(), None);
281    /// # Ok::<(), form_net::FormError>(())
282    /// ```
283    #[must_use]
284    pub fn value_str(&self) -> Option<&'a str> {
285        if self.value_needs_decoding() {
286            None
287        } else {
288            core::str::from_utf8(self.value).ok()
289        }
290    }
291
292    /// Decodes the name into `out` (see [`decode_into`](crate::decode_into)).
293    ///
294    /// # Errors
295    ///
296    /// `Encoding { InvalidPercent | InvalidUtf8 }` located in the body;
297    /// `BufferTooSmall` when `out` is shorter than the raw name.
298    ///
299    /// # Examples
300    ///
301    /// ```
302    /// use form_net::PercentPolicy;
303    ///
304    /// let p = form_net::raw_pairs(b"a%20b=1", &form_net::Limits::DEFAULT).next().unwrap()?;
305    /// let mut out = [0u8; 16];
306    /// assert_eq!(p.decode_name(&mut out, PercentPolicy::Refuse)?, "a b");
307    /// # Ok::<(), form_net::FormError>(())
308    /// ```
309    pub fn decode_name<'b>(
310        &self,
311        out: &'b mut [u8],
312        policy: PercentPolicy,
313    ) -> Result<&'b str, FormError> {
314        decode_component(self.name, out, policy).map_err(|e| e.shifted(self.offset))
315    }
316
317    /// Decodes the value into `out` (see [`decode_into`](crate::decode_into)).
318    ///
319    /// # Errors
320    ///
321    /// As [`decode_name`](Self::decode_name).
322    ///
323    /// # Examples
324    ///
325    /// ```
326    /// use form_net::PercentPolicy;
327    ///
328    /// let p = form_net::raw_pairs(b"q=rust+forms", &form_net::Limits::DEFAULT).next().unwrap()?;
329    /// let mut out = [0u8; 16];
330    /// assert_eq!(p.decode_value(&mut out, PercentPolicy::Refuse)?, "rust forms");
331    /// # Ok::<(), form_net::FormError>(())
332    /// ```
333    pub fn decode_value<'b>(
334        &self,
335        out: &'b mut [u8],
336        policy: PercentPolicy,
337    ) -> Result<&'b str, FormError> {
338        let at = self
339            .offset
340            .saturating_add(self.name.len() as u64)
341            .saturating_add(1);
342        decode_component(self.value, out, policy).map_err(|e| e.shifted(at))
343    }
344
345    /// The byte offset of the sequence in the body.
346    ///
347    /// # Examples
348    ///
349    /// ```
350    /// let mut it = form_net::raw_pairs(b"a=1&bb=2", &form_net::Limits::DEFAULT);
351    /// let _ = it.next();
352    /// assert_eq!(it.next().unwrap()?.offset(), 4);
353    /// # Ok::<(), form_net::FormError>(())
354    /// ```
355    #[must_use]
356    pub const fn offset(&self) -> u64 {
357        self.offset
358    }
359}
360
361#[cfg(test)]
362mod tests {
363    use super::*;
364    use alloc::vec::Vec;
365
366    type Pairs<'a> = Vec<(&'a [u8], &'a [u8])>;
367
368    fn pairs(input: &[u8]) -> Result<Pairs<'_>, FormError> {
369        raw_pairs(input, &Limits::DEFAULT)
370            .map(|p| p.map(|p| (p.name_raw(), p.value_raw())))
371            .collect()
372    }
373
374    #[test]
375    fn test_raw_pairs_whatwg_splitting() {
376        assert_eq!(pairs(b"").unwrap(), []);
377        assert_eq!(pairs(b"&&&").unwrap(), []);
378        assert_eq!(pairs(b"=").unwrap(), [(&b""[..], &b""[..])]);
379        assert_eq!(pairs(b"a==b").unwrap(), [(&b"a"[..], &b"=b"[..])]);
380        assert_eq!(pairs(b"=a").unwrap(), [(&b""[..], &b"a"[..])]);
381        assert_eq!(pairs(b"a;b=c").unwrap(), [(&b"a;b"[..], &b"c"[..])]);
382        assert_eq!(
383            pairs(b"a=1&b=2&").unwrap(),
384            [(&b"a"[..], &b"1"[..]), (&b"b"[..], &b"2"[..])]
385        );
386    }
387
388    #[test]
389    fn test_raw_pairs_flags_per_side() {
390        let p = raw_pairs(b"a%=b", &Limits::DEFAULT)
391            .next()
392            .unwrap()
393            .unwrap();
394        assert!(p.name_needs_decoding() && !p.value_needs_decoding());
395        let p = raw_pairs(b"a=b+%", &Limits::DEFAULT)
396            .next()
397            .unwrap()
398            .unwrap();
399        assert!(!p.name_needs_decoding() && p.value_needs_decoding());
400        let p = raw_pairs(b"a=b=+", &Limits::DEFAULT)
401            .next()
402            .unwrap()
403            .unwrap();
404        assert!(p.value_needs_decoding() && p.has_equals());
405    }
406
407    #[test]
408    fn test_raw_pairs_field_limit_n_and_n_plus_one() {
409        let l = Limits::DEFAULT.with_max_fields(2);
410        assert_eq!(raw_pairs(b"a&b", &l).count(), 2);
411        let r: Result<Vec<_>, _> = raw_pairs(b"a&b&c", &l).collect();
412        assert!(matches!(
413            r,
414            Err(FormError::Limit {
415                limit: Limit::Fields,
416                at
417            }) if at.offset == 4
418        ));
419    }
420
421    #[test]
422    fn test_raw_pairs_length_limits_at_the_edge() {
423        let l = Limits::DEFAULT
424            .with_max_name_bytes(3)
425            .with_max_value_bytes(3);
426        assert!(raw_pairs(b"abc=def", &l).all(|p| p.is_ok()));
427        let e = raw_pairs(b"abcd=1", &l).next().unwrap().unwrap_err();
428        assert!(matches!(
429            e,
430            FormError::Limit {
431                limit: Limit::NameLength,
432                ..
433            }
434        ));
435        let e = raw_pairs(b"a=defg", &l).next().unwrap().unwrap_err();
436        assert!(matches!(e, FormError::Limit { limit: Limit::ValueLength, at } if at.offset == 2));
437        let l = Limits::DEFAULT.with_max_text_bytes(4);
438        let r: Result<Vec<_>, _> = raw_pairs(b"a=12&b=345", &l).collect();
439        assert!(matches!(
440            r,
441            Err(FormError::Limit {
442                limit: Limit::TextTotal,
443                ..
444            })
445        ));
446    }
447
448    #[test]
449    fn test_raw_pairs_body_limit_counts_empty_sequences() {
450        let l = Limits::DEFAULT.with_max_body_bytes(4);
451        assert_eq!(raw_pairs(b"&&&&", &l).count(), 0);
452        let e = raw_pairs(b"&&&&&", &l).next().unwrap().unwrap_err();
453        assert!(matches!(
454            e,
455            FormError::Limit {
456                limit: Limit::Body,
457                ..
458            }
459        ));
460    }
461
462    #[test]
463    fn test_raw_pairs_stops_after_error() {
464        let l = Limits::DEFAULT.with_max_fields(0);
465        let mut it = raw_pairs(b"a&b", &l);
466        assert!(it.next().unwrap().is_err());
467        assert!(it.next().is_none());
468    }
469
470    #[test]
471    fn test_raw_pair_debug_hides_values() {
472        let p = raw_pairs(b"password=hunter2", &Limits::DEFAULT)
473            .next()
474            .unwrap()
475            .unwrap();
476        let s = alloc::format!("{p:?}");
477        assert!(!s.contains("hunter2") && !s.contains("password"));
478    }
479}