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