| // Copyright 2016 `multipart` Crate Developers |
| // |
| // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or |
| // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or |
| // http://opensource.org/licenses/MIT>, 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::net::Fresh; |
| use hyper::header::ContentType; |
| use hyper::method::Method; |
| use hyper::server::{Handler, Request, Response}; |
| |
| pub use hyper::server::Request as HyperRequest; |
| |
| use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value}; |
| |
| use super::{Multipart, HttpRequest}; |
| |
| /// 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<H, M> { |
| normal: H, |
| multipart: M, |
| } |
| |
| impl<H, M> Switch<H, M> 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<H, M> { |
| Switch { normal, multipart } |
| } |
| } |
| |
| impl<H, M> Handler for Switch<H, M> 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<Request>, Response<Fresh>)`, |
| /// and subsequently static functions. |
| pub trait MultipartHandler: Send + Sync { |
| /// Generate a response from this multipart request. |
| fn handle_multipart<'a, 'k>(&self, |
| multipart: Multipart<Request<'a, 'k>>, |
| response: Response<'a, Fresh>); |
| } |
| |
| impl<F> MultipartHandler for F |
| where F: Fn(Multipart<Request>, Response<Fresh>), F: Send + Sync { |
| fn handle_multipart<'a, 'k>(&self, |
| multipart: Multipart<Request<'a, 'k>>, |
| 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::<ContentType>().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::<ContentType>().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 |
| } |
| } |
| |