ntex/web/
error_default.rs1use std::{fmt, io, io::Write, str::Utf8Error};
3
4use serde::de::value::Error as DeError;
5use serde_json::error::Error as JsonError;
6use serde_urlencoded::ser::Error as FormError;
7
8use crate::client;
9use crate::http::{self, StatusCode, body::Body, header};
10use crate::util::{BytesMut, timeout::TimeoutError};
11#[cfg(feature = "ws")]
12use crate::ws::error::HandshakeError;
13
14use super::error::{self, ErrorContainer, ErrorRenderer, WebResponseError};
15use super::{HttpRequest, HttpResponse};
16
17#[derive(Clone, Copy, Default, Debug)]
19pub struct DefaultError;
20
21impl ErrorRenderer for DefaultError {
22 type Container = Error;
23}
24
25#[derive(thiserror::Error)]
27pub struct Error {
28 cause: Box<dyn WebResponseError<DefaultError>>,
29}
30
31impl Error {
32 pub fn new<T: WebResponseError<DefaultError> + 'static>(err: T) -> Error {
33 Error {
34 cause: Box::new(err),
35 }
36 }
37
38 pub fn as_response_error(&self) -> &dyn WebResponseError<DefaultError> {
40 self.cause.as_ref()
41 }
42}
43
44impl<T: WebResponseError<DefaultError>> From<T> for Error {
46 fn from(err: T) -> Self {
47 Error {
48 cause: Box::new(err),
49 }
50 }
51}
52
53impl ErrorContainer for Error {
54 fn error_response(&self, req: &HttpRequest) -> HttpResponse {
55 self.cause.error_response(req)
56 }
57}
58
59impl crate::http::error::ResponseError for Error {
60 fn error_response(&self) -> HttpResponse {
61 let mut resp = HttpResponse::new(self.cause.status_code());
62 let mut buf = BytesMut::new();
63 let _ = write!(&mut buf, "{}", self.cause);
64 resp.headers_mut().insert(
65 header::CONTENT_TYPE,
66 header::HeaderValue::from_static("text/plain; charset=utf-8"),
67 );
68 resp.set_body(Body::from(buf))
69 }
70}
71
72impl fmt::Display for Error {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 fmt::Display::fmt(&self.cause, f)
75 }
76}
77
78impl fmt::Debug for Error {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 write!(f, "web::Error({:?})", self.cause)
81 }
82}
83
84impl<E> From<TimeoutError<E>> for Error
86where
87 Error: From<E>,
88{
89 fn from(err: TimeoutError<E>) -> Error {
90 match err {
91 TimeoutError::Service(e) => e.into(),
92 TimeoutError::Timeout => super::error::ErrorGatewayTimeout("").into(),
93 }
94 }
95}
96
97impl WebResponseError<DefaultError> for error::StateExtractorError {}
99
100impl WebResponseError<DefaultError> for JsonError {}
102
103impl WebResponseError<DefaultError> for FormError {}
105
106#[cfg(feature = "openssl")]
107impl WebResponseError<DefaultError> for tls_openssl::ssl::Error {}
109
110#[cfg(feature = "openssl")]
111impl<T: fmt::Debug + 'static> WebResponseError<DefaultError>
113 for tls_openssl::ssl::HandshakeError<T>
114{
115}
116
117impl WebResponseError<DefaultError> for DeError {
119 fn status_code(&self) -> StatusCode {
120 StatusCode::BAD_REQUEST
121 }
122}
123
124impl WebResponseError<DefaultError> for crate::http::error::Canceled {}
126
127impl<E: fmt::Debug + 'static> WebResponseError<DefaultError>
129 for crate::http::error::BlockingError<E>
130{
131}
132
133impl WebResponseError<DefaultError> for Utf8Error {
135 fn status_code(&self) -> StatusCode {
136 StatusCode::BAD_REQUEST
137 }
138}
139
140impl WebResponseError<DefaultError> for crate::http::error::HttpError {}
143
144impl WebResponseError<DefaultError> for io::Error {
146 fn status_code(&self) -> StatusCode {
147 match self.kind() {
148 io::ErrorKind::NotFound => StatusCode::NOT_FOUND,
149 io::ErrorKind::PermissionDenied => StatusCode::FORBIDDEN,
150 _ => StatusCode::INTERNAL_SERVER_ERROR,
151 }
152 }
153}
154
155impl WebResponseError<DefaultError> for error::UrlGenerationError {}
157
158impl WebResponseError<DefaultError> for error::UrlencodedError {
160 fn status_code(&self) -> StatusCode {
161 match *self {
162 error::UrlencodedError::Overflow { .. } => StatusCode::PAYLOAD_TOO_LARGE,
163 error::UrlencodedError::UnknownLength => StatusCode::LENGTH_REQUIRED,
164 _ => StatusCode::BAD_REQUEST,
165 }
166 }
167}
168
169impl WebResponseError<DefaultError> for error::JsonPayloadError {
171 fn status_code(&self) -> StatusCode {
172 match *self {
173 error::JsonPayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE,
174 _ => StatusCode::BAD_REQUEST,
175 }
176 }
177}
178
179impl WebResponseError<DefaultError> for error::PathError {
181 fn status_code(&self) -> StatusCode {
182 StatusCode::NOT_FOUND
183 }
184}
185
186impl WebResponseError<DefaultError> for error::QueryPayloadError {
188 fn status_code(&self) -> StatusCode {
189 StatusCode::BAD_REQUEST
190 }
191}
192
193impl WebResponseError<DefaultError> for error::PayloadError {
194 fn status_code(&self) -> StatusCode {
195 StatusCode::BAD_REQUEST
196 }
197}
198
199impl WebResponseError<DefaultError> for http::error::PayloadError {
204 fn status_code(&self) -> StatusCode {
205 match *self {
206 http::error::PayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE,
207 _ => StatusCode::BAD_REQUEST,
208 }
209 }
210}
211
212#[cfg(feature = "cookie")]
213impl WebResponseError<DefaultError> for coo_kie::ParseError {
215 fn status_code(&self) -> StatusCode {
216 StatusCode::BAD_REQUEST
217 }
218}
219
220impl WebResponseError<DefaultError> for http::error::ContentTypeError {
222 fn status_code(&self) -> StatusCode {
223 StatusCode::BAD_REQUEST
224 }
225}
226
227impl WebResponseError<DefaultError> for client::error::ClientError {
229 fn status_code(&self) -> StatusCode {
230 match self {
231 client::error::ClientError::Connect(err) => {
232 if matches!(err, client::error::ConnectError::Timeout) {
233 StatusCode::GATEWAY_TIMEOUT
234 } else {
235 StatusCode::BAD_REQUEST
236 }
237 }
238 _ => StatusCode::INTERNAL_SERVER_ERROR,
239 }
240 }
241}
242
243#[cfg(feature = "ws")]
244impl WebResponseError<DefaultError> for HandshakeError {
246 fn error_response(&self, _: &HttpRequest) -> HttpResponse {
247 match *self {
248 HandshakeError::GetMethodRequired => HttpResponse::MethodNotAllowed()
249 .header(header::ALLOW, "GET")
250 .finish(),
251 HandshakeError::NoWebsocketUpgrade => HttpResponse::BadRequest()
252 .reason("No WebSocket UPGRADE header found")
253 .finish(),
254 HandshakeError::NoConnectionUpgrade => HttpResponse::BadRequest()
255 .reason("No CONNECTION upgrade")
256 .finish(),
257 HandshakeError::NoVersionHeader => HttpResponse::BadRequest()
258 .reason("Websocket version header is required")
259 .finish(),
260 HandshakeError::UnsupportedVersion => HttpResponse::BadRequest()
261 .reason("Unsupported version")
262 .finish(),
263 HandshakeError::BadWebsocketKey => HttpResponse::BadRequest()
264 .reason("Handshake error")
265 .finish(),
266 }
267 }
268}