rocket/form/
field.rs

1use crate::form::{name::NameView, error::{Error, ErrorKind, Entity}};
2use crate::http::{ContentType, RawStr};
3use crate::{Request, Data};
4use crate::fs::FileName;
5
6/// A form field with a string value.
7///
8/// Rocket preprocesses all form fields into either [`ValueField`]s or
9/// [`DataField`]s. All fields from url-encoded forms, and fields without
10/// Content-Types from multipart forms, are preprocessed as a `ValueField`.
11#[derive(Debug, Clone)]
12pub struct ValueField<'r> {
13    /// The (decoded) name of the form field.
14    pub name: NameView<'r>,
15    /// The (decoded) value of the form field.
16    pub value: &'r str,
17}
18
19/// A multipart form field with an underlying data stream.
20///
21/// Rocket preprocesses all form fields into either [`ValueField`]s or
22/// [`DataField`]s. Multipart form fields with a `Content-Type` are preprocessed
23/// as a `DataField`. The underlying data is _not_ read into memory, but
24/// instead, streamable from the contained [`Data`] structure.
25pub struct DataField<'r, 'i> {
26    /// The (decoded) name of the form field.
27    pub name: NameView<'r>,
28    /// The form fields's file name.
29    pub file_name: Option<&'r FileName>,
30    /// The form field's Content-Type, as submitted, which may or may not
31    /// reflect on `data`.
32    pub content_type: ContentType,
33    /// The request in which the form field was submitted.
34    pub request: &'r Request<'i>,
35    /// The raw data stream.
36    pub data: Data<'r>,
37}
38
39impl<'v> ValueField<'v> {
40    /// Parse a field string, where both the key and value are assumed to be
41    /// URL-decoded while preserving the `=` delimiter, into a `ValueField`.
42    ///
43    /// This implements 3.2, 3.3 of [section 5.1 of the WHATWG living standard].
44    ///
45    /// [section 5.1 of the WHATWG living standard]: https://url.spec.whatwg.org/#urlencoded-parsing
46    ///
47    /// # Example
48    ///
49    /// ```rust
50    /// use rocket::form::ValueField;
51    ///
52    /// let parsed = ValueField::parse("a cat=an A+ pet");
53    /// assert_eq!(parsed.name, "a cat");
54    /// assert_eq!(parsed.value, "an A+ pet");
55    ///
56    /// let parsed = ValueField::parse("a cat is an A+ pet");
57    /// assert_eq!(parsed.name, "a cat is an A+ pet");
58    /// assert_eq!(parsed.value, "");
59    ///
60    /// let parsed = ValueField::parse("cat.food=yum?");
61    /// assert_eq!(parsed.name, "cat");
62    /// assert_eq!(parsed.name.source(), "cat.food");
63    /// assert_eq!(parsed.value, "yum?");
64    /// ```
65    pub fn parse(field: &'v str) -> Self {
66        // WHATWG URL Living Standard 5.1 steps 3.2, 3.3.
67        let (name, val) = RawStr::new(field).split_at_byte(b'=');
68        ValueField::from((name.as_str(), val.as_str()))
69    }
70
71    /// Create a `ValueField` from a value, which is assumed to be URL-decoded.
72    /// The field `name` will be empty.
73    ///
74    /// This is equivalent to `ValueField::from(("", value))`. To create a
75    /// `ValueField` from both a `name` and a `value`, use
76    /// `ValueField::from((name, value))`.
77    ///
78    /// # Example
79    ///
80    /// ```rust
81    /// use rocket::form::ValueField;
82    ///
83    /// let parsed = ValueField::from_value("A+=kitten");
84    /// assert_eq!(parsed.name, "");
85    /// assert_eq!(parsed.value, "A+=kitten");
86    /// ```
87    pub fn from_value(value: &'v str) -> Self {
88        ValueField::from(("", value))
89    }
90
91    /// Shift the `name` of `self` and return `self` with the shifted `name`.
92    ///
93    /// See [`NameView::shift()`] for the details on name "shifting".
94    ///
95    /// # Example
96    ///
97    /// ```rust
98    /// use rocket::form::ValueField;
99    ///
100    /// let parsed = ValueField::parse("cat.food=yum?");
101    /// assert_eq!(parsed.name, "cat");
102    /// assert_eq!(parsed.name.source(), "cat.food");
103    /// assert_eq!(parsed.name.key_lossy(), "cat");
104    ///
105    /// let shifted = parsed.shift();
106    /// assert_eq!(shifted.name, "cat.food");
107    /// assert_eq!(shifted.name.key_lossy(), "food");
108    /// ```
109    pub fn shift(mut self) -> Self {
110        self.name.shift();
111        self
112    }
113
114    /// Creates a complete unexpected value field [`Error`] from `self`.
115    ///
116    /// The error will have the following properties:
117    ///   * `kind`: [`ErrorKind::Unexpected`]
118    ///   * `name`: [`self.name.source()`](NameView::source())
119    ///   * `value`: [`self.value`](ValueField::value)
120    ///   * `entity`: [`Entity::ValueField`]
121    ///
122    /// # Example
123    ///
124    /// ```rust
125    /// use rocket::form::ValueField;
126    /// use rocket::form::error::{ErrorKind, Entity};
127    ///
128    /// let field = ValueField::parse("cat.food=yum?");
129    /// let error = field.unexpected();
130    ///
131    /// assert_eq!(error.name.as_ref().unwrap(), "cat.food");
132    /// assert_eq!(error.value.as_ref().unwrap(), "yum?");
133    /// assert_eq!(error.kind, ErrorKind::Unexpected);
134    /// assert_eq!(error.entity, Entity::ValueField);
135    /// ```
136    pub fn unexpected(&self) -> Error<'v> {
137        Error::from(ErrorKind::Unexpected)
138            .with_name(self.name.source())
139            .with_value(self.value)
140            .with_entity(Entity::ValueField)
141    }
142
143    /// Creates a complete missing value field [`Error`] from `self`.
144    ///
145    /// The error will have the following properties:
146    ///   * `kind`: [`ErrorKind::Missing`]
147    ///   * `name`: [`self.name.source()`](NameView::source())
148    ///   * `value`: [`self.value`](ValueField::value)
149    ///   * `entity`: [`Entity::ValueField`]
150    ///
151    /// # Example
152    ///
153    /// ```rust
154    /// use rocket::form::ValueField;
155    /// use rocket::form::error::{ErrorKind, Entity};
156    ///
157    /// let field = ValueField::parse("cat.food=yum?");
158    /// let error = field.missing();
159    ///
160    /// assert_eq!(error.name.as_ref().unwrap(), "cat.food");
161    /// assert_eq!(error.value.as_ref().unwrap(), "yum?");
162    /// assert_eq!(error.kind, ErrorKind::Missing);
163    /// assert_eq!(error.entity, Entity::ValueField);
164    /// ```
165    pub fn missing(&self) -> Error<'v> {
166        Error::from(ErrorKind::Missing)
167            .with_name(self.name.source())
168            .with_value(self.value)
169            .with_entity(Entity::ValueField)
170    }
171}
172
173impl<'v> DataField<'v, '_> {
174    /// Shift the `name` of `self` and return `self` with the shifted `name`.
175    ///
176    /// This is identical to [`ValueField::shift()`] but for `DataField`s. See
177    /// [`NameView::shift()`] for the details on name "shifting".
178    ///
179    /// # Example
180    ///
181    /// ```rust
182    /// use rocket::form::DataField;
183    ///
184    /// fn push_data(field: DataField<'_, '_>) {
185    ///     let shifted = field.shift();
186    /// }
187    /// ```
188    pub fn shift(mut self) -> Self {
189        self.name.shift();
190        self
191    }
192
193    /// Creates a complete unexpected data field [`Error`] from `self`.
194    ///
195    /// The error will have the following properties:
196    ///   * `kind`: [`ErrorKind::Unexpected`]
197    ///   * `name`: [`self.name.source()`](NameView::source())
198    ///   * `value`: `None`
199    ///   * `entity`: [`Entity::DataField`]
200    ///
201    /// # Example
202    ///
203    /// ```rust
204    /// use rocket::form::DataField;
205    ///
206    /// fn push_data(field: DataField<'_, '_>) {
207    ///     let error = field.unexpected();
208    /// }
209    /// ```
210    pub fn unexpected(&self) -> Error<'v> {
211        Error::from(ErrorKind::Unexpected)
212            .with_name(self.name.source())
213            .with_entity(Entity::DataField)
214    }
215}
216
217impl<'a> From<(&'a str, &'a str)> for ValueField<'a> {
218    fn from((name, value): (&'a str, &'a str)) -> Self {
219        ValueField { name: NameView::new(name), value }
220    }
221}
222
223impl<'a, 'b> PartialEq<ValueField<'b>> for ValueField<'a> {
224    fn eq(&self, other: &ValueField<'b>) -> bool {
225        self.name == other.name && self.value == other.value
226    }
227}