Skip to content

Commit

Permalink
support url generation for mounted routers
Browse files Browse the repository at this point in the history
  • Loading branch information
flosse committed Nov 25, 2016
1 parent 6c124dd commit c696855
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 5 deletions.
16 changes: 15 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,22 @@ rust:
- stable
- beta
sudo: false

# load travis-cargo
before_script:
- |
pip install 'travis-cargo<0.2' --user &&
export PATH=$HOME/.local/bin:$PATH
script:
- |
travis-cargo build -- --features mount &&
travis-cargo test -- --features mount &&
travis-cargo --only stable doc
env:
global:
secure: MjdqCPMV5iaByoY3m545Iw/S7UHbX5d3ZgU9H3c62Vo2WqJ12EWk4H0Z0HU+Ptu1+FriplfbnKKcfiE9zHam2yBs2XfhysWm/nOCk5eTetSpapYddWkwQaoEgxcan4kUyJiG0v4ZylorZea7d2wa9iKZKFQPChnvCI+Xd/9dlJs=
- TRAVIS_CARGO_NIGHTLY_FEATURE=""
- secure: MjdqCPMV5iaByoY3m545Iw/S7UHbX5d3ZgU9H3c62Vo2WqJ12EWk4H0Z0HU+Ptu1+FriplfbnKKcfiE9zHam2yBs2XfhysWm/nOCk5eTetSpapYddWkwQaoEgxcan4kUyJiG0v4ZylorZea7d2wa9iKZKFQPChnvCI+Xd/9dlJs=
after_success: 'curl https://raw.githubusercontent.com/iron-bot/build-doc/master/build-doc.sh
| sh '
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ keywords = ["iron", "web", "http", "routing", "router"]
route-recognizer = "0.1"
iron = "0.4"
url = "1.1"
mount = { version = "0.2", optional = true }
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
extern crate iron;
extern crate route_recognizer as recognizer;
extern crate url;
#[cfg(feature = "mount")]
extern crate mount;

pub use router::{Router, RouterError, NoRoute, TrailingSlash};
pub use recognizer::Params;
pub use url_for::url_for;
pub use url_for::mounted_url_for;

mod router;
mod macros;
Expand Down
54 changes: 50 additions & 4 deletions src/url_for.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use url::Url;

use iron::prelude::*;
use router::RouterInner;
#[cfg(feature = "mount")]
use mount::OriginalUrl;

/// Generate a URL based off of the currently requested URL.
///
Expand All @@ -12,27 +14,60 @@ use router::RouterInner;
/// `params` will be inserted as route parameters if fitting, the rest will be appended as query
/// parameters.
pub fn url_for(request: &Request, route_id: &str, params: HashMap<String, String>) -> ::iron::Url {
let url = request.url.clone().into_generic_url();
_url_for(url, request, route_id, params)
}

/// Generate a URL based off of the currently requested URL.
/// In contrast to `url_for` this method respects the hidden path if the router is mounted.
///
/// The `route_id` used during route registration will be used here again.
///
/// `params` will be inserted as route parameters if fitting, the rest will be appended as query
/// parameters.
#[cfg(feature = "mount")]
pub fn mounted_url_for(request: &Request, route_id: &str, params: HashMap<String, String>) -> ::iron::Url {
let url = request.extensions.get::<OriginalUrl>().unwrap().clone().into_generic_url();
_url_for(url, request, route_id, params)
}

fn _url_for(mut url: Url, request: &Request, route_id: &str, params: HashMap<String, String>) -> ::iron::Url {
let inner = request.extensions.get::<RouterInner>().expect("Couldn\'t find router set up properly.");
let glob = inner.route_ids.get(route_id).expect("No route with that ID");

let mut url = request.url.clone().into_generic_url();
url_for_impl(&mut url, glob, params);
::iron::Url::from_generic_url(url).unwrap()
}

fn url_for_impl(url: &mut Url, glob: &str, mut params: HashMap<String, String>) {
{
let globs = glob.split('/');
let globs_count = globs.clone().filter(|x| *x != "").count();
let segments_count = url.path_segments().unwrap().count();
let mut url_path_segments = url.path_segments_mut().unwrap();
url_path_segments.clear();
for path_segment in glob.split('/') {

if globs_count < segments_count {
for _ in 0..globs_count+1 {
url_path_segments.pop();
}
} else {
url_path_segments.clear();
}

let mut idx = 0;
for path_segment in globs {
if path_segment.len() > 1 && (path_segment.starts_with(':') || path_segment.starts_with('*')) {
let key = &path_segment[1..];
match params.remove(key) {
Some(x) => url_path_segments.push(&x),
None => panic!("No value for key {}", key)
};
} else {
url_path_segments.push(path_segment);
if idx == 0 && path_segment == "" {
idx += 1;
} else {
url_path_segments.push(path_segment);
}
}
}
}
Expand Down Expand Up @@ -73,4 +108,15 @@ mod test {
});
assert_eq!(url.to_string(), "http://localhost/foo/bam/");
}

#[test]
fn test_with_mount() {
let mut url = "http://localhost/mounted/foo/bar/baz".parse().unwrap();
url_for_impl(&mut url, "/foo/:user/", {
let mut rv = HashMap::new();
rv.insert("user".into(), "bam".into());
rv
});
assert_eq!(url.to_string(), "http://localhost/mounted/foo/bam/");
}
}

0 comments on commit c696855

Please sign in to comment.