2016-03-28 09:34:09 +00:00
|
|
|
use std::io::{Read, Write};
|
|
|
|
use std::fs::File;
|
|
|
|
use std::fmt;
|
|
|
|
|
2016-10-04 00:09:13 +00:00
|
|
|
use http::mime::{Mime, TopLevel, SubLevel};
|
|
|
|
use http::hyper::{header, FreshHyperResponse, StatusCode};
|
2016-10-25 09:17:49 +00:00
|
|
|
use outcome::{self, IntoOutcome};
|
|
|
|
use outcome::Outcome::*;
|
|
|
|
|
2016-10-25 14:42:10 +00:00
|
|
|
/// Type alias for the `Outcome` of a `Responder`.
|
2016-10-25 09:17:49 +00:00
|
|
|
pub type Outcome<'a> = outcome::Outcome<(), (), (StatusCode, FreshHyperResponse<'a>)>;
|
2016-10-04 00:09:13 +00:00
|
|
|
|
2016-10-25 11:03:50 +00:00
|
|
|
impl<'a, T, E> IntoOutcome<(), (), (StatusCode, FreshHyperResponse<'a>)> for Result<T, E> {
|
|
|
|
fn into_outcome(self) -> Outcome<'a> {
|
|
|
|
match self {
|
|
|
|
Ok(_) => Success(()),
|
|
|
|
Err(_) => Failure(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-28 09:34:09 +00:00
|
|
|
pub trait Responder {
|
2016-11-02 16:39:41 +00:00
|
|
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a>;
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Responder for &'a str {
|
2016-10-25 09:17:49 +00:00
|
|
|
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
|
2016-08-27 01:37:28 +00:00
|
|
|
if res.headers().get::<header::ContentType>().is_none() {
|
|
|
|
let mime = Mime(TopLevel::Text, SubLevel::Plain, vec![]);
|
|
|
|
res.headers_mut().set(header::ContentType(mime));
|
|
|
|
}
|
|
|
|
|
2016-10-25 09:17:49 +00:00
|
|
|
res.send(self.as_bytes()).into_outcome()
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Responder for String {
|
2016-10-25 09:17:49 +00:00
|
|
|
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
2016-08-27 01:37:28 +00:00
|
|
|
if res.headers().get::<header::ContentType>().is_none() {
|
|
|
|
let mime = Mime(TopLevel::Text, SubLevel::Html, vec![]);
|
|
|
|
res.headers_mut().set(header::ContentType(mime));
|
|
|
|
}
|
2016-10-09 11:29:02 +00:00
|
|
|
|
2016-10-25 09:17:49 +00:00
|
|
|
res.send(self.as_bytes()).into_outcome()
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Responder for File {
|
2016-10-25 09:17:49 +00:00
|
|
|
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
2016-10-09 11:29:02 +00:00
|
|
|
let size = match self.metadata() {
|
|
|
|
Ok(md) => md.len(),
|
|
|
|
Err(e) => {
|
|
|
|
error_!("Failed to read file metadata: {:?}", e);
|
2016-10-25 09:17:49 +00:00
|
|
|
return Forward((StatusCode::InternalServerError, res));
|
2016-10-09 11:29:02 +00:00
|
|
|
}
|
|
|
|
};
|
2016-03-28 09:34:09 +00:00
|
|
|
|
|
|
|
let mut v = Vec::new();
|
2016-10-09 11:29:02 +00:00
|
|
|
if let Err(e) = self.read_to_end(&mut v) {
|
|
|
|
error_!("Failed to read file: {:?}", e);
|
2016-10-25 09:17:49 +00:00
|
|
|
return Forward((StatusCode::InternalServerError, res));
|
2016-10-09 11:29:02 +00:00
|
|
|
}
|
2016-03-28 09:34:09 +00:00
|
|
|
|
2016-10-09 11:29:02 +00:00
|
|
|
res.headers_mut().set(header::ContentLength(size));
|
2016-10-25 09:17:49 +00:00
|
|
|
res.start().and_then(|mut stream| stream.write_all(&v)).into_outcome()
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Responder> Responder for Option<T> {
|
2016-10-25 09:17:49 +00:00
|
|
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
2016-10-09 11:29:02 +00:00
|
|
|
if let Some(ref mut val) = *self {
|
|
|
|
val.respond(res)
|
|
|
|
} else {
|
|
|
|
warn_!("Response was `None`.");
|
2016-10-25 09:17:49 +00:00
|
|
|
Forward((StatusCode::NotFound, res))
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Responder, E: fmt::Debug> Responder for Result<T, E> {
|
|
|
|
// prepend with `default` when using impl specialization
|
2016-10-25 09:17:49 +00:00
|
|
|
default fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
2016-10-09 11:29:02 +00:00
|
|
|
match *self {
|
|
|
|
Ok(ref mut val) => val.respond(res),
|
|
|
|
Err(ref e) => {
|
|
|
|
error_!("{:?}", e);
|
2016-10-25 09:17:49 +00:00
|
|
|
Forward((StatusCode::InternalServerError, res))
|
2016-10-09 11:29:02 +00:00
|
|
|
}
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Responder, E: Responder + fmt::Debug> Responder for Result<T, E> {
|
2016-10-25 09:17:49 +00:00
|
|
|
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
|
2016-04-23 02:48:03 +00:00
|
|
|
match *self {
|
|
|
|
Ok(ref mut responder) => responder.respond(res),
|
2016-09-30 22:20:11 +00:00
|
|
|
Err(ref mut responder) => responder.respond(res),
|
2016-03-28 09:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|