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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
use crate::helpers;
use crate::middleware::{PostMiddleware, PreMiddleware};
use crate::prelude::*;
use crate::route::Route;
use hyper::{body::HttpBody, Request, Response};
use regex::RegexSet;
use std::fmt::{self, Debug, Formatter};
use std::future::Future;
use std::pin::Pin;
pub use self::builder::RouterBuilder;
mod builder;
pub(crate) type ErrHandler<B> = Box<dyn FnMut(crate::Error) -> ErrHandlerReturn<B> + Send + Sync + 'static>;
pub(crate) type ErrHandlerReturn<B> = Box<dyn Future<Output = Response<B>> + Send + 'static>;
pub struct Router<B, E> {
pub(crate) pre_middlewares: Vec<PreMiddleware<E>>,
pub(crate) routes: Vec<Route<B, E>>,
pub(crate) post_middlewares: Vec<PostMiddleware<B, E>>,
pub(crate) err_handler: Option<ErrHandler<B>>,
regex_set: Option<RegexSet>,
}
impl<B: HttpBody + Send + Sync + Unpin + 'static, E: std::error::Error + Send + Sync + Unpin + 'static> Router<B, E> {
pub(crate) fn new(
pre_middlewares: Vec<PreMiddleware<E>>,
routes: Vec<Route<B, E>>,
post_middlewares: Vec<PostMiddleware<B, E>>,
err_handler: Option<ErrHandler<B>>,
) -> Self {
Router {
pre_middlewares,
routes,
post_middlewares,
err_handler,
regex_set: None,
}
}
pub(crate) fn init_regex_set(&mut self) -> crate::Result<()> {
let regex_iter = self
.pre_middlewares
.iter()
.map(|m| m.regex.as_str())
.chain(self.routes.iter().map(|r| r.regex.as_str()))
.chain(self.post_middlewares.iter().map(|m| m.regex.as_str()));
self.regex_set = Some(RegexSet::new(regex_iter).context("Couldn't create router RegexSet")?);
Ok(())
}
pub fn builder() -> RouterBuilder<B, E> {
builder::RouterBuilder::new()
}
pub(crate) async fn process(&mut self, req: Request<hyper::Body>) -> crate::Result<Response<B>> {
let target_path =
helpers::percent_decode_request_path(req.uri().path()).context("Couldn't percent decode request path")?;
let (matched_pre_middleware_idxs, matched_route_idxs, matched_post_middleware_idxs) =
self.match_regex_set(target_path.as_str());
let mut transformed_req = req;
for idx in matched_pre_middleware_idxs {
let pre_middleware = &mut self.pre_middlewares[idx];
transformed_req = pre_middleware
.process(transformed_req)
.await
.context("One of the pre middlewares couldn't process the request")?;
}
let mut resp: Option<Response<B>> = None;
for idx in matched_route_idxs {
let route = &mut self.routes[idx];
if route.is_match_method(transformed_req.method()) {
let route_resp_res = route
.process(target_path.as_str(), transformed_req)
.await
.context("One of the routes couldn't process the request");
let route_resp = match route_resp_res {
Ok(route_resp) => route_resp,
Err(err) => {
if let Some(ref mut err_handler) = self.err_handler {
Pin::from(err_handler(err)).await
} else {
return crate::Result::Err(err);
}
}
};
resp = Some(route_resp);
break;
}
}
if let None = resp {
return Err(crate::Error::new("No handlers added to handle non-existent routes. Tips: Please add an '.any' route at the bottom to handle any routes."));
}
let mut transformed_res = resp.unwrap();
for idx in matched_post_middleware_idxs {
let post_middleware = &mut self.post_middlewares[idx];
transformed_res = post_middleware
.process(transformed_res)
.await
.context("One of the post middlewares couldn't process the response")?;
}
Ok(transformed_res)
}
fn match_regex_set(&self, target_path: &str) -> (Vec<usize>, Vec<usize>, Vec<usize>) {
let matches = self
.regex_set
.as_ref()
.expect("The 'regex_set' field in Router is not initialized")
.matches(target_path)
.into_iter();
let pre_middlewares_len = self.pre_middlewares.len();
let routes_len = self.routes.len();
let post_middlewares_len = self.post_middlewares.len();
let mut matched_pre_middleware_idxs = Vec::new();
let mut matched_route_idxs = Vec::new();
let mut matched_post_middleware_idxs = Vec::new();
for idx in matches {
if idx < pre_middlewares_len {
matched_pre_middleware_idxs.push(idx);
} else if idx >= pre_middlewares_len && idx < (pre_middlewares_len + routes_len) {
matched_route_idxs.push(idx - pre_middlewares_len);
} else if idx >= (pre_middlewares_len + routes_len)
&& idx < (pre_middlewares_len + routes_len + post_middlewares_len)
{
matched_post_middleware_idxs.push(idx - pre_middlewares_len - routes_len);
}
}
(
matched_pre_middleware_idxs,
matched_route_idxs,
matched_post_middleware_idxs,
)
}
}
impl<B, E> Debug for Router<B, E> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{{ Pre-Middlewares: {:?}, Routes: {:?}, Post-Middlewares: {:?}, ErrHandler: {:?} }}",
self.pre_middlewares,
self.routes,
self.post_middlewares,
self.err_handler.is_some()
)
}
}