diff --git a/examples/diesel/Cargo.toml b/examples/diesel/Cargo.toml index 703b806ab..f9dcf1c78 100644 --- a/examples/diesel/Cargo.toml +++ b/examples/diesel/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Nikolay Kim "] workspace = "../.." [dependencies] -env_logger = "0.4" +env_logger = "0.5" actix = "0.4" actix-web = { path = "../../" } diff --git a/examples/hello-world/Cargo.toml b/examples/hello-world/Cargo.toml index 4cb1f70f7..20a93788a 100644 --- a/examples/hello-world/Cargo.toml +++ b/examples/hello-world/Cargo.toml @@ -5,6 +5,6 @@ authors = ["Nikolay Kim "] workspace = "../.." [dependencies] -env_logger = "0.4" +env_logger = "0.5" actix = "0.4" actix-web = { path = "../../" } diff --git a/examples/state/Cargo.toml b/examples/state/Cargo.toml index b92b0082f..0880ced5f 100644 --- a/examples/state/Cargo.toml +++ b/examples/state/Cargo.toml @@ -6,6 +6,6 @@ workspace = "../.." [dependencies] futures = "*" -env_logger = "0.4" +env_logger = "0.5" actix = "0.4" actix-web = { path = "../../" } diff --git a/examples/template_tera/Cargo.toml b/examples/template_tera/Cargo.toml index 876dbb938..400c367a8 100644 --- a/examples/template_tera/Cargo.toml +++ b/examples/template_tera/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Nikolay Kim "] workspace = "../.." [dependencies] -env_logger = "0.4" +env_logger = "0.5" actix = "0.4" actix-web = { path = "../../" } tera = "*" diff --git a/examples/tls/Cargo.toml b/examples/tls/Cargo.toml index e1d5507b5..024d7fc1d 100644 --- a/examples/tls/Cargo.toml +++ b/examples/tls/Cargo.toml @@ -9,6 +9,6 @@ name = "server" path = "src/main.rs" [dependencies] -env_logger = "0.4" +env_logger = "0.5" actix = "^0.4.2" actix-web = { path = "../../", features=["alpn"] } diff --git a/src/error.rs b/src/error.rs index 512419a85..39cf69295 100644 --- a/src/error.rs +++ b/src/error.rs @@ -68,8 +68,8 @@ impl fmt::Display for Error { impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.backtrace.is_none() { - fmt::Debug::fmt(&self.cause, f) + if let Some(bt) = self.cause.backtrace() { + write!(f, "{:?}\n\n{:?}", &self.cause, bt) } else { write!(f, "{:?}\n\n{:?}", &self.cause, self.backtrace.as_ref().unwrap()) } @@ -495,52 +495,7 @@ impl From for UrlGenerationError { } } -macro_rules! ERROR_WRAP { - ($type:ty, $status:expr) => { - unsafe impl Sync for $type {} - unsafe impl Send for $type {} - - impl $type { - pub fn cause(&self) -> &T { - &self.0 - } - } - - impl Fail for $type {} - impl Fail for $type { - fn backtrace(&self) -> Option<&Backtrace> { - self.cause().backtrace() - } - } - - impl fmt::Display for $type { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } - } - - impl ResponseError for $type - where T: Send + Sync + fmt::Debug + fmt::Display + 'static - { - fn error_response(&self) -> HttpResponse { - HttpResponse::new($status, Body::Empty) - } - } - - impl Responder for $type - where T: Send + Sync + fmt::Debug + fmt::Display + 'static - { - type Item = HttpResponse; - type Error = Error; - - fn respond_to(self, _: HttpRequest) -> Result { - Err(self.into()) - } - } - } -} - -/// Helper type that can wrap any error and generate *BAD REQUEST* response. +/// Helper type that can wrap any error and generate custom response. /// /// In following example any `io::Error` will be converted into "BAD REQUEST" response /// as opposite to *INNTERNAL SERVER ERROR* which is defined by default. @@ -556,59 +511,133 @@ macro_rules! ERROR_WRAP { /// } /// # fn main() {} /// ``` -#[derive(Debug)] -pub struct ErrorBadRequest(pub T); -ERROR_WRAP!(ErrorBadRequest, StatusCode::BAD_REQUEST); +pub struct InternalError { + cause: T, + status: StatusCode, + backtrace: Backtrace, +} + +unsafe impl Sync for InternalError {} +unsafe impl Send for InternalError {} + +impl InternalError { + pub fn new(err: T, status: StatusCode) -> Self { + InternalError { + cause: err, + status: status, + backtrace: Backtrace::new(), + } + } +} + +impl Fail for InternalError + where T: Send + Sync + fmt::Display + fmt::Debug + 'static +{ + fn backtrace(&self) -> Option<&Backtrace> { + Some(&self.backtrace) + } +} + +impl fmt::Debug for InternalError + where T: Send + Sync + fmt::Display + fmt::Debug + 'static +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.cause, f) + } +} + +impl fmt::Display for InternalError + where T: Send + Sync + fmt::Display + fmt::Debug + 'static +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.cause, f) + } +} + +impl ResponseError for InternalError + where T: Send + Sync + fmt::Display + fmt::Debug + 'static +{ + fn error_response(&self) -> HttpResponse { + HttpResponse::new(self.status, Body::Empty) + } +} + +impl Responder for InternalError + where T: Send + Sync + fmt::Display + fmt::Debug + 'static +{ + type Item = HttpResponse; + type Error = Error; + + fn respond_to(self, _: HttpRequest) -> Result { + Err(self.into()) + } +} + +/// Helper type that can wrap any error and generate *BAD REQUEST* response. +#[allow(non_snake_case)] +pub fn ErrorBadRequest(err: T) -> InternalError { + InternalError::new(err, StatusCode::BAD_REQUEST) +} -#[derive(Debug)] /// Helper type that can wrap any error and generate *UNAUTHORIZED* response. -pub struct ErrorUnauthorized(pub T); -ERROR_WRAP!(ErrorUnauthorized, StatusCode::UNAUTHORIZED); +#[allow(non_snake_case)] +pub fn ErrorUnauthorized(err: T) -> InternalError { + InternalError::new(err, StatusCode::UNAUTHORIZED) +} -#[derive(Debug)] /// Helper type that can wrap any error and generate *FORBIDDEN* response. -pub struct ErrorForbidden(pub T); -ERROR_WRAP!(ErrorForbidden, StatusCode::FORBIDDEN); +#[allow(non_snake_case)] +pub fn ErrorForbidden(err: T) -> InternalError { + InternalError::new(err, StatusCode::FORBIDDEN) +} -#[derive(Debug)] /// Helper type that can wrap any error and generate *NOT FOUND* response. -pub struct ErrorNotFound(pub T); -ERROR_WRAP!(ErrorNotFound, StatusCode::NOT_FOUND); +#[allow(non_snake_case)] +pub fn ErrorNotFound(err: T) -> InternalError { + InternalError::new(err, StatusCode::NOT_FOUND) +} -#[derive(Debug)] /// Helper type that can wrap any error and generate *METHOD NOT ALLOWED* response. -pub struct ErrorMethodNotAllowed(pub T); -ERROR_WRAP!(ErrorMethodNotAllowed, StatusCode::METHOD_NOT_ALLOWED); +#[allow(non_snake_case)] +pub fn ErrorMethodNotAllowed(err: T) -> InternalError { + InternalError::new(err, StatusCode::METHOD_NOT_ALLOWED) +} -#[derive(Debug)] /// Helper type that can wrap any error and generate *REQUEST TIMEOUT* response. -pub struct ErrorRequestTimeout(pub T); -ERROR_WRAP!(ErrorRequestTimeout, StatusCode::REQUEST_TIMEOUT); +#[allow(non_snake_case)] +pub fn ErrorRequestTimeout(err: T) -> InternalError { + InternalError::new(err, StatusCode::REQUEST_TIMEOUT) +} -#[derive(Debug)] /// Helper type that can wrap any error and generate *CONFLICT* response. -pub struct ErrorConflict(pub T); -ERROR_WRAP!(ErrorConflict, StatusCode::CONFLICT); +#[allow(non_snake_case)] +pub fn ErrorConflict(err: T) -> InternalError { + InternalError::new(err, StatusCode::CONFLICT) +} -#[derive(Debug)] /// Helper type that can wrap any error and generate *GONE* response. -pub struct ErrorGone(pub T); -ERROR_WRAP!(ErrorGone, StatusCode::GONE); +#[allow(non_snake_case)] +pub fn ErrorGone(err: T) -> InternalError { + InternalError::new(err, StatusCode::GONE) +} -#[derive(Debug)] /// Helper type that can wrap any error and generate *PRECONDITION FAILED* response. -pub struct ErrorPreconditionFailed(pub T); -ERROR_WRAP!(ErrorPreconditionFailed, StatusCode::PRECONDITION_FAILED); +#[allow(non_snake_case)] +pub fn ErrorPreconditionFailed(err: T) -> InternalError { + InternalError::new(err, StatusCode::PRECONDITION_FAILED) +} -#[derive(Debug)] /// Helper type that can wrap any error and generate *EXPECTATION FAILED* response. -pub struct ErrorExpectationFailed(pub T); -ERROR_WRAP!(ErrorExpectationFailed, StatusCode::EXPECTATION_FAILED); +#[allow(non_snake_case)] +pub fn ErrorExpectationFailed(err: T) -> InternalError { + InternalError::new(err, StatusCode::EXPECTATION_FAILED) +} -#[derive(Debug)] /// Helper type that can wrap any error and generate *INTERNAL SERVER ERROR* response. -pub struct ErrorInternalServerError(pub T); -ERROR_WRAP!(ErrorInternalServerError, StatusCode::INTERNAL_SERVER_ERROR); +#[allow(non_snake_case)] +pub fn ErrorInternalServerError(err: T) -> InternalError { + InternalError::new(err, StatusCode::INTERNAL_SERVER_ERROR) +} #[cfg(test)] mod tests { diff --git a/src/param.rs b/src/param.rs index 59454a76d..1bb89d2db 100644 --- a/src/param.rs +++ b/src/param.rs @@ -6,7 +6,7 @@ use std::slice::Iter; use std::borrow::Cow; use smallvec::SmallVec; -use error::{ResponseError, UriSegmentError, ErrorBadRequest}; +use error::{ResponseError, UriSegmentError, InternalError, ErrorBadRequest}; /// A trait to abstract the idea of creating a new instance of a type from a path parameter. @@ -141,7 +141,7 @@ impl FromParam for PathBuf { macro_rules! FROM_STR { ($type:ty) => { impl FromParam for $type { - type Err = ErrorBadRequest<<$type as FromStr>::Err>; + type Err = InternalError<<$type as FromStr>::Err>; fn from_param(val: &str) -> Result { <$type as FromStr>::from_str(val).map_err(ErrorBadRequest)