-
-
Save reem/f13f0254f4eeced42b28 to your computer and use it in GitHub Desktop.
#![license = "MIT"] | |
extern crate error; | |
use std::sync::Arc; | |
use error::Error; | |
pub type IronResult<T> = Result<T, Box<Error>>; | |
pub struct Request; | |
pub struct Response; | |
#[deriving(Clone)] | |
struct IronListener { | |
handler: Arc<Box<Handler + Send + Sync>> | |
} | |
pub trait Handler: Send + Sync { | |
fn call(&self, &mut Request) -> IronResult<Response>; | |
fn catch(&self, &mut Request, Box<Error>) -> (Response, IronResult<()>); | |
} | |
impl Handler for fn(&mut Request) -> IronResult<Response> { | |
fn call(&self, req: &mut Request) -> IronResult<Response> { | |
self.call(req) | |
} | |
fn catch(&self, _: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) { | |
(Response, Err(err)) | |
} | |
} | |
pub trait BeforeMiddleware: Send + Sync { | |
fn before(&self, &mut Request) -> IronResult<()>; | |
fn catch(&self, _: &mut Request, err: Box<Error>) -> IronResult<()> { | |
Err(err) | |
} | |
} | |
pub trait AfterMiddleware: Send + Sync { | |
fn after(&self, &mut Request, &mut Response) -> IronResult<()>; | |
// This response was generated by the `catch` function of Handlers and is abnormal in some way. | |
fn catch(&self, _: &mut Request, _: &mut Response, err: Box<Error>) -> IronResult<()> { | |
Err(err) | |
} | |
} | |
pub trait AroundMiddleware: Handler { | |
fn with_handler(&mut self, handler: Box<Handler + Send + Sync>); | |
} | |
pub trait Chain: Handler { | |
fn new<H: Handler>(H) -> Self; | |
} | |
pub struct StackChain { | |
befores: Vec<Box<BeforeMiddleware + Send + Sync>>, | |
afters: Vec<Box<AfterMiddleware + Send + Sync>>, | |
handler: Box<Handler + Send + Sync> | |
} | |
impl Handler for StackChain { | |
fn call(&self, req: &mut Request) -> IronResult<Response> { | |
let before_result = run_befores(req, self.befores.as_slice(), None); | |
let (res, err) = match before_result { | |
Ok(()) => match self.handler.call(req) { | |
Ok(res) => (res, None), | |
Err(e) => run_handler_catch(req, e, &self.handler) | |
}, | |
Err(e) => run_handler_catch(req, e, &self.handler) | |
}; | |
run_afters(req, res, err, self.afters.as_slice()) | |
} | |
fn catch(&self, req: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) { | |
let before_result = run_befores(req, self.befores.as_slice(), Some(err)); | |
let (res, err) = match before_result { | |
Ok(()) => match self.handler.call(req) { | |
Ok(res) => (res, None), | |
Err(e) => run_handler_catch(req, e, &self.handler) | |
}, | |
Err(e) => run_handler_catch(req, e, &self.handler) | |
}; | |
match run_afters(req, res, err, self.afters.as_slice()) { | |
Ok(res) => (res, Ok(())), | |
Err(err) => (Response, Err(err)) | |
} | |
} | |
} | |
impl Chain for StackChain { | |
fn new<H: Handler>(handler: H) -> StackChain { | |
StackChain { | |
befores: vec![], | |
afters: vec![], | |
handler: box handler as Box<Handler + Send + Sync> | |
} | |
} | |
} | |
fn run_befores(req: &mut Request, befores: &[Box<BeforeMiddleware>], err: Option<Box<Error>>) -> IronResult<()> { | |
match err { | |
Some(mut e) => { | |
for (i, before) in befores.iter().enumerate() { | |
match before.catch(req, e) { | |
Ok(_) => return run_befores(req, befores, None), | |
Err(new) => e = new | |
} | |
} | |
Err(e) | |
}, | |
None => { | |
for (i, before) in befores.iter().enumerate() { | |
match before.before(req) { | |
Ok(_) => (), | |
Err(err) => return run_befores(req, befores.slice_from(i), Some(err)) | |
} | |
} | |
Ok(()) | |
} | |
} | |
} | |
fn run_afters(req: &mut Request, mut res: Response, err: Option<Box<Error>>, | |
afters: &[Box<AfterMiddleware>]) -> IronResult<Response> { | |
match err { | |
Some(mut e) => { | |
for (i, after) in afters.iter().enumerate() { | |
match after.catch(req, &mut res, e) { | |
Ok(_) => return run_afters(req, res, None, afters), | |
Err(new) => e = new | |
} | |
} | |
Err(e) | |
}, | |
None => { | |
for (i, after) in afters.iter().enumerate() { | |
match after.after(req, &mut res) { | |
Ok(_) => (), | |
Err(err) => return run_afters(req, res, Some(err), afters.slice_from(i)) | |
} | |
} | |
Ok(res) | |
} | |
} | |
} | |
fn run_handler_catch(req: &mut Request, err: Box<Error>, | |
handler: &Box<Handler>) -> (Response, Option<Box<Error>>) { | |
match handler.catch(req, err) { | |
(res, Ok(())) => (res, None), | |
(res, Err(e)) => (res, Some(e)) | |
} | |
} | |
impl Handler for Box<Handler + Send + Sync> { | |
fn call(&self, req: &mut Request) -> IronResult<Response> { | |
self.call(req) | |
} | |
fn catch(&self, req: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) { | |
self.catch(req, err) | |
} | |
} | |
impl Handler for Arc<Box<Handler + Send + Sync>> { | |
fn call(&self, req: &mut Request) -> IronResult<Response> { | |
self.call(req) | |
} | |
fn catch(&self, req: &mut Request, err: Box<Error>) -> (Response, IronResult<()>) { | |
self.catch(req, err) | |
} | |
} | |
The purpose of AroundMiddleware
is exactly to address that you can only have one handler, by allowing you to arbitrarily augment that handler.
You can also nest handlers using Mount or Router, so you have a master handler that internally calls another handler (just like here, Chain is a handler but calls a sub-handler).
run_befores
needs to take an Error
because it can be called in an errored state in the implementation of Handler::catch
for StackChain
.
The implementations of run_befores
and run_afters
could be made a bit shorter with some code sharing, but I was aiming to just get something working clearly.
Looks like on ln 67 run_befores
is always passed a None value as the third argument. Where does it ever get passed in an Error that it should handle?
π
AroundMiddleware
?runbefores
need to take an error in its signature? Shouldn't it always be run from a clean state?Won'trunafters
be called twice in the event of an error: once throughhandler.call
, and once throughhandler.catch
?runafters
can be called twice in the event that an error is handled - just want to confirm that this is a correct reading.