From 07dbd96fcf294b61a8d934d21645d973aa5b428a Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Sat, 23 Oct 2021 10:28:50 +0800 Subject: [PATCH] add boxed middleware --- src/middleware/boxed.rs | 91 +++++++++++++++++++++++++++++++++++++++++ src/middleware/mod.rs | 2 + 2 files changed, 93 insertions(+) create mode 100644 src/middleware/boxed.rs diff --git a/src/middleware/boxed.rs b/src/middleware/boxed.rs new file mode 100644 index 000000000..ecf43bfaa --- /dev/null +++ b/src/middleware/boxed.rs @@ -0,0 +1,91 @@ +//! For middleware documentation, see [`Boxed`]. + +use actix_service::{ + boxed::{self, BoxService}, + Service, Transform, +}; +use futures_core::future::LocalBoxFuture; + +/// Middleware for boxing another middleware's output. It would do type earse for the final middleware service +/// and reduce type complexity for potential faster compile time in exchange for extra overhead at runtime. +pub struct Boxed { + transform: T, +} + +impl Boxed { + /// Wrap a middleware to erase it's type signature and reduce type complexity. + pub fn new(middleware: T) -> Self { + Self { + transform: middleware, + } + } +} + +impl Transform for Boxed +where + S: Service + 'static, + T: Transform + 'static, + Req: 'static, +{ + type Response = T::Response; + type Error = T::Error; + type Transform = BoxedMiddleware; + type InitError = T::InitError; + type Future = LocalBoxFuture<'static, Result>; + + fn new_transform(&self, service: S) -> Self::Future { + let fut = self.transform.new_transform(service); + Box::pin(async move { + let service = fut.await?; + Ok(BoxedMiddleware { + service: boxed::service(service), + }) + }) + } +} + +pub struct BoxedMiddleware { + service: BoxService, +} + +impl Service for BoxedMiddleware { + type Response = Res; + type Error = Err; + type Future = LocalBoxFuture<'static, Result>; + + actix_service::forward_ready!(service); + + fn call(&self, req: Req) -> Self::Future { + self.service.call(req) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use actix_service::IntoService; + + use crate::dev::ServiceRequest; + use crate::http::StatusCode; + use crate::middleware::Logger; + use crate::test::{call_service, TestRequest}; + use crate::HttpResponse; + + #[actix_rt::test] + async fn test_boxed_logger_middleware() { + let srv = |req: ServiceRequest| { + Box::pin(async move { + Ok(req.into_response(HttpResponse::InternalServerError().finish())) + }) + }; + + let mw = Boxed::new(Logger::default()) + .new_transform(srv.into_service()) + .await + .unwrap(); + + let resp = call_service(&mw, TestRequest::default().to_srv_request()).await; + assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); + } +} diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs index d19cb64e9..d76905c1c 100644 --- a/src/middleware/mod.rs +++ b/src/middleware/mod.rs @@ -1,5 +1,6 @@ //! Commonly used middleware. +mod boxed; mod compat; mod condition; mod default_headers; @@ -7,6 +8,7 @@ mod err_handlers; mod logger; mod normalize; +pub use self::boxed::Boxed; pub use self::compat::Compat; pub use self::condition::Condition; pub use self::default_headers::DefaultHeaders;