rocket_community/form/form.rs
1use std::ops::{Deref, DerefMut};
2
3use crate::data::{Data, FromData, Outcome};
4use crate::form::prelude::{
5 parser::{Parser, RawStrParser},
6 *,
7};
8use crate::http::{ext::IntoOwned, RawStr};
9use crate::outcome::try_outcome;
10use crate::Request;
11
12/// A data guard for [`FromForm`] types.
13///
14/// This type implements the [`FromData`] trait. It provides a generic means to
15/// parse arbitrary structures from incoming form data.
16///
17/// See the [forms guide](https://rocket.rs/master/guide/requests#forms) for
18/// general form support documentation.
19///
20/// # Leniency
21///
22/// A `Form<T>` will parse successfully from an incoming form if the form
23/// contains a superset of the fields in `T`. Said another way, a `Form<T>`
24/// automatically discards extra fields without error. For instance, if an
25/// incoming form contains the fields "a", "b", and "c" while `T` only contains
26/// "a" and "c", the form _will_ parse as `Form<T>`. To parse strictly, use the
27/// [`Strict`](crate::form::Strict) form guard.
28///
29/// # Usage
30///
31/// This type can be used with any type that implements the `FromForm` trait.
32/// The trait can be automatically derived; see the [`FromForm`] documentation
33/// for more information on deriving or implementing the trait.
34///
35/// Because `Form` implements `FromData`, it can be used directly as a target of
36/// the `data = "<param>"` route parameter as long as its generic type
37/// implements the `FromForm` trait:
38///
39/// ```rust
40/// # #[macro_use] extern crate rocket_community as rocket;
41/// use rocket::form::Form;
42/// use rocket::http::RawStr;
43///
44/// #[derive(FromForm)]
45/// struct UserInput<'r> {
46/// value: &'r str
47/// }
48///
49/// #[post("/submit", data = "<user_input>")]
50/// fn submit_task(user_input: Form<UserInput<'_>>) -> String {
51/// format!("Your value: {}", user_input.value)
52/// }
53/// ```
54///
55/// A type of `Form<T>` automatically dereferences into an `&T` or `&mut T`,
56/// though you can also transform a `Form<T>` into a `T` by calling
57/// [`into_inner()`](Form::into_inner()). Thanks to automatic dereferencing, you
58/// can access fields of `T` transparently through a `Form<T>`, as seen above
59/// with `user_input.value`.
60///
61/// ## Errors
62///
63/// A `Form<T>` data guard may fail, forward, or succeed.
64///
65/// If a request's content-type is neither [`ContentType::Form`] nor
66/// [`ContentType::FormData`], the guard **forwards**.
67///
68/// If the request `ContentType` _does_ identify as a form but the form data
69/// does not parse as `T`, according to `T`'s [`FromForm`] implementation, the
70/// guard **fails**. The `Error` variant contains a vector of the [`Errors`]
71/// emitted by `T`'s `FromForm` parser. If the error is not caught by a
72/// [`form::Result<T>`](Result) or `Option<Form<T>>` data guard, the status code
73/// is set to [`Errors::status()`], and the corresponding error catcher is
74/// called.
75///
76/// Otherwise the guard **succeeds**.
77///
78/// [`ContentType::Form`]: crate::http::ContentType::Form
79/// [`ContentType::FormData`]: crate::http::ContentType::FormData
80///
81/// ## Data Limits
82///
83/// The total amount of data accepted by the `Form` data guard is limited by the
84/// following limits:
85///
86/// | Limit Name | Default | Description |
87/// |-------------|---------|------------------------------------|
88/// | `form` | 32KiB | total limit for url-encoded forms |
89/// | `data-form` | 2MiB | total limit for multipart forms |
90/// | `*` | N/A | each field type has its own limits |
91///
92/// As noted above, each form field type (a form guard) typically imposes its
93/// own limits. For example, the `&str` form guard imposes a data limit of
94/// `string` when multipart data is streamed.
95///
96/// ### URL-Encoded Forms
97///
98/// The `form` limit specifies the data limit for an entire url-encoded form
99/// data. It defaults to 32KiB. URL-encoded form data is percent-decoded, stored
100/// in-memory, and parsed into [`ValueField`]s. If the incoming data exceeds
101/// this limit, the `Form` data guard fails without attempting to parse fields
102/// with a `413: Payload Too Large` error.
103///
104/// ### Multipart Forms
105///
106/// The `data-form` limit specifies the data limit for an entire multipart form
107/// data stream. It defaults to 2MiB. Multipart data is streamed, and form
108/// fields are processed into [`DataField`]s or [`ValueField`]s as they arrive.
109/// If the commutative data received while streaming exceeds the limit, parsing
110/// is aborted, an error is created and pushed via [`FromForm::push_error()`],
111/// and the form is finalized.
112///
113/// ### Individual Fields
114///
115/// Individual fields _may_ have data limits as well. The type of the field
116/// determines whether there is a data limit. For instance, the `&str` type
117/// imposes the `string` data limit. Consult the type's documentation or
118/// [`FromFormField`] for details.
119///
120/// ### Changing Limits
121///
122/// To change data limits, set the `limits.form` and/or `limits.data-form`
123/// configuration parameters. For instance, to increase the URL-encoded forms
124/// limit to 128KiB for all environments, you might add the following to your
125/// `Rocket.toml`:
126///
127/// ```toml
128/// [global.limits]
129/// form = 128KiB
130/// ```
131///
132/// See the [`Limits`](crate::data::Limits) and [`config`](crate::config) docs
133/// for more.
134#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
135pub struct Form<T>(T);
136
137impl<T> Form<T> {
138 /// Consumes `self` and returns the inner value.
139 ///
140 /// Note that since `Form` implements [`Deref`] and [`DerefMut`] with
141 /// target `T`, reading and writing an inner value can be accomplished
142 /// transparently.
143 ///
144 /// # Example
145 ///
146 /// ```rust
147 /// # #[macro_use] extern crate rocket_community as rocket;
148 /// use rocket::form::Form;
149 ///
150 /// #[derive(FromForm)]
151 /// struct MyForm {
152 /// field: String,
153 /// }
154 ///
155 /// #[post("/submit", data = "<form>")]
156 /// fn submit(form: Form<MyForm>) -> String {
157 /// // We can read or mutate a value transparently:
158 /// let field: &str = &form.field;
159 ///
160 /// // To gain ownership, however, use `into_inner()`:
161 /// form.into_inner().field
162 /// }
163 /// ```
164 pub fn into_inner(self) -> T {
165 self.0
166 }
167}
168
169impl<T> From<T> for Form<T> {
170 #[inline]
171 fn from(val: T) -> Form<T> {
172 Form(val)
173 }
174}
175
176impl<'r, T: FromForm<'r>> Form<T> {
177 /// Leniently parses a `T` from a **percent-decoded**
178 /// `x-www-form-urlencoded` form string. Specifically, this method
179 /// implements [§5.1 of the WHATWG URL Living Standard] with the exception
180 /// of steps 3.4 and 3.5, which are assumed to already be reflected in
181 /// `string`, and then parses the fields as `T`.
182 ///
183 /// [§5.1 of the WHATWG URL Living Standard]: https://url.spec.whatwg.org/#application/x-www-form-urlencoded
184 ///
185 /// # Example
186 ///
187 /// ```rust
188 /// # extern crate rocket_community as rocket;
189 /// use rocket::form::{Form, FromForm};
190 ///
191 /// #[derive(FromForm)]
192 /// struct Pet<'r> {
193 /// name: &'r str,
194 /// wags: bool,
195 /// }
196 ///
197 /// let string = "name=Benson Wagger!&wags=true";
198 /// let pet: Pet<'_> = Form::parse(string).unwrap();
199 /// assert_eq!(pet.name, "Benson Wagger!");
200 /// assert_eq!(pet.wags, true);
201 /// ```
202 #[inline]
203 pub fn parse(string: &'r str) -> Result<'r, T> {
204 // WHATWG URL Living Standard 5.1 steps 1, 2, 3.1 - 3.3.
205 Self::parse_iter(Form::values(string))
206 }
207
208 /// Leniently parses a `T` from the **percent-decoded** `fields`.
209 /// Specifically, this method implements [§5.1 of the WHATWG URL Living
210 /// Standard] with the exception of step 3.
211 ///
212 /// [§5.1 of the WHATWG URL Living Standard]: https://url.spec.whatwg.org/#application/x-www-form-urlencoded
213 ///
214 /// # Example
215 ///
216 /// ```rust
217 /// # extern crate rocket_community as rocket;
218 /// use rocket::form::{Form, FromForm, ValueField};
219 ///
220 /// #[derive(FromForm)]
221 /// struct Pet<'r> {
222 /// name: &'r str,
223 /// wags: bool,
224 /// }
225 ///
226 /// let fields = vec![
227 /// ValueField::parse("name=Bob, the cat. :)"),
228 /// ValueField::parse("wags=no"),
229 /// ];
230 ///
231 /// let pet: Pet<'_> = Form::parse_iter(fields).unwrap();
232 /// assert_eq!(pet.name, "Bob, the cat. :)");
233 /// assert_eq!(pet.wags, false);
234 /// ```
235 pub fn parse_iter<I>(fields: I) -> Result<'r, T>
236 where
237 I: IntoIterator<Item = ValueField<'r>>,
238 {
239 // WHATWG URL Living Standard 5.1 steps 1, 2, 3.1 - 3.3.
240 let mut ctxt = T::init(Options::Lenient);
241 fields.into_iter().for_each(|f| T::push_value(&mut ctxt, f));
242 T::finalize(ctxt)
243 }
244}
245
246impl<T: for<'a> FromForm<'a> + 'static> Form<T> {
247 /// Leniently parses a `T` from a raw, `x-www-form-urlencoded` form string.
248 /// Specifically, this method implements [§5.1 of the WHATWG URL Living
249 /// Standard]. Because percent-decoding might modify the input string, the
250 /// output type `T` must be `'static`.
251 ///
252 /// [§5.1 of the WHATWG URL Living Standard]:https://url.spec.whatwg.org/#application/x-www-form-urlencoded
253 ///
254 /// # Example
255 ///
256 /// ```rust
257 /// # extern crate rocket_community as rocket;
258 /// use rocket::http::RawStr;
259 /// use rocket::form::{Form, FromForm};
260 ///
261 /// #[derive(FromForm)]
262 /// struct Pet {
263 /// name: String,
264 /// wags: bool,
265 /// }
266 ///
267 /// let string = RawStr::new("name=Benson+Wagger%21&wags=true");
268 /// let pet: Pet = Form::parse_encoded(string).unwrap();
269 /// assert_eq!(pet.name, "Benson Wagger!");
270 /// assert_eq!(pet.wags, true);
271 /// ```
272 pub fn parse_encoded(string: &RawStr) -> Result<'static, T> {
273 let buffer = SharedStack::new();
274 let mut ctxt = T::init(Options::Lenient);
275 for field in RawStrParser::new(&buffer, string) {
276 T::push_value(&mut ctxt, field)
277 }
278
279 T::finalize(ctxt).map_err(|e| e.into_owned())
280 }
281}
282
283impl Form<()> {
284 /// Returns an iterator of fields parsed from a `x-www-form-urlencoded` form
285 /// string. Specifically, this method implements steps 1, 2, and 3.1 - 3.3
286 /// of [§5.1 of the WHATWG URL Living Standard]. Fields in the returned
287 /// iterator _are not_ percent-decoded.
288 ///
289 /// [§5.1 of the WHATWG URL Living Standard]:https://url.spec.whatwg.org/#application/x-www-form-urlencoded
290 ///
291 /// # Example
292 ///
293 /// ```rust
294 /// # extern crate rocket_community as rocket;
295 /// use rocket::form::{Form, ValueField};
296 ///
297 /// let string = "name=Bobby Brown&&&email=me@rocket.rs";
298 /// let mut values = Form::values(string);
299 /// assert_eq!(values.next().unwrap(), ValueField::parse("name=Bobby Brown"));
300 /// assert_eq!(values.next().unwrap(), ValueField::parse("email=me@rocket.rs"));
301 /// assert!(values.next().is_none());
302 /// ```
303 pub fn values(string: &str) -> impl Iterator<Item = ValueField<'_>> {
304 // WHATWG URL Living Standard 5.1 steps 1, 2, 3.1 - 3.3.
305 string
306 .split('&')
307 .filter(|s| !s.is_empty())
308 .map(ValueField::parse)
309 }
310}
311
312impl<T> Deref for Form<T> {
313 type Target = T;
314
315 fn deref(&self) -> &Self::Target {
316 &self.0
317 }
318}
319
320impl<T> DerefMut for Form<T> {
321 fn deref_mut(&mut self) -> &mut Self::Target {
322 &mut self.0
323 }
324}
325
326#[crate::async_trait]
327impl<'r, T: FromForm<'r>> FromData<'r> for Form<T> {
328 type Error = Errors<'r>;
329
330 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
331 use either::Either;
332
333 let mut parser = try_outcome!(Parser::new(req, data).await);
334 let mut context = T::init(Options::Lenient);
335 while let Some(field) = parser.next().await {
336 match field {
337 Ok(Either::Left(value)) => T::push_value(&mut context, value),
338 Ok(Either::Right(data)) => T::push_data(&mut context, data).await,
339 Err(e) => T::push_error(&mut context, e),
340 }
341 }
342
343 match T::finalize(context) {
344 Ok(value) => Outcome::Success(Form(value)),
345 Err(e) => Outcome::Error((e.status(), e)),
346 }
347 }
348}