actix_modsecurity/
service.rs

1use std::ops::Deref;
2use std::rc::Rc;
3
4use actix_web::{
5    Error as ActixError,
6    body::BoxBody,
7    dev::{Service, ServiceRequest, ServiceResponse, forward_ready},
8};
9use futures_core::future::LocalBoxFuture;
10
11use crate::modsecurity::ModSecurity;
12
13/// Assembled LibModSecurity service
14#[derive(Clone)]
15pub struct ModSecurityService<S>(pub(crate) Rc<ModSecurityInner<S>>);
16
17impl<S> Deref for ModSecurityService<S> {
18    type Target = ModSecurityInner<S>;
19
20    fn deref(&self) -> &Self::Target {
21        &self.0
22    }
23}
24
25pub struct ModSecurityInner<S> {
26    pub(crate) service: Rc<S>,
27    pub(crate) modsecurity: Rc<ModSecurity>,
28}
29
30impl<S> Service<ServiceRequest> for ModSecurityService<S>
31where
32    S: Service<ServiceRequest, Response = ServiceResponse<BoxBody>, Error = ActixError> + 'static,
33    S::Future: 'static,
34{
35    type Response = ServiceResponse<BoxBody>;
36    type Error = ActixError;
37    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
38
39    forward_ready!(service);
40
41    fn call(&self, mut req: ServiceRequest) -> Self::Future {
42        let this = Rc::clone(&self.0);
43        Box::pin(async move {
44            let mut transaction = this.modsecurity.transaction()?;
45            transaction.process_request(&mut req).await?;
46
47            if let Some(intv) = transaction.intervention()? {
48                return Ok(req.into_response(intv));
49            }
50
51            let res = this.service.call(req).await?;
52
53            let (http_req, mut http_res) = res.into_parts();
54            http_res = transaction.process_response(http_res).await?;
55
56            match transaction.intervention()? {
57                Some(intv) => Ok(ServiceResponse::new(http_req, intv.into())),
58                None => Ok(ServiceResponse::new(http_req, http_res)),
59            }
60        })
61    }
62}