diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index 1368aea4..b838a605 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -19,7 +19,7 @@ rocket = { version = "0.3.0", path = "../lib/" } log = "0.3" [dev-dependencies] -compiletest_rs = "0.2" +compiletest_rs = "0.2.9" [build-dependencies] yansi = "0.3" diff --git a/codegen/src/decorators/derive_form.rs b/codegen/src/decorators/derive_form.rs index ae02de85..5c2a6ba8 100644 --- a/codegen/src/decorators/derive_form.rs +++ b/codegen/src/decorators/derive_form.rs @@ -122,6 +122,18 @@ pub fn from_form_derive(ecx: &mut ExtCtxt, span: Span, meta_item: &MetaItem, trait_def.expand(ecx, meta_item, annotated, push); } +fn is_valid_field_name(name: &str) -> bool { + // The HTML5 spec (4.10.18.1) says 'isindex' is not allowed. + if name == "isindex" || name.is_empty() { + return false + } + + // We allow all visible ASCII characters except '&', '=', and '?' since we + // use those as control characters for parsing. + name.chars() + .all(|c| (c >= ' ' && c <= '~') && c != '&' && c != '=' && c != '?') +} + pub fn extract_field_ident_name(ecx: &ExtCtxt, struct_field: &StructField) -> (Ident, String, Span) { let ident = match struct_field.ident { @@ -168,8 +180,10 @@ pub fn extract_field_ident_name(ecx: &ExtCtxt, struct_field: &StructField) let name = inner_item.value_str().unwrap().as_str().to_string(); let sp = inner_item.span.shorten_upto(name.len() + 2); - if !is_valid_ident(&name) { - ecx.span_err(sp, "invalid form field identifier"); + if !is_valid_field_name(&name) { + ecx.struct_span_err(sp, "invalid form field name") + .help("field names be visible ASCII characters without '&', '=', or '?'") + .emit(); } (ident, name, sp) diff --git a/codegen/tests/compile-fail/form-field-attr.rs b/codegen/tests/compile-fail/form-field-attr.rs index 5ccd45c6..f6118707 100644 --- a/codegen/tests/compile-fail/form-field-attr.rs +++ b/codegen/tests/compile-fail/form-field-attr.rs @@ -84,7 +84,7 @@ struct MyForm10 { #[derive(FromForm)] struct MyForm11 { - #[form(field = "hello world")] + #[form(field = "hello&world")] //~^ ERROR: invalid form field first: String, } @@ -95,3 +95,17 @@ struct MyForm12 { //~^ ERROR: invalid form field first: String, } + +#[derive(FromForm)] +struct MyForm13 { + #[form(field = "?")] + //~^ ERROR: invalid form field + first: String, +} + +#[derive(FromForm)] +struct MyForm14 { + #[form(field = "")] + //~^ ERROR: invalid form field + first: String, +} diff --git a/codegen/tests/run-pass/form-field-rename.rs b/codegen/tests/run-pass/form-field-rename.rs index 83dcef66..ec99d7a8 100644 --- a/codegen/tests/run-pass/form-field-rename.rs +++ b/codegen/tests/run-pass/form-field-rename.rs @@ -17,6 +17,8 @@ struct Form { field_type: isize, #[form(field = "DOUBLE")] double: String, + #[form(field = "a.b")] + dot: isize, } fn parse<'f, T: FromForm<'f>>(string: &'f str, strict: bool) -> Option { @@ -36,7 +38,7 @@ fn parse_strict<'f, T: FromForm<'f>>(string: &'f str) -> Option { fn main() { let form_string = &[ "single=100", "camelCase=helloThere", "TitleCase=HiHi", "type=-2", - "DOUBLE=bing_bong" + "DOUBLE=bing_bong", "a.b=123", ].join("&"); let form: Option
= parse_strict(&form_string); @@ -45,12 +47,13 @@ fn main() { camel_case: "helloThere".into(), title_case: "HiHi".into(), field_type: -2, - double: "bing_bong".into() + double: "bing_bong".into(), + dot: 123, })); let form_string = &[ "single=100", "camel_case=helloThere", "TitleCase=HiHi", "type=-2", - "DOUBLE=bing_bong" + "DOUBLE=bing_bong", "dot=123", ].join("&"); let form: Option = parse_strict(&form_string); diff --git a/codegen/tests/tests.rs b/codegen/tests/tests.rs index 3f813710..52f4d8c9 100644 --- a/codegen/tests/tests.rs +++ b/codegen/tests/tests.rs @@ -3,7 +3,7 @@ extern crate compiletest_rs as compiletest; use std::path::PathBuf; fn run_mode(mode: &'static str) { - let mut config = compiletest::default_config(); + let mut config = compiletest::Config::default(); let cfg_mode = mode.parse().expect("Invalid mode"); config.mode = cfg_mode;