rouille/input/
post.rs

1// Copyright (c) 2016 The Rouille developers
2// Licensed under the Apache License, Version 2.0
3// <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
6// at your option. All files in the project carrying such
7// notice may not be copied, modified, or distributed except
8// according to those terms.
9
10//! Parsing data sent with a `<form method="POST">`.
11//!
12//! In order to parse the body of a request, you can use the `post_input!` macro.
13//!
14//! ```
15//! # #[macro_use] extern crate rouille;
16//! use rouille::Request;
17//! use rouille::Response;
18//!
19//! fn handle_request(request: &Request) -> Response {
20//!     let input = try_or_400!(post_input!(request, {
21//!         field1: u32,
22//!         field2: String,
23//!     }));
24//!
25//!     Response::text(format!("the value of field1 is: {}", input.field1))
26//! }
27//! # fn main() {}
28//! ```
29//!
30//! In this example, the macro will read the body of the request and try to find fields whose
31//! names are `field1` and `field2`. If the body was already retrieved earlier, if the content-type
32//! is not one of the possible values, or if a field is missing or can't be parsed, then an error
33//! is returned. Usually you want to handle this error by returning an error to the client.
34//!
35//! The macro will define and build a struct whose members are the field names that are passed.
36//! The macro then returns a `Result<TheGeneratedStruct, PostError>`.
37//!
38//! # Data types
39//!
40//! The types that can be used with this macro are the following:
41//!
42//! - `String`: The value sent by the client is directly put in the `String`.
43//! - `u8`/`i8`/`u16`/`i16`/ `u32`/`i32`/ `u64`/`i64`/`usize`/`isize`/`f32`/`f64`: Rouille will try
44//!   to parse the number from the data passed by the client. An error is produced if the client
45//!   sent a value that failed to parse or that overflows the capacity of the number.
46//! - `Option<T>`: This is equivalent to `T`, but if the field is missing or fails to parse then
47//!   the `Option` will contain `None` and no error will be produced.
48//! - `bool`: Will be `true` if the field is present at least once and `false` if it is absent.
49//!   This is suitable to know whether a `<input type="checkbox" />` is checked or not.
50//! - `Vec<T>`: Same as `T`, except that if the client sends multiple fields with that name then
51//!   they are merged together. If you don't use a `Vec` then an error is returned in that
52//!   situation. If the client provides multiple values and some of them fail to parse, an error
53//!   is returned. You can use a `Vec<Option<T>>` if you don't want an error on parse failure.
54//!   Empty vecs are possible.
55//! - The file-uploads-related types. See below.
56//!
57//! > **Note**: You may find resources on the web telling you that you must put brackets (`[` `]`)
58//! > after the name of inputs of type `<select multiple>` and `<input type="file" multiple>`.
59//! > This is only necessary for some programming languages and frameworks, and is not relevant
60//! > for rouille. With rouille you just need to use a `Vec` for the data type.
61//!
62//! You can also use your own types by implementing the
63//! [`DecodePostField` trait](trait.DecodePostField.html). See below.
64//!
65//! # Handling file uploads
66//!
67//! In order to receive a file sent with a `<form>`, you should use one of the provided structs
68//! that represent a file:
69//!
70//! - [`BufferedFile`](struct.BufferedFile.html), in which case the body of the file will be stored
71//!   in memory.
72//!
73//! Example:
74//!
75//! ```
76//! # #[macro_use] extern crate rouille;
77//! use rouille::Request;
78//! use rouille::Response;
79//! use rouille::input::post::BufferedFile;
80//!
81//! fn handle_request(request: &Request) -> Response {
82//!     let input = try_or_400!(post_input!(request, {
83//!         file: BufferedFile,
84//!     }));
85//!
86//!     Response::text("everything ok")
87//! }
88//! # fn main() {}
89//! ```
90//!
91//! # How it works internally
92//!
93//! In order for the macro to work, each type of data (like `u32`, `String` or `BufferedFile`) must
94//! implement the [`DecodePostField` trait](trait.DecodePostField.html).
95//!
96//! The template parameter of the trait represents the type of the configuration object that is
97//! accepted by the methods. If the user doesn't specify any configuration, the type will be `()`.
98//!
99//! When rouille's parser finds a field with the correct name it will attempt to call the
100//! `from_field` method, and if it find a file with the correct name it will attempt to call the
101//! `from_file` method. You should return `PostFieldError::WrongFieldType` if you're
102//! expecting a file and `from_field` was called, or vice-versa.
103
104use Request;
105
106use std::borrow::Cow;
107use std::error;
108use std::fmt;
109use std::io::BufRead;
110use std::io::Error as IoError;
111use std::io::Read;
112use std::num;
113
114// Must be made public so that it can be used by the `post_input` macro.
115#[doc(hidden)]
116pub use url::form_urlencoded;
117
118/// Error that can happen when decoding POST data.
119#[derive(Debug)]
120pub enum PostError {
121    /// The `Content-Type` header of the request indicates that it doesn't contain POST data.
122    WrongContentType,
123
124    /// Can't parse the body of the request because it was already extracted.
125    BodyAlreadyExtracted,
126
127    /// Could not read the body from the request.
128    IoError(IoError),
129
130    /// Failed to parse a string field.
131    NotUtf8(String),
132
133    /// There was an error with a particular field.
134    Field {
135        field: Cow<'static, str>,
136        error: PostFieldError,
137    },
138}
139
140impl From<IoError> for PostError {
141    #[inline]
142    fn from(err: IoError) -> PostError {
143        PostError::IoError(err)
144    }
145}
146
147impl error::Error for PostError {
148    #[inline]
149    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
150        match *self {
151            PostError::IoError(ref e) => Some(e),
152            PostError::Field { ref error, .. } => Some(error),
153            _ => None,
154        }
155    }
156}
157
158impl fmt::Display for PostError {
159    #[inline]
160    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
161        let description = match *self {
162            PostError::BodyAlreadyExtracted => "the body of the request was already extracted",
163            PostError::WrongContentType => "the request didn't have a post content type",
164            PostError::IoError(_) => {
165                "could not read the body from the request, or could not execute the CGI program"
166            }
167            PostError::NotUtf8(_) => {
168                "the content-type encoding is not ASCII or UTF-8, or the body is not valid UTF-8"
169            }
170            PostError::Field { .. } => "failed to parse a requested field",
171        };
172
173        write!(fmt, "{}", description)
174    }
175}
176
177/// Error returned by the methods of [the `DecodePostField` trait](trait.DecodePostField.html).
178#[derive(Debug)]
179pub enum PostFieldError {
180    /// Could not read the body. Usually happens with files.
181    IoError(IoError),
182
183    /// A field is missing from the received data.
184    MissingField,
185
186    /// Expected a file but got a field, or vice versa.
187    WrongFieldType,
188
189    /// Got multiple values for the same field while only one was expected.
190    UnexpectedMultipleValues,
191
192    /// Failed to parse an integer field.
193    WrongDataTypeInt(num::ParseIntError),
194
195    /// Failed to parse a floating-point field.
196    WrongDataTypeFloat(num::ParseFloatError),
197}
198
199impl From<IoError> for PostFieldError {
200    #[inline]
201    fn from(err: IoError) -> PostFieldError {
202        PostFieldError::IoError(err)
203    }
204}
205
206impl From<num::ParseIntError> for PostFieldError {
207    #[inline]
208    fn from(err: num::ParseIntError) -> PostFieldError {
209        PostFieldError::WrongDataTypeInt(err)
210    }
211}
212
213impl From<num::ParseFloatError> for PostFieldError {
214    #[inline]
215    fn from(err: num::ParseFloatError) -> PostFieldError {
216        PostFieldError::WrongDataTypeFloat(err)
217    }
218}
219
220impl error::Error for PostFieldError {
221    #[inline]
222    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
223        match *self {
224            PostFieldError::IoError(ref e) => Some(e),
225            PostFieldError::WrongDataTypeInt(ref e) => Some(e),
226            PostFieldError::WrongDataTypeFloat(ref e) => Some(e),
227            _ => None,
228        }
229    }
230}
231
232impl fmt::Display for PostFieldError {
233    #[inline]
234    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
235        let description = match *self {
236            PostFieldError::IoError(_) => {
237                "could not read the body from the request, or could not execute the CGI program"
238            }
239            PostFieldError::MissingField => "the field is missing from the request's client",
240            PostFieldError::WrongFieldType => "expected a file but got a field, or vice versa",
241            PostFieldError::UnexpectedMultipleValues => {
242                "got multiple values for the same field while only one was expected"
243            }
244            PostFieldError::WrongDataTypeInt(_) => "failed to parse an integer field",
245            PostFieldError::WrongDataTypeFloat(_) => "failed to parse a floating-point field",
246        };
247
248        write!(fmt, "{}", description)
249    }
250}
251
252/// Must be implemented on types used with the `post_input!` macro.
253///
254/// The template parameter represents the type of a configuration object that can be passed by
255/// the user when the macro is called. If the user doesn't pass any configuration, the expected
256/// type is `()`.
257pub trait DecodePostField<Config>: fmt::Debug {
258    /// Called when a field with the given name is found in the POST input.
259    ///
260    /// The value of `content` is what the client sent. This function should attempt to parse it
261    /// into `Self` or return an error if it couldn't. If `Self` can't handle a field, then a
262    /// `PostFieldError::WrongFieldType` error should be returned.
263    fn from_field(config: Config, content: &str) -> Result<Self, PostFieldError>
264    where
265        Self: Sized;
266
267    /// Called when a file with the given name is found in the POST input.
268    ///
269    /// The `file` is an object from which the body of the file can be read. The `filename` and
270    /// `mime` are also arbitrary values sent directly by the client, so you shouldn't trust them
271    /// blindly.
272    ///
273    /// > **Note**: The `file` object can typically read directly from the socket. But don't worry
274    /// > about doing something wrong, as there are protection mechanisms that will prevent you
275    /// > from reading too far.
276    ///
277    /// This method should do something with the file (like storing it somewhere) and return a
278    /// `Self` that will allow the user to manipulate the file that was uploaded.
279    ///
280    /// If `Self` can't handle a file, then a `PostFieldError::WrongFieldType` error should
281    /// be returned.
282    fn from_file<R>(
283        config: Config,
284        file: R,
285        filename: Option<&str>,
286        mime: &str,
287    ) -> Result<Self, PostFieldError>
288    where
289        Self: Sized,
290        R: BufRead;
291
292    /// When multiple fields with the same name are found in the client's input, rouille will build
293    /// an object for each of them and then merge them with this method.
294    ///
295    /// The default implementation returns `UnexpectedMultipleValues`.
296    fn merge_multiple(self, _existing: Self) -> Result<Self, PostFieldError>
297    where
298        Self: Sized,
299    {
300        Err(PostFieldError::UnexpectedMultipleValues)
301    }
302
303    /// Called when no field is found in the POST input.
304    ///
305    /// The default implementation returns `MissingField`.
306    #[inline]
307    fn not_found(_: Config) -> Result<Self, PostFieldError>
308    where
309        Self: Sized,
310    {
311        Err(PostFieldError::MissingField)
312    }
313}
314
315macro_rules! impl_decode_post_field_decode {
316    ($t:ident) => {
317        impl DecodePostField<()> for $t {
318            fn from_field(_: (), content: &str) -> Result<Self, PostFieldError> {
319                Ok(match content.parse() {
320                    Ok(v) => v,
321                    Err(err) => return Err(err.into()),
322                })
323            }
324
325            fn from_file<R>(_: (), _: R, _: Option<&str>, _: &str) -> Result<Self, PostFieldError>
326            where
327                R: BufRead,
328            {
329                Err(PostFieldError::WrongFieldType)
330            }
331        }
332    };
333}
334
335impl_decode_post_field_decode!(u8);
336impl_decode_post_field_decode!(i8);
337impl_decode_post_field_decode!(u16);
338impl_decode_post_field_decode!(i16);
339impl_decode_post_field_decode!(u32);
340impl_decode_post_field_decode!(i32);
341impl_decode_post_field_decode!(u64);
342impl_decode_post_field_decode!(i64);
343impl_decode_post_field_decode!(usize);
344impl_decode_post_field_decode!(isize);
345impl_decode_post_field_decode!(f32);
346impl_decode_post_field_decode!(f64);
347
348impl DecodePostField<()> for String {
349    fn from_field(_: (), content: &str) -> Result<Self, PostFieldError> {
350        Ok(content.to_owned())
351    }
352
353    fn from_file<R>(_: (), _: R, _: Option<&str>, _: &str) -> Result<Self, PostFieldError>
354    where
355        R: BufRead,
356    {
357        Err(PostFieldError::WrongFieldType)
358    }
359}
360
361impl<T, C> DecodePostField<C> for Option<T>
362where
363    T: DecodePostField<C>,
364{
365    fn from_field(config: C, content: &str) -> Result<Self, PostFieldError> {
366        match DecodePostField::from_field(config, content) {
367            Ok(val) => Ok(Some(val)),
368            Err(_) => Ok(None),
369        }
370    }
371
372    fn from_file<R>(
373        config: C,
374        file: R,
375        filename: Option<&str>,
376        mime: &str,
377    ) -> Result<Self, PostFieldError>
378    where
379        R: BufRead,
380    {
381        match DecodePostField::from_file(config, file, filename, mime) {
382            Ok(val) => Ok(Some(val)),
383            Err(_) => Ok(None),
384        }
385    }
386
387    #[inline]
388    fn not_found(_: C) -> Result<Self, PostFieldError> {
389        Ok(None)
390    }
391}
392
393impl DecodePostField<()> for bool {
394    #[inline]
395    fn from_field(_: (), _: &str) -> Result<Self, PostFieldError> {
396        Ok(true)
397    }
398
399    #[inline]
400    fn from_file<R>(_: (), _: R, _: Option<&str>, _: &str) -> Result<Self, PostFieldError>
401    where
402        R: BufRead,
403    {
404        Ok(true)
405    }
406
407    #[inline]
408    fn merge_multiple(self, existing: bool) -> Result<bool, PostFieldError> {
409        Ok(self || existing)
410    }
411
412    #[inline]
413    fn not_found(_: ()) -> Result<Self, PostFieldError> {
414        Ok(false)
415    }
416}
417
418impl<T, C> DecodePostField<C> for Vec<T>
419where
420    T: DecodePostField<C>,
421{
422    fn from_field(config: C, content: &str) -> Result<Self, PostFieldError> {
423        Ok(vec![DecodePostField::from_field(config, content)?])
424    }
425
426    fn from_file<R>(
427        config: C,
428        file: R,
429        filename: Option<&str>,
430        mime: &str,
431    ) -> Result<Self, PostFieldError>
432    where
433        R: BufRead,
434    {
435        Ok(vec![DecodePostField::from_file(
436            config, file, filename, mime,
437        )?])
438    }
439
440    fn merge_multiple(mut self, mut existing: Vec<T>) -> Result<Vec<T>, PostFieldError> {
441        self.append(&mut existing);
442        Ok(self)
443    }
444
445    #[inline]
446    fn not_found(_: C) -> Result<Self, PostFieldError> {
447        Ok(Vec::new())
448    }
449}
450
451/// Implementation of the `DecodePostField` that puts the body of the file in memory.
452#[derive(Clone)]
453pub struct BufferedFile {
454    /// The file's data.
455    pub data: Vec<u8>,
456    /// The MIME type. Remember that this shouldn't be blindly trusted.
457    pub mime: String,
458    /// The name of the file, if known. Remember that this shouldn't be blindly trusted.
459    pub filename: Option<String>,
460}
461
462impl fmt::Debug for BufferedFile {
463    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
464        fmt.debug_struct("BufferedFile")
465            .field("data", &format!("<{} bytes>", self.data.len()))
466            .field("mime", &self.mime)
467            .field("filename", &self.filename)
468            .finish()
469    }
470}
471
472impl DecodePostField<()> for BufferedFile {
473    fn from_field(_: (), _: &str) -> Result<Self, PostFieldError> {
474        Err(PostFieldError::WrongFieldType)
475    }
476
477    fn from_file<R>(
478        _: (),
479        mut file: R,
480        filename: Option<&str>,
481        mime: &str,
482    ) -> Result<Self, PostFieldError>
483    where
484        R: BufRead,
485    {
486        let mut out = Vec::new();
487        file.read_to_end(&mut out)?;
488
489        Ok(BufferedFile {
490            data: out,
491            mime: mime.to_owned(),
492            filename: filename.map(|n| n.to_owned()),
493        })
494    }
495}
496
497/// Parse input from HTML forms. See [the `post` module](input/post/index.html) for general
498/// documentation.
499#[macro_export]
500macro_rules! post_input {
501    ($request:expr, {$($field:ident: $ty:ty $({$config:expr})*),*$(,)*}) => ({
502        use std::io::Read;
503        use std::result::Result;
504        use $crate::Request;
505        use $crate::input::post::DecodePostField;
506        use $crate::input::post::PostFieldError;
507        use $crate::input::post::PostError;
508        use $crate::input::post::form_urlencoded;
509        use $crate::input::multipart;
510
511        #[derive(Debug)]
512        struct PostInput {
513            $(
514                $field: $ty,
515            )*
516        }
517
518        fn merge<C, T: DecodePostField<C>>(existing: &mut Option<T>, new: T)
519                                           -> Result<(), PostFieldError>
520        {
521            match existing {
522                a @ &mut Some(_) => {
523                    let extracted = a.take().unwrap();
524                    let merged = extracted.merge_multiple(new)?;
525                    *a = Some(merged);
526                },
527                a @ &mut None => *a = Some(new),
528            };
529
530            Ok(())
531        }
532
533        fn go(request: &Request) -> Result<PostInput, PostError> {
534            $(
535                let mut $field: Option<$ty> = None;
536            )*
537
538            // TODO: handle if the same field is specified multiple times
539
540            if request.header("Content-Type").map(|ct| ct.starts_with("application/x-www-form-urlencoded")).unwrap_or(false) {
541                let body = {
542                    // TODO: DDoSable server if body is too large?
543                    let mut out = Vec::new();       // TODO: with_capacity()?
544                    if let Some(mut b) = request.data() {
545                        b.read_to_end(&mut out)?;
546                    } else {
547                        return Err(PostError::BodyAlreadyExtracted);
548                    }
549                    out
550                };
551
552                for (field, value) in form_urlencoded::parse(&body) {
553                    $(
554                        if field == stringify!($field) {
555                            let config = ();
556                            $(
557                                let config = $config;
558                            )*
559
560                            let decoded = match DecodePostField::from_field(config, &value) {
561                                Ok(d) => d,
562                                Err(err) => return Err(PostError::Field {
563                                    field: stringify!($field).into(),
564                                    error: err,
565                                }),
566                            };
567
568                            match merge(&mut $field, decoded) {
569                                Ok(d) => d,
570                                Err(err) => return Err(PostError::Field {
571                                    field: stringify!($field).into(),
572                                    error: err,
573                                }),
574                            };
575                            continue;
576                        }
577                    )*
578                }
579
580            } else {
581                let mut multipart = match multipart::get_multipart_input(request) {
582                    Ok(m) => m,
583                    Err(multipart::MultipartError::WrongContentType) => {
584                        return Err(PostError::WrongContentType);
585                    },
586                    Err(multipart::MultipartError::BodyAlreadyExtracted) => {
587                        return Err(PostError::BodyAlreadyExtracted);
588                    },
589                };
590
591                while let Some(mut multipart_entry) = multipart.next() {
592                    $(
593                        if multipart_entry.headers.name.as_ref() == stringify!($field) {
594                            let config = ();
595                            $(
596                                let config = $config;
597                            )*
598
599                            if multipart_entry.is_text() {
600                                let mut text = String::new();
601                                multipart_entry.data.read_to_string(&mut text)?;
602                                let decoded = match DecodePostField::from_field(config, &text) {
603                                    Ok(d) => d,
604                                    Err(err) => return Err(PostError::Field {
605                                        field: stringify!($field).into(),
606                                        error: err,
607                                    }),
608                                };
609                                match merge(&mut $field, decoded) {
610                                    Ok(d) => d,
611                                    Err(err) => return Err(PostError::Field {
612                                        field: stringify!($field).into(),
613                                        error: err,
614                                    }),
615                                };
616                            } else {
617                                let name = multipart_entry.headers.filename.as_ref().map(|n| n.to_owned());
618                                let name = name.as_ref().map(|n| &n[..]);
619                                let mime = multipart_entry.headers.content_type
620                                    .map(|m| m.to_string())
621                                    .unwrap_or_else(String::new);
622                                let decoded = match DecodePostField::from_file(config, multipart_entry.data, name, &mime) {
623                                    Ok(d) => d,
624                                    Err(err) => return Err(PostError::Field {
625                                        field: stringify!($field).into(),
626                                        error: err,
627                                    }),
628                                };
629                                match merge(&mut $field, decoded) {
630                                    Ok(d) => d,
631                                    Err(err) => return Err(PostError::Field {
632                                        field: stringify!($field).into(),
633                                        error: err,
634                                    }),
635                                };
636                            }
637                            continue;
638                        }
639                    )*
640                }
641            }
642
643            Ok(PostInput {
644                $(
645                    $field: match $field {
646                        Some(v) => v,
647                        None => {
648                            let config = ();
649                            $(
650                                let config = $config;
651                            )*
652
653                            match DecodePostField::not_found(config) {
654                                Ok(d) => d,
655                                Err(err) => return Err(PostError::Field {
656                                    field: stringify!($field).into(),
657                                    error: err,
658                                }),
659                            }
660                        }
661                    },
662                )*
663            })
664        }
665
666        go($request)
667    });
668}
669
670/// Attempts to decode the `POST` data received by the request.
671///
672/// If successful, returns a list of fields and values.
673///
674/// Returns an error if the request's content-type is not related to POST data.
675// TODO: what to do with this function?
676pub fn raw_urlencoded_post_input(request: &Request) -> Result<Vec<(String, String)>, PostError> {
677    if request
678        .header("Content-Type")
679        .map(|ct| !ct.starts_with("application/x-www-form-urlencoded"))
680        .unwrap_or(true)
681    {
682        return Err(PostError::WrongContentType);
683    }
684
685    let body = {
686        // TODO: DDoSable server if body is too large?
687        let mut out = Vec::new(); // TODO: with_capacity()?
688        if let Some(mut b) = request.data() {
689            b.read_to_end(&mut out)?;
690        } else {
691            return Err(PostError::BodyAlreadyExtracted);
692        }
693        out
694    };
695
696    Ok(form_urlencoded::parse(&body).into_owned().collect()) // TODO: suboptimal
697}
698
699#[cfg(test)]
700mod tests {
701    use input::post::PostError;
702    use input::post::PostFieldError;
703    use Request;
704
705    #[test]
706    fn basic_int() {
707        let request = Request::fake_http(
708            "GET",
709            "/",
710            vec![
711                ("Host".to_owned(), "localhost".to_owned()),
712                (
713                    "Content-Type".to_owned(),
714                    "application/x-www-form-urlencoded".to_owned(),
715                ),
716            ],
717            b"field=12".to_vec(),
718        );
719
720        let input = post_input!(&request, { field: u32 }).unwrap();
721
722        assert_eq!(input.field, 12);
723    }
724
725    #[test]
726    fn basic_float() {
727        let request = Request::fake_http(
728            "GET",
729            "/",
730            vec![
731                ("Host".to_owned(), "localhost".to_owned()),
732                (
733                    "Content-Type".to_owned(),
734                    "application/x-www-form-urlencoded".to_owned(),
735                ),
736            ],
737            b"field=12.8".to_vec(),
738        );
739
740        let input = post_input!(&request, { field: f32 }).unwrap();
741
742        assert_eq!(input.field, 12.8);
743    }
744
745    #[test]
746    fn basic_string() {
747        let request = Request::fake_http(
748            "GET",
749            "/",
750            vec![
751                ("Host".to_owned(), "localhost".to_owned()),
752                (
753                    "Content-Type".to_owned(),
754                    "application/x-www-form-urlencoded".to_owned(),
755                ),
756            ],
757            b"field=value".to_vec(),
758        );
759
760        let input = post_input!(&request, { field: String }).unwrap();
761
762        assert_eq!(input.field, "value");
763    }
764
765    #[test]
766    fn basic_option_string() {
767        let request = Request::fake_http(
768            "GET",
769            "/",
770            vec![
771                ("Host".to_owned(), "localhost".to_owned()),
772                (
773                    "Content-Type".to_owned(),
774                    "application/x-www-form-urlencoded".to_owned(),
775                ),
776            ],
777            b"field=value".to_vec(),
778        );
779
780        let input = post_input!(&request, {
781            field: Option<String>
782        })
783        .unwrap();
784
785        assert_eq!(input.field.unwrap(), "value");
786    }
787
788    #[test]
789    fn basic_bool() {
790        let request = Request::fake_http(
791            "GET",
792            "/",
793            vec![
794                ("Host".to_owned(), "localhost".to_owned()),
795                (
796                    "Content-Type".to_owned(),
797                    "application/x-www-form-urlencoded".to_owned(),
798                ),
799            ],
800            b"field=value".to_vec(),
801        );
802
803        let input = post_input!(&request, { field: bool }).unwrap();
804
805        assert_eq!(input.field, true);
806    }
807
808    #[test]
809    fn weird_stuff() {
810        let request = Request::fake_http(
811            "GET",
812            "/",
813            vec![
814                ("Host".to_owned(), "localhost".to_owned()),
815                (
816                    "Content-Type".to_owned(),
817                    "application/x-www-form-urlencoded".to_owned(),
818                ),
819            ],
820            b"&=&aa&b=&c=c=c&field=value&".to_vec(),
821        );
822
823        let input = post_input!(&request, { field: String }).unwrap();
824
825        assert_eq!(input.field, "value");
826    }
827
828    #[test]
829    fn wrong_content_type() {
830        let request = Request::fake_http(
831            "GET",
832            "/",
833            vec![
834                ("Host".to_owned(), "localhost".to_owned()),
835                ("Content-Type".to_owned(), "wrong".to_owned()),
836            ],
837            b"field=value".to_vec(),
838        );
839
840        let input = post_input!(&request, { field: String });
841
842        match input {
843            Err(PostError::WrongContentType) => (),
844            _ => panic!(),
845        }
846    }
847
848    #[test]
849    fn too_many_fields() {
850        let request = Request::fake_http(
851            "GET",
852            "/",
853            vec![
854                ("Host".to_owned(), "localhost".to_owned()),
855                (
856                    "Content-Type".to_owned(),
857                    "application/x-www-form-urlencoded".to_owned(),
858                ),
859            ],
860            b"field=12&field2=58".to_vec(),
861        );
862
863        let input = post_input!(&request, { field: u32 }).unwrap();
864
865        assert_eq!(input.field, 12);
866    }
867
868    #[test]
869    fn multiple_values() {
870        let request = Request::fake_http(
871            "GET",
872            "/",
873            vec![
874                ("Host".to_owned(), "localhost".to_owned()),
875                (
876                    "Content-Type".to_owned(),
877                    "application/x-www-form-urlencoded".to_owned(),
878                ),
879            ],
880            b"field=12&field=58".to_vec(),
881        );
882
883        let input = post_input!(&request, { field: u32 });
884
885        match input {
886            Err(PostError::Field {
887                ref field,
888                error: PostFieldError::UnexpectedMultipleValues,
889            }) if field == "field" => (),
890            _ => panic!(),
891        }
892    }
893
894    #[test]
895    fn multiple_values_bool() {
896        let request = Request::fake_http(
897            "GET",
898            "/",
899            vec![
900                ("Host".to_owned(), "localhost".to_owned()),
901                (
902                    "Content-Type".to_owned(),
903                    "application/x-www-form-urlencoded".to_owned(),
904                ),
905            ],
906            b"field=12&field=58".to_vec(),
907        );
908
909        let input = post_input!(&request, { field: bool }).unwrap();
910
911        assert_eq!(input.field, true);
912    }
913
914    #[test]
915    fn multiple_values_vec() {
916        let request = Request::fake_http(
917            "GET",
918            "/",
919            vec![
920                ("Host".to_owned(), "localhost".to_owned()),
921                (
922                    "Content-Type".to_owned(),
923                    "application/x-www-form-urlencoded".to_owned(),
924                ),
925            ],
926            b"field=12&field=58".to_vec(),
927        );
928
929        let input = post_input!(&request, {
930            field: Vec<u32>
931        })
932        .unwrap();
933
934        assert_eq!(input.field, &[12, 58]);
935    }
936
937    #[test]
938    fn multiple_values_vec_parse_failure() {
939        let request = Request::fake_http(
940            "GET",
941            "/",
942            vec![
943                ("Host".to_owned(), "localhost".to_owned()),
944                (
945                    "Content-Type".to_owned(),
946                    "application/x-www-form-urlencoded".to_owned(),
947                ),
948            ],
949            b"field=12&field=800".to_vec(),
950        );
951
952        let input = post_input!(&request, {
953            field: Vec<u8>
954        });
955
956        match input {
957            Err(PostError::Field {
958                ref field,
959                error: PostFieldError::WrongDataTypeInt(_),
960            }) if field == "field" => (),
961            _ => panic!(),
962        }
963    }
964
965    #[test]
966    fn multiple_values_vec_option_parse_failure() {
967        let request = Request::fake_http(
968            "GET",
969            "/",
970            vec![
971                ("Host".to_owned(), "localhost".to_owned()),
972                (
973                    "Content-Type".to_owned(),
974                    "application/x-www-form-urlencoded".to_owned(),
975                ),
976            ],
977            b"field=12&field=800".to_vec(),
978        );
979
980        let input = post_input!(&request, {
981            field: Vec<Option<u8>>
982        })
983        .unwrap();
984
985        assert_eq!(input.field, &[Some(12), None]);
986    }
987
988    #[test]
989    fn missing_field() {
990        let request = Request::fake_http(
991            "GET",
992            "/",
993            vec![
994                ("Host".to_owned(), "localhost".to_owned()),
995                (
996                    "Content-Type".to_owned(),
997                    "application/x-www-form-urlencoded".to_owned(),
998                ),
999            ],
1000            b"wrong_field=value".to_vec(),
1001        );
1002
1003        let input = post_input!(&request, { field: String });
1004
1005        match input {
1006            Err(PostError::Field {
1007                ref field,
1008                error: PostFieldError::MissingField,
1009            }) if field == "field" => (),
1010            _ => panic!(),
1011        }
1012    }
1013
1014    #[test]
1015    fn missing_field_option() {
1016        let request = Request::fake_http(
1017            "GET",
1018            "/",
1019            vec![
1020                ("Host".to_owned(), "localhost".to_owned()),
1021                (
1022                    "Content-Type".to_owned(),
1023                    "application/x-www-form-urlencoded".to_owned(),
1024                ),
1025            ],
1026            b"wrong=value".to_vec(),
1027        );
1028
1029        let input = post_input!(&request, {
1030            field: Option<String>
1031        })
1032        .unwrap();
1033
1034        assert_eq!(input.field, None);
1035    }
1036
1037    #[test]
1038    fn missing_field_bool() {
1039        let request = Request::fake_http(
1040            "GET",
1041            "/",
1042            vec![
1043                ("Host".to_owned(), "localhost".to_owned()),
1044                (
1045                    "Content-Type".to_owned(),
1046                    "application/x-www-form-urlencoded".to_owned(),
1047                ),
1048            ],
1049            b"wrong=value".to_vec(),
1050        );
1051
1052        let input = post_input!(&request, { field: bool }).unwrap();
1053
1054        assert_eq!(input.field, false);
1055    }
1056
1057    #[test]
1058    fn missing_field_vec() {
1059        let request = Request::fake_http(
1060            "GET",
1061            "/",
1062            vec![
1063                ("Host".to_owned(), "localhost".to_owned()),
1064                (
1065                    "Content-Type".to_owned(),
1066                    "application/x-www-form-urlencoded".to_owned(),
1067                ),
1068            ],
1069            b"wrong=value".to_vec(),
1070        );
1071
1072        let input = post_input!(&request, {
1073            field: Vec<String>
1074        })
1075        .unwrap();
1076
1077        assert!(input.field.is_empty());
1078    }
1079
1080    #[test]
1081    fn num_parse_error() {
1082        let request = Request::fake_http(
1083            "GET",
1084            "/",
1085            vec![
1086                ("Host".to_owned(), "localhost".to_owned()),
1087                (
1088                    "Content-Type".to_owned(),
1089                    "application/x-www-form-urlencoded".to_owned(),
1090                ),
1091            ],
1092            b"field=12foo".to_vec(),
1093        );
1094
1095        let input = post_input!(&request, { field: u32 });
1096
1097        match input {
1098            Err(PostError::Field {
1099                ref field,
1100                error: PostFieldError::WrongDataTypeInt(_),
1101            }) if field == "field" => (),
1102            _ => panic!(),
1103        }
1104    }
1105
1106    #[test]
1107    fn num_parse_error_option() {
1108        let request = Request::fake_http(
1109            "GET",
1110            "/",
1111            vec![
1112                ("Host".to_owned(), "localhost".to_owned()),
1113                (
1114                    "Content-Type".to_owned(),
1115                    "application/x-www-form-urlencoded".to_owned(),
1116                ),
1117            ],
1118            b"field=12foo".to_vec(),
1119        );
1120
1121        let input = post_input!(&request, {
1122            field: Option<u32>
1123        })
1124        .unwrap();
1125
1126        assert_eq!(input.field, None);
1127    }
1128
1129    #[test]
1130    fn num_overflow() {
1131        let request = Request::fake_http(
1132            "GET",
1133            "/",
1134            vec![
1135                ("Host".to_owned(), "localhost".to_owned()),
1136                (
1137                    "Content-Type".to_owned(),
1138                    "application/x-www-form-urlencoded".to_owned(),
1139                ),
1140            ],
1141            b"field=800".to_vec(),
1142        );
1143
1144        let input = post_input!(&request, { field: u8 });
1145
1146        match input {
1147            Err(PostError::Field {
1148                ref field,
1149                error: PostFieldError::WrongDataTypeInt(_),
1150            }) if field == "field" => (),
1151            _ => panic!(),
1152        }
1153    }
1154
1155    #[test]
1156    fn body_extracted() {
1157        let request = Request::fake_http(
1158            "GET",
1159            "/",
1160            vec![
1161                ("Host".to_owned(), "localhost".to_owned()),
1162                (
1163                    "Content-Type".to_owned(),
1164                    "application/x-www-form-urlencoded".to_owned(),
1165                ),
1166            ],
1167            b"field=800".to_vec(),
1168        );
1169
1170        let _ = request.data();
1171
1172        let input = post_input!(&request, { field: u8 });
1173
1174        match input {
1175            Err(PostError::BodyAlreadyExtracted) => (),
1176            _ => panic!(),
1177        }
1178    }
1179
1180    #[test]
1181    #[ignore] // FIXME:
1182    fn not_utf8() {
1183        let request = Request::fake_http(
1184            "GET",
1185            "/",
1186            vec![
1187                ("Host".to_owned(), "localhost".to_owned()),
1188                (
1189                    "Content-Type".to_owned(),
1190                    "application/x-www-form-urlencoded".to_owned(),
1191                ),
1192            ],
1193            b"field=\xc3\x28".to_vec(),
1194        );
1195
1196        let input = post_input!(&request, { field: String });
1197
1198        match input {
1199            Err(PostError::NotUtf8(_)) => (),
1200            v => panic!("{:?}", v),
1201        }
1202    }
1203
1204    // TODO: add tests for multipart/form-data
1205}