Improve fairing and request/data guard docs.

This commit is contained in:
Sergio Benitez 2017-06-24 18:31:22 -07:00
parent 150aef7764
commit dfbd3265f3
5 changed files with 180 additions and 76 deletions

View File

@ -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());

View File

@ -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.

View File

@ -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&lt;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&lt;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&lt;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) {

View File

@ -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

View File

@ -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)
///