mirror of
https://github.com/rwf2/Rocket.git
synced 2025-02-16 21:52:08 +00:00
Improve fairing and request/data guard docs.
This commit is contained in:
parent
150aef7764
commit
dfbd3265f3
@ -289,7 +289,7 @@ impl ConfigBuilder {
|
||||
/// assert!(config.is_ok());
|
||||
///
|
||||
/// let config = Config::build(Environment::Staging)
|
||||
/// .address("?")
|
||||
/// .address("definitely not an address!")
|
||||
/// .finalize();
|
||||
///
|
||||
/// assert!(config.is_err());
|
||||
|
@ -14,6 +14,8 @@ use http::Key;
|
||||
|
||||
/// Structure for Rocket application configuration.
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// A `Config` structure is typically built using the [build](#method.build)
|
||||
/// method and [ConfigBuilder](/rocket/config/struct.ConfigBuilder.html)
|
||||
/// methods:
|
||||
@ -28,6 +30,13 @@ use http::Key;
|
||||
/// .workers(12)
|
||||
/// .unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// ## General Configuration
|
||||
///
|
||||
/// For more information about Rocket's configuration, see the [`config`] module
|
||||
/// documentaiton.
|
||||
///
|
||||
/// [`config`]: /rocket/config/index.html
|
||||
#[derive(Clone)]
|
||||
pub struct Config {
|
||||
/// The environment that this configuration corresponds to.
|
||||
|
@ -27,18 +27,32 @@ impl<'a, S, E> IntoOutcome<S, (Status, E), Data> for Result<S, E> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait used to derive an object from incoming request data.
|
||||
/// Trait implemented by data guards to derive a value from request body data.
|
||||
///
|
||||
/// Types that implement this trait can be used as a target for the `data =
|
||||
/// "<param>"` route parmater, as illustrated below:
|
||||
/// # Data Guards
|
||||
///
|
||||
/// A data guard is a [request guard] that operates on a request's body data.
|
||||
/// Data guards validate, parse, and optionally convert request body data.
|
||||
/// Validation and parsing/conversion is implemented through `FromData`. In
|
||||
/// other words, every type that implements `FromData` is a data guard.
|
||||
///
|
||||
/// [request guard]: /rocket/request/trait.FromRequest.html
|
||||
///
|
||||
/// Data guards are used as the target of the `data` route attribute parameter.
|
||||
/// A handler can have at most one data guard.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// In the example below, `var` is used as the argument name for the data guard
|
||||
/// type `T`. When the `submit` route matches, Rocket will call the `FromData`
|
||||
/// implemention for the type `T`. The handler will only be called if the guard
|
||||
/// returns succesfully.
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// #[post("/submit", data = "<var>")]
|
||||
/// fn submit(var: T) -> ... { ... }
|
||||
/// ```
|
||||
///
|
||||
/// In this example, `T` can be any type that implements `FromData`.
|
||||
///
|
||||
/// # Outcomes
|
||||
///
|
||||
/// The returned [Outcome](/rocket/outcome/index.html) of a `from_data` call
|
||||
@ -64,6 +78,52 @@ impl<'a, S, E> IntoOutcome<S, (Status, E), Data> for Result<S, E> {
|
||||
/// matching request. This requires that no data has been read from the `Data`
|
||||
/// parameter. Note that users can request an `Option<S>` to catch `Forward`s.
|
||||
///
|
||||
/// # Provided Implementations
|
||||
///
|
||||
/// Rocket implements `FromData` for several built-in types. Their behavior is
|
||||
/// documented here.
|
||||
///
|
||||
/// * **Data**
|
||||
///
|
||||
/// The identity implementation; simply returns `Data` directly.
|
||||
///
|
||||
/// _This implementation always returns successfully._
|
||||
///
|
||||
/// * **Option<T>** _where_ **T: FromData**
|
||||
///
|
||||
/// The type `T` is derived from the incoming data using `T`'s `FromData`
|
||||
/// implementation. If the derivation is a `Success`, the dervived value is
|
||||
/// returned in `Some`. Otherwise, a `None` is returned.
|
||||
///
|
||||
/// _This implementation always returns successfully._
|
||||
///
|
||||
/// * **Result<T, T::Error>** _where_ **T: FromData**
|
||||
///
|
||||
/// The type `T` is derived from the incoming data using `T`'s `FromData`
|
||||
/// implementation. If derivation is a `Success`, the value is returned in
|
||||
/// `Ok`. If the derivation is a `Failure`, the error value is returned in
|
||||
/// `Err`. If the derivation is a `Forward`, the request is forwarded.
|
||||
///
|
||||
/// * **String**
|
||||
///
|
||||
/// Reads the entire request body into a `String`. If reading fails, returns
|
||||
/// a `Failure` with the corresponding `io::Error`.
|
||||
///
|
||||
/// **WARNING:** Do **not** use this implementation for anything _but_
|
||||
/// debugging. This is because the implementation reads the entire body into
|
||||
/// memory; since the user controls the size of the body, this is an obvious
|
||||
/// vector for a denial of service attack.
|
||||
///
|
||||
/// * **Vec<u8>**
|
||||
///
|
||||
/// Reads the entire request body into a `Vec<u8>`. If reading fails,
|
||||
/// returns a `Failure` with the corresponding `io::Error`.
|
||||
///
|
||||
/// **WARNING:** Do **not** use this implementation for anything _but_
|
||||
/// debugging. This is because the implementation reads the entire body into
|
||||
/// memory; since the user controls the size of the body, this is an obvious
|
||||
/// vector for a denial of service attack.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Say that you have a custom type, `Person`:
|
||||
@ -149,14 +209,15 @@ impl<'a, S, E> IntoOutcome<S, (Status, E), Data> for Result<S, E> {
|
||||
/// # fn main() { }
|
||||
/// ```
|
||||
pub trait FromData: Sized {
|
||||
/// The associated error to be returned when parsing fails.
|
||||
/// The associated error to be returned when the guard fails.
|
||||
type Error;
|
||||
|
||||
/// Parses an instance of `Self` from the incoming request body data.
|
||||
/// Validates, parses, and converts an instance of `Self` from the incoming
|
||||
/// request body data.
|
||||
///
|
||||
/// If the parse is successful, an outcome of `Success` is returned. If the
|
||||
/// data does not correspond to the type of `Self`, `Forward` is returned.
|
||||
/// If parsing fails, `Failure` is returned.
|
||||
/// If validation and parsing succeeds, an outcome of `Success` is returned.
|
||||
/// If the data is not appropriate given the type of `Self`, `Forward` is
|
||||
/// returned. If parsing fails, `Failure` is returned.
|
||||
fn from_data(request: &Request, data: Data) -> Outcome<Self, Self::Error>;
|
||||
}
|
||||
|
||||
@ -194,7 +255,6 @@ impl<T: FromData> FromData for Option<T> {
|
||||
impl FromData for String {
|
||||
type Error = io::Error;
|
||||
|
||||
// FIXME: Doc.
|
||||
fn from_data(_: &Request, data: Data) -> Outcome<Self, Self::Error> {
|
||||
let mut string = String::new();
|
||||
match data.open().read_to_string(&mut string) {
|
||||
@ -204,11 +264,9 @@ impl FromData for String {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME Implement this.
|
||||
impl FromData for Vec<u8> {
|
||||
type Error = io::Error;
|
||||
|
||||
// FIXME: Doc.
|
||||
fn from_data(_: &Request, data: Data) -> Outcome<Self, Self::Error> {
|
||||
let mut bytes = Vec::new();
|
||||
match data.open().read_to_end(&mut bytes) {
|
||||
|
@ -7,17 +7,19 @@
|
||||
//! fairings to rewrite or record information about requests and responses, or
|
||||
//! to perform an action once a Rocket application has launched.
|
||||
//!
|
||||
//! To learn more about writing a fairing, see the [`Fairing` trait
|
||||
//! documentation](/rocket/fairing/trait.Fairing.html).
|
||||
//! To learn more about writing a fairing, see the [`Fairing`] trait
|
||||
//! documentation. You can also use [`AdHoc`] to create a fairing on-the-fly
|
||||
//! from a closure or function.
|
||||
//!
|
||||
//! [`AdHoc`]: /rocket/fairing/enum.AdHoc.html
|
||||
//!
|
||||
//! ## Attaching
|
||||
//!
|
||||
//! You must inform Rocket about fairings that you wish to be active by calling
|
||||
//! the [`attach`](/rocket/struct.Rocket.html#method.attach) method on the
|
||||
//! [`Rocket`](/rocket/struct.Rocket.html) instance and passing in the
|
||||
//! appropriate [`Fairing`](/rocket/fairing/trait.Fairing.html). For instance,
|
||||
//! to attach fairings named `req_fairing` and `res_fairing` to a new Rocket
|
||||
//! instance, you might write:
|
||||
//! appropriate [`Fairing`]. For instance, to attach fairings named
|
||||
//! `req_fairing` and `res_fairing` to a new Rocket instance, you might write:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use rocket::fairing::AdHoc;
|
||||
@ -29,19 +31,23 @@
|
||||
//! ```
|
||||
//!
|
||||
//! Once a fairing is attached, Rocket will execute it at the appropiate time,
|
||||
//! which varies depending on the fairing implementation. See the
|
||||
//! [`Fairing`](/rocket/fairing/trait.Fairing.html) trait documentation for more
|
||||
//! information on the dispatching of fairing methods.
|
||||
//! which varies depending on the fairing implementation. See the [`Fairing`]
|
||||
//! trait documentation for more information on the dispatching of fairing
|
||||
//! methods.
|
||||
//!
|
||||
//! [`Fairing`]: /rocket/fairing/trait.Fairing.html
|
||||
//!
|
||||
//! ## Ordering
|
||||
//!
|
||||
//! `Fairing`s are executed in the same order in which they are attached: the
|
||||
//! first attached fairing has its callbacks executed before all others. Because
|
||||
//! fairing callbacks may not be commutative, it is important to communicate to
|
||||
//! the user every consequence of a fairing. Furthermore, a `Fairing` should
|
||||
//! take care to act locally so that the actions of other `Fairings` are not
|
||||
//! jeopardized. For instance, unless it is made abundantly clear, a fairing
|
||||
//! should not rewrite every request.
|
||||
//! `Fairing`s 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. Because of this, it is important to communicate
|
||||
//! to the user every consequence of a fairing.
|
||||
//!
|
||||
//! Furthermore, a `Fairing` should take care to act locally so that the actions
|
||||
//! of other `Fairings` are not jeopardized. For instance, unless it is made
|
||||
//! abundantly clear, a fairing should not rewrite every request.
|
||||
use {Rocket, Request, Response, Data};
|
||||
|
||||
mod fairings;
|
||||
@ -66,39 +72,33 @@ pub use self::info_kind::{Info, Kind};
|
||||
|
||||
/// Trait implemented by fairings: Rocket's structured middleware.
|
||||
///
|
||||
/// ## Fairing Information
|
||||
/// # Considerations
|
||||
///
|
||||
/// Every `Fairing` must implement the
|
||||
/// [`info`](/rocket/fairing/trait.Fairing.html#tymethod.info) method, which
|
||||
/// returns an [`Info`](http://localhost:8000/rocket/fairing/struct.Info.html)
|
||||
/// structure. This structure is used by Rocket to:
|
||||
/// 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
|
||||
/// apprioriate 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.
|
||||
///
|
||||
/// 1. Assign a name to the `Fairing`.
|
||||
/// 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 authenitcation 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.
|
||||
///
|
||||
/// This is the `name` field, which can be any arbitrary string. Name your
|
||||
/// fairing something illustrative. The name will be logged during the
|
||||
/// application's launch procedures.
|
||||
///
|
||||
/// 2. Determine which callbacks to actually issue on the `Fairing`.
|
||||
///
|
||||
/// This is the `kind` field of type
|
||||
/// [`Kind`](/rocket/fairing/struct.Kind.html). 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. `Kind`
|
||||
/// structures can be `or`d together to represent any combination of kinds
|
||||
/// of callbacks. For instance, to request launch and response callbacks,
|
||||
/// return a `kind` field with the value `Kind::Launch | Kind::Response`.
|
||||
///
|
||||
/// See the [top-level documentation](/rocket/fairing/) for more general
|
||||
/// information.
|
||||
/// [request guard]: /rocket/request/trait.FromRequest.html
|
||||
/// [request guards]: /rocket/request/trait.FromRequest.html
|
||||
/// [data guards]: /rocket/data/trait.FromData.html
|
||||
///
|
||||
/// ## Fairing Callbacks
|
||||
///
|
||||
/// There are four kinds of fairing callbacks: attach, launch, request, and
|
||||
/// response. As mentioned above, 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.
|
||||
/// 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:
|
||||
///
|
||||
@ -154,11 +154,37 @@ pub use self::info_kind::{Info, Kind};
|
||||
///
|
||||
/// # Implementing
|
||||
///
|
||||
/// A `Fairing` implementation has one required method: `info`. A `Fairing` can
|
||||
/// also implement any of the available callbacks: `on_attach`, `on_launch`,
|
||||
/// 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 issued by Rocket.
|
||||
/// [`info`] for a callback to actually be called by Rocket.
|
||||
///
|
||||
/// ## Fairing `Info`
|
||||
///
|
||||
/// Every `Fairing` must implement the [`info`] method, which returns an
|
||||
/// [`Info`](http://localhost:8000/rocket/fairing/struct.Info.html) structure.
|
||||
/// This structure is used by Rocket to:
|
||||
///
|
||||
/// 1. Assign a name to the `Fairing`.
|
||||
///
|
||||
/// This is the `name` field, which can be any arbitrary string. Name your
|
||||
/// fairing something illustrative. The name will be logged during the
|
||||
/// application's launch procedures.
|
||||
///
|
||||
/// 2. Determine which callbacks to actually issue on the `Fairing`.
|
||||
///
|
||||
/// This is the `kind` field of type
|
||||
/// [`Kind`](/rocket/fairing/struct.Kind.html). 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. `Kind`
|
||||
/// structures can be `or`d together to represent any combination of kinds
|
||||
/// of callbacks. For instance, to request launch and response callbacks,
|
||||
/// return a `kind` field with the value `Kind::Launch | Kind::Response`.
|
||||
///
|
||||
/// [`info`]: /rocket/fairing/trait.Fairing.html#tymethod.info
|
||||
///
|
||||
/// ## Restrictions
|
||||
///
|
||||
/// A `Fairing` must be `Send + Sync + 'static`. This means that the fairing
|
||||
/// must be sendable across thread boundaries (`Send`), thread-safe (`Sync`),
|
||||
@ -166,7 +192,7 @@ pub use self::info_kind::{Info, Kind};
|
||||
/// not_ prohibit a `Fairing` from holding state: the state need simply be
|
||||
/// thread-safe and statically available or heap allocated.
|
||||
///
|
||||
/// # Example
|
||||
/// ## 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
|
||||
|
@ -30,26 +30,37 @@ impl<S, E> IntoOutcome<S, (Status, E), ()> for Result<S, E> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait used to derive an object from incoming request metadata.
|
||||
/// Trait implemented by request guards to derive a value from incoming
|
||||
/// requests.
|
||||
///
|
||||
/// An arbitrary number of types that implement this trait can appear as
|
||||
/// parameters in a route handler, as illustrated below:
|
||||
/// # Request Guards
|
||||
///
|
||||
/// A request guard is a type that represents an arbitrary validation policy.
|
||||
/// The validation policy is implemented through `FromRequest`. In other words,
|
||||
/// every type that implements `FromRequest` is a request guard.
|
||||
///
|
||||
/// Request guards appear as inputs to handlers. An arbitrary number of request
|
||||
/// guards can appear as arguments in a route handler. Rocket will automatically
|
||||
/// invoke the `FromRequest` implementation for request guards before calling
|
||||
/// the handler. Rocket only dispatches requests to a handler when all of its
|
||||
/// guards pass.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// The following dummy handler makes use of three request guards, `A`, `B`, and
|
||||
/// `C`. An input type can be identified as a request guard if it is not named
|
||||
/// in the route attribute. This is why, for instance, `param` is not a request
|
||||
/// guard.
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// #[get("/")]
|
||||
/// fn index(a: A, b: B, c: C) -> ... { ... }
|
||||
/// #[get("/<param>")]
|
||||
/// fn index(param: isize, a: A, b: B, c: C) -> ... { ... }
|
||||
/// ```
|
||||
///
|
||||
/// In this example, `A`, `B`, and `C` can be any types that implements
|
||||
/// `FromRequest`. There can be any number of `FromRequest` types in the
|
||||
/// function signature. Note that unlike every other derived object in Rocket,
|
||||
/// `FromRequest` parameter names do not need to be declared in the route
|
||||
/// attribute.
|
||||
///
|
||||
/// Derivation of `FromRequest` arguments is always attemped in left-to-right
|
||||
/// declaration order. In the example above, for instance, the order will be `a`
|
||||
/// followed by `b` followed by `c`. If a deriviation fails, the following
|
||||
/// aren't attempted.
|
||||
/// Request guards always fire in left-to-right declaration order. In the
|
||||
/// example above, for instance, the order will be `a` followed by `b` followed
|
||||
/// by `c`. Failure is short-circuiting; if one guard fails, the remaining are
|
||||
/// not attempted.
|
||||
///
|
||||
/// # Outcomes
|
||||
///
|
||||
@ -59,8 +70,8 @@ impl<S, E> IntoOutcome<S, (Status, E), ()> for Result<S, E> {
|
||||
/// * **Success**(S)
|
||||
///
|
||||
/// If the `Outcome` is `Success`, then the `Success` value will be used as
|
||||
/// the value for the corresponding parameter. As long as all other parsed
|
||||
/// types succeed, the request will be handled.
|
||||
/// the value for the corresponding parameter. As long as all other guards
|
||||
/// succeed, the request will be handled.
|
||||
///
|
||||
/// * **Failure**(Status, E)
|
||||
///
|
||||
|
Loading…
Reference in New Issue
Block a user