rocket_community/route/handler.rs
1use crate::http::Status;
2use crate::response::{Responder, Response};
3use crate::{Data, Request};
4
5/// Type alias for the return type of a [`Route`](crate::Route)'s
6/// [`Handler::handle()`].
7pub type Outcome<'r> = crate::outcome::Outcome<Response<'r>, Status, (Data<'r>, Status)>;
8
9/// Type alias for the return type of a _raw_ [`Route`](crate::Route)'s
10/// [`Handler`].
11pub type BoxFuture<'r, T = Outcome<'r>> = futures::future::BoxFuture<'r, T>;
12
13/// Trait implemented by [`Route`](crate::Route) request handlers.
14///
15/// In general, you will never need to implement `Handler` manually or be
16/// concerned about the `Handler` trait; Rocket's code generation handles
17/// everything for you. You only need to learn about this trait if you want to
18/// provide an external, library-based mechanism to handle requests where
19/// request handling depends on input from the user. In other words, if you want
20/// to write a plugin for Rocket that looks mostly like a static route but need
21/// user provided state to make a request handling decision, you should consider
22/// implementing a custom `Handler`.
23///
24/// ## Async Trait
25///
26/// This is an _async_ trait. Implementations must be decorated
27/// [`#[rocket::async_trait]`](crate::async_trait).
28///
29/// # Example
30///
31/// Say you'd like to write a handler that changes its functionality based on an
32/// enum value that the user provides:
33///
34/// ```rust
35/// #[derive(Copy, Clone)]
36/// enum Kind {
37/// Simple,
38/// Intermediate,
39/// Complex,
40/// }
41/// ```
42///
43/// Such a handler might be written and used as follows:
44///
45/// ```rust,no_run
46/// # extern crate rocket_community as rocket;
47/// # #[derive(Copy, Clone)] enum Kind { Simple, Intermediate, Complex, }
48/// use rocket::{Request, Data};
49/// use rocket::route::{Handler, Route, Outcome};
50/// use rocket::http::Method;
51///
52/// #[derive(Clone)]
53/// struct CustomHandler(Kind);
54///
55/// #[rocket::async_trait]
56/// impl Handler for CustomHandler {
57/// async fn handle<'r>(&self, req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r> {
58/// match self.0 {
59/// Kind::Simple => Outcome::from(req, "simple"),
60/// Kind::Intermediate => Outcome::from(req, "intermediate"),
61/// Kind::Complex => Outcome::from(req, "complex"),
62/// }
63/// }
64/// }
65///
66/// impl Into<Vec<Route>> for CustomHandler {
67/// fn into(self) -> Vec<Route> {
68/// vec![Route::new(Method::Get, "/", self)]
69/// }
70/// }
71///
72/// #[rocket::launch]
73/// fn rocket() -> _ {
74/// rocket::build().mount("/", CustomHandler(Kind::Simple))
75/// }
76/// ```
77///
78/// Note the following:
79///
80/// 1. `CustomHandler` implements `Clone`. This is required so that
81/// `CustomHandler` implements `Cloneable` automatically. The `Cloneable`
82/// trait serves no other purpose but to ensure that every `Handler` can be
83/// cloned, allowing `Route`s to be cloned.
84/// 2. `CustomHandler` implements `Into<Vec<Route>>`, allowing an instance to
85/// be used directly as the second parameter to `rocket.mount()`.
86/// 3. Unlike static-function-based handlers, this custom handler can make use
87/// of any internal state.
88///
89/// # Alternatives
90///
91/// The previous example could have been implemented using a combination of
92/// managed state and a static route, as follows:
93///
94/// ```rust,no_run
95/// # #[macro_use] extern crate rocket_community as rocket;
96/// #
97/// # #[derive(Copy, Clone)]
98/// # enum Kind {
99/// # Simple,
100/// # Intermediate,
101/// # Complex,
102/// # }
103/// #
104/// use rocket::State;
105///
106/// #[get("/")]
107/// fn custom_handler(state: &State<Kind>) -> &'static str {
108/// match state.inner() {
109/// Kind::Simple => "simple",
110/// Kind::Intermediate => "intermediate",
111/// Kind::Complex => "complex",
112/// }
113/// }
114///
115/// #[launch]
116/// fn rocket() -> _ {
117/// rocket::build()
118/// .mount("/", routes![custom_handler])
119/// .manage(Kind::Simple)
120/// }
121/// ```
122///
123/// Pros:
124///
125/// * The handler is easier to implement since Rocket's code generation
126/// ensures type-safety at all levels.
127///
128/// Cons:
129///
130/// * Only one `Kind` can be stored in managed state. As such, only one
131/// variant of the custom handler can be used.
132/// * The user must remember to manually call `rocket.manage(state)`.
133///
134/// Use this alternative when a single configuration is desired and your custom
135/// handler is private to your application. For all other cases, a custom
136/// `Handler` implementation is preferred.
137#[crate::async_trait]
138pub trait Handler: Cloneable + Send + Sync + 'static {
139 /// Called by Rocket when a `Request` with its associated `Data` should be
140 /// handled by this handler.
141 ///
142 /// The variant of `Outcome` returned by the returned `Future` determines
143 /// what Rocket does next. If the return value is a `Success(Response)`, the
144 /// wrapped `Response` is used to respond to the client. If the return value
145 /// is an `Error(Status)`, the error catcher for `Status` is invoked to
146 /// generate a response. Otherwise, if the return value is `Forward(Data)`,
147 /// the next matching route is attempted. If there are no other matching
148 /// routes, the `404` error catcher is invoked.
149 async fn handle<'r>(&self, request: &'r Request<'_>, data: Data<'r>) -> Outcome<'r>;
150}
151
152// We write this manually to avoid double-boxing.
153impl<F: Clone + Sync + Send + 'static> Handler for F
154where
155 for<'x> F: Fn(&'x Request<'_>, Data<'x>) -> BoxFuture<'x>,
156{
157 #[inline(always)]
158 fn handle<'r, 'life0, 'life1, 'async_trait>(
159 &'life0 self,
160 req: &'r Request<'life1>,
161 data: Data<'r>,
162 ) -> BoxFuture<'r>
163 where
164 'r: 'async_trait,
165 'life0: 'async_trait,
166 'life1: 'async_trait,
167 Self: 'async_trait,
168 {
169 self(req, data)
170 }
171}
172
173impl<'r, 'o: 'r> Outcome<'o> {
174 /// Return the `Outcome` of response to `req` from `responder`.
175 ///
176 /// If the responder returns `Ok`, an outcome of `Success` is returned with
177 /// the response. If the responder returns `Err`, an outcome of `Error` is
178 /// returned with the status code.
179 ///
180 /// # Example
181 ///
182 /// ```rust
183 /// # extern crate rocket_community as rocket;
184 /// use rocket::{Request, Data, route};
185 ///
186 /// fn str_responder<'r>(req: &'r Request, _: Data<'r>) -> route::Outcome<'r> {
187 /// route::Outcome::from(req, "Hello, world!")
188 /// }
189 /// ```
190 #[inline]
191 pub fn from<R: Responder<'r, 'o>>(req: &'r Request<'_>, responder: R) -> Outcome<'r> {
192 match responder.respond_to(req) {
193 Ok(response) => Outcome::Success(response),
194 Err(status) => Outcome::Error(status),
195 }
196 }
197
198 /// Return the `Outcome` of response to `req` from `responder`.
199 ///
200 /// If the responder returns `Ok`, an outcome of `Success` is returned with
201 /// the response. If the responder returns `Err`, an outcome of `Error` is
202 /// returned with the status code.
203 ///
204 /// # Example
205 ///
206 /// ```rust
207 /// # extern crate rocket_community as rocket;
208 /// use rocket::{Request, Data, route};
209 ///
210 /// fn str_responder<'r>(req: &'r Request, _: Data<'r>) -> route::Outcome<'r> {
211 /// route::Outcome::from(req, "Hello, world!")
212 /// }
213 /// ```
214 #[inline]
215 pub fn try_from<R, E>(req: &'r Request<'_>, result: Result<R, E>) -> Outcome<'r>
216 where
217 R: Responder<'r, 'o>,
218 E: std::fmt::Debug,
219 {
220 let responder = result.map_err(crate::response::Debug);
221 match responder.respond_to(req) {
222 Ok(response) => Outcome::Success(response),
223 Err(status) => Outcome::Error(status),
224 }
225 }
226
227 /// Return an `Outcome` of `Error` with the status code `code`. This is
228 /// equivalent to `Outcome::Error(code)`.
229 ///
230 /// This method exists to be used during manual routing.
231 ///
232 /// # Example
233 ///
234 /// ```rust
235 /// # extern crate rocket_community as rocket;
236 /// use rocket::{Request, Data, route};
237 /// use rocket::http::Status;
238 ///
239 /// fn bad_req_route<'r>(_: &'r Request, _: Data<'r>) -> route::Outcome<'r> {
240 /// route::Outcome::error(Status::BadRequest)
241 /// }
242 /// ```
243 #[inline(always)]
244 pub fn error(code: Status) -> Outcome<'r> {
245 Outcome::Error(code)
246 }
247
248 /// Return an `Outcome` of `Forward` with the data `data` and status
249 /// `status`. This is equivalent to `Outcome::Forward((data, status))`.
250 ///
251 /// This method exists to be used during manual routing.
252 ///
253 /// # Example
254 ///
255 /// ```rust
256 /// # extern crate rocket_community as rocket;
257 /// use rocket::{Request, Data, route};
258 /// use rocket::http::Status;
259 ///
260 /// fn always_forward<'r>(_: &'r Request, data: Data<'r>) -> route::Outcome<'r> {
261 /// route::Outcome::forward(data, Status::InternalServerError)
262 /// }
263 /// ```
264 #[inline(always)]
265 pub fn forward(data: Data<'r>, status: Status) -> Outcome<'r> {
266 Outcome::Forward((data, status))
267 }
268}
269
270// INTERNAL: A handler to use when one is needed temporarily.
271#[doc(hidden)]
272pub fn dummy_handler<'r>(r: &'r Request<'_>, _: Data<'r>) -> BoxFuture<'r> {
273 Outcome::from(r, ()).pin()
274}
275
276mod private {
277 pub trait Sealed {}
278 impl<T: super::Handler + Clone> Sealed for T {}
279}
280
281/// Helper trait to make a [`Route`](crate::Route)'s `Box<dyn Handler>`
282/// `Clone`.
283///
284/// This trait cannot be implemented directly. Instead, implement `Clone` and
285/// [`Handler`]; all types that implement `Clone` and `Handler` automatically
286/// implement `Cloneable`.
287pub trait Cloneable: private::Sealed {
288 #[doc(hidden)]
289 fn clone_handler(&self) -> Box<dyn Handler>;
290}
291
292impl<T: Handler + Clone> Cloneable for T {
293 fn clone_handler(&self) -> Box<dyn Handler> {
294 Box::new(self.clone())
295 }
296}
297
298impl Clone for Box<dyn Handler> {
299 fn clone(&self) -> Box<dyn Handler> {
300 self.clone_handler()
301 }
302}