1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//! Errors that can occur while extracting information from the request body.
use crate::response::Response;
use ubyte::ByteUnit;

#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
/// The error returned by [`JsonBody::extract`] when the extraction fails.
///
/// [`JsonBody::extract`]: crate::request::body::json::JsonBody::extract
pub enum ExtractJsonBodyError {
    #[error(transparent)]
    /// See [`MissingJsonContentType`] for details.
    MissingContentType(#[from] MissingJsonContentType),
    #[error(transparent)]
    /// See [`JsonContentTypeMismatch`] for details.
    ContentTypeMismatch(#[from] JsonContentTypeMismatch),
    #[error(transparent)]
    /// See [`JsonDeserializationError`] for details.
    DeserializationError(#[from] JsonDeserializationError),
}

impl ExtractJsonBodyError {
    /// Convert an [`ExtractJsonBodyError`] into an HTTP response.
    pub fn into_response(&self) -> Response {
        match self {
            ExtractJsonBodyError::MissingContentType(_)
            | ExtractJsonBodyError::ContentTypeMismatch(_) => Response::unsupported_media_type(),
            ExtractJsonBodyError::DeserializationError(_) => Response::bad_request(),
        }
        .set_typed_body(format!("{}", self))
    }
}

#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
/// The error returned by [`BufferedBody::extract`] when the extraction fails.
///
/// [`BufferedBody::extract`]: crate::request::body::buffered_body::BufferedBody::extract
pub enum ExtractBufferedBodyError {
    #[error(transparent)]
    /// See [`SizeLimitExceeded`] for details.
    SizeLimitExceeded(#[from] SizeLimitExceeded),
    #[error(transparent)]
    /// See [`UnexpectedBufferError`] for details.
    UnexpectedBufferError(#[from] UnexpectedBufferError),
}

impl ExtractBufferedBodyError {
    /// Convert an [`ExtractBufferedBodyError`] into an HTTP response.
    pub fn into_response(&self) -> Response {
        match self {
            ExtractBufferedBodyError::SizeLimitExceeded(_) => Response::payload_too_large(),
            ExtractBufferedBodyError::UnexpectedBufferError(_) => Response::internal_server_error(),
        }
        .set_typed_body(format!("{}", self))
    }
}

#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
/// The error returned by [`UrlEncodedBody::extract`] when the extraction fails.
///
/// [`UrlEncodedBody::extract`]: crate::request::body::url_encoded::UrlEncodedBody::extract
pub enum ExtractUrlEncodedBodyError {
    #[error(transparent)]
    /// See [`MissingUrlEncodedContentType`] for details.
    MissingContentType(#[from] MissingUrlEncodedContentType),
    #[error(transparent)]
    /// See [`UrlEncodedContentTypeMismatch`] for details.
    ContentTypeMismatch(#[from] UrlEncodedContentTypeMismatch),
    #[error(transparent)]
    /// See [`UrlEncodedBodyDeserializationError`] for details.
    DeserializationError(#[from] UrlEncodedBodyDeserializationError),
}

impl ExtractUrlEncodedBodyError {
    /// Convert an [`ExtractUrlEncodedBodyError`] into an HTTP response.
    pub fn into_response(&self) -> Response {
        match self {
            ExtractUrlEncodedBodyError::MissingContentType(_)
            | ExtractUrlEncodedBodyError::ContentTypeMismatch(_) => {
                Response::unsupported_media_type()
            }
            ExtractUrlEncodedBodyError::DeserializationError(_) => Response::bad_request(),
        }
        .set_typed_body(format!("{}", self))
    }
}

#[derive(Debug, thiserror::Error)]
#[error("The request body is larger than the maximum size limit enforced by this server.")]
#[non_exhaustive]
/// The request body is larger than the maximum size limit enforced by this server.
pub struct SizeLimitExceeded {
    /// The maximum size limit enforced by this server.
    pub max_size: ByteUnit,
    /// The value of the `Content-Length` header for the request that breached the body
    /// size limit.  
    ///
    /// It's set to `None` if the `Content-Length` header was missing or invalid.  
    /// If it's set to `Some(n)` and `n` is smaller than `max_n_bytes`, then the request
    /// lied about the size of its body in the `Content-Length` header.
    pub content_length: Option<usize>,
}

#[derive(Debug, thiserror::Error)]
#[error("Something went wrong while reading the request body.")]
#[non_exhaustive]
/// Something went wrong while reading the request body, but we don't know what specifically.
pub struct UnexpectedBufferError {
    #[source]
    pub(super) source: Box<dyn std::error::Error + Send + Sync>,
}

#[derive(Debug, thiserror::Error)]
#[error(
"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"
)]
#[non_exhaustive]
/// The `Content-Type` header is missing, while we expected it to be set to `application/json`, or
/// another `application/*+json` MIME type.
pub struct MissingJsonContentType;

#[derive(Debug, thiserror::Error)]
#[error("Failed to deserialize the body as a JSON document.\n{source}")]
#[non_exhaustive]
/// Something went wrong when deserializing the request body into the specified type.
pub struct JsonDeserializationError {
    #[source]
    pub(super) source: serde_path_to_error::Error<serde_json::Error>,
}

#[derive(Debug, thiserror::Error)]
#[error(
"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"
)]
#[non_exhaustive]
/// The `Content-Type` header not set to `application/json`, or another `application/*+json` MIME type.
pub struct JsonContentTypeMismatch {
    /// The actual value of the `Content-Type` header for this request.
    pub actual: String,
}

#[derive(Debug, thiserror::Error)]
#[error(
"The `Content-Type` header is missing. This endpoint expects requests with a `Content-Type` header set to `application/x-www-form-urlencoded`"
)]
#[non_exhaustive]
/// The `Content-Type` header is missing, while we expected it to be set to `application/x-www-form-urlencoded`.
pub struct MissingUrlEncodedContentType;

#[derive(Debug, thiserror::Error)]
#[error(
"The `Content-Type` header was set to `{actual}`. This endpoint expects requests with a `Content-Type` header set to `application/x-www-form-urlencoded`"
)]
#[non_exhaustive]
/// The `Content-Type` header not set to `application/x-www-form-urlencoded`.
pub struct UrlEncodedContentTypeMismatch {
    /// The actual value of the `Content-Type` header for this request.
    pub actual: String,
}

#[derive(Debug, thiserror::Error)]
#[error("Failed to deserialize the body as a urlencoded form.\n{source}")]
#[non_exhaustive]
/// Something went wrong when deserializing the request body into the specified type.
pub struct UrlEncodedBodyDeserializationError {
    #[source]
    pub(super) source: serde_html_form::de::Error,
}