2021-06-24 14:11:01 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2021-06-22 21:22:33 +00:00
|
|
|
use actix_utils::future::{ok, Ready};
|
2021-06-24 14:11:01 +00:00
|
|
|
use actix_web::{
|
|
|
|
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
|
|
|
|
get,
|
|
|
|
test::{call_service, init_service, TestRequest},
|
|
|
|
ResponseError,
|
|
|
|
};
|
|
|
|
use futures_core::future::LocalBoxFuture;
|
2021-06-22 21:22:33 +00:00
|
|
|
use futures_util::lock::Mutex;
|
|
|
|
|
|
|
|
#[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")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-24 14:11:01 +00:00
|
|
|
#[get("/test")]
|
2021-06-22 21:22:33 +00:00
|
|
|
async fn test() -> Result<actix_web::HttpResponse, actix_web::error::Error> {
|
2021-07-12 15:55:24 +00:00
|
|
|
Err(MyError.into())
|
2021-06-22 21:22:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[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;
|
2021-06-24 14:11:01 +00:00
|
|
|
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
|
2021-06-22 21:22:33 +00:00
|
|
|
|
2021-06-24 14:11:01 +00:00
|
|
|
forward_ready!(service);
|
2021-06-22 21:22:33 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|