diff --git a/CHANGES.md b/CHANGES.md index 5fa6f12b2..6c72e3e23 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,8 @@ ### Added +* Add `.has_prefixed_route()` method to `router::RouteInfo` for route matching with prefix awareness + * Add `HttpMessage::readlines()` for reading line by line. * Add `ClientRequestBuilder::form()` for sending `application/x-www-form-urlencoded` requests. diff --git a/src/httprequest.rs b/src/httprequest.rs index 02edcae9a..216888777 100644 --- a/src/httprequest.rs +++ b/src/httprequest.rs @@ -437,7 +437,9 @@ mod tests { let info = router.default_route_info(); assert!(info.has_route("/user/test.html")); + assert!(info.has_prefixed_route("/user/test.html")); assert!(!info.has_route("/test/unknown")); + assert!(!info.has_prefixed_route("/test/unknown")); let req = TestRequest::with_header(header::HOST, "www.rust-lang.org") .finish_with_router(router); @@ -467,7 +469,9 @@ mod tests { let mut info = router.default_route_info(); info.set_prefix(7); assert!(info.has_route("/user/test.html")); + assert!(!info.has_prefixed_route("/user/test.html")); assert!(!info.has_route("/prefix/user/test.html")); + assert!(info.has_prefixed_route("/prefix/user/test.html")); let req = TestRequest::with_uri("/prefix/test") .prefix(7) @@ -490,7 +494,9 @@ mod tests { let mut info = router.default_route_info(); info.set_prefix(7); assert!(info.has_route("/index.html")); + assert!(!info.has_prefixed_route("/index.html")); assert!(!info.has_route("/prefix/index.html")); + assert!(info.has_prefixed_route("/prefix/index.html")); let req = TestRequest::with_uri("/prefix/test") .prefix(7) @@ -513,6 +519,7 @@ mod tests { let info = router.default_route_info(); assert!(!info.has_route("https://youtube.com/watch/unknown")); + assert!(!info.has_prefixed_route("https://youtube.com/watch/unknown")); let req = TestRequest::default().finish_with_router(router); let url = req.url_for("youtube", &["oHg5SJYRHA0"]); diff --git a/src/router.rs b/src/router.rs index fbdcbc08a..56f304947 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,6 +1,7 @@ use std::cmp::min; use std::collections::HashMap; use std::hash::{Hash, Hasher}; +use std::path::Path; use std::rc::Rc; use regex::{escape, Regex}; @@ -146,6 +147,32 @@ impl ResourceInfo { } false } + + /// Check if application contains matching route. + /// + /// This method does take `prefix` into account + /// but behaves like `has_route` in case `prefix` is not set in the router. + /// + /// For example if prefix is `/test` and router contains route `/name`, the + /// following path would be recognizable `/test/name` and `has_prefixed_route()` call + /// would return `true`. + /// It will not match against prefix in case it's not given. For example for `/name` + /// with a `/test` prefix would return `false` + pub fn has_prefixed_route(&self, path: &str) -> bool { + if self.prefix == 0 { + return self.has_route(path); + } + + let path_matcher = Path::new(if path.is_empty() { "/" } else { path }); + let router_prefix = Path::new(&path[..(self.prefix as usize)]); + if let Ok(p) = path_matcher.strip_prefix(router_prefix) { + if let Some(p_str) = p.to_str() { + return self.has_route(&format!("/{}", p_str)); + } + } + + false + } } struct Inner {