actix_web/error/
mod.rs

1//! Error and Result module
2
3// This is meant to be a glob import of the whole error module except for `Error`. Rustdoc can't yet
4// correctly resolve the conflicting `Error` type defined in this module, so these re-exports are
5// expanded manually.
6//
7// See <https://github.com/rust-lang/rust/issues/83375>
8pub use actix_http::error::{ContentTypeError, DispatchError, HttpError, ParseError, PayloadError};
9use derive_more::{Display, Error, From};
10use serde_json::error::Error as JsonError;
11use serde_urlencoded::{de::Error as FormDeError, ser::Error as FormError};
12use url::ParseError as UrlParseError;
13
14use crate::http::StatusCode;
15
16#[allow(clippy::module_inception)]
17mod error;
18mod internal;
19mod macros;
20mod response_error;
21
22pub(crate) use self::macros::{downcast_dyn, downcast_get_type_id};
23pub use self::{error::Error, internal::*, response_error::ResponseError};
24pub use crate::types::EitherExtractError;
25
26/// A convenience [`Result`](std::result::Result) for Actix Web operations.
27///
28/// This type alias is generally used to avoid writing out `actix_http::Error` directly.
29pub type Result<T, E = Error> = std::result::Result<T, E>;
30
31/// An error representing a problem running a blocking task on a thread pool.
32#[derive(Debug, Display, Error)]
33#[display("Blocking thread pool is shut down unexpectedly")]
34#[non_exhaustive]
35pub struct BlockingError;
36
37impl ResponseError for crate::error::BlockingError {}
38
39/// Errors which can occur when attempting to generate resource uri.
40#[derive(Debug, PartialEq, Eq, Display, Error, From)]
41#[non_exhaustive]
42pub enum UrlGenerationError {
43    /// Resource not found.
44    #[display("Resource not found")]
45    ResourceNotFound,
46
47    /// Not all URL parameters covered.
48    #[display("Not all URL parameters covered")]
49    NotEnoughElements,
50
51    /// URL parse error.
52    #[display("{}", _0)]
53    ParseError(UrlParseError),
54}
55
56impl ResponseError for UrlGenerationError {}
57
58/// A set of errors that can occur during parsing urlencoded payloads
59#[derive(Debug, Display, Error, From)]
60#[non_exhaustive]
61pub enum UrlencodedError {
62    /// Can not decode chunked transfer encoding.
63    #[display("Can not decode chunked transfer encoding.")]
64    Chunked,
65
66    /// Payload size is larger than allowed. (default limit: 256kB).
67    #[display(
68        "URL encoded payload is larger ({} bytes) than allowed (limit: {} bytes).",
69        size,
70        limit
71    )]
72    Overflow { size: usize, limit: usize },
73
74    /// Payload size is now known.
75    #[display("Payload size is now known.")]
76    UnknownLength,
77
78    /// Content type error.
79    #[display("Content type error.")]
80    ContentType,
81
82    /// Parse error.
83    #[display("Parse error: {}.", _0)]
84    Parse(FormDeError),
85
86    /// Encoding error.
87    #[display("Encoding error.")]
88    Encoding,
89
90    /// Serialize error.
91    #[display("Serialize error: {}.", _0)]
92    Serialize(FormError),
93
94    /// Payload error.
95    #[display("Error that occur during reading payload: {}.", _0)]
96    Payload(PayloadError),
97}
98
99impl ResponseError for UrlencodedError {
100    fn status_code(&self) -> StatusCode {
101        match self {
102            Self::Overflow { .. } => StatusCode::PAYLOAD_TOO_LARGE,
103            Self::UnknownLength => StatusCode::LENGTH_REQUIRED,
104            Self::ContentType => StatusCode::UNSUPPORTED_MEDIA_TYPE,
105            Self::Payload(err) => err.status_code(),
106            _ => StatusCode::BAD_REQUEST,
107        }
108    }
109}
110
111/// A set of errors that can occur during parsing json payloads
112#[derive(Debug, Display, Error)]
113#[non_exhaustive]
114pub enum JsonPayloadError {
115    /// Payload size is bigger than allowed & content length header set. (default: 2MB)
116    #[display(
117        "JSON payload ({} bytes) is larger than allowed (limit: {} bytes).",
118        length,
119        limit
120    )]
121    OverflowKnownLength { length: usize, limit: usize },
122
123    /// Payload size is bigger than allowed but no content length header set. (default: 2MB)
124    #[display("JSON payload has exceeded limit ({} bytes).", limit)]
125    Overflow { limit: usize },
126
127    /// Content type error
128    #[display("Content type error")]
129    ContentType,
130
131    /// Deserialize error
132    #[display("Json deserialize error: {}", _0)]
133    Deserialize(JsonError),
134
135    /// Serialize error
136    #[display("Json serialize error: {}", _0)]
137    Serialize(JsonError),
138
139    /// Payload error
140    #[display("Error that occur during reading payload: {}", _0)]
141    Payload(PayloadError),
142}
143
144impl From<PayloadError> for JsonPayloadError {
145    fn from(err: PayloadError) -> Self {
146        Self::Payload(err)
147    }
148}
149
150impl ResponseError for JsonPayloadError {
151    fn status_code(&self) -> StatusCode {
152        match self {
153            Self::OverflowKnownLength {
154                length: _,
155                limit: _,
156            } => StatusCode::PAYLOAD_TOO_LARGE,
157            Self::Overflow { limit: _ } => StatusCode::PAYLOAD_TOO_LARGE,
158            Self::Serialize(_) => StatusCode::INTERNAL_SERVER_ERROR,
159            Self::Payload(err) => err.status_code(),
160            _ => StatusCode::BAD_REQUEST,
161        }
162    }
163}
164
165/// A set of errors that can occur during parsing request paths
166#[derive(Debug, Display, Error)]
167#[non_exhaustive]
168pub enum PathError {
169    /// Deserialize error
170    #[display("Path deserialize error: {}", _0)]
171    Deserialize(serde::de::value::Error),
172}
173
174/// Return `BadRequest` for `PathError`
175impl ResponseError for PathError {
176    fn status_code(&self) -> StatusCode {
177        StatusCode::BAD_REQUEST
178    }
179}
180
181/// A set of errors that can occur during parsing query strings.
182#[derive(Debug, Display, Error, From)]
183#[non_exhaustive]
184pub enum QueryPayloadError {
185    /// Query deserialize error.
186    #[display("Query deserialize error: {}", _0)]
187    Deserialize(serde::de::value::Error),
188}
189
190impl ResponseError for QueryPayloadError {
191    fn status_code(&self) -> StatusCode {
192        StatusCode::BAD_REQUEST
193    }
194}
195
196/// Error type returned when reading body as lines.
197#[derive(Debug, Display, Error, From)]
198#[non_exhaustive]
199pub enum ReadlinesError {
200    #[display("Encoding error")]
201    /// Payload size is bigger than allowed. (default: 256kB)
202    EncodingError,
203
204    /// Payload error.
205    #[display("Error that occur during reading payload: {}", _0)]
206    Payload(PayloadError),
207
208    /// Line limit exceeded.
209    #[display("Line limit exceeded")]
210    LimitOverflow,
211
212    /// ContentType error.
213    #[display("Content-type error")]
214    ContentTypeError(ContentTypeError),
215}
216
217impl ResponseError for ReadlinesError {
218    fn status_code(&self) -> StatusCode {
219        match *self {
220            ReadlinesError::LimitOverflow => StatusCode::PAYLOAD_TOO_LARGE,
221            _ => StatusCode::BAD_REQUEST,
222        }
223    }
224}
225
226#[cfg(test)]
227mod tests {
228    use super::*;
229
230    #[test]
231    fn test_urlencoded_error() {
232        let resp = UrlencodedError::Overflow { size: 0, limit: 0 }.error_response();
233        assert_eq!(resp.status(), StatusCode::PAYLOAD_TOO_LARGE);
234        let resp = UrlencodedError::UnknownLength.error_response();
235        assert_eq!(resp.status(), StatusCode::LENGTH_REQUIRED);
236        let resp = UrlencodedError::ContentType.error_response();
237        assert_eq!(resp.status(), StatusCode::UNSUPPORTED_MEDIA_TYPE);
238    }
239
240    #[test]
241    fn test_json_payload_error() {
242        let resp = JsonPayloadError::OverflowKnownLength {
243            length: 0,
244            limit: 0,
245        }
246        .error_response();
247        assert_eq!(resp.status(), StatusCode::PAYLOAD_TOO_LARGE);
248        let resp = JsonPayloadError::Overflow { limit: 0 }.error_response();
249        assert_eq!(resp.status(), StatusCode::PAYLOAD_TOO_LARGE);
250        let resp = JsonPayloadError::ContentType.error_response();
251        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
252    }
253
254    #[test]
255    fn test_query_payload_error() {
256        let resp = QueryPayloadError::Deserialize(
257            serde_urlencoded::from_str::<i32>("bad query").unwrap_err(),
258        )
259        .error_response();
260        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
261    }
262
263    #[test]
264    fn test_readlines_error() {
265        let resp = ReadlinesError::LimitOverflow.error_response();
266        assert_eq!(resp.status(), StatusCode::PAYLOAD_TOO_LARGE);
267        let resp = ReadlinesError::EncodingError.error_response();
268        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
269    }
270}