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) } }