1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 16:02:59 +01:00

fixed HttpRequest::url_for for a named route with no variables #265

This commit is contained in:
Nikolay Kim 2018-06-02 11:44:09 -07:00
parent 8d905c8504
commit 4a39216aa7
2 changed files with 81 additions and 19 deletions

View File

@ -311,6 +311,7 @@ impl<S> HttpRequest<S> {
Err(UrlGenerationError::RouterNotAvailable) Err(UrlGenerationError::RouterNotAvailable)
} else { } else {
let path = self.router().unwrap().resource_path(name, elements)?; let path = self.router().unwrap().resource_path(name, elements)?;
println!("==== {:?}", path);
if path.starts_with('/') { if path.starts_with('/') {
let conn = self.connection_info(); let conn = self.connection_info();
Ok(Url::parse(&format!( Ok(Url::parse(&format!(
@ -325,6 +326,15 @@ impl<S> HttpRequest<S> {
} }
} }
/// Generate url for named resource
///
/// This method is similar to `HttpRequest::url_for()` but it can be used
/// for urls that do not contain variable parts.
pub fn url_for_static(&self, name: &str) -> Result<Url, UrlGenerationError> {
const NO_PARAMS: [&str; 0] = [];
self.url_for(name, &NO_PARAMS)
}
/// This method returns reference to current `Router` object. /// This method returns reference to current `Router` object.
#[inline] #[inline]
pub fn router(&self) -> Option<&Router> { pub fn router(&self) -> Option<&Router> {
@ -695,20 +705,38 @@ mod tests {
let mut resource = ResourceHandler::<()>::default(); let mut resource = ResourceHandler::<()>::default();
resource.name("index"); resource.name("index");
let routes = let routes = vec![(Resource::new("index", "/user/{name}.html"), Some(resource))];
vec![(Resource::new("index", "/user/{name}.{ext}"), Some(resource))];
let (router, _) = Router::new("/prefix/", ServerSettings::default(), routes); let (router, _) = Router::new("/prefix/", ServerSettings::default(), routes);
assert!(router.has_route("/user/test.html")); assert!(router.has_route("/user/test.html"));
assert!(!router.has_route("/prefix/user/test.html")); assert!(!router.has_route("/prefix/user/test.html"));
let req = req.with_state(Rc::new(()), router); let req = req.with_state(Rc::new(()), router);
let url = req.url_for("index", &["test", "html"]); let url = req.url_for("index", &["test"]);
assert_eq!( assert_eq!(
url.ok().unwrap().as_str(), url.ok().unwrap().as_str(),
"http://www.rust-lang.org/prefix/user/test.html" "http://www.rust-lang.org/prefix/user/test.html"
); );
} }
#[test]
fn test_url_for_static() {
let req = TestRequest::with_header(header::HOST, "www.rust-lang.org").finish();
let mut resource = ResourceHandler::<()>::default();
resource.name("index");
let routes = vec![(Resource::new("index", "/index.html"), Some(resource))];
let (router, _) = Router::new("/prefix/", ServerSettings::default(), routes);
assert!(router.has_route("/index.html"));
assert!(!router.has_route("/prefix/index.html"));
let req = req.with_state(Rc::new(()), router);
let url = req.url_for_static("index");
assert_eq!(
url.ok().unwrap().as_str(),
"http://www.rust-lang.org/prefix/index.html"
);
}
#[test] #[test]
fn test_url_for_external() { fn test_url_for_external() {
let req = HttpRequest::default(); let req = HttpRequest::default();

View File

@ -211,6 +211,8 @@ impl Resource {
let (pattern, elements, is_dynamic, len) = let (pattern, elements, is_dynamic, len) =
Resource::parse(path, prefix, for_prefix); Resource::parse(path, prefix, for_prefix);
println!("ELEMENT: {:?} {:?} {:?}", pattern, elements, is_dynamic);
let tp = if is_dynamic { let tp = if is_dynamic {
let re = match Regex::new(&pattern) { let re = match Regex::new(&pattern) {
Ok(re) => re, Ok(re) => re,
@ -338,22 +340,42 @@ impl Resource {
U: IntoIterator<Item = I>, U: IntoIterator<Item = I>,
I: AsRef<str>, I: AsRef<str>,
{ {
let mut iter = elements.into_iter(); let mut path = match self.tp {
let mut path = if self.rtp != ResourceType::External { PatternType::Prefix(ref p) => p.to_owned(),
format!("{}/", router.prefix()) PatternType::Static(ref p) => p.to_owned(),
} else { PatternType::Dynamic(..) => {
String::new() let mut path = String::new();
}; let mut iter = elements.into_iter();
for el in &self.elements { for el in &self.elements {
match *el { println!("EL: {:?}", el);
PatternElement::Str(ref s) => path.push_str(s), match *el {
PatternElement::Var(_) => { PatternElement::Str(ref s) => path.push_str(s),
if let Some(val) = iter.next() { PatternElement::Var(_) => {
path.push_str(val.as_ref()) if let Some(val) = iter.next() {
} else { path.push_str(val.as_ref())
return Err(UrlGenerationError::NotEnoughElements); } else {
return Err(UrlGenerationError::NotEnoughElements);
}
}
} }
} }
path
}
};
if self.rtp != ResourceType::External {
let prefix = router.prefix();
if prefix.ends_with('/') {
if path.starts_with('/') {
path.insert_str(0, &prefix[..prefix.len() - 1]);
} else {
path.insert_str(0, prefix);
}
} else {
if !path.starts_with('/') {
path.insert(0, '/');
}
path.insert_str(0, prefix);
} }
} }
Ok(path) Ok(path)
@ -418,6 +440,10 @@ impl Resource {
} }
} }
if !el.is_empty() {
elems.push(PatternElement::Str(el.clone()));
}
let re = if is_dynamic { let re = if is_dynamic {
if !for_prefix { if !for_prefix {
re1.push('$'); re1.push('$');
@ -450,7 +476,7 @@ mod tests {
use test::TestRequest; use test::TestRequest;
#[test] #[test]
fn test_recognizer() { fn test_recognizer10() {
let routes = vec![ let routes = vec![
(Resource::new("", "/name"), Some(ResourceHandler::default())), (Resource::new("", "/name"), Some(ResourceHandler::default())),
( (
@ -473,6 +499,10 @@ mod tests {
Resource::new("", "/v/{tail:.*}"), Resource::new("", "/v/{tail:.*}"),
Some(ResourceHandler::default()), Some(ResourceHandler::default()),
), ),
(
Resource::new("", "/test2/{test}.html"),
Some(ResourceHandler::default()),
),
( (
Resource::new("", "{test}/index.html"), Resource::new("", "{test}/index.html"),
Some(ResourceHandler::default()), Some(ResourceHandler::default()),
@ -510,8 +540,12 @@ mod tests {
"blah-blah/index.html" "blah-blah/index.html"
); );
let mut req = TestRequest::with_uri("/bbb/index.html").finish(); let mut req = TestRequest::with_uri("/test2/index.html").finish();
assert_eq!(rec.recognize(&mut req), Some(6)); assert_eq!(rec.recognize(&mut req), Some(6));
assert_eq!(req.match_info().get("test").unwrap(), "index");
let mut req = TestRequest::with_uri("/bbb/index.html").finish();
assert_eq!(rec.recognize(&mut req), Some(7));
assert_eq!(req.match_info().get("test").unwrap(), "bbb"); assert_eq!(req.match_info().get("test").unwrap(), "bbb");
} }