actix_rewrite/
rewrite.rs

1//! Utilities for Actix-Web Rewrite Actions
2
3use actix_http::{StatusCode, Uri};
4use actix_web::http::header;
5use actix_web::{HttpRequest, HttpResponse};
6use mod_rewrite::context::{EngineCtx, ServerCtx};
7
8use crate::Middleware;
9
10use super::error::Error;
11use super::util;
12
13/// Actix-Web compatible wrapper on [`Rewrite`](mod_rewrite::Rewrite)
14pub enum Rewrite {
15    Uri(Uri),
16    Redirect(HttpResponse),
17    Response(HttpResponse),
18}
19
20/// Actix-Web compatible wrapper on [`Engine`](mod_rewrite::Engine)
21pub struct Engine {
22    engine: mod_rewrite::Engine,
23    srv_ctx: ServerCtx,
24}
25
26impl Engine {
27    /// Creates a new [`Engine`](crate::Engine) instance.
28    ///
29    /// See [`mod_rewrite::Engine`](mod_rewrite::Engine) for more details.
30    pub fn new() -> Self {
31        Self {
32            engine: mod_rewrite::Engine::default(),
33            srv_ctx: ServerCtx::default(),
34        }
35    }
36
37    /// Configure max number of loops over entire ruleset during
38    /// rewrite before error.
39    ///
40    /// See [`mod_rewrite::Engine::max_iterations`](mod_rewrite::Engine::max_iterations)
41    /// for more details.
42    pub fn max_iterations(mut self, iterations: usize) -> Self {
43        self.engine = self.engine.max_iterations(iterations);
44        self
45    }
46
47    /// Pass a configured [`ServerCtx`](crate::ServerCtx) instance
48    /// to the engine to use when running [`Engine::rewrite`]
49    pub fn server_context(mut self, ctx: ServerCtx) -> Self {
50        self.srv_ctx = ctx;
51        self
52    }
53
54    /// Parses additonal rewrite expressions to append to the engine.
55    ///
56    /// See [`mod_rewrite::Engine::add_rules`](mod_rewrite::Engine::add_rules)
57    /// for more details.
58    pub fn add_rules(&mut self, rules: &str) -> Result<&mut Self, Error> {
59        self.engine.add_rules(rules)?;
60        Ok(self)
61    }
62
63    /// Evaluates the given [`HttpRequest`](actix_web::HttpRequest) against
64    /// the engine rules and returns a [`Rewrite`] response.
65    pub fn rewrite(&self, req: &HttpRequest) -> Result<Rewrite, Error> {
66        let mut ctx = EngineCtx::default()
67            .with_env()
68            .with_time()
69            .with_ctx(util::request_ctx(req))
70            .with_ctx(self.srv_ctx.clone());
71        Ok(
72            match self.engine.rewrite_ctx(&req.uri().to_string(), &mut ctx)? {
73                mod_rewrite::Rewrite::Uri(uri) => Rewrite::Uri(util::recode(uri)?),
74                mod_rewrite::Rewrite::EndUri(uri) => Rewrite::Uri(util::recode(uri)?),
75                mod_rewrite::Rewrite::Redirect(uri, sc) => Rewrite::Redirect(
76                    HttpResponse::build(StatusCode::from_u16(sc)?)
77                        .insert_header((header::LOCATION, uri))
78                        .body(""),
79                ),
80                mod_rewrite::Rewrite::StatusCode(sc) => {
81                    Rewrite::Response(HttpResponse::new(StatusCode::from_u16(sc)?))
82                }
83            },
84        )
85    }
86
87    /// Converts Engine Instance into Actix-Web Middleware
88    ///
89    /// # Examples
90    ///
91    /// ```
92    /// use actix_web::App;
93    /// use actix_rewrite::Engine;
94    ///
95    /// let mut engine = Engine::new();
96    /// engine.add_rules("RewriteEngine On\n").expect("Failed to add rules");
97    ///
98    /// let app = App::new()
99    ///     .wrap(engine.middleware());
100    /// ```
101    #[inline]
102    pub fn middleware(self) -> Middleware {
103        self.into()
104    }
105}
106
107impl Default for Engine {
108    fn default() -> Self {
109        Self::new()
110    }
111}