// Example usage with Rocket (https://rocket.rs) // // Direct integration is not provided at this time as it appears the Rocket folks would prefer // to handle multipart requests behind the scenes. #![feature(proc_macro_hygiene, decl_macro)] #![feature(plugin, custom_attribute)] extern crate multipart; #[macro_use] extern crate rocket; use multipart::mock::StdoutTee; use multipart::server::Multipart; use multipart::server::save::Entries; use multipart::server::save::SaveResult::*; use rocket::Data; use rocket::http::{ContentType, Status}; use rocket::response::Stream; use rocket::response::status::Custom; use std::io::{self, Cursor, Write}; #[post("/upload", data = "")] // signature requires the request to have a `Content-Type` fn multipart_upload(cont_type: &ContentType, data: Data) -> Result>>, Custom> { // this and the next check can be implemented as a request guard but it seems like just // more boilerplate than necessary if !cont_type.is_form_data() { return Err(Custom( Status::BadRequest, "Content-Type not multipart/form-data".into() )); } let (_, boundary) = cont_type.params().find(|&(k, _)| k == "boundary").ok_or_else( || Custom( Status::BadRequest, "`Content-Type: multipart/form-data` boundary param not provided".into() ) )?; match process_upload(boundary, data) { Ok(resp) => Ok(Stream::from(Cursor::new(resp))), Err(err) => Err(Custom(Status::InternalServerError, err.to_string())) } } fn process_upload(boundary: &str, data: Data) -> io::Result> { let mut out = Vec::new(); // saves all fields, any field longer than 10kB goes to a temporary directory // Entries could implement FromData though that would give zero control over // how the files are saved; Multipart would be a good impl candidate though match Multipart::with_body(data.open(), boundary).save().temp() { Full(entries) => process_entries(entries, &mut out)?, Partial(partial, reason) => { writeln!(out, "Request partially processed: {:?}", reason)?; if let Some(field) = partial.partial { writeln!(out, "Stopped on field: {:?}", field.source.headers)?; } process_entries(partial.entries, &mut out)? }, Error(e) => return Err(e), } Ok(out) } // having a streaming output would be nice; there's one for returning a `Read` impl // but not one that you can `write()` to fn process_entries(entries: Entries, mut out: &mut Vec) -> io::Result<()> { { let stdout = io::stdout(); let tee = StdoutTee::new(&mut out, &stdout); entries.write_debug(tee)?; } writeln!(out, "Entries processed") } fn main() { rocket::ignite().mount("/", routes![multipart_upload]).launch(); }