[−][src]Trait rocket::fairing::Fairing
Trait implemented by fairings: Rocket's structured middleware.
Considerations
Fairings are a large hammer that can easily be abused and misused. If you
are considering writing a Fairing implementation, first consider if it is
appropriate to do so. While middleware is often the best solution to some
problems in other frameworks, it is often a suboptimal solution in Rocket.
This is because Rocket provides richer mechanisms such as request guards
and data guards that can be used to accomplish the same objective in a
cleaner, more composable, and more robust manner.
As a general rule of thumb, only globally applicable actions should be implemented via fairings. For instance, 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 the entire application. On the other hand, you should use a fairing to record timing and/or usage statistics or to implement global security policies.
Fairing Callbacks
There are four kinds of fairing callbacks: attach, launch, request, and
response. A fairing can request any combination of these callbacks through
the kind field of the Info structure returned from the info method.
Rocket will only invoke the callbacks set in the kind field.
The four callback kinds are as follows:
-
Attach (
on_attach)An attach callback, represented by the
on_attachmethod, is called when a fairing is first attached via theattachmethod. The state of theRocketinstance is, at this point, not finalized, as the user may still add additional information to theRocketinstance. As a result, it is unwise to depend on the state of theRocketinstance.An attach callback can arbitrarily modify the
Rocketinstance being constructed. It returnsOkif it would like launching to proceed nominally andErrotherwise. If an attach callback returnsErr, launch will be aborted. All attach callbacks are executed onlaunch, even if one or more signal a failure. -
Launch (
on_launch)A launch callback, represented by the
on_launchmethod, is called immediately before the Rocket application has launched. At this point, Rocket has opened a socket for listening but has not yet begun accepting connections. A launch callback can inspect theRocketinstance being launched. -
Request (
on_request)A request callback, represented by the
on_requestmethod, is called just after a request is received. At this point, Rocket has parsed the incoming HTTP intoRequestandDatastructures but has not routed the request. A request callback can modify the request at will andpeekinto 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. Any modifications to a request are persisted and can potentially alter how a request is routed. -
Response (
on_response)A response callback is called when a response is ready to be sent to the client. At this point, Rocket has completed all routing, including to error catchers, and has generated the would-be final response. A response callback can modify the response at will. For exammple, a response callback can provide a default response when the user fails to handle the request by checking for 404 responses.
Implementing
A Fairing implementation has one required method: info. A Fairing
can also implement any of the available callbacks: on_attach, on_launch,
on_request, and on_response. A Fairing must set the appropriate
callback kind in the kind field of the returned Info structure from
info for a callback to actually be called by Rocket.
Fairing Info
Every Fairing must implement the info method, which returns an
Info structure. This structure is used
by Rocket to:
-
Assign a name to the
Fairing.This is the
namefield, which can be any arbitrary string. Name your fairing something illustrative. The name will be logged during the application's launch procedures. -
Determine which callbacks to actually issue on the
Fairing.This is the
kindfield of typeKind. This field is a bitset that represents the kinds of callbacks the fairing wishes to receive. Rocket will only invoke the callbacks that are flagged in this set.Kindstructures can beord together to represent any combination of kinds of callbacks. For instance, to request launch and response callbacks, return akindfield with the valueKind::Launch | Kind::Response.
Restrictions
A Fairing must 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.
Example
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.
The Counter fairing below records the number of all GET and POST
requests received. It makes these counts available at a special '/counts'
path.
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}; #[derive(Default)] struct Counter { get: AtomicUsize, post: AtomicUsize, } impl Fairing for Counter { fn info(&self) -> Info { Info { name: "GET/POST Counter", kind: Kind::Request | Kind::Response } } fn on_request(&self, request: &mut Request, _: &Data) { if request.method() == Method::Get { self.get.fetch_add(1, Ordering::Relaxed); } else if request.method() == Method::Post { self.post.fetch_add(1, Ordering::Relaxed); } } fn on_response(&self, request: &Request, response: &mut Response) { // Don't change a successful user's response, ever. if response.status() != Status::NotFound { return } 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(Cursor::new(body)); } } }
Required Methods
fn info(&self) -> Info
Returns an Info structure
containing the name and Kind of
this fairing. The name can be any arbitrary string. Kind must be an
ord set of Kind variants.
This is the only required method of a Fairing. All other methods have
no-op default implementations.
Rocket will only dispatch callbacks to this fairing for the kinds in the
kind field of the returned Info structure. For instance, if
Kind::Launch | Kind::Request is used, then Rocket will only call the
on_launch and on_request methods of the fairing. Similarly, if
Kind::Response is used, Rocket will only call the on_response method
of this fairing.
Example
An info implementation for MyFairing: a fairing named "My Custom
Fairing" that is both a launch and response fairing.
use rocket::fairing::{Fairing, Info, Kind}; struct MyFairing; impl Fairing for MyFairing { fn info(&self) -> Info { Info { name: "My Custom Fairing", kind: Kind::Launch | Kind::Response } } }
Provided Methods
fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket>
The attach callback. Returns Ok if launch should proceed and Err if
launch should be aborted.
This method is called when a fairing is attached if Kind::Attach is in
the kind field of the Info structure for this fairing. The rocket
parameter is the Rocket instance that is currently being built for
this application.
Default Implementation
The default implementation of this method simply returns Ok(rocket).
fn on_launch(&self, rocket: &Rocket)
The launch callback.
This method is called just prior to launching the application if
Kind::Launch is in the kind field of the Info structure for this
fairing. The &Rocket parameter curresponds to the application that
will be launched.
Default Implementation
The default implementation of this method does nothing.
fn on_request(&self, request: &mut Request, data: &Data)
The request callback.
This method is called when a new request is received if Kind::Request
is in the kind field of the Info structure for this fairing. The
&mut Request parameter is the incoming request, and the &Data
parameter is the incoming data in the request.
Default Implementation
The default implementation of this method does nothing.
fn on_response(&self, request: &Request, response: &mut Response)
The response callback.
This method is called when a response is ready to be issued to a client
if Kind::Response is in the kind field of the Info structure for
this fairing. The &Request parameter is the request that was routed,
and the &mut Response parameter is the resulting response.
Default Implementation
The default implementation of this method does nothing.
Implementations on Foreign Types
impl<T: Fairing> Fairing for Arc<T>[src]
impl<T: Fairing> Fairing for Arc<T>fn info(&self) -> Info[src]
fn info(&self) -> Infofn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket>[src]
fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket>fn on_launch(&self, rocket: &Rocket)[src]
fn on_launch(&self, rocket: &Rocket)fn on_request(&self, request: &mut Request, data: &Data)[src]
fn on_request(&self, request: &mut Request, data: &Data)fn on_response(&self, request: &Request, response: &mut Response)[src]
fn on_response(&self, request: &Request, response: &mut Response)