iron_error_router/
lib.rs

1// DOCS
2
3extern crate iron;
4
5use iron::prelude::*;
6use iron::modifier::Modifier;
7
8use std::collections::HashMap;
9use std::collections::hash_map;
10
11trait ModifierInner: Send + Sync {
12    fn clone_box(&self) -> Box<ModifierInner>;
13    fn apply_modify(self: Box<Self>, res: &mut Response);
14}
15
16impl<M: Modifier<Response> + Send + Sync + Clone + 'static> ModifierInner for M {
17    fn clone_box(&self) -> Box<ModifierInner> {
18        Box::new(self.clone())
19    }
20
21    fn apply_modify(self: Box<Self>, res: &mut Response) { self.modify(res) }
22}
23
24impl Modifier<Response> for Box<ModifierInner> {
25    fn modify(self, res: &mut Response) { self.apply_modify(res) }
26}
27
28enum Target {
29    AfterMiddleware(Box<iron::middleware::AfterMiddleware>),
30    Modifier(Box<ModifierInner>),
31    Handler(Box<iron::Handler>),
32}
33
34impl iron::middleware::AfterMiddleware for Target {
35    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
36        match *self {
37            Target::AfterMiddleware(ref x) => x.after(req, res),
38            Target::Modifier(ref x) => Ok(res.set(x.clone_box())),
39            Target::Handler(ref x) => x.handle(req)
40        }
41    }
42
43    fn catch(&self, req: &mut Request, mut err: IronError) -> IronResult<Response> {
44        match *self {
45            Target::AfterMiddleware(ref x) => x.catch(req, err),
46            Target::Modifier(ref x) => { err.response.set_mut(x.clone_box()); Err(err) },
47            Target::Handler(ref x) => x.handle(req)
48        }
49    }
50}
51
52pub struct ErrorRouter {
53    by_status: HashMap<iron::status::Status, Target>
54}
55
56impl Default for ErrorRouter {
57    fn default() -> ErrorRouter { ErrorRouter { by_status: HashMap::new() } }
58}
59
60impl ErrorRouter {
61    pub fn new() -> Self { ErrorRouter::default() }
62
63    fn register(&mut self, status: iron::status::Status, target: Target) {
64        match self.by_status.entry(status) {
65            hash_map::Entry::Occupied(_) => panic!("Target for {:?} already registered.", status),
66            hash_map::Entry::Vacant(x) => x.insert(target)
67        };
68    }
69
70    pub fn handle_status<T: iron::Handler>(&mut self, status: iron::status::Status, handler: T) {
71        self.register(status, Target::Handler(Box::new(handler)))
72    }
73
74    pub fn after_status<T: iron::middleware::AfterMiddleware>
75        (&mut self, status: iron::status::Status, middleware: T) {
76        self.register(status, Target::AfterMiddleware(Box::new(middleware)))
77    }
78
79    pub fn modifier_for_status<T: Modifier<Response> + Send + Sync + Clone + 'static>
80        (&mut self, status: iron::status::Status, modifier: T) {
81        self.register(status, Target::Modifier(Box::new(modifier)))
82    }
83}
84
85impl iron::middleware::AfterMiddleware for ErrorRouter {
86    fn after(&self, req: &mut Request, res: Response) -> IronResult<Response> {
87        match (res.body.is_some(), res.status.and_then(|s| self.by_status.get(&s))) {
88            (false, Some(x)) => x.after(req, res),
89            _ => Ok(res)
90        }
91    }
92
93    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<Response> {
94        match err.response.status.and_then(|s| self.by_status.get(&s)) {
95            Some(x) => x.catch(req, err),
96            None => Err(err)
97        }
98    }
99}