webframework_core/
response.rs

1use crate::WebResult;
2
3use failure::{Context, Fail, Error};
4pub use http::StatusCode;
5use http::header::{HeaderMap, HeaderValue, HeaderName};
6use hyper;
7use futures::future::{self, Future};
8use futures::Stream;
9
10#[derive(Debug, Fail, Clone)]
11pub enum ResponseErrorKind {
12    #[fail(display = "unknown error")]
13    UnknownError,
14    #[fail(display = "an error occurred with the inner Body type")]
15    BodyError,
16}
17
18#[derive(Debug)]
19pub struct ResponseError {
20    inner: Context<ResponseErrorKind>,
21}
22
23impl_fail_boilerplate!(ResponseErrorKind, ResponseError);
24
25enum ResponseBody {
26    Text(String),
27}
28
29impl ResponseBody {
30    fn as_bytes_fut(self) -> impl Future<Item = Vec<u8>, Error = Error> {
31        match self {
32            ResponseBody::Text(s) => future::ok(s.into_bytes()),
33        }
34    }
35}
36
37pub struct Response {
38    status: Option<StatusCode>,
39    body: Option<ResponseBody>,
40    headers: HeaderMap,
41}
42
43impl Response {
44    pub fn from_string<S: ToString>(cont: S) -> Response {
45        Response {
46            status: None,
47            body: Some(ResponseBody::Text(cont.to_string())),
48            headers: HeaderMap::new(),
49        }
50    }
51
52    pub fn with_status(self, status: StatusCode) -> Self {
53        Response {
54            status: Some(status),
55            ..self
56        }
57    }
58
59    pub fn with_header(mut self, key: HeaderName, value: HeaderValue) -> Self {
60        self.headers.insert(key, value);
61        self
62    }
63
64    pub fn as_response(self) -> WebResult<hyper::Response<hyper::Body>> {
65        let mut resp = hyper::Response::builder();
66
67        if let Some(status) = self.status {
68            resp.status(status);
69        }
70
71        for (k, v) in &self.headers {
72            resp.header(k, v);
73        }
74
75        if let Some(body) = self.body {
76            Ok(resp.body(hyper::Body::wrap_stream(body.as_bytes_fut().into_stream().map_err(|e| {
77                e.context(ResponseErrorKind::BodyError).compat()
78            })))?)
79        } else {
80            Ok(resp.body(hyper::Body::empty())?)
81        }
82    }
83}
84
85pub struct Redirect(HeaderValue);
86
87impl Redirect {
88    pub fn from_str(val: &str) -> WebResult<Redirect> {
89        Ok(Redirect(val.parse()?))
90    }
91}
92
93impl<'a> From<&'a str> for Response {
94    fn from(s: &'a str) -> Response {
95        Response::from_string(s)
96    }
97}
98
99impl From<String> for Response {
100    fn from(s: String) -> Response {
101        Response::from_string(s)
102    }
103}
104
105impl From<Redirect> for Response {
106    fn from(r: Redirect) -> Response {
107        Response::from_string("")
108            .with_header("Location".parse().unwrap(), r.0)
109            .with_status(StatusCode::SEE_OTHER)
110    }
111}