mirror of https://github.com/rwf2/Rocket.git
Rename 'FromDataSimple' to 'FromData'. Make async.
The 'FromData' trait becomes 'FromTransformedData'.
This commit is contained in:
parent
854e90d39f
commit
33e95f4900
|
@ -22,7 +22,7 @@ use tokio::io::AsyncReadExt;
|
|||
|
||||
use rocket::request::Request;
|
||||
use rocket::outcome::Outcome::*;
|
||||
use rocket::data::{Transform::*, Transformed, Data, FromData, TransformFuture, FromDataFuture};
|
||||
use rocket::data::{Transform::*, Transformed, Data, FromTransformedData, TransformFuture, FromDataFuture};
|
||||
use rocket::response::{self, Responder, content};
|
||||
use rocket::http::Status;
|
||||
|
||||
|
@ -32,7 +32,7 @@ use serde::de::{Deserialize, Deserializer};
|
|||
#[doc(hidden)]
|
||||
pub use serde_json::{json_internal, json_internal_vec};
|
||||
|
||||
/// The JSON type: implements [`FromData`] and [`Responder`], allowing you to
|
||||
/// The JSON type: implements [`FromTransformedData`] and [`Responder`], allowing you to
|
||||
/// easily consume and respond with JSON.
|
||||
///
|
||||
/// ## Receiving JSON
|
||||
|
@ -128,7 +128,7 @@ pub enum JsonError<'a> {
|
|||
Parse(&'a str, serde_json::error::Error),
|
||||
}
|
||||
|
||||
impl<'a, T: Deserialize<'a>> FromData<'a> for Json<T> {
|
||||
impl<'a, T: Deserialize<'a>> FromTransformedData<'a> for Json<T> {
|
||||
type Error = JsonError<'a>;
|
||||
type Owned = String;
|
||||
type Borrowed = str;
|
||||
|
|
|
@ -20,7 +20,7 @@ use tokio::io::AsyncReadExt;
|
|||
|
||||
use rocket::request::Request;
|
||||
use rocket::outcome::Outcome::*;
|
||||
use rocket::data::{Data, FromData, FromDataFuture, Transform::*, TransformFuture, Transformed};
|
||||
use rocket::data::{Data, FromTransformedData, FromDataFuture, Transform::*, TransformFuture, Transformed};
|
||||
use rocket::http::Status;
|
||||
use rocket::response::{self, content, Responder};
|
||||
|
||||
|
@ -29,7 +29,7 @@ use serde::de::Deserialize;
|
|||
|
||||
pub use rmp_serde::decode::Error;
|
||||
|
||||
/// The `MsgPack` type: implements [`FromData`] and [`Responder`], allowing you
|
||||
/// The `MsgPack` type: implements [`FromTransformedData`] and [`Responder`], allowing you
|
||||
/// to easily consume and respond with MessagePack data.
|
||||
///
|
||||
/// ## Receiving MessagePack
|
||||
|
@ -113,7 +113,7 @@ impl<T> MsgPack<T> {
|
|||
/// Default limit for MessagePack is 1MB.
|
||||
const LIMIT: u64 = 1 << 20;
|
||||
|
||||
impl<'a, T: Deserialize<'a>> FromData<'a> for MsgPack<T> {
|
||||
impl<'a, T: Deserialize<'a>> FromTransformedData<'a> for MsgPack<T> {
|
||||
type Error = Error;
|
||||
type Owned = Vec<u8>;
|
||||
type Borrowed = [u8];
|
||||
|
|
|
@ -175,10 +175,10 @@ fn param_expr(seg: &Segment, ident: &syn::Ident, ty: &syn::Type) -> TokenStream2
|
|||
}
|
||||
|
||||
fn data_expr(ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
|
||||
define_vars_and_mods!(req, data, FromData, Outcome, Transform);
|
||||
define_vars_and_mods!(req, data, FromTransformedData, Outcome, Transform);
|
||||
let span = ident.span().unstable().join(ty.span()).unwrap().into();
|
||||
quote_spanned! { span =>
|
||||
let __transform = <#ty as #FromData>::transform(#req, #data).await;
|
||||
let __transform = <#ty as #FromTransformedData>::transform(#req, #data).await;
|
||||
|
||||
#[allow(unreachable_patterns, unreachable_code)]
|
||||
let __outcome = match __transform {
|
||||
|
@ -195,7 +195,7 @@ fn data_expr(ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
|
|||
};
|
||||
|
||||
#[allow(non_snake_case, unreachable_patterns, unreachable_code)]
|
||||
let #ident: #ty = match <#ty as #FromData>::from_data(#req, __outcome).await {
|
||||
let #ident: #ty = match <#ty as #FromTransformedData>::from_data(#req, __outcome).await {
|
||||
#Outcome::Success(__d) => __d,
|
||||
#Outcome::Forward(__d) => return #Outcome::Forward(__d),
|
||||
#Outcome::Failure((__c, _)) => return #Outcome::Failure(__c),
|
||||
|
|
|
@ -84,7 +84,7 @@ vars_and_mods! {
|
|||
handler => rocket::handler,
|
||||
log => rocket::logger,
|
||||
Outcome => rocket::Outcome,
|
||||
FromData => rocket::data::FromData,
|
||||
FromTransformedData => rocket::data::FromTransformedData,
|
||||
Transform => rocket::data::Transform,
|
||||
Query => rocket::request::Query,
|
||||
Request => rocket::Request,
|
||||
|
@ -252,7 +252,7 @@ macro_rules! route_attribute {
|
|||
/// | path | `<ident..>` | [`FromSegments`] |
|
||||
/// | query | `<ident>` | [`FromFormValue`] |
|
||||
/// | query | `<ident..>` | [`FromQuery`] |
|
||||
/// | data | `<ident>` | [`FromData`] |
|
||||
/// | data | `<ident>` | [`FromTransformedData`] |
|
||||
///
|
||||
/// The type of each function argument that _does not_ have a
|
||||
/// corresponding dynamic parameter is required to implement the
|
||||
|
@ -265,7 +265,7 @@ macro_rules! route_attribute {
|
|||
/// [`FromSegments`]: ../rocket/request/trait.FromSegments.html
|
||||
/// [`FromFormValue`]: ../rocket/request/trait.FromFormValue.html
|
||||
/// [`FromQuery`]: ../rocket/request/trait.FromQuery.html
|
||||
/// [`FromData`]: ../rocket/data/trait.FromData.html
|
||||
/// [`FromTransformedData`]: ../rocket/data/trait.FromTransformedData.html
|
||||
/// [`FromRequest`]: ../rocket/request/trait.FromRequest.html
|
||||
/// [`Route`]: ../rocket/struct.Route.html
|
||||
/// [`Responder`]: ../rocket/response/trait.Responder.html
|
||||
|
@ -297,7 +297,7 @@ macro_rules! route_attribute {
|
|||
///
|
||||
/// If a data guard fails, the request is forwarded if the
|
||||
/// [`Outcome`] is `Forward` or failed if the [`Outcome`] is
|
||||
/// `Failure`. See [`FromData` Outcomes] for further detail.
|
||||
/// `Failure`. See [`FromTransformedData` Outcomes] for further detail.
|
||||
///
|
||||
/// If all validation succeeds, the decorated function is called.
|
||||
/// The returned value is used to generate a [`Response`] via the
|
||||
|
@ -320,7 +320,7 @@ macro_rules! route_attribute {
|
|||
/// [`Outcome`]: ../rocket/enum.Outcome.html
|
||||
/// [`Response`]: ../rocket/struct.Response.html
|
||||
/// [`FromRequest` Outcomes]: ../rocket/request/trait.FromRequest.html#outcomes
|
||||
/// [`FromData` Outcomes]: ../rocket/data/trait.FromData.html#outcomes
|
||||
/// [`FromTransformedData` Outcomes]: ../rocket/data/trait.FromTransformedData.html#outcomes
|
||||
#[proc_macro_attribute]
|
||||
pub fn $name(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
emit!(attribute::route::route_attribute($method, args, input))
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use rocket::{Request, Data, Outcome::*};
|
||||
use rocket::local::blocking::Client;
|
||||
use rocket::request::Form;
|
||||
use rocket::data::{self, FromDataSimple};
|
||||
use rocket::data::{self, FromData};
|
||||
use rocket::http::{RawStr, ContentType, Status};
|
||||
use rocket::tokio::io::AsyncReadExt;
|
||||
|
||||
|
@ -16,19 +16,18 @@ struct Inner<'r> {
|
|||
|
||||
struct Simple(String);
|
||||
|
||||
impl FromDataSimple for Simple {
|
||||
#[async_trait]
|
||||
impl FromData for Simple {
|
||||
type Error = ();
|
||||
|
||||
fn from_data(_: &Request<'_>, data: Data) -> data::FromDataFuture<'static, Self, ()> {
|
||||
Box::pin(async {
|
||||
let mut string = String::new();
|
||||
let mut stream = data.open().take(64);
|
||||
if let Err(_) = stream.read_to_string(&mut string).await {
|
||||
return Failure((Status::InternalServerError, ()));
|
||||
}
|
||||
async fn from_data(_: &Request<'_>, data: Data) -> data::Outcome<Self, ()> {
|
||||
let mut string = String::new();
|
||||
let mut stream = data.open().take(64);
|
||||
if let Err(_) = stream.read_to_string(&mut string).await {
|
||||
return Failure((Status::InternalServerError, ()));
|
||||
}
|
||||
|
||||
Success(Simple(string))
|
||||
})
|
||||
Success(Simple(string))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::path::PathBuf;
|
|||
use rocket::{Request, Outcome::*};
|
||||
use rocket::http::ext::Normalize;
|
||||
use rocket::local::blocking::Client;
|
||||
use rocket::data::{self, Data, FromDataSimple};
|
||||
use rocket::data::{self, Data, FromData};
|
||||
use rocket::request::Form;
|
||||
use rocket::http::{Status, RawStr, ContentType};
|
||||
use rocket::tokio::io::AsyncReadExt;
|
||||
|
@ -24,16 +24,15 @@ struct Inner<'r> {
|
|||
|
||||
struct Simple(String);
|
||||
|
||||
impl FromDataSimple for Simple {
|
||||
#[async_trait]
|
||||
impl FromData for Simple {
|
||||
type Error = ();
|
||||
|
||||
fn from_data(_: &Request<'_>, data: Data) -> data::FromDataFuture<'static, Self, ()> {
|
||||
Box::pin(async move {
|
||||
let mut string = String::new();
|
||||
let mut stream = data.open().take(64);
|
||||
stream.read_to_string(&mut string).await.unwrap();
|
||||
Success(Simple(string))
|
||||
})
|
||||
async fn from_data(_: &Request<'_>, data: Data) -> data::Outcome<Self, ()> {
|
||||
let mut string = String::new();
|
||||
let mut stream = data.open().take(64);
|
||||
stream.read_to_string(&mut string).await.unwrap();
|
||||
Success(Simple(string))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,13 +22,13 @@ error[E0277]: the trait bound `Q: rocket::request::FromQuery<'_>` is not satisfi
|
|||
15 | fn f3(foo: Q) {} //~ ERROR FromQuery
|
||||
| ^^^^^^ the trait `rocket::request::FromQuery<'_>` is not implemented for `Q`
|
||||
|
||||
error[E0277]: the trait bound `Q: rocket::data::FromDataSimple` is not satisfied
|
||||
error[E0277]: the trait bound `Q: rocket::data::FromData` is not satisfied
|
||||
--> $DIR/route-type-errors.rs:18:7
|
||||
|
|
||||
18 | fn f4(foo: Q) {} //~ ERROR FromData
|
||||
| ^^^^^^ the trait `rocket::data::FromDataSimple` is not implemented for `Q`
|
||||
| ^^^^^^ the trait `rocket::data::FromData` is not implemented for `Q`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `rocket::data::FromData<'_>` for `Q`
|
||||
= note: required because of the requirements on the impl of `rocket::data::FromTransformedData<'_>` for `Q`
|
||||
|
||||
error[E0277]: the trait bound `Q: rocket::request::FromRequest<'_, '_>` is not satisfied
|
||||
--> $DIR/route-type-errors.rs:21:7
|
||||
|
|
|
@ -16,7 +16,7 @@ const PEEK_BYTES: usize = 512;
|
|||
///
|
||||
/// This type is the only means by which the body of a request can be retrieved.
|
||||
/// This type is not usually used directly. Instead, types that implement
|
||||
/// [`FromData`](crate::data::FromData) are used via code generation by
|
||||
/// [`FromTransformedData`](crate::data::FromTransformedData) are used via code generation by
|
||||
/// specifying the `data = "<var>"` route parameter as follows:
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -27,8 +27,8 @@ const PEEK_BYTES: usize = 512;
|
|||
/// # fn main() { }
|
||||
/// ```
|
||||
///
|
||||
/// Above, `DataGuard` can be any type that implements `FromData`. Note that
|
||||
/// `Data` itself implements `FromData`.
|
||||
/// Above, `DataGuard` can be any type that implements `FromTransformedData`. Note that
|
||||
/// `Data` itself implements `FromTransformedData`.
|
||||
///
|
||||
/// # Reading Data
|
||||
///
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::http::Status;
|
|||
use crate::request::Request;
|
||||
use crate::data::Data;
|
||||
|
||||
/// Type alias for the `Outcome` of a `FromData` conversion.
|
||||
/// Type alias for the `Outcome` of a `FromTransformedData` conversion.
|
||||
pub type Outcome<S, E> = outcome::Outcome<S, (Status, E), Data>;
|
||||
|
||||
impl<S, E> IntoOutcome<S, (Status, E), Data> for Result<S, E> {
|
||||
|
@ -36,14 +36,14 @@ impl<S, E> IntoOutcome<S, (Status, E), Data> for Result<S, E> {
|
|||
/// Indicates how incoming data should be transformed before being parsed and
|
||||
/// validated by a data guard.
|
||||
///
|
||||
/// See the documentation for [`FromData`] for usage details.
|
||||
/// See the documentation for [`FromTransformedData`] for usage details.
|
||||
pub enum Transform<T, B = T> {
|
||||
/// Indicates that data should be or has been transformed into the
|
||||
/// [`FromData::Owned`] variant.
|
||||
/// [`FromTransformedData::Owned`] variant.
|
||||
Owned(T),
|
||||
|
||||
/// Indicates that data should be or has been transformed into the
|
||||
/// [`FromData::Borrowed`] variant.
|
||||
/// [`FromTransformedData::Borrowed`] variant.
|
||||
Borrowed(B)
|
||||
}
|
||||
|
||||
|
@ -92,29 +92,29 @@ impl<T, B> Transform<T, B> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Type alias to the `outcome` input type of [`FromData::from_data`].
|
||||
/// Type alias to the `outcome` input type of [`FromTransformedData::from_data`].
|
||||
///
|
||||
/// This is a hairy type, but the gist is that this is a [`Transform`] where,
|
||||
/// for a given `T: FromData`:
|
||||
/// for a given `T: FromTransformedData`:
|
||||
///
|
||||
/// * The `Owned` variant is an `Outcome` whose `Success` value is of type
|
||||
/// [`FromData::Owned`].
|
||||
/// [`FromTransformedData::Owned`].
|
||||
///
|
||||
/// * The `Borrowed` variant is an `Outcome` whose `Success` value is a borrow
|
||||
/// of type [`FromData::Borrowed`].
|
||||
/// of type [`FromTransformedData::Borrowed`].
|
||||
///
|
||||
/// * In either case, the `Outcome`'s `Failure` variant is a value of type
|
||||
/// [`FromData::Error`].
|
||||
/// [`FromTransformedData::Error`].
|
||||
pub type Transformed<'a, T> =
|
||||
Transform<
|
||||
Outcome<<T as FromData<'a>>::Owned, <T as FromData<'a>>::Error>,
|
||||
Outcome<&'a <T as FromData<'a>>::Borrowed, <T as FromData<'a>>::Error>
|
||||
Outcome<<T as FromTransformedData<'a>>::Owned, <T as FromTransformedData<'a>>::Error>,
|
||||
Outcome<&'a <T as FromTransformedData<'a>>::Borrowed, <T as FromTransformedData<'a>>::Error>
|
||||
>;
|
||||
|
||||
/// Type alias to the `Future` returned by [`FromData::transform`].
|
||||
/// Type alias to the `Future` returned by [`FromTransformedData::transform`].
|
||||
pub type TransformFuture<'fut, T, E> = BoxFuture<'fut, Transform<Outcome<T, E>>>;
|
||||
|
||||
/// Type alias to the `Future` returned by [`FromData::from_data`].
|
||||
/// Type alias to the `Future` returned by [`FromTransformedData::from_data`].
|
||||
pub type FromDataFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
|
||||
|
||||
/// Trait implemented by data guards to derive a value from request body data.
|
||||
|
@ -123,16 +123,16 @@ pub type FromDataFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
|
|||
///
|
||||
/// 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.
|
||||
/// Validation and parsing/conversion is implemented through `FromTransformedData`. In
|
||||
/// other words, every type that implements `FromTransformedData` 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`.
|
||||
/// For many data guards, implementing [`FromData`] will be simpler and
|
||||
/// sufficient. All types that implement `FromData` automatically
|
||||
/// implement `FromTransformedData`. Thus, when possible, prefer to implement
|
||||
/// [`FromData`] instead of `FromTransformedData`.
|
||||
///
|
||||
/// [request guard]: crate::request::FromRequest
|
||||
///
|
||||
|
@ -140,7 +140,7 @@ pub type FromDataFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
|
|||
///
|
||||
/// 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
|
||||
/// `FromTransformedData` implementation for the type `T`. The handler will only be called
|
||||
/// if the guard returns successfully.
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -154,22 +154,22 @@ pub type FromDataFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
|
|||
/// # Transforming
|
||||
///
|
||||
/// Data guards can optionally _transform_ incoming data before processing it
|
||||
/// via an implementation of the [`FromData::transform()`] method. This is
|
||||
/// via an implementation of the [`FromTransformedData::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
|
||||
/// on a reference to body data, [`FromData`] should be implemented
|
||||
/// instead; it is simpler to implement and less error prone. All types that
|
||||
/// implement `FromDataSimple` automatically implement `FromData`.
|
||||
/// implement `FromData` automatically implement `FromTransformedData`.
|
||||
///
|
||||
/// When exercising a data guard, Rocket first calls the guard's
|
||||
/// [`FromData::transform()`] method and awaits on the returned future, then
|
||||
/// calls the guard's [`FromData::from_data()`] method and awaits on that
|
||||
/// returned future. Rocket stores data returned by [`FromData::transform()`] on
|
||||
/// [`FromTransformedData::transform()`] method and awaits on the returned future, then
|
||||
/// calls the guard's [`FromTransformedData::from_data()`] method and awaits on that
|
||||
/// returned future. Rocket stores data returned by [`FromTransformedData::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
|
||||
/// the associated [`FromTransformedData::Borrowed`] type and passing it as a
|
||||
/// `Transform::Borrowed`.
|
||||
///
|
||||
/// ## Example
|
||||
|
@ -198,7 +198,7 @@ pub type FromDataFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
|
|||
/// use tokio::io::AsyncReadExt;
|
||||
///
|
||||
/// use rocket::{Request, Data, Outcome::*};
|
||||
/// use rocket::data::{FromData, Outcome, Transform, Transformed, TransformFuture, FromDataFuture};
|
||||
/// use rocket::data::{FromTransformedData, Outcome, Transform, Transformed, TransformFuture, FromDataFuture};
|
||||
/// use rocket::http::Status;
|
||||
///
|
||||
/// const NAME_LIMIT: u64 = 256;
|
||||
|
@ -208,7 +208,7 @@ pub type FromDataFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
|
|||
/// Parse
|
||||
/// }
|
||||
///
|
||||
/// impl<'a> FromData<'a> for Name<'a> {
|
||||
/// impl<'a> FromTransformedData<'a> for Name<'a> {
|
||||
/// type Error = NameError;
|
||||
/// type Owned = String;
|
||||
/// type Borrowed = str;
|
||||
|
@ -279,7 +279,7 @@ pub type FromDataFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
|
|||
///
|
||||
/// # Provided Implementations
|
||||
///
|
||||
/// Rocket implements `FromData` for several built-in types. Their behavior is
|
||||
/// Rocket implements `FromTransformedData` for several built-in types. Their behavior is
|
||||
/// documented here.
|
||||
///
|
||||
/// * **Data**
|
||||
|
@ -288,24 +288,24 @@ pub type FromDataFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
|
|||
///
|
||||
/// _This implementation always returns successfully._
|
||||
///
|
||||
/// * **Option<T>** _where_ **T: FromData**
|
||||
/// * **Option<T>** _where_ **T: FromTransformedData**
|
||||
///
|
||||
/// The type `T` is derived from the incoming data using `T`'s `FromData`
|
||||
/// The type `T` is derived from the incoming data using `T`'s `FromTransformedData`
|
||||
/// implementation. If the derivation is a `Success`, the derived value is
|
||||
/// returned in `Some`. Otherwise, a `None` is returned.
|
||||
///
|
||||
/// _This implementation always returns successfully._
|
||||
///
|
||||
/// * **Result<T, T::Error>** _where_ **T: FromData**
|
||||
/// * **Result<T, T::Error>** _where_ **T: FromTransformedData**
|
||||
///
|
||||
/// The type `T` is derived from the incoming data using `T`'s `FromData`
|
||||
/// The type `T` is derived from the incoming data using `T`'s `FromTransformedData`
|
||||
/// 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**
|
||||
///
|
||||
/// **Note:** _An implementation of `FromData` for `String` is only available
|
||||
/// **Note:** _An implementation of `FromTransformedData` for `String` is only available
|
||||
/// when compiling in debug mode!_
|
||||
///
|
||||
/// Reads the entire request body into a `String`. If reading fails, returns
|
||||
|
@ -318,7 +318,7 @@ pub type FromDataFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
|
|||
///
|
||||
/// * **Vec<u8>**
|
||||
///
|
||||
/// **Note:** _An implementation of `FromData` for `Vec<u8>` is only
|
||||
/// **Note:** _An implementation of `FromTransformedData` for `Vec<u8>` is only
|
||||
/// available when compiling in debug mode!_
|
||||
///
|
||||
/// Reads the entire request body into a `Vec<u8>`. If reading fails,
|
||||
|
@ -329,24 +329,24 @@ pub type FromDataFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
|
|||
/// memory; since the user controls the size of the body, this is an obvious
|
||||
/// vector for a denial of service attack.
|
||||
///
|
||||
/// # Simplified `FromData`
|
||||
/// # Simplified `FromTransformedData`
|
||||
///
|
||||
/// For an example of a type that wouldn't require transformation, see the
|
||||
/// [`FromDataSimple`] documentation.
|
||||
pub trait FromData<'a>: Sized {
|
||||
/// [`FromData`] documentation.
|
||||
pub trait FromTransformedData<'a>: Sized {
|
||||
/// The associated error to be returned when the guard fails.
|
||||
type Error: Send;
|
||||
|
||||
/// The owned type returned from [`FromData::transform()`].
|
||||
/// The owned type returned from [`FromTransformedData::transform()`].
|
||||
///
|
||||
/// The trait bounds ensures that it is is possible to borrow an
|
||||
/// `&Self::Borrowed` from a value of this type.
|
||||
type Owned: Borrow<Self::Borrowed>;
|
||||
|
||||
/// The _borrowed_ type consumed by [`FromData::from_data()`] when
|
||||
/// [`FromData::transform()`] returns a [`Transform::Borrowed`].
|
||||
/// The _borrowed_ type consumed by [`FromTransformedData::from_data()`] when
|
||||
/// [`FromTransformedData::transform()`] returns a [`Transform::Borrowed`].
|
||||
///
|
||||
/// If [`FromData::from_data()`] returns a [`Transform::Owned`], this
|
||||
/// If [`FromTransformedData::from_data()`] returns a [`Transform::Owned`], this
|
||||
/// associated type should be set to `Self::Owned`.
|
||||
type Borrowed: ?Sized;
|
||||
|
||||
|
@ -385,14 +385,14 @@ pub trait FromData<'a>: Sized {
|
|||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate rocket;
|
||||
/// # use rocket::data::{Data, FromData, Transformed, Outcome};
|
||||
/// # fn f<'a>(outcome: Transformed<'a, Data>) -> Outcome<Data, <Data as FromData<'a>>::Error> {
|
||||
/// # use rocket::data::{Data, FromTransformedData, Transformed, Outcome};
|
||||
/// # fn f<'a>(outcome: Transformed<'a, Data>) -> Outcome<Data, <Data as FromTransformedData<'a>>::Error> {
|
||||
/// // If `Owned` was returned from `transform`:
|
||||
/// let data = try_outcome!(outcome.owned());
|
||||
/// # unimplemented!()
|
||||
/// # }
|
||||
///
|
||||
/// # fn g<'a>(outcome: Transformed<'a, Data>) -> Outcome<Data, <Data as FromData<'a>>::Error> {
|
||||
/// # fn g<'a>(outcome: Transformed<'a, Data>) -> Outcome<Data, <Data as FromTransformedData<'a>>::Error> {
|
||||
/// // If `Borrowed` was returned from `transform`:
|
||||
/// let data = try_outcome!(outcome.borrowed());
|
||||
/// # unimplemented!()
|
||||
|
@ -401,8 +401,8 @@ pub trait FromData<'a>: Sized {
|
|||
fn from_data(request: &'a Request<'_>, outcome: Transformed<'a, Self>) -> FromDataFuture<'a, Self, Self::Error>;
|
||||
}
|
||||
|
||||
/// The identity implementation of `FromData`. Always returns `Success`.
|
||||
impl<'a> FromData<'a> for Data {
|
||||
/// The identity implementation of `FromTransformedData`. Always returns `Success`.
|
||||
impl<'a> FromTransformedData<'a> for Data {
|
||||
type Error = std::convert::Infallible;
|
||||
type Owned = Data;
|
||||
type Borrowed = ();
|
||||
|
@ -418,12 +418,34 @@ impl<'a> FromData<'a> for Data {
|
|||
}
|
||||
}
|
||||
|
||||
/// A simple, less complex variant of [`FromData`].
|
||||
/// A simple, less complex variant of [`FromTransformedData`].
|
||||
///
|
||||
/// When transformation of incoming data isn't required, data guards should
|
||||
/// implement this trait instead of [`FromData`]. Any type that implements
|
||||
/// `FromDataSimple` automatically implements `FromData`. For a description of
|
||||
/// data guards, see the [`FromData`] documentation.
|
||||
/// implement this trait instead of [`FromTransformedData`]. Any type that implements
|
||||
/// `FromData` automatically implements `FromTransformedData`. For a description of
|
||||
/// data guards, see the [`FromTransformedData`] documentation.
|
||||
///
|
||||
/// ## Async Trait
|
||||
///
|
||||
/// [`FromData`] is an _async_ trait. Implementations of `FromData` must
|
||||
/// be decorated with an attribute of `#[rocket::async_trait]`:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::request::Request;
|
||||
/// use rocket::data::{self, Data, FromData};
|
||||
/// # struct MyType;
|
||||
/// # type MyError = String;
|
||||
///
|
||||
/// #[rocket::async_trait]
|
||||
/// impl FromData for MyType {
|
||||
/// type Error = MyError;
|
||||
///
|
||||
/// async fn from_data(req: &Request<'_>, data: Data) -> data::Outcome<Self, MyError> {
|
||||
/// /* .. */
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -438,7 +460,7 @@ impl<'a> FromData<'a> for Data {
|
|||
///
|
||||
/// `Person` has a custom serialization format, so the built-in `Json` type
|
||||
/// doesn't suffice. The format is `<name>:<age>` with `Content-Type:
|
||||
/// application/x-person`. You'd like to use `Person` as a `FromData` type so
|
||||
/// application/x-person`. You'd like to use `Person` as a `FromTransformedData` type so
|
||||
/// that you can retrieve it directly from a client's request body:
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -450,7 +472,7 @@ impl<'a> FromData<'a> for Data {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// A `FromDataSimple` implementation allowing this looks like:
|
||||
/// A `FromData` implementation allowing this looks like:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate rocket;
|
||||
|
@ -460,48 +482,46 @@ impl<'a> FromData<'a> for Data {
|
|||
/// #
|
||||
/// use std::io::Read;
|
||||
///
|
||||
/// use tokio::io::AsyncReadExt;
|
||||
///
|
||||
/// use rocket::{Request, Data, Outcome, Outcome::*};
|
||||
/// use rocket::data::{self, FromDataSimple, FromDataFuture};
|
||||
/// use rocket::data::{self, FromData, FromDataFuture};
|
||||
/// use rocket::http::{Status, ContentType};
|
||||
/// use rocket::tokio::io::AsyncReadExt;
|
||||
///
|
||||
/// // Always use a limit to prevent DoS attacks.
|
||||
/// const LIMIT: u64 = 256;
|
||||
///
|
||||
/// impl FromDataSimple for Person {
|
||||
/// #[rocket::async_trait]
|
||||
/// impl FromData for Person {
|
||||
/// type Error = String;
|
||||
///
|
||||
/// fn from_data(req: &Request, data: Data) -> FromDataFuture<'static, Self, String> {
|
||||
/// async fn from_data(req: &Request<'_>, data: Data) -> data::Outcome<Self, String> {
|
||||
/// // Ensure the content type is correct before opening the data.
|
||||
/// let person_ct = ContentType::new("application", "x-person");
|
||||
/// if req.content_type() != Some(&person_ct) {
|
||||
/// return Box::pin(async move { Outcome::Forward(data) });
|
||||
/// return Forward(data);
|
||||
/// }
|
||||
///
|
||||
/// Box::pin(async move {
|
||||
/// // Read the data into a String.
|
||||
/// let mut string = String::new();
|
||||
/// let mut reader = data.open().take(LIMIT);
|
||||
/// if let Err(e) = reader.read_to_string(&mut string).await {
|
||||
/// return Failure((Status::InternalServerError, format!("{:?}", e)));
|
||||
/// }
|
||||
/// // Read the data into a String.
|
||||
/// let mut string = String::new();
|
||||
/// let mut reader = data.open().take(LIMIT);
|
||||
/// if let Err(e) = reader.read_to_string(&mut string).await {
|
||||
/// return Failure((Status::InternalServerError, format!("{:?}", e)));
|
||||
/// }
|
||||
///
|
||||
/// // Split the string into two pieces at ':'.
|
||||
/// let (name, age) = match string.find(':') {
|
||||
/// Some(i) => (string[..i].to_string(), &string[(i + 1)..]),
|
||||
/// None => return Failure((Status::UnprocessableEntity, "':'".into()))
|
||||
/// };
|
||||
/// // Split the string into two pieces at ':'.
|
||||
/// let (name, age) = match string.find(':') {
|
||||
/// Some(i) => (string[..i].to_string(), &string[(i + 1)..]),
|
||||
/// None => return Failure((Status::UnprocessableEntity, "':'".into()))
|
||||
/// };
|
||||
///
|
||||
/// // Parse the age.
|
||||
/// let age: u16 = match age.parse() {
|
||||
/// Ok(age) => age,
|
||||
/// Err(_) => return Failure((Status::UnprocessableEntity, "Age".into()))
|
||||
/// };
|
||||
/// // Parse the age.
|
||||
/// let age: u16 = match age.parse() {
|
||||
/// Ok(age) => age,
|
||||
/// Err(_) => return Failure((Status::UnprocessableEntity, "Age".into()))
|
||||
/// };
|
||||
///
|
||||
/// // Return successfully.
|
||||
/// Success(Person { name, age })
|
||||
/// })
|
||||
/// // Return successfully.
|
||||
/// Success(Person { name, age })
|
||||
/// }
|
||||
/// }
|
||||
/// # #[post("/person", data = "<person>")]
|
||||
|
@ -510,7 +530,8 @@ impl<'a> FromData<'a> for Data {
|
|||
/// # fn person2(person: Result<Person, String>) { }
|
||||
/// # fn main() { }
|
||||
/// ```
|
||||
pub trait FromDataSimple: Sized {
|
||||
#[crate::async_trait]
|
||||
pub trait FromData: Sized {
|
||||
/// The associated error to be returned when the guard fails.
|
||||
type Error: Send + 'static;
|
||||
|
||||
|
@ -520,10 +541,10 @@ pub trait FromDataSimple: Sized {
|
|||
/// 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) -> FromDataFuture<'static, Self, Self::Error>;
|
||||
async fn from_data(request: &Request<'_>, data: Data) -> Outcome<Self, Self::Error>;
|
||||
}
|
||||
|
||||
impl<'a, T: FromDataSimple + 'a> FromData<'a> for T {
|
||||
impl<'a, T: FromData + 'a> FromTransformedData<'a> for T {
|
||||
type Error = T::Error;
|
||||
type Owned = Data;
|
||||
type Borrowed = ();
|
||||
|
@ -542,7 +563,7 @@ impl<'a, T: FromDataSimple + 'a> FromData<'a> for T {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: FromData<'a> + 'a> FromData<'a> for Result<T, T::Error> {
|
||||
impl<'a, T: FromTransformedData<'a> + 'a> FromTransformedData<'a> for Result<T, T::Error> {
|
||||
type Error = T::Error;
|
||||
type Owned = T::Owned;
|
||||
type Borrowed = T::Borrowed;
|
||||
|
@ -562,7 +583,7 @@ impl<'a, T: FromData<'a> + 'a> FromData<'a> for Result<T, T::Error> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: FromData<'a> + 'a> FromData<'a> for Option<T> {
|
||||
impl<'a, T: FromTransformedData<'a> + 'a> FromTransformedData<'a> for Option<T> {
|
||||
type Error = T::Error;
|
||||
type Owned = T::Owned;
|
||||
type Borrowed = T::Borrowed;
|
||||
|
@ -582,37 +603,37 @@ impl<'a, T: FromData<'a> + 'a> FromData<'a> for Option<T> {
|
|||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
impl FromDataSimple for String {
|
||||
#[crate::async_trait]
|
||||
impl FromData for String {
|
||||
type Error = std::io::Error;
|
||||
|
||||
#[inline(always)]
|
||||
fn from_data(_: &Request<'_>, data: Data) -> FromDataFuture<'static, Self, Self::Error> {
|
||||
async fn from_data(_: &Request<'_>, data: Data) -> Outcome<Self, Self::Error> {
|
||||
use tokio::io::AsyncReadExt;
|
||||
Box::pin(async {
|
||||
let mut string = String::new();
|
||||
let mut reader = data.open();
|
||||
match reader.read_to_string(&mut string).await {
|
||||
Ok(_) => Success(string),
|
||||
Err(e) => Failure((Status::BadRequest, e)),
|
||||
}
|
||||
})
|
||||
|
||||
let mut string = String::new();
|
||||
let mut reader = data.open();
|
||||
match reader.read_to_string(&mut string).await {
|
||||
Ok(_) => Success(string),
|
||||
Err(e) => Failure((Status::BadRequest, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
impl FromDataSimple for Vec<u8> {
|
||||
#[crate::async_trait]
|
||||
impl FromData for Vec<u8> {
|
||||
type Error = std::io::Error;
|
||||
|
||||
#[inline(always)]
|
||||
fn from_data(_: &Request<'_>, data: Data) -> FromDataFuture<'static, Self, Self::Error> {
|
||||
async fn from_data(_: &Request<'_>, data: Data) -> Outcome<Self, Self::Error> {
|
||||
use tokio::io::AsyncReadExt;
|
||||
Box::pin(async {
|
||||
let mut stream = data.open();
|
||||
let mut buf = Vec::new();
|
||||
match stream.read_to_end(&mut buf).await {
|
||||
Ok(_) => Success(buf),
|
||||
Err(e) => Failure((Status::BadRequest, e)),
|
||||
}
|
||||
})
|
||||
|
||||
let mut stream = data.open();
|
||||
let mut buf = Vec::new();
|
||||
match stream.read_to_end(&mut buf).await {
|
||||
Ok(_) => Success(buf),
|
||||
Err(e) => Failure((Status::BadRequest, e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@ mod from_data;
|
|||
|
||||
pub use self::data::Data;
|
||||
pub use self::data_stream::DataStream;
|
||||
pub use self::from_data::{FromData, FromDataFuture, FromDataSimple, Outcome, Transform, Transformed, TransformFuture};
|
||||
pub use self::from_data::{FromTransformedData, FromDataFuture, FromData, Outcome, Transform, Transformed, TransformFuture};
|
||||
|
|
|
@ -90,7 +90,7 @@ pub use self::info_kind::{Info, Kind};
|
|||
///
|
||||
/// [request guard]: crate::request::FromRequest
|
||||
/// [request guards]: crate::request::FromRequest
|
||||
/// [data guards]: crate::data::FromData
|
||||
/// [data guards]: crate::data::FromTransformedData
|
||||
///
|
||||
/// ## Fairing Callbacks
|
||||
///
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
//! processing next.
|
||||
//!
|
||||
//! The `Outcome` type is the return type of many of the core Rocket traits,
|
||||
//! including [`FromRequest`](crate::request::FromRequest), [`FromData`]
|
||||
//! including [`FromRequest`](crate::request::FromRequest), [`FromTransformedData`]
|
||||
//! [`Responder`]. It is also the return type of request handlers via the
|
||||
//! [`Response`](crate::response::Response) type.
|
||||
//!
|
||||
//! [`FromData`]: crate::data::FromData
|
||||
//! [`FromTransformedData`]: crate::data::FromTransformedData
|
||||
//! [`Responder`]: crate::response::Responder
|
||||
//!
|
||||
//! # Success
|
||||
|
@ -21,7 +21,7 @@
|
|||
//! A successful `Outcome<S, E, F>`, `Success(S)`, is returned from functions
|
||||
//! that complete successfully. The meaning of a `Success` outcome depends on
|
||||
//! the context. For instance, the `Outcome` of the `from_data` method of the
|
||||
//! [`FromData`] trait will be matched against the type expected by the user.
|
||||
//! [`FromTransformedData`] trait will be matched against the type expected by the user.
|
||||
//! For example, consider the following handler:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
|
@ -29,7 +29,7 @@
|
|||
//! fn hello(my_val: S) -> ... { }
|
||||
//! ```
|
||||
//!
|
||||
//! The [`FromData`] implementation for the type `S` returns an `Outcome` with a
|
||||
//! The [`FromTransformedData`] implementation for the type `S` returns an `Outcome` with a
|
||||
//! `Success(S)`. If `from_data` returns a `Success`, the `Success` value will
|
||||
//! be unwrapped and the value will be used as the value of `my_val`.
|
||||
//!
|
||||
|
@ -50,7 +50,7 @@
|
|||
//! fn hello(my_val: Result<S, E>) -> ... { }
|
||||
//! ```
|
||||
//!
|
||||
//! The [`FromData`] implementation for the type `S` returns an `Outcome` with a
|
||||
//! The [`FromTransformedData`] implementation for the type `S` returns an `Outcome` with a
|
||||
//! `Success(S)` and `Failure(E)`. If `from_data` returns a `Failure`, the
|
||||
//! `Failure` value will be unwrapped and the value will be used as the `Err`
|
||||
//! value of `my_val` while a `Success` will be unwrapped and used the `Ok`
|
||||
|
@ -71,7 +71,7 @@
|
|||
//! fn hello(my_val: S) -> ... { }
|
||||
//! ```
|
||||
//!
|
||||
//! The [`FromData`] implementation for the type `S` returns an `Outcome` with a
|
||||
//! The [`FromTransformedData`] implementation for the type `S` returns an `Outcome` with a
|
||||
//! `Success(S)`, `Failure(E)`, and `Forward(F)`. If the `Outcome` is a
|
||||
//! `Forward`, the `hello` handler isn't called. Instead, the incoming request
|
||||
//! is forwarded, or passed on to, the next matching route, if any. Ultimately,
|
||||
|
|
|
@ -22,7 +22,7 @@ pub enum FormParseError<'f> {
|
|||
Missing(&'f RawStr),
|
||||
}
|
||||
|
||||
/// Error returned by the [`FromData`](crate::data::FromData) implementations of
|
||||
/// Error returned by the [`FromTransformedData`](crate::data::FromTransformedData) implementations of
|
||||
/// [`Form`](crate::request::Form) and [`LenientForm`](crate::request::LenientForm).
|
||||
#[derive(Debug)]
|
||||
pub enum FormDataError<'f, E> {
|
||||
|
@ -37,13 +37,13 @@ pub enum FormDataError<'f, E> {
|
|||
Parse(E, &'f str)
|
||||
}
|
||||
|
||||
/// Alias to the type of form errors returned by the [`FromData`]
|
||||
/// Alias to the type of form errors returned by the [`FromTransformedData`]
|
||||
/// implementations of [`Form<T>`] where the [`FromForm`] implementation for `T`
|
||||
/// was derived.
|
||||
///
|
||||
/// This alias is particularly useful when "catching" form errors in routes.
|
||||
///
|
||||
/// [`FromData`]: crate::data::FromData
|
||||
/// [`FromTransformedData`]: crate::data::FromTransformedData
|
||||
/// [`Form<T>`]: crate::request::Form
|
||||
/// [`FromForm`]: crate::request::FromForm
|
||||
///
|
||||
|
|
|
@ -4,12 +4,12 @@ use tokio::io::AsyncReadExt;
|
|||
|
||||
use crate::outcome::Outcome::*;
|
||||
use crate::request::{Request, form::{FromForm, FormItems, FormDataError}};
|
||||
use crate::data::{Outcome, Transform, Transformed, Data, FromData, TransformFuture, FromDataFuture};
|
||||
use crate::data::{Outcome, Transform, Transformed, Data, FromTransformedData, TransformFuture, FromDataFuture};
|
||||
use crate::http::{Status, uri::{Query, FromUriParam}};
|
||||
|
||||
/// A data guard for parsing [`FromForm`] types strictly.
|
||||
///
|
||||
/// This type implements the [`FromData`] trait. It provides a generic means to
|
||||
/// This type implements the [`FromTransformedData`] trait. It provides a generic means to
|
||||
/// parse arbitrary structures from incoming form data.
|
||||
///
|
||||
/// # Strictness
|
||||
|
@ -27,7 +27,7 @@ use crate::http::{Status, uri::{Query, FromUriParam}};
|
|||
/// The trait can be automatically derived; see the [`FromForm`] documentation
|
||||
/// for more information on deriving or implementing the trait.
|
||||
///
|
||||
/// Because `Form` implements `FromData`, it can be used directly as a target of
|
||||
/// Because `Form` implements `FromTransformedData`, it can be used directly as a target of
|
||||
/// the `data = "<param>"` route parameter as long as its generic type
|
||||
/// implements the `FromForm` trait:
|
||||
///
|
||||
|
@ -183,7 +183,7 @@ impl<'f, T: FromForm<'f>> Form<T> {
|
|||
///
|
||||
/// All relevant warnings and errors are written to the console in Rocket
|
||||
/// logging format.
|
||||
impl<'f, T: FromForm<'f> + Send + 'f> FromData<'f> for Form<T> {
|
||||
impl<'f, T: FromForm<'f> + Send + 'f> FromTransformedData<'f> for Form<T> {
|
||||
type Error = FormDataError<'f, T::Error>;
|
||||
type Owned = String;
|
||||
type Borrowed = str;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use crate::request::{Request, form::{Form, FormDataError, FromForm}};
|
||||
use crate::data::{Data, Transformed, FromData, TransformFuture, FromDataFuture};
|
||||
use crate::data::{Data, Transformed, FromTransformedData, TransformFuture, FromDataFuture};
|
||||
use crate::http::uri::{Query, FromUriParam};
|
||||
|
||||
/// A data guard for parsing [`FromForm`] types leniently.
|
||||
///
|
||||
/// This type implements the [`FromData`] trait, and like [`Form`], provides a
|
||||
/// This type implements the [`FromTransformedData`] trait, and like [`Form`], provides a
|
||||
/// generic means to parse arbitrary structures from incoming form data. Unlike
|
||||
/// `Form`, this type uses a _lenient_ parsing strategy: forms that contains a
|
||||
/// superset of the expected fields (i.e, extra fields) will parse successfully.
|
||||
|
@ -24,7 +24,7 @@ use crate::http::uri::{Query, FromUriParam};
|
|||
/// The usage of a `LenientForm` type is equivalent to that of [`Form`], so we
|
||||
/// defer details to its documentation.
|
||||
///
|
||||
/// `LenientForm` implements `FromData`, so it can be used directly as a target
|
||||
/// `LenientForm` implements `FromTransformedData`, so it can be used directly as a target
|
||||
/// of the `data = "<param>"` route parameter. For instance, if some structure
|
||||
/// of type `T` implements the `FromForm` trait, an incoming form can be
|
||||
/// automatically parsed into the `T` structure with the following route and
|
||||
|
@ -93,7 +93,7 @@ impl<T> Deref for LenientForm<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'f, T: FromForm<'f> + Send + 'f> FromData<'f> for LenientForm<T> {
|
||||
impl<'f, T: FromForm<'f> + Send + 'f> FromTransformedData<'f> for LenientForm<T> {
|
||||
type Error = FormDataError<'f, T::Error>;
|
||||
type Owned = String;
|
||||
type Borrowed = str;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#[macro_use] extern crate rocket;
|
||||
|
||||
use rocket::Outcome::*;
|
||||
use rocket::{Request, Data};
|
||||
use rocket::request::{self, FromRequest};
|
||||
use rocket::outcome::IntoOutcome;
|
||||
|
||||
struct HasContentType;
|
||||
|
||||
|
@ -10,26 +10,19 @@ struct HasContentType;
|
|||
impl<'a, 'r> FromRequest<'a, 'r> for HasContentType {
|
||||
type Error = ();
|
||||
|
||||
async fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, ()> {
|
||||
if request.content_type().is_some() {
|
||||
Success(HasContentType)
|
||||
} else {
|
||||
Forward(())
|
||||
}
|
||||
async fn from_request(req: &'a Request<'r>) -> request::Outcome<Self, ()> {
|
||||
req.content_type().map(|_| HasContentType).or_forward(())
|
||||
}
|
||||
}
|
||||
|
||||
use rocket::data::{self, FromDataSimple};
|
||||
use rocket::data::{self, FromData};
|
||||
|
||||
impl FromDataSimple for HasContentType {
|
||||
#[rocket::async_trait]
|
||||
impl FromData for HasContentType {
|
||||
type Error = ();
|
||||
|
||||
fn from_data(request: &Request<'_>, data: Data) -> data::FromDataFuture<'static, Self, Self::Error> {
|
||||
Box::pin(futures::future::ready(if request.content_type().is_some() {
|
||||
Success(HasContentType)
|
||||
} else {
|
||||
Forward(data)
|
||||
}))
|
||||
async fn from_data(req: &Request<'_>, data: Data) -> data::Outcome<Self, ()> {
|
||||
req.content_type().map(|_| HasContentType).or_forward(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue