diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2bf70f8d..6a39f25b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -55,10 +55,10 @@ jobs: uses: actions-rs/cargo@v1 with: command: build - args: --features ${{ matrix.features }} + args: --features ${{ matrix.features }} --workspace - name: Test uses: actions-rs/cargo@v1 with: command: test - args: --features ${{ matrix.features }} + args: --features ${{ matrix.features }} --workspace diff --git a/Cargo.toml b/Cargo.toml index 13050dac..8abaca5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ brotli = { version = "3.3.2", optional = true } chrono = { version = "0.4.19", default-features = false, features = ["clock"] } filetime = "0.2.0" deflate = { version = "1.0.0", optional = true, features = ["gzip"] } -rouille-multipart = { version = "0.18", path = "rouille-multipart", default-features = false, features = ["server"] } +rouille-multipart = { version = "0.19", path = "rouille-multipart", default-features = false, features = ["server"] } percent-encoding = "2" rand = "0.8" serde = "1" diff --git a/rouille-multipart/Cargo.toml b/rouille-multipart/Cargo.toml index 7511a801..89498b99 100644 --- a/rouille-multipart/Cargo.toml +++ b/rouille-multipart/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "rouille-multipart" -version = "0.18.0" +version = "0.19.0" authors = ["Austin Bonander "] description = "A backend-agnostic extension for HTTP libraries that provides support for POST multipart/form-data requests on both client and server." -keywords = ["form-data", "hyper", "iron", "http", "upload"] +keywords = ["form-data", "http", "upload"] repository = "http://github.com/abonander/multipart" documentation = "http://docs.rs/multipart/" license = "MIT OR Apache-2.0" @@ -12,7 +12,6 @@ autobins = false edition = "2021" [dependencies] -lazy_static = { version = "1.2.0", optional = true } log = "0.4" mime = "0.3.14" mime_guess = "2.0.1" @@ -28,57 +27,13 @@ twoway = { version = "0.1", optional = true } quick-error = { version = "1.2", optional = true } # Optional Integrations -hyper = { version = ">=0.9, <0.11", optional = true, default-features = false } -iron = { version = ">=0.4,<0.7", optional = true } tiny_http = { version = "0.6", optional = true } -nickel = { version = ">=0.10.1", optional = true } - -# Only for Rocket example but dev-dependencies can't be optional -rocket = { version = "0.4", optional = true } [dev-dependencies] env_logger = "0.5" [features] client = [] -default = ["client", "hyper", "iron", "mock", "nickel", "server", "tiny_http"] +default = ["client", "mock", "server", "tiny_http"] server = ["buffer-redux", "httparse", "quick-error", "safemem", "twoway"] mock = [] -nightly = [] -bench = [] - -[[example]] -name = "hyper_client" -required-features = ["client", "mock", "hyper"] - -[[example]] -name = "hyper_reqbuilder" -required-features = ["client", "mock", "hyper"] - -[[example]] -name = "hyper_server" -required-features = ["mock", "hyper", "server"] - -[[example]] -name = "iron" -required-features = ["mock", "iron", "server"] - -[[example]] -name = "iron_intercept" -required-features = ["mock", "iron", "server"] - -[[example]] -name = "nickel" -required-features = ["mock", "nickel", "server"] - -[[example]] -name = "tiny_http" -required-features = ["mock", "tiny_http", "server"] - -[[example]] -name = "rocket" -required-features = ["mock", "rocket", "server"] - -[[bin]] -name = "form_test" -required-features = ["mock", "hyper", "server"] diff --git a/rouille-multipart/README.md b/rouille-multipart/README.md index a97f8058..946dfa18 100644 --- a/rouille-multipart/README.md +++ b/rouille-multipart/README.md @@ -22,38 +22,11 @@ Look for a release of [multipart-async] soon which targets newer releases of Hyp Example files demonstrating how to use `multipart` with these crates are available under [`examples/`](examples). -### [Hyper ![](https://img.shields.io/crates/v/hyper.svg)](https://crates.io/crates/hyper) -via the `hyper` feature (enabled by default). - -**Note: Hyper 0.9, 0.10 (synchronous API) only**; support for asynchronous APIs will be provided by [multipart-async]. - -Client integration includes support for regular `hyper::client::Request` objects via `multipart::client::Multipart`, as well -as integration with the new `hyper::Client` API via `multipart::client::lazy::Multipart` (new in 0.5). - -Server integration for `hyper::server::Request` via `multipart::server::Multipart`. - -### [Iron ![](https://img.shields.io/crates/v/iron.svg)](https://crates.io/crates/iron) -via the `iron` feature. - -Provides regular server-side integration with `iron::Request` via `multipart::server::Multipart`, -as well as a convenient `BeforeMiddleware` implementation in `multipart::server::iron::Intercept`. - -### [Nickel ![](https://img.shields.io/crates/v/nickel.svg)](https://crates.io/crates/nickel) returning to `multipart` in 0.14! -via the `nickel` feature. - -Provides server-side integration with `&mut nickel::Request` via `multipart::server::Multipart`. - ### [tiny_http ![](https://img.shields.io/crates/v/tiny_http.svg)](https://crates.io/crates/tiny_http) via the `tiny_http` feature. Provides server-side integration with `tiny_http::Request` via `multipart::server::Multipart`. -### [Rocket ![](https://img.shields.io/crates/v/rocket.svg)](https://crates.io/crates/rocket) - -Direct integration is not provided as the Rocket folks seem to want to handle `multipart/form-data` -behind the scenes which would supercede any integration with `multipart`. However, an example is available -showing how to use `multipart` on a Rocket server: [examples/rocket.rs](examples/rocket.rs) - ## ⚡ Powered By ⚡ ### [buf_redux ![](https://img.shields.io/crates/v/buf_redux.svg)](https://crates.io/crates/buf_redux) diff --git a/rouille-multipart/examples/README.md b/rouille-multipart/examples/README.md index 580d3bbd..9f35379f 100644 --- a/rouille-multipart/examples/README.md +++ b/rouille-multipart/examples/README.md @@ -5,67 +5,8 @@ These example files show how to use `multipart` with the various crates it integ These files carry the same licenses as [`multipart` itself](https://github.com/abonander/multipart#license), though this may be lightened to a copyright-free license in the near future. -## Client - -Examples for the client-side integrations of `multipart`'s API. - -[`hyper_client`](hyper_client.rs) ---------------------------------- -Author: [abonander] - -This example showcases usage of `multipart` with the `hyper::client::Request` API. - -``` -$ cargo run --example hyper_client -``` - -[`hyper_reqbuilder`](hyper_reqbuilder.rs) ------------------------------------------ -Author: [abonander] - -This example showcases usage of `multipart` with Hyper's new `Client` API, -via the lazy-writing capabilities of `multipart::client::lazy`. - -``` -$ cargo run --example hyper_reqbuilder -``` - ## Server -[`hyper_server`](hyper_server.rs) ---------------------------------- -Author: [Puhrez] - -This example shows how to use `multipart` with a [`hyper::Server`] (http://hyper.rs/) to intercept multipart requests. - -``` -$ cargo run --example hyper_server -``` - -[`iron`](iron.rs) ------------------ -Author: [White-Oak] - -This example shows how to use `multipart` with the [Iron web application framework](https://github.com/iron/iron), via `multipart`'s support -for the `iron::Request` type. - -To run: - -``` -$ cargo run --features iron --example iron -``` - -[`iron_intercept`](iron_intercept.rs) -------------------------------------- -Author: [abonander] - -This example shows how to use `multipart`'s specialized `Intercept` middleware with Iron, which reads out all fields and -files to local storage so they can be accessed arbitrarily. - -``` -$ cargo run --features iron --example iron_intercept -``` - [`tiny_http`](tiny_http.rs) --------------------------- Author: [White-Oak] @@ -76,40 +17,6 @@ This example shows how to use `multipart` with the [`tiny_http` crate](https://c $ cargo run --features tiny_http --example tiny_http ``` -[`hyper_server`](hyper_server.rs) ---------------------------------- -Author: [Puhrez] - -This example shows how to use `multipart` with a [`hyper::Server`] (http://hyper.rs/) to intercept multipart requests. - -``` -$ cargo run --example hyper_server -``` - -[`nickel`](nickel.rs) ---------------------- -Author: [iamsebastian] - -This example shows how to use `multipart` to handle multipart uploads in [nickel.rs](https://nickel.rs). - -``` -$ cargo run --example nickel --features nickel -``` - -[Rocket](rocket.rs) -------------------- -Author: [abonander] - -This example shows how `multipart`'s server API can be used with [Rocket](https://rocket.rs) without -explicit support (the Rocket folks seem to want to handle `multipart/form-data` behind the scenes -but haven't gotten around to implementing it yet; this would supercede any integration from `multipart`). - -``` -$ cargo run --example rocket --features "rocket" -``` - -[iamsebastian]: https://github.com/iamsebastian [Puhrez]: https://github.com/puhrez [White-Oak]: https://github.com/white-oak -[abonander]: https://github.com/abonander diff --git a/rouille-multipart/examples/hyper_client.rs b/rouille-multipart/examples/hyper_client.rs deleted file mode 100644 index a8bdaad2..00000000 --- a/rouille-multipart/examples/hyper_client.rs +++ /dev/null @@ -1,43 +0,0 @@ -extern crate hyper; -extern crate multipart; - -use hyper::client::Request; -use hyper::method::Method; -use hyper::net::Streaming; - -use multipart::client::Multipart; - -use std::io::Read; - -fn main() { - let url = "http://localhost:80".parse().expect("Failed to parse URL"); - - let request = Request::new(Method::Post, url).expect("Failed to create request"); - - let mut multipart = Multipart::from_request(request).expect("Failed to create Multipart"); - - write_body(&mut multipart).expect("Failed to write multipart body"); - - let mut response = multipart.send().expect("Failed to send multipart request"); - - if !response.status.is_success() { - let mut res = String::new(); - response - .read_to_string(&mut res) - .expect("failed to read response"); - println!("response reported unsuccessful: {:?}\n {}", response, res); - } - - // Optional: read out response -} - -fn write_body(multi: &mut Multipart>) -> hyper::Result<()> { - let mut binary = "Hello world from binary!".as_bytes(); - - multi.write_text("text", "Hello, world!")?; - multi.write_file("file", "lorem_ipsum.txt")?; - // &[u8] impl Read - multi - .write_stream("binary", &mut binary, None, None) - .and(Ok(())) -} diff --git a/rouille-multipart/examples/hyper_reqbuilder.rs b/rouille-multipart/examples/hyper_reqbuilder.rs deleted file mode 100644 index 06c0bbc0..00000000 --- a/rouille-multipart/examples/hyper_reqbuilder.rs +++ /dev/null @@ -1,19 +0,0 @@ -extern crate hyper; -extern crate multipart; - -use hyper::Client; - -use multipart::client::lazy::Multipart; - -fn main() { - let mut binary = "Hello world in binary!".as_bytes(); - - let _response = Multipart::new() - .add_text("text", "Hello, world!") - .add_file("file", "lorem_ipsum.txt") - // A little extra type info needed. - .add_stream("binary", &mut binary, None as Option<&str>, None) - // Request is sent here - .client_request(&Client::new(), "http://localhost:80") - .expect("Error sending multipart request"); -} diff --git a/rouille-multipart/examples/hyper_server.rs b/rouille-multipart/examples/hyper_server.rs deleted file mode 100644 index 30333323..00000000 --- a/rouille-multipart/examples/hyper_server.rs +++ /dev/null @@ -1,51 +0,0 @@ -extern crate hyper; -extern crate multipart; - -use hyper::server::response::Response as HyperResponse; -use hyper::server::{Handler, Request, Response, Server}; -use hyper::status::StatusCode; -use multipart::mock::StdoutTee; -use multipart::server::hyper::{HyperRequest, MultipartHandler, Switch}; -use multipart::server::{Entries, Multipart, SaveResult}; -use std::io; - -struct NonMultipart; -impl Handler for NonMultipart { - fn handle(&self, _: Request, mut res: Response) { - *res.status_mut() = StatusCode::ImATeapot; - res.send(b"Please send a multipart req :(\n").unwrap(); - } -} - -struct EchoMultipart; -impl MultipartHandler for EchoMultipart { - fn handle_multipart(&self, mut multipart: Multipart, res: HyperResponse) { - match multipart.save().temp() { - SaveResult::Full(entries) => process_entries(res, entries).unwrap(), - SaveResult::Partial(entries, error) => { - println!("Errors saving multipart:\n{:?}", error); - process_entries(res, entries.into()).unwrap(); - } - SaveResult::Error(error) => { - println!("Errors saving multipart:\n{:?}", error); - res.send(format!("An error occurred {}", error).as_bytes()) - .unwrap(); - } - }; - } -} - -fn process_entries(res: HyperResponse, entries: Entries) -> io::Result<()> { - let mut res = res.start()?; - let stdout = io::stdout(); - let out = StdoutTee::new(&mut res, &stdout); - entries.write_debug(out) -} - -fn main() { - println!("Listening on 0.0.0.0:3333"); - Server::http("0.0.0.0:3333") - .unwrap() - .handle(Switch::new(NonMultipart, EchoMultipart)) - .unwrap(); -} diff --git a/rouille-multipart/examples/iron.rs b/rouille-multipart/examples/iron.rs deleted file mode 100644 index 944c0b34..00000000 --- a/rouille-multipart/examples/iron.rs +++ /dev/null @@ -1,69 +0,0 @@ -extern crate iron; -extern crate multipart; - -extern crate env_logger; - -use iron::prelude::*; -use iron::status; -use multipart::mock::StdoutTee; -use multipart::server::{Entries, Multipart, SaveResult}; -use std::io::{self, Write}; - -fn main() { - env_logger::init(); - - Iron::new(process_request) - .http("localhost:80") - .expect("Could not bind localhost:80"); -} - -/// Processes a request and returns response or an occured error. -fn process_request(request: &mut Request) -> IronResult { - // Getting a multipart reader wrapper - match Multipart::from_request(request) { - Ok(mut multipart) => { - // Fetching all data and processing it. - // save().temp() reads the request fully, parsing all fields and saving all files - // in a new temporary directory under the OS temporary directory. - match multipart.save().temp() { - SaveResult::Full(entries) => process_entries(entries), - SaveResult::Partial(entries, reason) => { - process_entries(entries.keep_partial())?; - Ok(Response::with(( - status::BadRequest, - format!("error reading request: {}", reason.unwrap_err()), - ))) - } - SaveResult::Error(error) => Ok(Response::with(( - status::BadRequest, - format!("error reading request: {}", error), - ))), - } - } - Err(_) => Ok(Response::with(( - status::BadRequest, - "The request is not multipart", - ))), - } -} - -/// Processes saved entries from multipart request. -/// Returns an OK response or an error. -fn process_entries(entries: Entries) -> IronResult { - let mut data = Vec::new(); - - { - let stdout = io::stdout(); - let tee = StdoutTee::new(&mut data, &stdout); - entries.write_debug(tee).map_err(|e| { - IronError::new( - e, - (status::InternalServerError, "Error printing request fields"), - ) - })?; - } - - let _ = writeln!(data, "Entries processed"); - - Ok(Response::with((status::Ok, data))) -} diff --git a/rouille-multipart/examples/iron_intercept.rs b/rouille-multipart/examples/iron_intercept.rs deleted file mode 100644 index d9f5ba0d..00000000 --- a/rouille-multipart/examples/iron_intercept.rs +++ /dev/null @@ -1,25 +0,0 @@ -extern crate iron; -extern crate multipart; - -use iron::prelude::*; - -use multipart::server::iron::Intercept; -use multipart::server::Entries; - -fn main() { - // We start with a basic request handler chain. - let mut chain = Chain::new(|req: &mut Request| { - if let Some(entries) = req.extensions.get::() { - Ok(Response::with(format!("{:?}", entries))) - } else { - Ok(Response::with("Not a multipart request")) - } - }); - - // `Intercept` will read out the entries and place them as an extension in the request. - // It has various builder-style methods for changing how it will behave, but has sane settings - // by default. - chain.link_before(Intercept::default()); - - Iron::new(chain).http("localhost:80").unwrap(); -} diff --git a/rouille-multipart/examples/nickel.rs b/rouille-multipart/examples/nickel.rs deleted file mode 100644 index b1a5334f..00000000 --- a/rouille-multipart/examples/nickel.rs +++ /dev/null @@ -1,61 +0,0 @@ -extern crate multipart; -extern crate nickel; - -use nickel::status::StatusCode; -use nickel::{Action, HttpRouter, MiddlewareResult, Nickel, Request, Response}; -use std::io::{self, Write}; - -use multipart::mock::StdoutTee; -use multipart::server::nickel::MultipartBody; -use multipart::server::{Entries, SaveResult}; - -fn handle_multipart<'mw>(req: &mut Request, mut res: Response<'mw>) -> MiddlewareResult<'mw> { - match (*req).multipart_body() { - Some(mut multipart) => match multipart.save().temp() { - SaveResult::Full(entries) => process_entries(res, entries), - - SaveResult::Partial(entries, e) => { - println!("Partial errors ... {:?}", e); - return process_entries(res, entries.keep_partial()); - } - - SaveResult::Error(e) => { - println!("There are errors in multipart POSTing ... {:?}", e); - res.set(StatusCode::InternalServerError); - return res.send(format!("Server could not handle multipart POST! {:?}", e)); - } - }, - None => { - res.set(StatusCode::BadRequest); - return res.send("Request seems not was a multipart request"); - } - } -} - -/// Processes saved entries from multipart request. -/// Returns an OK response or an error. -fn process_entries<'mw>(res: Response<'mw>, entries: Entries) -> MiddlewareResult<'mw> { - let stdout = io::stdout(); - let mut res = res.start()?; - if let Err(e) = entries.write_debug(StdoutTee::new(&mut res, &stdout)) { - writeln!(res, "Error while reading entries: {}", e).expect("writeln"); - } - - Ok(Action::Halt(res)) -} - -fn main() { - let mut srv = Nickel::new(); - - srv.post("/multipart_upload/", handle_multipart); - - // Start this example via: - // - // `cargo run --example nickel --features nickel` - // - // And - if you are in the root of this repository - do an example - // upload via: - // - // `curl -F file=@LICENSE 'http://localhost:6868/multipart_upload/'` - srv.listen("127.0.0.1:6868").expect("Failed to bind server"); -} diff --git a/rouille-multipart/examples/rocket.rs b/rouille-multipart/examples/rocket.rs deleted file mode 100644 index 0cdb7953..00000000 --- a/rouille-multipart/examples/rocket.rs +++ /dev/null @@ -1,93 +0,0 @@ -// 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::save::Entries; -use multipart::server::save::SaveResult::*; -use multipart::server::Multipart; - -use rocket::http::{ContentType, Status}; -use rocket::response::status::Custom; -use rocket::response::Stream; -use rocket::Data; - -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(); -} diff --git a/rouille-multipart/examples/tiny_http.rs b/rouille-multipart/examples/tiny_http.rs index 73b62aba..deacff85 100644 --- a/rouille-multipart/examples/tiny_http.rs +++ b/rouille-multipart/examples/tiny_http.rs @@ -1,10 +1,8 @@ -extern crate multipart; -extern crate tiny_http; - -use multipart::mock::StdoutTee; -use multipart::server::{Entries, Multipart, SaveResult}; +use rouille_multipart::mock::StdoutTee; +use rouille_multipart::server::{Entries, Multipart, SaveResult}; use std::io::{self, Cursor, Write}; use tiny_http::{Request, Response, StatusCode}; + fn main() { // Starting a server on `localhost:80` let server = tiny_http::Server::http("localhost:80").expect("Could not bind localhost:80"); diff --git a/rouille-multipart/fuzz/fuzzers/server_basic.rs b/rouille-multipart/fuzz/fuzzers/server_basic.rs index 09312acc..307c869a 100644 --- a/rouille-multipart/fuzz/fuzzers/server_basic.rs +++ b/rouille-multipart/fuzz/fuzzers/server_basic.rs @@ -1,12 +1,8 @@ #![no_main] extern crate libfuzzer_sys; -extern crate multipart; -#[macro_use] -extern crate log; - -use multipart::server::{Multipart, MultipartData}; -use multipart::mock::ServerRequest; +use rouille_multipart::server::{Multipart, MultipartData}; +use rouille_multipart::mock::ServerRequest; mod logger; diff --git a/rouille-multipart/src/client/hyper.rs b/rouille-multipart/src/client/hyper.rs deleted file mode 100644 index 0d30be2a..00000000 --- a/rouille-multipart/src/client/hyper.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2016 `multipart` Crate Developers -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. -//! Client-side integration with [Hyper](https://github.com/hyperium/hyper). -//! Enabled with the `hyper` feature (on by default). -//! -//! Contains `impl HttpRequest for Request` and `impl HttpStream for Request`. -//! -//! Also see: [`lazy::Multipart::client_request()`](../lazy/struct.Multipart.html#method.client_request) -//! and [`lazy::Multipart::client_request_mut()`](../lazy/struct.Multipart.html#method.client_request_mut) -//! (adaptors for `hyper::client::RequestBuilder`). -use hyper::client::request::Request; -use hyper::client::response::Response; -use hyper::header::{ContentLength, ContentType}; -use hyper::method::Method; -use hyper::net::{Fresh, Streaming}; - -use hyper::Error as HyperError; - -use hyper::mime::{Attr, Mime, SubLevel, TopLevel, Value}; - -use super::{HttpRequest, HttpStream}; - -/// #### Feature: `hyper` -impl HttpRequest for Request { - type Stream = Request; - type Error = HyperError; - - /// # Panics - /// If `self.method() != Method::Post`. - fn apply_headers(&mut self, boundary: &str, content_len: Option) -> bool { - if self.method() != Method::Post { - error!( - "Expected Hyper request method to be `Post`, was actually `{:?}`", - self.method() - ); - - return false; - } - - let headers = self.headers_mut(); - - headers.set(ContentType(multipart_mime(boundary))); - - if let Some(size) = content_len { - headers.set(ContentLength(size)); - } - - debug!("Hyper headers: {}", headers); - - true - } - - fn open_stream(self) -> Result { - self.start() - } -} - -/// #### Feature: `hyper` -impl HttpStream for Request { - type Request = Request; - type Response = Response; - type Error = HyperError; - - fn finish(self) -> Result { - self.send() - } -} - -/// Create a `Content-Type: multipart/form-data;boundary={bound}` -pub fn content_type(bound: &str) -> ContentType { - ContentType(multipart_mime(bound)) -} - -fn multipart_mime(bound: &str) -> Mime { - Mime( - TopLevel::Multipart, - SubLevel::Ext("form-data".into()), - vec![(Attr::Ext("boundary".into()), Value::Ext(bound.into()))], - ) -} diff --git a/rouille-multipart/src/client/lazy.rs b/rouille-multipart/src/client/lazy.rs index ca7cbb65..80a8ebb5 100644 --- a/rouille-multipart/src/client/lazy.rs +++ b/rouille-multipart/src/client/lazy.rs @@ -481,67 +481,3 @@ impl<'a> IntoCowPath<'a> for &'a str { fn cursor_at_end>(cursor: &Cursor) -> bool { cursor.position() == (cursor.get_ref().as_ref().len() as u64) } - -#[cfg(feature = "hyper")] -mod hyper { - use crate::client; - use hyper::client::{Body, Client, IntoUrl, RequestBuilder, Response}; - use hyper::Result as HyperResult; - - impl<'n, 'd> super::Multipart<'n, 'd> { - /// #### Feature: `hyper` - /// Complete a POST request with the given `hyper::client::Client` and URL. - /// - /// Supplies the fields in the body, optionally setting the content-length header if - /// applicable (all added fields were text or files, i.e. no streams). - pub fn client_request( - &mut self, - client: &Client, - url: U, - ) -> HyperResult { - self.client_request_mut(client, url, |r| r) - } - - /// #### Feature: `hyper` - /// Complete a POST request with the given `hyper::client::Client` and URL; - /// allows mutating the `hyper::client::RequestBuilder` via the passed closure. - /// - /// Note that the body, and the `ContentType` and `ContentLength` headers will be - /// overwritten, either by this method or by Hyper. - pub fn client_request_mut RequestBuilder>( - &mut self, - client: &Client, - url: U, - mut_fn: F, - ) -> HyperResult { - let mut fields = match self.prepare() { - Ok(fields) => fields, - Err(err) => { - error!("Error preparing request: {}", err); - return Err(err.error.into()); - } - }; - - mut_fn(client.post(url)) - .header(client::hyper::content_type(fields.boundary())) - .body(fields.to_body()) - .send() - } - } - - impl<'d> super::PreparedFields<'d> { - /// #### Feature: `hyper` - /// Convert `self` to `hyper::client::Body`. - #[cfg_attr(feature = "clippy", warn(wrong_self_convention))] - pub fn to_body<'b>(&'b mut self) -> Body<'b> - where - 'd: 'b, - { - if let Some(content_len) = self.content_len { - Body::SizedBody(self, content_len) - } else { - Body::ChunkedBody(self) - } - } - } -} diff --git a/rouille-multipart/src/client/mod.rs b/rouille-multipart/src/client/mod.rs index b1ba9391..a48d9dce 100644 --- a/rouille-multipart/src/client/mod.rs +++ b/rouille-multipart/src/client/mod.rs @@ -16,9 +16,6 @@ use std::io::prelude::*; use std::path::Path; -#[cfg(feature = "hyper")] -pub mod hyper; - pub mod lazy; mod sized; diff --git a/rouille-multipart/src/lib.rs b/rouille-multipart/src/lib.rs index 896ea754..23620f45 100644 --- a/rouille-multipart/src/lib.rs +++ b/rouille-multipart/src/lib.rs @@ -16,16 +16,6 @@ //! * `mock`: Provides mock implementations of core `client` and `server` traits for debugging //! or non-standard use. //! -//! * `hyper`: Integration with the [Hyper](https://crates.io/crates/hyper) HTTP library -//! for client and/or server depending on which other feature flags are set. -//! -//! * `iron`: Integration with the [Iron](http://crates.io/crates/iron) web application -//! framework. See the [`server::iron`](server/iron/index.html) module for more information. -//! -//! * `nickel` (returning in 0.14!): Integration with the [Nickel](https://crates.io/crates/nickel) -//! web application framework. See the [`server::nickel`](server/nickel/index.html) module for more -//! information. -//! //! * `tiny_http`: Integration with the [`tiny_http`](https://crates.io/crates/tiny_http) //! crate. See the [`server::tiny_http`](server/tiny_http/index.html) module for more information. //! @@ -39,7 +29,6 @@ #![cfg_attr(feature = "clippy", feature(plugin))] #![cfg_attr(feature = "clippy", plugin(clippy))] #![cfg_attr(feature = "clippy", deny(clippy))] -#![cfg_attr(feature = "bench", feature(test))] #![deny(missing_docs)] #[macro_use] @@ -57,12 +46,6 @@ extern crate quick_error; #[cfg(feature = "server")] extern crate safemem; -#[cfg(feature = "hyper")] -extern crate hyper; - -#[cfg(feature = "iron")] -extern crate iron; - #[cfg(feature = "tiny_http")] extern crate tiny_http; @@ -77,8 +60,6 @@ use rand::Rng; /// Chain a series of results together, with or without previous results. /// /// ``` -/// #[macro_use] extern crate multipart; -/// /// fn try_add_one(val: u32) -> Result { /// if val < 5 { /// Ok(val + 1) @@ -88,7 +69,7 @@ use rand::Rng; /// } /// /// fn main() { -/// let res = chain_result! { +/// let res = rouille_multipart::chain_result! { /// try_add_one(1), /// prev -> try_add_one(prev), /// prev -> try_add_one(prev), diff --git a/rouille-multipart/src/local_test.rs b/rouille-multipart/src/local_test.rs index 3d24a920..41aa15e7 100644 --- a/rouille-multipart/src/local_test.rs +++ b/rouille-multipart/src/local_test.rs @@ -4,9 +4,8 @@ // http://apache.org/licenses/LICENSE-2.0> or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use mock::{ClientRequest, HttpBuffer}; - -use server::{FieldHeaders, MultipartField, ReadEntry}; +use crate::mock::{ClientRequest, HttpBuffer}; +use crate::server::{FieldHeaders, MultipartField, ReadEntry}; use mime::Mime; @@ -226,7 +225,7 @@ impl fmt::Debug for PrintHex { macro_rules! do_test ( ($client_test:ident, $server_test:ident) => ( - ::init_log(); + crate::init_log(); info!("Client Test: {:?} Server Test: {:?}", stringify!($client_test), stringify!($server_test)); @@ -344,7 +343,7 @@ fn gen_bytes() -> Vec { } fn test_client(test_fields: &TestFields) -> HttpBuffer { - use client::Multipart; + use crate::client::Multipart; let request = ClientRequest::default(); @@ -392,7 +391,7 @@ fn test_client(test_fields: &TestFields) -> HttpBuffer { } fn test_client_lazy(test_fields: &TestFields) -> HttpBuffer { - use client::lazy::Multipart; + use crate::client::lazy::Multipart; let mut multipart = Multipart::new(); @@ -441,7 +440,7 @@ fn test_client_lazy(test_fields: &TestFields) -> HttpBuffer { } fn test_server(buf: HttpBuffer, fields: &mut TestFields) { - use server::Multipart; + use crate::server::Multipart; let server_buf = buf.for_server(); @@ -461,7 +460,7 @@ fn test_server(buf: HttpBuffer, fields: &mut TestFields) { } fn test_server_entry_api(buf: HttpBuffer, fields: &mut TestFields) { - use server::Multipart; + use crate::server::Multipart; let server_buf = buf.for_server(); diff --git a/rouille-multipart/src/server/boundary.rs b/rouille-multipart/src/server/boundary.rs index 6d4fbf2f..ff55b638 100644 --- a/rouille-multipart/src/server/boundary.rs +++ b/rouille-multipart/src/server/boundary.rs @@ -240,20 +240,6 @@ fn find_boundary(buf: &[u8], boundary: &[u8]) -> Result { Err(buf.len()) } -#[cfg(feature = "bench")] -impl<'a> BoundaryReader> { - fn new_with_bytes(bytes: &'a [u8], boundary: &str) -> Self { - Self::from_reader(io::Cursor::new(bytes), boundary) - } - - fn reset(&mut self) { - // Dump buffer and reset cursor - self.source.seek(io::SeekFrom::Start(0)); - self.state = Searching; - self.search_idx = 0; - } -} - impl Borrow for BoundaryReader { fn borrow(&self) -> &R { self.source.get_ref() @@ -310,7 +296,7 @@ mod test { #[test] fn test_boundary() { - ::init_log(); + crate::init_log(); debug!("Testing boundary (no split)"); @@ -356,7 +342,7 @@ mod test { #[test] fn test_split_boundary() { - ::init_log(); + crate::init_log(); debug!("Testing boundary (split)"); @@ -406,7 +392,7 @@ mod test { #[test] fn test_empty_body() { - ::init_log(); + crate::init_log(); // empty body contains closing boundary only let mut body: &[u8] = b"--boundary--"; @@ -428,7 +414,7 @@ mod test { #[test] fn test_leading_crlf() { - ::init_log(); + crate::init_log(); let mut body: &[u8] = b"\r\n\r\n--boundary\r\n\ asdf1234\ @@ -455,7 +441,7 @@ mod test { #[test] fn test_trailing_crlf() { - ::init_log(); + crate::init_log(); let mut body: &[u8] = b"--boundary\r\n\ asdf1234\ @@ -499,7 +485,7 @@ mod test { // https://github.com/abonander/multipart/issues/93#issuecomment-343610587 #[test] fn test_trailing_lflf() { - ::init_log(); + crate::init_log(); let mut body: &[u8] = b"--boundary\r\n\ asdf1234\ @@ -542,7 +528,7 @@ mod test { // https://github.com/abonander/multipart/issues/104 #[test] fn test_unterminated_body() { - ::init_log(); + crate::init_log(); let mut body: &[u8] = b"--boundary\r\n\ asdf1234\ @@ -607,23 +593,4 @@ mod test { assert_eq!(reader.consume_boundary().unwrap(), false); } - - #[cfg(feature = "bench")] - mod bench { - extern crate test; - use self::test::Bencher; - - use super::*; - - #[bench] - fn bench_boundary_reader(b: &mut Bencher) { - let mut reader = BoundaryReader::new_with_bytes(TEST_VAL.as_bytes(), BOUNDARY); - let mut buf = String::with_capacity(256); - - b.iter(|| { - reader.reset(); - test_boundary_reader(&mut reader, &mut buf); - }); - } - } } diff --git a/rouille-multipart/src/server/hyper.rs b/rouille-multipart/src/server/hyper.rs deleted file mode 100644 index 2c9f5e2d..00000000 --- a/rouille-multipart/src/server/hyper.rs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2016 `multipart` Crate Developers -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. -//! Server-side integration with [Hyper](https://github.com/hyperium/hyper). -//! Enabled with the `hyper` feature (on by default). -//! -//! Also contains an implementation of [`HttpRequest`](../trait.HttpRequest.html) -//! for `hyper::server::Request` and `&mut hyper::server::Request`. -use hyper::header::ContentType; -use hyper::method::Method; -use hyper::net::Fresh; -use hyper::server::{Handler, Request, Response}; - -pub use hyper::server::Request as HyperRequest; - -use hyper::mime::{Attr, Mime, SubLevel, TopLevel, Value}; - -use super::{HttpRequest, Multipart}; - -/// A container that implements `hyper::server::Handler` which will switch -/// the handler implementation depending on if the incoming request is multipart or not. -/// -/// Create an instance with `new()` and pass it to `hyper::server::Server::listen()` where -/// you would normally pass a `Handler` instance. -/// -/// A convenient wrapper for `Multipart::from_request()`. -pub struct Switch { - normal: H, - multipart: M, -} - -impl Switch -where - H: Handler, - M: MultipartHandler, -{ - /// Create a new `Switch` instance where - /// `normal` handles normal Hyper requests and `multipart` handles Multipart requests - pub fn new(normal: H, multipart: M) -> Switch { - Switch { normal, multipart } - } -} - -impl Handler for Switch -where - H: Handler, - M: MultipartHandler, -{ - fn handle<'a, 'k>(&'a self, req: Request<'a, 'k>, res: Response<'a, Fresh>) { - match Multipart::from_request(req) { - Ok(multi) => self.multipart.handle_multipart(multi, res), - Err(req) => self.normal.handle(req, res), - } - } -} - -/// A trait defining a type that can handle an incoming multipart request. -/// -/// Extends to closures of the type `Fn(Multipart, Response)`, -/// and subsequently static functions. -pub trait MultipartHandler: Send + Sync { - /// Generate a response from this multipart request. - fn handle_multipart<'a, 'k>( - &self, - multipart: Multipart>, - response: Response<'a, Fresh>, - ); -} - -impl MultipartHandler for F -where - F: Fn(Multipart, Response), - F: Send + Sync, -{ - fn handle_multipart<'a, 'k>( - &self, - multipart: Multipart>, - response: Response<'a, Fresh>, - ) { - (*self)(multipart, response); - } -} - -impl<'a, 'b> HttpRequest for HyperRequest<'a, 'b> { - type Body = Self; - - fn multipart_boundary(&self) -> Option<&str> { - if self.method != Method::Post { - return None; - } - - self.headers.get::().and_then(|ct| { - let ContentType(ref mime) = *ct; - let params = match *mime { - Mime(TopLevel::Multipart, SubLevel::FormData, ref params) => params, - _ => return None, - }; - - params - .iter() - .find(|&&(ref name, _)| match *name { - Attr::Boundary => true, - _ => false, - }) - .and_then(|&(_, ref val)| match *val { - Value::Ext(ref val) => Some(&**val), - _ => None, - }) - }) - } - - fn body(self) -> Self { - self - } -} - -impl<'r, 'a, 'b> HttpRequest for &'r mut HyperRequest<'a, 'b> { - type Body = Self; - - fn multipart_boundary(&self) -> Option<&str> { - if self.method != Method::Post { - return None; - } - - self.headers.get::().and_then(|ct| { - let ContentType(ref mime) = *ct; - let params = match *mime { - Mime(TopLevel::Multipart, SubLevel::FormData, ref params) => params, - _ => return None, - }; - - params - .iter() - .find(|&&(ref name, _)| match *name { - Attr::Boundary => true, - _ => false, - }) - .and_then(|&(_, ref val)| match *val { - Value::Ext(ref val) => Some(&**val), - _ => None, - }) - }) - } - - fn body(self) -> Self::Body { - self - } -} diff --git a/rouille-multipart/src/server/iron.rs b/rouille-multipart/src/server/iron.rs deleted file mode 100644 index cd93157e..00000000 --- a/rouille-multipart/src/server/iron.rs +++ /dev/null @@ -1,334 +0,0 @@ -//! Integration with the [Iron](https://github.com/iron/iron) framework, enabled with the `iron` feature (optional). Includes a `BeforeMiddleware` implementation. -//! -//! Not shown here: `impl `[`HttpRequest`](../trait.HttpRequest.html#implementors)` for -//! iron::Request`. - -use iron::headers::ContentType; -use iron::mime::{Mime, SubLevel, TopLevel}; -use iron::request::{Body as IronBody, Request as IronRequest}; -use iron::typemap::Key; -use iron::{BeforeMiddleware, IronError, IronResult}; - -use std::path::PathBuf; -use std::{error, fmt, io}; -use tempfile; - -use super::save::SaveResult::*; -use super::save::{Entries, PartialReason, TempDir}; -use super::{FieldHeaders, HttpRequest, Multipart}; - -impl<'r, 'a, 'b> HttpRequest for &'r mut IronRequest<'a, 'b> { - type Body = &'r mut IronBody<'a, 'b>; - - fn multipart_boundary(&self) -> Option<&str> { - let content_type = try_opt!(self.headers.get::()); - if let Mime(TopLevel::Multipart, SubLevel::FormData, _) = **content_type { - content_type.get_param("boundary").map(|b| b.as_str()) - } else { - None - } - } - - fn body(self) -> &'r mut IronBody<'a, 'b> { - &mut self.body - } -} - -/// The default file size limit for [`Intercept`](struct.Intercept.html), in bytes. -pub const DEFAULT_FILE_SIZE_LIMIT: u64 = 2 * 1024 * 1024; - -/// The default file count limit for [`Intercept`](struct.Intercept.html). -pub const DEFAULT_FILE_COUNT_LIMIT: u32 = 16; - -/// A `BeforeMiddleware` for Iron which will intercept and read-out multipart requests and store -/// the result in the request. -/// -/// Successful reads will be placed in the `extensions: TypeMap` field of `iron::Request` as an -/// [`Entries`](../struct.Entries.html) instance (as both key-type and value): -/// -/// ```no_run -/// extern crate iron; -/// extern crate multipart; -/// -/// use iron::prelude::*; -/// -/// use multipart::server::Entries; -/// use multipart::server::iron::Intercept; -/// -/// fn main() { -/// let mut chain = Chain::new(|req: &mut Request| if let Some(entries) = -/// req.extensions.get::() { -/// -/// Ok(Response::with(format!("{:?}", entries))) -/// } else { -/// Ok(Response::with("Not a multipart request")) -/// }); -/// -/// chain.link_before(Intercept::default()); -/// -/// Iron::new(chain).http("localhost:80").unwrap(); -/// } -/// ``` -/// -/// Any errors during which occur during reading will be passed on as `IronError`. -#[derive(Debug)] -pub struct Intercept { - /// The parent directory for all temporary directories created by this middleware. - /// Will be created if it doesn't exist (lazy). - /// - /// If omitted, uses the OS temporary directory. - /// - /// Default value: `None`. - pub temp_dir_path: Option, - /// The size limit of uploaded files, in bytes. - /// - /// Files which exceed this size will be rejected. - /// See the `limit_behavior` field for more info. - /// - /// Default value: [`DEFAULT_FILE_SIZE_LIMIT`](constant.default_file_size_limit.html) - pub file_size_limit: u64, - /// The limit on the number of files which will be saved from - /// the request. Requests which exceed this count will be rejected. - /// - /// Default value: [`DEFAULT_FILE_COUNT_LIMT`](constant.default_file_count_limit.html) - pub file_count_limit: u32, - /// What to do when a file count or size limit has been exceeded. - /// - /// See [`LimitBehavior`](enum.limitbehavior.html) for more info. - pub limit_behavior: LimitBehavior, -} - -impl Intercept { - /// Set the `temp_dir_path` for this middleware. - pub fn temp_dir_path>(self, path: P) -> Self { - Intercept { - temp_dir_path: Some(path.into()), - ..self - } - } - - /// Set the `file_size_limit` for this middleware. - pub fn file_size_limit(self, limit: u64) -> Self { - Intercept { - file_size_limit: limit, - ..self - } - } - - /// Set the `file_count_limit` for this middleware. - pub fn file_count_limit(self, limit: u32) -> Self { - Intercept { - file_count_limit: limit, - ..self - } - } - - /// Set the `limit_behavior` for this middleware. - pub fn limit_behavior(self, behavior: LimitBehavior) -> Self { - Intercept { - limit_behavior: behavior, - ..self - } - } - - fn read_request(&self, req: &mut IronRequest) -> IronResult> { - let multipart = match Multipart::from_request(req) { - Ok(multipart) => multipart, - Err(_) => return Ok(None), - }; - - let tempdir = self - .temp_dir_path - .as_ref() - .map_or_else( - || tempfile::Builder::new().prefix("multipart-iron").tempdir(), - |path| { - tempfile::Builder::new() - .prefix("multipart-iron") - .tempdir_in(path) - }, - ) - .map_err(|e| io_to_iron(e, "Error opening temporary directory for request."))?; - - match self.limit_behavior { - LimitBehavior::ThrowError => self.read_request_strict(multipart, tempdir), - LimitBehavior::Continue => self.read_request_lenient(multipart, tempdir), - } - } - - fn read_request_strict( - &self, - mut multipart: IronMultipart, - tempdir: TempDir, - ) -> IronResult> { - match multipart - .save() - .size_limit(self.file_size_limit) - .count_limit(self.file_count_limit) - .with_temp_dir(tempdir) - { - Full(entries) => Ok(Some(entries)), - Partial(_, PartialReason::Utf8Error(_)) => unreachable!(), - Partial(_, PartialReason::IoError(err)) => { - Err(io_to_iron(err, "Error midway through request")) - } - Partial(_, PartialReason::CountLimit) => { - Err(FileCountLimitError(self.file_count_limit).into()) - } - Partial(partial, PartialReason::SizeLimit) => { - let partial = partial.partial.expect(EXPECT_PARTIAL_FILE); - Err(FileSizeLimitError { - field: partial.source.headers, - } - .into()) - } - Error(err) => Err(io_to_iron(err, "Error at start of request")), - } - } - - fn read_request_lenient( - &self, - mut multipart: IronMultipart, - tempdir: TempDir, - ) -> IronResult> { - let mut entries = match multipart - .save() - .size_limit(self.file_size_limit) - .count_limit(self.file_count_limit) - .with_temp_dir(tempdir) - { - Full(entries) => return Ok(Some(entries)), - Partial(_, PartialReason::IoError(err)) => { - return Err(io_to_iron(err, "Error midway through request")) - } - Partial(partial, _) => partial.keep_partial(), - Error(err) => return Err(io_to_iron(err, "Error at start of request")), - }; - - loop { - entries = match multipart - .save() - .size_limit(self.file_size_limit) - .count_limit(self.file_count_limit) - .with_entries(entries) - { - Full(entries) => return Ok(Some(entries)), - Partial(_, PartialReason::IoError(err)) => { - return Err(io_to_iron(err, "Error midway through request")) - } - Partial(partial, _) => partial.keep_partial(), - Error(err) => return Err(io_to_iron(err, "Error at start of request")), - }; - } - } -} - -type IronMultipart<'r, 'a, 'b> = Multipart<&'r mut IronBody<'a, 'b>>; - -const EXPECT_PARTIAL_FILE: &str = "File size limit hit but the offending \ - file was not available; this is a bug."; - -impl Default for Intercept { - fn default() -> Self { - Intercept { - temp_dir_path: None, - file_size_limit: DEFAULT_FILE_SIZE_LIMIT, - file_count_limit: DEFAULT_FILE_COUNT_LIMIT, - limit_behavior: LimitBehavior::ThrowError, - } - } -} - -impl BeforeMiddleware for Intercept { - fn before(&self, req: &mut IronRequest) -> IronResult<()> { - self.read_request(req)? - .map(|entries| req.extensions.insert::(entries)); - - Ok(()) - } -} - -impl Key for Entries { - type Value = Self; -} - -/// The behavior of `Intercept` when a file size or count limit is exceeded. -#[derive(Clone, Copy, Debug)] -#[repr(u32)] -pub enum LimitBehavior { - /// Return an error from the middleware describing the issue. - ThrowError, - /// Ignore the limit. - /// - /// In the case of file size limits, the offending file will be truncated - /// in the result. - /// - /// In the case of file count limits, the request will be completed. - Continue, -} - -/// An error returned from `Intercept` when the size limit -/// for an individual file is exceeded. -#[derive(Debug)] -pub struct FileSizeLimitError { - /// The field where the error occurred. - pub field: FieldHeaders, -} - -impl error::Error for FileSizeLimitError { - fn description(&self) -> &str { - "file size limit reached" - } -} - -impl fmt::Display for FileSizeLimitError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.field.filename { - Some(ref filename) => write!( - f, - "File size limit reached for field \"{}\" (filename: \"{}\")", - self.field.name, filename - ), - None => write!( - f, - "File size limit reached for field \"{}\" (no filename)", - self.field.name - ), - } - } -} - -impl Into for FileSizeLimitError { - fn into(self) -> IronError { - let desc_str = self.to_string(); - IronError::new(self, desc_str) - } -} - -/// An error returned from `Intercept` when the file count limit -/// for a single request was exceeded. -#[derive(Debug)] -pub struct FileCountLimitError(u32); - -impl error::Error for FileCountLimitError { - fn description(&self) -> &str { - "file count limit reached" - } -} - -impl fmt::Display for FileCountLimitError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "File count limit reached for request. Limit: {}", self.0) - } -} - -impl Into for FileCountLimitError { - fn into(self) -> IronError { - let desc_string = self.to_string(); - IronError::new(self, desc_string) - } -} - -fn io_to_iron>(err: io::Error, msg: M) -> IronError { - IronError::new(err, msg.into()) -} diff --git a/rouille-multipart/src/server/mod.rs b/rouille-multipart/src/server/mod.rs index b0bd13d8..8ba2a6cf 100644 --- a/rouille-multipart/src/server/mod.rs +++ b/rouille-multipart/src/server/mod.rs @@ -59,18 +59,9 @@ macro_rules! try_read_entry { mod boundary; mod field; -#[cfg(feature = "hyper")] -pub mod hyper; - -#[cfg(feature = "iron")] -pub mod iron; - #[cfg(feature = "tiny_http")] pub mod tiny_http; -#[cfg(feature = "nickel")] -pub mod nickel; - pub mod save; /// The server-side implementation of `multipart/form-data` requests. @@ -203,7 +194,7 @@ pub trait HttpRequest { #[test] fn issue_104() { - ::init_log(); + crate::init_log(); use std::io::Cursor; @@ -226,7 +217,7 @@ fn issue_104() { #[test] fn issue_114() { - ::init_log(); + crate::init_log(); fn consume_all(mut rdr: R) { loop { diff --git a/rouille-multipart/src/server/nickel.rs b/rouille-multipart/src/server/nickel.rs deleted file mode 100644 index 1b4a603f..00000000 --- a/rouille-multipart/src/server/nickel.rs +++ /dev/null @@ -1,76 +0,0 @@ -//! Support for `multipart/form-data` bodies in [Nickel](https://nickel.rs). -pub extern crate nickel; - -use self::hyper::header::ContentType; -use self::nickel::hyper; - -pub use self::nickel::hyper::server::Request as HyperRequest; -pub use self::nickel::Request as NickelRequest; - -use crate::server::{HttpRequest, Multipart}; - -/// A wrapper for `&mut nickel::Request` which implements `multipart::server::HttpRequest`. -/// -/// Necessary because this crate cannot directly provide an impl of `HttpRequest` for -/// `&mut NickelRequest`. -pub struct Maybe<'r, 'mw: 'r, 'server: 'mw, D: 'mw>(pub &'r mut NickelRequest<'mw, 'server, D>); - -impl<'r, 'mw: 'r, 'server: 'mw, D: 'mw> HttpRequest for Maybe<'r, 'mw, 'server, D> { - type Body = &'r mut HyperRequest<'mw, 'server>; - - fn multipart_boundary(&self) -> Option<&str> { - // we can't use the impl from the `hyper` module because it might be the wrong version - let cont_type = try_opt!(self.0.origin.headers.get::()); - cont_type.get_param("boundary").map(|v| v.as_str()) - } - - fn body(self) -> Self::Body { - &mut self.0.origin - } -} - -/// Extension trait for getting the `multipart/form-data` body from `nickel::Request`. -/// -/// Implemented for `nickel::Request`. -pub trait MultipartBody<'mw, 'server> { - /// Get a multipart reader for the request body, if the request is of the right type. - fn multipart_body(&mut self) -> Option>>; -} - -impl<'mw, 'server, D: 'mw> MultipartBody<'mw, 'server> for NickelRequest<'mw, 'server, D> { - fn multipart_body(&mut self) -> Option>> { - Multipart::from_request(Maybe(self)).ok() - } -} - -impl<'r, 'mw: 'r, 'server: 'mw, D: 'mw> AsRef<&'r mut NickelRequest<'mw, 'server, D>> - for Maybe<'r, 'mw, 'server, D> -{ - fn as_ref(&self) -> &&'r mut NickelRequest<'mw, 'server, D> { - &self.0 - } -} - -impl<'r, 'mw: 'r, 'server: 'mw, D: 'mw> AsMut<&'r mut NickelRequest<'mw, 'server, D>> - for Maybe<'r, 'mw, 'server, D> -{ - fn as_mut(&mut self) -> &mut &'r mut NickelRequest<'mw, 'server, D> { - &mut self.0 - } -} - -impl<'r, 'mw: 'r, 'server: 'mw, D: 'mw> Into<&'r mut NickelRequest<'mw, 'server, D>> - for Maybe<'r, 'mw, 'server, D> -{ - fn into(self) -> &'r mut NickelRequest<'mw, 'server, D> { - self.0 - } -} - -impl<'r, 'mw: 'r, 'server: 'mw, D: 'mw> From<&'r mut NickelRequest<'mw, 'server, D>> - for Maybe<'r, 'mw, 'server, D> -{ - fn from(req: &'r mut NickelRequest<'mw, 'server, D>) -> Self { - Maybe(req) - } -}