//! Types and traits for request and error handlers and their return values. use data::Data; use request::Request; use response::{self, Response, Responder}; use http::Status; use outcome; /// Type alias for the `Outcome` of a `Handler`. pub type Outcome<'r> = outcome::Outcome, Status, Data>; /// Trait implemented by types that can handle requests. /// /// In general, you will never need to implement `Handler` manually or be /// concerned about the `Handler` trait; Rocket's code generation handles /// everything for you. You only need to learn about this trait if you want to /// provide an external, library-based mechanism to handle requests where /// request handling depends on input from the user. In other words, if you want /// to write a plugin for Rocket that looks mostly like a static route but need /// user provided state to make a request handling decision, you should consider /// implementing a custom `Handler`. /// /// # Example /// /// Say you'd like to write a handler that changes its functionality based on an /// enum value that the user provides: /// /// ```rust /// #[derive(Copy, Clone)] /// enum Kind { /// Simple, /// Intermediate, /// Complex, /// } /// ``` /// /// Such a handler might be written and used as follows: /// /// ```rust /// # #[derive(Copy, Clone)] enum Kind { Simple, Intermediate, Complex, } /// use rocket::{Request, Data, Route, http::Method}; /// use rocket::handler::{self, Handler, Outcome}; /// /// #[derive(Clone)] /// struct CustomHandler(Kind); /// /// impl Handler for CustomHandler { /// fn handle<'r>(&self, req: &'r Request, data: Data) -> Outcome<'r> { /// match self.0 { /// Kind::Simple => Outcome::from(req, "simple"), /// Kind::Intermediate => Outcome::from(req, "intermediate"), /// Kind::Complex => Outcome::from(req, "complex"), /// } /// } /// } /// /// impl Into> for CustomHandler { /// fn into(self) -> Vec { /// vec![Route::new(Method::Get, "/", self)] /// } /// } /// /// fn main() { /// # if false { /// rocket::ignite() /// .mount("/", CustomHandler(Kind::Simple)) /// .launch(); /// # } /// } /// ``` /// /// Note the following: /// /// 1. `CustomHandler` implements `Clone`. This is required so that /// `CustomHandler` implements `Cloneable` automatically. The `Cloneable` /// trait serves no other purpose but to ensure that every `Handler` can be /// cloned, allowing `Route`s to be cloned. /// 2. `CustomHandler` implements `Into>`, allowing an instance to /// be used directly as the second parameter to `rocket.mount()`. /// 3. Unlike static-function-based handlers, this custom handler can make use /// of any internal state. /// /// # Alternatives /// /// The previous example could have been implemented using a combination of /// managed state and a static route, as follows: /// /// ```rust /// # #![feature(proc_macro_hygiene, decl_macro)] /// # #[macro_use] extern crate rocket; /// # /// # #[derive(Copy, Clone)] /// # enum Kind { /// # Simple, /// # Intermediate, /// # Complex, /// # } /// # /// use rocket::State; /// /// #[get("/")] /// fn custom_handler(state: State) -> &'static str { /// match *state { /// Kind::Simple => "simple", /// Kind::Intermediate => "intermediate", /// Kind::Complex => "complex", /// } /// } /// /// fn main() { /// # if false { /// rocket::ignite() /// .mount("/", routes![custom_handler]) /// .manage(Kind::Simple) /// .launch(); /// # } /// } /// ``` /// /// Pros: /// /// * The handler is easier to implement since Rocket's code generation /// ensures type-safety at all levels. /// /// Cons: /// /// * Only one `Kind` can be stored in managed state. As such, only one /// variant of the custom handler can be used. /// * The user must remember to manually call `rocket.manage(state)`. /// /// Use this alternative when a single configuration is desired and your custom /// handler is private to your application. For all other cases, a custom /// `Handler` implementation is preferred. pub trait Handler: Cloneable + Send + Sync + 'static { /// Called by Rocket when a `Request` with its associated `Data` should be /// handled by this handler. /// /// The variant of `Outcome` returned determines what Rocket does next. If /// the return value is a `Success(Response)`, the wrapped `Response` is /// used to respond to the client. If the return value is a /// `Failure(Status)`, the error catcher for `Status` is invoked to generate /// a response. Otherwise, if the return value is `Forward(Data)`, the next /// matching route is attempted. If there are no other matching routes, the /// `404` error catcher is invoked. fn handle<'r>(&self, request: &'r Request, data: Data) -> Outcome<'r>; } /// Unfortunate but necessary hack to be able to clone a `Box`. /// /// This trait should _never_ (and cannot, due to coherence) be implemented by /// any type. Instead, implement `Clone`. All types that implement `Clone` and /// `Handler` automatically implement `Cloneable`. pub trait Cloneable { fn clone_handler(&self) -> Box; } impl Cloneable for T { #[inline(always)] fn clone_handler(&self) -> Box { Box::new(self.clone()) } } impl Clone for Box { #[inline(always)] fn clone(&self) -> Box { self.clone_handler() } } impl Handler for F where for<'r> F: Fn(&'r Request, Data) -> Outcome<'r> { #[inline(always)] fn handle<'r>(&self, req: &'r Request, data: Data) -> Outcome<'r> { self(req, data) } } /// The type of an error handler. pub type ErrorHandler = for<'r> fn(&'r Request) -> response::Result<'r>; impl<'r> Outcome<'r> { /// Return the `Outcome` of response to `req` from `responder`. /// /// If the responder returns `Ok`, an outcome of `Success` is /// returned with the response. If the responder returns `Err`, an /// outcome of `Failure` is returned with the status code. /// /// # Example /// /// ```rust /// use rocket::{Request, Data}; /// use rocket::handler::Outcome; /// /// fn str_responder(req: &Request, _: Data) -> Outcome<'static> { /// Outcome::from(req, "Hello, world!") /// } /// ``` #[inline] pub fn from>(req: &Request, responder: T) -> Outcome<'r> { match responder.respond_to(req) { Ok(response) => outcome::Outcome::Success(response), Err(status) => outcome::Outcome::Failure(status) } } /// Return an `Outcome` of `Failure` with the status code `code`. This is /// equivalent to `Outcome::Failure(code)`. /// /// This method exists to be used during manual routing where /// `rocket::handler::Outcome` is imported instead of `rocket::Outcome`. /// /// # Example /// /// ```rust /// use rocket::{Request, Data}; /// use rocket::handler::Outcome; /// use rocket::http::Status; /// /// fn bad_req_route(_: &Request, _: Data) -> Outcome<'static> { /// Outcome::failure(Status::BadRequest) /// } /// ``` #[inline(always)] pub fn failure(code: Status) -> Outcome<'static> { outcome::Outcome::Failure(code) } /// Return an `Outcome` of `Forward` with the data `data`. This is /// equivalent to `Outcome::Forward(data)`. /// /// This method exists to be used during manual routing where /// `rocket::handler::Outcome` is imported instead of `rocket::Outcome`. /// /// # Example /// /// ```rust /// use rocket::{Request, Data}; /// use rocket::handler::Outcome; /// /// fn always_forward(_: &Request, data: Data) -> Outcome<'static> { /// Outcome::forward(data) /// } /// ``` #[inline(always)] pub fn forward(data: Data) -> Outcome<'static> { outcome::Outcome::Forward(data) } }