1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
use memchr::memchr2;

/// Iterator over the key/value pairs of a given HTTP form string.
///
/// **Note:** The returned key/value pairs are _not_ URL decoded. To URL decode
/// the raw strings, use `String::from_form_value`:
///
/// ```rust
/// use rocket::request::{FormItems, FromFormValue};
///
/// let form_string = "greeting=Hello%2C+Mark%21&username=jake%2Fother";
/// for (key, value) in FormItems::from(form_string) {
///     let decoded_value = String::from_form_value(value);
///     match key {
///         "greeting" => assert_eq!(decoded_value, Ok("Hello, Mark!".into())),
///         "username" => assert_eq!(decoded_value, Ok("jake/other".into())),
///         _ => unreachable!()
///     }
/// }
/// ```
///
/// # Completion
///
/// The iterator keeps track of whether the form string was parsed to completion
/// to determine if the form string was malformed. The iterator can be queried
/// for completion via the [completed](#method.completed) method, which returns
/// `true` if the iterator parsed the entire string that was passed to it. The
/// iterator can also attempt to parse any remaining contents via
/// [exhausted](#method.exhausted); this method returns `true` if exhaustion
/// succeeded.
///
/// This iterator guarantees that all valid form strings are parsed to
/// completion. The iterator attempts to be lenient. In particular, it allows
/// the following oddball behavior:
///
///   * A single trailing `&` character is allowed.
///   * Empty values are allowed.
///
/// # Examples
///
/// `FormItems` can be used directly as an iterator:
///
/// ```rust
/// use rocket::request::FormItems;
///
/// // prints "greeting = hello" then "username = jake"
/// let form_string = "greeting=hello&username=jake";
/// for (key, value) in FormItems::from(form_string) {
///     println!("{} = {}", key, value);
/// }
/// ```
///
/// This is the same example as above, but the iterator is used explicitly.
///
/// ```rust
/// use rocket::request::FormItems;
///
/// let form_string = "greeting=hello&username=jake";
/// let mut items = FormItems::from(form_string);
/// assert_eq!(items.next(), Some(("greeting", "hello")));
/// assert_eq!(items.next(), Some(("username", "jake")));
/// assert_eq!(items.next(), None);
/// assert!(items.completed());
/// ```
pub struct FormItems<'f> {
    string: &'f str,
    next_index: usize
}

impl<'f> FormItems<'f> {
    /// Returns `true` if the form string was parsed to completion. Returns
    /// `false` otherwise. All valid form strings will parse to completion,
    /// while invalid form strings will not.
    ///
    /// # Example
    ///
    /// A valid form string parses to completion:
    ///
    /// ```rust
    /// use rocket::request::FormItems;
    ///
    /// let mut items = FormItems::from("a=b&c=d");
    /// let key_values: Vec<_> = items.by_ref().collect();
    ///
    /// assert_eq!(key_values.len(), 2);
    /// assert_eq!(items.completed(), true);
    /// ```
    ///
    /// In invalid form string does not parse to completion:
    ///
    /// ```rust
    /// use rocket::request::FormItems;
    ///
    /// let mut items = FormItems::from("a=b&=d");
    /// let key_values: Vec<_> = items.by_ref().collect();
    ///
    /// assert_eq!(key_values.len(), 1);
    /// assert_eq!(items.completed(), false);
    /// ```
    #[inline]
    pub fn completed(&self) -> bool {
        self.next_index >= self.string.len()
    }

    /// Parses all remaining key/value pairs and returns `true` if parsing ran
    /// to completion. All valid form strings will parse to completion, while
    /// invalid form strings will not.
    ///
    /// # Example
    ///
    /// A valid form string can be exhausted:
    ///
    /// ```rust
    /// use rocket::request::FormItems;
    ///
    /// let mut items = FormItems::from("a=b&c=d");
    ///
    /// assert!(items.next().is_some());
    /// assert_eq!(items.completed(), false);
    /// assert_eq!(items.exhausted(), true);
    /// assert_eq!(items.completed(), true);
    /// ```
    ///
    /// An invalid form string cannot be exhausted:
    ///
    /// ```rust
    /// use rocket::request::FormItems;
    ///
    /// let mut items = FormItems::from("a=b&=d");
    ///
    /// assert!(items.next().is_some());
    /// assert_eq!(items.completed(), false);
    /// assert_eq!(items.exhausted(), false);
    /// assert_eq!(items.completed(), false);
    /// ```
    pub fn exhausted(&mut self) -> bool {
        while let Some(_) = self.next() {  }
        self.completed()
    }

    #[inline]
    #[doc(hidden)]
    pub fn mark_complete(&mut self) {
        self.next_index = self.string.len()
    }

    /// Retrieves the original string being parsed by this iterator. The string
    /// returned by this method does not change, regardless of the status of the
    /// iterator.
    ///
    /// # Example
    ///
    /// ```rust
    /// use rocket::request::FormItems;
    ///
    /// let form_string = "a=b&c=d";
    /// let mut items = FormItems::from(form_string);
    /// assert_eq!(items.inner_str(), form_string);
    ///
    /// assert!(items.next().is_some());
    /// assert_eq!(items.inner_str(), form_string);
    ///
    /// assert!(items.next().is_some());
    /// assert_eq!(items.inner_str(), form_string);
    ///
    /// assert!(items.next().is_none());
    /// assert_eq!(items.inner_str(), form_string);
    /// ```
    #[inline]
    pub fn inner_str(&self) -> &'f str {
        self.string
    }
}

impl<'f> From<&'f str> for FormItems<'f> {
    /// Returns an iterator over the key/value pairs in the
    /// `x-www-form-urlencoded` form `string`.
    fn from(string: &'f str) -> FormItems<'f> {
        FormItems {
            string: string,
            next_index: 0
        }
    }
}

impl<'f> Iterator for FormItems<'f> {
    type Item = (&'f str, &'f str);

    fn next(&mut self) -> Option<Self::Item> {
        let s = &self.string[self.next_index..];
        let (key, rest) = match memchr2(b'=', b'&', s.as_bytes()) {
            Some(i) if s.as_bytes()[i] == b'=' => (&s[..i], &s[(i + 1)..]),
            Some(_) => return None,
            None => return None,
        };

        if key.is_empty() {
            return None;
        }

        let (value, consumed) = match rest.find('&') {
            Some(index) => (&rest[..index], index + 1),
            None => (rest, rest.len()),
        };

        self.next_index += key.len() + 1 + consumed;
        Some((key, value))
    }
}


#[cfg(test)]
mod test {
    use super::FormItems;

    macro_rules! check_form {
        (@opt $string:expr, $expected:expr) => ({
            let mut items = FormItems::from($string);
            let results: Vec<_> = items.by_ref().collect();
            if let Some(expected) = $expected {
                assert_eq!(expected.len(), results.len());

                for i in 0..results.len() {
                    let (expected_key, actual_key) = (expected[i].0, results[i].0);
                    let (expected_val, actual_val) = (expected[i].1, results[i].1);

                    assert!(expected_key == actual_key,
                            "key [{}] mismatch: expected {}, got {}",
                            i, expected_key, actual_key);

                    assert!(expected_val == actual_val,
                            "val [{}] mismatch: expected {}, got {}",
                            i, expected_val, actual_val);
                }
            } else {
                assert!(!items.exhausted());
            }
        });
        (@bad $string:expr) => (check_form!(@opt $string, None : Option<&[(&str, &str)]>));
        ($string:expr, $expected:expr) => (check_form!(@opt $string, Some($expected)));
    }

    #[test]
    fn test_form_string() {
        check_form!("username=user&password=pass",
                    &[("username", "user"), ("password", "pass")]);

        check_form!("user=user&user=pass",
                    &[("user", "user"), ("user", "pass")]);

        check_form!("user=&password=pass",
                    &[("user", ""), ("password", "pass")]);

        check_form!("a=b", &[("a", "b")]);

        check_form!("user=", &[("user", "")]);
        check_form!("user=&", &[("user", "")]);
        check_form!("a=b&a=", &[("a", "b"), ("a", "")]);

        check_form!(@bad "user=&password");
        check_form!(@bad "user=x&&");
        check_form!(@bad "a=b&a");
        check_form!(@bad "=");
        check_form!(@bad "&");
        check_form!(@bad "=&");
        check_form!(@bad "&=&");
        check_form!(@bad "=&=");
    }
}