webframework_core/
response.rs1use 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}