rocket_community/form/
from_form_field.rs

1use std::borrow::Cow;
2use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
3use std::num::{
4    NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
5    NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
6};
7
8use time::{format_description::FormatItem, macros::format_description};
9use time::{Date, PrimitiveDateTime, Time};
10
11use crate::data::Capped;
12use crate::form::prelude::*;
13use crate::http::uncased::AsUncased;
14
15/// Implied form guard ([`FromForm`]) for parsing a single form field.
16///
17/// Types that implement `FromFormField` automatically implement [`FromForm`]
18/// via a blanket implementation. As such, all `FromFormField` types are form
19/// guards and can appear as the type of values in derived `FromForm` struct
20/// fields:
21///
22/// ```rust
23/// # extern crate rocket_community as rocket;
24/// # use rocket::form::FromForm;
25/// #[derive(FromForm)]
26/// struct Person<'r> {
27///     name: &'r str,
28///     age: u16
29/// }
30/// ```
31///
32/// # Semantics
33///
34/// The implementation of `FromForm` for a `T: FromFormField` type operates as
35/// follows:
36///
37///   * When parsing is **strict**, the parser accepts the _first_ value or data
38///     field with the corresponding field name and calls `T::from_value()` or
39///     `T::from_data()` with the field's value, respectively. If more than one
40///     field value is seen, an [`ErrorKind::Duplicate`) is emitted. If no
41///     matching field is seen, an [`ErrorKind::Missing`] is emitted. Otherwise,
42///     the result from the call is emitted.
43///
44///   * When parsing is **lenient**, the parser accepts the first _expected_
45///     value or data field with the corresponding field name and calls
46///     `T::from_value()` or `T::from_data()` with the field's value,
47///     respectively. Unexpected values, identified by returning an
48///     [`ErrorKind::Unexpected`] from `from_value()` or `from_data()` are
49///     ignored. Any additional fields with a matching field name are ignored.
50///     If no matching field is seen and `T` has a default, it is used,
51///     otherwise an [`ErrorKind::Missing`] is emitted.
52///
53/// # Deriving
54///
55/// `FromFormField` can be derived for C-like enums, where the generated
56/// implementation case-insensitively parses fields with values equal to the
57/// name of the variant or the value in `field()`.
58///
59/// ```rust
60/// # extern crate rocket_community as rocket;
61/// # use rocket::form::FromFormField;
62/// /// Fields with value `"simple"` parse as `Kind::Simple`. Fields with value
63/// /// `"fancy"` parse as `Kind::SoFancy`.
64/// #[derive(FromFormField)]
65/// enum Kind {
66///     Simple,
67///     #[field(value = "fancy")]
68///     SoFancy,
69/// }
70/// ```
71///
72/// # Provided Implementations
73///
74/// See [`FromForm`](crate::form::FromForm#provided-implementations) for a list
75/// of all form guards, including those implemented via `FromFormField`.
76///
77/// # Implementing
78///
79/// Implementing `FromFormField` requires implementing one or both of
80/// `from_value` or `from_data`, depending on whether the type can be parsed
81/// from a value field (text) and/or streaming binary data. Typically, a value
82/// can be parsed from either, either directly or by using request-local cache
83/// as an intermediary, and parsing from both should be preferred when sensible.
84///
85/// `FromFormField` is an async trait, so implementations must be decorated with
86/// an attribute of `#[rocket::async_trait]`:
87///
88/// ```rust
89/// # #[macro_use] extern crate rocket_community as rocket;
90/// # struct MyType;
91/// use rocket::form::{self, FromFormField, DataField, ValueField};
92///
93/// #[rocket::async_trait]
94/// impl<'r> FromFormField<'r> for MyType {
95///     fn from_value(field: ValueField<'r>) -> form::Result<'r, Self> {
96///         todo!("parse from a value or use default impl")
97///     }
98///
99///     async fn from_data(field: DataField<'r, '_>) -> form::Result<'r, Self> {
100///         todo!("parse from a value or use default impl")
101///     }
102/// }
103/// ```
104///
105/// ## Example
106///
107/// The following example parses a custom `Person` type with the format
108/// `$name:$data`, where `$name` is expected to be string and `data` is expected
109/// to be any slice of bytes.
110///
111/// ```rust
112/// # extern crate rocket_community as rocket;
113/// # use rocket::post;
114/// use rocket::data::ToByteUnit;
115/// use rocket::form::{self, FromFormField, DataField, ValueField};
116///
117/// use memchr::memchr;
118///
119/// struct Person<'r> {
120///     name: &'r str,
121///     data: &'r [u8]
122/// }
123///
124/// #[rocket::async_trait]
125/// impl<'r> FromFormField<'r> for Person<'r> {
126///     fn from_value(field: ValueField<'r>) -> form::Result<'r, Self> {
127///         match field.value.find(':') {
128///             Some(i) => Ok(Person {
129///                 name: &field.value[..i],
130///                 data: field.value[(i + 1)..].as_bytes()
131///             }),
132///             None => Err(form::Error::validation("does not contain ':'"))?
133///         }
134///     }
135///
136///     async fn from_data(field: DataField<'r, '_>) -> form::Result<'r, Self> {
137///         // Retrieve the configured data limit or use `256KiB` as default.
138///         let limit = field.request.limits()
139///             .get("person")
140///             .unwrap_or(256.kibibytes());
141///
142///         // Read the capped data stream, returning a limit error as needed.
143///         let bytes = field.data.open(limit).into_bytes().await?;
144///         if !bytes.is_complete() {
145///             Err((None, Some(limit)))?;
146///         }
147///
148///         // Store the bytes in request-local cache and split at ':'.
149///         let bytes = bytes.into_inner();
150///         let bytes = rocket::request::local_cache!(field.request, bytes);
151///         let (raw_name, data) = match memchr(b':', bytes) {
152///             Some(i) => (&bytes[..i], &bytes[(i + 1)..]),
153///             None => Err(form::Error::validation("does not contain ':'"))?
154///         };
155///
156///         // Try to parse the name as UTF-8 or return an error if it fails.
157///         let name = std::str::from_utf8(raw_name)?;
158///         Ok(Person { name, data })
159///     }
160/// }
161///
162/// use rocket::form::{Form, FromForm};
163///
164/// // The type can be used directly, if only one field is expected...
165/// #[post("/person", data = "<person>")]
166/// fn person(person: Form<Person<'_>>) { /* ... */ }
167///
168/// // ...or as a named field in another form guard...
169/// #[derive(FromForm)]
170/// struct NewPerson<'r> {
171///     person: Person<'r>
172/// }
173///
174/// #[post("/person", data = "<person>")]
175/// fn new_person(person: Form<NewPerson<'_>>) { /* ... */ }
176/// ```
177// NOTE: Ideally, we would have two traits instead one with two fallible
178// methods: `FromFormValue` and `FromFormData`. This would be especially nice
179// for use with query values, where `FromFormData` would make no sense.
180//
181// However, blanket implementations of `FromForm` for these traits would result
182// in duplicate implementations of `FromForm`; we need specialization to resolve
183// this concern. Thus, for now, we keep this as one trait.
184#[crate::async_trait]
185pub trait FromFormField<'v>: Send + Sized {
186    /// Parse a value of `T` from a form value field.
187    ///
188    /// The default implementation returns an error of
189    /// [`ValueField::unexpected()`].
190    fn from_value(field: ValueField<'v>) -> Result<'v, Self> {
191        Err(field.unexpected())?
192    }
193
194    /// Parse a value of `T` from a form data field.
195    ///
196    /// The default implementation returns an error of
197    /// [`DataField::unexpected()`].
198    async fn from_data(field: DataField<'v, '_>) -> Result<'v, Self> {
199        Err(field.unexpected())?
200    }
201
202    /// Returns a default value, if any exists, to be used during lenient
203    /// parsing when the form field is missing.
204    ///
205    /// A return value of `None` means that field is required to exist and parse
206    /// successfully, always. A return value of `Some(default)` means that
207    /// `default` should be used when a field is missing.
208    ///
209    /// The default implementation returns `None`.
210    fn default() -> Option<Self> {
211        None
212    }
213}
214
215#[doc(hidden)]
216pub struct FromFieldContext<'v, T: FromFormField<'v>> {
217    field_name: Option<NameView<'v>>,
218    field_value: Option<&'v str>,
219    opts: Options,
220    value: Option<Result<'v, T>>,
221    pushes: usize,
222}
223
224impl<'v, T: FromFormField<'v>> FromFieldContext<'v, T> {
225    fn should_push(&mut self) -> bool {
226        self.pushes += 1;
227        self.value.is_none()
228    }
229
230    fn push(&mut self, name: NameView<'v>, result: Result<'v, T>) {
231        fn is_unexpected(e: &Errors<'_>) -> bool {
232            matches!(e.last().map(|e| &e.kind), Some(ErrorKind::Unexpected))
233        }
234
235        self.field_name = Some(name);
236        match result {
237            Err(e) if !self.opts.strict && is_unexpected(&e) => { /* ok */ }
238            result => self.value = Some(result),
239        }
240    }
241}
242
243#[crate::async_trait]
244impl<'v, T: FromFormField<'v>> FromForm<'v> for T {
245    type Context = FromFieldContext<'v, T>;
246
247    fn init(opts: Options) -> Self::Context {
248        FromFieldContext {
249            opts,
250            field_name: None,
251            field_value: None,
252            value: None,
253            pushes: 0,
254        }
255    }
256
257    fn push_value(ctxt: &mut Self::Context, field: ValueField<'v>) {
258        if ctxt.should_push() {
259            ctxt.field_value = Some(field.value);
260            ctxt.push(field.name, Self::from_value(field))
261        }
262    }
263
264    async fn push_data(ctxt: &mut FromFieldContext<'v, T>, field: DataField<'v, '_>) {
265        if ctxt.should_push() {
266            ctxt.push(field.name, Self::from_data(field).await);
267        }
268    }
269
270    fn finalize(ctxt: Self::Context) -> Result<'v, Self> {
271        let mut errors = match ctxt.value {
272            Some(Ok(val)) if !ctxt.opts.strict || ctxt.pushes <= 1 => return Ok(val),
273            Some(Ok(_)) => Errors::from(ErrorKind::Duplicate),
274            Some(Err(errors)) => errors,
275            None if !ctxt.opts.strict => match <T as FromFormField>::default() {
276                Some(default) => return Ok(default),
277                None => Errors::from(ErrorKind::Missing),
278            },
279            None => Errors::from(ErrorKind::Missing),
280        };
281
282        if let Some(name) = ctxt.field_name {
283            errors.set_name(name);
284        }
285
286        if let Some(value) = ctxt.field_value {
287            errors.set_value(value);
288        }
289
290        Err(errors)
291    }
292}
293
294#[crate::async_trait]
295impl<'v> FromFormField<'v> for Capped<&'v str> {
296    fn from_value(field: ValueField<'v>) -> Result<'v, Self> {
297        Ok(Capped::from(field.value))
298    }
299
300    async fn from_data(f: DataField<'v, '_>) -> Result<'v, Self> {
301        use crate::data::{Capped, FromData, Outcome};
302
303        match <Capped<&'v str> as FromData>::from_data(f.request, f.data).await {
304            Outcome::Success(p) => Ok(p),
305            Outcome::Error((_, e)) => Err(e)?,
306            Outcome::Forward(..) => {
307                Err(Error::from(ErrorKind::Unexpected).with_entity(Entity::DataField))?
308            }
309        }
310    }
311}
312
313impl_strict_from_form_field_from_capped!(&'v str);
314
315#[crate::async_trait]
316impl<'v> FromFormField<'v> for Capped<String> {
317    fn from_value(field: ValueField<'v>) -> Result<'v, Self> {
318        Ok(Capped::from(field.value.to_string()))
319    }
320
321    async fn from_data(f: DataField<'v, '_>) -> Result<'v, Self> {
322        use crate::data::{Capped, FromData, Outcome};
323
324        match <Capped<String> as FromData>::from_data(f.request, f.data).await {
325            Outcome::Success(p) => Ok(p),
326            Outcome::Error((_, e)) => Err(e)?,
327            Outcome::Forward(..) => {
328                Err(Error::from(ErrorKind::Unexpected).with_entity(Entity::DataField))?
329            }
330        }
331    }
332}
333
334impl_strict_from_form_field_from_capped!(String);
335
336impl<'v> FromFormField<'v> for bool {
337    fn default() -> Option<Self> {
338        Some(false)
339    }
340
341    fn from_value(field: ValueField<'v>) -> Result<'v, Self> {
342        match field.value.as_uncased() {
343            v if v == "off" || v == "no" || v == "false" => Ok(false),
344            v if v.is_empty() || v == "on" || v == "yes" || v == "true" => Ok(true),
345            // force a `ParseBoolError`
346            _ => Ok("".parse()?),
347        }
348    }
349}
350
351#[crate::async_trait]
352impl<'v> FromFormField<'v> for Capped<&'v [u8]> {
353    fn from_value(field: ValueField<'v>) -> Result<'v, Self> {
354        Ok(Capped::from(field.value.as_bytes()))
355    }
356
357    async fn from_data(f: DataField<'v, '_>) -> Result<'v, Self> {
358        use crate::data::{Capped, FromData, Outcome};
359
360        match <Capped<&'v [u8]> as FromData>::from_data(f.request, f.data).await {
361            Outcome::Success(p) => Ok(p),
362            Outcome::Error((_, e)) => Err(e)?,
363            Outcome::Forward(..) => {
364                Err(Error::from(ErrorKind::Unexpected).with_entity(Entity::DataField))?
365            }
366        }
367    }
368}
369
370impl_strict_from_form_field_from_capped!(&'v [u8]);
371
372#[crate::async_trait]
373impl<'v> FromFormField<'v> for Capped<Cow<'v, str>> {
374    fn from_value(field: ValueField<'v>) -> Result<'v, Self> {
375        let capped = <Capped<&'v str>>::from_value(field)?;
376        Ok(capped.map(|s| s.into()))
377    }
378
379    async fn from_data(field: DataField<'v, '_>) -> Result<'v, Self> {
380        let capped = <Capped<&'v str>>::from_data(field).await?;
381        Ok(capped.map(|s| s.into()))
382    }
383}
384
385impl_strict_from_form_field_from_capped!(Cow<'v, str>);
386
387macro_rules! impl_with_parse {
388    ($($T:ident),+ $(,)?) => ($(
389        impl<'v> FromFormField<'v> for $T {
390            #[inline(always)]
391            fn from_value(field: ValueField<'v>) -> Result<'v, Self> {
392                Ok(field.value.parse()?)
393            }
394        }
395    )+)
396}
397
398impl_with_parse!(
399    char,
400    f32,
401    f64,
402    isize,
403    i8,
404    i16,
405    i32,
406    i64,
407    i128,
408    usize,
409    u8,
410    u16,
411    u32,
412    u64,
413    u128,
414    NonZeroIsize,
415    NonZeroI8,
416    NonZeroI16,
417    NonZeroI32,
418    NonZeroI64,
419    NonZeroI128,
420    NonZeroUsize,
421    NonZeroU8,
422    NonZeroU16,
423    NonZeroU32,
424    NonZeroU64,
425    NonZeroU128,
426    Ipv4Addr,
427    IpAddr,
428    Ipv6Addr,
429    SocketAddrV4,
430    SocketAddrV6,
431    SocketAddr
432);
433
434// Keep formats in sync with 'FromFormField' impls.
435static DATE_FMT: &[FormatItem<'_>] = format_description!("[year padding:none]-[month]-[day]");
436static TIME_FMT1: &[FormatItem<'_>] = format_description!("[hour padding:none]:[minute]:[second]");
437static TIME_FMT2: &[FormatItem<'_>] = format_description!("[hour padding:none]:[minute]");
438static DATE_TIME_FMT1: &[FormatItem<'_>] =
439    format_description!("[year padding:none]-[month]-[day]T[hour padding:none]:[minute]:[second]");
440static DATE_TIME_FMT2: &[FormatItem<'_>] =
441    format_description!("[year padding:none]-[month]-[day]T[hour padding:none]:[minute]");
442
443impl<'v> FromFormField<'v> for Date {
444    fn from_value(field: ValueField<'v>) -> Result<'v, Self> {
445        let date = Self::parse(field.value, &DATE_FMT)
446            .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send>)?;
447
448        Ok(date)
449    }
450}
451
452impl<'v> FromFormField<'v> for Time {
453    fn from_value(field: ValueField<'v>) -> Result<'v, Self> {
454        let time = Self::parse(field.value, &TIME_FMT1)
455            .or_else(|_| Self::parse(field.value, &TIME_FMT2))
456            .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send>)?;
457
458        Ok(time)
459    }
460}
461
462impl<'v> FromFormField<'v> for PrimitiveDateTime {
463    fn from_value(field: ValueField<'v>) -> Result<'v, Self> {
464        let dt = Self::parse(field.value, &DATE_TIME_FMT1)
465            .or_else(|_| Self::parse(field.value, &DATE_TIME_FMT2))
466            .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send>)?;
467
468        Ok(dt)
469    }
470}