use std::fmt;
use std::old_io::{ IoResult, MemReader};
use std::old_io as io;
use hyper::net::Fresh;
pub use hyper::server::Response as HttpResponse;
pub use hyper::header as headers;
use status;
pub struct Response {
pub content_type: Option<headers::ContentType>,
pub body: Option<Box<Reader + Send>>,
pub status: Option<status::Status>
}
pub trait IntoReader {
type OutReader: Reader;
fn into_reader(self) -> Self::OutReader;
}
impl Response {
pub fn new() -> Response {
Response { body: None, content_type: None, status: Some(status::Ok) }
}
pub fn set_body<I>(&mut self, data: I)
where I: IntoReader, <I as IntoReader>::OutReader: Send + 'static {
self.body = Some(Box::new(data.into_reader()));
}
pub fn with_body<I>(data: I) -> Response
where I: IntoReader, <I as IntoReader>::OutReader: Send + 'static {
let mut res = Response::new();
res.body = Some(Box::new(data.into_reader()));
res
}
pub fn write_back(self, mut http_res: HttpResponse<Fresh>) {
*http_res.status_mut() = self.status.clone().unwrap_or(status::Ok);
let out = match self.body {
Some(body) => write_with_body(http_res, body),
None => {
http_res.headers_mut().set(headers::ContentLength(0));
http_res.start().and_then(|res| res.end())
}
};
match out {
Err(e) => {
error!("Error writing response: {}", e);
},
_ => {}
}
}
}
impl IntoReader for String {
type OutReader = MemReader;
fn into_reader(self) -> MemReader {
MemReader::new(self.into_bytes())
}
}
impl fmt::Debug for Response {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(writeln!(f, "Response {{"));
if let Some(ref content_type) = self.content_type {
try!(writeln!(f, " content_type: {:?}", content_type));
}
try!(writeln!(f, " status: {:?}", self.status));
try!(writeln!(f, " body: {}", if self.body.is_some() { "{omitted}" } else { "{empty}"}));
try!(write!(f, "}}"));
Ok(())
}
}
fn write_with_body(mut res: HttpResponse<Fresh>, mut body: Box<Reader + Send>) -> IoResult<()> {
let content_type = headers::ContentType("application/json".parse().unwrap());
res.headers_mut().set(content_type);
let mut res = try!(res.start());
let mut buf = &mut [0; 1024 * 64];
loop {
let len = match body.read(buf) {
Ok(len) => len,
Err(ref e) if e.kind == io::EndOfFile => break,
Err(e) => { return Err(e) },
};
try!(res.write_all(&buf[..len]))
}
res.end()
}