rocket/form/
from_form_field.rs

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