1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
//! Support for `multipart/form-data` bodies in [Nickel](https://nickel.rs) via the //! [`multipart`](https://crates.io/crates/multipart) crate. //! //! ### Why an external crate? //! Three major reasons led to the decision to move Nickel integration to an external crate. //! //! 1: The part of Nickel's public API that matters to `multipart` (getting headers and //! reading the request) uses Hyper's request type; this means that Nickel's integration //! must necessarily be coupled to Hyper's integration. //! //! 2: Cargo does not allow specifying two different versions of the same crate in the //! same manifest, probably for some good reasons but this crate's author has not looked into it. //! //! 3: Nickel's development moves incredibly slowly; when a new version of Hyper releases, there is //! always a significant lag before Nickel upgrades, //! [sometimes several months](https://github.com/nickel-org/nickel.rs/issues/367)--in this case, //! Hyper was upgraded (in May) two months before the issue was opened (July), but a new version of //! Nickel was not published until four months later (September). //! //! This causes problems for `multipart` because it cannot upgrade Hyper until Nickel does, //! but its Hyper users often want to upgrade their Hyper as soon as possible. //! //! In order to provide up-to-date integration for Hyper, it was necessary to move Nickel //! integration to an external crate so it can be pinned at the version of Hyper that Nickel //! supports. This allows `multipart` to upgrade Hyper arbitrarily and still keep everyone happy. //! //! ### Porting from `multipart`'s Integration //! //! Whereas `multipart` only provided one way to wrap a Nickel request, this crate provides two: //! //! * To continue using `Multipart::from_request()`, wrap the request in //! [`Maybe`](struct.Maybe.html): //! //! ```ignore //! // Where `req` is `&mut nickel::Request` //! - Multipart::from_request(req) //! + use multipart_nickel::Maybe; //! + Multipart::from_request(Maybe(req)) //! ``` //! //! * Import `multipart_nickel::MultipartBody` and call `.multipart_body()`, which returns //! `Option` (which better matches the conventions of `nickel::FormBody` and `nickel::JsonBody`): //! //! ```rust,ignore //! use multipart_nickel::MultipartBody; //! //! // Where `req` is `&mut nickel::Request` //! match req.multipart_body() { //! Some(multipart) => // handle multipart body //! None => // handle regular body //! } //! ``` //! //! This crate also reexports the `server` module from the version of `multipart` //! that it uses, so that you don't have to import `multipart` separately. extern crate hyper; extern crate multipart; extern crate nickel; use nickel::Request as NickelRequest; use hyper::server::Request as HyperRequest; /// The `server` module from the version of `multipart` that this crate uses. pub use multipart::server as multipart_server; use multipart_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> { self.0.origin.multipart_boundary() } 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<Multipart<&mut HyperRequest<'mw, 'server>>>; } impl<'mw, 'server, D: 'mw> MultipartBody<'mw, 'server> for NickelRequest<'mw, 'server, D> { fn multipart_body(&mut self) -> Option<Multipart<&mut HyperRequest<'mw, 'server>>> { 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) } }