mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-27 17:52:56 +01:00
checks nested scopes in has_resource()
This commit is contained in:
parent
22385505a3
commit
2dd57a48d6
@ -1,10 +1,10 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## [0.7.0] - 2018-07-10
|
## [0.7.0] - 2018-07-17
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
* Add `.has_prefixed_route()` method to `router::RouteInfo` for route matching with prefix awareness
|
* Add `.has_prefixed_resource()` method to `router::ResourceInfo` for route matching with prefix awareness
|
||||||
|
|
||||||
* Add `HttpMessage::readlines()` for reading line by line.
|
* Add `HttpMessage::readlines()` for reading line by line.
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ impl<S> Handler<S> for NormalizePath {
|
|||||||
// merge slashes
|
// merge slashes
|
||||||
let p = self.re_merge.replace_all(req.path(), "/");
|
let p = self.re_merge.replace_all(req.path(), "/");
|
||||||
if p.len() != req.path().len() {
|
if p.len() != req.path().len() {
|
||||||
if req.resource().has_prefixed_route(p.as_ref()) {
|
if req.resource().has_prefixed_resource(p.as_ref()) {
|
||||||
let p = if !query.is_empty() {
|
let p = if !query.is_empty() {
|
||||||
p + "?" + query
|
p + "?" + query
|
||||||
} else {
|
} else {
|
||||||
@ -105,7 +105,7 @@ impl<S> Handler<S> for NormalizePath {
|
|||||||
// merge slashes and append trailing slash
|
// merge slashes and append trailing slash
|
||||||
if self.append && !p.ends_with('/') {
|
if self.append && !p.ends_with('/') {
|
||||||
let p = p.as_ref().to_owned() + "/";
|
let p = p.as_ref().to_owned() + "/";
|
||||||
if req.resource().has_prefixed_route(&p) {
|
if req.resource().has_prefixed_resource(&p) {
|
||||||
let p = if !query.is_empty() {
|
let p = if !query.is_empty() {
|
||||||
p + "?" + query
|
p + "?" + query
|
||||||
} else {
|
} else {
|
||||||
@ -120,7 +120,7 @@ impl<S> Handler<S> for NormalizePath {
|
|||||||
// try to remove trailing slash
|
// try to remove trailing slash
|
||||||
if p.ends_with('/') {
|
if p.ends_with('/') {
|
||||||
let p = p.as_ref().trim_right_matches('/');
|
let p = p.as_ref().trim_right_matches('/');
|
||||||
if req.resource().has_prefixed_route(p) {
|
if req.resource().has_prefixed_resource(p) {
|
||||||
let mut req = HttpResponse::build(self.redirect);
|
let mut req = HttpResponse::build(self.redirect);
|
||||||
return if !query.is_empty() {
|
return if !query.is_empty() {
|
||||||
req.header(
|
req.header(
|
||||||
@ -135,7 +135,7 @@ impl<S> Handler<S> for NormalizePath {
|
|||||||
} else if p.ends_with('/') {
|
} else if p.ends_with('/') {
|
||||||
// try to remove trailing slash
|
// try to remove trailing slash
|
||||||
let p = p.as_ref().trim_right_matches('/');
|
let p = p.as_ref().trim_right_matches('/');
|
||||||
if req.resource().has_prefixed_route(p) {
|
if req.resource().has_prefixed_resource(p) {
|
||||||
let mut req = HttpResponse::build(self.redirect);
|
let mut req = HttpResponse::build(self.redirect);
|
||||||
return if !query.is_empty() {
|
return if !query.is_empty() {
|
||||||
req.header(
|
req.header(
|
||||||
@ -151,7 +151,7 @@ impl<S> Handler<S> for NormalizePath {
|
|||||||
// append trailing slash
|
// append trailing slash
|
||||||
if self.append && !req.path().ends_with('/') {
|
if self.append && !req.path().ends_with('/') {
|
||||||
let p = req.path().to_owned() + "/";
|
let p = req.path().to_owned() + "/";
|
||||||
if req.resource().has_prefixed_route(&p) {
|
if req.resource().has_prefixed_resource(&p) {
|
||||||
let p = if !query.is_empty() {
|
let p = if !query.is_empty() {
|
||||||
p + "?" + query
|
p + "?" + query
|
||||||
} else {
|
} else {
|
||||||
|
@ -436,10 +436,10 @@ mod tests {
|
|||||||
router.register_resource(resource);
|
router.register_resource(resource);
|
||||||
|
|
||||||
let info = router.default_route_info();
|
let info = router.default_route_info();
|
||||||
assert!(info.has_route("/user/test.html"));
|
assert!(info.has_resource("/user/test.html"));
|
||||||
assert!(info.has_prefixed_route("/user/test.html"));
|
assert!(info.has_prefixed_resource("/user/test.html"));
|
||||||
assert!(!info.has_route("/test/unknown"));
|
assert!(!info.has_resource("/test/unknown"));
|
||||||
assert!(!info.has_prefixed_route("/test/unknown"));
|
assert!(!info.has_prefixed_resource("/test/unknown"));
|
||||||
|
|
||||||
let req = TestRequest::with_header(header::HOST, "www.rust-lang.org")
|
let req = TestRequest::with_header(header::HOST, "www.rust-lang.org")
|
||||||
.finish_with_router(router);
|
.finish_with_router(router);
|
||||||
@ -468,10 +468,10 @@ mod tests {
|
|||||||
|
|
||||||
let mut info = router.default_route_info();
|
let mut info = router.default_route_info();
|
||||||
info.set_prefix(7);
|
info.set_prefix(7);
|
||||||
assert!(info.has_route("/user/test.html"));
|
assert!(info.has_resource("/user/test.html"));
|
||||||
assert!(!info.has_prefixed_route("/user/test.html"));
|
assert!(!info.has_prefixed_resource("/user/test.html"));
|
||||||
assert!(!info.has_route("/prefix/user/test.html"));
|
assert!(!info.has_resource("/prefix/user/test.html"));
|
||||||
assert!(info.has_prefixed_route("/prefix/user/test.html"));
|
assert!(info.has_prefixed_resource("/prefix/user/test.html"));
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/prefix/test")
|
let req = TestRequest::with_uri("/prefix/test")
|
||||||
.prefix(7)
|
.prefix(7)
|
||||||
@ -493,10 +493,10 @@ mod tests {
|
|||||||
|
|
||||||
let mut info = router.default_route_info();
|
let mut info = router.default_route_info();
|
||||||
info.set_prefix(7);
|
info.set_prefix(7);
|
||||||
assert!(info.has_route("/index.html"));
|
assert!(info.has_resource("/index.html"));
|
||||||
assert!(!info.has_prefixed_route("/index.html"));
|
assert!(!info.has_prefixed_resource("/index.html"));
|
||||||
assert!(!info.has_route("/prefix/index.html"));
|
assert!(!info.has_resource("/prefix/index.html"));
|
||||||
assert!(info.has_prefixed_route("/prefix/index.html"));
|
assert!(info.has_prefixed_resource("/prefix/index.html"));
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/prefix/test")
|
let req = TestRequest::with_uri("/prefix/test")
|
||||||
.prefix(7)
|
.prefix(7)
|
||||||
@ -518,8 +518,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let info = router.default_route_info();
|
let info = router.default_route_info();
|
||||||
assert!(!info.has_route("https://youtube.com/watch/unknown"));
|
assert!(!info.has_resource("https://youtube.com/watch/unknown"));
|
||||||
assert!(!info.has_prefixed_route("https://youtube.com/watch/unknown"));
|
assert!(!info.has_prefixed_resource("https://youtube.com/watch/unknown"));
|
||||||
|
|
||||||
let req = TestRequest::default().finish_with_router(router);
|
let req = TestRequest::default().finish_with_router(router);
|
||||||
let url = req.url_for("youtube", &["oHg5SJYRHA0"]);
|
let url = req.url_for("youtube", &["oHg5SJYRHA0"]);
|
||||||
|
156
src/router.rs
156
src/router.rs
@ -37,7 +37,7 @@ enum ResourceItem<S> {
|
|||||||
|
|
||||||
/// Interface for application router.
|
/// Interface for application router.
|
||||||
pub struct Router<S> {
|
pub struct Router<S> {
|
||||||
defs: Rc<Inner>,
|
rmap: Rc<ResourceMap>,
|
||||||
patterns: Vec<ResourcePattern<S>>,
|
patterns: Vec<ResourcePattern<S>>,
|
||||||
resources: Vec<ResourceItem<S>>,
|
resources: Vec<ResourceItem<S>>,
|
||||||
default: Option<DefaultResource<S>>,
|
default: Option<DefaultResource<S>>,
|
||||||
@ -46,7 +46,7 @@ pub struct Router<S> {
|
|||||||
/// Information about current resource
|
/// Information about current resource
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ResourceInfo {
|
pub struct ResourceInfo {
|
||||||
router: Rc<Inner>,
|
rmap: Rc<ResourceMap>,
|
||||||
resource: ResourceId,
|
resource: ResourceId,
|
||||||
params: Params,
|
params: Params,
|
||||||
prefix: u16,
|
prefix: u16,
|
||||||
@ -57,7 +57,7 @@ impl ResourceInfo {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
if let ResourceId::Normal(idx) = self.resource {
|
if let ResourceId::Normal(idx) = self.resource {
|
||||||
self.router.patterns[idx as usize].name()
|
self.rmap.patterns[idx as usize].0.name()
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ impl ResourceInfo {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn rdef(&self) -> Option<&ResourceDef> {
|
pub fn rdef(&self) -> Option<&ResourceDef> {
|
||||||
if let ResourceId::Normal(idx) = self.resource {
|
if let ResourceId::Normal(idx) = self.resource {
|
||||||
Some(&self.router.patterns[idx as usize])
|
Some(&self.rmap.patterns[idx as usize].0)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -111,7 +111,7 @@ impl ResourceInfo {
|
|||||||
U: IntoIterator<Item = I>,
|
U: IntoIterator<Item = I>,
|
||||||
I: AsRef<str>,
|
I: AsRef<str>,
|
||||||
{
|
{
|
||||||
if let Some(pattern) = self.router.named.get(name) {
|
if let Some(pattern) = self.rmap.named.get(name) {
|
||||||
let path =
|
let path =
|
||||||
pattern.resource_path(elements, &req.path()[..(self.prefix as usize)])?;
|
pattern.resource_path(elements, &req.path()[..(self.prefix as usize)])?;
|
||||||
if path.starts_with('/') {
|
if path.starts_with('/') {
|
||||||
@ -130,24 +130,17 @@ impl ResourceInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if application contains matching route.
|
/// Check if application contains matching resource.
|
||||||
///
|
///
|
||||||
/// This method does not take `prefix` into account.
|
/// This method does not take `prefix` into account.
|
||||||
/// For example if prefix is `/test` and router contains route `/name`,
|
/// For example if prefix is `/test` and router contains route `/name`,
|
||||||
/// following path would be recognizable `/test/name` but `has_route()` call
|
/// following path would be recognizable `/test/name` but `has_resource()` call
|
||||||
/// would return `false`.
|
/// would return `false`.
|
||||||
pub fn has_route(&self, path: &str) -> bool {
|
pub fn has_resource(&self, path: &str) -> bool {
|
||||||
let path = if path.is_empty() { "/" } else { path };
|
self.rmap.has_resource(path)
|
||||||
|
|
||||||
for pattern in &self.router.patterns {
|
|
||||||
if pattern.is_match(path) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if application contains matching route.
|
/// Check if application contains matching resource.
|
||||||
///
|
///
|
||||||
/// This method does take `prefix` into account
|
/// This method does take `prefix` into account
|
||||||
/// but behaves like `has_route` in case `prefix` is not set in the router.
|
/// but behaves like `has_route` in case `prefix` is not set in the router.
|
||||||
@ -157,18 +150,35 @@ impl ResourceInfo {
|
|||||||
/// would return `true`.
|
/// would return `true`.
|
||||||
/// It will not match against prefix in case it's not given. For example for `/name`
|
/// It will not match against prefix in case it's not given. For example for `/name`
|
||||||
/// with a `/test` prefix would return `false`
|
/// with a `/test` prefix would return `false`
|
||||||
pub fn has_prefixed_route(&self, path: &str) -> bool {
|
pub fn has_prefixed_resource(&self, path: &str) -> bool {
|
||||||
let prefix = self.prefix as usize;
|
let prefix = self.prefix as usize;
|
||||||
if prefix >= path.len() {
|
if prefix >= path.len() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
self.has_route(&path[prefix..])
|
self.rmap.has_resource(&path[prefix..])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Inner {
|
pub(crate) struct ResourceMap {
|
||||||
named: HashMap<String, ResourceDef>,
|
named: HashMap<String, ResourceDef>,
|
||||||
patterns: Vec<ResourceDef>,
|
patterns: Vec<(ResourceDef, Option<Rc<ResourceMap>>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResourceMap {
|
||||||
|
pub fn has_resource(&self, path: &str) -> bool {
|
||||||
|
let path = if path.is_empty() { "/" } else { path };
|
||||||
|
|
||||||
|
for (pattern, rmap) in &self.patterns {
|
||||||
|
if let Some(ref rmap) = rmap {
|
||||||
|
if let Some(plen) = pattern.is_prefix_match(path) {
|
||||||
|
return rmap.has_resource(&path[plen..]);
|
||||||
|
}
|
||||||
|
} else if pattern.is_match(path) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static> Default for Router<S> {
|
impl<S: 'static> Default for Router<S> {
|
||||||
@ -180,7 +190,7 @@ impl<S: 'static> Default for Router<S> {
|
|||||||
impl<S: 'static> Router<S> {
|
impl<S: 'static> Router<S> {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Router {
|
Router {
|
||||||
defs: Rc::new(Inner {
|
rmap: Rc::new(ResourceMap {
|
||||||
named: HashMap::new(),
|
named: HashMap::new(),
|
||||||
patterns: Vec::new(),
|
patterns: Vec::new(),
|
||||||
}),
|
}),
|
||||||
@ -195,7 +205,7 @@ impl<S: 'static> Router<S> {
|
|||||||
ResourceInfo {
|
ResourceInfo {
|
||||||
params,
|
params,
|
||||||
prefix: 0,
|
prefix: 0,
|
||||||
router: self.defs.clone(),
|
rmap: self.rmap.clone(),
|
||||||
resource: ResourceId::Normal(idx),
|
resource: ResourceId::Normal(idx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,7 +218,7 @@ impl<S: 'static> Router<S> {
|
|||||||
ResourceInfo {
|
ResourceInfo {
|
||||||
params,
|
params,
|
||||||
prefix: 0,
|
prefix: 0,
|
||||||
router: self.defs.clone(),
|
rmap: self.rmap.clone(),
|
||||||
resource: ResourceId::Default,
|
resource: ResourceId::Default,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,7 +227,7 @@ impl<S: 'static> Router<S> {
|
|||||||
pub(crate) fn default_route_info(&self) -> ResourceInfo {
|
pub(crate) fn default_route_info(&self) -> ResourceInfo {
|
||||||
ResourceInfo {
|
ResourceInfo {
|
||||||
params: Params::new(),
|
params: Params::new(),
|
||||||
router: self.defs.clone(),
|
rmap: self.rmap.clone(),
|
||||||
resource: ResourceId::Default,
|
resource: ResourceId::Default,
|
||||||
prefix: 0,
|
prefix: 0,
|
||||||
}
|
}
|
||||||
@ -225,18 +235,18 @@ impl<S: 'static> Router<S> {
|
|||||||
|
|
||||||
pub(crate) fn register_resource(&mut self, resource: Resource<S>) {
|
pub(crate) fn register_resource(&mut self, resource: Resource<S>) {
|
||||||
{
|
{
|
||||||
let inner = Rc::get_mut(&mut self.defs).unwrap();
|
let rmap = Rc::get_mut(&mut self.rmap).unwrap();
|
||||||
|
|
||||||
let name = resource.get_name();
|
let name = resource.get_name();
|
||||||
if !name.is_empty() {
|
if !name.is_empty() {
|
||||||
assert!(
|
assert!(
|
||||||
!inner.named.contains_key(name),
|
!rmap.named.contains_key(name),
|
||||||
"Named resource {:?} is registered.",
|
"Named resource {:?} is registered.",
|
||||||
name
|
name
|
||||||
);
|
);
|
||||||
inner.named.insert(name.to_owned(), resource.rdef().clone());
|
rmap.named.insert(name.to_owned(), resource.rdef().clone());
|
||||||
}
|
}
|
||||||
inner.patterns.push(resource.rdef().clone());
|
rmap.patterns.push((resource.rdef().clone(), None));
|
||||||
}
|
}
|
||||||
self.patterns
|
self.patterns
|
||||||
.push(ResourcePattern::Resource(resource.rdef().clone()));
|
.push(ResourcePattern::Resource(resource.rdef().clone()));
|
||||||
@ -244,10 +254,10 @@ impl<S: 'static> Router<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn register_scope(&mut self, mut scope: Scope<S>) {
|
pub(crate) fn register_scope(&mut self, mut scope: Scope<S>) {
|
||||||
Rc::get_mut(&mut self.defs)
|
Rc::get_mut(&mut self.rmap)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.patterns
|
.patterns
|
||||||
.push(scope.rdef().clone());
|
.push((scope.rdef().clone(), Some(scope.router().rmap.clone())));
|
||||||
let filters = scope.take_filters();
|
let filters = scope.take_filters();
|
||||||
self.patterns
|
self.patterns
|
||||||
.push(ResourcePattern::Scope(scope.rdef().clone(), filters));
|
.push(ResourcePattern::Scope(scope.rdef().clone(), filters));
|
||||||
@ -259,10 +269,10 @@ impl<S: 'static> Router<S> {
|
|||||||
filters: Option<Vec<Box<Predicate<S>>>>,
|
filters: Option<Vec<Box<Predicate<S>>>>,
|
||||||
) {
|
) {
|
||||||
let rdef = ResourceDef::prefix(path);
|
let rdef = ResourceDef::prefix(path);
|
||||||
Rc::get_mut(&mut self.defs)
|
Rc::get_mut(&mut self.rmap)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.patterns
|
.patterns
|
||||||
.push(rdef.clone());
|
.push((rdef.clone(), None));
|
||||||
self.resources.push(ResourceItem::Handler(hnd));
|
self.resources.push(ResourceItem::Handler(hnd));
|
||||||
self.patterns.push(ResourcePattern::Handler(rdef, filters));
|
self.patterns.push(ResourcePattern::Handler(rdef, filters));
|
||||||
}
|
}
|
||||||
@ -298,13 +308,13 @@ impl<S: 'static> Router<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn register_external(&mut self, name: &str, rdef: ResourceDef) {
|
pub(crate) fn register_external(&mut self, name: &str, rdef: ResourceDef) {
|
||||||
let inner = Rc::get_mut(&mut self.defs).unwrap();
|
let rmap = Rc::get_mut(&mut self.rmap).unwrap();
|
||||||
assert!(
|
assert!(
|
||||||
!inner.named.contains_key(name),
|
!rmap.named.contains_key(name),
|
||||||
"Named resource {:?} is registered.",
|
"Named resource {:?} is registered.",
|
||||||
name
|
name
|
||||||
);
|
);
|
||||||
inner.named.insert(name.to_owned(), rdef);
|
rmap.named.insert(name.to_owned(), rdef);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn register_route<T, F, R>(&mut self, path: &str, method: Method, f: F)
|
pub(crate) fn register_route<T, F, R>(&mut self, path: &str, method: Method, f: F)
|
||||||
@ -406,7 +416,7 @@ impl<S: 'static> Router<S> {
|
|||||||
ResourceInfo {
|
ResourceInfo {
|
||||||
prefix: tail as u16,
|
prefix: tail as u16,
|
||||||
params: Params::new(),
|
params: Params::new(),
|
||||||
router: self.defs.clone(),
|
rmap: self.rmap.clone(),
|
||||||
resource: ResourceId::Default,
|
resource: ResourceId::Default,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -534,6 +544,54 @@ impl ResourceDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_prefix_match(&self, path: &str) -> Option<usize> {
|
||||||
|
let plen = path.len();
|
||||||
|
let path = if path.is_empty() { "/" } else { path };
|
||||||
|
|
||||||
|
match self.tp {
|
||||||
|
PatternType::Static(ref s) => if s == path {
|
||||||
|
Some(plen)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
PatternType::Dynamic(ref re, _, len) => {
|
||||||
|
if let Some(captures) = re.captures(path) {
|
||||||
|
let mut pos = 0;
|
||||||
|
let mut passed = false;
|
||||||
|
for capture in captures.iter() {
|
||||||
|
if let Some(ref m) = capture {
|
||||||
|
if !passed {
|
||||||
|
passed = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = m.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(plen + pos + len)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PatternType::Prefix(ref s) => {
|
||||||
|
let len = if path == s {
|
||||||
|
s.len()
|
||||||
|
} else if path.starts_with(s)
|
||||||
|
&& (s.ends_with('/') || path.split_at(s.len()).1.starts_with('/'))
|
||||||
|
{
|
||||||
|
if s.ends_with('/') {
|
||||||
|
s.len() - 1
|
||||||
|
} else {
|
||||||
|
s.len()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(min(plen, len))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Are the given path and parameters a match against this resource?
|
/// Are the given path and parameters a match against this resource?
|
||||||
pub fn match_with_params(&self, req: &Request, plen: usize) -> Option<Params> {
|
pub fn match_with_params(&self, req: &Request, plen: usize) -> Option<Params> {
|
||||||
let path = &req.path()[plen..];
|
let path = &req.path()[plen..];
|
||||||
@ -588,7 +646,9 @@ impl ResourceDef {
|
|||||||
|
|
||||||
match self.tp {
|
match self.tp {
|
||||||
PatternType::Static(ref s) => if s == path {
|
PatternType::Static(ref s) => if s == path {
|
||||||
Some(Params::with_url(req.url()))
|
let mut params = Params::with_url(req.url());
|
||||||
|
params.set_tail(req.path().len() as u16);
|
||||||
|
Some(params)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
@ -1008,4 +1068,24 @@ mod tests {
|
|||||||
assert_eq!(info.resource, ResourceId::Normal(1));
|
assert_eq!(info.resource, ResourceId::Normal(1));
|
||||||
assert_eq!(info.name(), "r2");
|
assert_eq!(info.name(), "r2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_has_resource() {
|
||||||
|
let mut router = Router::<()>::new();
|
||||||
|
let scope = Scope::new("/test").resource("/name", |_| "done");
|
||||||
|
router.register_scope(scope);
|
||||||
|
|
||||||
|
{
|
||||||
|
let info = router.default_route_info();
|
||||||
|
assert!(!info.has_resource("/test"));
|
||||||
|
assert!(info.has_resource("/test/name"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let scope =
|
||||||
|
Scope::new("/test2").nested("/test10", |s| s.resource("/name", |_| "done"));
|
||||||
|
router.register_scope(scope);
|
||||||
|
|
||||||
|
let info = router.default_route_info();
|
||||||
|
assert!(info.has_resource("/test2/test10/name"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,10 @@ impl<S: 'static> Scope<S> {
|
|||||||
&self.rdef
|
&self.rdef
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn router(&self) -> &Router<S> {
|
||||||
|
self.router.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn take_filters(&mut self) -> Vec<Box<Predicate<S>>> {
|
pub(crate) fn take_filters(&mut self) -> Vec<Box<Predicate<S>>> {
|
||||||
mem::replace(&mut self.filters, Vec::new())
|
mem::replace(&mut self.filters, Vec::new())
|
||||||
|
Loading…
Reference in New Issue
Block a user