1use error::Error;
2use serde_json;
3use response::Serializer;
4use util::BufStream;
5
6use futures::{future, Future, IntoFuture};
7use http;
8
9use std::sync::Arc;
10
11pub trait Catch: Clone {
21
22 type Body: BufStream;
24
25 type Future: Future<Item = http::Response<Self::Body>, Error = Error>;
27
28 fn catch(&mut self, request: &http::Request<()>, error: Error) -> Self::Future;
35}
36
37pub trait IntoCatch<S> {
45 type Catch: Catch;
47
48 fn into_catch(self) -> Self::Catch;
50}
51
52#[derive(Debug, Clone)]
57pub struct DefaultCatch {
58 _p: (),
59}
60
61#[derive(Debug)]
63pub struct FnCatch<F>(Arc<F>);
64
65impl DefaultCatch {
68 pub fn new() -> DefaultCatch {
70 DefaultCatch {
71 _p: (),
72 }
73 }
74}
75
76impl<S> IntoCatch<S> for DefaultCatch
77where S: Serializer,
78{
79 type Catch = DefaultCatch;
80
81 fn into_catch(self) -> Self::Catch {
82 self
83 }
84}
85
86impl Catch for DefaultCatch {
91 type Body = String;
92 type Future = future::FutureResult<http::Response<Self::Body>, Error>;
93
94 fn catch(&mut self, _request: &http::Request<()>, error: Error) -> Self::Future {
95 let status = error.status_code().as_u16();
96 let problem = serde_json::to_string(&error)
97 .unwrap_or_else(|_| {
98 serde_json::to_string(&Error::from(http::status::StatusCode::INTERNAL_SERVER_ERROR))
99 .expect("Error serializing a blank error to JSON")
100 });
101
102 let response = http::response::Builder::new()
104 .status(status)
105 .header("content-type", "application/problem+json")
106 .body(problem)
107 .unwrap();
108
109 future::ok(response)
110 }
111}
112
113impl<F, R, Body, S> IntoCatch<S> for F
116where F: Fn(&http::Request<()>, Error) -> R,
117 R: IntoFuture<Item = http::Response<Body>, Error = Error>,
118 Body: BufStream,
119{
120 type Catch = FnCatch<F>;
121
122 fn into_catch(self) -> Self::Catch {
123 FnCatch(Arc::new(self))
124 }
125}
126
127impl<F, R, Body> Catch for FnCatch<F>
128where F: Fn(&http::Request<()>, Error) -> R,
129 R: IntoFuture<Item = http::Response<Body>, Error = Error>,
130 Body: BufStream,
131{
132 type Body = Body;
133 type Future = R::Future;
134
135 fn catch(&mut self, request: &http::Request<()>, error: Error) -> Self::Future {
136 self.0(request, error).into_future()
137 }
138}
139
140impl<F> Clone for FnCatch<F> {
141 fn clone(&self) -> FnCatch<F> {
142 FnCatch(self.0.clone())
143 }
144}