1use std::borrow::Cow;
4use std::fmt;
5
6use either::Either;
7use failure::{self, Fail};
8use http::StatusCode;
9use http::header::{HeaderMap, HeaderValue};
10
11pub trait HttpError: fmt::Debug + fmt::Display + Send + Sync + 'static {
16 fn status_code(&self) -> StatusCode;
18
19 #[allow(unused_variables)]
21 fn append_headers(&self, headers: &mut HeaderMap<HeaderValue>) {}
22
23 fn as_fail(&self) -> Option<&Fail> {
25 None
26 }
27}
28
29impl<L, R> HttpError for Either<L, R>
30where
31 L: HttpError,
32 R: HttpError,
33{
34 fn status_code(&self) -> StatusCode {
35 match *self {
36 Either::Left(ref e) => e.status_code(),
37 Either::Right(ref e) => e.status_code(),
38 }
39 }
40
41 fn as_fail(&self) -> Option<&Fail> {
42 match *self {
43 Either::Left(ref e) => e.as_fail(),
44 Either::Right(ref e) => e.as_fail(),
45 }
46 }
47}
48
49pub struct BadRequest {
51 inner: Either<Cow<'static, str>, failure::Error>,
52}
53
54impl<E: Into<failure::Error>> From<E> for BadRequest {
55 fn from(fail: E) -> Self {
56 BadRequest::from_fail(fail)
57 }
58}
59
60impl BadRequest {
61 #[allow(missing_docs)]
62 pub fn new<S>(message: S) -> BadRequest
63 where
64 S: Into<Cow<'static, str>>,
65 {
66 BadRequest {
67 inner: Either::Left(message.into()),
68 }
69 }
70
71 #[allow(missing_docs)]
72 pub fn from_fail<E>(fail: E) -> BadRequest
73 where
74 E: Into<failure::Error>,
75 {
76 BadRequest {
77 inner: Either::Right(Into::into(fail)),
78 }
79 }
80}
81
82impl fmt::Debug for BadRequest {
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84 match self.inner {
85 Either::Left(ref message) => f.debug_tuple("BadRequest").field(message).finish(),
86 Either::Right(ref err) => f.debug_tuple("BadRequest").field(err).finish(),
87 }
88 }
89}
90
91impl fmt::Display for BadRequest {
92 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93 match self.inner {
94 Either::Left(ref message) => f.write_str(message),
95 Either::Right(ref e) => fmt::Display::fmt(e, f),
96 }
97 }
98}
99
100impl HttpError for BadRequest {
101 fn status_code(&self) -> StatusCode {
102 StatusCode::BAD_REQUEST
103 }
104
105 fn as_fail(&self) -> Option<&Fail> {
106 self.inner.as_ref().right().map(failure::Error::cause)
107 }
108}
109
110pub struct ServerError {
112 inner: Either<Cow<'static, str>, failure::Error>,
113}
114
115impl<E: Into<failure::Error>> From<E> for ServerError {
116 fn from(fail: E) -> Self {
117 ServerError::from_fail(fail)
118 }
119}
120
121impl ServerError {
122 #[allow(missing_docs)]
123 pub fn new<S>(message: S) -> ServerError
124 where
125 S: Into<Cow<'static, str>>,
126 {
127 ServerError {
128 inner: Either::Left(message.into()),
129 }
130 }
131
132 #[allow(missing_docs)]
133 pub fn from_fail<E>(fail: E) -> ServerError
134 where
135 E: Into<failure::Error>,
136 {
137 ServerError {
138 inner: Either::Right(Into::into(fail)),
139 }
140 }
141}
142
143impl fmt::Debug for ServerError {
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 match self.inner {
146 Either::Left(ref message) => f.debug_tuple("ServerError").field(message).finish(),
147 Either::Right(ref err) => f.debug_tuple("ServerError").field(err).finish(),
148 }
149 }
150}
151
152impl fmt::Display for ServerError {
153 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
154 match self.inner {
155 Either::Left(ref message) => f.write_str(message),
156 Either::Right(ref e) => fmt::Display::fmt(e, f),
157 }
158 }
159}
160
161impl HttpError for ServerError {
162 fn status_code(&self) -> StatusCode {
163 StatusCode::INTERNAL_SERVER_ERROR
164 }
165
166 fn as_fail(&self) -> Option<&Fail> {
167 self.inner.as_ref().right().map(failure::Error::cause)
168 }
169}
170
171#[derive(Debug)]
175pub struct NotPresent {
176 message: Cow<'static, str>,
177}
178
179impl NotPresent {
180 #[allow(missing_docs)]
181 pub fn new<S>(message: S) -> NotPresent
182 where
183 S: Into<Cow<'static, str>>,
184 {
185 NotPresent {
186 message: message.into(),
187 }
188 }
189}
190
191impl fmt::Display for NotPresent {
192 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
193 f.write_str(&*self.message)
194 }
195}
196
197impl HttpError for NotPresent {
198 fn status_code(&self) -> StatusCode {
199 StatusCode::BAD_REQUEST
200 }
201}
202
203#[derive(Debug, Fail)]
204#[fail(display = "no route")]
205struct NoRoute;
206
207impl HttpError for NoRoute {
208 fn status_code(&self) -> StatusCode {
209 StatusCode::NOT_FOUND
210 }
211}
212
213#[derive(Debug)]
215pub struct Error {
216 inner: Either<Box<HttpError>, NoRoute>,
217}
218
219impl<E: HttpError> From<E> for Error {
220 fn from(err: E) -> Self {
221 Error {
222 inner: Either::Left(Box::new(err)),
223 }
224 }
225}
226
227impl fmt::Display for Error {
228 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229 match self.inner {
230 Either::Left(ref e) => fmt::Display::fmt(&*e, f),
231 Either::Right(ref e) => fmt::Display::fmt(e, f),
232 }
233 }
234}
235
236impl Error {
237 pub(crate) fn skipped() -> Error {
238 Error {
239 inner: Either::Right(NoRoute),
240 }
241 }
242
243 #[allow(missing_docs)]
244 pub fn is_skipped(&self) -> bool {
245 self.inner.is_right()
246 }
247
248 pub fn as_http_error(&self) -> &HttpError {
250 match self.inner {
251 Either::Left(ref e) => &**e,
252 Either::Right(ref e) => &*e as &HttpError,
253 }
254 }
255}