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}