tosic_http/error/
mod.rs

1//! Main Error handling of the library
2//!
3//! Internally all errors are wrapped in the `ServerError` type.
4//!
5//! Externally the [`struct@Error`] should be used or implement the [`ResponseError`] trait.
6
7use crate::body::BoxBody;
8use crate::response::HttpResponse;
9use http::{HeaderMap, Response};
10use std::fmt;
11use std::fmt::Debug;
12use thiserror::Error;
13
14mod foreign_impls;
15pub(crate) mod macros;
16pub mod response_error;
17
18pub use response_error::ResponseError;
19
20#[derive(Debug, Error)]
21#[allow(missing_docs)]
22/// The main error type used in the library
23pub enum ServerError {
24    #[error(transparent)]
25    Io(#[from] std::io::Error),
26    #[error(transparent)]
27    Error(#[from] Error),
28    #[error(transparent)]
29    Http(#[from] http::Error),
30    #[error(transparent)]
31    ExtractionError(#[from] crate::extractors::ExtractionError),
32    #[error(transparent)]
33    ParseError(#[from] httparse::Error),
34    #[error(transparent)]
35    InvalidHeaderValue(#[from] http::header::InvalidHeaderValue),
36    #[error(transparent)]
37    InvalidUri(#[from] http::uri::InvalidUri),
38    #[error(transparent)]
39    InvalidMethod(#[from] http::method::InvalidMethod),
40    #[error("Uri Empty")]
41    UriEmpty,
42    #[error("Method not Provided")]
43    MethodEmpty,
44    #[error("Version is not provided")]
45    VersionEmpty,
46    #[error("Connection was closed")]
47    ConnectionClosed,
48    #[error("Partially parsed the request")]
49    PartialParsed,
50    #[error("Invalid encoding for request")]
51    InvalidEncoding,
52    #[error("Failed to construct the service")]
53    ServiceConstructionFailed,
54}
55
56/// External Error type should implement the `ResponseError` trait.
57pub struct Error {
58    cause: Box<dyn ResponseError>,
59}
60
61/*impl Debug for Error {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        fmt::Debug::fmt(&self.cause, f)
64    }
65}*/
66
67impl Error {
68    /// Returns the reference to the underlying `ResponseError`.
69    pub fn as_response_error(&self) -> &dyn ResponseError {
70        self.cause.as_ref()
71    }
72
73    /// Similar to `as_response_error` but downcasts.
74    pub fn as_error<T: ResponseError + 'static>(&self) -> Option<&T> {
75        <dyn ResponseError>::downcast_ref(self.cause.as_ref())
76    }
77
78    /// Shortcut for creating an `HttpResponse`.
79    pub fn error_response(&self) -> HttpResponse {
80        self.cause.error_response()
81    }
82}
83
84impl fmt::Display for Error {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        fmt::Display::fmt(&self.cause, f)
87    }
88}
89
90impl fmt::Debug for Error {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        write!(f, "{:?}", &self.cause)
93    }
94}
95
96impl std::error::Error for Error {
97    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
98        None
99    }
100}
101
102/// `Error` for any error that implements `ResponseError`
103impl<T: ResponseError + 'static> From<T> for Error {
104    fn from(err: T) -> Error {
105        Error {
106            cause: Box::new(err),
107        }
108    }
109}
110
111impl From<Box<dyn ResponseError>> for Error {
112    fn from(value: Box<dyn ResponseError>) -> Self {
113        Error { cause: value }
114    }
115}
116
117impl From<Error> for Response<BoxBody> {
118    fn from(err: Error) -> Response<BoxBody> {
119        err.error_response().into()
120    }
121}
122
123impl From<HttpResponse> for Response<BoxBody> {
124    fn from(value: HttpResponse<BoxBody>) -> Self {
125        let mut response = Response::builder().status(value.status_code());
126
127        let headers = if let Some(headers) = response.headers_mut() {
128            headers
129        } else {
130            &mut HeaderMap::new()
131        };
132
133        for (header, value) in value.headers() {
134            headers.insert(header, value.clone());
135        }
136
137        response.body(value.body).unwrap()
138    }
139}