forked from actix/actix-web
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Propagate error cause to middlewares (actix#2280)
- Loading branch information
Luca Palmieri
authored
Jun 22, 2021
1 parent
b1148fd
commit 3b6333e
Showing
2 changed files
with
104 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
use actix_utils::future::{ok, Ready}; | ||
use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform}; | ||
use actix_web::test::{call_service, init_service, TestRequest}; | ||
use actix_web::{HttpResponse, ResponseError}; | ||
use futures_util::lock::Mutex; | ||
use std::future::Future; | ||
use std::pin::Pin; | ||
use std::sync::Arc; | ||
use std::task::{Context, Poll}; | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct MyError; | ||
|
||
impl ResponseError for MyError {} | ||
|
||
impl std::fmt::Display for MyError { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
write!(f, "A custom error") | ||
} | ||
} | ||
|
||
#[actix_web::get("/test")] | ||
async fn test() -> Result<actix_web::HttpResponse, actix_web::error::Error> { | ||
Err(MyError)?; | ||
Ok(HttpResponse::NoContent().finish()) | ||
} | ||
|
||
#[derive(Clone)] | ||
pub struct SpyMiddleware(Arc<Mutex<Option<bool>>>); | ||
|
||
impl<S, B> Transform<S, ServiceRequest> for SpyMiddleware | ||
where | ||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = actix_web::Error>, | ||
S::Future: 'static, | ||
B: 'static, | ||
{ | ||
type Response = ServiceResponse<B>; | ||
type Error = actix_web::Error; | ||
type Transform = Middleware<S>; | ||
type InitError = (); | ||
type Future = Ready<Result<Self::Transform, Self::InitError>>; | ||
|
||
fn new_transform(&self, service: S) -> Self::Future { | ||
ok(Middleware { | ||
was_error: self.0.clone(), | ||
service, | ||
}) | ||
} | ||
} | ||
|
||
#[doc(hidden)] | ||
pub struct Middleware<S> { | ||
was_error: Arc<Mutex<Option<bool>>>, | ||
service: S, | ||
} | ||
|
||
impl<S, B> Service<ServiceRequest> for Middleware<S> | ||
where | ||
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = actix_web::Error>, | ||
S::Future: 'static, | ||
B: 'static, | ||
{ | ||
type Response = ServiceResponse<B>; | ||
type Error = actix_web::Error; | ||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>; | ||
|
||
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { | ||
self.service.poll_ready(cx) | ||
} | ||
|
||
fn call(&self, req: ServiceRequest) -> Self::Future { | ||
let lock = self.was_error.clone(); | ||
let response_future = self.service.call(req); | ||
Box::pin(async move { | ||
let response = response_future.await; | ||
if let Ok(success) = &response { | ||
*lock.lock().await = Some(success.response().error().is_some()); | ||
} | ||
response | ||
}) | ||
} | ||
} | ||
|
||
#[actix_rt::test] | ||
async fn error_cause_should_be_propagated_to_middlewares() { | ||
let lock = Arc::new(Mutex::new(None)); | ||
let spy_middleware = SpyMiddleware(lock.clone()); | ||
|
||
let app = init_service( | ||
actix_web::App::new() | ||
.wrap(spy_middleware.clone()) | ||
.service(test), | ||
) | ||
.await; | ||
|
||
call_service(&app, TestRequest::with_uri("/test").to_request()).await; | ||
|
||
let was_error_captured = lock.lock().await.unwrap(); | ||
assert!(was_error_captured); | ||
} |