Skip to main content

ntex/web/
error.rs

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