simple_proxy/middlewares/
router.rs

1use http::uri::{Parts, Uri};
2use hyper::header::HeaderValue;
3use hyper::{Body, Request, StatusCode};
4use regex::Regex;
5
6use crate::proxy::error::MiddlewareError;
7use crate::proxy::middleware::MiddlewareResult::Next;
8use crate::proxy::middleware::{Middleware, MiddlewareResult};
9use crate::proxy::service::{ServiceContext, State};
10
11use serde_json;
12
13#[derive(Clone)]
14pub struct Router {
15    routes: RouterRules,
16    name: String,
17}
18
19#[derive(Debug, Clone, Deserialize)]
20pub struct RouteRegex {
21    #[serde(with = "serde_regex")]
22    pub host: Regex,
23    #[serde(with = "serde_regex")]
24    pub path: Regex,
25}
26
27#[derive(Debug, Clone, Deserialize)]
28pub struct Route {
29    pub from: RouteRegex,
30    pub to: RouteRegex,
31    pub public: bool,
32}
33
34#[derive(Debug, Clone, Deserialize)]
35pub struct RouterRulesWrapper {
36    pub rules: RouterRules,
37}
38
39pub type RouterRules = Vec<Route>;
40
41#[derive(Serialize, Deserialize, Debug)]
42pub struct MatchedRoute {
43    pub uri: String,
44    pub public: bool,
45}
46
47pub trait RouterConfig {
48    fn get_router_filename(&self) -> &str;
49}
50
51fn get_host_and_path(req: &mut Request<Body>) -> Result<(String, String), MiddlewareError> {
52    let uri = req.uri();
53    let path = uri
54        .path_and_query()
55        .map(ToString::to_string)
56        .unwrap_or_else(|| String::from(""));
57
58    match uri.host() {
59        Some(host) => Ok((String::from(host), path)),
60        None => Ok((
61            String::from(req.headers().get("host").unwrap().to_str()?),
62            path,
63        )),
64    }
65}
66
67fn inject_new_uri(
68    req: &mut Request<Body>,
69    old_host: &str,
70    host: &str,
71    path: &str,
72) -> Result<(), MiddlewareError> {
73    {
74        let headers = req.headers_mut();
75
76        headers.insert("X-Forwarded-Host", HeaderValue::from_str(old_host).unwrap());
77        headers.insert("host", HeaderValue::from_str(host).unwrap());
78    }
79    let mut parts = Parts::default();
80    parts.scheme = Some("http".parse()?);
81    parts.authority = Some(host.parse()?);
82    parts.path_and_query = Some(path.parse()?);
83
84    debug!("Found a route to {:?}", parts);
85
86    *req.uri_mut() = Uri::from_parts(parts)?;
87
88    Ok(())
89}
90
91impl Middleware for Router {
92    fn name() -> String {
93        String::from("Router")
94    }
95
96    fn before_request(
97        &mut self,
98        req: &mut Request<Body>,
99        context: &ServiceContext,
100        state: &State,
101    ) -> Result<MiddlewareResult, MiddlewareError> {
102        let routes = &self.routes;
103
104        let (host, path) = get_host_and_path(req)?;
105        debug!("Routing => Host: {} Path: {}", host, path);
106
107        for route in routes {
108            let (re_host, re_path) = (&route.from.host, &route.from.path);
109            let to = &route.to;
110            let public = route.public;
111
112            debug!("Trying to convert from {} / {:?}", &re_host, &re_path);
113
114            if re_host.is_match(&host) {
115                let new_host = re_host.replace(&host, to.host.as_str());
116
117                let new_path = if re_path.is_match(&path) {
118                    re_path.replace(&path, to.path.as_str())
119                } else {
120                    continue;
121                };
122
123                debug!("Proxying to {}", &new_host);
124                inject_new_uri(req, &host, &new_host, &new_path)?;
125                self.set_state(
126                    context.req_id,
127                    state,
128                    serde_json::to_string(&MatchedRoute {
129                        uri: req.uri().to_string(),
130                        public,
131                    })?,
132                )?;
133                return Ok(Next);
134            }
135        }
136
137        Err(MiddlewareError::new(
138            String::from("No route matched"),
139            Some(String::from("Not found")),
140            StatusCode::NOT_FOUND,
141        ))
142    }
143}
144
145fn read_routes<T: RouterConfig>(config: &T) -> RouterRules {
146    use std::fs::File;
147    use std::io::prelude::Read;
148
149    let mut f = File::open(config.get_router_filename()).expect("Router config not found !");
150
151    let mut data = String::new();
152    f.read_to_string(&mut data)
153        .expect("Cannot read Router config !");
154
155    let rules: RouterRulesWrapper =
156        serde_json::from_str(&data).expect("Cannot parse Router config file !");
157
158    rules.rules
159}
160
161impl Router {
162    pub fn new<T: RouterConfig>(config: &T) -> Self {
163        Router {
164            routes: read_routes(config),
165            name: String::from("Router"),
166        }
167    }
168}