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}