rocket/catcher/
handler.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use crate::{Request, Response};
use crate::http::Status;

/// Type alias for the return type of a [`Catcher`](crate::Catcher)'s
/// [`Handler::handle()`].
pub type Result<'r> = std::result::Result<Response<'r>, crate::http::Status>;

/// Type alias for the return type of a _raw_ [`Catcher`](crate::Catcher)'s
/// [`Handler`].
pub type BoxFuture<'r, T = Result<'r>> = futures::future::BoxFuture<'r, T>;

/// Trait implemented by [`Catcher`](crate::Catcher) error handlers.
///
/// This trait is exactly like a [`Route`](crate::Route)'s
/// [`Handler`](crate::route::Handler) except it handles errors instead of
/// requests. Thus, the documentation for
/// [`route::Handler`](crate::route::Handler) applies to this trait as well. We
/// defer to it for full details.
///
/// ## Async Trait
///
/// This is an _async_ trait. Implementations must be decorated
/// [`#[rocket::async_trait]`](crate::async_trait).
///
/// # Example
///
/// Say you'd like to write a handler that changes its functionality based on a
/// `Kind` enum value that the user provides. Such a handler might be written
/// and used as follows:
///
/// ```rust,no_run
/// use rocket::{Request, Catcher, catcher};
/// use rocket::response::{Response, Responder};
/// use rocket::http::Status;
///
/// #[derive(Copy, Clone)]
/// enum Kind {
///     Simple,
///     Intermediate,
///     Complex,
/// }
///
/// #[derive(Clone)]
/// struct CustomHandler(Kind);
///
/// #[rocket::async_trait]
/// impl catcher::Handler for CustomHandler {
///     async fn handle<'r>(&self, status: Status, req: &'r Request<'_>) -> catcher::Result<'r> {
///         let inner = match self.0 {
///             Kind::Simple => "simple".respond_to(req)?,
///             Kind::Intermediate => "intermediate".respond_to(req)?,
///             Kind::Complex => "complex".respond_to(req)?,
///         };
///
///         Response::build_from(inner).status(status).ok()
///     }
/// }
///
/// impl CustomHandler {
///     /// Returns a `default` catcher that uses `CustomHandler`.
///     fn default(kind: Kind) -> Vec<Catcher> {
///         vec![Catcher::new(None, CustomHandler(kind))]
///     }
///
///     /// Returns a catcher for code `status` that uses `CustomHandler`.
///     fn catch(status: Status, kind: Kind) -> Vec<Catcher> {
///         vec![Catcher::new(status.code, CustomHandler(kind))]
///     }
/// }
///
/// #[rocket::launch]
/// fn rocket() -> _ {
///     rocket::build()
///         // to handle only `404`
///         .register("/", CustomHandler::catch(Status::NotFound, Kind::Simple))
///         // or to register as the default
///         .register("/", CustomHandler::default(Kind::Simple))
/// }
/// ```
///
/// 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 `Catcher`s to be cloned.
///   2. `CustomHandler`'s methods return `Vec<Route>`, allowing for use
///      directly as the parameter to `rocket.register("/", )`.
///   3. Unlike static-function-based handlers, this custom handler can make use
///      of internal state.
#[crate::async_trait]
pub trait Handler: Cloneable + Send + Sync + 'static {
    /// Called by Rocket when an error with `status` for a given `Request`
    /// should be handled by this handler.
    ///
    /// Error handlers _should not_ fail and thus _should_ always return `Ok`.
    /// Nevertheless, failure is allowed, both for convenience and necessity. If
    /// an error handler fails, Rocket's default `500` catcher is invoked. If it
    /// succeeds, the returned `Response` is used to respond to the client.
    async fn handle<'r>(&self, status: Status, req: &'r Request<'_>) -> Result<'r>;
}

// We write this manually to avoid double-boxing.
impl<F: Clone + Sync + Send + 'static> Handler for F
    where for<'x> F: Fn(Status, &'x Request<'_>) -> BoxFuture<'x>,
{
    fn handle<'r, 'life0, 'life1, 'async_trait>(
        &'life0 self,
        status: Status,
        req: &'r Request<'life1>,
    ) -> BoxFuture<'r>
        where 'r: 'async_trait,
              'life0: 'async_trait,
              'life1: 'async_trait,
              Self: 'async_trait,
    {
        self(status, req)
    }
}

// Used in tests! Do not use, please.
#[doc(hidden)]
pub fn dummy_handler<'r>(_: Status, _: &'r Request<'_>) -> BoxFuture<'r> {
   Box::pin(async move { Ok(Response::new()) })
}

mod private {
    pub trait Sealed {}
    impl<T: super::Handler + Clone> Sealed for T {}
}

/// Helper trait to make a [`Catcher`](crate::Catcher)'s `Box<dyn Handler>`
/// `Clone`.
///
/// This trait cannot be implemented directly. Instead, implement `Clone` and
/// [`Handler`]; all types that implement `Clone` and `Handler` automatically
/// implement `Cloneable`.
pub trait Cloneable: private::Sealed {
    #[doc(hidden)]
    fn clone_handler(&self) -> Box<dyn Handler>;
}

impl<T: Handler + Clone> Cloneable for T {
    fn clone_handler(&self) -> Box<dyn Handler> {
        Box::new(self.clone())
    }
}

impl Clone for Box<dyn Handler> {
    fn clone(&self) -> Box<dyn Handler> {
        self.clone_handler()
    }
}