use hyper::net::Fresh;
use hyper::header::ContentType;
use hyper::method::Method;
use hyper::server::{Handler, Request, Response};
use mime::{Mime, TopLevel, SubLevel, Attr, Value};
use super::{Multipart, HttpRequest};
pub struct Switch<H, M> {
normal: H,
multipart: M,
}
impl<H, M> Switch<H, M> where H: Handler, M: MultipartHandler {
pub fn new(normal: H, multipart: M) -> Switch<H, M> {
Switch {
normal: normal,
multipart: 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),
}
}
}
pub trait MultipartHandler: Send + Sync {
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 Request<'a, 'b> {
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,
}
)
})
}
}