use std;
use std::io::{self, Write};
use std::error;
use std::borrow::Cow;
use std::convert::From;
use std::str::{from_utf8, Utf8Error};
use std::string::{FromUtf8Error};
use std::fs::File;
use std::path::Path;
use hyper;
use anymap::AnyMap;
use StatusCode;
use header::{
Headers,
ContentType,
Connection,
ConnectionOption
};
use filter::{FilterContext, ResponseFilter};
use filter::ResponseAction as Action;
use mime::{Mime, TopLevel, SubLevel};
use server::Global;
use utils::BytesExt;
#[derive(Debug)]
pub enum Error {
Filter(String),
Io(io::Error)
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
Error::Io(err)
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
Error::Filter(ref desc) => write!(f, "filter error: {}", desc),
Error::Io(ref e) => write!(f, "io error: {}", e)
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::Filter(ref desc) => desc,
Error::Io(ref e) => e.description()
}
}
fn cause(&self) -> Option<&std::error::Error> {
match *self {
Error::Filter(_) => None,
Error::Io(ref e) => Some(e)
}
}
}
pub enum FileError<'a, 'b> {
Open(io::Error, Response<'a, 'b>),
Send(io::Error)
}
impl<'a, 'b> FileError<'a, 'b> {
pub fn recover_response(self) -> Result<Response<'a, 'b>, FileError<'a, 'b>> {
match self {
FileError::Open(_, r) => Ok(r),
FileError::Send(_) => Err(self),
}
}
pub fn send_not_found<'d, M: Into<Data<'d>>>(self, message: M) -> Result<(), FileError<'a, 'b>> {
match self {
FileError::Open(e, mut response) => if let io::ErrorKind::NotFound = e.kind() {
response.set_status(StatusCode::NotFound);
response.send(message);
Ok(())
} else {
Err(FileError::Open(e, response))
},
e => Err(e)
}
}
pub fn ignore_send_error(self) -> Result<(), (io::Error, Response<'a, 'b>)> {
match self {
FileError::Open(e, response) => Err((e, response)),
_ => Ok(())
}
}
}
impl<'a, 'b> Into<io::Error> for FileError<'a, 'b> {
fn into(self) -> io::Error {
match self {
FileError::Open(e, _) => e,
FileError::Send(e) => e
}
}
}
impl<'a, 'b> std::fmt::Debug for FileError<'a, 'b> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
FileError::Open(ref e, _) => write!(f, "FileError::Open({:?}, Response)", e),
FileError::Send(ref e) => write!(f, "FileError::Send({:?})", e)
}
}
}
impl<'a, 'b> std::fmt::Display for FileError<'a, 'b> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
FileError::Open(ref e, _) => write!(f, "failed to open a file: {}", e),
FileError::Send(ref e) => write!(f, "failed to send a file: {}", e)
}
}
}
impl<'a, 'b> error::Error for FileError<'a, 'b> {
fn description(&self) -> &str {
match *self {
FileError::Open(ref e, _) => e.description(),
FileError::Send(ref e) => e.description()
}
}
fn cause(&self) -> Option<&std::error::Error> {
match *self {
FileError::Open(ref e, _) => Some(e),
FileError::Send(ref e) => Some(e)
}
}
}
#[derive(Clone)]
pub enum Data<'a> {
Bytes(Cow<'a, [u8]>),
String(Cow<'a, str>)
}
impl<'a> Data<'a> {
pub fn as_bytes(&self) -> &[u8] {
match self {
&Data::Bytes(ref bytes) => bytes,
&Data::String(ref string) => string.as_bytes(),
}
}
pub fn into_bytes(self) -> Vec<u8> {
match self {
Data::Bytes(bytes) => bytes.into_owned(),
Data::String(string) => string.into_owned().into_bytes()
}
}
pub fn as_string(&self) -> Result<&str, Utf8Error> {
match self {
&Data::Bytes(ref bytes) => from_utf8(bytes),
&Data::String(ref string) => Ok(string),
}
}
pub fn into_string(self) -> Result<String, FromUtf8Error> {
match self {
Data::Bytes(bytes) => String::from_utf8(bytes.into_owned()),
Data::String(string) => Ok(string.into_owned())
}
}
}
impl<'a> Into<Data<'a>> for Vec<u8> {
fn into(self) -> Data<'a> {
Data::Bytes(Cow::Owned(self))
}
}
impl<'a> Into<Data<'a>> for &'a [u8] {
fn into(self) -> Data<'a> {
Data::Bytes(Cow::Borrowed(self))
}
}
impl<'a> Into<Data<'a>> for String {
fn into(self) -> Data<'a> {
Data::String(Cow::Owned(self))
}
}
impl<'a> Into<Data<'a>> for &'a str {
fn into(self) -> Data<'a> {
Data::String(Cow::Borrowed(self))
}
}
pub struct Response<'a, 'b> {
writer: Option<hyper::server::response::Response<'a>>,
filters: &'b Vec<Box<ResponseFilter>>,
global: &'b Global,
filter_storage: Option<AnyMap>,
force_close: bool
}
impl<'a, 'b> Response<'a, 'b> {
#[doc(hidden)]
pub fn new(
response: hyper::server::response::Response<'a>,
filters: &'b Vec<Box<ResponseFilter>>,
global: &'b Global,
force_close: bool
) -> Response<'a, 'b> {
Response {
writer: Some(response),
filters: filters,
global: global,
filter_storage: Some(AnyMap::new()),
force_close: force_close
}
}
pub fn status(&self) -> StatusCode {
self.writer.as_ref().expect("status accessed after drop").status()
}
pub fn set_status(&mut self, status: StatusCode) {
if let Some(ref mut writer) = self.writer {
*writer.status_mut() = status;
}
}
pub fn headers(&self) -> &Headers {
self.writer.as_ref().expect("headers accessed after drop").headers()
}
pub fn headers_mut(&mut self) -> &mut Headers {
self.writer.as_mut().expect("headers mutably accessed after drop").headers_mut()
}
pub fn filter_storage(&self) -> &AnyMap {
self.filter_storage.as_ref().expect("filter storage accessed after drop")
}
pub fn filter_storage_mut(&mut self) -> &mut AnyMap {
self.filter_storage.as_mut().expect("filter storage mutably accessed after drop")
}
#[allow(unused_must_use)]
pub fn send<'d, Content: Into<Data<'d>>>(self, content: Content) {
self.try_send(content);
}
pub fn try_send<'d, Content: Into<Data<'d>>>(mut self, content: Content) -> Result<(), Error> {
self.send_sized(content)
}
fn send_sized<'d, Content: Into<Data<'d>>>(&mut self, content: Content) -> Result<(), Error> {
let mut writer = self.writer.take().expect("response used after drop");
let mut filter_storage = self.filter_storage.take().expect("response used after drop");
if self.filters.is_empty() {
if self.force_close {
writer.headers_mut().set(Connection(vec![ConnectionOption::Close]));
}
writer.send(content.into().as_bytes()).map_err(|e| e.into())
} else {
let mut buffer = vec![];
let (status, write_queue) = try!(filter_headers(
self.filters,
writer.status(),
writer.headers_mut(),
self.global,
&mut filter_storage
));
if self.force_close {
writer.headers_mut().set(Connection(vec![ConnectionOption::Close]));
}
*writer.status_mut() = status;
for action in write_queue {
match action {
Action::Next(Some(content)) => buffer.push_bytes(content.as_bytes()),
Action::Next(None) => {},
Action::Abort(e) => return Err(Error::Filter(e)),
Action::SilentAbort => break
}
}
let filter_result = filter_content(self.filters, content, self.global, &mut filter_storage);
match filter_result {
Action::Next(Some(content)) => buffer.push_bytes(content.as_bytes()),
Action::Abort(e) => return Err(Error::Filter(e)),
_ => {}
}
let write_queue = try!(filter_end(self.filters, self.global, &mut filter_storage));
for action in write_queue {
match action {
Action::Next(Some(content)) => buffer.push_bytes(content.as_bytes()),
Action::Next(None) => {},
Action::Abort(e) => return Err(Error::Filter(e)),
Action::SilentAbort => break
}
}
writer.send(&buffer).map_err(|e| e.into())
}
}
pub fn send_file<P: AsRef<Path>>(self, path: P) -> Result<(), FileError<'a, 'b>> {
self.send_file_with_mime(path, ::file::ext_to_mime)
}
pub fn send_file_with_mime<P, F>(mut self, path: P, to_mime: F) -> Result<(), FileError<'a, 'b>> where
P: AsRef<Path>,
F: FnOnce(&str) -> Option<Mime>
{
let path: &Path = path.as_ref();
let mime = path
.extension()
.and_then(|ext| to_mime(&ext.to_string_lossy()))
.unwrap_or(Mime(TopLevel::Application, SubLevel::Ext("octet-stream".into()), vec![]));
let mut file = match File::open(path) {
Ok(file) => file,
Err(e) => return Err(FileError::Open(e, self))
};
let metadata = match file.metadata() {
Ok(metadata) => metadata,
Err(e) => return Err(FileError::Open(e, self))
};
self.headers_mut().set(ContentType(mime));
let mut writer = unsafe { self.into_raw(metadata.len()) };
io::copy(&mut file, &mut writer).map_err(|e| FileError::Send(e)).map(|_| ())
}
pub fn into_chunked(mut self) -> Chunked<'a, 'b> {
let mut writer = self.writer.take().expect("response used after drop");
writer.headers_mut().remove::<::header::ContentLength>();
writer.headers_mut().remove_raw("content-length");
let writer = filter_headers(
self.filters,
writer.status(),
writer.headers_mut(),
self.global,
self.filter_storage_mut()
).and_then(|(status, write_queue)|{
if self.force_close {
writer.headers_mut().set(Connection(vec![ConnectionOption::Close]));
}
*writer.status_mut() = status;
let mut writer = try!(writer.start());
for action in write_queue {
match action {
Action::Next(Some(content)) => try!(writer.write_all(content.as_bytes())),
Action::Next(None) => {},
Action::Abort(e) => return Err(Error::Filter(e)),
Action::SilentAbort => break
}
}
Ok(writer)
});
Chunked {
writer: Some(writer),
filters: self.filters,
global: self.global,
filter_storage: self.filter_storage.take().expect("response used after drop")
}
}
pub unsafe fn into_raw(mut self, content_length: u64) -> Raw<'a> {
let mut writer = self.writer.take().expect("response used after drop");
if self.force_close {
writer.headers_mut().set(Connection(vec![ConnectionOption::Close]));
}
writer.headers_mut().remove_raw("content-length");
writer.headers_mut().set(::header::ContentLength(content_length));
Raw {
writer: Some(writer.start())
}
}
}
#[allow(unused_must_use)]
impl<'a, 'b> Drop for Response<'a, 'b> {
fn drop(&mut self) {
if self.writer.is_some() {
self.send_sized(&[][..]);
}
}
}
pub struct Chunked<'a, 'b> {
writer: Option<Result<hyper::server::response::Response<'a, hyper::net::Streaming>, Error>>,
filters: &'b Vec<Box<ResponseFilter>>,
global: &'b Global,
filter_storage: AnyMap
}
impl<'a, 'b> Chunked<'a, 'b> {
pub fn filter_storage(&self) -> &AnyMap {
&self.filter_storage
}
pub fn filter_storage_mut(&mut self) -> &mut AnyMap {
&mut self.filter_storage
}
#[allow(unused_must_use)]
pub fn send<'d, Content: Into<Data<'d>>>(&mut self, content: Content) {
self.try_send(content);
}
pub fn try_send<'d, Content: Into<Data<'d>>>(&mut self, content: Content) -> Result<usize, Error> {
let mut writer = match self.writer {
Some(Ok(ref mut writer)) => writer,
None => return Err(Error::Io(io::Error::new(io::ErrorKind::BrokenPipe, "write after close"))),
Some(Err(_)) => if let Some(Err(e)) = self.writer.take() {
return Err(e);
} else { unreachable!(); }
};
let filter_result = filter_content(self.filters, content, self.global, &mut self.filter_storage);
let write_result = match filter_result {
Action::Next(Some(ref s)) => {
let buf = s.as_bytes();
match writer.write_all(buf) {
Ok(()) => Some(Ok(buf.len())),
Err(e) => Some(Err(e))
}
},
_ => None
};
match write_result {
Some(Ok(l)) => Ok(l),
Some(Err(e)) => Err(Error::Io(e)),
None => match filter_result {
Action::Abort(e) => Err(Error::Filter(e)),
Action::Next(None) => Ok(0),
_ => unreachable!()
}
}
}
pub fn end(mut self) -> Result<(), Error> {
self.finish()
}
fn finish(&mut self) -> Result<(), Error> {
let mut writer = try!(self.writer.take().expect("can only finish once"));
let write_queue = try!(filter_end(self.filters, self.global, &mut self.filter_storage));
for action in write_queue {
try!{
match action {
Action::Next(Some(content)) => writer.write_all(content.as_bytes()),
Action::Abort(e) => return Err(Error::Filter(e)),
_ => Ok(())
}
}
}
writer.end().map_err(|e| Error::Io(e))
}
fn borrow_writer(&mut self) -> Result<&mut hyper::server::response::Response<'a, hyper::net::Streaming>, Error> {
match self.writer {
Some(Ok(ref mut writer)) => Ok(writer),
None => Err(Error::Io(io::Error::new(io::ErrorKind::BrokenPipe, "write after close"))),
Some(Err(_)) => if let Some(Err(e)) = self.writer.take() {
Err(e)
} else { unreachable!(); }
}
}
}
impl<'a, 'b> Write for Chunked<'a, 'b> {
fn write(&mut self, content: &[u8]) -> io::Result<usize> {
response_to_io_result(self.try_send(content))
}
fn write_all(&mut self, content: &[u8]) -> io::Result<()> {
self.write(content).map(|_| ())
}
fn flush(&mut self) -> io::Result<()> {
let mut writer = try!(response_to_io_result(self.borrow_writer()));
writer.flush()
}
}
#[allow(unused_must_use)]
impl<'a, 'b> Drop for Chunked<'a, 'b> {
fn drop(&mut self) {
if self.writer.is_some() {
self.finish();
}
}
}
pub struct Raw<'a> {
writer: Option<Result<hyper::server::response::Response<'a, hyper::net::Streaming>, io::Error>>
}
impl<'a> Raw<'a> {
#[allow(unused_must_use)]
pub fn send<'d, Content: Into<Data<'d>>>(&mut self, content: Content) {
self.try_send(content);
}
pub fn try_send<'d, Content: Into<Data<'d>>>(&mut self, content: Content) -> io::Result<()> {
self.write_all(content.into().as_bytes())
}
pub fn end(mut self) -> io::Result<()> {
let writer = match self.writer.take() {
Some(Ok(writer)) => writer,
None => return Ok(()), Some(Err(e)) => return Err(e)
};
writer.end()
}
fn borrow_writer(&mut self) -> io::Result<&mut hyper::server::response::Response<'a, hyper::net::Streaming>> {
match self.writer {
Some(Ok(ref mut writer)) => Ok(writer),
None => Err(io::Error::new(io::ErrorKind::BrokenPipe, "write after close")),
Some(Err(_)) => if let Some(Err(e)) = self.writer.take() {
Err(e)
} else { unreachable!(); }
}
}
}
impl<'a> Write for Raw<'a> {
fn write(&mut self, content: &[u8]) -> io::Result<usize> {
let mut writer = try!(self.borrow_writer());
writer.write(content)
}
fn write_all(&mut self, content: &[u8]) -> io::Result<()> {
let mut writer = try!(self.borrow_writer());
writer.write_all(content)
}
fn flush(&mut self) -> io::Result<()> {
let mut writer = try!(self.borrow_writer());
writer.flush()
}
}
fn response_to_io_result<T>(res: Result<T, Error>) -> io::Result<T> {
match res {
Ok(v) => Ok(v),
Err(Error::Io(e)) => Err(e),
Err(e) => Err(io::Error::new(io::ErrorKind::Other, e))
}
}
fn filter_headers<'a>(
filters: &'a [Box<ResponseFilter>],
status: StatusCode,
headers: &mut Headers,
global: &Global,
filter_storage: &mut AnyMap
) -> Result<(StatusCode, Vec<Action<'a>>), Error> {
let mut write_queue = Vec::new();
let mut header_result = (status, Action::Next(None));
for filter in filters {
header_result = match header_result {
(_, Action::SilentAbort) => break,
(_, Action::Abort(_)) => break,
(status, r) => {
write_queue.push(r);
let filter_res = {
let filter_context = FilterContext {
storage: filter_storage,
global: global,
};
filter.begin(filter_context, status, headers)
};
match filter_res {
(status, Action::Abort(e)) => (status, Action::Abort(e)),
(status, result) => {
let mut error = None;
write_queue = write_queue.into_iter().filter_map(|action| match action {
Action::Next(content) => {
let filter_context = FilterContext {
storage: filter_storage,
global: global,
};
Some(filter.write(filter_context, content))
},
Action::SilentAbort => None,
Action::Abort(e) => {
error = Some(e);
None
}
}).collect();
match error {
Some(e) => (status, Action::Abort(e)),
None => (status, result)
}
}
}
}
}
}
match header_result {
(_, Action::Abort(e)) => Err(Error::Filter(e)),
(status, action) => {
write_queue.push(action);
Ok((status, write_queue))
}
}
}
fn filter_content<'a, 'd: 'a, Content: Into<Data<'d>>>(filters: &'a [Box<ResponseFilter>], content: Content, global: &Global, filter_storage: &mut AnyMap) -> Action<'a> {
let mut filter_result = Action::next(Some(content));
for filter in filters {
filter_result = match filter_result {
Action::Next(content) => {
let filter_context = FilterContext {
storage: filter_storage,
global: global,
};
filter.write(filter_context, content)
},
_ => break
}
}
filter_result
}
fn filter_end<'a>(filters: &'a [Box<ResponseFilter>], global: &Global, filter_storage: &mut AnyMap) -> Result<Vec<Action<'a>>, Error> {
let otuputs: Vec<_> = filters.into_iter()
.rev()
.map(|filter| {
let filter_context = FilterContext {
storage: filter_storage,
global: global,
};
filter.end(filter_context)
})
.take_while(|a| if let &Action::Next(_) = a { true } else { false })
.map(|a| Some(a))
.collect();
let mut write_queue = vec![];
for (filter, action) in filters.into_iter().zip(otuputs.into_iter().chain(::std::iter::repeat(None))) {
let mut error = None;
write_queue = write_queue.into_iter().filter_map(|action| match action {
Action::Next(content) => {
let filter_context = FilterContext {
storage: filter_storage,
global: global,
};
Some(filter.write(filter_context, content))
},
Action::SilentAbort => None,
Action::Abort(e) => {
error = Some(e);
None
}
}).collect();
if let Some(e) = error {
return Err(Error::Filter(e))
}
if let Some(action) = action {
write_queue.push(action);
}
}
Ok(write_queue)
}