1 #[macro_use] extern crate rocket;
2 
3 use rocket::request::{FromForm, FormItems, FormParseError};
4 use rocket::http::RawStr;
5 
parse<'f, T>(string: &'f str, strict: bool) -> Result<T, FormParseError<'f>> where T: FromForm<'f, Error = FormParseError<'f>>6 fn parse<'f, T>(string: &'f str, strict: bool) -> Result<T, FormParseError<'f>>
7     where T: FromForm<'f, Error = FormParseError<'f>>
8 {
9     let mut items = FormItems::from(string);
10     let result = T::from_form(items.by_ref(), strict);
11     if !items.exhaust() {
12         panic!("Invalid form input.");
13     }
14 
15     result
16 }
17 
strict<'f, T>(string: &'f str) -> Result<T, FormParseError<'f>> where T: FromForm<'f, Error = FormParseError<'f>>18 fn strict<'f, T>(string: &'f str) -> Result<T, FormParseError<'f>>
19     where T: FromForm<'f, Error = FormParseError<'f>>
20 {
21     parse(string, true)
22 }
23 
lenient<'f, T>(string: &'f str) -> Result<T, FormParseError<'f>> where T: FromForm<'f, Error = FormParseError<'f>>24 fn lenient<'f, T>(string: &'f str) -> Result<T, FormParseError<'f>>
25     where T: FromForm<'f, Error = FormParseError<'f>>
26 {
27     parse(string, false)
28 }
29 
30 #[derive(Debug, PartialEq, FromForm)]
31 struct TodoTask {
32     description: String,
33     completed: bool
34 }
35 
36 #[test]
simple()37 fn simple() {
38     // Same number of arguments: simple case.
39     let task: Option<TodoTask> = strict("description=Hello&completed=on").ok();
40     assert_eq!(task, Some(TodoTask {
41         description: "Hello".to_string(),
42         completed: true
43     }));
44 
45     // Argument in string but not in form.
46     let task: Option<TodoTask> = strict("other=a&description=Hello&completed=on").ok();
47     assert!(task.is_none());
48 
49     // Ensure _method isn't required.
50     let task: Option<TodoTask> = strict("_method=patch&description=Hello&completed=off").ok();
51     assert_eq!(task, Some(TodoTask {
52         description: "Hello".to_string(),
53         completed: false
54     }));
55 }
56 
57 #[derive(Debug, PartialEq, FromFormValue)]
58 enum FormOption {
59     A, B, C
60 }
61 
62 #[derive(Debug, PartialEq, FromForm)]
63 struct FormInput<'r> {
64     checkbox: bool,
65     number: usize,
66     radio: FormOption,
67     password: &'r RawStr,
68     textarea: String,
69     select: FormOption,
70 }
71 
72 #[derive(Debug, PartialEq, FromForm)]
73 struct DefaultInput<'r> {
74     arg: Option<&'r RawStr>,
75 }
76 
77 #[derive(Debug, PartialEq, FromForm)]
78 struct ManualMethod<'r> {
79     _method: Option<&'r RawStr>,
80     done: bool
81 }
82 
83 #[derive(Debug, PartialEq, FromForm)]
84 struct UnpresentCheckbox {
85     checkbox: bool
86 }
87 
88 #[derive(Debug, PartialEq, FromForm)]
89 struct UnpresentCheckboxTwo<'r> {
90     checkbox: bool,
91     something: &'r RawStr
92 }
93 
94 #[derive(Debug, PartialEq, FromForm)]
95 struct FieldNamedV<'r> {
96     v: &'r RawStr,
97 }
98 
99 #[test]
base_conditions()100 fn base_conditions() {
101     let form_string = &[
102         "password=testing", "checkbox=off", "checkbox=on", "number=10",
103         "checkbox=off", "textarea=", "select=a", "radio=c",
104     ].join("&");
105 
106     let input: Option<FormInput<'_>> = strict(&form_string).ok();
107     assert_eq!(input, Some(FormInput {
108         checkbox: false,
109         number: 10,
110         radio: FormOption::C,
111         password: "testing".into(),
112         textarea: "".to_string(),
113         select: FormOption::A,
114     }));
115 
116     // Argument not in string with default in form.
117     let default: Option<DefaultInput<'_>> = strict("").ok();
118     assert_eq!(default, Some(DefaultInput {
119         arg: None
120     }));
121 
122     // Ensure _method can be captured if desired.
123     let manual: Option<ManualMethod<'_>> = strict("_method=put&done=true").ok();
124     assert_eq!(manual, Some(ManualMethod {
125         _method: Some("put".into()),
126         done: true
127     }));
128 
129     let manual: Option<ManualMethod<'_>> = lenient("_method=put&done=true").ok();
130     assert_eq!(manual, Some(ManualMethod {
131         _method: Some("put".into()),
132         done: true
133     }));
134 
135     // And ignored when not present.
136     let manual: Option<ManualMethod<'_>> = strict("done=true").ok();
137     assert_eq!(manual, Some(ManualMethod {
138         _method: None,
139         done: true
140     }));
141 
142     // Check that a `bool` value that isn't in the form is marked as `false`.
143     let manual: Option<UnpresentCheckbox> = strict("").ok();
144     assert_eq!(manual, Some(UnpresentCheckbox {
145         checkbox: false
146     }));
147 
148     // Check that a `bool` value that isn't in the form is marked as `false`.
149     let manual: Option<UnpresentCheckboxTwo<'_>> = strict("something=hello").ok();
150     assert_eq!(manual, Some(UnpresentCheckboxTwo {
151         checkbox: false,
152         something: "hello".into()
153     }));
154 
155     // Check that a structure with one field `v` parses correctly.
156     let manual: Option<FieldNamedV<'_>> = strict("v=abc").ok();
157     assert_eq!(manual, Some(FieldNamedV {
158         v: "abc".into()
159     }));
160 
161 }
162 
163 #[test]
lenient_parsing()164 fn lenient_parsing() {
165     // Check that a structure with one field `v` parses correctly (lenient).
166     let manual: Option<FieldNamedV<'_>> = lenient("v=abc").ok();
167     assert_eq!(manual, Some(FieldNamedV { v: "abc".into() }));
168 
169     let manual: Option<FieldNamedV<'_>> = lenient("v=abc&a=123").ok();
170     assert_eq!(manual, Some(FieldNamedV { v: "abc".into() }));
171 
172     let manual: Option<FieldNamedV<'_>> = lenient("c=abcddef&v=abc&a=123").ok();
173     assert_eq!(manual, Some(FieldNamedV { v: "abc".into() }));
174 
175     // Check default values (bool) with lenient parsing.
176     let manual: Option<UnpresentCheckboxTwo<'_>> = lenient("something=hello").ok();
177     assert_eq!(manual, Some(UnpresentCheckboxTwo {
178         checkbox: false,
179         something: "hello".into()
180     }));
181 
182     let manual: Option<UnpresentCheckboxTwo<'_>> = lenient("hi=hi&something=hello").ok();
183     assert_eq!(manual, Some(UnpresentCheckboxTwo {
184         checkbox: false,
185         something: "hello".into()
186     }));
187 
188     // Check that a missing field doesn't parse, even leniently.
189     let manual: Option<FieldNamedV<'_>> = lenient("a=abc").ok();
190     assert!(manual.is_none());
191 
192     let manual: Option<FieldNamedV<'_>> = lenient("_method=abc").ok();
193     assert!(manual.is_none());
194 }
195 
196 #[derive(Debug, PartialEq, FromForm)]
197 struct RenamedForm {
198     single: usize,
199     #[form(field = "camelCase")]
200     camel_case: String,
201     #[form(field = "TitleCase")]
202     title_case: String,
203     #[form(field = "type")]
204     field_type: isize,
205     #[form(field = "DOUBLE")]
206     double: String,
207     #[form(field = "a.b")]
208     dot: isize,
209     #[form(field = "some space")]
210     some_space: String,
211 }
212 
213 #[test]
field_renaming()214 fn field_renaming() {
215     let form_string = &[
216         "single=100", "camelCase=helloThere", "TitleCase=HiHi", "type=-2",
217         "DOUBLE=bing_bong", "a.b=123", "some space=okay"
218     ].join("&");
219 
220     let form: Option<RenamedForm> = strict(&form_string).ok();
221     assert_eq!(form, Some(RenamedForm {
222         single: 100,
223         camel_case: "helloThere".into(),
224         title_case: "HiHi".into(),
225         field_type: -2,
226         double: "bing_bong".into(),
227         dot: 123,
228         some_space: "okay".into(),
229     }));
230 
231     let form_string = &[
232         "single=100", "camel_case=helloThere", "TitleCase=HiHi", "type=-2",
233         "DOUBLE=bing_bong", "dot=123", "some_space=okay"
234     ].join("&");
235 
236     let form: Option<RenamedForm> = strict(&form_string).ok();
237     assert!(form.is_none());
238 }
239 
240 #[derive(FromForm, Debug, PartialEq)]
241 struct YetOneMore<'f, T> {
242     string: &'f RawStr,
243     other: T,
244 }
245 
246 #[derive(FromForm, Debug, PartialEq)]
247 struct Oops<A, B, C> {
248     base: String,
249     a: A,
250     b: B,
251     c: C,
252 }
253 
254 #[test]
generics()255 fn generics() {
256     let form_string = &[
257         "string=hello", "other=00128"
258     ].join("&");
259 
260     let form: Option<YetOneMore<'_, usize>> = strict(&form_string).ok();
261     assert_eq!(form, Some(YetOneMore {
262         string: "hello".into(),
263         other: 128,
264     }));
265 
266     let form: Option<YetOneMore<'_, u8>> = strict(&form_string).ok();
267     assert_eq!(form, Some(YetOneMore {
268         string: "hello".into(),
269         other: 128,
270     }));
271 
272     let form: Option<YetOneMore<'_, i8>> = strict(&form_string).ok();
273     assert!(form.is_none());
274 
275     let form_string = &[
276         "base=just%20a%20test", "a=hey%20there", "b=a", "c=811",
277     ].join("&");
278 
279     let form: Option<Oops<&RawStr, FormOption, usize>> = strict(&form_string).ok();
280     assert_eq!(form, Some(Oops {
281         base: "just a test".into(),
282         a: "hey%20there".into(),
283         b: FormOption::A,
284         c: 811,
285     }));
286 }
287 
288 #[derive(Debug, PartialEq, FromForm)]
289 struct WhoopsForm {
290     complete: bool,
291     other: usize,
292 }
293 
294 #[test]
form_errors()295 fn form_errors() {
296     let form: Result<WhoopsForm, _> = strict("complete=true&other=781");
297     assert_eq!(form, Ok(WhoopsForm { complete: true, other: 781 }));
298 
299     let form: Result<WhoopsForm, _> = strict("complete=true&other=unknown");
300     assert_eq!(form, Err(FormParseError::BadValue("other".into(), "unknown".into())));
301 
302     let form: Result<WhoopsForm, _> = strict("complete=unknown&other=unknown");
303     assert_eq!(form, Err(FormParseError::BadValue("complete".into(), "unknown".into())));
304 
305     let form: Result<WhoopsForm, _> = strict("complete=true&other=1&extra=foo");
306     assert_eq!(form, Err(FormParseError::Unknown("extra".into(), "foo".into())));
307 
308     // Bad values take highest precedence.
309     let form: Result<WhoopsForm, _> = strict("complete=unknown&unknown=foo");
310     assert_eq!(form, Err(FormParseError::BadValue("complete".into(), "unknown".into())));
311 
312     // Then unknown key/values for strict parses.
313     let form: Result<WhoopsForm, _> = strict("complete=true&unknown=foo");
314     assert_eq!(form, Err(FormParseError::Unknown("unknown".into(), "foo".into())));
315 
316     // Finally, missing.
317     let form: Result<WhoopsForm, _> = strict("complete=true");
318     assert_eq!(form, Err(FormParseError::Missing("other".into())));
319 }
320