Trait rocket::data::FromData [−][src]
pub trait FromData<'a>: Sized {
type Error;
type Owned: Borrow<Self::Borrowed>;
type Borrowed: ?Sized;
fn transform(
request: &Request<'_>,
data: Data
) -> Transform<Outcome<Self::Owned, Self::Error>>;
fn from_data(
request: &Request<'_>,
outcome: Transformed<'a, Self>
) -> Outcome<Self, Self::Error>;
}Expand description
Trait implemented by data guards to derive a value from request body data.
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.
Data guards are used as the target of the data route attribute parameter.
A handler can have at most one data guard.
For many data guards, implementing FromDataSimple will be simpler and
sufficient. All types that implement FromDataSimple automatically
implement FromData. Thus, when possible, prefer to implement
FromDataSimple instead of FromData.
Example
In the example below, var is used as the argument name for the data guard
type DataGuard. When the submit route matches, Rocket will call the
FromData implementation for the type T. The handler will only be called
if the guard returns successfully.
#[post("/submit", data = "<var>")]
fn submit(var: DataGuard) { /* ... */ }Transforming
Data guards can optionally transform incoming data before processing it
via an implementation of the FromData::transform() method. This is
useful when a data guard requires or could benefit from a reference to body
data as opposed to an owned version. If a data guard has no need to operate
on a reference to body data, FromDataSimple should be implemented
instead; it is simpler to implement and less error prone. All types that
implement FromDataSimple automatically implement FromData.
When exercising a data guard, Rocket first calls the guard’s
FromData::transform() method and then subsequently calls the guard’s
FromData::from_data() method. Rocket stores data returned by
FromData::transform() on the stack. If transform returns a
Transform::Owned, Rocket moves the data back to the data guard in the
subsequent from_data call as a Transform::Owned. If instead transform
returns a Transform::Borrowed variant, Rocket calls borrow() on the
owned value, producing a borrow of the associated FromData::Borrowed
type and passing it as a Transform::Borrowed.
Example
Consider a data guard type that wishes to hold a slice to two different parts of the incoming data:
struct Name<'a> {
first: &'a str,
last: &'a str
}Without the ability to transform into a borrow, implementing such a data
guard would be impossible. With transformation, however, we can instruct
Rocket to produce a borrow to a Data that has been transformed into a
String (an &str).
use std::io::{self, Read};
use rocket::{Request, Data, Outcome::*};
use rocket::data::{FromData, Outcome, Transform, Transformed};
use rocket::http::Status;
const NAME_LIMIT: u64 = 256;
enum NameError {
Io(io::Error),
Parse
}
impl<'a> FromData<'a> for Name<'a> {
type Error = NameError;
type Owned = String;
type Borrowed = str;
fn transform(_: &Request, data: Data) -> Transform<Outcome<Self::Owned, Self::Error>> {
let mut stream = data.open().take(NAME_LIMIT);
let mut string = String::with_capacity((NAME_LIMIT / 2) as usize);
let outcome = match stream.read_to_string(&mut string) {
Ok(_) => Success(string),
Err(e) => Failure((Status::InternalServerError, NameError::Io(e)))
};
// Returning `Borrowed` here means we get `Borrowed` in `from_data`.
Transform::Borrowed(outcome)
}
fn from_data(_: &Request, outcome: Transformed<'a, Self>) -> Outcome<Self, Self::Error> {
// Retrieve a borrow to the now transformed `String` (an &str). This
// is only correct because we know we _always_ return a `Borrowed` from
// `transform` above.
let string = outcome.borrowed()?;
// Perform a crude, inefficient parse.
let splits: Vec<&str> = string.split(" ").collect();
if splits.len() != 2 || splits.iter().any(|s| s.is_empty()) {
return Failure((Status::UnprocessableEntity, NameError::Parse));
}
// Return successfully.
Success(Name { first: splits[0], last: splits[1] })
}
}Outcomes
The returned Outcome of a from_data call determines how the incoming
request will be processed.
-
Success(S)
If the
OutcomeisSuccess, then theSuccessvalue will be used as the value for the data parameter. As long as all other parsed types succeed, the request will be handled by the requesting handler. -
Failure(Status, E)
If the
OutcomeisFailure, the request will fail with the given status code and error. The designated errorCatcherwill be used to respond to the request. Note that users can request types ofResult<S, E>andOption<S>to catchFailures and retrieve the error value. -
Forward(Data)
If the
OutcomeisForward, the request will be forwarded to the next matching request. This requires that no data has been read from theDataparameter. Note that users can request anOption<S>to catchForwards.
Provided Implementations
Rocket implements FromData for several built-in types. Their behavior is
documented here.
-
Data
The identity implementation; simply returns
Datadirectly.This implementation always returns successfully.
-
Option<T> where T: FromData
The type
Tis derived from the incoming data usingT’sFromDataimplementation. If the derivation is aSuccess, the derived value is returned inSome. Otherwise, aNoneis returned.This implementation always returns successfully.
-
Result<T, T::Error> where T: FromData
The type
Tis derived from the incoming data usingT’sFromDataimplementation. If derivation is aSuccess, the value is returned inOk. If the derivation is aFailure, the error value is returned inErr. If the derivation is aForward, the request is forwarded. -
String
Note: An implementation of
FromDataforStringis only available when compiling in debug mode!Reads the entire request body into a
String. If reading fails, returns aFailurewith the correspondingio::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>
Note: An implementation of
FromDataforVec<u8>is only available when compiling in debug mode!Reads the entire request body into a
Vec<u8>. If reading fails, returns aFailurewith the correspondingio::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.
Simplified FromData
For an example of a type that wouldn’t require transformation, see the
FromDataSimple documentation.
Associated Types
The owned type returned from FromData::transform().
The trait bounds ensures that it is is possible to borrow an
&Self::Borrowed from a value of this type.
The borrowed type consumed by FromData::from_data() when
FromData::transform() returns a Transform::Borrowed.
If FromData::from_data() returns a Transform::Owned, this
associated type should be set to Self::Owned.
Required methods
Transforms data into a value of type Self::Owned.
If this method returns a Transform::Owned(Self::Owned), then
from_data should subsequently be called with a data value of
Transform::Owned(Self::Owned). If this method returns a
Transform::Borrowed(Self::Owned), from_data should subsequently be
called with a data value of Transform::Borrowed(&Self::Borrowed). In
other words, the variant of Transform returned from this method is
used to determine which variant of Transform should be passed to the
from_data method. Rocket always makes the subsequent call correctly.
It is very unlikely that a correct implementation of this method is
capable of returning either of an Owned or Borrowed variant.
Instead, this method should return exactly one of these variants.
If transformation succeeds, an outcome of Success is returned.
If the data is not appropriate given the type of Self, Forward is
returned. On failure, Failure is returned.
Validates, parses, and converts the incoming request body data into an
instance of Self.
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 or validation fails, Failure is returned.
Example
When implementing this method, you rarely need to destruct the outcome
parameter. Instead, the first line of the method should be one of the
following:
// If `Owned` was returned from `transform`:
let data = outcome.owned()?;
// If `Borrowed` was returned from `transform`:
let data = outcome.borrowed()?;Implementations on Foreign Types
Implementors
The identity implementation of FromData. Always returns Success.
Parses a Form from incoming form data.
If the content type of the request data is not
application/x-www-form-urlencoded, Forwards the request. If the form
data cannot be parsed into a T, a Failure with status code
UnprocessableEntity is returned. If the form string is malformed, a
Failure with status code BadRequest is returned. Finally, if reading the
incoming stream fails, returns a Failure with status code
InternalServerError. In all failure cases, the raw form string is returned
if it was able to be retrieved from the incoming stream.
All relevant warnings and errors are written to the console in Rocket logging format.