pavex/request/body/
errors.rs

1//! Errors that can occur while extracting information from the request body.
2use crate::Response;
3use pavex_macros::methods;
4use ubyte::ByteUnit;
5
6#[derive(Debug, thiserror::Error)]
7#[non_exhaustive]
8/// The error returned by [`JsonBody::extract`] when the extraction fails.
9///
10/// [`JsonBody::extract`]: crate::request::body::json::JsonBody::extract
11pub enum ExtractJsonBodyError {
12    #[error(transparent)]
13    /// See [`MissingJsonContentType`] for details.
14    MissingContentType(#[from] MissingJsonContentType),
15    #[error(transparent)]
16    /// See [`JsonContentTypeMismatch`] for details.
17    ContentTypeMismatch(#[from] JsonContentTypeMismatch),
18    #[error(transparent)]
19    /// See [`JsonDeserializationError`] for details.
20    DeserializationError(#[from] JsonDeserializationError),
21}
22
23#[methods]
24impl ExtractJsonBodyError {
25    /// Convert an [`ExtractJsonBodyError`] into an HTTP response.
26    #[error_handler(pavex = crate)]
27    pub fn into_response(&self) -> Response {
28        match self {
29            ExtractJsonBodyError::MissingContentType(_)
30            | ExtractJsonBodyError::ContentTypeMismatch(_) => Response::unsupported_media_type(),
31            ExtractJsonBodyError::DeserializationError(_) => Response::bad_request(),
32        }
33        .set_typed_body(format!("{self}"))
34    }
35}
36
37#[derive(Debug, thiserror::Error)]
38#[non_exhaustive]
39/// The error returned by [`BufferedBody::extract`] when the extraction fails.
40///
41/// [`BufferedBody::extract`]: crate::request::body::buffered_body::BufferedBody::extract
42pub enum ExtractBufferedBodyError {
43    #[error(transparent)]
44    /// See [`SizeLimitExceeded`] for details.
45    SizeLimitExceeded(#[from] SizeLimitExceeded),
46    #[error(transparent)]
47    /// See [`UnexpectedBufferError`] for details.
48    UnexpectedBufferError(#[from] UnexpectedBufferError),
49}
50
51#[methods]
52impl ExtractBufferedBodyError {
53    /// Convert an [`ExtractBufferedBodyError`] into an HTTP response.
54    #[error_handler(pavex = crate)]
55    pub fn into_response(&self) -> Response {
56        match self {
57            ExtractBufferedBodyError::SizeLimitExceeded(_) => Response::payload_too_large(),
58            ExtractBufferedBodyError::UnexpectedBufferError(_) => Response::internal_server_error(),
59        }
60        .set_typed_body(format!("{self}"))
61    }
62}
63
64#[derive(Debug, thiserror::Error)]
65#[non_exhaustive]
66/// The error returned by [`UrlEncodedBody::extract`] when the extraction fails.
67///
68/// [`UrlEncodedBody::extract`]: crate::request::body::url_encoded::UrlEncodedBody::extract
69pub enum ExtractUrlEncodedBodyError {
70    #[error(transparent)]
71    /// See [`MissingUrlEncodedContentType`] for details.
72    MissingContentType(#[from] MissingUrlEncodedContentType),
73    #[error(transparent)]
74    /// See [`UrlEncodedContentTypeMismatch`] for details.
75    ContentTypeMismatch(#[from] UrlEncodedContentTypeMismatch),
76    #[error(transparent)]
77    /// See [`UrlEncodedBodyDeserializationError`] for details.
78    DeserializationError(#[from] UrlEncodedBodyDeserializationError),
79}
80
81#[methods]
82impl ExtractUrlEncodedBodyError {
83    /// Convert an [`ExtractUrlEncodedBodyError`] into an HTTP response.
84    #[error_handler(pavex = crate)]
85    pub fn into_response(&self) -> Response {
86        match self {
87            ExtractUrlEncodedBodyError::MissingContentType(_)
88            | ExtractUrlEncodedBodyError::ContentTypeMismatch(_) => {
89                Response::unsupported_media_type()
90            }
91            ExtractUrlEncodedBodyError::DeserializationError(_) => Response::bad_request(),
92        }
93        .set_typed_body(format!("{self}"))
94    }
95}
96
97#[derive(Debug, thiserror::Error)]
98#[error("The request body is larger than the maximum size limit enforced by this server.")]
99#[non_exhaustive]
100/// The request body is larger than the maximum size limit enforced by this server.
101pub struct SizeLimitExceeded {
102    /// The maximum size limit enforced by this server.
103    pub max_size: ByteUnit,
104    /// The value of the `Content-Length` header for the request that breached the body
105    /// size limit.
106    ///
107    /// It's set to `None` if the `Content-Length` header was missing or invalid.
108    /// If it's set to `Some(n)` and `n` is smaller than `max_n_bytes`, then the request
109    /// lied about the size of its body in the `Content-Length` header.
110    pub content_length: Option<usize>,
111}
112
113#[derive(Debug, thiserror::Error)]
114#[error("Something went wrong while reading the request body.")]
115#[non_exhaustive]
116/// Something went wrong while reading the request body, but we don't know what specifically.
117pub struct UnexpectedBufferError {
118    #[source]
119    pub(super) source: Box<dyn std::error::Error + Send + Sync>,
120}
121
122#[derive(Debug, thiserror::Error)]
123#[error(
124    "The `Content-Type` header is missing. This endpoint expects requests with a `Content-Type` header set to `application/json`, or another `application/*+json` MIME type"
125)]
126#[non_exhaustive]
127/// The `Content-Type` header is missing, while we expected it to be set to `application/json`, or
128/// another `application/*+json` MIME type.
129pub struct MissingJsonContentType;
130
131#[derive(Debug, thiserror::Error)]
132#[error("Failed to deserialize the body as a JSON document.\n{source}")]
133#[non_exhaustive]
134/// Something went wrong when deserializing the request body into the specified type.
135pub struct JsonDeserializationError {
136    #[source]
137    pub(super) source: serde_path_to_error::Error<serde_json::Error>,
138}
139
140#[derive(Debug, thiserror::Error)]
141#[error(
142    "The `Content-Type` header was set to `{actual}`. This endpoint expects requests with a `Content-Type` header set to `application/json`, or another `application/*+json` MIME type"
143)]
144#[non_exhaustive]
145/// The `Content-Type` header not set to `application/json`, or another `application/*+json` MIME type.
146pub struct JsonContentTypeMismatch {
147    /// The actual value of the `Content-Type` header for this request.
148    pub actual: String,
149}
150
151#[derive(Debug, thiserror::Error)]
152#[error(
153    "The `Content-Type` header is missing. This endpoint expects requests with a `Content-Type` header set to `application/x-www-form-urlencoded`"
154)]
155#[non_exhaustive]
156/// The `Content-Type` header is missing, while we expected it to be set to `application/x-www-form-urlencoded`.
157pub struct MissingUrlEncodedContentType;
158
159#[derive(Debug, thiserror::Error)]
160#[error(
161    "The `Content-Type` header was set to `{actual}`. This endpoint expects requests with a `Content-Type` header set to `application/x-www-form-urlencoded`"
162)]
163#[non_exhaustive]
164/// The `Content-Type` header not set to `application/x-www-form-urlencoded`.
165pub struct UrlEncodedContentTypeMismatch {
166    /// The actual value of the `Content-Type` header for this request.
167    pub actual: String,
168}
169
170#[derive(Debug, thiserror::Error)]
171#[error("Failed to deserialize the body as a urlencoded form.\n{source}")]
172#[non_exhaustive]
173/// Something went wrong when deserializing the request body into the specified type.
174pub struct UrlEncodedBodyDeserializationError {
175    #[source]
176    pub(super) source: serde_html_form::de::Error,
177}