Skip to main content

form_net/multipart/
parser.rs

1//! The sans-IO multipart parser: a state machine over the delimiter matcher
2//! and the header reader.
3
4use core::fmt;
5
6use crate::error::{EncodingError, FormError, Limit, Location, PolicyRefusal, SyntaxError};
7use crate::limits::{CHARSET_CAPTURE, EmptyFilePolicy, Limits, Policy, TokenPlacement};
8use crate::multipart::boundary::{Boundary, Hit};
9use crate::multipart::filename::FileName;
10use crate::multipart::header::{Areas, BlockScan, HeadFacts, Text, read_block};
11
12/// Whether a part is a text field or a file.
13///
14/// # Examples
15///
16/// ```
17/// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--X--";
18/// let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", body)?;
19/// assert_eq!(mp.parts()[0].kind(), form_net::PartKind::Field);
20/// # Ok::<(), form_net::FormError>(())
21/// ```
22#[non_exhaustive]
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
24pub enum PartKind {
25    /// A text field: no `filename` parameter.
26    Field,
27    /// A file: a `filename` parameter (even an empty one) or an accepted
28    /// `filename*`.
29    File,
30}
31
32/// The `charset` a part declared.
33///
34/// `Unspecified` means no `charset` parameter: UTF-8 is assumed unless a
35/// `_charset_` field before the part said otherwise. `Other` is any label
36/// that is not UTF-8 or US-ASCII; its text is refused by every text accessor.
37///
38/// # Examples
39///
40/// ```
41/// use form_net::Charset;
42///
43/// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n1\r\n--X--";
44/// # let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", body)?;
45/// assert_eq!(mp.parts()[0].content_type().unwrap().charset(), Charset::Utf8);
46/// # Ok::<(), form_net::FormError>(())
47/// ```
48#[non_exhaustive]
49#[derive(Clone, Copy, Debug, PartialEq, Eq)]
50pub enum Charset {
51    /// `utf-8`.
52    Utf8,
53    /// `us-ascii`.
54    Ascii,
55    /// No `charset` parameter.
56    Unspecified,
57    /// Any other label.
58    Other,
59}
60
61/// How a text value is read, from its charset label.
62#[cfg(feature = "alloc")]
63#[derive(Clone, Copy, Debug, PartialEq, Eq)]
64pub(crate) enum TextRule {
65    /// UTF-8 (no label, or `utf-8`).
66    Utf8,
67    /// `us-ascii`: every byte below 0x80. WHATWG readers decode the label as
68    /// windows-1252, so a higher byte would read differently there (D-150).
69    Ascii,
70    /// Any other label.
71    Refuse,
72}
73
74#[cfg(feature = "alloc")]
75impl TextRule {
76    /// Checks `bytes` against the rule, then as UTF-8.
77    pub(crate) fn check(self, bytes: &[u8]) -> Result<(), EncodingError> {
78        match self {
79            TextRule::Refuse => Err(EncodingError::UnsupportedCharset),
80            TextRule::Ascii if !bytes.is_ascii() => Err(EncodingError::UnsupportedCharset),
81            _ if core::str::from_utf8(bytes).is_err() => Err(EncodingError::InvalidUtf8),
82            _ => Ok(()),
83        }
84    }
85}
86
87/// The rule a declared `_charset_` value sets for the text after it.
88#[cfg(feature = "alloc")]
89pub(crate) fn declared_rule(declared: Option<&[u8]>) -> TextRule {
90    match declared {
91        None => TextRule::Utf8,
92        Some(label) => match Charset::from_label(label) {
93            Charset::Utf8 => TextRule::Utf8,
94            Charset::Ascii => TextRule::Ascii,
95            _ => TextRule::Refuse,
96        },
97    }
98}
99
100impl Charset {
101    /// How a text part with this charset is read: by its own label, else by
102    /// the `_charset_` declared before it, else as UTF-8.
103    #[cfg(feature = "alloc")]
104    pub(crate) const fn rule(self, declared: TextRule) -> TextRule {
105        match self {
106            Charset::Utf8 => TextRule::Utf8,
107            Charset::Ascii => TextRule::Ascii,
108            Charset::Other => TextRule::Refuse,
109            Charset::Unspecified => declared,
110        }
111    }
112
113    pub(crate) fn from_label(label: &[u8]) -> Charset {
114        if label.eq_ignore_ascii_case(b"utf-8") {
115            Charset::Utf8
116        } else if label.eq_ignore_ascii_case(b"us-ascii") {
117            Charset::Ascii
118        } else {
119            Charset::Other
120        }
121    }
122}
123
124/// One step of the parser: how many input bytes it consumed, and what
125/// happened.
126///
127/// # Examples
128///
129/// ```
130/// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
131/// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
132/// let body = b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--X--";
133/// let step = parser.parse(body, true)?;
134/// assert!(matches!(step.event, MultipartEvent::PartStart(_)));
135/// // The rest of the body goes to the next call.
136/// assert!(step.consumed > 0 && step.consumed < body.len());
137/// # Ok::<(), form_net::FormError>(())
138/// ```
139#[non_exhaustive]
140#[derive(Debug)]
141pub struct MultipartStep<'p> {
142    /// Bytes of the input consumed; pass the rest (and later new bytes) to
143    /// the next call.
144    pub consumed: usize,
145    /// What happened.
146    pub event: MultipartEvent<'p>,
147}
148
149/// What the parser found.
150///
151/// Per part the order is always `PartStart`, any number of `Data` (none for
152/// an empty part), `PartEnd`. A `Data` slice is never empty. After the last
153/// part comes `End`. `NeedInput` can appear anywhere between.
154///
155/// `Debug` prints the length of `Data`, never the bytes.
156///
157/// # Examples
158///
159/// ```
160/// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
161/// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
162/// let mut rest = &b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n12\r\n--X--"[..];
163/// let mut seen = String::new();
164/// loop {
165///     let step = parser.parse(rest, true)?;
166///     rest = &rest[step.consumed..];
167///     match step.event {
168///         MultipartEvent::PartStart(head) => seen.push_str(head.name()),
169///         MultipartEvent::Data(bytes) => seen.push_str(&format!(" {}", bytes.len())),
170///         MultipartEvent::PartEnd(_) => seen.push_str(" end"),
171///         MultipartEvent::End | MultipartEvent::NeedInput => break,
172///         _ => {}
173///     }
174/// }
175/// assert_eq!(seen, "a 2 end");
176/// # Ok::<(), form_net::FormError>(())
177/// ```
178#[non_exhaustive]
179pub enum MultipartEvent<'p> {
180    /// A part's headers were read and checked.
181    PartStart(PartHead<'p>),
182    /// Bytes of the current part's data.
183    Data(&'p [u8]),
184    /// The current part ended.
185    PartEnd(PartSummary),
186    /// The close delimiter was read: the form is complete.
187    End,
188    /// Every byte given was consumed; give more.
189    NeedInput,
190}
191
192impl fmt::Debug for MultipartEvent<'_> {
193    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194        match self {
195            Self::PartStart(head) => f.debug_tuple("PartStart").field(head).finish(),
196            Self::Data(bytes) => write!(f, "Data({} bytes)", bytes.len()),
197            Self::PartEnd(summary) => f.debug_tuple("PartEnd").field(summary).finish(),
198            Self::End => f.write_str("End"),
199            Self::NeedInput => f.write_str("NeedInput"),
200        }
201    }
202}
203
204/// What one part was.
205///
206/// # Examples
207///
208/// ```
209/// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
210/// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
211/// let mut rest = &b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\nhello\r\n--X--"[..];
212/// let summary = loop {
213///     let step = parser.parse(rest, true)?;
214///     rest = &rest[step.consumed..];
215///     if let MultipartEvent::PartEnd(summary) = step.event {
216///         break summary;
217///     }
218/// };
219/// assert_eq!((summary.index, summary.bytes, summary.skipped), (0, 5, false));
220/// assert_eq!(summary.kind, PartKind::Field);
221/// # Ok::<(), form_net::FormError>(())
222/// ```
223#[non_exhaustive]
224#[derive(Clone, Copy, Debug, PartialEq, Eq)]
225pub struct PartSummary {
226    /// The part index, from 0.
227    pub index: u32,
228    /// Field or file.
229    pub kind: PartKind,
230    /// The length of the part's data.
231    pub bytes: u64,
232    /// Whether the part was skipped (by `skip_part` or an inspector).
233    pub skipped: bool,
234}
235
236/// The validated header block of one part, borrowed.
237///
238/// A head is only produced after every header budget and rule passed.
239///
240/// # Examples
241///
242/// ```
243/// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
244/// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
245/// let body = b"--X\r\nContent-Disposition: form-data; name=doc; filename=a.pdf\r\nContent-Type: application/pdf\r\n\r\n%PDF\r\n--X--";
246/// let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event else { unreachable!() };
247/// assert_eq!(head.name(), "doc");
248/// assert!(head.is_file());
249/// assert!(head.content_type().unwrap().is("application", "pdf"));
250/// # Ok::<(), form_net::FormError>(())
251/// ```
252#[derive(Clone, Copy)]
253pub struct PartHead<'p> {
254    index: u32,
255    block: &'p [u8],
256    name: &'p str,
257    name_raw: &'p [u8],
258    kind: PartKind,
259    filename: Option<FileName<'p>>,
260    content_type: Option<&'p [u8]>,
261    charset: Charset,
262}
263
264impl fmt::Debug for PartHead<'_> {
265    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266        f.debug_struct("PartHead")
267            .field("index", &self.index)
268            .field("name", &self.name)
269            .field("kind", &self.kind)
270            .field("filename", &self.filename)
271            .finish_non_exhaustive()
272    }
273}
274
275impl<'p> PartHead<'p> {
276    /// A head over bytes kept elsewhere (an owned copy).
277    #[cfg(feature = "alloc")]
278    #[allow(clippy::too_many_arguments)]
279    pub(crate) const fn from_parts(
280        index: u32,
281        block: &'p [u8],
282        name: &'p str,
283        name_raw: &'p [u8],
284        kind: PartKind,
285        filename: Option<FileName<'p>>,
286        content_type: Option<&'p [u8]>,
287        charset: Charset,
288    ) -> Self {
289        Self {
290            index,
291            block,
292            name,
293            name_raw,
294            kind,
295            filename,
296            content_type,
297            charset,
298        }
299    }
300
301    /// The header block, the final CRLF CRLF included.
302    #[cfg(feature = "alloc")]
303    pub(crate) const fn block(&self) -> &'p [u8] {
304        self.block
305    }
306
307    /// The part index, from 0, in body order.
308    ///
309    /// # Examples
310    ///
311    /// ```
312    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
313    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
314    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--X--";
315    /// let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event else { unreachable!() };
316    /// assert_eq!(head.index(), 0);
317    /// # Ok::<(), form_net::FormError>(())
318    /// ```
319    #[must_use]
320    pub const fn index(&self) -> u32 {
321        self.index
322    }
323
324    /// The field name, with `%0A`, `%0D`, `%22` decoded to LF, CR, `"` (no
325    /// other escape is decoded). Always valid UTF-8 and never empty.
326    ///
327    /// # Examples
328    ///
329    /// ```
330    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
331    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
332    /// # let body = b"--X\r\nContent-Disposition: form-data; name=\"a%22b\"\r\n\r\n1\r\n--X--";
333    /// let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event else { unreachable!() };
334    /// assert_eq!(head.name(), "a\"b");
335    /// # Ok::<(), form_net::FormError>(())
336    /// ```
337    #[must_use]
338    pub const fn name(&self) -> &'p str {
339        self.name
340    }
341
342    /// The field name as sent.
343    ///
344    /// # Examples
345    ///
346    /// ```
347    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
348    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
349    /// # let body = b"--X\r\nContent-Disposition: form-data; name=\"a%22b\"\r\n\r\n1\r\n--X--";
350    /// let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event else { unreachable!() };
351    /// assert_eq!(head.name_raw(), b"a%22b");
352    /// # Ok::<(), form_net::FormError>(())
353    /// ```
354    #[must_use]
355    pub const fn name_raw(&self) -> &'p [u8] {
356        self.name_raw
357    }
358
359    /// Field or file.
360    ///
361    /// # Examples
362    ///
363    /// ```
364    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
365    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
366    /// # let body = b"--X\r\nContent-Disposition: form-data; name=f; filename=a.txt\r\n\r\nhi\r\n--X--";
367    /// let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event else { unreachable!() };
368    /// assert_eq!(head.kind(), PartKind::File);
369    /// # Ok::<(), form_net::FormError>(())
370    /// ```
371    #[must_use]
372    pub const fn kind(&self) -> PartKind {
373        self.kind
374    }
375
376    /// Whether this is a file part.
377    ///
378    /// # Examples
379    ///
380    /// ```
381    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
382    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
383    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--X--";
384    /// let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event else { unreachable!() };
385    /// assert!(!head.is_file());
386    /// # Ok::<(), form_net::FormError>(())
387    /// ```
388    #[must_use]
389    pub const fn is_file(&self) -> bool {
390        matches!(self.kind, PartKind::File)
391    }
392
393    /// The client's file name, for file parts.
394    ///
395    /// # Examples
396    ///
397    /// ```
398    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
399    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
400    /// # let body = b"--X\r\nContent-Disposition: form-data; name=f; filename=a.txt\r\n\r\nhi\r\n--X--";
401    /// let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event else { unreachable!() };
402    /// assert_eq!(head.filename().unwrap().raw(), b"a.txt");
403    /// # Ok::<(), form_net::FormError>(())
404    /// ```
405    #[must_use]
406    pub const fn filename(&self) -> Option<FileName<'p>> {
407        self.filename
408    }
409
410    /// The declared `Content-Type`: a hint, never trusted.
411    ///
412    /// # Examples
413    ///
414    /// ```
415    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
416    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
417    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\nContent-Type: text/plain\r\n\r\n1\r\n--X--";
418    /// let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event else { unreachable!() };
419    /// assert!(head.content_type().unwrap().is("text", "plain"));
420    /// # Ok::<(), form_net::FormError>(())
421    /// ```
422    #[must_use]
423    pub fn content_type(&self) -> Option<ContentType<'p>> {
424        self.content_type.and_then(ContentType::parse)
425    }
426
427    /// The part's own `charset` parameter (`Unspecified` when absent).
428    ///
429    /// # Examples
430    ///
431    /// ```
432    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
433    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
434    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\nContent-Type: text/plain; charset=us-ascii\r\n\r\n1\r\n--X--";
435    /// let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event else { unreachable!() };
436    /// assert_eq!(head.charset(), Charset::Ascii);
437    /// # Ok::<(), form_net::FormError>(())
438    /// ```
439    #[must_use]
440    pub const fn charset(&self) -> Charset {
441        self.charset
442    }
443
444    /// Every header line, in order, as raw `(name, value)` bytes.
445    ///
446    /// # Examples
447    ///
448    /// ```
449    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
450    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
451    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\nContent-Type: text/plain\r\n\r\n1\r\n--X--";
452    /// let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event else { unreachable!() };
453    /// let (name, value) = head.headers().nth(1).unwrap();
454    /// assert_eq!((name, value), (&b"Content-Type"[..], &b"text/plain"[..]));
455    /// # Ok::<(), form_net::FormError>(())
456    /// ```
457    #[must_use]
458    pub fn headers(&self) -> Headers<'p> {
459        Headers { rest: self.block }
460    }
461
462    /// The size of the header block, the final CRLF CRLF included.
463    ///
464    /// # Examples
465    ///
466    /// ```
467    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
468    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
469    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--X--";
470    /// let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event else { unreachable!() };
471    /// // The block ends with the blank line.
472    /// let block = "Content-Disposition: form-data; name=a\r\n\r\n";
473    /// assert_eq!(head.header_bytes() as usize, block.len());
474    /// # Ok::<(), form_net::FormError>(())
475    /// ```
476    #[must_use]
477    pub const fn header_bytes(&self) -> u32 {
478        self.block.len() as u32
479    }
480}
481
482/// A part's declared `Content-Type`, already checked. **A hint**: the client
483/// chose it.
484///
485/// # Examples
486///
487/// ```
488/// # let body = b"--X\r\nContent-Disposition: form-data; name=f; filename=a.png\r\nContent-Type: Image/PNG; q=\"x y\"\r\n\r\n\r\n--X--";
489/// # let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", body)?;
490/// let ct = mp.file("f").unwrap().content_type().unwrap();
491/// assert!(ct.is("image", "png"));
492/// assert_eq!((ct.type_(), ct.subtype()), ("Image", "PNG"));
493/// assert_eq!(ct.parameter("Q"), Some(&b"x y"[..]));
494/// # Ok::<(), form_net::FormError>(())
495/// ```
496#[derive(Clone, Copy)]
497pub struct ContentType<'p> {
498    raw: &'p [u8],
499    media: parse_net::MediaType<'p>,
500}
501
502impl fmt::Debug for ContentType<'_> {
503    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
504        f.debug_struct("ContentType")
505            .field("type", &self.type_())
506            .field("subtype", &self.subtype())
507            .finish_non_exhaustive()
508    }
509}
510
511impl<'p> ContentType<'p> {
512    pub(crate) fn parse(raw: &'p [u8]) -> Option<ContentType<'p>> {
513        parse_net::media::parse(raw, &crate::kind::HEADER_LIMITS)
514            .ok()
515            .map(|media| ContentType { raw, media })
516    }
517
518    /// The value as sent.
519    ///
520    /// # Examples
521    ///
522    /// ```
523    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n1\r\n--X--";
524    /// # let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", body)?;
525    /// let ct = mp.parts()[0].content_type().unwrap();
526    /// assert_eq!(ct.raw(), b"text/plain; charset=utf-8");
527    /// # Ok::<(), form_net::FormError>(())
528    /// ```
529    #[must_use]
530    pub const fn raw(&self) -> &'p [u8] {
531        self.raw
532    }
533
534    /// The type, as sent.
535    ///
536    /// # Examples
537    ///
538    /// ```
539    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n1\r\n--X--";
540    /// # let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", body)?;
541    /// let ct = mp.parts()[0].content_type().unwrap();
542    /// assert_eq!(ct.type_(), "text");
543    /// # Ok::<(), form_net::FormError>(())
544    /// ```
545    #[must_use]
546    pub fn type_(&self) -> &'p str {
547        core::str::from_utf8(self.media.type_()).unwrap_or("")
548    }
549
550    /// The subtype, as sent.
551    ///
552    /// # Examples
553    ///
554    /// ```
555    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n1\r\n--X--";
556    /// # let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", body)?;
557    /// let ct = mp.parts()[0].content_type().unwrap();
558    /// assert_eq!(ct.subtype(), "plain");
559    /// # Ok::<(), form_net::FormError>(())
560    /// ```
561    #[must_use]
562    pub fn subtype(&self) -> &'p str {
563        core::str::from_utf8(self.media.subtype()).unwrap_or("")
564    }
565
566    /// Whether the type and subtype are these, ASCII case-insensitively.
567    ///
568    /// # Examples
569    ///
570    /// ```
571    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n1\r\n--X--";
572    /// # let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", body)?;
573    /// let ct = mp.parts()[0].content_type().unwrap();
574    /// assert!(ct.is("TEXT", "Plain"));
575    /// assert!(!ct.is("text", "html"));
576    /// # Ok::<(), form_net::FormError>(())
577    /// ```
578    #[must_use]
579    pub fn is(&self, type_: &str, subtype: &str) -> bool {
580        self.media.is(type_, subtype)
581    }
582
583    /// A parameter's value by name (ASCII case-insensitive), without
584    /// surrounding quotes; backslashes are literal, as browsers send them.
585    ///
586    /// # Examples
587    ///
588    /// ```
589    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n1\r\n--X--";
590    /// # let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", body)?;
591    /// let ct = mp.parts()[0].content_type().unwrap();
592    /// assert_eq!(ct.parameter("Charset"), Some(&b"utf-8"[..]));
593    /// assert_eq!(ct.parameter("boundary"), None);
594    /// # Ok::<(), form_net::FormError>(())
595    /// ```
596    #[must_use]
597    pub fn parameter(&self, name: &str) -> Option<&'p [u8]> {
598        self.media
599            .params()
600            .get(name)
601            .map(|w| crate::kind::word_raw(&w))
602    }
603
604    /// The `charset` parameter.
605    ///
606    /// # Examples
607    ///
608    /// ```
609    /// use form_net::Charset;
610    ///
611    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n1\r\n--X--";
612    /// # let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", body)?;
613    /// let ct = mp.parts()[0].content_type().unwrap();
614    /// assert_eq!(ct.charset(), Charset::Utf8);
615    /// # Ok::<(), form_net::FormError>(())
616    /// ```
617    #[must_use]
618    pub fn charset(&self) -> Charset {
619        self.parameter("charset")
620            .map_or(Charset::Unspecified, Charset::from_label)
621    }
622}
623
624/// Every header line of a part, in order, as raw `(name, value)` bytes with
625/// the value trimmed.
626///
627/// `Debug` prints the header names only: values carry file names.
628///
629/// # Examples
630///
631/// ```
632/// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
633/// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
634/// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\nContent-Type: text/plain\r\n\r\n1\r\n--X--";
635/// let MultipartEvent::PartStart(head) = parser.parse(body, true)?.event else { unreachable!() };
636/// let names: Vec<&[u8]> = head.headers().map(|(name, _)| name).collect();
637/// assert_eq!(names, [&b"Content-Disposition"[..], &b"Content-Type"[..]]);
638/// # Ok::<(), form_net::FormError>(())
639/// ```
640#[derive(Clone)]
641pub struct Headers<'p> {
642    rest: &'p [u8],
643}
644
645impl fmt::Debug for Headers<'_> {
646    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
647        let mut list = f.debug_list();
648        for (name, _) in self.clone() {
649            list.entry(&core::str::from_utf8(name).unwrap_or("?"));
650        }
651        list.finish()
652    }
653}
654
655impl<'p> Iterator for Headers<'p> {
656    type Item = (&'p [u8], &'p [u8]);
657
658    fn next(&mut self) -> Option<Self::Item> {
659        let lf = self.rest.iter().position(|&b| b == b'\n')?;
660        let line = self.rest.get(..lf.saturating_sub(1)).unwrap_or(&[]);
661        self.rest = self.rest.get(lf.wrapping_add(1)..).unwrap_or(&[]);
662        if line.is_empty() {
663            self.rest = &[];
664            return None;
665        }
666        let colon = line.iter().position(|&b| b == b':').unwrap_or(line.len());
667        let name = line.get(..colon).unwrap_or(&[]);
668        let value = line.get(colon.wrapping_add(1)..).unwrap_or(&[]);
669        Some((name, parse_net::text::trim_ows(value)))
670    }
671}
672
673#[derive(Clone, Copy, Debug, PartialEq, Eq)]
674enum State {
675    Preamble,
676    /// After a delimiter: expecting `--`, padding, or CRLF.
677    AfterDelimiter(After),
678    Headers,
679    Body,
680    /// The delimiter that ends the current part was found; `PartEnd` is due.
681    EndOfPart,
682    Epilogue,
683    Poisoned,
684}
685
686#[derive(Clone, Copy, Debug, PartialEq, Eq)]
687enum After {
688    Start,
689    Dash,
690    Padding(u8),
691    Cr,
692}
693
694/// The token field's progress.
695#[derive(Clone, Copy, Debug, PartialEq, Eq)]
696enum Token {
697    NotSeen,
698    Capturing,
699    Captured,
700}
701
702const SKIPPING: u8 = 1;
703const IS_TOKEN: u8 = 2;
704const IS_CHARSET: u8 = 4;
705const DEFERRED: u8 = 8;
706
707/// Where a head's block is.
708#[derive(Clone, Copy, Debug)]
709pub(crate) enum Source {
710    /// In the input, from this index.
711    Input(usize),
712    /// In the parser buffer, from 0.
713    Buffer,
714}
715
716/// What a call to `advance` produced, as positions only.
717#[derive(Clone, Copy, Debug)]
718pub(crate) enum Outcome {
719    PartStart(HeadFacts, Source),
720    /// `input[start..end]`.
721    DataInput(usize, usize),
722    /// The first bytes of the delimiter.
723    DataDelimiter(usize),
724    PartEnd(PartSummary),
725    End,
726    NeedInput,
727}
728
729/// The sans-IO `multipart/form-data` parser.
730///
731/// Feed it bytes as they arrive, in chunks of any size split at any byte;
732/// it returns one [`MultipartEvent`] per call and how many bytes it consumed. The
733/// events are identical for every split of a body that parses; for a body
734/// that fails, the error is identical, though a split body may emit data
735/// before it that a whole one does not. It never allocates after
736/// construction. The delimiter search skips 32 bytes at a time to a line
737/// break followed by `-` and compares the delimiter there a word at a time;
738/// bytes that may start a delimiter at a chunk's end are carried and
739/// scanned again with the next chunk (at most 73 per boundary), so the
740/// search stays linear. The streaming automaton (a Knuth-Morris-Pratt
741/// table) only carries that state between chunks.
742///
743/// The buffer holds the header block, the decoded field name, the decoded
744/// `filename*` (under `AcceptAlone`), the token, and the `_charset_` value:
745/// [`Limits::multipart_buffer_len`] bytes. It is wiped on `reset` and on
746/// drop.
747///
748/// # Examples
749///
750/// ```
751/// use form_net::{MultipartEvent, FormKind, Limits, MultipartParser, Policy};
752///
753/// let content_type = b"multipart/form-data; boundary=X";
754/// let body = b"--X\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nHoliday\r\n--X--\r\n";
755/// let FormKind::Multipart(boundary) = FormKind::detect(content_type)? else { unreachable!() };
756/// let mut parser = MultipartParser::new(boundary, &Limits::DEFAULT, &Policy::DEFAULT)?;
757///
758/// let mut events = Vec::new();
759/// let mut chunks = body.chunks(7).peekable();     // any split gives the same events
760/// while let Some(chunk) = chunks.next() {
761///     let last = chunks.peek().is_none();
762///     let mut rest = chunk;
763///     loop {
764///         let step = parser.parse(rest, last)?;
765///         rest = &rest[step.consumed..];
766///         match step.event {
767///             MultipartEvent::PartStart(head) => events.push(format!("start {}", head.name())),
768///             MultipartEvent::Data(bytes) => events.push(format!("data {}", bytes.len())),
769///             MultipartEvent::PartEnd(summary) => events.push(format!("end {}", summary.bytes)),
770///             MultipartEvent::End => break,
771///             MultipartEvent::NeedInput => break,
772///             _ => {}
773///         }
774///     }
775/// }
776/// assert!(parser.is_done());
777/// assert_eq!(events.first().map(String::as_str), Some("start title"));
778/// assert_eq!(events.last().map(String::as_str), Some("end 7"));
779/// # Ok::<(), form_net::FormError>(())
780/// ```
781pub struct MultipartParser<B: AsMut<[u8]> + AsRef<[u8]>> {
782    boundary: Boundary,
783    limits: Limits,
784    policy: Policy,
785    buffer: B,
786    state: State,
787    /// Delimiter bytes matched and not yet known to be data.
788    k: u8,
789    /// Bytes of a lone CR or LF and `--boundary` matched (D-113); while
790    /// `k > 0` it follows from `k`.
791    bare: u8,
792    flags: u8,
793    token: Token,
794    token_len: u16,
795    charset_len: u8,
796    charset_done: bool,
797    scan: BlockScan,
798    /// Header bytes copied into the buffer.
799    copied: u32,
800    /// The longest header block read so far: every byte the parser writes
801    /// into the header, name, and file-name areas lies within this many
802    /// bytes of each area's start (decoding never lengthens), so the wipe
803    /// covers exactly what was written (D-103).
804    dirty: u32,
805    parts: u32,
806    files: u32,
807    fields: u32,
808    kind: PartKind,
809    part_bytes: u64,
810    text_total: u64,
811    data_start: u64,
812    preamble: u64,
813    epilogue: u64,
814    /// Where the current header block starts in the body.
815    head_start: u64,
816    /// Where the epilogue starts in the body.
817    epilogue_start: u64,
818    bytes_seen: u64,
819}
820
821impl<B: AsMut<[u8]> + AsRef<[u8]>> fmt::Debug for MultipartParser<B> {
822    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
823        f.debug_struct("MultipartParser")
824            .field("boundary", &self.boundary)
825            .field("state", &self.state)
826            .field("bytes_seen", &self.bytes_seen)
827            .field("parts_seen", &self.parts)
828            .finish_non_exhaustive()
829    }
830}
831
832#[cfg(feature = "alloc")]
833impl MultipartParser<alloc::vec::Vec<u8>> {
834    /// A parser with its own buffer of
835    /// [`Limits::multipart_buffer_len`] bytes, allocated once.
836    ///
837    /// # Errors
838    ///
839    /// `InvalidLimits` from validating the limits with the policy.
840    ///
841    /// # Examples
842    ///
843    /// ```
844    /// use form_net::{Boundary, Limits, MultipartParser, Policy};
845    ///
846    /// let parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
847    /// assert_eq!(parser.bytes_seen(), 0);
848    /// # Ok::<(), form_net::FormError>(())
849    /// ```
850    pub fn new(boundary: Boundary, limits: &Limits, policy: &Policy) -> Result<Self, FormError> {
851        limits.validate_with(policy)?;
852        let buffer = alloc::vec![0u8; limits.multipart_buffer_len(policy)];
853        Self::with_buffer(boundary, limits, policy, buffer)
854    }
855}
856
857impl<B: AsMut<[u8]> + AsRef<[u8]>> MultipartParser<B> {
858    /// A parser over a buffer the caller provides; it never allocates.
859    ///
860    /// # Errors
861    ///
862    /// `InvalidLimits`; `BufferTooSmall` when `buffer` is shorter than
863    /// [`Limits::multipart_buffer_len`].
864    ///
865    /// # Examples
866    ///
867    /// ```
868    /// use form_net::{Boundary, Limits, MultipartParser, Policy};
869    ///
870    /// const LIMITS: Limits = Limits::DEFAULT.with_max_part_header_bytes(1024);
871    /// const LEN: usize = LIMITS.multipart_buffer_len(&Policy::DEFAULT);
872    /// let mut buffer = [0u8; LEN];
873    /// let parser = MultipartParser::with_buffer(Boundary::new(b"X")?, &LIMITS, &Policy::DEFAULT, &mut buffer[..])?;
874    /// # Ok::<(), form_net::FormError>(())
875    /// ```
876    pub fn with_buffer(
877        boundary: Boundary,
878        limits: &Limits,
879        policy: &Policy,
880        buffer: B,
881    ) -> Result<Self, FormError> {
882        limits.validate_with(policy)?;
883        let needed = limits.multipart_buffer_len(policy);
884        if buffer.as_ref().len() < needed {
885            return Err(FormError::BufferTooSmall { needed });
886        }
887        Ok(Self {
888            boundary,
889            limits: *limits,
890            policy: *policy,
891            buffer,
892            state: State::Preamble,
893            // The body may start with `--boundary`: start as if CRLF had
894            // been seen.
895            k: 2,
896            bare: 1,
897            flags: 0,
898            token: Token::NotSeen,
899            token_len: 0,
900            charset_len: 0,
901            charset_done: false,
902            scan: BlockScan::default(),
903            copied: 0,
904            dirty: 0,
905            parts: 0,
906            files: 0,
907            fields: 0,
908            kind: PartKind::Field,
909            part_bytes: 0,
910            text_total: 0,
911            data_start: 0,
912            preamble: 0,
913            epilogue: 0,
914            head_start: 0,
915            epilogue_start: 0,
916            bytes_seen: 0,
917        })
918    }
919
920    /// Consumes a prefix of `input` and returns one event. `eof = true` says
921    /// `input` ends the body.
922    ///
923    /// # Errors
924    ///
925    /// Every multipart error (see the crate's `docs/API.md`); `Poisoned`
926    /// after any error until [`reset`](Self::reset).
927    ///
928    /// # Examples
929    ///
930    /// ```
931    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
932    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
933    /// let body = b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--X--";
934    /// // The first 10 bytes are not a whole header block: give more.
935    /// let step = parser.parse(&body[..10], false)?;
936    /// assert!(matches!(step.event, MultipartEvent::NeedInput));
937    /// let rest = &body[step.consumed..];
938    /// let step = parser.parse(rest, true)?;
939    /// assert!(matches!(step.event, MultipartEvent::PartStart(head) if head.name() == "a"));
940    /// # Ok::<(), form_net::FormError>(())
941    /// ```
942    pub fn parse<'p>(
943        &'p mut self,
944        input: &'p [u8],
945        eof: bool,
946    ) -> Result<MultipartStep<'p>, FormError> {
947        let (consumed, outcome) = self.advance(input, eof)?;
948        Ok(MultipartStep {
949            consumed,
950            event: self.view(outcome, input),
951        })
952    }
953
954    /// Discards the rest of the current part: its bytes are consumed and
955    /// counted against the budgets but produce no `Data` events, and its
956    /// summary has `skipped = true`. Outside a part it does nothing.
957    ///
958    /// # Examples
959    ///
960    /// ```
961    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
962    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
963    /// # let body = b"--X\r\nContent-Disposition: form-data; name=big\r\n\r\nunwanted\r\n--X--";
964    /// let step = parser.parse(body, true)?;
965    /// # assert!(matches!(step.event, MultipartEvent::PartStart(_)));
966    /// let mut rest = &body[step.consumed..];
967    /// parser.skip_part();
968    /// let summary = loop {
969    ///     let step = parser.parse(rest, true)?;
970    ///     rest = &rest[step.consumed..];
971    ///     assert!(!matches!(step.event, MultipartEvent::Data(_)));
972    ///     if let MultipartEvent::PartEnd(summary) = step.event {
973    ///         break summary;
974    ///     }
975    /// };
976    /// assert!(summary.skipped);
977    /// # Ok::<(), form_net::FormError>(())
978    /// ```
979    pub fn skip_part(&mut self) {
980        if matches!(self.state, State::Body) {
981            self.flags |= SKIPPING;
982        }
983    }
984
985    /// Returns the parser to its initial state for a new body, wipes its
986    /// buffer, and clears the poisoned state. It never allocates.
987    ///
988    /// # Examples
989    ///
990    /// ```
991    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
992    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
993    /// assert!(parser.parse(b"no delimiter here", true).is_err());
994    /// // Poisoned until reset; reset also takes the next body's boundary.
995    /// assert!(parser.parse(b"", true).is_err());
996    /// parser.reset(Boundary::new(b"Y")?);
997    /// let body = b"--Y\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--Y--";
998    /// assert!(matches!(parser.parse(body, true)?.event, MultipartEvent::PartStart(_)));
999    /// # Ok::<(), form_net::FormError>(())
1000    /// ```
1001    pub fn reset(&mut self, boundary: Boundary) {
1002        self.wipe_used();
1003        let limits = self.limits;
1004        let policy = self.policy;
1005        self.boundary = boundary;
1006        self.state = State::Preamble;
1007        self.k = 2;
1008        self.bare = 1;
1009        self.flags = 0;
1010        self.token = Token::NotSeen;
1011        self.token_len = 0;
1012        self.charset_len = 0;
1013        self.charset_done = false;
1014        self.scan = BlockScan::default();
1015        self.copied = 0;
1016        self.parts = 0;
1017        self.files = 0;
1018        self.fields = 0;
1019        self.kind = PartKind::Field;
1020        self.part_bytes = 0;
1021        self.text_total = 0;
1022        self.data_start = 0;
1023        self.preamble = 0;
1024        self.epilogue = 0;
1025        self.head_start = 0;
1026        self.epilogue_start = 0;
1027        self.bytes_seen = 0;
1028        self.limits = limits;
1029        self.policy = policy;
1030    }
1031
1032    /// Body bytes consumed so far.
1033    ///
1034    /// # Examples
1035    ///
1036    /// ```
1037    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
1038    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
1039    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--X--";
1040    /// let consumed = parser.parse(body, true)?.consumed;
1041    /// assert_eq!(parser.bytes_seen(), consumed as u64);
1042    /// # Ok::<(), form_net::FormError>(())
1043    /// ```
1044    #[must_use]
1045    pub const fn bytes_seen(&self) -> u64 {
1046        self.bytes_seen
1047    }
1048
1049    /// Parts started so far.
1050    ///
1051    /// # Examples
1052    ///
1053    /// ```
1054    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
1055    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
1056    /// # let body = b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--X--";
1057    /// parser.parse(body, true)?;
1058    /// assert_eq!(parser.parts_seen(), 1);
1059    /// # Ok::<(), form_net::FormError>(())
1060    /// ```
1061    #[must_use]
1062    pub const fn parts_seen(&self) -> u32 {
1063        self.parts
1064    }
1065
1066    /// File parts counted so far.
1067    ///
1068    /// # Examples
1069    ///
1070    /// ```
1071    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
1072    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
1073    /// # let body = b"--X\r\nContent-Disposition: form-data; name=f; filename=a.txt\r\n\r\nhi\r\n--X--";
1074    /// parser.parse(body, true)?;
1075    /// assert_eq!(parser.files_seen(), 1);
1076    /// # Ok::<(), form_net::FormError>(())
1077    /// ```
1078    #[must_use]
1079    pub const fn files_seen(&self) -> u32 {
1080        self.files
1081    }
1082
1083    /// Whether the close delimiter was read.
1084    ///
1085    /// # Examples
1086    ///
1087    /// ```
1088    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
1089    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
1090    /// let mut rest = &b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--X--"[..];
1091    /// assert!(!parser.is_done());
1092    /// while !parser.is_done() {
1093    ///     let step = parser.parse(rest, true)?;
1094    ///     rest = &rest[step.consumed..];
1095    /// }
1096    /// // The close delimiter was read.
1097    /// assert!(rest.is_empty());
1098    /// # Ok::<(), form_net::FormError>(())
1099    /// ```
1100    #[must_use]
1101    pub fn is_done(&self) -> bool {
1102        self.state == State::Epilogue
1103    }
1104
1105    /// The limits the parser was built with.
1106    ///
1107    /// # Examples
1108    ///
1109    /// ```
1110    /// use form_net::{Boundary, Limits, MultipartParser, Policy};
1111    ///
1112    /// let limits = Limits::DEFAULT.with_max_part_header_bytes(1024);
1113    /// let parser = MultipartParser::new(Boundary::new(b"X")?, &limits, &Policy::DEFAULT)?;
1114    /// assert_eq!(parser.limits(), &limits);
1115    /// # Ok::<(), form_net::FormError>(())
1116    /// ```
1117    #[must_use]
1118    pub const fn limits(&self) -> &Limits {
1119        &self.limits
1120    }
1121
1122    /// The policy the parser was built with.
1123    ///
1124    /// # Examples
1125    ///
1126    /// ```
1127    /// use form_net::{Boundary, Limits, MultipartParser, Policy, TokenField};
1128    ///
1129    /// let policy = Policy::DEFAULT.with_token_field(TokenField::new("csrf"));
1130    /// let parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &policy)?;
1131    /// assert_eq!(parser.policy(), &policy);
1132    /// # Ok::<(), form_net::FormError>(())
1133    /// ```
1134    #[must_use]
1135    pub const fn policy(&self) -> &Policy {
1136        &self.policy
1137    }
1138
1139    /// The token field's value, once its part has ended.
1140    ///
1141    /// # Examples
1142    ///
1143    /// ```
1144    /// use form_net::{Boundary, Limits, MultipartParser, Policy, TokenField};
1145    ///
1146    /// let policy = Policy::DEFAULT.with_token_field(TokenField::new("csrf"));
1147    /// let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &policy)?;
1148    /// let mut rest = &b"--X\r\nContent-Disposition: form-data; name=csrf\r\n\r\nabc123\r\n--X--"[..];
1149    /// while !parser.is_done() {
1150    ///     let step = parser.parse(rest, true)?;
1151    ///     rest = &rest[step.consumed..];
1152    /// }
1153    /// assert_eq!(parser.captured_token(), Some("abc123"));
1154    /// # Ok::<(), form_net::FormError>(())
1155    /// ```
1156    #[must_use]
1157    pub fn captured_token(&self) -> Option<&str> {
1158        if self.token != Token::Captured {
1159            return None;
1160        }
1161        let start = self.token_area();
1162        let bytes = self
1163            .buffer
1164            .as_ref()
1165            .get(start..start.saturating_add(usize::from(self.token_len)))?;
1166        core::str::from_utf8(bytes).ok()
1167    }
1168
1169    /// The value of the last complete `_charset_` field.
1170    ///
1171    /// # Examples
1172    ///
1173    /// ```
1174    /// # use form_net::{Boundary, Charset, Limits, MultipartEvent, MultipartParser, PartKind, Policy};
1175    /// # let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
1176    /// let mut rest = &b"--X\r\nContent-Disposition: form-data; name=_charset_\r\n\r\nutf-8\r\n--X--"[..];
1177    /// while !parser.is_done() {
1178    ///     let step = parser.parse(rest, true)?;
1179    ///     rest = &rest[step.consumed..];
1180    /// }
1181    /// assert_eq!(parser.declared_charset(), Some(&b"utf-8"[..]));
1182    /// # Ok::<(), form_net::FormError>(())
1183    /// ```
1184    #[must_use]
1185    pub fn declared_charset(&self) -> Option<&[u8]> {
1186        if !self.charset_done {
1187            return None;
1188        }
1189        let start = self.charset_area();
1190        self.buffer
1191            .as_ref()
1192            .get(start..start.saturating_add(usize::from(self.charset_len)))
1193    }
1194
1195    /// The decoded name of the last head, `len` bytes in the name area.
1196    #[cfg(feature = "alloc")]
1197    pub(crate) fn area_name(&self, len: u32) -> &str {
1198        let start = self.name_area();
1199        let bytes = self
1200            .buffer
1201            .as_ref()
1202            .get(start..start.saturating_add(len as usize))
1203            .unwrap_or(&[]);
1204        core::str::from_utf8(bytes).unwrap_or("")
1205    }
1206
1207    /// The decoded `filename*` of the last head, `len` bytes.
1208    #[cfg(feature = "alloc")]
1209    pub(crate) fn area_filename(&self, len: u32) -> &[u8] {
1210        let start = self.filename_area();
1211        self.buffer
1212            .as_ref()
1213            .get(start..start.saturating_add(len as usize))
1214            .unwrap_or(&[])
1215    }
1216
1217    /// Where the current part's data starts in the body.
1218    #[cfg(feature = "alloc")]
1219    pub(crate) const fn data_start(&self) -> u64 {
1220        self.data_start
1221    }
1222
1223    // Buffer layout: header block, name, filename (AcceptAlone), token, charset.
1224
1225    fn name_area(&self) -> usize {
1226        self.limits.max_part_header_bytes as usize
1227    }
1228
1229    fn filename_area(&self) -> usize {
1230        self.name_area().saturating_add(self.limits.name() as usize)
1231    }
1232
1233    fn token_area(&self) -> usize {
1234        let filename = if matches!(
1235            self.policy.extended_filename,
1236            crate::ExtendedFilenamePolicy::AcceptAlone
1237        ) {
1238            self.limits.filename() as usize
1239        } else {
1240            0
1241        };
1242        self.filename_area().saturating_add(filename)
1243    }
1244
1245    fn charset_area(&self) -> usize {
1246        let token = if self.policy.token_field.is_some() {
1247            usize::from(self.limits.token())
1248        } else {
1249            0
1250        };
1251        self.token_area().saturating_add(token)
1252    }
1253
1254    /// The location of the current part's header block.
1255    fn head_at(&self) -> Location {
1256        Location::in_part(self.parts.checked_sub(1), self.head_start)
1257    }
1258
1259    /// The location of the first data byte past a budget of `limit` of
1260    /// which `used` is spent, in the current part.
1261    fn excess(&self, used: u64, limit: u64) -> Location {
1262        let into_part = self.part_bytes.saturating_add(limit.saturating_sub(used));
1263        Location::in_part(
1264            self.parts.checked_sub(1),
1265            self.data_start.saturating_add(into_part),
1266        )
1267    }
1268
1269    fn at(&self, pos: usize) -> Location {
1270        self.at_offset(self.bytes_seen.saturating_add(pos as u64))
1271    }
1272
1273    /// As [`at`](Self::at), for an offset in the whole body.
1274    fn at_offset(&self, offset: u64) -> Location {
1275        let part = if matches!(self.state, State::Preamble | State::Epilogue) {
1276            None
1277        } else {
1278            self.parts.checked_sub(1)
1279        };
1280        Location::in_part(part, offset)
1281    }
1282
1283    /// Runs the state machine and returns positions only, so callers that
1284    /// own the input for longer (the buffered parser) can slice it
1285    /// themselves.
1286    pub(crate) fn advance(
1287        &mut self,
1288        input: &[u8],
1289        eof: bool,
1290    ) -> Result<(usize, Outcome), FormError> {
1291        if self.state == State::Poisoned {
1292            return Err(FormError::Poisoned);
1293        }
1294        match self.run(input, eof) {
1295            Ok((consumed, outcome)) => {
1296                self.bytes_seen = self.bytes_seen.saturating_add(consumed as u64);
1297                Ok((consumed, outcome))
1298            }
1299            Err(e) => {
1300                self.state = State::Poisoned;
1301                Err(e)
1302            }
1303        }
1304    }
1305
1306    /// An input that crosses `max_body_bytes`: off the hot path. It parses
1307    /// what fits, as a split at the limit would, and refuses only when a byte
1308    /// past the limit is needed, so an error inside the limit is reported
1309    /// the same however the body was split (D-080, D-145).
1310    #[cold]
1311    #[inline(never)]
1312    fn run_over_limit(&mut self, input: &[u8]) -> Result<(usize, Outcome), FormError> {
1313        let over = FormError::limit(Limit::Body, Location::at(self.limits.body()));
1314        let room = self.limits.body().saturating_sub(self.bytes_seen);
1315        if room == 0 {
1316            return Err(over);
1317        }
1318        let within = input.get(..room as usize).unwrap_or(&[]);
1319        let (consumed, outcome) = self.run(within, false)?;
1320        // More input is needed, or the body ended with bytes left past the
1321        // limit (epilogue): either way a byte past it is read.
1322        if matches!(outcome, Outcome::NeedInput | Outcome::End) {
1323            return Err(over);
1324        }
1325        Ok((consumed, outcome))
1326    }
1327
1328    fn run(&mut self, input: &[u8], eof: bool) -> Result<(usize, Outcome), FormError> {
1329        // The comparison saturates, so `u64::MAX` is no limit at all.
1330        if self.bytes_seen.saturating_add(input.len() as u64) > self.limits.body() {
1331            return self.run_over_limit(input);
1332        }
1333        let mut pos = 0usize;
1334        loop {
1335            let hay = input.get(pos..).unwrap_or(&[]);
1336            match self.state {
1337                State::Poisoned => return Err(FormError::Poisoned),
1338                State::Preamble => {
1339                    if let Some(after) = self.preamble_step(hay)? {
1340                        pos = pos.wrapping_add(after);
1341                        self.state = State::AfterDelimiter(After::Start);
1342                        continue;
1343                    }
1344                    if eof {
1345                        return Err(FormError::syntax(
1346                            SyntaxError::NoInitialDelimiter,
1347                            self.at(input.len()),
1348                        ));
1349                    }
1350                    return Ok((input.len(), Outcome::NeedInput));
1351                }
1352                State::AfterDelimiter(sub) => {
1353                    let Some(&c) = hay.first() else {
1354                        return self.need_input(input.len(), eof);
1355                    };
1356                    pos = pos.wrapping_add(1);
1357                    let at = self.at(pos);
1358                    self.state = match (sub, c) {
1359                        (After::Start, b'-') => State::AfterDelimiter(After::Dash),
1360                        (After::Dash, b'-') => {
1361                            self.state = State::Epilogue;
1362                            self.epilogue_start = self.bytes_seen.saturating_add(pos as u64);
1363                            return Ok((pos, Outcome::End));
1364                        }
1365                        (After::Start, b' ' | b'\t') => {
1366                            if self.limits.max_padding_bytes == 0 {
1367                                return Err(FormError::limit(Limit::Padding, at));
1368                            }
1369                            State::AfterDelimiter(After::Padding(1))
1370                        }
1371                        (After::Padding(n), b' ' | b'\t') => {
1372                            if n >= self.limits.max_padding_bytes {
1373                                return Err(FormError::limit(Limit::Padding, at));
1374                            }
1375                            State::AfterDelimiter(After::Padding(n.saturating_add(1)))
1376                        }
1377                        (After::Start | After::Padding(_), b'\r') => {
1378                            State::AfterDelimiter(After::Cr)
1379                        }
1380                        (After::Cr, b'\n') => {
1381                            self.parts = self.parts.saturating_add(1);
1382                            if self.parts > self.limits.max_parts {
1383                                return Err(FormError::limit(Limit::Parts, self.at(pos)));
1384                            }
1385                            self.scan = BlockScan::default();
1386                            self.copied = 0;
1387                            self.head_start = self.bytes_seen.saturating_add(pos as u64);
1388                            State::Headers
1389                        }
1390                        (After::Start | After::Padding(_), b'\n') => {
1391                            return Err(FormError::syntax(SyntaxError::BareLineFeed, at));
1392                        }
1393                        _ => return Err(FormError::syntax(SyntaxError::BoundaryInContent, at)),
1394                    };
1395                }
1396                State::Headers => {
1397                    let at = self.head_at();
1398                    match self.scan.feed(hay, &self.limits, at)? {
1399                        Some(end) => {
1400                            let source = if self.copied == 0 {
1401                                Source::Input(pos)
1402                            } else {
1403                                self.copy_header(hay.get(..end).unwrap_or(&[]), at)?;
1404                                Source::Buffer
1405                            };
1406                            let block_start_in_input = pos;
1407                            pos = pos.wrapping_add(end);
1408                            let facts =
1409                                self.read_head(input, source, block_start_in_input, end, at)?;
1410                            let (is_token, is_charset) = {
1411                                let block = self.block(&facts, source, input);
1412                                let name = self.name_bytes(&facts, block);
1413                                let token = self
1414                                    .policy
1415                                    .token_field
1416                                    .is_some_and(|t| name == t.name().as_bytes());
1417                                (token, name == b"_charset_")
1418                            };
1419                            self.start_part(&facts, is_token, is_charset, at)?;
1420                            self.data_start = self.bytes_seen.saturating_add(pos as u64);
1421                            return Ok((pos, Outcome::PartStart(facts, source)));
1422                        }
1423                        None => {
1424                            self.copy_header(hay, at)?;
1425                            return self.need_input(input.len(), eof);
1426                        }
1427                    }
1428                }
1429                State::Body => {
1430                    if hay.is_empty() {
1431                        return self.need_input(input.len(), eof);
1432                    }
1433                    match self.body_step(hay, pos, input.len(), eof)? {
1434                        BodyStep::Emit(consumed, outcome) => return Ok((consumed, outcome)),
1435                        BodyStep::Continue(next) => pos = next,
1436                    }
1437                }
1438                State::EndOfPart => {
1439                    let summary = self.end_part(self.at(pos))?;
1440                    self.state = State::AfterDelimiter(After::Start);
1441                    return Ok((pos, Outcome::PartEnd(summary)));
1442                }
1443                State::Epilogue => {
1444                    self.epilogue = self.epilogue.saturating_add(hay.len() as u64);
1445                    if self.epilogue > self.limits.epilogue() {
1446                        let at = self.epilogue_start.saturating_add(self.limits.epilogue());
1447                        return Err(FormError::limit(Limit::Epilogue, Location::at(at)));
1448                    }
1449                    return Ok((input.len(), Outcome::End));
1450                }
1451            }
1452        }
1453    }
1454
1455    fn need_input(&self, len: usize, eof: bool) -> Result<(usize, Outcome), FormError> {
1456        if eof {
1457            Err(FormError::syntax(SyntaxError::Truncated, self.at(len)))
1458        } else {
1459            Ok((len, Outcome::NeedInput))
1460        }
1461    }
1462
1463    /// The refusal for `--boundary` after a lone CR or LF, ending at `after`
1464    /// in a `hay` that starts at `pos` in the input (D-113).
1465    /// The location is the line break's, in whichever chunk it came.
1466    fn bare_break(&self, after: usize, pos: usize) -> FormError {
1467        let end = self
1468            .bytes_seen
1469            .saturating_add(pos.wrapping_add(after) as u64);
1470        let bare = self.boundary.len().saturating_sub(1) as u64;
1471        FormError::syntax(
1472            SyntaxError::BoundaryInContent,
1473            self.at_offset(end.saturating_sub(bare)),
1474        )
1475    }
1476
1477    /// Scans the preamble. Returns the index in `hay` just after the first
1478    /// delimiter, or `None` when all of `hay` was consumed.
1479    fn preamble_step(&mut self, hay: &[u8]) -> Result<Option<usize>, FormError> {
1480        let len = self.boundary.len() as u64;
1481        // A delimiter must end within max_preamble_bytes + its own length.
1482        let budget = self.limits.preamble().saturating_add(len);
1483        let room = usize::try_from(budget.saturating_sub(self.preamble)).unwrap_or(usize::MAX);
1484        let window = hay.get(..room.min(hay.len())).unwrap_or(hay);
1485        let (k, m, found) = self
1486            .boundary
1487            .run(usize::from(self.k), usize::from(self.bare), window);
1488        self.k = k as u8;
1489        self.bare = m as u8;
1490        match found {
1491            Hit::BareBreak(after) => Err(self.bare_break(after, 0)),
1492            Hit::Delimiter(after) => {
1493                // Real bytes up to the end of the delimiter; a delimiter that
1494                // includes the two virtual bytes (CRLF) starts the body.
1495                let end = self.preamble.saturating_add(after as u64);
1496                let preamble = end.saturating_sub(len);
1497                if preamble > self.limits.preamble() {
1498                    return Err(FormError::limit(
1499                        Limit::Preamble,
1500                        Location::at(self.limits.preamble()),
1501                    ));
1502                }
1503                self.k = 0;
1504                self.bare = 0;
1505                Ok(Some(after))
1506            }
1507            Hit::None => {
1508                self.preamble = self.preamble.saturating_add(window.len() as u64);
1509                if window.len() < hay.len() || self.preamble >= budget {
1510                    return Err(FormError::limit(
1511                        Limit::Preamble,
1512                        Location::at(self.limits.preamble()),
1513                    ));
1514                }
1515                Ok(None)
1516            }
1517        }
1518    }
1519
1520    fn copy_header(&mut self, bytes: &[u8], at: Location) -> Result<(), FormError> {
1521        let start = self.copied as usize;
1522        let end = start.saturating_add(bytes.len());
1523        if end > self.limits.max_part_header_bytes as usize {
1524            return Err(FormError::limit(Limit::PartHeaderBytes, at));
1525        }
1526        match self.buffer.as_mut().get_mut(start..end) {
1527            Some(dst) => dst.copy_from_slice(bytes),
1528            None => return Err(FormError::limit(Limit::PartHeaderBytes, at)),
1529        }
1530        self.copied = end as u32;
1531        self.dirty = self.dirty.max(self.copied);
1532        Ok(())
1533    }
1534
1535    fn read_head(
1536        &mut self,
1537        input: &[u8],
1538        source: Source,
1539        start: usize,
1540        end: usize,
1541        at: Location,
1542    ) -> Result<HeadFacts, FormError> {
1543        let name_area = self.name_area();
1544        let filename_area = self.filename_area();
1545        let filename_end = self.token_area();
1546        let limits = self.limits;
1547        let policy = self.policy;
1548        let copied = self.copied as usize;
1549        let block_len = match source {
1550            Source::Input(_) => end,
1551            Source::Buffer => copied,
1552        };
1553        self.dirty = self.dirty.max(u32::try_from(block_len).unwrap_or(u32::MAX));
1554        let buf = self.buffer.as_mut();
1555        let (head, rest) = buf.split_at_mut(name_area.min(buf.len()));
1556        let (name, rest) =
1557            rest.split_at_mut(filename_area.saturating_sub(name_area).min(rest.len()));
1558        let filename = rest
1559            .get_mut(..filename_end.saturating_sub(filename_area))
1560            .unwrap_or(&mut []);
1561        let block = match source {
1562            Source::Input(_) => input.get(start..start.saturating_add(end)).unwrap_or(&[]),
1563            Source::Buffer => head.get(..copied).unwrap_or(&[]),
1564        };
1565        read_block(block, &limits, &policy, Areas { name, filename }, at)
1566    }
1567
1568    /// The budgets and rules that apply when a part starts.
1569    fn start_part(
1570        &mut self,
1571        facts: &HeadFacts,
1572        is_token: bool,
1573        is_charset: bool,
1574        at: Location,
1575    ) -> Result<(), FormError> {
1576        self.state = State::Body;
1577        self.k = 0;
1578        // The data starts after the blank line's LF: `--boundary` right
1579        // there reads as an empty part to an RFC 2046 reader (D-113).
1580        self.bare = 1;
1581        self.flags = 0;
1582        self.kind = facts.kind;
1583        self.part_bytes = 0;
1584        match facts.kind {
1585            PartKind::Field => {
1586                self.fields = self.fields.saturating_add(1);
1587                if self.fields > self.limits.max_fields {
1588                    return Err(FormError::limit(Limit::Fields, at));
1589                }
1590                if is_token {
1591                    if self.token != Token::NotSeen {
1592                        return Err(FormError::policy(PolicyRefusal::DuplicateToken, at));
1593                    }
1594                    self.token = Token::Capturing;
1595                    self.token_len = 0;
1596                    self.flags |= IS_TOKEN;
1597                }
1598                if is_charset {
1599                    self.flags |= IS_CHARSET;
1600                    self.charset_len = 0;
1601                    self.charset_done = false;
1602                }
1603            }
1604            PartKind::File => {
1605                let empty = matches!(facts.filename, Some((Text::Block(span), _)) if span.len == 0)
1606                    || matches!(facts.filename, Some((Text::Area(0), _)));
1607                if empty && self.policy.empty_files == EmptyFilePolicy::Skip {
1608                    self.flags |= DEFERRED;
1609                } else {
1610                    self.count_file(at)?;
1611                }
1612            }
1613        }
1614        Ok(())
1615    }
1616
1617    /// The block of a head, wherever it is.
1618    fn block<'a>(&'a self, facts: &HeadFacts, source: Source, input: &'a [u8]) -> &'a [u8] {
1619        let len = facts.block_len as usize;
1620        match source {
1621            Source::Input(start) => input.get(start..start.saturating_add(len)).unwrap_or(&[]),
1622            Source::Buffer => self.buffer.as_ref().get(..len).unwrap_or(&[]),
1623        }
1624    }
1625
1626    /// The decoded name of a head.
1627    fn name_bytes<'a>(&'a self, facts: &HeadFacts, block: &'a [u8]) -> &'a [u8] {
1628        match facts.name {
1629            Text::Block(span) => span.get(block),
1630            Text::Area(len) => {
1631                let start = self.name_area();
1632                self.buffer
1633                    .as_ref()
1634                    .get(start..start.saturating_add(len as usize))
1635                    .unwrap_or(&[])
1636            }
1637        }
1638    }
1639
1640    /// The borrowed view of a head.
1641    fn head_view<'p>(&'p self, facts: &HeadFacts, source: Source, input: &'p [u8]) -> PartHead<'p> {
1642        let block = self.block(facts, source, input);
1643        let name = core::str::from_utf8(self.name_bytes(facts, block)).unwrap_or("");
1644        let filename = facts.filename.map(|(text, origin)| {
1645            let raw = match text {
1646                Text::Block(span) => span.get(block),
1647                Text::Area(len) => {
1648                    let start = self.filename_area();
1649                    self.buffer
1650                        .as_ref()
1651                        .get(start..start.saturating_add(len as usize))
1652                        .unwrap_or(&[])
1653                }
1654            };
1655            FileName::new(raw, origin)
1656        });
1657        PartHead {
1658            index: self.parts.saturating_sub(1),
1659            block,
1660            name,
1661            name_raw: facts.name_raw.get(block),
1662            kind: facts.kind,
1663            filename,
1664            content_type: facts.content_type.map(|span| span.get(block)),
1665            charset: facts.charset,
1666        }
1667    }
1668
1669    /// Turns positions into borrowed events.
1670    fn view<'p>(&'p self, outcome: Outcome, input: &'p [u8]) -> MultipartEvent<'p> {
1671        match outcome {
1672            Outcome::PartStart(facts, source) => {
1673                MultipartEvent::PartStart(self.head_view(&facts, source, input))
1674            }
1675            Outcome::DataInput(start, end) => {
1676                MultipartEvent::Data(input.get(start..end).unwrap_or(&[]))
1677            }
1678            Outcome::DataDelimiter(n) => {
1679                MultipartEvent::Data(self.boundary.delimiter().get(..n).unwrap_or(&[]))
1680            }
1681            Outcome::PartEnd(summary) => MultipartEvent::PartEnd(summary),
1682            Outcome::End => MultipartEvent::End,
1683            Outcome::NeedInput => MultipartEvent::NeedInput,
1684        }
1685    }
1686
1687    fn count_file(&mut self, at: Location) -> Result<(), FormError> {
1688        self.files = self.files.saturating_add(1);
1689        if self.files > self.limits.max_files {
1690            return Err(FormError::limit(Limit::Files, at));
1691        }
1692        if let Some(t) = self.policy.token_field {
1693            if t.placement() == TokenPlacement::BeforeFirstFile && self.token != Token::Captured {
1694                return Err(FormError::policy(PolicyRefusal::TokenFieldLate, at));
1695            }
1696        }
1697        Ok(())
1698    }
1699
1700    /// Checks budgets for `n` more data bytes of the current part, and
1701    /// captures the token or `_charset_` value.
1702    fn take_data(&mut self, bytes: &[u8]) -> Result<(), FormError> {
1703        let n = bytes.len() as u64;
1704        if n == 0 {
1705            return Ok(());
1706        }
1707        if self.flags & DEFERRED != 0 {
1708            self.flags &= !DEFERRED;
1709            let at = Location::in_part(self.parts.checked_sub(1), self.data_start);
1710            self.count_file(at)?;
1711        }
1712        let total = self.part_bytes.saturating_add(n);
1713        match self.kind {
1714            PartKind::File => {
1715                let limit = self.limits.file();
1716                if total > limit {
1717                    let at = self.excess(self.part_bytes, limit);
1718                    return Err(FormError::limit(Limit::FileSize, at));
1719                }
1720            }
1721            PartKind::Field => {
1722                let limit = u64::from(self.limits.value());
1723                if total > limit {
1724                    let at = self.excess(self.part_bytes, limit);
1725                    return Err(FormError::limit(Limit::ValueLength, at));
1726                }
1727                let text = self.text_total.saturating_add(n);
1728                let limit = self.limits.text();
1729                if text > limit {
1730                    let at = self.excess(self.text_total, limit);
1731                    return Err(FormError::limit(Limit::TextTotal, at));
1732                }
1733                self.text_total = text;
1734            }
1735        }
1736        if self.flags & IS_TOKEN != 0 {
1737            let start = self
1738                .token_area()
1739                .saturating_add(usize::from(self.token_len));
1740            let end = start.saturating_add(bytes.len());
1741            let limit = u64::from(self.limits.token());
1742            let at = self.excess(u64::from(self.token_len), limit);
1743            if end
1744                > self
1745                    .token_area()
1746                    .saturating_add(usize::from(self.limits.token()))
1747            {
1748                return Err(FormError::limit(Limit::TokenLength, at));
1749            }
1750            match self.buffer.as_mut().get_mut(start..end) {
1751                Some(dst) => dst.copy_from_slice(bytes),
1752                None => return Err(FormError::limit(Limit::TokenLength, at)),
1753            }
1754            self.token_len = self.token_len.saturating_add(bytes.len() as u16);
1755        }
1756        if self.flags & IS_CHARSET != 0 {
1757            let start = self
1758                .charset_area()
1759                .saturating_add(usize::from(self.charset_len));
1760            let end = start.saturating_add(bytes.len());
1761            let at = self.excess(u64::from(self.charset_len), CHARSET_CAPTURE as u64);
1762            if end > self.charset_area().saturating_add(CHARSET_CAPTURE) {
1763                return Err(FormError::encoding(EncodingError::UnsupportedCharset, at));
1764            }
1765            match self.buffer.as_mut().get_mut(start..end) {
1766                Some(dst) => dst.copy_from_slice(bytes),
1767                None => return Err(FormError::encoding(EncodingError::UnsupportedCharset, at)),
1768            }
1769            self.charset_len = self.charset_len.saturating_add(bytes.len() as u8);
1770        }
1771        self.part_bytes = total;
1772        Ok(())
1773    }
1774
1775    fn end_part(&mut self, at: Location) -> Result<PartSummary, FormError> {
1776        if self.flags & IS_TOKEN != 0 {
1777            let start = self.token_area();
1778            let bytes = self
1779                .buffer
1780                .as_ref()
1781                .get(start..start.saturating_add(usize::from(self.token_len)))
1782                .unwrap_or(&[]);
1783            if core::str::from_utf8(bytes).is_err() {
1784                return Err(FormError::encoding(EncodingError::InvalidUtf8, at));
1785            }
1786            self.token = Token::Captured;
1787        }
1788        if self.flags & IS_CHARSET != 0 {
1789            self.charset_done = true;
1790        }
1791        let summary = PartSummary {
1792            index: self.parts.saturating_sub(1),
1793            kind: self.kind,
1794            bytes: self.part_bytes,
1795            skipped: self.flags & SKIPPING != 0,
1796        };
1797        self.flags = 0;
1798        self.k = 0;
1799        Ok(summary)
1800    }
1801
1802    /// One step in a part's data. `pos` is where `hay` starts in the input.
1803    fn body_step(
1804        &mut self,
1805        hay: &[u8],
1806        pos: usize,
1807        input_len: usize,
1808        eof: bool,
1809    ) -> Result<BodyStep, FormError> {
1810        let len = self.boundary.len();
1811        let k0 = usize::from(self.k);
1812        if k0 > 0 {
1813            // Bytes from earlier chunks that matched the start of the
1814            // delimiter: resolve them before anything else. The delimiter
1815            // has one CR, so the match either goes on or all of it is over.
1816            let need = self.boundary.delimiter().get(k0..).unwrap_or(&[]);
1817            let (need_len, n) = (need.len(), super::boundary::shared(need, hay));
1818            if n == need_len {
1819                // The delimiter started inside the held bytes.
1820                self.k = 0;
1821                self.bare = 0;
1822                self.state = State::EndOfPart;
1823                return self.emit_delimiter_bytes(0, pos.wrapping_add(n));
1824            }
1825            if n < hay.len() {
1826                // Every held byte is data; scan the input again from 0,
1827                // with the bare-break state the held bytes leave: they
1828                // are a CR, a CR LF, or a CR LF and dashes (D-113).
1829                self.k = 0;
1830                self.bare = k0.max(2).wrapping_sub(1) as u8;
1831                return self.emit_delimiter_bytes(k0, pos);
1832            }
1833            // All of `hay` extended the partial match.
1834            if eof {
1835                // Every byte is data now: charge it first, as a split body
1836                // charges it before it learns the body ended (D-145).
1837                let boundary = self.boundary;
1838                self.take_data(boundary.delimiter().get(..k0).unwrap_or(&[]))?;
1839                self.take_data(hay)?;
1840                return Err(FormError::syntax(
1841                    SyntaxError::Truncated,
1842                    self.at(input_len),
1843                ));
1844            }
1845            self.k = k0.saturating_add(n) as u8;
1846            return self.emit_delimiter_bytes(0, input_len);
1847        }
1848        let (k, m, found) = self.boundary.run(0, usize::from(self.bare), hay);
1849        match found {
1850            Hit::BareBreak(after) => {
1851                // The data before the break is charged first, as a split
1852                // before the break would charge it (D-145).
1853                let start = after.saturating_sub(len.saturating_sub(1));
1854                self.take_data(hay.get(..start).unwrap_or(&[]))?;
1855                Err(self.bare_break(after, pos))
1856            }
1857            Hit::Delimiter(after) => {
1858                let data = after.saturating_sub(len);
1859                self.k = 0;
1860                self.bare = 0;
1861                self.state = State::EndOfPart;
1862                let bytes = hay.get(..data).unwrap_or(&[]);
1863                self.emit_input_bytes(bytes, pos, pos.wrapping_add(data), pos.wrapping_add(after))
1864            }
1865            Hit::None => {
1866                if eof {
1867                    // As above: the rest is data, charged before `Truncated`.
1868                    self.take_data(hay)?;
1869                    return Err(FormError::syntax(
1870                        SyntaxError::Truncated,
1871                        self.at(input_len),
1872                    ));
1873                }
1874                self.k = k as u8;
1875                self.bare = m as u8;
1876                let data_end = hay.len().saturating_sub(k);
1877                let bytes = hay.get(..data_end).unwrap_or(&[]);
1878                self.emit_input_bytes(bytes, pos, pos.wrapping_add(data_end), input_len)
1879            }
1880        }
1881    }
1882
1883    /// Emits `delimiter[..n]` as data (or skips it), consuming up to
1884    /// `consumed`.
1885    fn emit_delimiter_bytes(&mut self, n: usize, consumed: usize) -> Result<BodyStep, FormError> {
1886        let boundary = self.boundary;
1887        let bytes = boundary.delimiter().get(..n).unwrap_or(&[]);
1888        self.take_data(bytes)?;
1889        if n == 0 || self.flags & SKIPPING != 0 {
1890            return Ok(BodyStep::Continue(consumed));
1891        }
1892        Ok(BodyStep::Emit(consumed, Outcome::DataDelimiter(n)))
1893    }
1894
1895    /// Emits `input[start..end]` as data (or skips it), consuming up to
1896    /// `consumed`.
1897    fn emit_input_bytes(
1898        &mut self,
1899        bytes: &[u8],
1900        start: usize,
1901        end: usize,
1902        consumed: usize,
1903    ) -> Result<BodyStep, FormError> {
1904        self.take_data(bytes)?;
1905        if start == end || self.flags & SKIPPING != 0 {
1906            return Ok(BodyStep::Continue(consumed));
1907        }
1908        Ok(BodyStep::Emit(consumed, Outcome::DataInput(start, end)))
1909    }
1910}
1911
1912/// What a body step did.
1913enum BodyStep {
1914    Emit(usize, Outcome),
1915    Continue(usize),
1916}
1917
1918impl<B: AsMut<[u8]> + AsRef<[u8]>> MultipartParser<B> {
1919    /// Wipes every byte the parser wrote into its buffer, and nothing more:
1920    /// a buffer of the default size is 9.6 KiB, and a login form writes a
1921    /// few hundred bytes of it (D-103).
1922    fn wipe_used(&mut self) {
1923        let used = self.dirty as usize;
1924        let regions = [
1925            (0, used.min(self.name_area())),
1926            (
1927                self.name_area(),
1928                used.min(self.filename_area().saturating_sub(self.name_area())),
1929            ),
1930            (
1931                self.filename_area(),
1932                used.min(self.token_area().saturating_sub(self.filename_area())),
1933            ),
1934            (self.token_area(), usize::from(self.token_len)),
1935            // The whole capture area: a second, shorter `_charset_` value
1936            // resets the length over the tail of the first (found by review).
1937            (self.charset_area(), CHARSET_CAPTURE),
1938        ];
1939        let buf = self.buffer.as_mut();
1940        for (start, len) in regions {
1941            if let Some(region) = buf.get_mut(start..start.saturating_add(len)) {
1942                crate::wipe::wipe(region);
1943            }
1944        }
1945        self.dirty = 0;
1946    }
1947}
1948
1949impl<B: AsMut<[u8]> + AsRef<[u8]>> Drop for MultipartParser<B> {
1950    fn drop(&mut self) {
1951        self.wipe_used();
1952    }
1953}
1954
1955#[cfg(test)]
1956mod tests {
1957    use super::*;
1958
1959    /// D-103: the wipe covers every byte the parser wrote. With a caller
1960    /// buffer the result is visible: after a body that writes every area
1961    /// (header blocks, an escaped name, a decoded `filename*`, the token,
1962    /// `_charset_`), dropping or resetting leaves the buffer all zeros.
1963    #[test]
1964    fn test_wipe_covers_every_area_written() {
1965        let policy = Policy::DEFAULT
1966            .with_extended_filename(crate::ExtendedFilenamePolicy::AcceptAlone)
1967            .with_token_field(crate::TokenField::new("csrf"));
1968        let limits = Limits::DEFAULT.with_max_part_header_bytes(512);
1969        let long = "x".repeat(300);
1970        let body = alloc::format!(
1971            "--X\r\nContent-Disposition: form-data; name=csrf\r\n\r\nsecret-token-value\r\n\
1972             --X\r\nContent-Disposition: form-data; name=_charset_\r\n\r\nUTF-8\r\n\
1973             --X\r\nContent-Disposition: form-data; name=\"pass%22word\"\r\nX-Pad: {long}\r\n\r\nhunter2\r\n\
1974             --X\r\nContent-Disposition: form-data; name=f; filename*=UTF-8''caf%C3%A9.txt\r\n\r\nfile\r\n--X--"
1975        );
1976        // Two `_charset_` values, the second shorter: the first one's tail
1977        // must not survive (found by review).
1978        let body = body.replace(
1979            "name=_charset_\r\n\r\nUTF-8\r\n",
1980            "name=_charset_\r\n\r\nunicode-1-1-utf-8\r\n--X\r\nContent-Disposition: form-data; name=_charset_\r\n\r\nutf8\r\n",
1981        );
1982        assert!(body.contains("unicode-1-1-utf-8"));
1983        for split in [usize::MAX, 7, 1] {
1984            let mut buf = alloc::vec![0u8; limits.multipart_buffer_len(&policy)];
1985            {
1986                let mut p = MultipartParser::with_buffer(
1987                    Boundary::new(b"X").unwrap(),
1988                    &limits,
1989                    &policy,
1990                    &mut buf[..],
1991                )
1992                .unwrap();
1993                let bytes = body.as_bytes();
1994                let chunks: alloc::vec::Vec<&[u8]> = bytes.chunks(split.min(bytes.len())).collect();
1995                let mut ended = false;
1996                for (i, c) in chunks.iter().enumerate() {
1997                    let last = i + 1 == chunks.len();
1998                    let mut rest = *c;
1999                    loop {
2000                        let step = p.parse(rest, last).unwrap();
2001                        rest = &rest[step.consumed..];
2002                        match step.event {
2003                            MultipartEvent::NeedInput => break,
2004                            MultipartEvent::End => {
2005                                ended = true;
2006                                break;
2007                            }
2008                            _ => {}
2009                        }
2010                    }
2011                }
2012                assert!(ended);
2013                assert_eq!(p.captured_token(), Some("secret-token-value"));
2014            }
2015            assert!(
2016                buf.iter().all(|&b| b == 0),
2017                "split {split}: bytes left at {:?}",
2018                buf.iter().position(|&b| b != 0)
2019            );
2020        }
2021    }
2022
2023    /// Feeds `body` whole and returns the first error, or `None` at `End`.
2024    #[cfg(feature = "alloc")]
2025    fn run(p: &mut MultipartParser<alloc::vec::Vec<u8>>, body: &[u8]) -> Option<FormError> {
2026        let mut rest = body;
2027        loop {
2028            match p.parse(rest, true) {
2029                Err(e) => return Some(e),
2030                Ok(step) => {
2031                    rest = &rest[step.consumed..];
2032                    if matches!(step.event, MultipartEvent::End) {
2033                        return None;
2034                    }
2035                }
2036            }
2037        }
2038    }
2039
2040    /// T-28, through the counter seam: counters set near `u64::MAX` never
2041    /// wrap. Under finite limits they still refuse; under `u64::MAX` limits
2042    /// they saturate and positions stay at the maximum.
2043    #[cfg(feature = "alloc")]
2044    #[test]
2045    fn test_attack_t28_counters_near_u64_max_never_wrap() {
2046        let body = b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\nvalue\r\n--X--";
2047        let new = |limits: &Limits| {
2048            MultipartParser::new(Boundary::new(b"X").unwrap(), limits, &Policy::DEFAULT).unwrap()
2049        };
2050        let mut p = new(&Limits::DEFAULT);
2051        p.bytes_seen = u64::MAX - 4;
2052        assert!(matches!(
2053            run(&mut p, body),
2054            Some(FormError::Limit {
2055                limit: crate::error::Limit::Body,
2056                ..
2057            })
2058        ));
2059
2060        let mut p = new(&Limits::DEFAULT);
2061        p.text_total = u64::MAX - 2;
2062        assert!(matches!(
2063            run(&mut p, body),
2064            Some(FormError::Limit {
2065                limit: crate::error::Limit::TextTotal,
2066                ..
2067            })
2068        ));
2069
2070        let open = Limits::DEFAULT
2071            .with_max_body_bytes(u64::MAX)
2072            .with_max_text_bytes(u64::MAX);
2073        let mut p = new(&open);
2074        p.bytes_seen = u64::MAX - 4;
2075        assert!(run(&mut p, body).is_none());
2076        assert_eq!(p.bytes_seen, u64::MAX);
2077    }
2078
2079    #[test]
2080    fn test_parser_size_is_bounded() {
2081        // NFR-18 as measured: the boundary and its matcher table are 149 of
2082        // these bytes; the buffer is separate.
2083        assert!(core::mem::size_of::<MultipartParser<&mut [u8]>>() <= 384);
2084        assert!(core::mem::size_of::<Boundary>() <= 150);
2085    }
2086
2087    #[cfg(feature = "alloc")]
2088    #[test]
2089    fn test_debug_never_shows_data_or_file_names() {
2090        let body = b"--X\r\nContent-Disposition: form-data; name=f; filename=\"secret.pdf\"\r\n\r\nhunter2\r\n--X--";
2091        let mut p = MultipartParser::new(
2092            Boundary::new(b"X").unwrap(),
2093            &Limits::DEFAULT,
2094            &Policy::DEFAULT,
2095        )
2096        .unwrap();
2097        let mut rest: &[u8] = body;
2098        let mut seen = alloc::string::String::new();
2099        loop {
2100            let step = p.parse(rest, true).unwrap();
2101            rest = &rest[step.consumed..];
2102            if let MultipartEvent::PartStart(head) = &step.event {
2103                seen.push_str(&alloc::format!("{:?}", head.headers()));
2104            }
2105            seen.push_str(&alloc::format!("{step:?}"));
2106            if matches!(step.event, MultipartEvent::End) {
2107                break;
2108            }
2109        }
2110        assert!(seen.contains("Data(7 bytes)"), "{seen}");
2111        assert!(
2112            !seen.contains("hunter2") && !seen.contains("secret"),
2113            "{seen}"
2114        );
2115    }
2116
2117    #[test]
2118    fn test_charset_labels() {
2119        assert_eq!(Charset::from_label(b"UTF-8"), Charset::Utf8);
2120        assert_eq!(Charset::from_label(b"us-ascii"), Charset::Ascii);
2121        assert_eq!(Charset::from_label(b"utf8"), Charset::Other);
2122    }
2123}