Skip to main content

obsidian/
router.rs

1mod handler;
2mod req_deserializer;
3mod resource;
4mod responder;
5mod response;
6mod response_body;
7mod route;
8mod route_trie;
9
10use self::route_trie::RouteTrie;
11use crate::context::Context;
12use crate::middleware::Middleware;
13use crate::Method;
14pub use hyper::header;
15
16pub use self::handler::{ContextResult, Handler};
17pub use self::req_deserializer::{from_cow_map, Error as FormError};
18pub use self::resource::Resource;
19pub use self::responder::Responder;
20pub use self::response::Response;
21pub use self::response_body::ResponseBody;
22pub use self::route::Route;
23
24pub(crate) use self::route_trie::RouteValueResult;
25
26pub struct Router {
27    routes: RouteTrie,
28}
29
30impl Clone for Router {
31    fn clone(&self) -> Self {
32        Router {
33            routes: self.routes.clone(),
34        }
35    }
36}
37
38impl Default for Router {
39    fn default() -> Self {
40        Self::new()
41    }
42}
43
44impl Router {
45    pub fn new() -> Self {
46        Router {
47            routes: RouteTrie::new(),
48        }
49    }
50
51    pub fn get(&mut self, path: &str, handler: impl Handler) {
52        self.insert_route(Method::GET, path, handler);
53    }
54
55    pub fn post(&mut self, path: &str, handler: impl Handler) {
56        self.insert_route(Method::POST, path, handler);
57    }
58
59    pub fn put(&mut self, path: &str, handler: impl Handler) {
60        self.insert_route(Method::PUT, path, handler);
61    }
62
63    pub fn patch(&mut self, path: &str, handler: impl Handler) {
64        self.insert_route(Method::PATCH, path, handler);
65    }
66
67    pub fn delete(&mut self, path: &str, handler: impl Handler) {
68        self.insert_route(Method::DELETE, path, handler);
69    }
70
71    /// Apply middleware in the provided route
72    pub fn use_service_to(&mut self, path: &str, middleware: impl Middleware) {
73        self.routes.insert_middleware(path, middleware);
74    }
75
76    /// Apply middleware in current relative route
77    pub fn use_service(&mut self, middleware: impl Middleware) {
78        self.routes.insert_default_middleware(middleware);
79    }
80
81    /// Serve static files by the virtual path as the route and directory path as the server file path
82    pub fn use_static_to(&mut self, virtual_path: &str, dir_path: &str) {
83        let mut path = String::from(virtual_path);
84        path.push_str("/*");
85
86        self.get(
87            &path,
88            Self::static_virtual_file_handler(virtual_path, dir_path),
89        );
90    }
91
92    /// Serve static files by the directory path as the route and server file path
93    pub fn use_static(&mut self, dir_path: &str) {
94        let mut path = String::from(dir_path);
95        path.push_str("/*");
96
97        self.get(&path, Self::static_dir_file_handler);
98    }
99
100    /// Apply route handler in current relative route
101    pub fn use_router(&mut self, path: &str, other: Router) {
102        RouteTrie::insert_sub_route(&mut self.routes, path, other.routes);
103    }
104
105    pub fn search_route(&self, path: &str) -> Option<RouteValueResult> {
106        self.routes.search_route(path)
107    }
108
109    fn insert_route(&mut self, method: Method, path: &str, handler: impl Handler) {
110        let route = Route::new(method, handler);
111
112        self.routes.insert_route(path, route);
113    }
114
115    fn static_virtual_file_handler(virtual_path: &str, dir_path: &str) -> impl Handler {
116        let dir_path = dir_path
117            .split('/')
118            .filter(|key| !key.is_empty())
119            .map(|x| x.to_string())
120            .collect::<Vec<String>>();
121
122        let virtual_path_len = virtual_path
123            .split('/')
124            .filter(|key| !key.is_empty())
125            .count();
126
127        move |ctx: Context| {
128            let mut dir_path = dir_path.clone();
129            let mut relative_path = ctx
130                .uri()
131                .path()
132                .split('/')
133                .filter(|key| !key.is_empty())
134                .skip(virtual_path_len)
135                .map(|x| x.to_string())
136                .collect::<Vec<String>>();
137
138            dir_path.append(&mut relative_path);
139
140            Box::pin(async move {
141                ctx.build(Response::ok().file(&dir_path.join("/")).await)
142                    .ok()
143            })
144        }
145    }
146
147    async fn static_dir_file_handler(ctx: Context) -> ContextResult {
148        let relative_path = ctx
149            .uri()
150            .path()
151            .split('/')
152            .filter(|key| !key.is_empty())
153            .map(|x| x.to_string())
154            .collect::<Vec<String>>();
155
156        ctx.build(Response::ok().file(&relative_path.join("/")).await)
157            .ok()
158    }
159}
160
161#[cfg(test)]
162mod tests {
163    use super::*;
164    use crate::context::Context;
165    use crate::middleware::logger::Logger;
166
167    async fn handler(ctx: Context) -> ContextResult {
168        ctx.build("test").ok()
169    }
170
171    #[test]
172    fn router_get_test() {
173        let mut router = Router::new();
174
175        router.get("router/test", handler);
176
177        let result = router.search_route("router/test");
178        let fail_result = router.search_route("failed");
179
180        assert!(result.is_some());
181        assert!(fail_result.is_none());
182
183        match result {
184            Some(route) => {
185                let middlewares = route.get_middlewares();
186                let route_value = route.get_route(&Method::GET).unwrap();
187
188                assert_eq!(middlewares.len(), 0);
189                assert_eq!(route_value.method, Method::GET);
190            }
191            _ => panic!(),
192        }
193    }
194
195    #[test]
196    fn router_post_test() {
197        let mut router = Router::new();
198
199        router.post("router/test", handler);
200
201        let result = router.search_route("router/test");
202        let fail_result = router.search_route("failed");
203
204        assert!(result.is_some());
205        assert!(fail_result.is_none());
206
207        match result {
208            Some(route) => {
209                let middlewares = route.get_middlewares();
210                let route_value = route.get_route(&Method::POST).unwrap();
211
212                assert_eq!(middlewares.len(), 0);
213                assert_eq!(route_value.method, Method::POST);
214            }
215            _ => panic!(),
216        }
217    }
218
219    #[test]
220    fn router_put_test() {
221        let mut router = Router::new();
222
223        router.put("router/test", handler);
224
225        let result = router.search_route("router/test");
226        let fail_result = router.search_route("failed");
227
228        assert!(result.is_some());
229        assert!(fail_result.is_none());
230
231        match result {
232            Some(route) => {
233                let middlewares = route.get_middlewares();
234                let route_value = route.get_route(&Method::PUT).unwrap();
235
236                assert_eq!(middlewares.len(), 0);
237                assert_eq!(route_value.method, Method::PUT);
238            }
239            _ => panic!(),
240        }
241    }
242
243    #[test]
244    fn router_delete_test() {
245        let mut router = Router::new();
246
247        router.delete("router/test", handler);
248
249        let result = router.search_route("router/test");
250        let fail_result = router.search_route("failed");
251
252        assert!(result.is_some());
253        assert!(fail_result.is_none());
254
255        match result {
256            Some(route) => {
257                let middlewares = route.get_middlewares();
258                let route_value = route.get_route(&Method::DELETE).unwrap();
259
260                assert_eq!(middlewares.len(), 0);
261                assert_eq!(route_value.method, Method::DELETE);
262            }
263            _ => panic!(),
264        }
265    }
266
267    #[test]
268    fn router_root_middleware_test() {
269        let mut router = Router::new();
270        let logger = Logger::new();
271
272        router.use_service(logger);
273
274        let result = router.search_route("/");
275        let fail_result = router.search_route("failed");
276
277        assert!(result.is_some());
278        assert!(fail_result.is_none());
279
280        match result {
281            Some(route) => {
282                let middlewares = route.get_middlewares();
283
284                assert_eq!(middlewares.len(), 1);
285            }
286            _ => panic!(),
287        }
288    }
289
290    #[test]
291    fn router_relative_middleware_test() {
292        let mut router = Router::new();
293        let logger = Logger::new();
294
295        router.use_service_to("middleware/child", logger);
296
297        let result = router.search_route("/middleware/child");
298        let fail_result = router.search_route("/");
299
300        assert!(result.is_some());
301        assert!(fail_result.is_none());
302
303        match result {
304            Some(route) => {
305                let middlewares = route.get_middlewares();
306
307                assert_eq!(middlewares.len(), 1);
308            }
309            _ => panic!(),
310        }
311    }
312
313    #[test]
314    fn router_search_test() {
315        let mut router = Router::new();
316
317        router.get("router/test", handler);
318        router.post("router/test", handler);
319        router.put("router/test", handler);
320        router.delete("router/test", handler);
321
322        router.get("route/diff_route", handler);
323
324        let result = router.search_route("router/test");
325        let diff_result = router.search_route("route/diff_route");
326        let fail_result = router.search_route("failed");
327
328        assert!(result.is_some());
329        assert!(diff_result.is_some());
330        assert!(fail_result.is_none());
331
332        match result {
333            Some(route) => {
334                let middlewares = route.get_middlewares();
335                let route_value = route.get_route(&Method::GET).unwrap();
336
337                assert_eq!(middlewares.len(), 0);
338                assert_eq!(route_value.method, Method::GET);
339
340                let route_value = route.get_route(&Method::POST).unwrap();
341
342                assert_eq!(middlewares.len(), 0);
343                assert_eq!(route_value.method, Method::POST);
344
345                let route_value = route.get_route(&Method::PUT).unwrap();
346
347                assert_eq!(middlewares.len(), 0);
348                assert_eq!(route_value.method, Method::PUT);
349
350                let route_value = route.get_route(&Method::DELETE).unwrap();
351
352                assert_eq!(middlewares.len(), 0);
353                assert_eq!(route_value.method, Method::DELETE);
354            }
355            _ => panic!(),
356        }
357
358        match diff_result {
359            Some(route) => {
360                let middlewares = route.get_middlewares();
361                let route_value = route.get_route(&Method::GET).unwrap();
362
363                assert_eq!(middlewares.len(), 0);
364                assert_eq!(route_value.method, Method::GET);
365            }
366            _ => panic!(),
367        }
368    }
369
370    #[test]
371    fn router_merge_test() {
372        let mut main_router = Router::new();
373        let mut sub_router = Router::new();
374
375        main_router.get("router/test", handler);
376        sub_router.get("router/test", handler);
377
378        let logger = Logger::new();
379
380        sub_router.use_service(logger);
381
382        main_router.use_router("sub_router", sub_router);
383
384        let result = main_router.search_route("router/test");
385        let sub_result = main_router.search_route("sub_router/router/test");
386        let fail_result = main_router.search_route("failed");
387
388        assert!(result.is_some());
389        assert!(sub_result.is_some());
390        assert!(fail_result.is_none());
391
392        match result {
393            Some(route) => {
394                let middlewares = route.get_middlewares();
395                let route_value = route.get_route(&Method::GET).unwrap();
396
397                assert_eq!(middlewares.len(), 0);
398                assert_eq!(route_value.method, Method::GET);
399            }
400            _ => panic!(),
401        }
402
403        match sub_result {
404            Some(route) => {
405                let middlewares = route.get_middlewares();
406                let route_value = route.get_route(&Method::GET).unwrap();
407
408                assert_eq!(middlewares.len(), 1);
409                assert_eq!(route_value.method, Method::GET);
410            }
411            _ => panic!(),
412        }
413    }
414
415    #[should_panic]
416    #[test]
417    fn router_duplicate_path_test() {
418        let mut router = Router::new();
419
420        router.get("router/test", handler);
421        router.get("router/test", handler);
422    }
423
424    #[should_panic]
425    #[test]
426    fn router_ambiguous_path_test() {
427        let mut router = Router::new();
428
429        router.get("router/:test", handler);
430        router.get("router/test", handler);
431    }
432
433    #[should_panic]
434    #[test]
435    fn router_duplicate_merge_test() {
436        let mut main_router = Router::new();
437        let mut sub_router = Router::new();
438
439        main_router.get("sub_router/test", handler);
440        sub_router.get("test", handler);
441
442        let logger = Logger::new();
443
444        sub_router.use_service(logger);
445
446        main_router.use_router("sub_router", sub_router);
447    }
448}