use std::io;
use std::io::Cursor;
use std::io::Read;
use std::fs::File;
use rustc_serialize;
pub struct Response {
pub status_code: u16,
pub headers: Vec<(String, String)>,
pub data: ResponseBody,
}
impl Response {
#[inline]
pub fn success(&self) -> bool {
self.status_code >= 200 && self.status_code < 400
}
#[inline]
pub fn error(&self) -> bool {
!self.success()
}
#[inline]
pub fn redirect(target: &str) -> Response {
Response {
status_code: 303,
headers: vec![("Location".to_owned(), target.to_owned())],
data: ResponseBody::empty(),
}
}
#[inline]
pub fn html<D>(content: D) -> Response where D: Into<Vec<u8>> {
Response {
status_code: 200,
headers: vec![("Content-Type".to_owned(), "text/html; charset=utf8".to_owned())],
data: ResponseBody::from_data(content),
}
}
#[inline]
pub fn svg<D>(content: D) -> Response where D: Into<Vec<u8>> {
Response {
status_code: 200,
headers: vec![("Content-Type".to_owned(), "image/svg+xml; charset=utf8".to_owned())],
data: ResponseBody::from_data(content),
}
}
#[inline]
pub fn text<S>(text: S) -> Response where S: Into<String> {
Response {
status_code: 200,
headers: vec![("Content-Type".to_owned(), "text/plain; charset=utf8".to_owned())],
data: ResponseBody::from_string(text),
}
}
#[inline]
pub fn json<T>(content: &T) -> Response where T: rustc_serialize::Encodable {
let data = rustc_serialize::json::encode(content).unwrap();
Response {
status_code: 200,
headers: vec![("Content-Type".to_owned(), "application/json".to_owned())],
data: ResponseBody::from_data(data),
}
}
#[inline]
pub fn basic_http_auth_login_required(realm: &str) -> Response {
Response {
status_code: 401,
headers: vec![("WWW-Authenticate".to_owned(), format!("Basic realm=\"{}\"", realm))],
data: ResponseBody::empty(),
}
}
#[inline]
pub fn empty_400() -> Response {
Response {
status_code: 400,
headers: vec![],
data: ResponseBody::empty()
}
}
#[inline]
pub fn empty_404() -> Response {
Response {
status_code: 404,
headers: vec![],
data: ResponseBody::empty()
}
}
#[inline]
pub fn with_status_code(mut self, code: u16) -> Response {
self.status_code = code;
self
}
}
pub struct ResponseBody {
data: Box<Read + Send>,
data_length: Option<usize>,
}
impl ResponseBody {
#[doc(hidden)]
#[inline]
pub fn into_inner(self) -> (Box<Read + Send>, Option<usize>) {
(self.data, self.data_length)
}
#[inline]
pub fn empty() -> ResponseBody {
ResponseBody {
data: Box::new(io::empty()),
data_length: Some(0),
}
}
#[inline]
pub fn from_reader<R>(data: R) -> ResponseBody where R: Read + Send + 'static {
ResponseBody {
data: Box::new(data),
data_length: None,
}
}
#[inline]
pub fn from_data<D>(data: D) -> ResponseBody where D: Into<Vec<u8>> {
let data = data.into();
let len = data.len();
ResponseBody {
data: Box::new(Cursor::new(data)),
data_length: Some(len),
}
}
#[inline]
pub fn from_file(file: File) -> ResponseBody {
let len = file.metadata().map(|metadata| metadata.len() as usize).ok();
ResponseBody {
data: Box::new(file),
data_length: len,
}
}
#[inline]
pub fn from_string<S>(data: S) -> ResponseBody where S: Into<String> {
ResponseBody::from_data(data.into().into_bytes())
}
}