Skip to main content

form_net/urlencoded/
stream.rs

1//! The streaming urlencoded parser: chunks in, pairs out, identical for
2//! every split of the body.
3
4use core::fmt;
5
6use crate::error::{FormError, Limit, Location};
7use crate::limits::Limits;
8use crate::urlencoded::raw::{Budget, RawPair};
9
10/// A streaming urlencoded parser over a caller scratch buffer.
11///
12/// A sequence that ends inside the current chunk is returned borrowed from
13/// the input; one that straddles chunks is assembled in the scratch buffer
14/// ([`Limits::urlencoded_buffer_len`] bytes) and returned borrowed from it.
15/// A sequence too long for its budgets is refused as soon as its first
16/// bytes prove it, before it is copied, so the scratch never overflows.
17/// Pairs and errors are the same for every split of the same body.
18///
19/// # Examples
20///
21/// ```
22/// use form_net::{Limits, UrlencodedEvent, UrlencodedParser};
23///
24/// // A small route: the scratch fits on the stack.
25/// const LIMITS: Limits = Limits::DEFAULT.with_max_name_bytes(32).with_max_value_bytes(256);
26/// let mut scratch = [0u8; LIMITS.urlencoded_buffer_len()];
27/// let mut parser = UrlencodedParser::with_buffer(&LIMITS, &mut scratch[..])?;
28/// let mut names = Vec::new();
29/// for (chunk, last) in [(&b"na"[..], false), (b"me=Al&ci", false), (b"ty=Paris", true)] {
30///     let mut rest = chunk;
31///     loop {
32///         let step = parser.parse(rest, last)?;
33///         rest = &rest[step.consumed..];
34///         match step.event {
35///             UrlencodedEvent::Pair(p) => names.push(p.name_raw().to_vec()),
36///             _ => break,
37///         }
38///     }
39/// }
40/// assert_eq!(names, [b"name".to_vec(), b"city".to_vec()]);
41/// # Ok::<(), form_net::FormError>(())
42/// ```
43pub struct UrlencodedParser<B: AsMut<[u8]> + AsRef<[u8]>> {
44    scratch: B,
45    /// Bytes of the current, unfinished sequence held in `scratch`.
46    held: usize,
47    /// Body offset of the held sequence.
48    held_at: u64,
49    /// The last call handed out a pair borrowed from `scratch`.
50    release: bool,
51    /// Body bytes consumed so far.
52    seen: u64,
53    /// The most of `scratch` ever held: only that is wiped (D-103).
54    dirty: usize,
55    budget: Budget,
56    poisoned: bool,
57    ended: bool,
58}
59
60impl<B: AsMut<[u8]> + AsRef<[u8]>> fmt::Debug for UrlencodedParser<B> {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        f.debug_struct("UrlencodedParser")
63            .field("bytes_seen", &self.seen)
64            .field("held", &self.held)
65            .field("ended", &self.ended)
66            .finish_non_exhaustive()
67    }
68}
69
70/// One step of [`UrlencodedParser::parse`]: how much input was consumed and
71/// what it completed.
72///
73/// # Examples
74///
75/// ```
76/// use form_net::{Limits, UrlencodedEvent, UrlencodedParser};
77///
78/// let mut scratch = vec![0u8; Limits::DEFAULT.urlencoded_buffer_len()];
79/// let mut parser = UrlencodedParser::with_buffer(&Limits::DEFAULT, &mut scratch[..])?;
80/// let step = parser.parse(b"a=1&b=2", true)?;
81/// assert_eq!(step.consumed, 4);
82/// assert!(matches!(step.event, UrlencodedEvent::Pair(p) if p.value_raw() == b"1"));
83/// # Ok::<(), form_net::FormError>(())
84/// ```
85#[non_exhaustive]
86#[derive(Debug)]
87pub struct UrlencodedStep<'p> {
88    /// Bytes of the input consumed (or held in the scratch buffer).
89    pub consumed: usize,
90    /// What the consumed bytes completed.
91    pub event: UrlencodedEvent<'p>,
92}
93
94/// What a step of the streaming parser completed.
95///
96/// # Examples
97///
98/// ```
99/// use form_net::{Limits, UrlencodedEvent, UrlencodedParser};
100///
101/// # let mut parser = UrlencodedParser::with_buffer(&Limits::DEFAULT, vec![0u8; Limits::DEFAULT.urlencoded_buffer_len()])?;
102/// // The pair may go on in the next chunk, so it is held.
103/// assert!(matches!(parser.parse(b"a=1", false)?.event, UrlencodedEvent::NeedInput));
104/// let step = parser.parse(b"", true)?;
105/// assert!(matches!(step.event, UrlencodedEvent::Pair(p) if p.name_raw() == b"a"));
106/// assert!(matches!(parser.parse(b"", true)?.event, UrlencodedEvent::End));
107/// # Ok::<(), form_net::FormError>(())
108/// ```
109#[non_exhaustive]
110#[derive(Clone, Copy, Debug)]
111pub enum UrlencodedEvent<'p> {
112    /// One non-empty `name=value` sequence, undecoded.
113    Pair(RawPair<'p>),
114    /// Every byte of the input was consumed or held; pass the next chunk.
115    NeedInput,
116    /// The body is complete (only after `eof = true`).
117    End,
118}
119
120/// Where the pair of a step lives, decided before any borrow is taken.
121enum Found {
122    Input { start: usize, end: usize, at: u64 },
123    Scratch { len: usize, at: u64 },
124    NeedInput,
125    End,
126}
127
128impl<B: AsMut<[u8]> + AsRef<[u8]>> UrlencodedParser<B> {
129    /// A parser over `scratch`, which must hold at least
130    /// [`Limits::urlencoded_buffer_len`] bytes.
131    ///
132    /// # Errors
133    ///
134    /// `InvalidLimits`; `BufferTooSmall { needed }`.
135    ///
136    /// # Examples
137    ///
138    /// ```
139    /// use form_net::{FormError, Limits, UrlencodedParser};
140    ///
141    /// let needed = Limits::DEFAULT.urlencoded_buffer_len();
142    /// let mut small = [0u8; 16];
143    /// let err = UrlencodedParser::with_buffer(&Limits::DEFAULT, &mut small[..]).unwrap_err();
144    /// assert_eq!(err, FormError::BufferTooSmall { needed });
145    /// let parser = UrlencodedParser::with_buffer(&Limits::DEFAULT, vec![0u8; needed])?;
146    /// assert_eq!(parser.bytes_seen(), 0);
147    /// # Ok::<(), form_net::FormError>(())
148    /// ```
149    pub fn with_buffer(limits: &Limits, scratch: B) -> Result<Self, FormError> {
150        limits.validate()?;
151        let needed = limits.urlencoded_buffer_len();
152        if scratch.as_ref().len() < needed {
153            return Err(FormError::BufferTooSmall { needed });
154        }
155        Ok(UrlencodedParser {
156            scratch,
157            held: 0,
158            held_at: 0,
159            release: false,
160            seen: 0,
161            dirty: 0,
162            budget: Budget::new(limits),
163            poisoned: false,
164            ended: false,
165        })
166    }
167
168    /// Feeds `input` (`eof = true` says it ends the body) and returns the
169    /// next pair, a request for more input, or the end.
170    ///
171    /// # Errors
172    ///
173    /// The errors of [`raw_pairs`](crate::raw_pairs); `Poisoned` after an
174    /// error until [`reset`](Self::reset).
175    ///
176    /// # Examples
177    ///
178    /// ```
179    /// use form_net::{Limits, UrlencodedEvent, UrlencodedParser};
180    ///
181    /// # let mut parser = UrlencodedParser::with_buffer(&Limits::DEFAULT, vec![0u8; Limits::DEFAULT.urlencoded_buffer_len()])?;
182    /// let mut body = &b"q=rust&page=2"[..];
183    /// let mut names = Vec::new();
184    /// loop {
185    ///     let step = parser.parse(body, true)?;
186    ///     body = &body[step.consumed..];
187    ///     match step.event {
188    ///         UrlencodedEvent::Pair(p) => names.push(p.name_raw().to_vec()),
189    ///         _ => break,
190    ///     }
191    /// }
192    /// assert_eq!(names, [b"q".to_vec(), b"page".to_vec()]);
193    /// # Ok::<(), form_net::FormError>(())
194    /// ```
195    pub fn parse<'p>(
196        &'p mut self,
197        input: &'p [u8],
198        eof: bool,
199    ) -> Result<UrlencodedStep<'p>, FormError> {
200        if self.poisoned {
201            return Err(FormError::Poisoned);
202        }
203        if self.release {
204            self.release = false;
205            self.clear_held();
206        }
207        let (consumed, found) = match self.step(input, eof) {
208            Ok(r) => r,
209            Err(e) => {
210                self.poisoned = true;
211                self.clear_held();
212                return Err(e);
213            }
214        };
215        let event = match found {
216            Found::Input { start, end, at } => {
217                UrlencodedEvent::Pair(RawPair::split(input.get(start..end).unwrap_or(&[]), at))
218            }
219            Found::Scratch { len, at } => {
220                self.release = true;
221                let seq = self.scratch.as_ref().get(..len).unwrap_or(&[]);
222                UrlencodedEvent::Pair(RawPair::split(seq, at))
223            }
224            Found::NeedInput => UrlencodedEvent::NeedInput,
225            Found::End => UrlencodedEvent::End,
226        };
227        Ok(UrlencodedStep { consumed, event })
228    }
229
230    /// Clears the counters and the poisoned state and wipes the scratch, for
231    /// the next body.
232    ///
233    /// # Examples
234    ///
235    /// ```
236    /// use form_net::{FormError, Limits, UrlencodedEvent, UrlencodedParser};
237    ///
238    /// let limits = Limits::DEFAULT.with_max_name_bytes(4);
239    /// let mut parser = UrlencodedParser::with_buffer(&limits, vec![0u8; limits.urlencoded_buffer_len()])?;
240    /// assert!(parser.parse(b"too_long=1", true).is_err());
241    /// assert_eq!(parser.parse(b"a=1", true).unwrap_err(), FormError::Poisoned);
242    /// parser.reset();
243    /// assert!(matches!(parser.parse(b"a=1", true)?.event, UrlencodedEvent::Pair(_)));
244    /// # Ok::<(), form_net::FormError>(())
245    /// ```
246    pub fn reset(&mut self) {
247        self.wipe_used();
248        self.held = 0;
249        self.held_at = 0;
250        self.release = false;
251        self.seen = 0;
252        self.budget.reset();
253        self.poisoned = false;
254        self.ended = false;
255    }
256
257    /// Body bytes consumed so far.
258    ///
259    /// # Examples
260    ///
261    /// ```
262    /// use form_net::{Limits, UrlencodedParser};
263    ///
264    /// # let mut parser = UrlencodedParser::with_buffer(&Limits::DEFAULT, vec![0u8; Limits::DEFAULT.urlencoded_buffer_len()])?;
265    /// let consumed = parser.parse(b"a=1&b=2", false)?.consumed;
266    /// assert_eq!((consumed, parser.bytes_seen()), (4, 4));
267    /// # Ok::<(), form_net::FormError>(())
268    /// ```
269    #[must_use]
270    pub const fn bytes_seen(&self) -> u64 {
271        self.seen
272    }
273
274    fn wipe_used(&mut self) {
275        let used = self.dirty;
276        if let Some(region) = self.scratch.as_mut().get_mut(..used) {
277            crate::wipe::wipe(region);
278        }
279        self.dirty = 0;
280    }
281
282    fn clear_held(&mut self) {
283        if let Some(held) = self.scratch.as_mut().get_mut(..self.held) {
284            crate::wipe::wipe(held);
285        }
286        self.held = 0;
287    }
288
289    fn step(&mut self, input: &[u8], eof: bool) -> Result<(usize, Found), FormError> {
290        if self.ended {
291            return Ok((0, Found::End));
292        }
293        let body = self.budget.body;
294        let mut pos = 0usize;
295        loop {
296            let rest = input.get(pos..).unwrap_or(&[]);
297            let allowed = usize::try_from(body.saturating_sub(self.seen)).unwrap_or(usize::MAX);
298            let window = rest.get(..allowed.min(rest.len())).unwrap_or(&[]);
299            let over = rest.len() > window.len();
300            let amp = crate::scan::find_any(window, 0, *b"&&&&").min(window.len());
301            let terminated = amp < window.len();
302            let piece = window.get(..amp).unwrap_or(&[]);
303            if !terminated && (!eof || over) {
304                // The sequence goes on past this chunk (or past the body
305                // budget): check what is known, then hold it or refuse.
306                self.check_partial(piece)?;
307                if over {
308                    return Err(FormError::limit(Limit::Body, Location::at(body)));
309                }
310                self.hold(piece);
311                pos = pos.saturating_add(piece.len());
312                self.seen = self.seen.saturating_add(piece.len() as u64);
313                return Ok((pos, Found::NeedInput));
314            }
315            // The sequence is complete: `piece` ends at `&` or at the end of
316            // the body.
317            let start = pos;
318            let at = self.seen;
319            let seq_len = self.held.saturating_add(piece.len());
320            pos = pos.saturating_add(piece.len());
321            self.seen = self.seen.saturating_add(piece.len() as u64);
322            if terminated {
323                pos = pos.saturating_add(1);
324                self.seen = self.seen.saturating_add(1);
325            }
326            if seq_len == 0 {
327                if terminated {
328                    continue;
329                }
330                self.ended = true;
331                return Ok((pos, Found::End));
332            }
333            if self.held == 0 {
334                self.budget.admit(&RawPair::split(piece, at))?;
335                return Ok((
336                    pos,
337                    Found::Input {
338                        start,
339                        end: start.saturating_add(piece.len()),
340                        at,
341                    },
342                ));
343            }
344            // Part of the sequence is held: the rest joins it in scratch.
345            self.check_partial(piece)?;
346            self.hold(piece);
347            let at = self.held_at;
348            let len = self.held;
349            let seq = self.scratch.as_ref().get(..len).unwrap_or(&[]);
350            self.budget.admit(&RawPair::split(seq, at))?;
351            return Ok((pos, Found::Scratch { len, at }));
352        }
353    }
354
355    /// Refuses the held sequence plus `more` when its complete form is
356    /// certain to be refused.
357    fn check_partial(&self, more: &[u8]) -> Result<(), FormError> {
358        let held = self.scratch.as_ref().get(..self.held).unwrap_or(&[]);
359        let at = if self.held == 0 {
360            self.seen
361        } else {
362            self.held_at
363        };
364        let (name_len, has_equals, value_len) = match held.iter().position(|&b| b == b'=') {
365            Some(e) => (
366                e,
367                true,
368                held.len()
369                    .saturating_sub(e)
370                    .saturating_sub(1)
371                    .saturating_add(more.len()),
372            ),
373            None => match more.iter().position(|&b| b == b'=') {
374                Some(e) => (
375                    held.len().saturating_add(e),
376                    true,
377                    more.len().saturating_sub(e).saturating_sub(1),
378                ),
379                None => (held.len().saturating_add(more.len()), false, 0),
380            },
381        };
382        self.budget
383            .admit_partial(at, name_len, has_equals, value_len)
384    }
385
386    /// Appends `bytes` to the held sequence. `check_partial` passed, so
387    /// they fit.
388    fn hold(&mut self, bytes: &[u8]) {
389        if bytes.is_empty() {
390            return;
391        }
392        if self.held == 0 {
393            self.held_at = self.seen;
394        }
395        let start = self.held;
396        let end = start.saturating_add(bytes.len());
397        if let Some(dst) = self.scratch.as_mut().get_mut(start..end) {
398            dst.copy_from_slice(bytes);
399            self.held = end;
400            self.dirty = self.dirty.max(end);
401        }
402    }
403}
404
405impl<B: AsMut<[u8]> + AsRef<[u8]>> Drop for UrlencodedParser<B> {
406    fn drop(&mut self) {
407        self.wipe_used();
408    }
409}
410
411#[cfg(feature = "alloc")]
412impl UrlencodedParser<alloc::vec::Vec<u8>> {
413    /// A parser that owns its scratch buffer.
414    ///
415    /// # Errors
416    ///
417    /// `InvalidLimits`.
418    ///
419    /// # Examples
420    ///
421    /// ```
422    /// use form_net::{Limits, UrlencodedEvent, UrlencodedParser};
423    ///
424    /// let mut parser = UrlencodedParser::new(&Limits::DEFAULT)?;
425    /// let step = parser.parse(b"a=1", true)?;
426    /// assert!(matches!(step.event, UrlencodedEvent::Pair(p) if p.value_raw() == b"1"));
427    /// # Ok::<(), form_net::FormError>(())
428    /// ```
429    pub fn new(limits: &Limits) -> Result<Self, FormError> {
430        limits.validate()?;
431        Self::with_buffer(limits, alloc::vec![0u8; limits.urlencoded_buffer_len()])
432    }
433}