Skip to main content

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 larger than allowed; full size is unknown. (default limit: 256kB).
75    #[display("URL encoded payload is larger than allowed (limit: {} bytes)", limit)]
76    OverflowUnknownLength { limit: usize },
77
78    /// Payload size is now known.
79    #[display("Payload size is now known.")]
80    UnknownLength,
81
82    /// Content type error.
83    #[display("Content type error.")]
84    ContentType,
85
86    /// Parse error.
87    #[display("Parse error: {}.", _0)]
88    Parse(FormDeError),
89
90    /// Encoding error.
91    #[display("Encoding error.")]
92    Encoding,
93
94    /// Serialize error.
95    #[display("Serialize error: {}.", _0)]
96    Serialize(FormError),
97
98    /// Payload error.
99    #[display("Error that occur during reading payload: {}.", _0)]
100    Payload(PayloadError),
101}
102
103impl ResponseError for UrlencodedError {
104    fn status_code(&self) -> StatusCode {
105        match self {
106            Self::Overflow { .. } | Self::OverflowUnknownLength { .. } => {
107                StatusCode::PAYLOAD_TOO_LARGE
108            }
109            Self::UnknownLength => StatusCode::LENGTH_REQUIRED,
110            Self::ContentType => StatusCode::UNSUPPORTED_MEDIA_TYPE,
111            Self::Payload(err) => err.status_code(),
112            _ => StatusCode::BAD_REQUEST,
113        }
114    }
115}
116
117/// A set of errors that can occur during parsing json payloads
118#[derive(Debug, Display, Error)]
119#[non_exhaustive]
120pub enum JsonPayloadError {
121    /// Payload size is bigger than allowed & content length header set. (default: 2MB)
122    #[display(
123        "JSON payload ({} bytes) is larger than allowed (limit: {} bytes).",
124        length,
125        limit
126    )]
127    OverflowKnownLength { length: usize, limit: usize },
128
129    /// Payload size is bigger than allowed but no content length header set. (default: 2MB)
130    #[display("JSON payload has exceeded limit ({} bytes).", limit)]
131    Overflow { limit: usize },
132
133    /// Content type error
134    #[display("Content type error")]
135    ContentType,
136
137    /// Deserialize error
138    #[display("Json deserialize error: {}", _0)]
139    Deserialize(JsonError),
140
141    /// Serialize error
142    #[display("Json serialize error: {}", _0)]
143    Serialize(JsonError),
144
145    /// Payload error
146    #[display("Error that occur during reading payload: {}", _0)]
147    Payload(PayloadError),
148}
149
150impl From<PayloadError> for JsonPayloadError {
151    fn from(err: PayloadError) -> Self {
152        Self::Payload(err)
153    }
154}
155
156impl ResponseError for JsonPayloadError {
157    fn status_code(&self) -> StatusCode {
158        match self {
159            Self::OverflowKnownLength {
160                length: _,
161                limit: _,
162            } => StatusCode::PAYLOAD_TOO_LARGE,
163            Self::Overflow { limit: _ } => StatusCode::PAYLOAD_TOO_LARGE,
164            Self::Serialize(_) => StatusCode::INTERNAL_SERVER_ERROR,
165            Self::Payload(err) => err.status_code(),
166            _ => StatusCode::BAD_REQUEST,
167        }
168    }
169}
170
171/// A set of errors that can occur during parsing request paths
172#[derive(Debug, Display, Error)]
173#[non_exhaustive]
174pub enum PathError {
175    /// Deserialize error
176    #[display("Path deserialize error: {}", _0)]
177    Deserialize(serde::de::value::Error),
178}
179
180/// Return `BadRequest` for `PathError`
181impl ResponseError for PathError {
182    fn status_code(&self) -> StatusCode {
183        StatusCode::BAD_REQUEST
184    }
185}
186
187/// A set of errors that can occur during parsing query strings.
188#[derive(Debug, Display, Error, From)]
189#[non_exhaustive]
190pub enum QueryPayloadError {
191    /// Query deserialize error.
192    #[display("Query deserialize error: {}", _0)]
193    Deserialize(serde::de::value::Error),
194}
195
196impl ResponseError for QueryPayloadError {
197    fn status_code(&self) -> StatusCode {
198        StatusCode::BAD_REQUEST
199    }
200}
201
202/// Error type returned when reading body as lines.
203#[derive(Debug, Display, Error, From)]
204#[non_exhaustive]
205pub enum ReadlinesError {
206    #[display("Encoding error")]
207    /// Payload size is bigger than allowed. (default: 256kB)
208    EncodingError,
209
210    /// Payload error.
211    #[display("Error that occur during reading payload: {}", _0)]
212    Payload(PayloadError),
213
214    /// Line limit exceeded.
215    #[display("Line limit exceeded")]
216    LimitOverflow,
217
218    /// ContentType error.
219    #[display("Content-type error")]
220    ContentTypeError(ContentTypeError),
221}
222
223impl ResponseError for ReadlinesError {
224    fn status_code(&self) -> StatusCode {
225        match *self {
226            ReadlinesError::LimitOverflow => StatusCode::PAYLOAD_TOO_LARGE,
227            _ => StatusCode::BAD_REQUEST,
228        }
229    }
230}
231
232#[cfg(test)]
233mod tests {
234    use super::*;
235
236    #[test]
237    fn test_urlencoded_error() {
238        let resp = UrlencodedError::Overflow { size: 0, limit: 0 }.error_response();
239        assert_eq!(resp.status(), StatusCode::PAYLOAD_TOO_LARGE);
240        let resp = UrlencodedError::UnknownLength.error_response();
241        assert_eq!(resp.status(), StatusCode::LENGTH_REQUIRED);
242        let resp = UrlencodedError::ContentType.error_response();
243        assert_eq!(resp.status(), StatusCode::UNSUPPORTED_MEDIA_TYPE);
244    }
245
246    #[test]
247    fn test_json_payload_error() {
248        let resp = JsonPayloadError::OverflowKnownLength {
249            length: 0,
250            limit: 0,
251        }
252        .error_response();
253        assert_eq!(resp.status(), StatusCode::PAYLOAD_TOO_LARGE);
254        let resp = JsonPayloadError::Overflow { limit: 0 }.error_response();
255        assert_eq!(resp.status(), StatusCode::PAYLOAD_TOO_LARGE);
256        let resp = JsonPayloadError::ContentType.error_response();
257        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
258    }
259
260    #[test]
261    fn test_query_payload_error() {
262        let resp = QueryPayloadError::Deserialize(
263            serde_urlencoded::from_str::<i32>("bad query").unwrap_err(),
264        )
265        .error_response();
266        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
267    }
268
269    #[test]
270    fn test_readlines_error() {
271        let resp = ReadlinesError::LimitOverflow.error_response();
272        assert_eq!(resp.status(), StatusCode::PAYLOAD_TOO_LARGE);
273        let resp = ReadlinesError::EncodingError.error_response();
274        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
275    }
276}