Skip to main content

MultipartWriter

Struct MultipartWriter 

Source
pub struct MultipartWriter<W: Write> { /* private fields */ }
Available on crate feature std only.
Expand description

Writes a multipart/form-data body as browsers do.

Names and file names are escaped by the browser rule; every input that could read back differently is refused; text line breaks become CRLF. With a caller boundary, data is scanned for the delimiter across chunk splits and refused if it contains one. So every body the writer produces parses back with form-net to the same fields.

§Examples

let mut body = Vec::new();
// `MultipartWriter::new` (feature `random`) generates the boundary.
let boundary = form_net::Boundary::new(b"----form-net-example")?;
let mut w = form_net::MultipartWriter::with_boundary(&mut body, boundary);
w.text("title", "Holiday")?;
w.file("photo", "beach.jpg", Some("image/jpeg"), &b"\xff\xd8 jpeg"[..])?;
let content_type = w.content_type();
w.finish()?;

let mp = form_net::parse_multipart(content_type.as_bytes(), &body)?;
assert_eq!(mp.field("title"), Some("Holiday"));
assert_eq!(mp.file("photo").map(|p| p.bytes()), Some(&b"\xff\xd8 jpeg"[..]));

Implementations§

Source§

impl<W: Write> MultipartWriter<W>

Source

pub fn new(out: W) -> Result<Self, FormError>

Available on crate feature random only.

A writer with a generated boundary.

§Errors

Random when the OS random source fails.

§Examples
let mut w = form_net::MultipartWriter::new(Vec::new())?;
w.text("title", "Holiday")?;
let content_type = w.content_type();
let body = w.finish()?;
let mp = form_net::parse_multipart(content_type.as_bytes(), &body)?;
assert_eq!(mp.field("title"), Some("Holiday"));
Source

pub fn with_boundary(out: W, boundary: Boundary) -> Self

A writer with the caller’s boundary; data is scanned for it.

§Examples
use form_net::{Boundary, MultipartWriter};

let mut w = MultipartWriter::with_boundary(Vec::new(), Boundary::new(b"X")?);
w.text("a", "1")?;
let body = w.finish()?;
assert_eq!(body, b"--X\r\nContent-Disposition: form-data; name=\"a\"\r\n\r\n1\r\n--X--\r\n");
Source

pub const fn boundary(&self) -> &Boundary

The boundary.

§Examples
use form_net::{Boundary, MultipartWriter};

let w = MultipartWriter::with_boundary(Vec::new(), Boundary::new(b"form-net-x")?);
assert_eq!(w.boundary().as_bytes(), b"form-net-x");
Source

pub fn content_type(&self) -> String

The Content-Type header value to send: multipart/form-data; boundary=..., quoted when the boundary holds a character that is not a token character.

§Examples
use form_net::{Boundary, MultipartWriter};

let w = MultipartWriter::with_boundary(Vec::new(), Boundary::new(b"abc")?);
assert_eq!(w.content_type(), "multipart/form-data; boundary=abc");
// A space is not a token character: the boundary is quoted.
let w = MultipartWriter::with_boundary(Vec::new(), Boundary::new(b"a b")?);
assert_eq!(w.content_type(), "multipart/form-data; boundary=\"a b\"");
Source

pub fn verify_boundary(&mut self, on: bool)

Turns the delimiter scan on or off. It is on for a caller boundary and off for a generated one.

§Examples
use form_net::{Boundary, MultipartWriter};

let mut w = MultipartWriter::with_boundary(Vec::new(), Boundary::new(b"X")?);
w.verify_boundary(true);
let err = w.text("a", "1\r\n--X").unwrap_err();
assert_eq!(err.code(), "syntax.boundary_in_content");
Source

pub fn text(&mut self, name: &str, value: &str) -> Result<(), FormError>

Writes a text field. Line breaks in value become CRLF. A refused head writes nothing; after any error the output is incomplete and must be discarded.

§Errors

The head errors of encode_part_head; Syntax { BoundaryInContent }; Encoding { UnsupportedCharset } for a _charset_ field naming anything but UTF-8 or US-ASCII (the text after it would not read back); Io; Poisoned.

§Examples
use form_net::{Boundary, MultipartWriter};

let mut w = MultipartWriter::with_boundary(Vec::new(), Boundary::new(b"X")?);
w.text("note", "line 1\nline 2")?;
let body = w.finish()?;
let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", &body)?;
assert_eq!(mp.field("note"), Some("line 1\r\nline 2"));
Source

pub fn file_start( &mut self, name: &str, filename: &str, content_type: Option<&str>, ) -> Result<(), FormError>

Starts a file part; its data follows through file_data.

§Errors

As text, without the charset rule.

§Examples
use form_net::{Boundary, MultipartWriter};

let mut w = MultipartWriter::with_boundary(Vec::new(), Boundary::new(b"X")?);
w.file_start("doc", "a.txt", Some("text/plain"))?;
w.file_data(b"hello")?;
let body = w.finish()?;
let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", &body)?;
assert_eq!(mp.file("doc").map(|p| p.bytes()), Some(&b"hello"[..]));
Source

pub fn file_data(&mut self, chunk: &[u8]) -> Result<(), FormError>

More data of the current file part.

§Errors

Syntax { BoundaryInContent }; Io; Poisoned outside a file part.

§Examples
use form_net::{Boundary, MultipartWriter};

let mut w = MultipartWriter::with_boundary(Vec::new(), Boundary::new(b"X")?);
w.file_start("log", "log.txt", None)?;
for chunk in [&b"part one, "[..], b"part two"] {
    w.file_data(chunk)?;
}
let body = w.finish()?;
let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", &body)?;
assert_eq!(mp.file("log").map(|p| p.bytes()), Some(&b"part one, part two"[..]));
Source

pub fn file<R: Read>( &mut self, name: &str, filename: &str, content_type: Option<&str>, data: R, ) -> Result<u64, FormError>

A whole file part read from data. Returns its length.

§Errors

As file_start and file_data; Io from data.

§Examples
use form_net::{Boundary, MultipartWriter};

let mut w = MultipartWriter::with_boundary(Vec::new(), Boundary::new(b"X")?);
let len = w.file("photo", "beach.jpg", Some("image/jpeg"), &b"\xff\xd8 jpeg"[..])?;
assert_eq!(len, 7);
let body = w.finish()?;
let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", &body)?;
assert_eq!(mp.file("photo").map(|p| p.bytes()), Some(&b"\xff\xd8 jpeg"[..]));
Source

pub fn finish(self) -> Result<W, FormError>

Writes the close delimiter and returns the writer.

§Errors

Io; Poisoned.

§Examples
use form_net::{Boundary, MultipartWriter};

let mut w = MultipartWriter::with_boundary(Vec::new(), Boundary::new(b"X")?);
w.text("a", "1")?;
let body = w.finish()?;
assert!(body.ends_with(b"\r\n--X--\r\n"));

Trait Implementations§

Source§

impl<W: Write> Debug for MultipartWriter<W>

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<W> Forget for MultipartWriter<W>

§

impl<W> Freeze for MultipartWriter<W>
where W: Freeze,

§

impl<W> Move for MultipartWriter<W>

§

impl<W> RefUnwindSafe for MultipartWriter<W>
where W: RefUnwindSafe,

§

impl<W> Send for MultipartWriter<W>
where W: Send,

§

impl<W> Sync for MultipartWriter<W>
where W: Sync,

§

impl<W> Unpin for MultipartWriter<W>
where W: Unpin,

§

impl<W> UnsafeUnpin for MultipartWriter<W>
where W: UnsafeUnpin,

§

impl<W> UnwindSafe for MultipartWriter<W>
where W: 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.