rocket/fairing/mod.rs
1//! Fairings: callbacks at launch, liftoff, request, and response time.
2//!
3//! Fairings allow for structured interposition at various points in the
4//! application lifetime. Fairings can be seen as a restricted form of
5//! "middleware". A fairing is an arbitrary structure with methods representing
6//! callbacks that Rocket will run at requested points in a program. You can use
7//! fairings to rewrite or record information about requests and responses, or
8//! to perform an action once a Rocket application has launched.
9//!
10//! To learn more about writing a fairing, see the [`Fairing`] trait
11//! documentation. You can also use [`AdHoc`] to create a fairing on-the-fly
12//! from a closure or function.
13//!
14//! ## Attaching
15//!
16//! You must inform Rocket about fairings that you wish to be active by calling
17//! [`Rocket::attach()`] method on the application's [`Rocket`] instance and
18//! passing in the appropriate [`Fairing`]. For instance, to attach fairings
19//! named `req_fairing` and `res_fairing` to a new Rocket instance, you might
20//! write:
21//!
22//! ```rust
23//! # use rocket::fairing::AdHoc;
24//! # let req_fairing = AdHoc::on_request("Request", |_, _| Box::pin(async move {}));
25//! # let res_fairing = AdHoc::on_response("Response", |_, _| Box::pin(async move {}));
26//! let rocket = rocket::build()
27//! .attach(req_fairing)
28//! .attach(res_fairing);
29//! ```
30//!
31//! Once a fairing is attached, Rocket will execute it at the appropriate time,
32//! which varies depending on the fairing implementation. See the [`Fairing`]
33//! trait documentation for more information on the dispatching of fairing
34//! methods.
35//!
36//! [`Fairing`]: crate::fairing::Fairing
37//!
38//! ## Ordering
39//!
40//! `Fairing`s are executed in the order in which they are attached: the first
41//! attached fairing has its callbacks executed before all others. A fairing can
42//! be attached any number of times. Except for [singleton
43//! fairings](Fairing#singletons), all attached instances are polled at runtime.
44//! Fairing callbacks may not be commutative; the order in which fairings are
45//! attached may be significant. It is thus important to communicate specific
46//! fairing functionality clearly.
47//!
48//! Furthermore, a `Fairing` should take care to act locally so that the actions
49//! of other `Fairings` are not jeopardized. For instance, unless it is made
50//! abundantly clear, a fairing should not rewrite every request.
51
52use std::any::Any;
53
54use crate::{Rocket, Request, Response, Data, Build, Orbit};
55
56mod fairings;
57mod ad_hoc;
58mod info_kind;
59
60pub(crate) use self::fairings::Fairings;
61pub use self::ad_hoc::AdHoc;
62pub use self::info_kind::{Info, Kind};
63
64/// A type alias for the return `Result` type of [`Fairing::on_ignite()`].
65pub type Result<T = Rocket<Build>, E = Rocket<Build>> = std::result::Result<T, E>;
66
67// We might imagine that a request fairing returns an `Outcome`. If it returns
68// `Success`, we don't do any routing and use that response directly. Same if it
69// returns `Error`. We only route if it returns `Forward`. I've chosen not to
70// go this direction because I feel like request guards are the correct
71// mechanism to use here. In other words, enabling this at the fairing level
72// encourages implicit handling, a bad practice. Fairings can still, however,
73// return a default `Response` if routing fails via a response fairing. For
74// instance, to automatically handle preflight in CORS, a response fairing can
75// check that the user didn't handle the `OPTIONS` request (404) and return an
76// appropriate response. This allows the users to handle `OPTIONS` requests
77// when they'd like but default to the fairing when they don't want to.
78
79/// Trait implemented by fairings: Rocket's structured middleware.
80///
81/// # Considerations
82///
83/// Fairings are a large hammer that can easily be abused and misused. If you
84/// are considering writing a `Fairing` implementation, first consider if it is
85/// appropriate to do so. While middleware is often the best solution to some
86/// problems in other frameworks, it is often a suboptimal solution in Rocket.
87/// This is because Rocket provides richer mechanisms such as [request guards]
88/// and [data guards] that can be used to accomplish the same objective in a
89/// cleaner, more composable, and more robust manner.
90///
91/// As a general rule of thumb, only _globally applicable actions_ should be
92/// implemented via fairings. For instance, you should _not_ use a fairing to
93/// implement authentication or authorization (preferring to use a [request
94/// guard] instead) _unless_ the authentication or authorization applies to the
95/// entire application. On the other hand, you _should_ use a fairing to record
96/// timing and/or usage statistics or to implement global security policies.
97///
98/// [request guard]: crate::request::FromRequest
99/// [request guards]: crate::request::FromRequest
100/// [data guards]: crate::data::FromData
101///
102/// ## Fairing Callbacks
103///
104/// There are five kinds of fairing callbacks: launch, liftoff, request,
105/// response, and shutdown. A fairing can request any combination of these
106/// callbacks through the `kind` field of the [`Info`] structure returned from
107/// the `info` method. Rocket will only invoke the callbacks identified in the
108/// fairing's [`Kind`].
109///
110/// The callback kinds are as follows:
111///
112/// * **<a name="ignite">Ignite</a> (`on_ignite`)**
113///
114/// An ignite callback, represented by the [`Fairing::on_ignite()`] method,
115/// is called just prior to liftoff, during ignition. The state of the
116/// `Rocket` instance is, at this point, not finalized, as it may be
117/// modified at will by other ignite fairings.
118///
119/// All ignite callbacks are executed in breadth-first `attach()` order. A
120/// callback `B` executing after a callback `A` can view changes made by `A`
121/// but not vice-versa.
122///
123/// An ignite callback can arbitrarily modify the `Rocket` instance being
124/// constructed. It should take care not to introduce infinite recursion by
125/// recursively attaching ignite fairings. It returns `Ok` if it would like
126/// ignition and launch to proceed nominally and `Err` otherwise. If an
127/// ignite fairing returns `Err`, launch will be aborted. All ignite
128/// fairings are executed even if one or more signal an error.
129///
130/// * **<a name="liftoff">Liftoff</a> (`on_liftoff`)**
131///
132/// A liftoff callback, represented by the [`Fairing::on_liftoff()`] method,
133/// is called immediately after a Rocket application has launched. At this
134/// point, Rocket has opened a socket for listening but has not yet begun
135/// accepting connections. A liftoff callback can inspect the `Rocket`
136/// instance that has launched and even schedule a shutdown using
137/// [`Shutdown::notify()`](crate::Shutdown::notify()) via
138/// [`Rocket::shutdown()`].
139///
140/// Liftoff fairings are run concurrently; resolution of all fairings is
141/// awaited before resuming request serving.
142///
143/// * **<a name="request">Request</a> (`on_request`)**
144///
145/// A request callback, represented by the [`Fairing::on_request()`] method,
146/// is called just after a request is received, immediately after
147/// pre-processing the request with method changes due to `_method` form
148/// fields. At this point, Rocket has parsed the incoming HTTP request into
149/// [`Request`] and [`Data`] structures but has not routed the request. A
150/// request callback can modify the request at will and [`Data::peek()`]
151/// into the incoming data. It may not, however, abort or respond directly
152/// to the request; these issues are better handled via [request guards] or
153/// via response callbacks. Any modifications to a request are persisted and
154/// can potentially alter how a request is routed.
155///
156/// * **<a name="response">Response</a> (`on_response`)**
157///
158/// A response callback, represented by the [`Fairing::on_response()`]
159/// method, is called when a response is ready to be sent to the client. At
160/// this point, Rocket has completed all routing, including to error
161/// catchers, and has generated the would-be final response. A response
162/// callback can modify the response at will. For example, a response
163/// callback can provide a default response when the user fails to handle
164/// the request by checking for 404 responses. Note that a given `Request`
165/// may have changed between `on_request` and `on_response` invocations.
166/// Apart from any change made by other fairings, Rocket sets the method for
167/// `HEAD` requests to `GET` if there is no matching `HEAD` handler for that
168/// request. Additionally, Rocket will automatically strip the body for
169/// `HEAD` requests _after_ response fairings have run.
170///
171/// * **<a name="shutdown">Shutdown</a> (`on_shutdown`)**
172///
173/// A shutdown callback, represented by the [`Fairing::on_shutdown()`]
174/// method, is called when [shutdown is triggered]. At this point, graceful
175/// shutdown has commenced but not completed; no new requests are accepted
176/// but the application may still be actively serving existing requests.
177///
178/// Rocket guarantees, however, that all requests are completed or aborted
179/// once [grace and mercy periods] have expired. This implies that a
180/// shutdown fairing that (asynchronously) sleeps for `grace + mercy + ε`
181/// seconds before executing any logic will execute said logic after all
182/// requests have been processed or aborted. Note that such fairings may
183/// wish to operate using the `Ok` return value of [`Rocket::launch()`]
184/// instead.
185///
186/// All registered shutdown fairings are run concurrently; resolution of all
187/// fairings is awaited before resuming shutdown. Shutdown fairings do not
188/// affect grace and mercy periods. In other words, any time consumed by
189/// shutdown fairings is not added to grace and mercy periods.
190///
191/// ***Note: Shutdown fairings are only run during testing if the `Client`
192/// is terminated using [`Client::terminate()`].***
193///
194/// [shutdown is triggered]: crate::config::Shutdown#triggers
195/// [grace and mercy periods]: crate::config::Shutdown#summary
196/// [`Client::terminate()`]: crate::local::blocking::Client::terminate()
197///
198/// # Singletons
199///
200/// In general, any number of instances of a given fairing type can be attached
201/// to one instance of `Rocket`. If this is not desired, a fairing can request
202/// to be a singleton by specifying [`Kind::Singleton`]. Only the _last_
203/// attached instance of a singleton will be preserved at ignite-time. That is,
204/// an attached singleton instance will replace any previously attached
205/// instance. The [`Shield`](crate::shield::Shield) fairing is an example of a
206/// singleton fairing.
207///
208/// # Implementing
209///
210/// A `Fairing` implementation has one required method: [`info`]. A `Fairing`
211/// can also implement any of the available callbacks: `on_ignite`, `on_liftoff`,
212/// `on_request`, and `on_response`. A `Fairing` _must_ set the appropriate
213/// callback kind in the `kind` field of the returned `Info` structure from
214/// [`info`] for a callback to actually be called by Rocket.
215///
216/// ## Fairing `Info`
217///
218/// Every `Fairing` must implement the [`info`] method, which returns an
219/// [`Info`] structure. This structure is used by Rocket to:
220///
221/// 1. Assign a name to the `Fairing`.
222///
223/// This is the `name` field, which can be any arbitrary string. Name your
224/// fairing something illustrative. The name will be logged during the
225/// application's ignition procedures.
226///
227/// 2. Determine which callbacks to actually issue on the `Fairing`.
228///
229/// This is the `kind` field of type [`Kind`]. This field is a bitset that
230/// represents the kinds of callbacks the fairing wishes to receive. Rocket
231/// will only invoke the callbacks that are flagged in this set. `Kind`
232/// structures can be `or`d together to represent any combination of kinds
233/// of callbacks. For instance, to request liftoff and response callbacks,
234/// return a `kind` field with the value `Kind::Liftoff | Kind::Response`.
235///
236/// [`info`]: Fairing::info()
237///
238/// ## Restrictions
239///
240/// A `Fairing` must be [`Send`] + [`Sync`] + `'static`. This means that the
241/// fairing must be sendable across thread boundaries (`Send`), thread-safe
242/// (`Sync`), and have only `'static` references, if any (`'static`). Note that
243/// these bounds _do not_ prohibit a `Fairing` from holding state: the state
244/// need simply be thread-safe and statically available or heap allocated.
245///
246/// ## Async Trait
247///
248/// [`Fairing`] is an _async_ trait. Implementations of `Fairing` must be
249/// decorated with an attribute of `#[rocket::async_trait]`:
250///
251/// ```rust
252/// use rocket::{Rocket, Request, Data, Response, Build, Orbit};
253/// use rocket::fairing::{self, Fairing, Info, Kind};
254///
255/// # struct MyType;
256/// #[rocket::async_trait]
257/// impl Fairing for MyType {
258/// fn info(&self) -> Info {
259/// /* ... */
260/// # unimplemented!()
261/// }
262///
263/// async fn on_ignite(&self, rocket: Rocket<Build>) -> fairing::Result {
264/// /* ... */
265/// # unimplemented!()
266/// }
267///
268/// async fn on_liftoff(&self, rocket: &Rocket<Orbit>) {
269/// /* ... */
270/// # unimplemented!()
271/// }
272///
273/// async fn on_request(&self, req: &mut Request<'_>, data: &mut Data<'_>) {
274/// /* ... */
275/// # unimplemented!()
276/// }
277///
278/// async fn on_response<'r>(&self, req: &'r Request<'_>, res: &mut Response<'r>) {
279/// /* ... */
280/// # unimplemented!()
281/// }
282///
283/// async fn on_shutdown(&self, rocket: &Rocket<Orbit>) {
284/// /* ... */
285/// # unimplemented!()
286/// }
287/// }
288/// ```
289///
290/// ## Example
291///
292/// As an example, we want to record the number of `GET` and `POST` requests
293/// that our application has received. While we could do this with [request
294/// guards] and [managed state](crate::State), it would require us to annotate
295/// every `GET` and `POST` request with custom types, polluting handler
296/// signatures. Instead, we can create a simple fairing that acts globally.
297///
298/// The `Counter` fairing below records the number of all `GET` and `POST`
299/// requests received. It makes these counts available at a special `'/counts'`
300/// path.
301///
302/// ```rust
303/// use std::future::Future;
304/// use std::io::Cursor;
305/// use std::pin::Pin;
306/// use std::sync::atomic::{AtomicUsize, Ordering};
307///
308/// use rocket::{Request, Data, Response};
309/// use rocket::fairing::{Fairing, Info, Kind};
310/// use rocket::http::{Method, ContentType, Status};
311///
312/// #[derive(Default)]
313/// struct Counter {
314/// get: AtomicUsize,
315/// post: AtomicUsize,
316/// }
317///
318/// #[rocket::async_trait]
319/// impl Fairing for Counter {
320/// fn info(&self) -> Info {
321/// Info {
322/// name: "GET/POST Counter",
323/// kind: Kind::Request | Kind::Response
324/// }
325/// }
326///
327/// async fn on_request(&self, req: &mut Request<'_>, _: &mut Data<'_>) {
328/// if req.method() == Method::Get {
329/// self.get.fetch_add(1, Ordering::Relaxed);
330/// } else if req.method() == Method::Post {
331/// self.post.fetch_add(1, Ordering::Relaxed);
332/// }
333/// }
334///
335/// async fn on_response<'r>(&self, req: &'r Request<'_>, res: &mut Response<'r>) {
336/// // Don't change a successful user's response, ever.
337/// if res.status() != Status::NotFound {
338/// return
339/// }
340///
341/// if req.method() == Method::Get && req.uri().path() == "/counts" {
342/// let get_count = self.get.load(Ordering::Relaxed);
343/// let post_count = self.post.load(Ordering::Relaxed);
344///
345/// let body = format!("Get: {}\nPost: {}", get_count, post_count);
346/// res.set_status(Status::Ok);
347/// res.set_header(ContentType::Plain);
348/// res.set_sized_body(body.len(), Cursor::new(body));
349/// }
350/// }
351/// }
352/// ```
353///
354/// ## Request-Local State
355///
356/// Fairings can use [request-local state] to persist or carry data between
357/// requests and responses, or to pass data to a request guard.
358///
359/// As an example, the following fairing uses request-local state to time
360/// requests, setting an `X-Response-Time` header on all responses with the
361/// elapsed time. It also exposes the start time of a request via a `StartTime`
362/// request guard.
363///
364/// ```rust
365/// # use std::future::Future;
366/// # use std::pin::Pin;
367/// # use std::time::{Duration, SystemTime};
368/// # use rocket::{Request, Data, Response};
369/// # use rocket::fairing::{Fairing, Info, Kind};
370/// # use rocket::http::Status;
371/// # use rocket::request::{self, FromRequest};
372/// #
373/// /// Fairing for timing requests.
374/// pub struct RequestTimer;
375///
376/// /// Value stored in request-local state.
377/// #[derive(Copy, Clone)]
378/// struct TimerStart(Option<SystemTime>);
379///
380/// #[rocket::async_trait]
381/// impl Fairing for RequestTimer {
382/// fn info(&self) -> Info {
383/// Info {
384/// name: "Request Timer",
385/// kind: Kind::Request | Kind::Response
386/// }
387/// }
388///
389/// /// Stores the start time of the request in request-local state.
390/// async fn on_request(&self, request: &mut Request<'_>, _: &mut Data<'_>) {
391/// // Store a `TimerStart` instead of directly storing a `SystemTime`
392/// // to ensure that this usage doesn't conflict with anything else
393/// // that might store a `SystemTime` in request-local cache.
394/// request.local_cache(|| TimerStart(Some(SystemTime::now())));
395/// }
396///
397/// /// Adds a header to the response indicating how long the server took to
398/// /// process the request.
399/// async fn on_response<'r>(&self, req: &'r Request<'_>, res: &mut Response<'r>) {
400/// let start_time = req.local_cache(|| TimerStart(None));
401/// if let Some(Ok(duration)) = start_time.0.map(|st| st.elapsed()) {
402/// let ms = duration.as_secs() * 1000 + duration.subsec_millis() as u64;
403/// res.set_raw_header("X-Response-Time", format!("{} ms", ms));
404/// }
405/// }
406/// }
407///
408/// /// Request guard used to retrieve the start time of a request.
409/// #[derive(Copy, Clone)]
410/// pub struct StartTime(pub SystemTime);
411///
412/// // Allows a route to access the time a request was initiated.
413/// #[rocket::async_trait]
414/// impl<'r> FromRequest<'r> for StartTime {
415/// type Error = ();
416///
417/// async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, ()> {
418/// match *request.local_cache(|| TimerStart(None)) {
419/// TimerStart(Some(time)) => request::Outcome::Success(StartTime(time)),
420/// TimerStart(None) => request::Outcome::Error((Status::InternalServerError, ())),
421/// }
422/// }
423/// }
424/// ```
425///
426/// [request-local state]: https://rocket.rs/v0.5/guide/state/#request-local-state
427#[crate::async_trait]
428pub trait Fairing: Send + Sync + Any + 'static {
429 /// Returns an [`Info`] structure containing the `name` and [`Kind`] of this
430 /// fairing. The `name` can be any arbitrary string. `Kind` must be an `or`d
431 /// set of `Kind` variants.
432 ///
433 /// This is the only required method of a `Fairing`. All other methods have
434 /// no-op default implementations.
435 ///
436 /// Rocket will only dispatch callbacks to this fairing for the kinds in the
437 /// `kind` field of the returned `Info` structure. For instance, if
438 /// `Kind::Ignite | Kind::Request` is used, then Rocket will only call the
439 /// `on_ignite` and `on_request` methods of the fairing. Similarly, if
440 /// `Kind::Response` is used, Rocket will only call the `on_response` method
441 /// of this fairing.
442 ///
443 /// # Example
444 ///
445 /// An `info` implementation for `MyFairing`: a fairing named "My Custom
446 /// Fairing" that is both an ignite and response fairing.
447 ///
448 /// ```rust
449 /// use rocket::fairing::{Fairing, Info, Kind};
450 ///
451 /// struct MyFairing;
452 ///
453 /// impl Fairing for MyFairing {
454 /// fn info(&self) -> Info {
455 /// Info {
456 /// name: "My Custom Fairing",
457 /// kind: Kind::Ignite | Kind::Response
458 /// }
459 /// }
460 /// }
461 /// ```
462 fn info(&self) -> Info;
463
464 /// The ignite callback. Returns `Ok` if ignition should proceed and `Err`
465 /// if ignition and launch should be aborted.
466 ///
467 /// See [Fairing Callbacks](#ignite) for complete semantics.
468 ///
469 /// This method is called during ignition and if `Kind::Ignite` is in the
470 /// `kind` field of the `Info` structure for this fairing. The `rocket`
471 /// parameter is the `Rocket` instance that is currently being built for
472 /// this application.
473 ///
474 /// ## Default Implementation
475 ///
476 /// The default implementation of this method simply returns `Ok(rocket)`.
477 async fn on_ignite(&self, rocket: Rocket<Build>) -> Result { Ok(rocket) }
478
479 /// The liftoff callback.
480 ///
481 /// See [Fairing Callbacks](#liftoff) for complete semantics.
482 ///
483 /// This method is called just after launching the application if
484 /// `Kind::Liftoff` is in the `kind` field of the `Info` structure for this
485 /// fairing. The `Rocket` parameter corresponds to the launched application.
486 ///
487 /// ## Default Implementation
488 ///
489 /// The default implementation of this method does nothing.
490 async fn on_liftoff(&self, _rocket: &Rocket<Orbit>) { }
491
492 /// The request callback.
493 ///
494 /// See [Fairing Callbacks](#request) for complete semantics.
495 ///
496 /// This method is called when a new request is received if `Kind::Request`
497 /// is in the `kind` field of the `Info` structure for this fairing. The
498 /// `&mut Request` parameter is the incoming request, and the `&Data`
499 /// parameter is the incoming data in the request.
500 ///
501 /// ## Default Implementation
502 ///
503 /// The default implementation of this method does nothing.
504 async fn on_request(&self, _req: &mut Request<'_>, _data: &mut Data<'_>) {}
505
506 /// The response callback.
507 ///
508 /// See [Fairing Callbacks](#response) for complete semantics.
509 ///
510 /// This method is called when a response is ready to be issued to a client
511 /// if `Kind::Response` is in the `kind` field of the `Info` structure for
512 /// this fairing. The `&Request` parameter is the request that was routed,
513 /// and the `&mut Response` parameter is the resulting response.
514 ///
515 /// ## Default Implementation
516 ///
517 /// The default implementation of this method does nothing.
518 async fn on_response<'r>(&self, _req: &'r Request<'_>, _res: &mut Response<'r>) {}
519
520 /// The shutdown callback.
521 ///
522 /// See [Fairing Callbacks](#shutdown) for complete semantics.
523 ///
524 /// This method is called when [shutdown is triggered] if `Kind::Shutdown`
525 /// is in the `kind` field of the `Info` structure for this fairing. The
526 /// `Rocket` parameter corresponds to the running application.
527 ///
528 /// [shutdown is triggered]: crate::config::Shutdown#triggers
529 ///
530 /// ## Default Implementation
531 ///
532 /// The default implementation of this method does nothing.
533 async fn on_shutdown(&self, _rocket: &Rocket<Orbit>) { }
534}
535
536#[crate::async_trait]
537impl<T: Fairing + ?Sized> Fairing for std::sync::Arc<T> {
538 #[inline]
539 fn info(&self) -> Info {
540 (self as &T).info()
541 }
542
543 #[inline]
544 async fn on_ignite(&self, rocket: Rocket<Build>) -> Result {
545 (self as &T).on_ignite(rocket).await
546 }
547
548 #[inline]
549 async fn on_liftoff(&self, rocket: &Rocket<Orbit>) {
550 (self as &T).on_liftoff(rocket).await
551 }
552
553 #[inline]
554 async fn on_request(&self, req: &mut Request<'_>, data: &mut Data<'_>) {
555 (self as &T).on_request(req, data).await
556 }
557
558 #[inline]
559 async fn on_response<'r>(&self, req: &'r Request<'_>, res: &mut Response<'r>) {
560 (self as &T).on_response(req, res).await
561 }
562
563 #[inline]
564 async fn on_shutdown(&self, rocket: &Rocket<Orbit>) {
565 (self as &T).on_shutdown(rocket).await
566 }
567}