Skip to main content

ntex/web/
error.rs

1//! Web error
2use std::{cell::RefCell, error::Error, fmt, io::Write};
3
4pub use ntex_http::error::Error as HttpError;
5pub use serde_json::error::Error as JsonError;
6pub use urly::InvalidUrl as UrlParseError;
7
8use crate::http::body::Body;
9use crate::http::{StatusCode, error, header};
10use crate::util::{BytesMut, Either};
11
12pub use crate::http::error::BlockingError;
13pub use crate::web::error_default::DefaultError;
14
15use super::HttpResponse;
16
17/// Error that can be rendered to a `Response`
18pub trait WebResponseError<St, Err>: Error + 'static {
19    /// Generate response for error
20    ///
21    /// Internal server error is generated by default.
22    fn error_response(&self, _: &St) -> HttpResponse {
23        HttpResponse::render_with(StatusCode::INTERNAL_SERVER_ERROR, &self)
24    }
25
26    /// Convert the error into a boxed trait object.
27    ///
28    /// Used when the error is stored in a [`WebError`]. `WebError` overrides
29    /// this method to return its inner error without boxing it again.
30    fn into(self) -> Box<dyn WebResponseError<St, Err>>
31    where
32        Self: Sized,
33    {
34        Box::new(self)
35    }
36}
37
38// ========================== WebErrorImpl ====================
39
40/// Type-erased web error for the `Err` error domain.
41///
42/// Web services, middleware, and filters use `WebError` as their error type.
43/// It stores any error that implements [`WebResponseError`] for the same
44/// application state and error domain, and renders it with that
45/// implementation.
46pub struct WebError<St = (), Err = DefaultError>(pub(crate) Box<dyn WebResponseError<St, Err>>);
47
48impl<St: 'static, Err: 'static> WebError<St, Err> {
49    /// Create `WebError` from an error that can be rendered for this domain.
50    pub fn from_err<E: WebResponseError<St, Err>>(err: E) -> Self {
51        Self(err.into())
52    }
53}
54
55impl<St: 'static, Err: 'static> WebResponseError<St, Err> for WebError<St, Err> {
56    fn error_response(&self, st: &St) -> HttpResponse {
57        self.0.error_response(st)
58    }
59
60    fn into(self) -> Box<dyn WebResponseError<St, Err>> {
61        self.0
62    }
63}
64
65impl<St, Err> Error for WebError<St, Err> {
66    fn source(&self) -> Option<&(dyn Error + 'static)> {
67        self.0.source()
68    }
69}
70
71impl<St, Err> crate::http::error::ResponseError for WebError<St, Err> {
72    fn error_response(&self) -> HttpResponse {
73        HttpResponse::new(StatusCode::INTERNAL_SERVER_ERROR)
74    }
75}
76
77impl<St, Err> fmt::Display for WebError<St, Err> {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        write!(f, "{}", self.0)
80    }
81}
82
83impl<St, Err> fmt::Debug for WebError<St, Err> {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        write!(f, "web::WebError({})", self.0)
86    }
87}
88
89// ========================== Error<E> ========================
90
91impl<E, St, Err> WebResponseError<St, Err> for crate::error::Error<E>
92where
93    E: WebResponseError<St, Err> + Clone,
94{
95    fn error_response(&self, st: &St) -> HttpResponse {
96        (**self).error_response(st)
97    }
98}
99
100// ==========================
101
102impl<St, Err> WebResponseError<St, Err> for std::convert::Infallible {}
103
104impl<St, Err, A, B> WebResponseError<St, Err> for Either<A, B>
105where
106    A: WebResponseError<St, Err>,
107    B: WebResponseError<St, Err>,
108{
109    fn error_response(&self, st: &St) -> HttpResponse {
110        match self {
111            Either::Left(a) => a.error_response(st),
112            Either::Right(b) => b.error_response(st),
113        }
114    }
115}
116
117/// Errors which can occur when attempting to generate resource uri.
118#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
119pub enum UrlGenerationError {
120    /// Resource not found
121    #[error("Resource not found")]
122    ResourceNotFound,
123    /// Not all path pattern covered
124    #[error("Not all path pattern covered")]
125    NotEnoughElements,
126    /// URL parse error
127    #[error("{0}")]
128    ParseError(
129        #[from]
130        #[source]
131        UrlParseError,
132    ),
133}
134
135/// A set of errors that can occur during parsing urlencoded payloads
136#[derive(Debug, thiserror::Error)]
137pub enum UrlencodedError {
138    /// Cannot decode chunked transfer encoding
139    #[error("Cannot decode chunked transfer encoding")]
140    Chunked,
141    /// Payload size is bigger than allowed. (default: 16kB)
142    #[error(
143        "Urlencoded payload size is bigger ({size} bytes) than allowed (default: {limit} bytes)"
144    )]
145    Overflow {
146        /// Size of the payload, in bytes.
147        size: usize,
148        /// Configured payload size limit, in bytes.
149        limit: usize,
150    },
151    /// Payload size is unknown
152    #[error("Payload size is unknown")]
153    UnknownLength,
154    /// Content type error
155    #[error("Content type error")]
156    ContentType,
157    /// Parse error
158    #[error("Parse error")]
159    Parse,
160    /// Payload error
161    #[error("Error that occur during reading payload: {0}")]
162    Payload(
163        #[from]
164        #[source]
165        error::PayloadError,
166    ),
167}
168
169/// A set of errors that can occur during parsing json payloads
170#[derive(Debug, thiserror::Error)]
171pub enum JsonPayloadError {
172    /// Payload size is bigger than allowed. (default: 32kB)
173    #[error("Json payload size is bigger than allowed")]
174    Overflow,
175    /// Content type error
176    #[error("Content type error")]
177    ContentType,
178    /// Deserialize error
179    #[error("Json deserialize error: {0}")]
180    Deserialize(
181        #[from]
182        #[source]
183        serde_json::error::Error,
184    ),
185    /// Payload error
186    #[error("Error that occur during reading payload: {0}")]
187    Payload(
188        #[from]
189        #[source]
190        error::PayloadError,
191    ),
192}
193
194/// A set of errors that can occur during parsing request paths
195#[derive(Debug, thiserror::Error)]
196pub enum PathError {
197    /// Deserialize error
198    #[error("Path deserialize error: {0}")]
199    Deserialize(
200        #[from]
201        #[source]
202        serde::de::value::Error,
203    ),
204}
205
206/// A set of errors that can occur during parsing query strings
207#[derive(Debug, thiserror::Error)]
208pub enum QueryPayloadError {
209    /// Deserialize error
210    #[error("Query deserialize error: {0}")]
211    Deserialize(
212        #[from]
213        #[source]
214        serde::de::value::Error,
215    ),
216}
217
218/// Errors that can occur while reading a request payload.
219///
220/// Returned by the `Bytes` and `String` extractors and by the `Payload` stream.
221#[derive(Debug, thiserror::Error)]
222pub enum PayloadError {
223    /// Http error.
224    #[error("{0:?}")]
225    Http(
226        #[from]
227        #[source]
228        error::HttpError,
229    ),
230    /// Error while reading the payload stream.
231    #[error("{0}")]
232    Payload(
233        #[from]
234        #[source]
235        error::PayloadError,
236    ),
237    /// Invalid content type or charset.
238    #[error("{0}")]
239    ContentType(
240        #[from]
241        #[source]
242        error::ContentTypeError,
243    ),
244    /// The body cannot be decoded with the request's charset.
245    #[error("Cannot decode body")]
246    Decoding,
247}
248
249/// Helper type that can wrap any error and generate custom response.
250///
251/// `InternalError` renders the wrapped error with a fixed status code, or with a
252/// prepared response, and implements [`WebResponseError`] for every error
253/// domain. The `Error*` helpers in this module, such as [`ErrorBadRequest`],
254/// create `InternalError` values.
255///
256/// In the following example an `io::Error` is rendered as `400 Bad Request`
257/// instead of the default `500 Internal Server Error`.
258///
259/// ```rust
260/// use ntex::http::StatusCode;
261/// use ntex::web::{self, InternalError};
262///
263/// async fn index() -> Result<&'static str, InternalError<std::io::Error>> {
264///     let err = std::io::Error::other("error");
265///     Err(InternalError::new(err, StatusCode::BAD_REQUEST))
266/// }
267///
268/// let app = web::App::default().route("/", web::get().to(index));
269/// ```
270pub struct InternalError<T> {
271    cause: T,
272    status: InternalErrorType,
273}
274
275enum InternalErrorType {
276    Status(StatusCode),
277    Response(RefCell<Option<HttpResponse>>),
278}
279
280impl<T> InternalError<T> {
281    /// Create `InternalError` instance
282    pub fn default(cause: T, status: StatusCode) -> Self {
283        InternalError {
284            cause,
285            status: InternalErrorType::Status(status),
286        }
287    }
288}
289
290impl<T> InternalError<T> {
291    /// Create `InternalError` instance
292    pub fn new(cause: T, status: StatusCode) -> Self {
293        InternalError {
294            cause,
295            status: InternalErrorType::Status(status),
296        }
297    }
298
299    /// Create `InternalError` with predefined `Response`.
300    pub fn from_response(cause: T, response: HttpResponse) -> Self {
301        InternalError {
302            cause,
303            status: InternalErrorType::Response(RefCell::new(Some(response))),
304        }
305    }
306}
307
308impl<T> fmt::Debug for InternalError<T>
309where
310    T: fmt::Debug + 'static,
311{
312    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313        write!(f, "web::InternalError({:?})", self.cause)
314    }
315}
316
317impl<T> fmt::Display for InternalError<T>
318where
319    T: fmt::Display + 'static,
320{
321    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322        fmt::Display::fmt(&self.cause, f)
323    }
324}
325
326impl<T: fmt::Display + fmt::Debug + 'static> std::error::Error for InternalError<T> {}
327
328impl<St, Err, T> WebResponseError<St, Err> for InternalError<T>
329where
330    T: fmt::Debug + fmt::Display + 'static,
331{
332    fn error_response(&self, _: &St) -> HttpResponse {
333        crate::http::error::ResponseError::error_response(self)
334    }
335}
336
337impl<T> crate::http::error::ResponseError for InternalError<T>
338where
339    T: fmt::Debug + fmt::Display + 'static,
340{
341    fn error_response(&self) -> HttpResponse {
342        match self.status {
343            InternalErrorType::Status(st) => {
344                let mut res = HttpResponse::new(st);
345                let mut buf = BytesMut::new();
346                let _ = write!(&mut buf, "{self}");
347                res.headers_mut().insert(
348                    header::CONTENT_TYPE,
349                    header::HeaderValue::from_static("text/plain; charset=utf-8"),
350                );
351                res.set_body(Body::from(buf))
352            }
353            InternalErrorType::Response(ref resp) => {
354                if let Some(resp) = resp.borrow_mut().take() {
355                    resp
356                } else {
357                    HttpResponse::new(StatusCode::INTERNAL_SERVER_ERROR)
358                }
359            }
360        }
361    }
362}
363
364/// Helper function that creates wrapper of any error and generate *BAD
365/// REQUEST* response.
366#[allow(non_snake_case)]
367pub fn ErrorBadRequest<T>(err: T) -> InternalError<T>
368where
369    T: fmt::Debug + fmt::Display + 'static,
370{
371    InternalError::new(err, StatusCode::BAD_REQUEST)
372}
373
374/// Helper function that creates wrapper of any error and generate
375/// *UNAUTHORIZED* response.
376#[allow(non_snake_case)]
377pub fn ErrorUnauthorized<T>(err: T) -> InternalError<T>
378where
379    T: fmt::Debug + fmt::Display + 'static,
380{
381    InternalError::new(err, StatusCode::UNAUTHORIZED)
382}
383
384/// Helper function that creates wrapper of any error and generate
385/// *`PAYMENT_REQUIRED`* response.
386#[allow(non_snake_case)]
387pub fn ErrorPaymentRequired<T>(err: T) -> InternalError<T>
388where
389    T: fmt::Debug + fmt::Display + 'static,
390{
391    InternalError::new(err, StatusCode::PAYMENT_REQUIRED)
392}
393
394/// Helper function that creates wrapper of any error and generate *FORBIDDEN*
395/// response.
396#[allow(non_snake_case)]
397pub fn ErrorForbidden<T>(err: T) -> InternalError<T>
398where
399    T: fmt::Debug + fmt::Display + 'static,
400{
401    InternalError::new(err, StatusCode::FORBIDDEN)
402}
403
404/// Helper function that creates wrapper of any error and generate *NOT FOUND*
405/// response.
406#[allow(non_snake_case)]
407pub fn ErrorNotFound<T>(err: T) -> InternalError<T>
408where
409    T: fmt::Debug + fmt::Display + 'static,
410{
411    InternalError::new(err, StatusCode::NOT_FOUND)
412}
413
414/// Helper function that creates wrapper of any error and generate *METHOD NOT
415/// ALLOWED* response.
416#[allow(non_snake_case)]
417pub fn ErrorMethodNotAllowed<T>(err: T) -> InternalError<T>
418where
419    T: fmt::Debug + fmt::Display + 'static,
420{
421    InternalError::new(err, StatusCode::METHOD_NOT_ALLOWED)
422}
423
424/// Helper function that creates wrapper of any error and generate *NOT
425/// ACCEPTABLE* response.
426#[allow(non_snake_case)]
427pub fn ErrorNotAcceptable<T>(err: T) -> InternalError<T>
428where
429    T: fmt::Debug + fmt::Display + 'static,
430{
431    InternalError::new(err, StatusCode::NOT_ACCEPTABLE)
432}
433
434/// Helper function that creates wrapper of any error and generate *PROXY
435/// AUTHENTICATION REQUIRED* response.
436#[allow(non_snake_case)]
437pub fn ErrorProxyAuthenticationRequired<T>(err: T) -> InternalError<T>
438where
439    T: fmt::Debug + fmt::Display + 'static,
440{
441    InternalError::new(err, StatusCode::PROXY_AUTHENTICATION_REQUIRED)
442}
443
444/// Helper function that creates wrapper of any error and generate *REQUEST
445/// TIMEOUT* response.
446#[allow(non_snake_case)]
447pub fn ErrorRequestTimeout<T>(err: T) -> InternalError<T>
448where
449    T: fmt::Debug + fmt::Display + 'static,
450{
451    InternalError::new(err, StatusCode::REQUEST_TIMEOUT)
452}
453
454/// Helper function that creates wrapper of any error and generate *CONFLICT*
455/// response.
456#[allow(non_snake_case)]
457pub fn ErrorConflict<T>(err: T) -> InternalError<T>
458where
459    T: fmt::Debug + fmt::Display + 'static,
460{
461    InternalError::new(err, StatusCode::CONFLICT)
462}
463
464/// Helper function that creates wrapper of any error and generate *GONE*
465/// response.
466#[allow(non_snake_case)]
467pub fn ErrorGone<T>(err: T) -> InternalError<T>
468where
469    T: fmt::Debug + fmt::Display + 'static,
470{
471    InternalError::new(err, StatusCode::GONE)
472}
473
474/// Helper function that creates wrapper of any error and generate *LENGTH
475/// REQUIRED* response.
476#[allow(non_snake_case)]
477pub fn ErrorLengthRequired<T>(err: T) -> InternalError<T>
478where
479    T: fmt::Debug + fmt::Display + 'static,
480{
481    InternalError::new(err, StatusCode::LENGTH_REQUIRED)
482}
483
484/// Helper function that creates wrapper of any error and generate
485/// *PAYLOAD TOO LARGE* response.
486#[allow(non_snake_case)]
487pub fn ErrorPayloadTooLarge<T>(err: T) -> InternalError<T>
488where
489    T: fmt::Debug + fmt::Display + 'static,
490{
491    InternalError::new(err, StatusCode::PAYLOAD_TOO_LARGE)
492}
493
494/// Helper function that creates wrapper of any error and generate
495/// *URI TOO LONG* response.
496#[allow(non_snake_case)]
497pub fn ErrorUriTooLong<T>(err: T) -> InternalError<T>
498where
499    T: fmt::Debug + fmt::Display + 'static,
500{
501    InternalError::new(err, StatusCode::URI_TOO_LONG)
502}
503
504/// Helper function that creates wrapper of any error and generate
505/// *UNSUPPORTED MEDIA TYPE* response.
506#[allow(non_snake_case)]
507pub fn ErrorUnsupportedMediaType<T>(err: T) -> InternalError<T>
508where
509    T: fmt::Debug + fmt::Display + 'static,
510{
511    InternalError::new(err, StatusCode::UNSUPPORTED_MEDIA_TYPE)
512}
513
514/// Helper function that creates wrapper of any error and generate
515/// *RANGE NOT SATISFIABLE* response.
516#[allow(non_snake_case)]
517pub fn ErrorRangeNotSatisfiable<T>(err: T) -> InternalError<T>
518where
519    T: fmt::Debug + fmt::Display + 'static,
520{
521    InternalError::new(err, StatusCode::RANGE_NOT_SATISFIABLE)
522}
523
524/// Helper function that creates wrapper of any error and generate
525/// *IM A TEAPOT* response.
526#[allow(non_snake_case)]
527pub fn ErrorImATeapot<T>(err: T) -> InternalError<T>
528where
529    T: fmt::Debug + fmt::Display + 'static,
530{
531    InternalError::new(err, StatusCode::IM_A_TEAPOT)
532}
533
534/// Helper function that creates wrapper of any error and generate
535/// *MISDIRECTED REQUEST* response.
536#[allow(non_snake_case)]
537pub fn ErrorMisdirectedRequest<T>(err: T) -> InternalError<T>
538where
539    T: fmt::Debug + fmt::Display + 'static,
540{
541    InternalError::new(err, StatusCode::MISDIRECTED_REQUEST)
542}
543
544/// Helper function that creates wrapper of any error and generate
545/// *UNPROCESSABLE ENTITY* response.
546#[allow(non_snake_case)]
547pub fn ErrorUnprocessableEntity<T>(err: T) -> InternalError<T>
548where
549    T: fmt::Debug + fmt::Display + 'static,
550{
551    InternalError::new(err, StatusCode::UNPROCESSABLE_ENTITY)
552}
553
554/// Helper function that creates wrapper of any error and generate
555/// *LOCKED* response.
556#[allow(non_snake_case)]
557pub fn ErrorLocked<T>(err: T) -> InternalError<T>
558where
559    T: fmt::Debug + fmt::Display + 'static,
560{
561    InternalError::new(err, StatusCode::LOCKED)
562}
563
564/// Helper function that creates wrapper of any error and generate
565/// *FAILED DEPENDENCY* response.
566#[allow(non_snake_case)]
567pub fn ErrorFailedDependency<T>(err: T) -> InternalError<T>
568where
569    T: fmt::Debug + fmt::Display + 'static,
570{
571    InternalError::new(err, StatusCode::FAILED_DEPENDENCY)
572}
573
574/// Helper function that creates wrapper of any error and generate
575/// *UPGRADE REQUIRED* response.
576#[allow(non_snake_case)]
577pub fn ErrorUpgradeRequired<T>(err: T) -> InternalError<T>
578where
579    T: fmt::Debug + fmt::Display + 'static,
580{
581    InternalError::new(err, StatusCode::UPGRADE_REQUIRED)
582}
583
584/// Helper function that creates wrapper of any error and generate
585/// *PRECONDITION FAILED* response.
586#[allow(non_snake_case)]
587pub fn ErrorPreconditionFailed<T>(err: T) -> InternalError<T>
588where
589    T: fmt::Debug + fmt::Display + 'static,
590{
591    InternalError::new(err, StatusCode::PRECONDITION_FAILED)
592}
593
594/// Helper function that creates wrapper of any error and generate
595/// *PRECONDITION REQUIRED* response.
596#[allow(non_snake_case)]
597pub fn ErrorPreconditionRequired<T>(err: T) -> InternalError<T>
598where
599    T: fmt::Debug + fmt::Display + 'static,
600{
601    InternalError::new(err, StatusCode::PRECONDITION_REQUIRED)
602}
603
604/// Helper function that creates wrapper of any error and generate
605/// *TOO MANY REQUESTS* response.
606#[allow(non_snake_case)]
607pub fn ErrorTooManyRequests<T>(err: T) -> InternalError<T>
608where
609    T: fmt::Debug + fmt::Display + 'static,
610{
611    InternalError::new(err, StatusCode::TOO_MANY_REQUESTS)
612}
613
614/// Helper function that creates wrapper of any error and generate
615/// *REQUEST HEADER FIELDS TOO LARGE* response.
616#[allow(non_snake_case)]
617pub fn ErrorRequestHeaderFieldsTooLarge<T>(err: T) -> InternalError<T>
618where
619    T: fmt::Debug + fmt::Display + 'static,
620{
621    InternalError::new(err, StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE)
622}
623
624/// Helper function that creates wrapper of any error and generate
625/// *UNAVAILABLE FOR LEGAL REASONS* response.
626#[allow(non_snake_case)]
627pub fn ErrorUnavailableForLegalReasons<T>(err: T) -> InternalError<T>
628where
629    T: fmt::Debug + fmt::Display + 'static,
630{
631    InternalError::new(err, StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS)
632}
633
634/// Helper function that creates wrapper of any error and generate
635/// *EXPECTATION FAILED* response.
636#[allow(non_snake_case)]
637pub fn ErrorExpectationFailed<T>(err: T) -> InternalError<T>
638where
639    T: fmt::Debug + fmt::Display + 'static,
640{
641    InternalError::new(err, StatusCode::EXPECTATION_FAILED)
642}
643
644/// Helper function that creates wrapper of any error and
645/// generate *INTERNAL SERVER ERROR* response.
646#[allow(non_snake_case)]
647pub fn ErrorInternalServerError<T>(err: T) -> InternalError<T>
648where
649    T: fmt::Debug + fmt::Display + 'static,
650{
651    InternalError::new(err, StatusCode::INTERNAL_SERVER_ERROR)
652}
653
654/// Helper function that creates wrapper of any error and
655/// generate *NOT IMPLEMENTED* response.
656#[allow(non_snake_case)]
657pub fn ErrorNotImplemented<T>(err: T) -> InternalError<T>
658where
659    T: fmt::Debug + fmt::Display + 'static,
660{
661    InternalError::new(err, StatusCode::NOT_IMPLEMENTED)
662}
663
664/// Helper function that creates wrapper of any error and
665/// generate *BAD GATEWAY* response.
666#[allow(non_snake_case)]
667pub fn ErrorBadGateway<T>(err: T) -> InternalError<T>
668where
669    T: fmt::Debug + fmt::Display + 'static,
670{
671    InternalError::new(err, StatusCode::BAD_GATEWAY)
672}
673
674/// Helper function that creates wrapper of any error and
675/// generate *SERVICE UNAVAILABLE* response.
676#[allow(non_snake_case)]
677pub fn ErrorServiceUnavailable<T>(err: T) -> InternalError<T>
678where
679    T: fmt::Debug + fmt::Display + 'static,
680{
681    InternalError::new(err, StatusCode::SERVICE_UNAVAILABLE)
682}
683
684/// Helper function that creates wrapper of any error and
685/// generate *GATEWAY TIMEOUT* response.
686#[allow(non_snake_case)]
687pub fn ErrorGatewayTimeout<T>(err: T) -> InternalError<T>
688where
689    T: fmt::Debug + fmt::Display + 'static,
690{
691    InternalError::new(err, StatusCode::GATEWAY_TIMEOUT)
692}
693
694/// Helper function that creates wrapper of any error and
695/// generate *HTTP VERSION NOT SUPPORTED* response.
696#[allow(non_snake_case)]
697pub fn ErrorHttpVersionNotSupported<T>(err: T) -> InternalError<T>
698where
699    T: fmt::Debug + fmt::Display + 'static,
700{
701    InternalError::new(err, StatusCode::HTTP_VERSION_NOT_SUPPORTED)
702}
703
704/// Helper function that creates wrapper of any error and
705/// generate *VARIANT ALSO NEGOTIATES* response.
706#[allow(non_snake_case)]
707pub fn ErrorVariantAlsoNegotiates<T>(err: T) -> InternalError<T>
708where
709    T: fmt::Debug + fmt::Display + 'static,
710{
711    InternalError::new(err, StatusCode::VARIANT_ALSO_NEGOTIATES)
712}
713
714/// Helper function that creates wrapper of any error and
715/// generate *INSUFFICIENT STORAGE* response.
716#[allow(non_snake_case)]
717pub fn ErrorInsufficientStorage<T>(err: T) -> InternalError<T>
718where
719    T: fmt::Debug + fmt::Display + 'static,
720{
721    InternalError::new(err, StatusCode::INSUFFICIENT_STORAGE)
722}
723
724/// Helper function that creates wrapper of any error and
725/// generate *LOOP DETECTED* response.
726#[allow(non_snake_case)]
727pub fn ErrorLoopDetected<T>(err: T) -> InternalError<T>
728where
729    T: fmt::Debug + fmt::Display + 'static,
730{
731    InternalError::new(err, StatusCode::LOOP_DETECTED)
732}
733
734/// Helper function that creates wrapper of any error and
735/// generate *NOT EXTENDED* response.
736#[allow(non_snake_case)]
737pub fn ErrorNotExtended<T>(err: T) -> InternalError<T>
738where
739    T: fmt::Debug + fmt::Display + 'static,
740{
741    InternalError::new(err, StatusCode::NOT_EXTENDED)
742}
743
744/// Helper function that creates wrapper of any error and
745/// generate *NETWORK AUTHENTICATION REQUIRED* response.
746#[allow(non_snake_case)]
747pub fn ErrorNetworkAuthenticationRequired<T>(err: T) -> InternalError<T>
748where
749    T: fmt::Debug + fmt::Display + 'static,
750{
751    InternalError::new(err, StatusCode::NETWORK_AUTHENTICATION_REQUIRED)
752}
753
754#[cfg(test)]
755mod tests {
756    use std::io;
757
758    use super::*;
759    use crate::client::error::{ClientError, ConnectError};
760    use crate::{http, web::WebError};
761
762    #[test]
763    fn test_into_error() {
764        let e = WebError::<(), _>::from_err(UrlencodedError::UnknownLength);
765        let s = format!("{e}");
766        assert!(s.contains("Payload size is unknown"), "{}", s);
767        let s = format!("{e:?}");
768        assert!(s.contains("web::WebError"), "{}", s);
769
770        let res = crate::http::ResponseError::error_response(&e);
771        assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
772
773        let res = WebResponseError::<(), DefaultError>::error_response(
774            &UrlencodedError::UnknownLength,
775            &(),
776        );
777        assert_eq!(res.status(), StatusCode::LENGTH_REQUIRED);
778    }
779
780    #[test]
781    fn test_other_errors() {
782        use crate::util::timeout::TimeoutError;
783
784        let err = TimeoutError::<UrlencodedError>::Timeout;
785        assert_eq!(
786            WebResponseError::<(), DefaultError>::error_response(&err, &(),).status(),
787            StatusCode::GATEWAY_TIMEOUT
788        );
789
790        let err = TimeoutError::<UrlencodedError>::Service(UrlencodedError::Chunked);
791        assert_eq!(
792            WebResponseError::<(), DefaultError>::error_response(&err, &(),).status(),
793            StatusCode::BAD_REQUEST
794        );
795
796        let resp = WebResponseError::error_response(
797            &ClientError::Connect(ConnectError::SslIsNotSupported),
798            &(),
799        );
800        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
801
802        let resp = WebResponseError::error_response(&ClientError::Timeout, &());
803        assert_eq!(resp.status(), StatusCode::GATEWAY_TIMEOUT);
804
805        let resp = WebResponseError::error_response(&ClientError::Send(io::Error::other("x")), &());
806        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
807
808        #[cfg(feature = "cookie")]
809        {
810            let resp: HttpResponse =
811                WebResponseError::error_response(&coo_kie::ParseError::EmptyName, &());
812            assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
813        }
814
815        let resp = WebResponseError::error_response(
816            &crate::http::error::ContentTypeError::ParseError,
817            &(),
818        );
819        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
820
821        let err = serde_urlencoded::from_str::<i32>("bad query").unwrap_err();
822        let resp = WebResponseError::error_response(&err, &());
823        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
824
825        let err = PayloadError::Decoding;
826        let resp = WebResponseError::error_response(&err, &());
827        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
828
829        #[allow(invalid_from_utf8)]
830        let err = std::str::from_utf8(b"\xF0").unwrap_err();
831        let resp = WebResponseError::error_response(&err, &());
832        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
833
834        let err = http::error::PayloadError::EncodingCorrupted;
835        let resp = WebResponseError::error_response(&err, &());
836        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
837    }
838
839    #[test]
840    fn test_either_error() {
841        let err: Either<ClientError, PayloadError> = Either::Left(ClientError::Timeout);
842        let resp = WebResponseError::error_response(&err, &());
843        assert_eq!(resp.status(), StatusCode::GATEWAY_TIMEOUT);
844
845        let err: Either<ClientError, PayloadError> = Either::Right(PayloadError::Decoding);
846        let resp = WebResponseError::error_response(&err, &());
847        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
848    }
849
850    #[test]
851    fn test_io_error() {
852        assert_eq!(
853            StatusCode::NOT_FOUND,
854            WebResponseError::error_response(&io::Error::new(io::ErrorKind::NotFound, ""), &(),)
855                .status(),
856        );
857        assert_eq!(
858            StatusCode::FORBIDDEN,
859            WebResponseError::error_response(
860                &io::Error::new(io::ErrorKind::PermissionDenied, ""),
861                &(),
862            )
863            .status(),
864        );
865        assert_eq!(
866            StatusCode::INTERNAL_SERVER_ERROR,
867            WebResponseError::error_response(&io::Error::other(""), &(),).status(),
868        );
869    }
870
871    #[test]
872    fn test_urlencoded_error() {
873        let resp: HttpResponse =
874            WebResponseError::error_response(&UrlencodedError::Overflow { size: 0, limit: 0 }, &());
875        assert_eq!(resp.status(), StatusCode::PAYLOAD_TOO_LARGE);
876        let resp: HttpResponse =
877            WebResponseError::error_response(&UrlencodedError::UnknownLength, &());
878        assert_eq!(resp.status(), StatusCode::LENGTH_REQUIRED);
879        let resp: HttpResponse =
880            WebResponseError::error_response(&UrlencodedError::ContentType, &());
881        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
882    }
883
884    #[test]
885    fn test_json_payload_error() {
886        let resp: HttpResponse = WebResponseError::error_response(&JsonPayloadError::Overflow, &());
887        assert_eq!(resp.status(), StatusCode::PAYLOAD_TOO_LARGE);
888        let resp: HttpResponse =
889            WebResponseError::error_response(&JsonPayloadError::ContentType, &());
890        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
891    }
892
893    #[test]
894    fn test_query_payload_error() {
895        let err = QueryPayloadError::Deserialize(
896            serde_urlencoded::from_str::<i32>("bad query").unwrap_err(),
897        );
898        let resp: HttpResponse = WebResponseError::error_response(&err, &());
899        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
900    }
901
902    #[test]
903    fn test_path_error() {
904        let err =
905            PathError::Deserialize(serde_urlencoded::from_str::<i32>("bad path").unwrap_err());
906        let resp: HttpResponse = WebResponseError::error_response(&err, &());
907        assert_eq!(resp.status(), StatusCode::NOT_FOUND);
908    }
909
910    #[test]
911    fn test_handshake_error() {
912        use crate::ws::error::HandshakeError;
913
914        let resp = WebResponseError::<_, DefaultError>::error_response(
915            &HandshakeError::GetMethodRequired,
916            &(),
917        );
918        assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED);
919        let resp = WebResponseError::<_, DefaultError>::error_response(
920            &HandshakeError::NoWebsocketUpgrade,
921            &(),
922        );
923        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
924        let resp = WebResponseError::<_, DefaultError>::error_response(
925            &HandshakeError::NoConnectionUpgrade,
926            &(),
927        );
928        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
929        let resp = WebResponseError::<_, DefaultError>::error_response(
930            &HandshakeError::NoVersionHeader,
931            &(),
932        );
933        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
934        let resp = WebResponseError::<_, DefaultError>::error_response(
935            &HandshakeError::UnsupportedVersion,
936            &(),
937        );
938        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
939        assert_eq!(
940            resp.headers().get(header::SEC_WEBSOCKET_VERSION).unwrap(),
941            "13"
942        );
943        let resp = WebResponseError::<_, DefaultError>::error_response(
944            &HandshakeError::BadWebsocketKey,
945            &(),
946        );
947        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
948        let resp = WebResponseError::<_, DefaultError>::error_response(
949            &HandshakeError::BadWebsocketProtocol,
950            &(),
951        );
952        assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
953    }
954
955    #[test]
956    fn test_error_helpers() {
957        let err = ErrorBadRequest::<_>("err");
958        assert!(format!("{err:?}").contains("web::InternalError"));
959
960        let err: InternalError<_> =
961            InternalError::from_response("err", HttpResponse::BadRequest().build());
962        let r = WebResponseError::<_, DefaultError>::error_response(&err, &());
963        assert_eq!(r.status(), StatusCode::BAD_REQUEST);
964
965        let r =
966            WebResponseError::<_, DefaultError>::error_response(&ErrorBadRequest::<_>("err"), &());
967        assert_eq!(r.status(), StatusCode::BAD_REQUEST);
968
969        let r = WebResponseError::<_, DefaultError>::error_response(
970            &ErrorUnauthorized::<_>("err"),
971            &(),
972        );
973        assert_eq!(r.status(), StatusCode::UNAUTHORIZED);
974
975        let r = WebResponseError::<_, DefaultError>::error_response(
976            &ErrorPaymentRequired::<_>("err"),
977            &(),
978        );
979        assert_eq!(r.status(), StatusCode::PAYMENT_REQUIRED);
980
981        let r =
982            WebResponseError::<_, DefaultError>::error_response(&ErrorForbidden::<_>("err"), &());
983        assert_eq!(r.status(), StatusCode::FORBIDDEN);
984
985        let r =
986            WebResponseError::<_, DefaultError>::error_response(&ErrorNotFound::<_>("err"), &());
987        assert_eq!(r.status(), StatusCode::NOT_FOUND);
988
989        let r = WebResponseError::<_, DefaultError>::error_response(
990            &ErrorMethodNotAllowed::<_>("err"),
991            &(),
992        );
993        assert_eq!(r.status(), StatusCode::METHOD_NOT_ALLOWED);
994
995        let r = WebResponseError::<_, DefaultError>::error_response(
996            &ErrorNotAcceptable::<_>("err"),
997            &(),
998        );
999        assert_eq!(r.status(), StatusCode::NOT_ACCEPTABLE);
1000
1001        let r = WebResponseError::<_, DefaultError>::error_response(
1002            &ErrorProxyAuthenticationRequired::<_>("err"),
1003            &(),
1004        );
1005        assert_eq!(r.status(), StatusCode::PROXY_AUTHENTICATION_REQUIRED);
1006
1007        let r = WebResponseError::<_, DefaultError>::error_response(
1008            &ErrorRequestTimeout::<_>("err"),
1009            &(),
1010        );
1011        assert_eq!(r.status(), StatusCode::REQUEST_TIMEOUT);
1012
1013        let r =
1014            WebResponseError::<_, DefaultError>::error_response(&ErrorConflict::<_>("err"), &());
1015        assert_eq!(r.status(), StatusCode::CONFLICT);
1016
1017        let r = WebResponseError::<_, DefaultError>::error_response(&ErrorGone::<_>("err"), &());
1018        assert_eq!(r.status(), StatusCode::GONE);
1019
1020        let r = WebResponseError::<_, DefaultError>::error_response(
1021            &ErrorLengthRequired::<_>("err"),
1022            &(),
1023        );
1024        assert_eq!(r.status(), StatusCode::LENGTH_REQUIRED);
1025
1026        let r = WebResponseError::<_, DefaultError>::error_response(
1027            &ErrorPreconditionFailed::<_>("err"),
1028            &(),
1029        );
1030        assert_eq!(r.status(), StatusCode::PRECONDITION_FAILED);
1031
1032        let r = WebResponseError::<_, DefaultError>::error_response(
1033            &ErrorPayloadTooLarge::<_>("err"),
1034            &(),
1035        );
1036        assert_eq!(r.status(), StatusCode::PAYLOAD_TOO_LARGE);
1037
1038        let r =
1039            WebResponseError::<_, DefaultError>::error_response(&ErrorUriTooLong::<_>("err"), &());
1040        assert_eq!(r.status(), StatusCode::URI_TOO_LONG);
1041
1042        let r = WebResponseError::<_, DefaultError>::error_response(
1043            &ErrorUnsupportedMediaType::<_>("err"),
1044            &(),
1045        );
1046        assert_eq!(r.status(), StatusCode::UNSUPPORTED_MEDIA_TYPE);
1047
1048        let r = WebResponseError::<_, DefaultError>::error_response(
1049            &ErrorRangeNotSatisfiable::<_>("err"),
1050            &(),
1051        );
1052        assert_eq!(r.status(), StatusCode::RANGE_NOT_SATISFIABLE);
1053
1054        let r = WebResponseError::<_, DefaultError>::error_response(
1055            &ErrorExpectationFailed::<_>("err"),
1056            &(),
1057        );
1058        assert_eq!(r.status(), StatusCode::EXPECTATION_FAILED);
1059
1060        let r =
1061            WebResponseError::<_, DefaultError>::error_response(&ErrorImATeapot::<_>("err"), &());
1062        assert_eq!(r.status(), StatusCode::IM_A_TEAPOT);
1063
1064        let r = WebResponseError::<_, DefaultError>::error_response(
1065            &ErrorMisdirectedRequest::<_>("err"),
1066            &(),
1067        );
1068        assert_eq!(r.status(), StatusCode::MISDIRECTED_REQUEST);
1069
1070        let r = WebResponseError::<_, DefaultError>::error_response(
1071            &ErrorUnprocessableEntity::<_>("err"),
1072            &(),
1073        );
1074        assert_eq!(r.status(), StatusCode::UNPROCESSABLE_ENTITY);
1075
1076        let r = WebResponseError::<_, DefaultError>::error_response(&ErrorLocked::<_>("err"), &());
1077        assert_eq!(r.status(), StatusCode::LOCKED);
1078
1079        let r = WebResponseError::<_, DefaultError>::error_response(
1080            &ErrorFailedDependency::<_>("err"),
1081            &(),
1082        );
1083        assert_eq!(r.status(), StatusCode::FAILED_DEPENDENCY);
1084
1085        let r = WebResponseError::<_, DefaultError>::error_response(
1086            &ErrorUpgradeRequired::<_>("err"),
1087            &(),
1088        );
1089        assert_eq!(r.status(), StatusCode::UPGRADE_REQUIRED);
1090
1091        let r = WebResponseError::<_, DefaultError>::error_response(
1092            &ErrorPreconditionRequired::<_>("err"),
1093            &(),
1094        );
1095        assert_eq!(r.status(), StatusCode::PRECONDITION_REQUIRED);
1096
1097        let r = WebResponseError::<_, DefaultError>::error_response(
1098            &ErrorTooManyRequests::<_>("err"),
1099            &(),
1100        );
1101        assert_eq!(r.status(), StatusCode::TOO_MANY_REQUESTS);
1102
1103        let r = WebResponseError::<_, DefaultError>::error_response(
1104            &ErrorRequestHeaderFieldsTooLarge::<_>("err"),
1105            &(),
1106        );
1107        assert_eq!(r.status(), StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE);
1108
1109        let r = WebResponseError::<_, DefaultError>::error_response(
1110            &ErrorUnavailableForLegalReasons::<_>("err"),
1111            &(),
1112        );
1113        assert_eq!(r.status(), StatusCode::UNAVAILABLE_FOR_LEGAL_REASONS);
1114
1115        let r = WebResponseError::<_, DefaultError>::error_response(
1116            &ErrorInternalServerError::<_>("err"),
1117            &(),
1118        );
1119        assert_eq!(r.status(), StatusCode::INTERNAL_SERVER_ERROR);
1120
1121        let r = WebResponseError::<_, DefaultError>::error_response(
1122            &ErrorNotImplemented::<_>("err"),
1123            &(),
1124        );
1125        assert_eq!(r.status(), StatusCode::NOT_IMPLEMENTED);
1126
1127        let r =
1128            WebResponseError::<_, DefaultError>::error_response(&ErrorBadGateway::<_>("err"), &());
1129        assert_eq!(r.status(), StatusCode::BAD_GATEWAY);
1130
1131        let r = WebResponseError::<_, DefaultError>::error_response(
1132            &ErrorServiceUnavailable::<_>("err"),
1133            &(),
1134        );
1135        assert_eq!(r.status(), StatusCode::SERVICE_UNAVAILABLE);
1136
1137        let r = WebResponseError::<_, DefaultError>::error_response(
1138            &ErrorGatewayTimeout::<_>("err"),
1139            &(),
1140        );
1141        assert_eq!(r.status(), StatusCode::GATEWAY_TIMEOUT);
1142
1143        let r = WebResponseError::<_, DefaultError>::error_response(
1144            &ErrorHttpVersionNotSupported::<_>("err"),
1145            &(),
1146        );
1147        assert_eq!(r.status(), StatusCode::HTTP_VERSION_NOT_SUPPORTED);
1148
1149        let r = WebResponseError::<_, DefaultError>::error_response(
1150            &ErrorVariantAlsoNegotiates::<_>("err"),
1151            &(),
1152        );
1153        assert_eq!(r.status(), StatusCode::VARIANT_ALSO_NEGOTIATES);
1154
1155        let r = WebResponseError::<_, DefaultError>::error_response(
1156            &ErrorInsufficientStorage::<_>("err"),
1157            &(),
1158        );
1159        assert_eq!(r.status(), StatusCode::INSUFFICIENT_STORAGE);
1160
1161        let r = WebResponseError::<_, DefaultError>::error_response(
1162            &ErrorLoopDetected::<_>("err"),
1163            &(),
1164        );
1165        assert_eq!(r.status(), StatusCode::LOOP_DETECTED);
1166
1167        let r =
1168            WebResponseError::<_, DefaultError>::error_response(&ErrorNotExtended::<_>("err"), &());
1169        assert_eq!(r.status(), StatusCode::NOT_EXTENDED);
1170
1171        let r = WebResponseError::<_, DefaultError>::error_response(
1172            &ErrorNetworkAuthenticationRequired::<_>("err"),
1173            &(),
1174        );
1175        assert_eq!(r.status(), StatusCode::NETWORK_AUTHENTICATION_REQUIRED);
1176    }
1177
1178    #[test]
1179    fn test_default_error_renderers() {
1180        use serde::de::Error as _;
1181
1182        fn status<E: WebResponseError<(), DefaultError>>(err: &E) -> StatusCode {
1183            WebResponseError::<(), DefaultError>::error_response(err, &()).status()
1184        }
1185
1186        let err = serde_json::from_str::<i32>("x").unwrap_err();
1187        assert_eq!(status(&err), StatusCode::INTERNAL_SERVER_ERROR);
1188        let err = serde_urlencoded::to_string(1).unwrap_err();
1189        assert_eq!(status(&err), StatusCode::INTERNAL_SERVER_ERROR);
1190        let err = serde::de::value::Error::custom("bad");
1191        assert_eq!(status(&err), StatusCode::BAD_REQUEST);
1192        assert_eq!(
1193            status(&crate::http::error::Canceled),
1194            StatusCode::INTERNAL_SERVER_ERROR
1195        );
1196        assert_eq!(
1197            status(&BlockingError::<io::Error>::Canceled),
1198            StatusCode::INTERNAL_SERVER_ERROR
1199        );
1200        let err: HttpError = http::header::HeaderName::try_from("bad header")
1201            .unwrap_err()
1202            .into();
1203        assert_eq!(status(&err), StatusCode::INTERNAL_SERVER_ERROR);
1204        assert_eq!(
1205            status(&UrlGenerationError::ResourceNotFound),
1206            StatusCode::INTERNAL_SERVER_ERROR
1207        );
1208        assert_eq!(
1209            status(&crate::client::error::ClientPayloadError(
1210                http::error::PayloadError::Incomplete(None)
1211            )),
1212            StatusCode::BAD_REQUEST
1213        );
1214        assert_eq!(
1215            status(&http::error::PayloadError::Overflow),
1216            StatusCode::PAYLOAD_TOO_LARGE
1217        );
1218
1219        #[cfg(feature = "openssl")]
1220        {
1221            let err = tls_openssl::ssl::Error::from(tls_openssl::error::ErrorStack::get());
1222            assert_eq!(status(&err), StatusCode::BAD_REQUEST);
1223        }
1224    }
1225
1226    #[derive(Debug, thiserror::Error)]
1227    #[error("custom error")]
1228    struct CustomError(#[source] io::Error);
1229
1230    impl WebResponseError<(), DefaultError> for CustomError {}
1231
1232    #[test]
1233    fn test_web_error() {
1234        let err = CustomError(io::Error::other("inner"));
1235        let res = WebResponseError::<(), DefaultError>::error_response(&err, &());
1236        assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
1237
1238        let err = WebError::<(), DefaultError>::from_err(CustomError(io::Error::other("inner")));
1239        assert_eq!(err.source().unwrap().to_string(), "inner");
1240        let res = WebResponseError::error_response(&err, &());
1241        assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
1242
1243        // WebError is not boxed twice
1244        let err = WebError::<(), DefaultError>::from_err(err);
1245        assert_eq!(err.to_string(), "custom error");
1246        let res = WebResponseError::error_response(&err, &());
1247        assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
1248
1249        let err = crate::error::Error::from(crate::http::error::Canceled);
1250        let res = WebResponseError::<(), DefaultError>::error_response(&err, &());
1251        assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
1252    }
1253
1254    #[test]
1255    fn test_internal_error_response_taken() {
1256        let err = InternalError::from_response("err", HttpResponse::Ok().build());
1257        let res = WebResponseError::<(), DefaultError>::error_response(&err, &());
1258        assert_eq!(res.status(), StatusCode::OK);
1259        let res = WebResponseError::<(), DefaultError>::error_response(&err, &());
1260        assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
1261    }
1262}