2017-07-07 03:46:43 +00:00
|
|
|
|
# Fairings
|
|
|
|
|
|
2017-07-11 11:43:08 +00:00
|
|
|
|
Fairings are Rocket's approach to structured middleware. With fairings, your
|
|
|
|
|
application can hook into the request lifecycle to record or rewrite information
|
|
|
|
|
about incoming requests and outgoing responses.
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
|
|
|
|
## Overview
|
|
|
|
|
|
2017-08-11 22:29:42 +00:00
|
|
|
|
Any type that implements the [`Fairing`] trait is a _fairing_. Fairings hook
|
|
|
|
|
into Rocket's request lifecycle, receiving callbacks for events such as incoming
|
2017-09-28 03:17:40 +00:00
|
|
|
|
requests and outgoing responses. Rocket passes information about these events to
|
2018-10-22 21:47:35 +00:00
|
|
|
|
the fairing; the fairing can do what it wants with the information. This
|
|
|
|
|
includes rewriting requests or responses, recording information about the event,
|
|
|
|
|
or doing nothing at all.
|
2017-07-11 11:43:08 +00:00
|
|
|
|
|
2017-08-11 22:29:42 +00:00
|
|
|
|
Rocket’s fairings are a lot like middleware from other frameworks, but they bear
|
|
|
|
|
a few key distinctions:
|
2017-07-11 11:43:08 +00:00
|
|
|
|
|
|
|
|
|
* Fairings **cannot** terminate or respond to an incoming request directly.
|
|
|
|
|
* Fairings **cannot** inject arbitrary, non-request data into a request.
|
|
|
|
|
* Fairings _can_ prevent an application from launching.
|
|
|
|
|
* Fairings _can_ inspect and modify the application's configuration.
|
|
|
|
|
|
|
|
|
|
If you are familiar with middleware from other frameworks, you may find yourself
|
2017-08-11 22:29:42 +00:00
|
|
|
|
reaching for fairings instinctively. Before doing so, remember that Rocket
|
|
|
|
|
provides a rich set of mechanisms such as [request guards] and [data guards]
|
|
|
|
|
that can be used to solve problems in a clean, composable, and robust manner.
|
2017-07-11 11:43:08 +00:00
|
|
|
|
|
2018-10-22 21:47:35 +00:00
|
|
|
|
! warning
|
|
|
|
|
|
|
|
|
|
As a general rule of thumb, only _globally applicable_ actions should be
|
|
|
|
|
effected through fairings. You should **_not_** use a fairing to implement
|
|
|
|
|
authentication or authorization (preferring to use a [request guard] instead)
|
|
|
|
|
_unless_ the authentication or authorization applies to all or the
|
|
|
|
|
overwhelming majority application. On the other hand, you _should_ use a
|
|
|
|
|
fairing to record timing and usage statistics or to enforce global security
|
|
|
|
|
policies.
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
2018-10-16 05:50:35 +00:00
|
|
|
|
[`Fairing`]: @api/rocket/fairing/trait.Fairing.html
|
|
|
|
|
[request guard]: ../requests/#request-guards
|
|
|
|
|
[request guards]: ../requests/#request-guards
|
|
|
|
|
[data guards]: ../requests/#body-data
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
|
|
|
|
### Attaching
|
|
|
|
|
|
2017-07-11 11:43:08 +00:00
|
|
|
|
Fairings are registered with Rocket via the [`attach`] method on a [`Rocket`]
|
|
|
|
|
instance. Only when a fairing is attached will its callbacks fire. As an
|
2020-02-15 11:43:47 +00:00
|
|
|
|
example, the following snippet attached two fairings, `req_fairing` and
|
2017-07-11 11:43:08 +00:00
|
|
|
|
`res_fairing`, to a new Rocket instance:
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
|
|
|
|
```rust
|
2020-07-22 23:10:02 +00:00
|
|
|
|
# use rocket::launch;
|
|
|
|
|
#[launch]
|
2020-07-11 16:42:05 +00:00
|
|
|
|
fn rocket() -> rocket::Rocket {
|
|
|
|
|
# let req_fairing = rocket::fairing::AdHoc::on_request("example", |_, _| Box::pin(async {}));
|
|
|
|
|
# let res_fairing = rocket::fairing::AdHoc::on_response("example", |_, _| Box::pin(async {}));
|
|
|
|
|
|
|
|
|
|
rocket::ignite()
|
|
|
|
|
.attach(req_fairing)
|
|
|
|
|
.attach(res_fairing)
|
|
|
|
|
}
|
2017-07-07 03:46:43 +00:00
|
|
|
|
```
|
|
|
|
|
|
2018-10-16 05:50:35 +00:00
|
|
|
|
[`attach`]: @api/rocket/struct.Rocket.html#method.attach
|
|
|
|
|
[`Rocket`]: @api/rocket/struct.Rocket.html
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
2017-07-11 11:43:08 +00:00
|
|
|
|
Fairings are executed in the order in which they are attached: the first
|
|
|
|
|
attached fairing has its callbacks executed before all others. Because fairing
|
|
|
|
|
callbacks may not be commutative, the order in which fairings are attached may
|
|
|
|
|
be significant.
|
|
|
|
|
|
2017-07-07 03:46:43 +00:00
|
|
|
|
### Callbacks
|
|
|
|
|
|
2017-07-11 11:43:08 +00:00
|
|
|
|
There are four events for which Rocket issues fairing callbacks. Each of these
|
|
|
|
|
events is described below:
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
2017-07-11 11:43:08 +00:00
|
|
|
|
* **Attach (`on_attach`)**
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
|
|
|
|
An attach callback is called when a fairing is first attached via the
|
2018-10-16 05:50:35 +00:00
|
|
|
|
[`attach`](@api/rocket/struct.Rocket.html#method.attach) method. An attach
|
|
|
|
|
callback can arbitrarily modify the `Rocket` instance being constructed and
|
|
|
|
|
optionally abort launch. Attach fairings are commonly used to parse and
|
|
|
|
|
validate configuration values, aborting on bad configurations, and inserting
|
|
|
|
|
the parsed value into managed state for later retrieval.
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
2017-07-11 11:43:08 +00:00
|
|
|
|
* **Launch (`on_launch`)**
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
|
|
|
|
A launch callback is called immediately before the Rocket application has
|
|
|
|
|
launched. A launch callback can inspect the `Rocket` instance being
|
2017-07-11 11:43:08 +00:00
|
|
|
|
launched. A launch callback can be a convenient hook for launching services
|
|
|
|
|
related to the Rocket application being launched.
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
2017-07-11 11:43:08 +00:00
|
|
|
|
* **Request (`on_request`)**
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
|
|
|
|
A request callback is called just after a request is received. A request
|
|
|
|
|
callback can modify the request at will and peek into the incoming data. It
|
|
|
|
|
may not, however, abort or respond directly to the request; these issues are
|
|
|
|
|
better handled via request guards or via response callbacks.
|
|
|
|
|
|
2017-07-11 11:43:08 +00:00
|
|
|
|
* **Response (`on_response`)**
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
|
|
|
|
A response callback is called when a response is ready to be sent to the
|
2017-07-11 11:43:08 +00:00
|
|
|
|
client. A response callback can modify part or all of the response. As such,
|
|
|
|
|
a response fairing can be used to provide a response when the greater
|
2018-08-09 02:06:52 +00:00
|
|
|
|
application fails by rewriting **404** responses as desired. As another
|
2017-07-11 11:43:08 +00:00
|
|
|
|
example, response fairings can also be used to inject headers into all
|
|
|
|
|
outgoing responses.
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
|
|
|
|
## Implementing
|
|
|
|
|
|
2017-07-11 11:43:08 +00:00
|
|
|
|
Recall that a fairing is any type that implements the [`Fairing`] trait. A
|
|
|
|
|
`Fairing` implementation has one required method: [`info`], which returns an
|
|
|
|
|
[`Info`] structure. This structure is used by Rocket to assign a name to the
|
|
|
|
|
fairing and determine the set of callbacks the fairing is registering for. A
|
|
|
|
|
`Fairing` can implement any of the available callbacks: [`on_attach`],
|
|
|
|
|
[`on_launch`], [`on_request`], and [`on_response`]. Each callback has a default
|
|
|
|
|
implementation that does absolutely nothing.
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
2018-10-16 05:50:35 +00:00
|
|
|
|
[`Info`]: @api/rocket/fairing/struct.Info.html
|
|
|
|
|
[`info`]: @api/rocket/fairing/trait.Fairing.html#tymethod.info
|
|
|
|
|
[`on_attach`]: @api/rocket/fairing/trait.Fairing.html#method.on_attach
|
|
|
|
|
[`on_launch`]: @api/rocket/fairing/trait.Fairing.html#method.on_launch
|
|
|
|
|
[`on_request`]: @api/rocket/fairing/trait.Fairing.html#method.on_request
|
|
|
|
|
[`on_response`]: @api/rocket/fairing/trait.Fairing.html#method.on_response
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
2017-07-11 11:43:08 +00:00
|
|
|
|
### Requirements
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
2017-07-11 11:43:08 +00:00
|
|
|
|
A type implementing `Fairing` is required to be `Send + Sync + 'static`. This
|
|
|
|
|
means that the fairing must be sendable across thread boundaries (`Send`),
|
|
|
|
|
thread-safe (`Sync`), and have only static references, if any (`'static`). Note
|
|
|
|
|
that these bounds _do not_ prohibit a `Fairing` from holding state: the state
|
|
|
|
|
need simply be thread-safe and statically available or heap allocated.
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
2017-07-07 03:50:39 +00:00
|
|
|
|
### Example
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
|
|
|
|
Imagine that we want to record the number of `GET` and `POST` requests that our
|
|
|
|
|
application has received. While we could do this with request guards and managed
|
|
|
|
|
state, it would require us to annotate every `GET` and `POST` request with
|
|
|
|
|
custom types, polluting handler signatures. Instead, we can create a simple
|
|
|
|
|
fairing that acts globally.
|
|
|
|
|
|
2017-07-11 11:43:08 +00:00
|
|
|
|
The code for a `Counter` fairing below implements exactly this. The fairing
|
|
|
|
|
receives a request callback, where it increments a counter on each `GET` and
|
|
|
|
|
`POST` request. It also receives a response callback, where it responds to
|
|
|
|
|
unrouted requests to the `/counts` path by returning the recorded number of
|
|
|
|
|
counts.
|
2017-07-07 03:46:43 +00:00
|
|
|
|
|
|
|
|
|
```rust
|
2020-02-15 11:43:47 +00:00
|
|
|
|
use std::io::Cursor;
|
|
|
|
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
|
|
|
|
|
|
|
|
use rocket::{Request, Data, Response};
|
|
|
|
|
use rocket::fairing::{Fairing, Info, Kind};
|
|
|
|
|
use rocket::http::{Method, ContentType, Status};
|
|
|
|
|
|
2017-07-07 03:46:43 +00:00
|
|
|
|
struct Counter {
|
|
|
|
|
get: AtomicUsize,
|
|
|
|
|
post: AtomicUsize,
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-11 16:41:53 +00:00
|
|
|
|
#[rocket::async_trait]
|
2017-07-07 03:46:43 +00:00
|
|
|
|
impl Fairing for Counter {
|
2017-07-12 22:36:16 +00:00
|
|
|
|
// This is a request and response fairing named "GET/POST Counter".
|
2017-07-07 03:46:43 +00:00
|
|
|
|
fn info(&self) -> Info {
|
|
|
|
|
Info {
|
|
|
|
|
name: "GET/POST Counter",
|
|
|
|
|
kind: Kind::Request | Kind::Response
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-11 11:43:08 +00:00
|
|
|
|
// Increment the counter for `GET` and `POST` requests.
|
2020-10-21 03:22:32 +00:00
|
|
|
|
async fn on_request(&self, request: &mut Request<'_>, _: &mut Data) {
|
2017-07-07 03:46:43 +00:00
|
|
|
|
match request.method() {
|
|
|
|
|
Method::Get => self.get.fetch_add(1, Ordering::Relaxed),
|
|
|
|
|
Method::Post => self.post.fetch_add(1, Ordering::Relaxed),
|
|
|
|
|
_ => return
|
2020-02-15 11:43:47 +00:00
|
|
|
|
};
|
2017-07-07 03:46:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-23 20:08:49 +00:00
|
|
|
|
async fn on_response<'r>(&self, request: &'r Request<'_>, response: &mut Response<'r>) {
|
2020-07-11 16:41:53 +00:00
|
|
|
|
// Don't change a successful user's response, ever.
|
|
|
|
|
if response.status() != Status::NotFound {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Rewrite the response to return the current counts.
|
|
|
|
|
if request.method() == Method::Get && request.uri().path() == "/counts" {
|
|
|
|
|
let get_count = self.get.load(Ordering::Relaxed);
|
|
|
|
|
let post_count = self.post.load(Ordering::Relaxed);
|
|
|
|
|
let body = format!("Get: {}\nPost: {}", get_count, post_count);
|
|
|
|
|
|
|
|
|
|
response.set_status(Status::Ok);
|
|
|
|
|
response.set_header(ContentType::Plain);
|
|
|
|
|
response.set_sized_body(body.len(), Cursor::new(body));
|
|
|
|
|
}
|
2017-07-07 03:46:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2020-02-15 11:43:47 +00:00
|
|
|
|
The complete example can be found in the [`Fairing`
|
|
|
|
|
documentation](@api/rocket/fairing/trait.Fairing.html#example).
|
2017-07-11 11:43:08 +00:00
|
|
|
|
|
|
|
|
|
## Ad-Hoc Fairings
|
|
|
|
|
|
|
|
|
|
For simple occasions, implementing the `Fairing` trait can be cumbersome. This
|
|
|
|
|
is why Rocket provides the [`AdHoc`] type, which creates a fairing from a simple
|
2017-07-15 06:12:11 +00:00
|
|
|
|
function or closure. Using the `AdHoc` type is easy: simply call the
|
2017-07-11 11:43:08 +00:00
|
|
|
|
`on_attach`, `on_launch`, `on_request`, or `on_response` constructors on `AdHoc`
|
|
|
|
|
to create an `AdHoc` structure from a function or closure.
|
|
|
|
|
|
|
|
|
|
As an example, the code below creates a `Rocket` instance with two attached
|
2018-08-14 16:14:06 +00:00
|
|
|
|
ad-hoc fairings. The first, a launch fairing named "Launch Printer", simply
|
2019-01-30 12:10:39 +00:00
|
|
|
|
prints a message indicating that the application is about to launch. The
|
2018-08-14 16:14:06 +00:00
|
|
|
|
second named "Put Rewriter", a request fairing, rewrites the method of all
|
|
|
|
|
requests to be `PUT`.
|
2017-07-11 11:43:08 +00:00
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
use rocket::fairing::AdHoc;
|
|
|
|
|
use rocket::http::Method;
|
|
|
|
|
|
|
|
|
|
rocket::ignite()
|
2018-08-14 16:14:06 +00:00
|
|
|
|
.attach(AdHoc::on_launch("Launch Printer", |_| {
|
|
|
|
|
println!("Rocket is about to launch! Exciting! Here we go...");
|
2017-07-11 11:43:08 +00:00
|
|
|
|
}))
|
2020-01-08 16:03:05 +00:00
|
|
|
|
.attach(AdHoc::on_request("Put Rewriter", |req, _| Box::pin(async move {
|
2017-07-11 11:43:08 +00:00
|
|
|
|
req.set_method(Method::Put);
|
2020-01-08 16:03:05 +00:00
|
|
|
|
})));
|
2017-07-11 11:43:08 +00:00
|
|
|
|
```
|
|
|
|
|
|
2018-10-16 06:24:23 +00:00
|
|
|
|
[`AdHoc`]: @api/rocket/fairing/struct.AdHoc.html
|