// This example illustrates the error flow of a Request in the middleware Chain. // Here is the chain used and the path of the request through the middleware pieces: // // Normal Flow : __[ErrorProducer::before]__ [ErrorRecover::before] __[handle::HelloWorldHandler]__[ErrorProducer::after]__ [ErrorRecover::after] __ ... // Error Flow : [ErrorProducer::catch ] |__[ErrorRecover::catch ]__| [ErrorProducer::catch] |__[ErrorRecover::catch]__| // // --------------- BEFORE MIDDLEWARE ----------------- || --------- HANDLER -------- || ---------------- AFTER MIDDLEWARE -------------- extern crate iron; use iron::prelude::*; use iron::StatusCode; use iron::{AfterMiddleware, BeforeMiddleware, Handler}; use std::error::Error; use std::fmt::{self, Debug}; struct HelloWorldHandler; struct ErrorProducer; struct ErrorRecover; #[derive(Debug)] struct StringError(String); impl fmt::Display for StringError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { Debug::fmt(self, f) } } impl Error for StringError { fn description(&self) -> &str { &*self.0 } } impl Handler for HelloWorldHandler { fn handle(&self, _: &mut Request) -> IronResult { // This will be called since we are in the normal flow before reaching the Handler. // However, the AfterMiddleware chain will override the Response. println!("The HelloWorldHandler has been called !"); Ok(Response::with((StatusCode::OK, "Hello world !"))) } } impl BeforeMiddleware for ErrorProducer { fn before(&self, _: &mut Request) -> IronResult<()> { // The error produced here switches to the error flow. // The catch method of following middleware pieces will be called. // The Handler will be skipped unless the error is handled by another middleware piece. // IronError::error tells the next middleware what went wrong. // IronError::response is the Response that will be sent back to the client if this error is not handled. // Here status::BadRequest acts as modifier, thus we can put more there than just a status. Err(IronError::new( StringError("Error in ErrorProducer BeforeMiddleware".to_string()), StatusCode::BAD_REQUEST, )) } } impl AfterMiddleware for ErrorProducer { fn after(&self, _: &mut Request, _: Response) -> IronResult { // The behavior here is the same as in ErrorProducer::before. // The previous response (from the Handler) is discarded and replaced with a new response (created from the modifier). Err(IronError::new( StringError("Error in ErrorProducer AfterMiddleware".to_string()), (StatusCode::BAD_REQUEST, "Response created in ErrorProducer"), )) } } impl BeforeMiddleware for ErrorRecover { fn catch(&self, _: &mut Request, err: IronError) -> IronResult<()> { // We can use the IronError from previous middleware to decide what to do. // Returning Ok() from a catch method resumes the normal flow and // passes the Request forward to the next middleware piece in the chain (here the HelloWorldHandler). println!("{} caught in ErrorRecover BeforeMiddleware.", err.error); match err.response.status { Some(StatusCode::BAD_REQUEST) => Ok(()), _ => Err(err), } } } impl AfterMiddleware for ErrorRecover { fn catch(&self, _: &mut Request, err: IronError) -> IronResult { // Just like in the BeforeMiddleware, we can return Ok(Response) here to return to the normal flow. // In this case, ErrorRecover is the last middleware in the chain // and the Response created in the ErrorProducer is modified and sent back to the client. println!("{} caught in ErrorRecover AfterMiddleware.", err.error); match err.response.status { Some(StatusCode::BAD_REQUEST) => Ok(err.response.set(StatusCode::OK)), _ => Err(err), } } } fn main() { let mut chain = Chain::new(HelloWorldHandler); chain.link_before(ErrorProducer); chain.link_before(ErrorRecover); chain.link_after(ErrorProducer); chain.link_after(ErrorRecover); Iron::new(chain).http("localhost:3000"); }