pub struct MultipartWriter<W: Write> { /* private fields */ }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>
impl<W: Write> MultipartWriter<W>
Sourcepub fn new(out: W) -> Result<Self, FormError>
Available on crate feature random only.
pub fn new(out: W) -> Result<Self, FormError>
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"));Sourcepub fn with_boundary(out: W, boundary: Boundary) -> Self
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");Sourcepub const fn boundary(&self) -> &Boundary
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");Sourcepub fn content_type(&self) -> String
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\"");Sourcepub fn verify_boundary(&mut self, on: bool)
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");Sourcepub fn text(&mut self, name: &str, value: &str) -> Result<(), FormError>
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"));Sourcepub fn file_start(
&mut self,
name: &str,
filename: &str,
content_type: Option<&str>,
) -> Result<(), FormError>
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"[..]));Sourcepub fn file_data(&mut self, chunk: &[u8]) -> Result<(), FormError>
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"[..]));Sourcepub fn file<R: Read>(
&mut self,
name: &str,
filename: &str,
content_type: Option<&str>,
data: R,
) -> Result<u64, FormError>
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"[..]));