actix_rewrite/
service.rs

1use std::{ops::Deref, rc::Rc};
2
3use actix_web::{
4    body::BoxBody,
5    dev::{Path, Service, ServiceRequest, ServiceResponse, Url, forward_ready},
6    error::Error as ActixError,
7};
8use futures_core::future::LocalBoxFuture;
9
10use super::rewrite::{Engine, Rewrite};
11use super::util;
12
13/// Assembled `mod_rewrite` service
14#[derive(Clone)]
15pub struct RewriteService<S>(pub(crate) Rc<RewriteInner<S>>);
16
17impl<S> Deref for RewriteService<S> {
18    type Target = RewriteInner<S>;
19
20    fn deref(&self) -> &Self::Target {
21        &self.0
22    }
23}
24
25pub struct RewriteInner<S> {
26    pub(crate) service: Rc<S>,
27    pub(crate) engine: Rc<Engine>,
28}
29
30impl<S> Service<ServiceRequest> for RewriteService<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 after = match this.engine.rewrite(req.request())? {
45                Rewrite::Uri(uri) => uri,
46                Rewrite::Redirect(res) => return Ok(req.into_response(res)),
47                Rewrite::Response(res) => return Ok(req.into_response(res)),
48            };
49
50            let uri = util::join_uri(req.uri(), &after)?;
51            req.head_mut().uri = uri.clone();
52            *req.match_info_mut() = Path::new(Url::new(uri));
53
54            this.service.call(req).await
55        })
56    }
57}