1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-12-18 14:16:47 +00:00

Implemented .cause() for InternalError's Fail trait.

This require Fail on InternalError's content.
This commit is contained in:
Sergey Mitskevich 2018-08-03 20:28:35 +03:00
parent 036cf5e867
commit 2e7ceb3f4a
6 changed files with 117 additions and 53 deletions

View file

@ -238,7 +238,9 @@ where
if self.fut.alive() { if self.fut.alive() {
match self.fut.poll() { match self.fut.poll() {
Ok(Async::NotReady) | Ok(Async::Ready(())) => (), Ok(Async::NotReady) | Ok(Async::Ready(())) => (),
Err(_) => return Err(ErrorInternalServerError("error")), Err(_) => {
return Err(ErrorInternalServerError(::error::FailMsg("error")))
}
} }
} }

View file

@ -633,6 +633,35 @@ impl ResponseError for StaticFileError {
} }
} }
/// Helper type for making `Fail` instance from `&'static str` without memory allocation.
///
/// In following example handler is returning error message with *BAD REQUEST* status code.
///
/// ```rust
/// # extern crate actix_web;
/// # use actix_web::*;
///
/// fn index(req: HttpRequest) -> Result<()> {
/// Err(error::ErrorBadRequest(error::FailMsg("example of error message")))
/// }
/// # fn main() {}
/// ```
pub struct FailMsg(pub &'static str);
impl Fail for FailMsg {}
impl fmt::Debug for FailMsg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl fmt::Display for FailMsg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
/// Helper type that can wrap any error and generate custom response. /// Helper type that can wrap any error and generate custom response.
/// ///
/// In following example any `io::Error` will be converted into "BAD REQUEST" /// In following example any `io::Error` will be converted into "BAD REQUEST"
@ -684,8 +713,12 @@ impl<T> InternalError<T> {
impl<T> Fail for InternalError<T> impl<T> Fail for InternalError<T>
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
fn cause(&self) -> Option<&Fail> {
self.cause.cause()
}
fn backtrace(&self) -> Option<&Backtrace> { fn backtrace(&self) -> Option<&Backtrace> {
Some(&self.backtrace) Some(&self.backtrace)
} }
@ -711,7 +744,7 @@ where
impl<T> ResponseError for InternalError<T> impl<T> ResponseError for InternalError<T>
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
fn error_response(&self) -> HttpResponse { fn error_response(&self) -> HttpResponse {
match self.status { match self.status {
@ -729,7 +762,7 @@ where
impl<T> Responder for InternalError<T> impl<T> Responder for InternalError<T>
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
type Item = HttpResponse; type Item = HttpResponse;
type Error = Error; type Error = Error;
@ -744,7 +777,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorBadRequest<T>(err: T) -> Error pub fn ErrorBadRequest<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::BAD_REQUEST).into() InternalError::new(err, StatusCode::BAD_REQUEST).into()
} }
@ -754,7 +787,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorUnauthorized<T>(err: T) -> Error pub fn ErrorUnauthorized<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::UNAUTHORIZED).into() InternalError::new(err, StatusCode::UNAUTHORIZED).into()
} }
@ -764,7 +797,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorForbidden<T>(err: T) -> Error pub fn ErrorForbidden<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::FORBIDDEN).into() InternalError::new(err, StatusCode::FORBIDDEN).into()
} }
@ -774,7 +807,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorNotFound<T>(err: T) -> Error pub fn ErrorNotFound<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::NOT_FOUND).into() InternalError::new(err, StatusCode::NOT_FOUND).into()
} }
@ -784,7 +817,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorMethodNotAllowed<T>(err: T) -> Error pub fn ErrorMethodNotAllowed<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::METHOD_NOT_ALLOWED).into() InternalError::new(err, StatusCode::METHOD_NOT_ALLOWED).into()
} }
@ -794,7 +827,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorRequestTimeout<T>(err: T) -> Error pub fn ErrorRequestTimeout<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::REQUEST_TIMEOUT).into() InternalError::new(err, StatusCode::REQUEST_TIMEOUT).into()
} }
@ -804,7 +837,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorConflict<T>(err: T) -> Error pub fn ErrorConflict<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::CONFLICT).into() InternalError::new(err, StatusCode::CONFLICT).into()
} }
@ -814,7 +847,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorGone<T>(err: T) -> Error pub fn ErrorGone<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::GONE).into() InternalError::new(err, StatusCode::GONE).into()
} }
@ -824,7 +857,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorPreconditionFailed<T>(err: T) -> Error pub fn ErrorPreconditionFailed<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::PRECONDITION_FAILED).into() InternalError::new(err, StatusCode::PRECONDITION_FAILED).into()
} }
@ -834,7 +867,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorExpectationFailed<T>(err: T) -> Error pub fn ErrorExpectationFailed<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::EXPECTATION_FAILED).into() InternalError::new(err, StatusCode::EXPECTATION_FAILED).into()
} }
@ -844,7 +877,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorInternalServerError<T>(err: T) -> Error pub fn ErrorInternalServerError<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::INTERNAL_SERVER_ERROR).into() InternalError::new(err, StatusCode::INTERNAL_SERVER_ERROR).into()
} }
@ -854,7 +887,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorNotImplemented<T>(err: T) -> Error pub fn ErrorNotImplemented<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::NOT_IMPLEMENTED).into() InternalError::new(err, StatusCode::NOT_IMPLEMENTED).into()
} }
@ -864,7 +897,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorBadGateway<T>(err: T) -> Error pub fn ErrorBadGateway<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::BAD_GATEWAY).into() InternalError::new(err, StatusCode::BAD_GATEWAY).into()
} }
@ -874,7 +907,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorServiceUnavailable<T>(err: T) -> Error pub fn ErrorServiceUnavailable<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::SERVICE_UNAVAILABLE).into() InternalError::new(err, StatusCode::SERVICE_UNAVAILABLE).into()
} }
@ -884,7 +917,7 @@ where
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn ErrorGatewayTimeout<T>(err: T) -> Error pub fn ErrorGatewayTimeout<T>(err: T) -> Error
where where
T: Send + Sync + fmt::Debug + fmt::Display + 'static, T: Fail,
{ {
InternalError::new(err, StatusCode::GATEWAY_TIMEOUT).into() InternalError::new(err, StatusCode::GATEWAY_TIMEOUT).into()
} }
@ -934,7 +967,7 @@ mod tests {
#[test] #[test]
fn test_backtrace() { fn test_backtrace() {
let e = ErrorBadRequest("err"); let e = ErrorBadRequest(FailMsg("err"));
let _ = e.backtrace(); let _ = e.backtrace();
} }
@ -1034,6 +1067,25 @@ mod tests {
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
} }
#[test]
fn test_internal_error_cause() {
#[derive(Debug, Fail)]
#[fail(display = "demo error parent")]
struct DemoErrorParent;
#[derive(Debug, Fail)]
#[fail(display = "demo error child")]
struct DemoErrorChild(#[cause] DemoErrorParent);
let f = DemoErrorChild(DemoErrorParent);
let err = ErrorBadRequest(f);
assert_eq!("demo error child", format!("{}", err.as_fail()));
assert_eq!(
"demo error parent",
format!("{}", err.as_fail().cause().unwrap())
);
}
#[test] #[test]
fn test_error_downcasting_direct() { fn test_error_downcasting_direct() {
#[derive(Debug, Fail)] #[derive(Debug, Fail)]
@ -1062,49 +1114,56 @@ mod tests {
#[test] #[test]
fn test_error_helpers() { fn test_error_helpers() {
let r: HttpResponse = ErrorBadRequest("err").into(); let r: HttpResponse = ErrorBadRequest(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::BAD_REQUEST); assert_eq!(r.status(), StatusCode::BAD_REQUEST);
let r: HttpResponse = ErrorUnauthorized("err").into(); let r: HttpResponse = ErrorUnauthorized(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::UNAUTHORIZED); assert_eq!(r.status(), StatusCode::UNAUTHORIZED);
let r: HttpResponse = ErrorForbidden("err").into(); let r: HttpResponse = ErrorForbidden(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::FORBIDDEN); assert_eq!(r.status(), StatusCode::FORBIDDEN);
let r: HttpResponse = ErrorNotFound("err").into(); let r: HttpResponse = ErrorNotFound(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::NOT_FOUND); assert_eq!(r.status(), StatusCode::NOT_FOUND);
let r: HttpResponse = ErrorMethodNotAllowed("err").into(); let r: HttpResponse = ErrorMethodNotAllowed(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::METHOD_NOT_ALLOWED); assert_eq!(r.status(), StatusCode::METHOD_NOT_ALLOWED);
let r: HttpResponse = ErrorRequestTimeout("err").into(); let r: HttpResponse = ErrorRequestTimeout(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::REQUEST_TIMEOUT); assert_eq!(r.status(), StatusCode::REQUEST_TIMEOUT);
let r: HttpResponse = ErrorConflict("err").into(); let r: HttpResponse = ErrorConflict(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::CONFLICT); assert_eq!(r.status(), StatusCode::CONFLICT);
let r: HttpResponse = ErrorGone("err").into(); let r: HttpResponse = ErrorGone(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::GONE); assert_eq!(r.status(), StatusCode::GONE);
let r: HttpResponse = ErrorPreconditionFailed("err").into(); let r: HttpResponse = ErrorPreconditionFailed(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::PRECONDITION_FAILED); assert_eq!(r.status(), StatusCode::PRECONDITION_FAILED);
let r: HttpResponse = ErrorExpectationFailed("err").into(); let r: HttpResponse = ErrorExpectationFailed(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::EXPECTATION_FAILED); assert_eq!(r.status(), StatusCode::EXPECTATION_FAILED);
let r: HttpResponse = ErrorInternalServerError("err").into(); let r: HttpResponse = ErrorInternalServerError(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::INTERNAL_SERVER_ERROR); assert_eq!(r.status(), StatusCode::INTERNAL_SERVER_ERROR);
let r: HttpResponse = ErrorNotImplemented("err").into(); let r: HttpResponse = ErrorNotImplemented(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::NOT_IMPLEMENTED); assert_eq!(r.status(), StatusCode::NOT_IMPLEMENTED);
let r: HttpResponse = ErrorBadGateway("err").into(); let r: HttpResponse = ErrorBadGateway(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::BAD_GATEWAY); assert_eq!(r.status(), StatusCode::BAD_GATEWAY);
let r: HttpResponse = ErrorServiceUnavailable("err").into(); let r: HttpResponse = ErrorServiceUnavailable(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::SERVICE_UNAVAILABLE); assert_eq!(r.status(), StatusCode::SERVICE_UNAVAILABLE);
let r: HttpResponse = ErrorGatewayTimeout("err").into(); let r: HttpResponse = ErrorGatewayTimeout(FailMsg("err")).into();
assert_eq!(r.status(), StatusCode::GATEWAY_TIMEOUT); assert_eq!(r.status(), StatusCode::GATEWAY_TIMEOUT);
} }
#[test]
fn test_error_helpers_from_std_err() {
let io_err = io::Error::new(io::ErrorKind::Other, "other");
let err = ErrorNotImplemented(io_err);
assert_eq!("other", format!("{}", err))
}
} }

View file

@ -12,7 +12,7 @@ use serde::de::{self, DeserializeOwned};
use serde_urlencoded; use serde_urlencoded;
use de::PathDeserializer; use de::PathDeserializer;
use error::{Error, ErrorBadRequest, ErrorNotFound, UrlencodedError}; use error::{Error, ErrorBadRequest, ErrorNotFound, FailMsg, UrlencodedError};
use handler::{AsyncResult, FromRequest}; use handler::{AsyncResult, FromRequest};
use httpmessage::{HttpMessage, MessageBody, UrlEncoded}; use httpmessage::{HttpMessage, MessageBody, UrlEncoded};
use httprequest::HttpRequest; use httprequest::HttpRequest;
@ -446,12 +446,13 @@ impl<S: 'static> FromRequest<S> for String {
let enc: *const Encoding = encoding as *const Encoding; let enc: *const Encoding = encoding as *const Encoding;
if enc == UTF_8 { if enc == UTF_8 {
Ok(str::from_utf8(body.as_ref()) Ok(str::from_utf8(body.as_ref())
.map_err(|_| ErrorBadRequest("Can not decode body"))? .map_err(|_| {
.to_owned()) ErrorBadRequest(FailMsg("Can not decode body"))
})?.to_owned())
} else { } else {
Ok(encoding Ok(encoding.decode(&body, DecoderTrap::Strict).map_err(
.decode(&body, DecoderTrap::Strict) |_| ErrorBadRequest(FailMsg("Can not decode body")),
.map_err(|_| ErrorBadRequest("Can not decode body"))?) )?)
} }
}), }),
)) ))
@ -469,7 +470,7 @@ impl<S: 'static> FromRequest<S> for String {
/// extern crate rand; /// extern crate rand;
/// #[macro_use] extern crate serde_derive; /// #[macro_use] extern crate serde_derive;
/// use actix_web::{http, App, Result, HttpRequest, Error, FromRequest}; /// use actix_web::{http, App, Result, HttpRequest, Error, FromRequest};
/// use actix_web::error::ErrorBadRequest; /// use actix_web::error::{ErrorBadRequest, FailMsg};
/// ///
/// #[derive(Debug, Deserialize)] /// #[derive(Debug, Deserialize)]
/// struct Thing { name: String } /// struct Thing { name: String }
@ -483,7 +484,7 @@ impl<S: 'static> FromRequest<S> for String {
/// if rand::random() { /// if rand::random() {
/// Ok(Thing { name: "thingy".into() }) /// Ok(Thing { name: "thingy".into() })
/// } else { /// } else {
/// Err(ErrorBadRequest("no luck")) /// Err(ErrorBadRequest(FailMsg("no luck")))
/// } /// }
/// ///
/// } /// }
@ -531,7 +532,7 @@ where
/// extern crate rand; /// extern crate rand;
/// #[macro_use] extern crate serde_derive; /// #[macro_use] extern crate serde_derive;
/// use actix_web::{http, App, Result, HttpRequest, Error, FromRequest}; /// use actix_web::{http, App, Result, HttpRequest, Error, FromRequest};
/// use actix_web::error::ErrorBadRequest; /// use actix_web::error::{ErrorBadRequest, FailMsg};
/// ///
/// #[derive(Debug, Deserialize)] /// #[derive(Debug, Deserialize)]
/// struct Thing { name: String } /// struct Thing { name: String }
@ -545,7 +546,7 @@ where
/// if rand::random() { /// if rand::random() {
/// Ok(Thing { name: "thingy".into() }) /// Ok(Thing { name: "thingy".into() })
/// } else { /// } else {
/// Err(ErrorBadRequest("no luck")) /// Err(ErrorBadRequest(FailMsg("no luck")))
/// } /// }
/// ///
/// } /// }
@ -604,11 +605,11 @@ impl PayloadConfig {
match req.mime_type() { match req.mime_type() {
Ok(Some(ref req_mt)) => { Ok(Some(ref req_mt)) => {
if mt != req_mt { if mt != req_mt {
return Err(ErrorBadRequest("Unexpected Content-Type")); return Err(ErrorBadRequest(FailMsg("Unexpected Content-Type")));
} }
} }
Ok(None) => { Ok(None) => {
return Err(ErrorBadRequest("Content-Type is expected")); return Err(ErrorBadRequest(FailMsg("Content-Type is expected")));
} }
Err(err) => { Err(err) => {
return Err(err.into()); return Err(err.into());

View file

@ -120,7 +120,9 @@ mod tests {
impl<S> Middleware<S> for MiddlewareOne { impl<S> Middleware<S> for MiddlewareOne {
fn start(&self, _: &HttpRequest<S>) -> Result<Started, Error> { fn start(&self, _: &HttpRequest<S>) -> Result<Started, Error> {
Err(ErrorInternalServerError("middleware error")) Err(ErrorInternalServerError(::error::FailMsg(
"middleware error",
)))
} }
} }

View file

@ -308,7 +308,7 @@ where
fn poll(&mut self) -> Poll<Option<SmallVec<[ContextFrame; 4]>>, Error> { fn poll(&mut self) -> Poll<Option<SmallVec<[ContextFrame; 4]>>, Error> {
if self.fut.alive() && self.fut.poll().is_err() { if self.fut.alive() && self.fut.poll().is_err() {
return Err(ErrorInternalServerError("error")); return Err(ErrorInternalServerError(::error::FailMsg("error")));
} }
// frames // frames

View file

@ -8,7 +8,7 @@ use std::sync::Arc;
use std::thread; use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use actix_web::error::{Error, ErrorInternalServerError}; use actix_web::error::{Error, ErrorInternalServerError, FailMsg};
use actix_web::*; use actix_web::*;
use futures::{future, Future}; use futures::{future, Future};
use tokio_timer::Delay; use tokio_timer::Delay;
@ -332,7 +332,7 @@ fn test_scope_middleware_async_handler() {
} }
fn index_test_middleware_async_error(_: &HttpRequest) -> FutureResponse<HttpResponse> { fn index_test_middleware_async_error(_: &HttpRequest) -> FutureResponse<HttpResponse> {
future::result(Err(error::ErrorBadRequest("TEST"))).responder() future::result(Err(error::ErrorBadRequest(FailMsg("TEST")))).responder()
} }
#[test] #[test]
@ -794,7 +794,7 @@ struct MiddlewareWithErr;
impl<S> middleware::Middleware<S> for MiddlewareWithErr { impl<S> middleware::Middleware<S> for MiddlewareWithErr {
fn start(&self, _: &HttpRequest<S>) -> Result<middleware::Started, Error> { fn start(&self, _: &HttpRequest<S>) -> Result<middleware::Started, Error> {
Err(ErrorInternalServerError("middleware error")) Err(ErrorInternalServerError(FailMsg("middleware error")))
} }
} }
@ -803,7 +803,7 @@ struct MiddlewareAsyncWithErr;
impl<S> middleware::Middleware<S> for MiddlewareAsyncWithErr { impl<S> middleware::Middleware<S> for MiddlewareAsyncWithErr {
fn start(&self, _: &HttpRequest<S>) -> Result<middleware::Started, Error> { fn start(&self, _: &HttpRequest<S>) -> Result<middleware::Started, Error> {
Ok(middleware::Started::Future(Box::new(future::err( Ok(middleware::Started::Future(Box::new(future::err(
ErrorInternalServerError("middleware error"), ErrorInternalServerError(FailMsg("middleware error")),
)))) ))))
} }
} }