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}