
multra
An async parser for multipart/form-data content-type in Rust. Forked from multer.
It accepts a Stream of Bytes as
a source, so that It can be plugged into any async Rust environment e.g. any async server.
Docs
Install
Add this to your Cargo.toml:
[dependencies]
multra = "3.1"
Basic Example
use bytes::Bytes;
use futures::stream::Stream;
use multra::{Constraints, Multipart, SizeLimit};
use std::convert::Infallible;
use futures::stream::once;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let (stream, boundary) = get_byte_stream_from_somewhere().await;
let constraints = Constraints::new().size_limit(
SizeLimit::new()
.whole_stream(15 * 1024 * 1024)
.per_field(10 * 1024 * 1024)
.for_field("my_text_field", 30 * 1024),
);
let mut multipart = Multipart::with_constraints(stream, boundary, constraints);
while let Some(mut field) = multipart.next_field().await? {
let name = field.name();
let file_name = field.file_name();
println!("Name: {:?}, File Name: {:?}", name, file_name);
while let Some(chunk) = field.chunk().await? {
println!("Chunk: {:?}", chunk);
}
}
Ok(())
}
async fn get_byte_stream_from_somewhere() -> (impl Stream<Item = Result<Bytes, Infallible>>, &'static str) {
let data = "--X-BOUNDARY\r\nContent-Disposition: form-data; name=\"my_text_field\"\r\n\r\nabcd\r\n--X-BOUNDARY--\r\n";
let stream = once(async move { Result::<Bytes, Infallible>::Ok(Bytes::from(data)) });
(stream, "X-BOUNDARY")
}
Multipart::new() and Multipart::with_reader() keep backward-compatible unbounded
size limits. For untrusted uploads, prefer the constrained constructors.
Prevent Denial of Service (DoS) Attacks
This crate provides APIs to prevent potential DoS attacks with fine grained control.
The default constructors leave stream and field size limits unbounded, so it is
recommended to add explicit constraints for untrusted multipart bodies.
An example:
use multra::{Constraints, Multipart, SizeLimit};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let constraints = Constraints::new()
.allowed_fields(vec!["my_text_field", "my_file_field"])
.size_limit(
SizeLimit::new()
.whole_stream(15 * 1024 * 1024)
.per_field(10 * 1024 * 1024)
.for_field("my_text_field", 30 * 1024),
);
let mut multipart = Multipart::with_constraints(some_stream, "X-BOUNDARY", constraints);
while let Some(field) = multipart.next_field().await.unwrap() {
let content = field.text().await.unwrap();
assert_eq!(content, "abcd");
}
Ok(())
}
Usage with hyper.rs server
An example showing usage with hyper.rs.
For more examples, please visit examples.
Contributing
Your PRs and suggestions are always welcome.