tower_web/error/
error.rs

1use self::KindPriv::*;
2
3use std::error;
4use std::fmt;
5use http::StatusCode;
6
7/// Builder for Error objects.
8#[derive(Debug)]
9pub struct Builder {
10    kind: Option<(String, String)>,
11    detail: Option<String>,
12    status: Option<StatusCode>,
13}
14
15/// Errors that can happen inside Tower Web.
16/// The object of this type is serializable into "Problem Detail" as defined in RFC7807.
17#[derive(Serialize)]
18pub struct Error {
19    #[serde(rename = "type")]
20    kind: String,
21    title: String,
22    // NOTE: type of this property might be changed in the future.
23    // Nevertheless, String type should be accepted.
24    #[serde(skip_serializing_if = "Option::is_none")]
25    detail: Option<String>,
26    #[serde(skip)]
27    status: StatusCode,
28
29    // TODO: this property isn't used and should be removed
30    #[serde(skip)]
31    error_kind: ErrorKind,
32}
33
34// ===== impl Builder =====
35
36impl Builder {
37    fn new() -> Self {
38        Self {
39            kind: None,
40            detail: None,
41            status: None,
42        }
43    }
44
45    /// Set status of the error.
46    pub fn status(self, status: StatusCode) -> Self {
47        Self {
48            kind: self.kind,
49            detail: self.detail,
50            status: Some(status),
51
52        }
53    }
54
55    /// Set kind and title of the error.
56    pub fn kind(self, kind: &str, title: &str) -> Self {
57        Self {
58            kind: Some((kind.to_owned(), title.to_owned())),
59            detail: self.detail,
60            status: self.status,
61        }
62    }
63
64    /// Set detailed information about the error.
65    pub fn detail(self, detail: &str) -> Self {
66        Self {
67            kind: self.kind,
68            detail: Some(detail.to_owned()),
69            status: self.status,
70        }
71    }
72
73    /// Create an error object.
74    pub fn build(self) -> Error {
75        let mut err =
76            match (self.kind, self.status) {
77                (Some((ref kind, ref title)), Some(status)) => Error::new(kind, title, status),
78                (Some(_), None) => Error::from(StatusCode::INTERNAL_SERVER_ERROR),
79                (None, Some(status)) => Error::from(status),
80                (None, None) => Error::from(StatusCode::INTERNAL_SERVER_ERROR),
81            };
82
83        match self.detail {
84            Some(ref detail) => {
85                err.set_detail(detail);
86                err
87            },
88            None => err,
89        }
90    }
91}
92
93// ===== impl Error =====
94
95impl Error {
96    // TODO: this function should return '&self.kind' property
97    // and its return value should be changed to '&str'
98    /// Returns the corresponding `ErrorKind` for this error.
99    #[deprecated(note="return value of the function will be changed to &str")]
100    pub fn kind(&self) -> &ErrorKind {
101        &self.error_kind
102    }
103
104    /// Create an error object.
105    pub fn new(kind: &str, title: &str, status: StatusCode) -> Self {
106        Self {
107            kind: kind.to_owned(),
108            title: title.to_owned(),
109            detail: None,
110            status,
111
112            // TODO: this property isn't used and should be removed
113            error_kind: ErrorKind::new(&status),
114        }
115    }
116
117    /// Set detailed information about the error.
118    pub fn set_detail(&mut self, value: &str) -> &mut Self {
119        self.detail = Some(value.to_owned());
120        self
121    }
122
123    /// Return a status code for this error.
124    pub fn status_code(&self) -> StatusCode {
125        self.status
126    }
127
128    /// Create an error builder object.
129    pub fn builder() -> Builder {
130        Builder::new()
131    }
132}
133
134impl error::Error for Error {
135    fn description(&self) -> &str {
136        self.status_code().canonical_reason().unwrap_or("Unknown status code")
137    }
138}
139
140impl fmt::Debug for Error {
141    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
142        fmt.debug_struct("Error")
143            .field("kind", &self.kind)
144            .field("title", &self.title)
145            .field("detail", &self.detail)
146            .field("status", &self.status)
147            .finish()
148    }
149}
150
151impl fmt::Display for Error {
152    #[allow(deprecated)] // .cause() is deprecated on nightly
153    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
154        write!(
155            fmt,
156            "[{}] {}",
157            self.kind, self.title,
158        )?;
159
160        if let Some(ref detail) = self.detail {
161            write!(fmt, ": {}", detail)?;
162        }
163
164        use std::error::Error;
165        if let Some(ref cause) = self.cause() {
166            write!(fmt, ": {}", cause)?;
167        }
168
169        Ok(())
170    }
171}
172
173impl From<StatusCode> for Error {
174    fn from(status: StatusCode) -> Self {
175        let title = status.canonical_reason().unwrap_or("Unknown status code");
176        Self {
177            kind: String::from("about:blank"),
178            title: title.to_owned(),
179            detail: None,
180            status,
181
182            // TODO: this property isn't used and should be removed
183            error_kind: ErrorKind::new(&status),
184        }
185    }
186}
187
188// Obsolete
189
190/// A list specifying the general categories of Tower Web errors.
191pub struct ErrorKind {
192    kind: KindPriv,
193}
194
195#[derive(Debug, Eq, PartialEq, Clone, Copy)]
196enum KindPriv {
197    BadRequest,
198    Unauthorized,
199    Fordidden,
200    NotFound,
201    UnprocessableEntity,
202    Internal,
203}
204
205impl From<ErrorKind> for Error {
206    fn from(error_kind: ErrorKind) -> Error {
207        error_kind.status_code().into()
208    }
209}
210
211// ===== impl ErrorKind =====
212
213impl ErrorKind {
214    /// Returns a new `ErrorKind` value representing a 400 -- bad request error.
215    #[deprecated(note="please use 'Error::from(http::StatusCode::BAD_REQUEST)' instead")]
216    pub fn bad_request() -> ErrorKind {
217        ErrorKind { kind: BadRequest }
218    }
219
220    /// Returns `true` if `self` represents a 400 -- bad request error
221    #[deprecated(note="please use 'kind() == http::StatusCode::BAD_REQUEST' instead")]
222    pub fn is_bad_request(&self) -> bool {
223        self.kind == BadRequest
224    }
225
226    /// Returns a new `ErrorKind` value representing a 401 -- unauthorized error.
227    #[deprecated(note="please use 'Error::from(http::StatusCode::UNAUTHORIZED)' instead")]
228    pub fn unauthorized() -> ErrorKind {
229        ErrorKind { kind: Unauthorized }
230    }
231
232    /// Returns a new `ErrorKind` value representing a 403 -- forbidden error.
233    #[deprecated(note="please use 'Error::from(http::StatusCode::FORBIDDEN)' instead")]
234    pub fn forbidden() -> ErrorKind {
235        ErrorKind { kind: Fordidden }
236    }
237
238    /// Returns a new `ErrorKind` value representing a 404 -- not found error
239    #[deprecated(note="please use 'Error::from(http::StatusCode::NOT_FOUND)' instead")]
240    pub fn not_found() -> ErrorKind {
241        ErrorKind { kind: NotFound }
242    }
243
244    /// Returns `true` if `self` represents a 404 -- not found error
245    #[deprecated(note="please use 'kind() == http::StatusCode::NOT_FOUND' instead")]
246    pub fn is_not_found(&self) -> bool {
247        self.kind == NotFound
248    }
249
250    /// Returns a new `ErrorKind` value representing a 422 -- unprocessable entity error
251    #[deprecated(note="please use 'Error::from(http::StatusCode::UNPROCESSABLE_ENTITY)' instead")]
252    pub fn unprocessable_entity() -> ErrorKind {
253        ErrorKind { kind: UnprocessableEntity }
254    }
255
256    /// Returns a new `ErrorKind` value representing 500 -- internal server
257    /// error.
258    #[deprecated(note="please use 'Error::from(http::StatusCode::INTERNAL_SERVER_ERROR)' instead")]
259    pub fn internal() -> ErrorKind {
260        ErrorKind { kind: Internal }
261    }
262
263    /// Returns `true` if `self` represents a 500 -- internal server error.
264    #[deprecated(note="please use 'kind() == http::StatusCode::INTERNAL_SERVER_ERROR' instead")]
265    pub fn is_internal(&self) -> bool {
266        self.kind == Internal
267    }
268
269    fn status_code(&self) -> StatusCode {
270        match self.kind {
271            BadRequest => StatusCode::BAD_REQUEST,
272            Unauthorized => StatusCode::UNAUTHORIZED,
273            Fordidden => StatusCode::FORBIDDEN,
274            NotFound => StatusCode::NOT_FOUND,
275            UnprocessableEntity => StatusCode::UNPROCESSABLE_ENTITY,
276            Internal => StatusCode::INTERNAL_SERVER_ERROR,
277        }
278    }
279
280    fn new(status: &StatusCode) -> Self {
281        match status {
282            &StatusCode::BAD_REQUEST => ErrorKind {
283                kind: BadRequest
284            },
285            &StatusCode::UNAUTHORIZED => ErrorKind {
286                kind: Unauthorized
287            },
288            &StatusCode::FORBIDDEN => ErrorKind {
289                kind: Fordidden
290            },
291            &StatusCode::NOT_FOUND => ErrorKind {
292                kind: NotFound
293            },
294            &StatusCode::UNPROCESSABLE_ENTITY => ErrorKind {
295                kind: UnprocessableEntity
296            },
297            _ => ErrorKind {
298                kind: Internal
299            },
300        }
301    }
302}
303
304impl fmt::Debug for ErrorKind {
305    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
306        match self.kind {
307            BadRequest => "ErrorKind::BadRequest",
308            Unauthorized => "ErrorKind::Unauthorized",
309            Fordidden => "ErrorKind::Forbidden",
310            NotFound => "ErrorKind::NotFound",
311            UnprocessableEntity => "ErrorKind::UnprocessableEntity",
312            Internal => "ErrorKind::Internal",
313        }.fmt(fmt)
314    }
315}