rocket/request/form/lenient.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
use std::ops::Deref;
use request::{Request, form::{Form, FormDataError, FromForm}};
use data::{Data, Transform, Transformed, FromData, Outcome};
use http::uri::{Query, FromUriParam};
/// A data guard for parsing [`FromForm`] types leniently.
///
/// This type implements the [`FromData`] 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.
///
/// # Leniency
///
/// A `LenientForm<T>` will parse successfully from an incoming form if the form
/// contains a superset of the fields in `T`. Said another way, a
/// `LenientForm<T>` automatically discards extra fields without error. For
/// instance, if an incoming form contains the fields "a", "b", and "c" while
/// `T` only contains "a" and "c", the form _will_ parse as `LenientForm<T>`.
///
/// # Usage
///
/// 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
/// 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
/// handler:
///
/// ```rust
/// # #![feature(proc_macro_hygiene, decl_macro)]
/// # #[macro_use] extern crate rocket;
/// use rocket::request::LenientForm;
///
/// #[derive(FromForm)]
/// struct UserInput {
/// value: String
/// }
///
/// #[post("/submit", data = "<user_input>")]
/// fn submit_task(user_input: LenientForm<UserInput>) -> String {
/// format!("Your value: {}", user_input.value)
/// }
/// # fn main() { }
/// ```
///
/// ## Incoming Data Limits
///
/// A `LenientForm` obeys the same data limits as a `Form` and defaults to
/// 32KiB. The limit can be increased by setting the `limits.forms`
/// configuration parameter. For instance, to increase the forms limit to 512KiB
/// for all environments, you may add the following to your `Rocket.toml`:
///
/// ```toml
/// [global.limits]
/// forms = 524288
/// ```
#[derive(Debug)]
pub struct LenientForm<T>(pub T);
impl<T> LenientForm<T> {
/// Consumes `self` and returns the parsed value.
///
/// # Example
///
/// ```rust
/// # #![feature(proc_macro_hygiene, decl_macro)]
/// # #[macro_use] extern crate rocket;
/// use rocket::request::LenientForm;
///
/// #[derive(FromForm)]
/// struct MyForm {
/// field: String,
/// }
///
/// #[post("/submit", data = "<form>")]
/// fn submit(form: LenientForm<MyForm>) -> String {
/// form.into_inner().field
/// }
/// # fn main() { }
#[inline(always)]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> Deref for LenientForm<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<'f, T: FromForm<'f>> FromData<'f> for LenientForm<T> {
type Error = FormDataError<'f, T::Error>;
type Owned = String;
type Borrowed = str;
fn transform(r: &Request, d: Data) -> Transform<Outcome<Self::Owned, Self::Error>> {
<Form<T>>::transform(r, d)
}
fn from_data(_: &Request, o: Transformed<'f, Self>) -> Outcome<Self, Self::Error> {
<Form<T>>::from_data(o.borrowed()?, false).map(LenientForm)
}
}
impl<'f, A, T: FromUriParam<Query, A> + FromForm<'f>> FromUriParam<Query, A> for LenientForm<T> {
type Target = T::Target;
#[inline(always)]
fn from_uri_param(param: A) -> Self::Target {
T::from_uri_param(param)
}
}