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() {
match self.fut.poll() {
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.
///
/// 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>
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
fn cause(&self) -> Option<&Fail> {
self.cause.cause()
}
fn backtrace(&self) -> Option<&Backtrace> {
Some(&self.backtrace)
}
@ -711,7 +744,7 @@ where
impl<T> ResponseError for InternalError<T>
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
fn error_response(&self) -> HttpResponse {
match self.status {
@ -729,7 +762,7 @@ where
impl<T> Responder for InternalError<T>
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
type Item = HttpResponse;
type Error = Error;
@ -744,7 +777,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorBadRequest<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::BAD_REQUEST).into()
}
@ -754,7 +787,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorUnauthorized<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::UNAUTHORIZED).into()
}
@ -764,7 +797,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorForbidden<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::FORBIDDEN).into()
}
@ -774,7 +807,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorNotFound<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::NOT_FOUND).into()
}
@ -784,7 +817,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorMethodNotAllowed<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::METHOD_NOT_ALLOWED).into()
}
@ -794,7 +827,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorRequestTimeout<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::REQUEST_TIMEOUT).into()
}
@ -804,7 +837,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorConflict<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::CONFLICT).into()
}
@ -814,7 +847,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorGone<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::GONE).into()
}
@ -824,7 +857,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorPreconditionFailed<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::PRECONDITION_FAILED).into()
}
@ -834,7 +867,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorExpectationFailed<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::EXPECTATION_FAILED).into()
}
@ -844,7 +877,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorInternalServerError<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::INTERNAL_SERVER_ERROR).into()
}
@ -854,7 +887,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorNotImplemented<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::NOT_IMPLEMENTED).into()
}
@ -864,7 +897,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorBadGateway<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::BAD_GATEWAY).into()
}
@ -874,7 +907,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorServiceUnavailable<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::SERVICE_UNAVAILABLE).into()
}
@ -884,7 +917,7 @@ where
#[allow(non_snake_case)]
pub fn ErrorGatewayTimeout<T>(err: T) -> Error
where
T: Send + Sync + fmt::Debug + fmt::Display + 'static,
T: Fail,
{
InternalError::new(err, StatusCode::GATEWAY_TIMEOUT).into()
}
@ -934,7 +967,7 @@ mod tests {
#[test]
fn test_backtrace() {
let e = ErrorBadRequest("err");
let e = ErrorBadRequest(FailMsg("err"));
let _ = e.backtrace();
}
@ -1034,6 +1067,25 @@ mod tests {
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]
fn test_error_downcasting_direct() {
#[derive(Debug, Fail)]
@ -1062,49 +1114,56 @@ mod tests {
#[test]
fn test_error_helpers() {
let r: HttpResponse = ErrorBadRequest("err").into();
let r: HttpResponse = ErrorBadRequest(FailMsg("err")).into();
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);
let r: HttpResponse = ErrorForbidden("err").into();
let r: HttpResponse = ErrorForbidden(FailMsg("err")).into();
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);
let r: HttpResponse = ErrorMethodNotAllowed("err").into();
let r: HttpResponse = ErrorMethodNotAllowed(FailMsg("err")).into();
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);
let r: HttpResponse = ErrorConflict("err").into();
let r: HttpResponse = ErrorConflict(FailMsg("err")).into();
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);
let r: HttpResponse = ErrorPreconditionFailed("err").into();
let r: HttpResponse = ErrorPreconditionFailed(FailMsg("err")).into();
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);
let r: HttpResponse = ErrorInternalServerError("err").into();
let r: HttpResponse = ErrorInternalServerError(FailMsg("err")).into();
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);
let r: HttpResponse = ErrorBadGateway("err").into();
let r: HttpResponse = ErrorBadGateway(FailMsg("err")).into();
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);
let r: HttpResponse = ErrorGatewayTimeout("err").into();
let r: HttpResponse = ErrorGatewayTimeout(FailMsg("err")).into();
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 de::PathDeserializer;
use error::{Error, ErrorBadRequest, ErrorNotFound, UrlencodedError};
use error::{Error, ErrorBadRequest, ErrorNotFound, FailMsg, UrlencodedError};
use handler::{AsyncResult, FromRequest};
use httpmessage::{HttpMessage, MessageBody, UrlEncoded};
use httprequest::HttpRequest;
@ -446,12 +446,13 @@ impl<S: 'static> FromRequest<S> for String {
let enc: *const Encoding = encoding as *const Encoding;
if enc == UTF_8 {
Ok(str::from_utf8(body.as_ref())
.map_err(|_| ErrorBadRequest("Can not decode body"))?
.to_owned())
.map_err(|_| {
ErrorBadRequest(FailMsg("Can not decode body"))
})?.to_owned())
} else {
Ok(encoding
.decode(&body, DecoderTrap::Strict)
.map_err(|_| ErrorBadRequest("Can not decode body"))?)
Ok(encoding.decode(&body, DecoderTrap::Strict).map_err(
|_| ErrorBadRequest(FailMsg("Can not decode body")),
)?)
}
}),
))
@ -469,7 +470,7 @@ impl<S: 'static> FromRequest<S> for String {
/// extern crate rand;
/// #[macro_use] extern crate serde_derive;
/// use actix_web::{http, App, Result, HttpRequest, Error, FromRequest};
/// use actix_web::error::ErrorBadRequest;
/// use actix_web::error::{ErrorBadRequest, FailMsg};
///
/// #[derive(Debug, Deserialize)]
/// struct Thing { name: String }
@ -483,7 +484,7 @@ impl<S: 'static> FromRequest<S> for String {
/// if rand::random() {
/// Ok(Thing { name: "thingy".into() })
/// } else {
/// Err(ErrorBadRequest("no luck"))
/// Err(ErrorBadRequest(FailMsg("no luck")))
/// }
///
/// }
@ -531,7 +532,7 @@ where
/// extern crate rand;
/// #[macro_use] extern crate serde_derive;
/// use actix_web::{http, App, Result, HttpRequest, Error, FromRequest};
/// use actix_web::error::ErrorBadRequest;
/// use actix_web::error::{ErrorBadRequest, FailMsg};
///
/// #[derive(Debug, Deserialize)]
/// struct Thing { name: String }
@ -545,7 +546,7 @@ where
/// if rand::random() {
/// Ok(Thing { name: "thingy".into() })
/// } else {
/// Err(ErrorBadRequest("no luck"))
/// Err(ErrorBadRequest(FailMsg("no luck")))
/// }
///
/// }
@ -604,11 +605,11 @@ impl PayloadConfig {
match req.mime_type() {
Ok(Some(ref req_mt)) => {
if mt != req_mt {
return Err(ErrorBadRequest("Unexpected Content-Type"));
return Err(ErrorBadRequest(FailMsg("Unexpected Content-Type")));
}
}
Ok(None) => {
return Err(ErrorBadRequest("Content-Type is expected"));
return Err(ErrorBadRequest(FailMsg("Content-Type is expected")));
}
Err(err) => {
return Err(err.into());

View file

@ -120,7 +120,9 @@ mod tests {
impl<S> Middleware<S> for MiddlewareOne {
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> {
if self.fut.alive() && self.fut.poll().is_err() {
return Err(ErrorInternalServerError("error"));
return Err(ErrorInternalServerError(::error::FailMsg("error")));
}
// frames

View file

@ -8,7 +8,7 @@ use std::sync::Arc;
use std::thread;
use std::time::{Duration, Instant};
use actix_web::error::{Error, ErrorInternalServerError};
use actix_web::error::{Error, ErrorInternalServerError, FailMsg};
use actix_web::*;
use futures::{future, Future};
use tokio_timer::Delay;
@ -332,7 +332,7 @@ fn test_scope_middleware_async_handler() {
}
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]
@ -794,7 +794,7 @@ struct MiddlewareWithErr;
impl<S> middleware::Middleware<S> for MiddlewareWithErr {
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 {
fn start(&self, _: &HttpRequest<S>) -> Result<middleware::Started, Error> {
Ok(middleware::Started::Future(Box::new(future::err(
ErrorInternalServerError("middleware error"),
ErrorInternalServerError(FailMsg("middleware error")),
))))
}
}