From b7d22d58f74a6aecb9d25e28f24b2fe26baf92e1 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Sun, 3 Apr 2016 22:41:31 -0700 Subject: [PATCH] Actually useful forms! --- examples/forms/src/main.rs | 122 ++++++++----------------------- examples/forms/static/index.html | 1 + lib/src/error.rs | 1 + lib/src/lib.rs | 1 + 4 files changed, 34 insertions(+), 91 deletions(-) diff --git a/examples/forms/src/main.rs b/examples/forms/src/main.rs index 7ff7f19e..72941dda 100644 --- a/examples/forms/src/main.rs +++ b/examples/forms/src/main.rs @@ -8,6 +8,7 @@ mod files; use rocket::Rocket; use rocket::response::Redirect; use rocket::Error; +use rocket::form::{FromForm, FromFormValue, form_items}; #[route(GET, path = "/user/")] fn user_page(username: &str) -> String { @@ -17,56 +18,37 @@ fn user_page(username: &str) -> String { // #[derive(FromForm)] // FIXME: Make that happen. struct UserLogin<'a> { username: &'a str, - password: &'a str + password: &'a str, + age: Result, } -fn form_items<'f>(string: &'f str, items: &mut [(&'f str, &'f str)]) -> usize { - let mut param_num = 0; - let mut rest = string; - while rest.len() > 0 && param_num < items.len() { - let (key, remainder) = match rest.find('=') { - Some(index) => (&rest[..index], &rest[(index + 1)..]), - None => return param_num - }; - - rest = remainder; - let (value, remainder) = match rest.find('&') { - Some(index) => (&rest[..index], &rest[(index + 1)..]), - None => (rest, "") - }; - - rest = remainder; - items[param_num] = (key, value); - param_num += 1; - } - - param_num -} - -trait FromForm<'f>: Sized { - fn from_form_string(s: &'f str) -> Result; -} - -// FIXME: Add a 'FromFormValue' trait and use it on each field in the form -// structure. Should be pretty simple. Implement for all FromStr and then -// implement for OptionT: FromFormValue> so forms still exist. Maybe have a way -// for FromFormValue types to have an error that says why it didn't work. This // will help for validation. IE, can have a type Range(1, 10) that returns an // enum with one of: TooLow(isize), TooHigh(isize), etc. impl<'f> FromForm<'f> for UserLogin<'f> { fn from_form_string(s: &'f str) -> Result { - let mut items = [("", ""); 2]; + let mut items = [("", ""); 3]; let form_count = form_items(s, &mut items); - if form_count != 2 { + if form_count != items.len() { return Err(Error::BadParse); } - let mut username = None; - let mut password = None; + let mut username: Option<&'f str> = None; + let mut password: Option<&'f str> = None; + let mut age: Option> = None; for &(key, value) in &items { match key { - "username" => username = Some(value), - "password" => password = Some(value), + "username" => username = match FromFormValue::parse(value) { + Ok(v) => Some(v), + Err(_) => return Err(Error::BadParse) + }, + "password" => password = match FromFormValue::parse(value) { + Ok(v) => Some(v), + Err(_) => return Err(Error::BadParse) + }, + "age" => age = match FromFormValue::parse(value) { + Ok(v) => Some(v), + Err(_) => return Err(Error::BadParse) + }, _ => return Err(Error::BadParse) } } @@ -77,7 +59,8 @@ impl<'f> FromForm<'f> for UserLogin<'f> { Ok(UserLogin { username: username.unwrap(), - password: password.unwrap() + password: password.unwrap(), + age: age.unwrap(), }) } } @@ -86,6 +69,15 @@ impl<'f> FromForm<'f> for UserLogin<'f> { // FIXME: fn login<'a>(user: UserLogin<'a>) #[route(POST, path = "/login", form = "")] fn login(user: UserLogin) -> Result { + if user.age.is_err() { + let input = user.age.unwrap_err(); + return Err(format!("'{}' is not a valid age integer.", input)); + } + + if user.age.unwrap() < 20 { + return Err(format!("Sorry, {} is too young!", user.age.unwrap())); + } + match user.username { "Sergio" => match user.password { "password" => Ok(Redirect::other("/user/Sergio")), @@ -100,55 +92,3 @@ fn main() { rocket.mount("/", routes![files::index, files::files, user_page, login]); rocket.launch(); } - -#[cfg(test)] -mod test { - use super::form_items; - - macro_rules! check_form { - ($string:expr, $expected: expr) => ({ - let mut output = Vec::with_capacity($expected.len()); - unsafe { output.set_len($expected.len()); } - - let results = output.as_mut_slice(); - assert_eq!($expected.len(), form_items($string, results)); - - 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); - } - }) - } - - #[test] - fn test_form_string() { - let results = &[("username", "user"), ("password", "pass")]; - check_form!("username=user&password=pass", results); - - let results = &[("user", "user"), ("user", "pass")]; - check_form!("user=user&user=pass", results); - - let results = &[("user", ""), ("password", "pass")]; - check_form!("user=&password=pass", results); - - let results = &[("", ""), ("", "")]; - check_form!("=&=", results); - - let results = &[("a", "b")]; - check_form!("a=b", results); - - let results = &[("a", "b")]; - check_form!("a=b&a", results); - - let results = &[("a", "b"), ("a", "")]; - check_form!("a=b&a=", results); - } -} diff --git a/examples/forms/static/index.html b/examples/forms/static/index.html index 0bd425f1..66bf2339 100644 --- a/examples/forms/static/index.html +++ b/examples/forms/static/index.html @@ -3,5 +3,6 @@
Username: Password: + Age:
diff --git a/lib/src/error.rs b/lib/src/error.rs index b67504b3..46af91a2 100644 --- a/lib/src/error.rs +++ b/lib/src/error.rs @@ -1,3 +1,4 @@ +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Error { BadMethod, BadParse, diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 49d99114..06647a4c 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -11,6 +11,7 @@ mod router; mod rocket; mod codegen; +pub mod form; pub mod request; pub mod response;