Skip to main content

MultipartParser

Struct MultipartParser 

Source
pub struct MultipartParser<B: AsMut<[u8]> + AsRef<[u8]>> { /* private fields */ }
Expand description

The sans-IO multipart/form-data parser.

Feed it bytes as they arrive, in chunks of any size split at any byte; it returns one MultipartEvent per call and how many bytes it consumed. The events are identical for every split of a body that parses; for a body that fails, the error is identical, though a split body may emit data before it that a whole one does not. It never allocates after construction. The delimiter search skips 32 bytes at a time to a line break followed by - and compares the delimiter there a word at a time; bytes that may start a delimiter at a chunk’s end are carried and scanned again with the next chunk (at most 73 per boundary), so the search stays linear. The streaming automaton (a Knuth-Morris-Pratt table) only carries that state between chunks.

The buffer holds the header block, the decoded field name, the decoded filename* (under AcceptAlone), the token, and the _charset_ value: Limits::multipart_buffer_len bytes. It is wiped on reset and on drop.

§Examples

use form_net::{MultipartEvent, FormKind, Limits, MultipartParser, Policy};

let content_type = b"multipart/form-data; boundary=X";
let body = b"--X\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nHoliday\r\n--X--\r\n";
let FormKind::Multipart(boundary) = FormKind::detect(content_type)? else { unreachable!() };
let mut parser = MultipartParser::new(boundary, &Limits::DEFAULT, &Policy::DEFAULT)?;

let mut events = Vec::new();
let mut chunks = body.chunks(7).peekable();     // any split gives the same events
while let Some(chunk) = chunks.next() {
    let last = chunks.peek().is_none();
    let mut rest = chunk;
    loop {
        let step = parser.parse(rest, last)?;
        rest = &rest[step.consumed..];
        match step.event {
            MultipartEvent::PartStart(head) => events.push(format!("start {}", head.name())),
            MultipartEvent::Data(bytes) => events.push(format!("data {}", bytes.len())),
            MultipartEvent::PartEnd(summary) => events.push(format!("end {}", summary.bytes)),
            MultipartEvent::End => break,
            MultipartEvent::NeedInput => break,
            _ => {}
        }
    }
}
assert!(parser.is_done());
assert_eq!(events.first().map(String::as_str), Some("start title"));
assert_eq!(events.last().map(String::as_str), Some("end 7"));

Implementations§

Source§

impl MultipartParser<Vec<u8>>

Source

pub fn new( boundary: Boundary, limits: &Limits, policy: &Policy, ) -> Result<Self, FormError>

Available on crate feature alloc only.

A parser with its own buffer of Limits::multipart_buffer_len bytes, allocated once.

§Errors

InvalidLimits from validating the limits with the policy.

§Examples
use form_net::{Boundary, Limits, MultipartParser, Policy};

let parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &Policy::DEFAULT)?;
assert_eq!(parser.bytes_seen(), 0);
Source§

impl<B: AsMut<[u8]> + AsRef<[u8]>> MultipartParser<B>

Source

pub fn with_buffer( boundary: Boundary, limits: &Limits, policy: &Policy, buffer: B, ) -> Result<Self, FormError>

A parser over a buffer the caller provides; it never allocates.

§Errors

InvalidLimits; BufferTooSmall when buffer is shorter than Limits::multipart_buffer_len.

§Examples
use form_net::{Boundary, Limits, MultipartParser, Policy};

const LIMITS: Limits = Limits::DEFAULT.with_max_part_header_bytes(1024);
const LEN: usize = LIMITS.multipart_buffer_len(&Policy::DEFAULT);
let mut buffer = [0u8; LEN];
let parser = MultipartParser::with_buffer(Boundary::new(b"X")?, &LIMITS, &Policy::DEFAULT, &mut buffer[..])?;
Source

pub fn parse<'p>( &'p mut self, input: &'p [u8], eof: bool, ) -> Result<MultipartStep<'p>, FormError>

Consumes a prefix of input and returns one event. eof = true says input ends the body.

§Errors

Every multipart error (see the crate’s docs/API.md); Poisoned after any error until reset.

§Examples
let body = b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--X--";
// The first 10 bytes are not a whole header block: give more.
let step = parser.parse(&body[..10], false)?;
assert!(matches!(step.event, MultipartEvent::NeedInput));
let rest = &body[step.consumed..];
let step = parser.parse(rest, true)?;
assert!(matches!(step.event, MultipartEvent::PartStart(head) if head.name() == "a"));
Source

pub fn skip_part(&mut self)

Discards the rest of the current part: its bytes are consumed and counted against the budgets but produce no Data events, and its summary has skipped = true. Outside a part it does nothing.

§Examples
let step = parser.parse(body, true)?;
let mut rest = &body[step.consumed..];
parser.skip_part();
let summary = loop {
    let step = parser.parse(rest, true)?;
    rest = &rest[step.consumed..];
    assert!(!matches!(step.event, MultipartEvent::Data(_)));
    if let MultipartEvent::PartEnd(summary) = step.event {
        break summary;
    }
};
assert!(summary.skipped);
Source

pub fn reset(&mut self, boundary: Boundary)

Returns the parser to its initial state for a new body, wipes its buffer, and clears the poisoned state. It never allocates.

§Examples
assert!(parser.parse(b"no delimiter here", true).is_err());
// Poisoned until reset; reset also takes the next body's boundary.
assert!(parser.parse(b"", true).is_err());
parser.reset(Boundary::new(b"Y")?);
let body = b"--Y\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--Y--";
assert!(matches!(parser.parse(body, true)?.event, MultipartEvent::PartStart(_)));
Source

pub const fn bytes_seen(&self) -> u64

Body bytes consumed so far.

§Examples
let consumed = parser.parse(body, true)?.consumed;
assert_eq!(parser.bytes_seen(), consumed as u64);
Source

pub const fn parts_seen(&self) -> u32

Parts started so far.

§Examples
parser.parse(body, true)?;
assert_eq!(parser.parts_seen(), 1);
Source

pub const fn files_seen(&self) -> u32

File parts counted so far.

§Examples
parser.parse(body, true)?;
assert_eq!(parser.files_seen(), 1);
Source

pub fn is_done(&self) -> bool

Whether the close delimiter was read.

§Examples
let mut rest = &b"--X\r\nContent-Disposition: form-data; name=a\r\n\r\n1\r\n--X--"[..];
assert!(!parser.is_done());
while !parser.is_done() {
    let step = parser.parse(rest, true)?;
    rest = &rest[step.consumed..];
}
// The close delimiter was read.
assert!(rest.is_empty());
Source

pub const fn limits(&self) -> &Limits

The limits the parser was built with.

§Examples
use form_net::{Boundary, Limits, MultipartParser, Policy};

let limits = Limits::DEFAULT.with_max_part_header_bytes(1024);
let parser = MultipartParser::new(Boundary::new(b"X")?, &limits, &Policy::DEFAULT)?;
assert_eq!(parser.limits(), &limits);
Source

pub const fn policy(&self) -> &Policy

The policy the parser was built with.

§Examples
use form_net::{Boundary, Limits, MultipartParser, Policy, TokenField};

let policy = Policy::DEFAULT.with_token_field(TokenField::new("csrf"));
let parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &policy)?;
assert_eq!(parser.policy(), &policy);
Source

pub fn captured_token(&self) -> Option<&str>

The token field’s value, once its part has ended.

§Examples
use form_net::{Boundary, Limits, MultipartParser, Policy, TokenField};

let policy = Policy::DEFAULT.with_token_field(TokenField::new("csrf"));
let mut parser = MultipartParser::new(Boundary::new(b"X")?, &Limits::DEFAULT, &policy)?;
let mut rest = &b"--X\r\nContent-Disposition: form-data; name=csrf\r\n\r\nabc123\r\n--X--"[..];
while !parser.is_done() {
    let step = parser.parse(rest, true)?;
    rest = &rest[step.consumed..];
}
assert_eq!(parser.captured_token(), Some("abc123"));
Source

pub fn declared_charset(&self) -> Option<&[u8]>

The value of the last complete _charset_ field.

§Examples
let mut rest = &b"--X\r\nContent-Disposition: form-data; name=_charset_\r\n\r\nutf-8\r\n--X--"[..];
while !parser.is_done() {
    let step = parser.parse(rest, true)?;
    rest = &rest[step.consumed..];
}
assert_eq!(parser.declared_charset(), Some(&b"utf-8"[..]));

Trait Implementations§

Source§

impl<B: AsMut<[u8]> + AsRef<[u8]>> Debug for MultipartParser<B>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<B: AsMut<[u8]> + AsRef<[u8]>> Drop for MultipartParser<B>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

impl<B> Forget for MultipartParser<B>

§

impl<B> Freeze for MultipartParser<B>
where B: Freeze,

§

impl<B> Move for MultipartParser<B>

§

impl<B> RefUnwindSafe for MultipartParser<B>
where B: RefUnwindSafe,

§

impl<B> Send for MultipartParser<B>
where B: Send,

§

impl<B> Sync for MultipartParser<B>
where B: Sync,

§

impl<B> Unpin for MultipartParser<B>
where B: Unpin,

§

impl<B> UnsafeUnpin for MultipartParser<B>
where B: UnsafeUnpin,

§

impl<B> UnwindSafe for MultipartParser<B>
where B: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.