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}