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}