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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use http::*;
use utils::ToRegex;
use utils::RequestContinuation;
use utils::RequestContinuation::*;
use regex::Regex;
use parking_lot::RwLock;
use std::sync::Arc;
pub struct MiddlewareStack {
middlewares: Arc<RwLock<Vec<(MiddlewareRule, Box<Middleware>)>>>
}
impl MiddlewareStack {
pub fn new() -> Self {
MiddlewareStack {
middlewares: Arc::new(RwLock::new(Vec::new())),
}
}
pub fn resolve(&self, req: &SyncRequest, res: &mut SyncResponse) -> RequestContinuation {
let path = req.uri().path();
for &(ref rule, ref middleware) in self.middlewares.read().iter() {
if rule.validate_path(path) {
if let None = middleware.resolve(req, res) {
return None;
}
}
}
Next
}
pub fn apply<M: 'static + Middleware>(&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().push((rule, boxed_m))
}
}
impl Clone for MiddlewareStack {
fn clone(&self) -> Self {
MiddlewareStack {
middlewares: self.middlewares.clone(),
}
}
}
pub trait Middleware: Send + Sync {
fn resolve(&self, req: &SyncRequest, res: &mut SyncResponse) -> 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
}
}