diff --git a/codegen/src/decorators/route.rs b/codegen/src/decorators/route.rs index e43a173ad7..7bf2bf0170 100644 --- a/codegen/src/decorators/route.rs +++ b/codegen/src/decorators/route.rs @@ -15,6 +15,7 @@ use syntax::parse::token; use syntax::ptr::P; use rocket::http::{Method, ContentType}; +use rocket::http::uri::URI; fn method_to_path(ecx: &ExtCtxt, method: Method) -> Path { quote_enum!(ecx, method => ::rocket::http::Method { @@ -136,10 +137,18 @@ impl RouteGenerateExt for RouteParams { Some(s) => <$ty as ::rocket::request::FromParam>::from_param(s), None => return ::rocket::Outcome::Forward(_data) }), - Param::Many(_) => quote_expr!(ecx, match _req.get_raw_segments($i) { - Some(s) => <$ty as ::rocket::request::FromSegments>::from_segments(s), - None => return ::rocket::Outcome::forward(_data) - }), + Param::Many(_) => { + // Determine the index the dynamic segments parameter begins. + let d = URI::new(self.path.node.as_str()).segments().enumerate() + .filter(|&(_, s)| s.starts_with("<")) + .map((&|(d, _)| d)) + .next().expect("segment when segment is iterated"); + + quote_expr!(ecx, match _req.get_raw_segments($d) { + Some(s) => <$ty as ::rocket::request::FromSegments>::from_segments(s), + None => return ::rocket::Outcome::forward(_data) + }) + }, }; let original_ident = param.ident(); diff --git a/lib/tests/segments-issue-41.rs b/lib/tests/segments-issue-41.rs new file mode 100644 index 0000000000..63c849e41b --- /dev/null +++ b/lib/tests/segments-issue-41.rs @@ -0,0 +1,45 @@ +#![feature(plugin)] +#![plugin(rocket_codegen)] + +extern crate rocket; + +use std::path::PathBuf; + +#[get("/test/")] +fn test(path: PathBuf) -> String { + format!("{:?}", path) +} + +#[get("/two/")] +fn two(path: PathBuf) -> String { + format!("{:?}", path) +} + +#[get("/one/two/")] +fn one_two(path: PathBuf) -> String { + format!("{:?}", path) +} + +#[get("/", rank = 2)] +fn none(path: PathBuf) -> String { + format!("{:?}", path) +} + +use rocket::testing::MockRequest; +use rocket::http::Method::*; + +#[test] +fn segments_works() { + let rocket = rocket::ignite().mount("/", routes![test, two, one_two, none]); + + // We construct a path that matches each of the routes above. We ensure the + // prefix is stripped, confirming that dynamic segments are working. + for prefix in &["", "/test", "/two", "/one/two"] { + let path = "this/is/the/path/we/want"; + let mut req = MockRequest::new(Get, format!("{}/{}", prefix, path)); + + let mut response = req.dispatch_with(&rocket); + let body_str = response.body().and_then(|b| b.into_string()); + assert_eq!(body_str, Some(format!("{:?}", path))); + } +}