Skip to main content

form_net/extract/
mod.rs

1//! Typed extraction: plain Rust structs filled from a form, without serde
2//! and without a procedural macro.
3//!
4//! [`form!`](crate::form) generates a struct and its [`FromForm`]
5//! implementation; each field type implements [`FromField`]. Unknown names
6//! are refused, a scalar given twice is refused, a missing required field is
7//! refused, and every error names the field by its Rust-side name.
8
9mod file;
10mod macros;
11mod secret;
12mod value;
13
14pub use file::FileData;
15pub use secret::Secret;
16
17use crate::error::{ExtractError, FormError};
18use crate::hook::{Inspector, NoInspector};
19use crate::kind::FormKind;
20use crate::limits::{Limits, Policy};
21use crate::multipart::Part;
22
23/// Why one field's value did not convert. [`form!`](crate::form) turns it
24/// into `FormError::Extract` with the field's name.
25///
26/// # Examples
27///
28/// ```
29/// use form_net::{FromField, ValueError};
30///
31/// let mut slot = <u8 as FromField>::Slot::default();
32/// assert_eq!(u8::accept_text(&mut slot, "300"), Err(ValueError::Invalid("out of range")));
33/// ```
34#[non_exhaustive]
35#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36pub enum ValueError {
37    /// A required field is absent.
38    Missing,
39    /// A single-valued field was given twice.
40    Duplicate,
41    /// The value does not convert; the text says why.
42    Invalid(&'static str),
43    /// Text was given to a file field.
44    ExpectedFile,
45    /// A file was given to a text field.
46    ExpectedText,
47}
48
49/// A file field's value.
50///
51/// # Examples
52///
53/// ```
54/// use form_net::{FileData, FileValue, FromField};
55///
56/// let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", b"--X\r\nContent-Disposition: form-data; name=f; filename=a.txt\r\n\r\nhi\r\n--X--")?;
57/// let mut slot = <FileData as FromField>::Slot::default();
58/// FileData::accept_file(&mut slot, FileValue::Buffered(mp.file("f").unwrap())).unwrap();
59/// assert_eq!(FileData::finish(slot).unwrap().bytes(), b"hi");
60/// # Ok::<(), form_net::FormError>(())
61/// ```
62#[non_exhaustive]
63pub enum FileValue<'a> {
64    /// A part of a buffered body.
65    Buffered(&'a Part<'a>),
66    /// A stored file from an upload.
67    #[cfg(feature = "fs")]
68    #[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
69    Stored(crate::store::StoredFile),
70}
71
72impl core::fmt::Debug for FileValue<'_> {
73    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74        match self {
75            FileValue::Buffered(p) => f.debug_tuple("Buffered").field(p).finish(),
76            #[cfg(feature = "fs")]
77            FileValue::Stored(s) => f.debug_tuple("Stored").field(s).finish(),
78        }
79    }
80}
81
82/// How one field type takes its values.
83///
84/// The slot holds what has arrived so far, so every arity rule lives in one
85/// place: a scalar's slot is `Option<T>` (a second value is `Duplicate`,
86/// none is `Missing`), `Vec<T>` pushes, `bool` finishes a missing value as
87/// `false`. Implement it for an application type to validate while
88/// extracting.
89///
90/// # Examples
91///
92/// ```
93/// use form_net::{FromField, ValueError};
94///
95/// pub struct Slug(String);
96///
97/// impl FromField for Slug {
98///     type Slot = Option<Slug>;
99///     fn accept_text(slot: &mut Option<Slug>, value: &str) -> Result<(), ValueError> {
100///         if slot.is_some() { return Err(ValueError::Duplicate); }
101///         if value.is_empty() || value.len() > 64 || !value.bytes().all(|b| b.is_ascii_lowercase() || b == b'-') {
102///             return Err(ValueError::Invalid("lowercase letters and hyphens, 1 to 64"));
103///         }
104///         *slot = Some(Slug(value.to_owned()));
105///         Ok(())
106///     }
107///     fn finish(slot: Option<Slug>) -> Result<Slug, ValueError> {
108///         slot.ok_or(ValueError::Missing)
109///     }
110/// }
111/// ```
112pub trait FromField: Sized {
113    /// What has arrived so far.
114    type Slot: Default;
115
116    /// Takes one text value.
117    ///
118    /// # Errors
119    ///
120    /// `ExpectedFile` by default; the type's own conversion errors.
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// use form_net::{FromField, ValueError};
126    ///
127    /// let mut slot = <u16 as FromField>::Slot::default();
128    /// assert_eq!(u16::accept_text(&mut slot, "8080"), Ok(()));
129    /// assert_eq!(u16::accept_text(&mut slot, "80"), Err(ValueError::Duplicate));
130    /// assert_eq!(u16::finish(slot), Ok(8080));
131    /// ```
132    fn accept_text(slot: &mut Self::Slot, value: &str) -> Result<(), ValueError> {
133        let _ = (slot, value);
134        Err(ValueError::ExpectedFile)
135    }
136
137    /// Takes one file.
138    ///
139    /// # Errors
140    ///
141    /// `ExpectedText` by default; the type's own errors.
142    ///
143    /// # Examples
144    ///
145    /// ```
146    /// use form_net::{FileValue, FromField, ValueError};
147    ///
148    /// let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", b"--X\r\nContent-Disposition: form-data; name=f; filename=a.txt\r\n\r\nhi\r\n--X--")?;
149    /// let mut slot = <String as FromField>::Slot::default();
150    /// let file = FileValue::Buffered(mp.file("f").unwrap());
151    /// // A text field type refuses a file.
152    /// assert_eq!(String::accept_file(&mut slot, file), Err(ValueError::ExpectedText));
153    /// # Ok::<(), form_net::FormError>(())
154    /// ```
155    fn accept_file(slot: &mut Self::Slot, file: FileValue<'_>) -> Result<(), ValueError> {
156        let _ = (slot, file);
157        Err(ValueError::ExpectedText)
158    }
159
160    /// The value, once every field has arrived.
161    ///
162    /// # Errors
163    ///
164    /// `Missing`, or the type's own errors.
165    ///
166    /// # Examples
167    ///
168    /// ```
169    /// use form_net::{FromField, ValueError};
170    ///
171    /// let mut slot = <Vec<u8> as FromField>::Slot::default();
172    /// <Vec<u8>>::accept_text(&mut slot, "1").unwrap();
173    /// <Vec<u8>>::accept_text(&mut slot, "2").unwrap();
174    /// assert_eq!(<Vec<u8>>::finish(slot), Ok(vec![1, 2]));
175    /// assert_eq!(String::finish(None), Err(ValueError::Missing));
176    /// ```
177    fn finish(slot: Self::Slot) -> Result<Self, ValueError>;
178}
179
180/// What [`form!`](crate::form) generates, and what a hand-written
181/// [`FromForm`] implementation provides. Reports problems as
182/// `FormError::Extract { reason, field }`.
183///
184/// # Examples
185///
186/// ```
187/// use form_net::{ExtractError, FileValue, FormBuilder, FormError, FromForm};
188///
189/// /// Accepts any field names, keeping the last `q`.
190/// #[derive(Default)]
191/// struct LastQ(Option<String>);
192///
193/// impl FormBuilder for LastQ {
194///     type Output = Query;
195///     fn text(&mut self, name: &str, value: &str) -> Result<(), FormError> {
196///         if name == "q" { self.0 = Some(value.to_owned()); }
197///         Ok(())
198///     }
199///     fn file(&mut self, _name: &str, _file: FileValue<'_>) -> Result<(), FormError> {
200///         Err(FormError::Extract { reason: ExtractError::WrongKind, field: Some("q") })
201///     }
202///     fn finish(self) -> Result<Query, FormError> {
203///         Ok(Query { q: self.0.unwrap_or_default() })
204///     }
205/// }
206///
207/// struct Query { q: String }
208/// impl FromForm for Query { type Builder = LastQ; }
209///
210/// assert_eq!(Query::from_query(b"q=a&q=b")?.q, "b");
211/// # Ok::<(), FormError>(())
212/// ```
213pub trait FormBuilder {
214    /// The struct being built.
215    type Output;
216
217    /// One text field.
218    ///
219    /// # Errors
220    ///
221    /// `Extract { .. }`.
222    ///
223    /// # Examples
224    ///
225    /// ```
226    /// use form_net::{FormBuilder, FromForm};
227    ///
228    /// form_net::form! { #[derive(Debug)] pub struct Search { pub q: String } }
229    ///
230    /// let mut b = <Search as FromForm>::Builder::default();
231    /// b.text("q", "rust")?;
232    /// assert_eq!(b.text("page", "2").unwrap_err().code(), "extract.unknown");
233    /// # Ok::<(), form_net::FormError>(())
234    /// ```
235    fn text(&mut self, name: &str, value: &str) -> Result<(), FormError>;
236
237    /// One file.
238    ///
239    /// # Errors
240    ///
241    /// `Extract { .. }`.
242    ///
243    /// # Examples
244    ///
245    /// ```
246    /// use form_net::{FileValue, FormBuilder, FromForm};
247    ///
248    /// form_net::form! { pub struct Avatar { pub f: form_net::FileData } }
249    ///
250    /// let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", b"--X\r\nContent-Disposition: form-data; name=f; filename=a.txt\r\n\r\nhi\r\n--X--")?;
251    /// let mut b = <Avatar as FromForm>::Builder::default();
252    /// b.file("f", FileValue::Buffered(mp.file("f").unwrap()))?;
253    /// assert_eq!(b.finish()?.f.bytes(), b"hi");
254    /// # Ok::<(), form_net::FormError>(())
255    /// ```
256    fn file(&mut self, name: &str, file: FileValue<'_>) -> Result<(), FormError>;
257
258    /// The struct, once every field has arrived.
259    ///
260    /// # Errors
261    ///
262    /// `Extract { Missing | Invalid, .. }`.
263    ///
264    /// # Examples
265    ///
266    /// ```
267    /// use form_net::{ExtractError, FormBuilder, FormError, FromForm};
268    ///
269    /// form_net::form! { #[derive(Debug)] pub struct Search { pub q: String } }
270    ///
271    /// let b = <Search as FromForm>::Builder::default();
272    /// let err = b.finish().unwrap_err();
273    /// assert!(matches!(err, FormError::Extract { reason: ExtractError::Missing, field: Some("q") }));
274    /// ```
275    fn finish(self) -> Result<Self::Output, FormError>;
276
277    /// What a file under `name` is to the struct: `Some(true)` a declared
278    /// field, `Some(false)` an ignored name, `None` an unknown one.
279    /// `FromForm::from_upload_mut` (feature `fs`) moves only declared files out of the
280    /// upload. The default says every name is declared.
281    ///
282    /// # Examples
283    ///
284    /// ```
285    /// use form_net::{FormBuilder, FromForm};
286    ///
287    /// form_net::form! {
288    ///     pub struct Post { pub cover: form_net::FileData }
289    ///     ignore = ["note"];
290    /// }
291    ///
292    /// let b = <Post as FromForm>::Builder::default();
293    /// assert_eq!(b.file_field("cover"), Some(true));
294    /// assert_eq!(b.file_field("note"), Some(false));
295    /// assert_eq!(b.file_field("other"), None);
296    /// ```
297    fn file_field(&self, name: &str) -> Option<bool> {
298        let _ = name;
299        Some(true)
300    }
301
302    /// As [`finish`](Self::finish), but records every field's error in
303    /// `errors` instead of stopping at the first; `None` when any field
304    /// failed. The default records the one error `finish` returns.
305    ///
306    /// # Examples
307    ///
308    /// ```
309    /// use form_net::{FormBuilder, FromForm};
310    ///
311    /// form_net::form! { #[derive(Debug)] pub struct Signup { pub email: String, pub age: u8 } }
312    ///
313    /// let mut errors = Vec::new();
314    /// let b = <Signup as FromForm>::Builder::default();
315    /// assert!(b.finish_all(&mut errors).is_none());
316    /// // Both missing fields are reported, not only the first.
317    /// assert_eq!(errors.len(), 2);
318    /// ```
319    fn finish_all(self, errors: &mut alloc::vec::Vec<FormError>) -> Option<Self::Output>
320    where
321        Self: Sized,
322    {
323        match self.finish() {
324            Ok(v) => Some(v),
325            Err(e) => {
326                errors.push(e);
327                None
328            }
329        }
330    }
331}
332
333/// Every problem with one submitted form, for showing the form again with
334/// a message beside each field: what
335/// [`FromForm::from_body_all`] returns.
336///
337/// A parse error (a malformed body, a limit) stops the parse, so it is the
338/// only error; extraction errors are collected for every field, at most one
339/// per received value plus one per missing field. No value is ever kept.
340///
341/// # Examples
342///
343/// ```
344/// use form_net::{ExtractError, FromForm};
345///
346/// form_net::form! {
347///     #[derive(Debug)]
348///     pub struct Signup { pub email: String, pub age: u8, pub tos: bool }
349/// }
350///
351/// let errors = Signup::from_body_all(b"application/x-www-form-urlencoded", b"age=300&role=admin").unwrap_err();
352/// assert_eq!(errors.len(), 3);
353/// assert_eq!(errors.field("age"), Some(ExtractError::Invalid("out of range")));
354/// assert_eq!(errors.field("email"), Some(ExtractError::Missing));
355/// assert_eq!(errors.unknown(), 1);
356/// assert_eq!(errors.status_hint(), 422);
357/// ```
358#[derive(Clone, Debug, PartialEq, Eq)]
359pub struct FormErrors(alloc::vec::Vec<FormError>);
360
361impl FormErrors {
362    /// Every error, in the order found.
363    ///
364    /// # Examples
365    ///
366    /// ```
367    /// use form_net::{ExtractError, FromForm};
368    ///
369    /// # form_net::form! { #[derive(Debug)] pub struct Signup { pub email: String, pub age: u8 } }
370    /// let ct = b"application/x-www-form-urlencoded";
371    /// let errors = Signup::from_body_all(ct, b"age=300&role=admin").unwrap_err();
372    /// let codes: Vec<_> = errors.iter().map(|e| e.code()).collect();
373    /// assert_eq!(codes, ["extract.invalid", "extract.unknown", "extract.missing"]);
374    /// ```
375    pub fn iter(&self) -> impl Iterator<Item = &FormError> {
376        self.0.iter()
377    }
378
379    /// How many errors.
380    ///
381    /// # Examples
382    ///
383    /// ```
384    /// use form_net::{ExtractError, FromForm};
385    ///
386    /// # form_net::form! { #[derive(Debug)] pub struct Signup { pub email: String, pub age: u8 } }
387    /// let ct = b"application/x-www-form-urlencoded";
388    /// let errors = Signup::from_body_all(ct, b"age=300&role=admin").unwrap_err();
389    /// assert_eq!(errors.len(), 3);
390    /// ```
391    #[must_use]
392    pub fn len(&self) -> usize {
393        self.0.len()
394    }
395
396    /// Whether there are none (never true for a returned value).
397    ///
398    /// # Examples
399    ///
400    /// ```
401    /// use form_net::{ExtractError, FromForm};
402    ///
403    /// # form_net::form! { #[derive(Debug)] pub struct Signup { pub email: String, pub age: u8 } }
404    /// let ct = b"application/x-www-form-urlencoded";
405    /// let errors = Signup::from_body_all(ct, b"age=300&role=admin").unwrap_err();
406    /// assert!(!errors.is_empty());
407    /// ```
408    #[must_use]
409    pub fn is_empty(&self) -> bool {
410        self.0.is_empty()
411    }
412
413    /// The first error.
414    ///
415    /// # Examples
416    ///
417    /// ```
418    /// use form_net::{ExtractError, FromForm};
419    ///
420    /// # form_net::form! { #[derive(Debug)] pub struct Signup { pub email: String, pub age: u8 } }
421    /// let ct = b"application/x-www-form-urlencoded";
422    /// let errors = Signup::from_body_all(ct, b"age=300&role=admin").unwrap_err();
423    /// assert_eq!(errors.first().map(|e| e.code()), Some("extract.invalid"));
424    /// ```
425    #[must_use]
426    pub fn first(&self) -> Option<&FormError> {
427        self.0.first()
428    }
429
430    /// The first extraction error for the field with this Rust name.
431    ///
432    /// # Examples
433    ///
434    /// ```
435    /// use form_net::{ExtractError, FromForm};
436    ///
437    /// # form_net::form! { #[derive(Debug)] pub struct Signup { pub email: String, pub age: u8 } }
438    /// let ct = b"application/x-www-form-urlencoded";
439    /// let errors = Signup::from_body_all(ct, b"age=300&role=admin").unwrap_err();
440    /// assert_eq!(errors.field("age"), Some(ExtractError::Invalid("out of range")));
441    /// assert_eq!(errors.field("email"), Some(ExtractError::Missing));
442    /// ```
443    #[must_use]
444    pub fn field(&self, name: &str) -> Option<ExtractError> {
445        self.0.iter().find_map(|e| match e {
446            FormError::Extract {
447                reason,
448                field: Some(f),
449            } if *f == name => Some(*reason),
450            _ => None,
451        })
452    }
453
454    /// How many received names the struct neither declares nor ignores.
455    ///
456    /// # Examples
457    ///
458    /// ```
459    /// use form_net::{ExtractError, FromForm};
460    ///
461    /// # form_net::form! { #[derive(Debug)] pub struct Signup { pub email: String, pub age: u8 } }
462    /// let ct = b"application/x-www-form-urlencoded";
463    /// let errors = Signup::from_body_all(ct, b"age=300&role=admin").unwrap_err();
464    /// // `role` is neither a field nor an ignored name.
465    /// assert_eq!(errors.unknown(), 1);
466    /// ```
467    #[must_use]
468    pub fn unknown(&self) -> usize {
469        self.0
470            .iter()
471            .filter(|e| {
472                matches!(
473                    e,
474                    FormError::Extract {
475                        reason: ExtractError::Unknown,
476                        ..
477                    }
478                )
479            })
480            .count()
481    }
482
483    /// The status hint of the first error (422 for extraction errors).
484    ///
485    /// # Examples
486    ///
487    /// ```
488    /// use form_net::{ExtractError, FromForm};
489    ///
490    /// # form_net::form! { #[derive(Debug)] pub struct Signup { pub email: String, pub age: u8 } }
491    /// let ct = b"application/x-www-form-urlencoded";
492    /// let errors = Signup::from_body_all(ct, b"age=300&role=admin").unwrap_err();
493    /// assert_eq!(errors.status_hint(), 422);
494    /// ```
495    #[must_use]
496    pub fn status_hint(&self) -> u16 {
497        self.first().map_or(422, FormError::status_hint)
498    }
499}
500
501impl From<FormError> for FormErrors {
502    fn from(e: FormError) -> FormErrors {
503        FormErrors(alloc::vec![e])
504    }
505}
506
507impl core::fmt::Display for FormErrors {
508    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
509        match self.first() {
510            Some(e) if self.0.len() > 1 => {
511                write!(f, "{e} (and {} more)", self.0.len().saturating_sub(1))
512            }
513            Some(e) => write!(f, "{e}"),
514            None => f.write_str("no errors"),
515        }
516    }
517}
518
519#[cfg(feature = "std")]
520impl std::error::Error for FormErrors {}
521
522/// Feeds a builder and keeps going after extraction errors, recording them.
523struct Collect<'e, B> {
524    inner: B,
525    errors: &'e mut alloc::vec::Vec<FormError>,
526}
527
528impl<B: FormBuilder> FormBuilder for Collect<'_, B> {
529    type Output = B::Output;
530
531    fn text(&mut self, name: &str, value: &str) -> Result<(), FormError> {
532        match self.inner.text(name, value) {
533            Err(e @ FormError::Extract { .. }) => {
534                self.errors.push(e);
535                Ok(())
536            }
537            other => other,
538        }
539    }
540
541    fn file(&mut self, name: &str, file: FileValue<'_>) -> Result<(), FormError> {
542        match self.inner.file(name, file) {
543            Err(e @ FormError::Extract { .. }) => {
544                self.errors.push(e);
545                Ok(())
546            }
547            other => other,
548        }
549    }
550
551    fn finish(self) -> Result<B::Output, FormError> {
552        self.inner.finish()
553    }
554}
555
556/// The bytes the decoders use without allocating.
557const STACK: usize = 512;
558
559/// Feeds a urlencoded body to `builder`, decoding each name and value into a
560/// stack buffer when it fits and a heap buffer otherwise.
561fn feed_urlencoded<B: FormBuilder, I: Inspector>(
562    builder: &mut B,
563    input: &[u8],
564    limits: &Limits,
565    policy: &Policy,
566    inspector: &mut I,
567) -> Result<(), FormError> {
568    let mut name_stack = [0u8; STACK];
569    let mut value_stack = [0u8; STACK];
570    // The most of each stack buffer any pair wrote: only that is wiped.
571    let (mut name_hi, mut value_hi) = (0usize, 0usize);
572    let mut heap = alloc::vec::Vec::new();
573    // One UTF-8 pass over the body; plain names and values are cut from it.
574    let whole = core::str::from_utf8(input).ok();
575    let fed = (|| {
576        for pair in crate::urlencoded::raw::raw_pairs(input, limits) {
577            let pair = pair?;
578            // Nothing to decode (the usual case): borrow, no copy.
579            if let (Some(name), Some(value)) = (pair.name_text(whole), pair.value_text(whole)) {
580                let at = crate::error::Location::at(pair.offset());
581                match inspector.field(name, value.as_bytes()) {
582                    crate::Verdict::Refuse(refusal) => {
583                        return Err(FormError::Refused { refusal, at });
584                    }
585                    crate::Verdict::Skip => {}
586                    _ => builder.text(name, value)?,
587                }
588                continue;
589            }
590            let name_len = pair.name_raw().len();
591            let value_len = pair.value_raw().len();
592            let (name_buf, value_buf): (&mut [u8], &mut [u8]) =
593                if name_len <= STACK && value_len <= STACK {
594                    name_hi = name_hi.max(name_len);
595                    value_hi = value_hi.max(value_len);
596                    (&mut name_stack, &mut value_stack)
597                } else {
598                    let needed = name_len.saturating_add(value_len);
599                    crate::wipe::wipe(&mut heap);
600                    heap.clear();
601                    if needed > heap.capacity() {
602                        // A new allocation; the old one is wiped, not freed
603                        // with a decoded value in it.
604                        let mut old =
605                            core::mem::replace(&mut heap, alloc::vec::Vec::with_capacity(needed));
606                        crate::wipe::wipe_vec(&mut old);
607                    }
608                    heap.resize(needed, 0);
609                    heap.split_at_mut(name_len)
610                };
611            let name = pair.decode_name(name_buf, policy.percent)?;
612            let value = pair.decode_value(value_buf, policy.percent)?;
613            let at = crate::error::Location::at(pair.offset());
614            match inspector.field(name, value.as_bytes()) {
615                crate::Verdict::Refuse(refusal) => return Err(FormError::Refused { refusal, at }),
616                crate::Verdict::Skip => {}
617                _ => builder.text(name, value)?,
618            }
619        }
620        Ok(())
621    })();
622    crate::wipe::wipe(name_stack.get_mut(..name_hi).unwrap_or(&mut []));
623    crate::wipe::wipe(value_stack.get_mut(..value_hi).unwrap_or(&mut []));
624    crate::wipe::wipe_vec(&mut heap);
625    fed?;
626    if let crate::Verdict::Refuse(refusal) = inspector.end() {
627        return Err(FormError::Refused {
628            refusal,
629            at: crate::error::Location::at(input.len() as u64),
630        });
631    }
632    Ok(())
633}
634
635fn feed_multipart<B: FormBuilder>(
636    builder: &mut B,
637    mp: &crate::Multipart<'_>,
638) -> Result<(), FormError> {
639    for part in mp.parts() {
640        if part.is_file() {
641            builder.file(part.name(), FileValue::Buffered(part))?;
642        } else {
643            builder.text(part.name(), part.text()?)?;
644        }
645    }
646    Ok(())
647}
648
649/// A struct that can be read from a form. Implemented by
650/// [`form!`](crate::form); every method is provided.
651///
652/// # Examples
653///
654/// ```
655/// use form_net::FromForm;
656///
657/// form_net::form! {
658///     pub struct Login {
659///         pub email: String,
660///         pub password: form_net::Secret,
661///         pub remember: bool,
662///     }
663///     ignore = ["csrf_token"];
664/// }
665///
666/// let login = Login::from_body(b"application/x-www-form-urlencoded", b"email=a%40b.example&password=x&csrf_token=t")?;
667/// assert_eq!((login.email.as_str(), login.remember), ("a@b.example", false));
668/// # Ok::<(), form_net::FormError>(())
669/// ```
670pub trait FromForm: Sized {
671    /// The builder that collects the fields.
672    type Builder: FormBuilder<Output = Self> + Default;
673
674    /// From a urlencoded body, with the default limits and policy.
675    ///
676    /// # Errors
677    ///
678    /// The parser's errors; `Extract { .. }`.
679    ///
680    /// # Examples
681    ///
682    /// ```
683    /// use form_net::FromForm;
684    ///
685    /// # form_net::form! { #[derive(Debug)] pub struct Search { pub q: String, pub page: u32 } }
686    /// let s = Search::from_urlencoded(b"q=rust+forms&page=2")?;
687    /// assert_eq!((s.q.as_str(), s.page), ("rust forms", 2));
688    /// # Ok::<(), form_net::FormError>(())
689    /// ```
690    fn from_urlencoded(input: &[u8]) -> Result<Self, FormError> {
691        Self::from_urlencoded_with(input, &Limits::DEFAULT, &Policy::DEFAULT)
692    }
693
694    /// From a query string; one leading `?` is stripped.
695    ///
696    /// # Errors
697    ///
698    /// As [`from_urlencoded`](Self::from_urlencoded).
699    ///
700    /// # Examples
701    ///
702    /// ```
703    /// use form_net::FromForm;
704    ///
705    /// # form_net::form! { #[derive(Debug)] pub struct Search { pub q: String, pub page: u32 } }
706    /// let s = Search::from_query(b"?q=rust&page=1")?;
707    /// assert_eq!((s.q.as_str(), s.page), ("rust", 1));
708    /// # Ok::<(), form_net::FormError>(())
709    /// ```
710    fn from_query(query: &[u8]) -> Result<Self, FormError> {
711        Self::from_urlencoded(query.strip_prefix(b"?").unwrap_or(query))
712    }
713
714    /// From a buffered `multipart/form-data` body.
715    ///
716    /// # Errors
717    ///
718    /// The parser's errors; `Extract { .. }`.
719    ///
720    /// # Examples
721    ///
722    /// ```
723    /// use form_net::FromForm;
724    ///
725    /// # form_net::form! { pub struct Note { pub title: String } }
726    /// let body = b"--X\r\nContent-Disposition: form-data; name=title\r\n\r\nHi\r\n--X--";
727    /// let note = Note::from_multipart(b"multipart/form-data; boundary=X", body)?;
728    /// assert_eq!(note.title, "Hi");
729    /// # Ok::<(), form_net::FormError>(())
730    /// ```
731    fn from_multipart(content_type: &[u8], body: &[u8]) -> Result<Self, FormError> {
732        let mp = crate::parse_multipart(content_type, body)?;
733        let mut b = Self::Builder::default();
734        feed_multipart(&mut b, &mp)?;
735        b.finish()
736    }
737
738    /// From either encoding, by the `Content-Type`.
739    ///
740    /// # Errors
741    ///
742    /// `UnsupportedMediaType`; the parsers' errors; `Extract { .. }`.
743    ///
744    /// # Examples
745    ///
746    /// ```
747    /// use form_net::FromForm;
748    ///
749    /// # form_net::form! { #[derive(Debug)] pub struct Search { pub q: String, pub page: u32 } }
750    /// let s = Search::from_body(b"application/x-www-form-urlencoded", b"q=a&page=3")?;
751    /// assert_eq!(s.page, 3);
752    /// let err = Search::from_body(b"application/json", b"{}").unwrap_err();
753    /// assert_eq!(err.code(), "unsupported_media_type");
754    /// # Ok::<(), form_net::FormError>(())
755    /// ```
756    fn from_body(content_type: &[u8], body: &[u8]) -> Result<Self, FormError> {
757        Self::from_body_with(content_type, body, &Limits::DEFAULT, &Policy::DEFAULT)
758    }
759
760    /// From a urlencoded body with explicit limits and policy.
761    ///
762    /// # Errors
763    ///
764    /// As [`from_urlencoded`](Self::from_urlencoded); `InvalidLimits`.
765    ///
766    /// # Examples
767    ///
768    /// ```
769    /// use form_net::{FromForm, Limits, Policy};
770    ///
771    /// # form_net::form! { #[derive(Debug)] pub struct Search { pub q: String, pub page: u32 } }
772    /// let limits = Limits::DEFAULT.with_max_body_bytes(16);
773    /// let r = Search::from_urlencoded_with(b"q=a-long-search-term&page=1", &limits, &Policy::DEFAULT);
774    /// assert_eq!(r.unwrap_err().code(), "limit.body");
775    /// ```
776    fn from_urlencoded_with(
777        input: &[u8],
778        limits: &Limits,
779        policy: &Policy,
780    ) -> Result<Self, FormError> {
781        limits.validate()?;
782        let mut b = Self::Builder::default();
783        feed_urlencoded(&mut b, input, limits, policy, &mut NoInspector)?;
784        b.finish()
785    }
786
787    /// From either encoding with explicit limits and policy.
788    ///
789    /// # Errors
790    ///
791    /// As [`from_body`](Self::from_body); `InvalidLimits`.
792    ///
793    /// # Examples
794    ///
795    /// ```
796    /// use form_net::{FromForm, Limits, Policy};
797    ///
798    /// # form_net::form! { #[derive(Debug)] pub struct Search { pub q: String, pub page: u32 } }
799    /// let limits = Limits::DEFAULT.with_max_fields(1);
800    /// let ct = b"application/x-www-form-urlencoded";
801    /// let err = Search::from_body_with(ct, b"q=a&page=1", &limits, &Policy::DEFAULT).unwrap_err();
802    /// assert_eq!(err.code(), "limit.fields");
803    /// ```
804    fn from_body_with(
805        content_type: &[u8],
806        body: &[u8],
807        limits: &Limits,
808        policy: &Policy,
809    ) -> Result<Self, FormError> {
810        Self::from_body_inspected(content_type, body, limits, policy, &mut NoInspector)
811    }
812
813    /// From either encoding, with an inspector in the same pass: the
814    /// inspector and the struct see the same bytes.
815    ///
816    /// # Errors
817    ///
818    /// As [`from_body_with`](Self::from_body_with); `Refused`.
819    ///
820    /// # Examples
821    ///
822    /// ```
823    /// use form_net::{FromForm, Inspector, Limits, Policy, Refusal, Verdict};
824    ///
825    /// # form_net::form! { #[derive(Debug)] pub struct Search { pub q: String, pub page: u32 } }
826    /// struct NoAdmin;
827    /// impl Inspector for NoAdmin {
828    ///     fn field(&mut self, name: &str, _value: &[u8]) -> Verdict {
829    ///         if name == "admin" { Verdict::Refuse(Refusal::new(403, "app.admin")) } else { Verdict::Continue }
830    ///     }
831    /// }
832    ///
833    /// let ct = b"application/x-www-form-urlencoded";
834    /// let r = Search::from_body_inspected(ct, b"admin=1&q=a", &Limits::DEFAULT, &Policy::DEFAULT, &mut NoAdmin);
835    /// assert_eq!(r.unwrap_err().code(), "app.admin");
836    /// ```
837    fn from_body_inspected<I: Inspector>(
838        content_type: &[u8],
839        body: &[u8],
840        limits: &Limits,
841        policy: &Policy,
842        inspector: &mut I,
843    ) -> Result<Self, FormError> {
844        let result = (|| {
845            let mut b = Self::Builder::default();
846            match FormKind::detect(content_type)? {
847                FormKind::Urlencoded => {
848                    limits.validate()?;
849                    feed_urlencoded(&mut b, body, limits, policy, inspector)?;
850                }
851                FormKind::Multipart(_) => {
852                    let mp = crate::multipart::parse_multipart_inspected_raw(
853                        content_type,
854                        body,
855                        limits,
856                        policy,
857                        inspector,
858                    )?;
859                    feed_multipart(&mut b, &mp)?;
860                }
861            }
862            b.finish()
863        })();
864        if let Err(e) = &result {
865            inspector.failed(e);
866        }
867        result
868    }
869
870    /// From either encoding, collecting every field's error instead of
871    /// stopping at the first (D-090), so a form can be shown again with a
872    /// message beside each field.
873    ///
874    /// # Errors
875    ///
876    /// [`FormErrors`]: the parse error alone, or every extraction error.
877    ///
878    /// # Examples
879    ///
880    /// ```
881    /// use form_net::{ExtractError, FromForm};
882    ///
883    /// # form_net::form! { #[derive(Debug)] pub struct Search { pub q: String, pub page: u32 } }
884    /// let errors = Search::from_body_all(b"application/x-www-form-urlencoded", b"page=x").unwrap_err();
885    /// assert_eq!(errors.field("page"), Some(ExtractError::Invalid("not a whole number")));
886    /// assert_eq!(errors.field("q"), Some(ExtractError::Missing));
887    /// ```
888    fn from_body_all(content_type: &[u8], body: &[u8]) -> Result<Self, FormErrors> {
889        Self::from_body_all_with(content_type, body, &Limits::DEFAULT, &Policy::DEFAULT)
890    }
891
892    /// As [`from_body_all`](Self::from_body_all), with explicit limits and
893    /// policy.
894    ///
895    /// # Errors
896    ///
897    /// As [`from_body_all`](Self::from_body_all); `InvalidLimits`.
898    ///
899    /// # Examples
900    ///
901    /// ```
902    /// use form_net::{FromForm, Limits, Policy};
903    ///
904    /// # form_net::form! { #[derive(Debug)] pub struct Search { pub q: String, pub page: u32 } }
905    /// let limits = Limits::DEFAULT.with_max_body_bytes(8);
906    /// let ct = b"application/x-www-form-urlencoded";
907    /// let errors = Search::from_body_all_with(ct, b"q=a&page=10", &limits, &Policy::DEFAULT).unwrap_err();
908    /// // A parse error stops the parse and is the only error.
909    /// assert_eq!((errors.len(), errors.status_hint()), (1, 413));
910    /// ```
911    fn from_body_all_with(
912        content_type: &[u8],
913        body: &[u8],
914        limits: &Limits,
915        policy: &Policy,
916    ) -> Result<Self, FormErrors> {
917        let mut errors = alloc::vec::Vec::new();
918        let mut b = Collect {
919            inner: Self::Builder::default(),
920            errors: &mut errors,
921        };
922        match FormKind::detect(content_type)? {
923            FormKind::Urlencoded => {
924                limits.validate()?;
925                feed_urlencoded(&mut b, body, limits, policy, &mut NoInspector)?;
926            }
927            FormKind::Multipart(_) => {
928                let mp = crate::parse_multipart_with(content_type, body, limits, policy)?;
929                feed_multipart(&mut b, &mp)?;
930            }
931        }
932        let Collect { inner, errors: _ } = b;
933        let value = inner.finish_all(&mut errors);
934        match value {
935            Some(v) if errors.is_empty() => Ok(v),
936            _ => Err(FormErrors(errors)),
937        }
938    }
939
940    /// From an upload that stays usable (D-090): text fields are read by
941    /// reference, and only the files the struct declares are moved out of
942    /// it; files under `ignore = [..]` names stay in the upload for the
943    /// caller. Unknown names are refused as in
944    /// [`from_upload`](Self::from_upload). On error, files already moved
945    /// into the builder are dropped (deleted).
946    ///
947    /// # Errors
948    ///
949    /// `Extract { .. }`.
950    ///
951    /// # Examples
952    ///
953    /// ```
954    /// use form_net::FromForm;
955    ///
956    /// form_net::form! {
957    ///     pub struct Post { pub title: String, pub cover: form_net::StoredFile }
958    ///     ignore = ["attachment"];
959    /// }
960    ///
961    /// let body = b"--X\r\nContent-Disposition: form-data; name=title\r\n\r\nHi\r\n--X\r\nContent-Disposition: form-data; name=cover; filename=c.png\r\n\r\nC\r\n--X\r\nContent-Disposition: form-data; name=attachment; filename=a.pdf\r\n\r\nA\r\n--X--";
962    /// let mut upload = form_net::read_multipart(b"multipart/form-data; boundary=X", &body[..])?;
963    /// let post = Post::from_upload_mut(&mut upload)?;
964    /// assert_eq!((post.title.as_str(), post.cover.len()), ("Hi", 1));
965    /// assert_eq!(upload.field("title"), Some("Hi"));
966    /// assert!(upload.file("cover").is_none() && upload.file("attachment").is_some());
967    /// # Ok::<(), form_net::FormError>(())
968    /// ```
969    #[cfg(feature = "fs")]
970    #[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
971    fn from_upload_mut(upload: &mut crate::store::Upload) -> Result<Self, FormError> {
972        let mut b = Self::Builder::default();
973        for (name, value) in upload.iter() {
974            b.text(name, value)?;
975        }
976        let files = upload.files_mut();
977        let mut i = 0usize;
978        while let Some(file) = files.get(i) {
979            match b.file_field(file.name()) {
980                Some(true) => {
981                    let file = files.remove(i);
982                    let name = alloc::string::String::from(file.name());
983                    b.file(&name, FileValue::Stored(file))?;
984                }
985                Some(false) => i = i.wrapping_add(1),
986                None => return Err(__unknown()),
987            }
988        }
989        b.finish()
990    }
991
992    /// From a finished upload: text fields as text, files moved into the
993    /// struct as `StoredFile`s.
994    ///
995    /// # Errors
996    ///
997    /// `Extract { .. }`.
998    ///
999    /// # Examples
1000    ///
1001    /// ```
1002    /// use form_net::FromForm;
1003    ///
1004    /// form_net::form! { pub struct Post { pub title: String, pub cover: form_net::StoredFile } }
1005    ///
1006    /// let body = b"--X\r\nContent-Disposition: form-data; name=title\r\n\r\nHi\r\n--X\r\nContent-Disposition: form-data; name=cover; filename=c.png\r\n\r\nC\r\n--X--";
1007    /// let upload = form_net::read_multipart(b"multipart/form-data; boundary=X", &body[..])?;
1008    /// let post = Post::from_upload(upload)?;
1009    /// assert_eq!((post.title.as_str(), post.cover.len()), ("Hi", 1));
1010    /// # Ok::<(), form_net::FormError>(())
1011    /// ```
1012    #[cfg(feature = "fs")]
1013    #[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
1014    fn from_upload(upload: crate::store::Upload) -> Result<Self, FormError> {
1015        let (fields, files) = upload.into_parts();
1016        let mut b = Self::Builder::default();
1017        for (name, value) in fields.iter() {
1018            b.text(name, value)?;
1019        }
1020        for file in files {
1021            let name = alloc::string::String::from(file.name());
1022            b.file(&name, FileValue::Stored(file))?;
1023        }
1024        b.finish()
1025    }
1026}
1027
1028/// Maps a field's [`ValueError`] to the error `form!` returns. Not part of
1029/// the API: used by the macro expansion.
1030#[doc(hidden)]
1031#[must_use]
1032pub fn __value_error(e: ValueError, field: &'static str) -> FormError {
1033    let reason = match e {
1034        ValueError::Missing => ExtractError::Missing,
1035        ValueError::Duplicate => ExtractError::Duplicate,
1036        ValueError::Invalid(why) => ExtractError::Invalid(why),
1037        _ => ExtractError::WrongKind,
1038    };
1039    FormError::Extract {
1040        reason,
1041        field: Some(field),
1042    }
1043}
1044
1045/// Records a field's error at `finish_all`, leaving out a `Missing` for a
1046/// field that already failed when its value arrived. Not part of the API.
1047#[doc(hidden)]
1048pub fn __push_field_error(
1049    errors: &mut alloc::vec::Vec<FormError>,
1050    e: ValueError,
1051    field: &'static str,
1052) {
1053    let seen = errors
1054        .iter()
1055        .any(|x| matches!(x, FormError::Extract { field: Some(f), .. } if *f == field));
1056    if !(seen && e == ValueError::Missing) {
1057        errors.push(__value_error(e, field));
1058    }
1059}
1060
1061/// Whether two of `names` are equal, byte for byte: `form!` refuses to
1062/// compile a struct whose second field of a name could never receive a
1063/// value (D-138). Quadratic, at compile time only. Not part of the API.
1064#[doc(hidden)]
1065#[must_use]
1066pub const fn __repeated_wire_name(mut names: &[&str]) -> bool {
1067    while let [first, rest @ ..] = names {
1068        let mut others = rest;
1069        while let [other, tail @ ..] = others {
1070            if bytes_equal(first.as_bytes(), other.as_bytes()) {
1071                return true;
1072            }
1073            others = tail;
1074        }
1075        names = rest;
1076    }
1077    false
1078}
1079
1080/// `a == b` in a const context.
1081const fn bytes_equal(mut a: &[u8], mut b: &[u8]) -> bool {
1082    if a.len() != b.len() {
1083        return false;
1084    }
1085    while let ([x, ra @ ..], [y, rb @ ..]) = (a, b) {
1086        if *x != *y {
1087            return false;
1088        }
1089        a = ra;
1090        b = rb;
1091    }
1092    true
1093}
1094
1095/// The error for a name the struct does not declare. Not part of the API.
1096#[doc(hidden)]
1097#[must_use]
1098pub const fn __unknown() -> FormError {
1099    FormError::Extract {
1100        reason: ExtractError::Unknown,
1101        field: None,
1102    }
1103}