mirror of https://github.com/rwf2/Rocket.git
parent
1f373cc83a
commit
a1878ad080
|
@ -15,7 +15,6 @@ 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 {
|
||||
|
@ -137,18 +136,10 @@ impl RouteGenerateExt for RouteParams {
|
|||
Some(s) => <$ty as ::rocket::request::FromParam>::from_param(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)
|
||||
})
|
||||
},
|
||||
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)
|
||||
}),
|
||||
};
|
||||
|
||||
let original_ident = param.ident();
|
||||
|
|
|
@ -32,9 +32,9 @@ impl<'a> URI<'a> {
|
|||
let qmark = uri.find('?');
|
||||
let hmark = uri.find('#');
|
||||
|
||||
let (start, end) = (0, uri.len());
|
||||
let end = uri.len();
|
||||
let (path, query, fragment) = match (qmark, hmark) {
|
||||
(Some(i), Some(j)) => ((start, i), Some((i+1, j)), Some((j+1, end))),
|
||||
(Some(i), Some(j)) => ((0, i), Some((i+1, j)), Some((j+1, end))),
|
||||
(Some(i), None) => ((0, i), Some((i+1, end)), None),
|
||||
(None, Some(j)) => ((0, j), None, Some((j+1, end))),
|
||||
(None, None) => ((0, end), None, None),
|
||||
|
@ -340,7 +340,7 @@ impl<'a, 'b> Collider<URI<'b>> for URI<'a> {
|
|||
/// }
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Segments<'a>(&'a str);
|
||||
pub struct Segments<'a>(pub &'a str);
|
||||
|
||||
impl<'a> Iterator for Segments<'a> {
|
||||
type Item = &'a str;
|
||||
|
|
|
@ -245,8 +245,8 @@ impl<'r> Request<'r> {
|
|||
.unwrap_or(ContentType::Any)
|
||||
}
|
||||
|
||||
/// Retrieves and parses into `T` the `n`th dynamic parameter from the
|
||||
/// request. Returns `Error::NoKey` if `n` is greater than the number of
|
||||
/// Retrieves and parses into `T` the 0-indexed `n`th dynamic parameter from
|
||||
/// the request. Returns `Error::NoKey` if `n` is greater than the number of
|
||||
/// params. Returns `Error::BadParse` if the parameter type `T` can't be
|
||||
/// parsed from the parameter.
|
||||
///
|
||||
|
@ -290,49 +290,58 @@ impl<'r> Request<'r> {
|
|||
}
|
||||
|
||||
let (i, j) = params[n];
|
||||
let uri_str = self.uri.as_str();
|
||||
if j > uri_str.len() {
|
||||
let path = self.uri.path();
|
||||
if j > path.len() {
|
||||
error!("Couldn't retrieve parameter: internal count incorrect.");
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(&uri_str[i..j])
|
||||
Some(&path[i..j])
|
||||
}
|
||||
|
||||
/// Retrieves and parses into `T` all of the path segments in the request
|
||||
/// URI beginning and including the 0-indexed `i`. `T` must implement
|
||||
/// [FromSegments](/rocket/request/trait.FromSegments.html), which is used
|
||||
/// to parse the segments.
|
||||
/// URI beginning at the 0-indexed `n`th dynamic parameter. `T` must
|
||||
/// implement [FromSegments](/rocket/request/trait.FromSegments.html), which
|
||||
/// is used to parse the segments.
|
||||
///
|
||||
/// This method exists only to be used by manual routing. To retrieve
|
||||
/// segments from a request, use Rocket's code generation facilities.
|
||||
///
|
||||
/// # Error
|
||||
///
|
||||
/// If there are less than `i` segments, returns an `Err` of `NoKey`. If
|
||||
/// If there are less than `n` segments, returns an `Err` of `NoKey`. If
|
||||
/// parsing the segments failed, returns an `Err` of `BadParse`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// If the request URI is `"/hello/there/i/am/here"`, then
|
||||
/// If the request URI is `"/hello/there/i/am/here"`, and the matched route
|
||||
/// path for this request is `"/hello/<name>/i/<segs..>"`, then
|
||||
/// `request.get_segments::<T>(1)` will attempt to parse the segments
|
||||
/// `"there/i/am/here"` as type `T`.
|
||||
pub fn get_segments<'a, T: FromSegments<'a>>(&'a self, i: usize)
|
||||
/// `"am/here"` as type `T`.
|
||||
pub fn get_segments<'a, T: FromSegments<'a>>(&'a self, n: usize)
|
||||
-> Result<T, Error> {
|
||||
let segments = self.get_raw_segments(i).ok_or(Error::NoKey)?;
|
||||
let segments = self.get_raw_segments(n).ok_or(Error::NoKey)?;
|
||||
T::from_segments(segments).map_err(|_| Error::BadParse)
|
||||
}
|
||||
|
||||
/// Get the segments beginning at the `i`th, if they exists.
|
||||
/// Get the segments beginning at the `n`th dynamic parameter, if they
|
||||
/// exist.
|
||||
#[doc(hidden)]
|
||||
pub fn get_raw_segments(&self, i: usize) -> Option<Segments> {
|
||||
if i >= self.uri.segment_count() {
|
||||
debug!("{} is >= segment count {}", i, self.uri().segment_count());
|
||||
None
|
||||
} else {
|
||||
// TODO: Really want to do self.uri.segments().skip(i).into_inner(),
|
||||
// but the std lib doesn't implement `into_inner` for Skip.
|
||||
let mut segments = self.uri.segments();
|
||||
for _ in segments.by_ref().take(i) { /* do nothing */ }
|
||||
Some(segments)
|
||||
pub fn get_raw_segments(&self, n: usize) -> Option<Segments> {
|
||||
let params = self.params.borrow();
|
||||
if n >= params.len() {
|
||||
debug!("{} is >= param (segments) count {}", n, params.len());
|
||||
return None;
|
||||
}
|
||||
|
||||
let (i, j) = params[n];
|
||||
let path = self.uri.path();
|
||||
if j > path.len() {
|
||||
error!("Couldn't retrieve segments: internal count incorrect.");
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Segments(&path[i..j]))
|
||||
}
|
||||
|
||||
/// Convert from Hyper types into a Rocket Request.
|
||||
|
|
|
@ -133,6 +133,10 @@ mod test {
|
|||
assert!(unranked_route_collisions(&["/<a>/b", "/a/<a..>"]));
|
||||
assert!(unranked_route_collisions(&["/a/<b>", "/a/<a..>"]));
|
||||
assert!(unranked_route_collisions(&["/a/b/<c>", "/a/<a..>"]));
|
||||
assert!(unranked_route_collisions(&["<a..>", "/a/<a..>"]));
|
||||
assert!(unranked_route_collisions(&["/a/<a..>", "/a/<a..>"]));
|
||||
assert!(unranked_route_collisions(&["/a/b/<a..>", "/a/<a..>"]));
|
||||
assert!(unranked_route_collisions(&["/a/b/c/d", "/a/<a..>"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -140,10 +144,12 @@ mod test {
|
|||
assert!(!unranked_route_collisions(&["/<a>", "/a/<a..>"]));
|
||||
assert!(!unranked_route_collisions(&["/a/b", "/a/b/c"]));
|
||||
assert!(!unranked_route_collisions(&["/a/b/c/d", "/a/b/c/<d>/e"]));
|
||||
assert!(!unranked_route_collisions(&["/a/d/<b..>", "/a/b/c"]));
|
||||
assert!(!unranked_route_collisions(&["/a/d/<b..>", "/a/d"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_none_collisions_when_ranked() {
|
||||
fn test_no_collision_when_ranked() {
|
||||
assert!(!default_rank_route_collisions(&["/<a>", "/hello"]));
|
||||
assert!(!default_rank_route_collisions(&["/hello/bob", "/hello/<b>"]));
|
||||
assert!(!default_rank_route_collisions(&["/a/b/c/d", "/<a>/<b>/c/d"]));
|
||||
|
@ -261,6 +267,17 @@ mod test {
|
|||
assert!(!ranked_collisions(&[(0, "a/<b>"), (2, "a/<b>")]));
|
||||
assert!(!ranked_collisions(&[(5, "a/<b>"), (2, "a/<b>")]));
|
||||
assert!(!ranked_collisions(&[(1, "a/<b>"), (1, "b/<b>")]));
|
||||
assert!(!ranked_collisions(&[(1, "a/<b..>"), (2, "a/<b..>")]));
|
||||
assert!(!ranked_collisions(&[(0, "a/<b..>"), (2, "a/<b..>")]));
|
||||
assert!(!ranked_collisions(&[(5, "a/<b..>"), (2, "a/<b..>")]));
|
||||
assert!(!ranked_collisions(&[(1, "<a..>"), (2, "<a..>")]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ranked_collisions() {
|
||||
assert!(ranked_collisions(&[(2, "a/<b..>"), (2, "a/<b..>")]));
|
||||
assert!(ranked_collisions(&[(2, "a/c/<b..>"), (2, "a/<b..>")]));
|
||||
assert!(ranked_collisions(&[(2, "<b..>"), (2, "a/<b..>")]));
|
||||
}
|
||||
|
||||
macro_rules! assert_ranked_routing {
|
||||
|
|
|
@ -77,14 +77,15 @@ impl Route {
|
|||
pub fn get_param_indexes(&self, uri: &URI) -> Vec<(usize, usize)> {
|
||||
let route_segs = self.path.segments();
|
||||
let uri_segs = uri.segments();
|
||||
let start_addr = uri.as_str().as_ptr() as usize;
|
||||
let start_addr = uri.path().as_ptr() as usize;
|
||||
|
||||
let mut result = Vec::with_capacity(self.path.segment_count());
|
||||
for (route_seg, uri_seg) in route_segs.zip(uri_segs) {
|
||||
let i = (uri_seg.as_ptr() as usize) - start_addr;
|
||||
if route_seg.ends_with("..>") {
|
||||
result.push((i, uri.path().len()));
|
||||
break;
|
||||
} else if route_seg.ends_with('>') {
|
||||
let i = (uri_seg.as_ptr() as usize) - start_addr;
|
||||
let j = i + uri_seg.len();
|
||||
result.push((i, j));
|
||||
}
|
||||
|
|
|
@ -25,16 +25,26 @@ fn none(path: Segments) -> String {
|
|||
path.collect::<Vec<_>>().join("/")
|
||||
}
|
||||
|
||||
#[get("/static/<user>/is/<path..>")]
|
||||
fn dual(user: String, path: Segments) -> String {
|
||||
user + "/is/" + &path.collect::<Vec<_>>().join("/")
|
||||
}
|
||||
|
||||
use rocket::testing::MockRequest;
|
||||
use rocket::http::Method::*;
|
||||
|
||||
#[test]
|
||||
fn segments_works() {
|
||||
let rocket = rocket::ignite().mount("/", routes![test, two, one_two, none]);
|
||||
let rocket = rocket::ignite()
|
||||
.mount("/", routes![test, two, one_two, none, dual])
|
||||
.mount("/point", routes![test, two, one_two, dual]);
|
||||
|
||||
// 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"] {
|
||||
for prefix in &["", "/test", "/two", "/one/two",
|
||||
"/point/test", "/point/two", "/point/one/two",
|
||||
"/static", "/point/static"]
|
||||
{
|
||||
let path = "this/is/the/path/we/want";
|
||||
let mut req = MockRequest::new(Get, format!("{}/{}", prefix, path));
|
||||
|
Loading…
Reference in New Issue