1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use http::*;
use utils::ToRegex;
use utils::RequestContinuation;
use utils::RequestContinuation::*;
use regex::Regex;
use std::sync::RwLock;

pub struct MiddlewareStack {
    middlewares: RwLock<Vec<(MiddlewareRule, Box<Middleware>)>>
}

impl MiddlewareStack {
    pub fn new() -> Self {
        MiddlewareStack {
            middlewares: RwLock::new(Vec::new()),
        }
    }

    pub fn resolve(&self, req: &SyncRequest, res: &mut Response<Body>) -> RequestContinuation {
        let path = req.path();

        for &(ref rule, ref middleware) in self.middlewares.read().unwrap().iter() {
            if rule.validate_path(path) {
                if let None = middleware.resolve(req, res) {
                    return None;
                }
            }
        }

        Next
    }

    pub fn apply<M: 'static + Middleware>(&mut self, m: M, include_path: Vec<&str>, exclude_path: Option<Vec<&str>>) {
        let rule = MiddlewareRule::new(include_path, exclude_path);
        let boxed_m = Box::new(m);

        self.middlewares.write().unwrap().push((rule, boxed_m))
    }
}

pub trait Middleware: Send + Sync {
    fn resolve(&self, req: &SyncRequest, res: &mut Response<Body>) -> RequestContinuation;
}

struct MiddlewareRule {
    included_path: Vec<Regex>,
    excluded_path: Option<Vec<Regex>>,
}

impl MiddlewareRule {
    pub fn new<R: ToRegex>(include_path: Vec<R>, exclude_path: Option<Vec<R>>) -> Self {
        let mut included_path = Vec::new();
        for include in include_path.iter() {
            included_path.push(reg!(include));
        }

        let mut excluded_path : Option<Vec<Regex>> = Option::None;

        if let Some(excludes) = exclude_path {
            let mut excludes_vec = Vec::new();
            for exclude in excludes.iter() {
                excludes_vec.push(reg!(exclude));
            }

            excluded_path = Some(excludes_vec);
        }

        MiddlewareRule {
            included_path,
            excluded_path,
        }
    }

    pub fn validate_path(&self, path: &str) -> bool {
        let path_clone = path.clone();
        if self.included_path.iter().enumerate().find(
            move | &(_index, r) | {
                r.is_match(path_clone)
            }
        ).is_some() {

            if let Some(ref excluded_path) = self.excluded_path {
                return excluded_path.iter().enumerate().find(
                    move | &(_index, re) | {
                        re.is_match(path_clone)
                    }
                ).is_none()
            } else {
                return true;
            }
        }

        false
    }
}