immortal_http/
router.rs

1
2use std::collections::HashMap;
3
4use crate::context::Context;
5
6pub type Handler = fn(&mut Context);
7
8/// provides an API to register and lookup HTTP routes
9pub struct Router {
10    pub fallback: Handler,
11    routes: HashMap<String, HashMap<String, Handler>>,
12}
13
14fn not_implemented(ctx: &mut Context) {
15    eprintln!("ERROR: default fallback handler fired, you probably mean to replace this.");
16    ctx.response_mut().code = "501";
17    ctx.response_mut().body = b"<h1>501: Not Implemented</h1>".to_vec();
18}
19
20impl Default for Router {
21    fn default() -> Self {
22        Self::new()
23    }
24}
25
26impl Router {
27    /// Creates a new router
28    pub fn new() -> Self {
29        Self {
30            fallback: not_implemented,
31            routes: HashMap::new(),
32        }
33    }
34
35    /// register a path with a function callback
36    /// if a request document path matches the callback path, the callback is fired.
37    pub fn register(&mut self, method: &str, route: &str, func: Handler) -> bool {
38        if !self.routes.contains_key(method) {
39            self.routes.insert(method.to_string(), HashMap::new());
40        }
41        match self.routes.get_mut(method) {
42            None => return false,
43            Some(inner) => inner,
44        }.insert(route.to_string(), func);
45        true
46    }
47
48    /// removes a registered path
49    pub fn unregister(&mut self, method: &str, route: &str) -> bool {
50        match self.routes.get_mut(method) {
51            None => false,
52            Some(inner) => {
53                inner.remove(route).is_some()
54            },
55        }
56    }
57
58    /// tries to call a registered path
59    /// if it fails, the fallback is automatically called.
60    /// if response is already a redirect, don't call.
61    pub fn call(&self, ctx: &mut Context) {
62        let method = ctx.request().method;
63        let document = ctx.request().document;
64
65        if ctx.response().is_redirect() {
66            return;
67        }
68        let by_method = match self.routes.get(method) {
69            None => {
70                (self.fallback)(ctx);
71                return;
72            },
73            Some(inner) => inner,
74        };
75        let func = match by_method.get(document) {
76            None => {
77                (self.fallback)(ctx);
78                return;
79            },
80            Some(inner) => inner,
81        };
82        func(ctx);
83    }
84}
85