1use std::collections::HashMap;
2
3use crate::request::Request;
4use crate::http::{Method, Status};
5
6use crate::{Route, Catcher};
7use crate::router::Collide;
8
9#[derive(Debug, Default)]
10pub(crate) struct Router {
11 routes: HashMap<Method, Vec<Route>>,
12 catchers: HashMap<Option<u16>, Vec<Catcher>>,
13}
14
15#[derive(Debug)]
16pub struct Collisions {
17 pub routes: Vec<(Route, Route)>,
18 pub catchers: Vec<(Catcher, Catcher)>,
19}
20
21impl Router {
22 pub fn new() -> Self {
23 Self::default()
24 }
25
26 pub fn add_route(&mut self, route: Route) {
27 let routes = self.routes.entry(route.method).or_default();
28 routes.push(route);
29 routes.sort_by_key(|r| r.rank);
30 }
31
32 pub fn add_catcher(&mut self, catcher: Catcher) {
33 let catchers = self.catchers.entry(catcher.code).or_default();
34 catchers.push(catcher);
35 catchers.sort_by(|a, b| b.base.path().segments().len().cmp(&a.base.path().segments().len()))
36 }
37
38 #[inline]
39 pub fn routes(&self) -> impl Iterator<Item = &Route> + Clone {
40 self.routes.values().flat_map(|v| v.iter())
41 }
42
43 #[inline]
44 pub fn catchers(&self) -> impl Iterator<Item = &Catcher> + Clone {
45 self.catchers.values().flat_map(|v| v.iter())
46 }
47
48 pub fn route<'r, 'a: 'r>(
49 &'a self,
50 req: &'r Request<'r>
51 ) -> impl Iterator<Item = &'a Route> + 'r {
52 self.routes.get(&req.method())
54 .into_iter()
55 .flat_map(move |routes| routes.iter().filter(move |r| r.matches(req)))
56 }
57
58 pub fn catch<'r>(&self, status: Status, req: &'r Request<'r>) -> Option<&Catcher> {
60 let explicit = self.catchers.get(&Some(status.code))
62 .and_then(|c| c.iter().find(|c| c.matches(status, req)));
63
64 let default = self.catchers.get(&None)
65 .and_then(|c| c.iter().find(|c| c.matches(status, req)));
66
67 match (explicit, default) {
68 (None, None) => None,
69 (None, c@Some(_)) | (c@Some(_), None) => c,
70 (Some(a), Some(b)) => {
71 if b.base.path().segments().len() > a.base.path().segments().len() {
72 Some(b)
73 } else {
74 Some(a)
75 }
76 }
77 }
78 }
79
80 fn collisions<'a, I, T>(&self, items: I) -> impl Iterator<Item = (T, T)> + 'a
81 where I: Iterator<Item = &'a T> + Clone + 'a, T: Collide + Clone + 'a,
82 {
83 items.clone().enumerate()
84 .flat_map(move |(i, a)| {
85 items.clone()
86 .skip(i + 1)
87 .filter(move |b| a.collides_with(b))
88 .map(move |b| (a.clone(), b.clone()))
89 })
90 }
91
92 pub fn finalize(&self) -> Result<(), Collisions> {
93 let routes: Vec<_> = self.collisions(self.routes()).collect();
94 let catchers: Vec<_> = self.collisions(self.catchers()).collect();
95
96 if !routes.is_empty() || !catchers.is_empty() {
97 return Err(Collisions { routes, catchers })
98 }
99
100 Ok(())
101 }
102}
103
104#[cfg(test)]
105mod test {
106 use super::*;
107
108 use crate::route::dummy_handler;
109 use crate::local::blocking::Client;
110 use crate::http::{Method, Method::*, uri::Origin};
111
112 impl Router {
113 fn has_collisions(&self) -> bool {
114 self.finalize().is_err()
115 }
116 }
117
118 fn router_with_routes(routes: &[&'static str]) -> Router {
119 let mut router = Router::new();
120 for route in routes {
121 let route = Route::new(Get, route, dummy_handler);
122 router.add_route(route);
123 }
124
125 router
126 }
127
128 fn router_with_ranked_routes(routes: &[(isize, &'static str)]) -> Router {
129 let mut router = Router::new();
130 for &(rank, route) in routes {
131 let route = Route::ranked(rank, Get, route, dummy_handler);
132 router.add_route(route);
133 }
134
135 router
136 }
137
138 fn router_with_rankless_routes(routes: &[&'static str]) -> Router {
139 let mut router = Router::new();
140 for route in routes {
141 let route = Route::ranked(0, Get, route, dummy_handler);
142 router.add_route(route);
143 }
144
145 router
146 }
147
148 fn rankless_route_collisions(routes: &[&'static str]) -> bool {
149 let router = router_with_rankless_routes(routes);
150 router.has_collisions()
151 }
152
153 fn default_rank_route_collisions(routes: &[&'static str]) -> bool {
154 let router = router_with_routes(routes);
155 router.has_collisions()
156 }
157
158 #[test]
159 fn test_rankless_collisions() {
160 assert!(rankless_route_collisions(&["/hello", "/hello"]));
161 assert!(rankless_route_collisions(&["/<a>", "/hello"]));
162 assert!(rankless_route_collisions(&["/<a>", "/<b>"]));
163 assert!(rankless_route_collisions(&["/hello/bob", "/hello/<b>"]));
164 assert!(rankless_route_collisions(&["/a/b/<c>/d", "/<a>/<b>/c/d"]));
165
166 assert!(rankless_route_collisions(&["/a/b", "/<a..>"]));
167 assert!(rankless_route_collisions(&["/a/b/c", "/a/<a..>"]));
168 assert!(rankless_route_collisions(&["/<a>/b", "/a/<a..>"]));
169 assert!(rankless_route_collisions(&["/a/<b>", "/a/<a..>"]));
170 assert!(rankless_route_collisions(&["/a/b/<c>", "/a/<a..>"]));
171 assert!(rankless_route_collisions(&["/<a..>", "/a/<a..>"]));
172 assert!(rankless_route_collisions(&["/a/<a..>", "/a/<a..>"]));
173 assert!(rankless_route_collisions(&["/a/b/<a..>", "/a/<a..>"]));
174 assert!(rankless_route_collisions(&["/a/b/c/d", "/a/<a..>"]));
175 assert!(rankless_route_collisions(&["/", "/<a..>"]));
176 assert!(rankless_route_collisions(&["/a/<_>", "/a/<a..>"]));
177 assert!(rankless_route_collisions(&["/a/<_>", "/a/<_..>"]));
178 assert!(rankless_route_collisions(&["/<_>", "/a/<_..>"]));
179 assert!(rankless_route_collisions(&["/foo", "/foo/<_..>"]));
180 assert!(rankless_route_collisions(&["/foo/bar/baz", "/foo/<_..>"]));
181 assert!(rankless_route_collisions(&["/a/d/<b..>", "/a/d"]));
182 assert!(rankless_route_collisions(&["/a/<_..>", "/<_>"]));
183 assert!(rankless_route_collisions(&["/a/<_..>", "/a"]));
184 assert!(rankless_route_collisions(&["/<a>", "/a/<a..>"]));
185
186 assert!(rankless_route_collisions(&["/<_>", "/<_>"]));
187 assert!(rankless_route_collisions(&["/a/<_>", "/a/b"]));
188 assert!(rankless_route_collisions(&["/a/<_>", "/a/<b>"]));
189 assert!(rankless_route_collisions(&["/<_..>", "/a/b"]));
190 assert!(rankless_route_collisions(&["/<_..>", "/<_>"]));
191 assert!(rankless_route_collisions(&["/<_>/b", "/a/b"]));
192 assert!(rankless_route_collisions(&["/", "/<foo..>"]));
193 }
194
195 #[test]
196 fn test_collisions_normalize() {
197 assert!(rankless_route_collisions(&["/hello/", "/hello"]));
198 assert!(rankless_route_collisions(&["//hello/", "/hello"]));
199 assert!(rankless_route_collisions(&["//hello/", "/hello//"]));
200 assert!(rankless_route_collisions(&["/<a>", "/hello//"]));
201 assert!(rankless_route_collisions(&["/<a>", "/hello///"]));
202 assert!(rankless_route_collisions(&["/hello///bob", "/hello/<b>"]));
203 assert!(rankless_route_collisions(&["/<a..>//", "/a//<a..>"]));
204 assert!(rankless_route_collisions(&["/a/<a..>//", "/a/<a..>"]));
205 assert!(rankless_route_collisions(&["/a/<a..>//", "/a/b//c//d/"]));
206 assert!(rankless_route_collisions(&["/a/<a..>/", "/a/bd/e/"]));
207 assert!(rankless_route_collisions(&["/<a..>/", "/a/bd/e/"]));
208 assert!(rankless_route_collisions(&["//", "/<foo..>"]));
209 assert!(rankless_route_collisions(&["/a/<a..>//", "/a/b//c//d/e/"]));
210 assert!(rankless_route_collisions(&["/a//<a..>//", "/a/b//c//d/e/"]));
211 assert!(rankless_route_collisions(&["///<_>", "/<_>"]));
212 assert!(rankless_route_collisions(&["/a/<_>", "///a//b"]));
213 assert!(rankless_route_collisions(&["//a///<_>", "/a//<b>"]));
214 assert!(rankless_route_collisions(&["//<_..>", "/a/b"]));
215 assert!(rankless_route_collisions(&["//<_..>", "/<_>"]));
216 assert!(rankless_route_collisions(&["///<a>/", "/a/<a..>"]));
217 assert!(rankless_route_collisions(&["///<a..>/", "/a/<a..>"]));
218 assert!(rankless_route_collisions(&["/<a..>", "/hello"]));
219 }
220
221 #[test]
222 fn test_collisions_query() {
223 assert!(rankless_route_collisions(&["/hello?<foo>", "/hello"]));
225 assert!(rankless_route_collisions(&["/<a>?foo=bar", "/hello?foo=bar&cat=fat"]));
226 assert!(rankless_route_collisions(&["/<a>?foo=bar", "/hello?foo=bar&cat=fat"]));
227 assert!(rankless_route_collisions(&["/<a>", "/<b>?<foo>"]));
228 assert!(rankless_route_collisions(&["/hello/bob?a=b", "/hello/<b>?d=e"]));
229 assert!(rankless_route_collisions(&["/<foo>?a=b", "/foo?d=e"]));
230 assert!(rankless_route_collisions(&["/<foo>?a=b&<c>", "/<foo>?d=e&<c>"]));
231 assert!(rankless_route_collisions(&["/<foo>?a=b&<c>", "/<foo>?d=e"]));
232 }
233
234 #[test]
235 fn test_no_collisions() {
236 assert!(!rankless_route_collisions(&["/a/b", "/a/b/c"]));
237 assert!(!rankless_route_collisions(&["/a/b/c/d", "/a/b/c/<d>/e"]));
238 assert!(!rankless_route_collisions(&["/a/d/<b..>", "/a/b/c"]));
239 assert!(!rankless_route_collisions(&["/<_>", "/"]));
240 assert!(!rankless_route_collisions(&["/a/<_>", "/a"]));
241 assert!(!rankless_route_collisions(&["/a/<_>", "/<_>"]));
242 }
243
244 #[test]
245 fn test_no_collision_when_ranked() {
246 assert!(!default_rank_route_collisions(&["/<a>", "/hello"]));
247 assert!(!default_rank_route_collisions(&["/hello/bob", "/hello/<b>"]));
248 assert!(!default_rank_route_collisions(&["/a/b/c/d", "/<a>/<b>/c/d"]));
249 assert!(!default_rank_route_collisions(&["/hi", "/<hi>"]));
250 assert!(!default_rank_route_collisions(&["/a", "/a/<path..>"]));
251 assert!(!default_rank_route_collisions(&["/", "/<path..>"]));
252 assert!(!default_rank_route_collisions(&["/a/b", "/a/b/<c..>"]));
253 assert!(!default_rank_route_collisions(&["/<_>", "/static"]));
254 assert!(!default_rank_route_collisions(&["/<_..>", "/static"]));
255 assert!(!default_rank_route_collisions(&["/<path..>", "/"]));
256 assert!(!default_rank_route_collisions(&["/<_>/<_>", "/foo/bar"]));
257 assert!(!default_rank_route_collisions(&["/foo/<_>", "/foo/bar"]));
258
259 assert!(!default_rank_route_collisions(&["/<a>/<b>", "/hello/<b>"]));
260 assert!(!default_rank_route_collisions(&["/<a>/<b..>", "/hello/<b>"]));
261 assert!(!default_rank_route_collisions(&["/<a..>", "/hello/<b>"]));
262 assert!(!default_rank_route_collisions(&["/<a..>", "/hello"]));
263 assert!(!default_rank_route_collisions(&["/<a>", "/a/<path..>"]));
264 assert!(!default_rank_route_collisions(&["/a/<b>/c", "/<d>/<c..>"]));
265 }
266
267 #[test]
268 fn test_collision_when_ranked() {
269 assert!(default_rank_route_collisions(&["/a/<b>/<c..>", "/a/<c>"]));
270 assert!(default_rank_route_collisions(&["/<a>/b", "/a/<b>"]));
271 }
272
273 #[test]
274 fn test_collision_when_ranked_query() {
275 assert!(default_rank_route_collisions(&["/a?a=b", "/a?c=d"]));
276 assert!(default_rank_route_collisions(&["/a?a=b&<b>", "/a?<c>&c=d"]));
277 assert!(default_rank_route_collisions(&["/a?a=b&<b..>", "/a?<c>&c=d"]));
278 }
279
280 #[test]
281 fn test_no_collision_when_ranked_query() {
282 assert!(!default_rank_route_collisions(&["/", "/?<c..>"]));
283 assert!(!default_rank_route_collisions(&["/hi", "/hi?<c>"]));
284 assert!(!default_rank_route_collisions(&["/hi", "/hi?c"]));
285 assert!(!default_rank_route_collisions(&["/hi?<c>", "/hi?c"]));
286 assert!(!default_rank_route_collisions(&["/<foo>?a=b", "/<foo>?c=d&<d>"]));
287 }
288
289 fn matches<'a>(router: &'a Router, method: Method, uri: &'a str) -> Vec<&'a Route> {
290 let client = Client::debug_with(vec![]).expect("client");
291 let request = client.req(method, Origin::parse(uri).unwrap());
292 router.route(&request).collect()
293 }
294
295 fn route<'a>(router: &'a Router, method: Method, uri: &'a str) -> Option<&'a Route> {
296 matches(router, method, uri).into_iter().next()
297 }
298
299 #[test]
300 fn test_ok_routing() {
301 let router = router_with_routes(&["/hello"]);
302 assert!(route(&router, Get, "/hello").is_some());
303
304 let router = router_with_routes(&["/<a>"]);
305 assert!(route(&router, Get, "/hello").is_some());
306 assert!(route(&router, Get, "/hi").is_some());
307 assert!(route(&router, Get, "/bobbbbbbbbbby").is_some());
308 assert!(route(&router, Get, "/dsfhjasdf").is_some());
309
310 let router = router_with_routes(&["/<a>/<b>"]);
311 assert!(route(&router, Get, "/hello/hi").is_some());
312 assert!(route(&router, Get, "/a/b/").is_some());
313 assert!(route(&router, Get, "/i/a").is_some());
314 assert!(route(&router, Get, "/jdlk/asdij").is_some());
315
316 let mut router = Router::new();
317 router.add_route(Route::new(Put, "/hello", dummy_handler));
318 router.add_route(Route::new(Post, "/hello", dummy_handler));
319 router.add_route(Route::new(Delete, "/hello", dummy_handler));
320 assert!(route(&router, Put, "/hello").is_some());
321 assert!(route(&router, Post, "/hello").is_some());
322 assert!(route(&router, Delete, "/hello").is_some());
323
324 let router = router_with_routes(&["/<a..>"]);
325 assert!(route(&router, Get, "/").is_some());
326 assert!(route(&router, Get, "//").is_some());
327 assert!(route(&router, Get, "/hi").is_some());
328 assert!(route(&router, Get, "/hello/hi").is_some());
329 assert!(route(&router, Get, "/a/b/").is_some());
330 assert!(route(&router, Get, "/i/a").is_some());
331 assert!(route(&router, Get, "/a/b/c/d/e/f").is_some());
332
333 let router = router_with_routes(&["/foo/<a..>"]);
334 assert!(route(&router, Get, "/foo").is_some());
335 assert!(route(&router, Get, "/foo/").is_some());
336 assert!(route(&router, Get, "/foo///bar").is_some());
337 }
338
339 #[test]
340 fn test_err_routing() {
341 let router = router_with_routes(&["/hello"]);
342 assert!(route(&router, Put, "/hello").is_none());
343 assert!(route(&router, Post, "/hello").is_none());
344 assert!(route(&router, Options, "/hello").is_none());
345 assert!(route(&router, Get, "/hell").is_none());
346 assert!(route(&router, Get, "/hi").is_none());
347 assert!(route(&router, Get, "/hello/there").is_none());
348 assert!(route(&router, Get, "/hello/i").is_none());
349 assert!(route(&router, Get, "/hillo").is_none());
350
351 let router = router_with_routes(&["/<a>"]);
352 assert!(route(&router, Put, "/hello").is_none());
353 assert!(route(&router, Post, "/hello").is_none());
354 assert!(route(&router, Options, "/hello").is_none());
355 assert!(route(&router, Get, "/hello/there").is_none());
356 assert!(route(&router, Get, "/hello/i").is_none());
357
358 let router = router_with_routes(&["/<a>/<b>"]);
359 assert!(route(&router, Get, "/a/b/c").is_none());
360 assert!(route(&router, Get, "/a").is_none());
361 assert!(route(&router, Get, "/a/").is_none());
362 assert!(route(&router, Get, "/a/b/c/d").is_none());
363 assert!(route(&router, Put, "/hello/hi").is_none());
364 assert!(route(&router, Put, "/a/b").is_none());
365 assert!(route(&router, Put, "/a/b").is_none());
366
367 let router = router_with_routes(&["/prefix/<a..>"]);
368 assert!(route(&router, Get, "/").is_none());
369 assert!(route(&router, Get, "/prefi/").is_none());
370 }
371
372 macro_rules! assert_ranked_match {
373 ($routes:expr, $to:expr => $want:expr) => ({
374 let router = router_with_routes($routes);
375 assert!(!router.has_collisions());
376 let route_path = route(&router, Get, $to).unwrap().uri.to_string();
377 assert_eq!(route_path, $want.to_string());
378 })
379 }
380
381 #[test]
382 fn test_default_ranking() {
383 assert_ranked_match!(&["/hello", "/<name>"], "/hello" => "/hello");
384 assert_ranked_match!(&["/<name>", "/hello"], "/hello" => "/hello");
385 assert_ranked_match!(&["/<a>", "/hi", "/hi/<b>"], "/hi" => "/hi");
386 assert_ranked_match!(&["/<a>/b", "/hi/c"], "/hi/c" => "/hi/c");
387 assert_ranked_match!(&["/<a>/<b>", "/hi/a"], "/hi/c" => "/<a>/<b>");
388 assert_ranked_match!(&["/hi/a", "/hi/<c>"], "/hi/c" => "/hi/<c>");
389 assert_ranked_match!(&["/a", "/a?<b>"], "/a?b=c" => "/a?<b>");
390 assert_ranked_match!(&["/a", "/a?<b>"], "/a" => "/a?<b>");
391 assert_ranked_match!(&["/a", "/<a>", "/a?<b>", "/<a>?<b>"], "/a" => "/a?<b>");
392 assert_ranked_match!(&["/a", "/<a>", "/a?<b>", "/<a>?<b>"], "/b" => "/<a>?<b>");
393 assert_ranked_match!(&["/a", "/<a>", "/a?<b>", "/<a>?<b>"], "/b?v=1" => "/<a>?<b>");
394 assert_ranked_match!(&["/a", "/<a>", "/a?<b>", "/<a>?<b>"], "/a?b=c" => "/a?<b>");
395 assert_ranked_match!(&["/a", "/a?b"], "/a?b" => "/a?b");
396 assert_ranked_match!(&["/<a>", "/a?b"], "/a?b" => "/a?b");
397 assert_ranked_match!(&["/a", "/<a>?b"], "/a?b" => "/a");
398 assert_ranked_match!(&["/a?<c>&b", "/a?<b>"], "/a" => "/a?<b>");
399 assert_ranked_match!(&["/a?<c>&b", "/a?<b>"], "/a?b" => "/a?<c>&b");
400 assert_ranked_match!(&["/a?<c>&b", "/a?<b>"], "/a?c" => "/a?<b>");
401 assert_ranked_match!(&["/", "/<foo..>"], "/" => "/");
402 assert_ranked_match!(&["/", "/<foo..>"], "/hi" => "/<foo..>");
403 assert_ranked_match!(&["/hi", "/<foo..>"], "/hi" => "/hi");
404 }
405
406 fn ranked_collisions(routes: &[(isize, &'static str)]) -> bool {
407 let router = router_with_ranked_routes(routes);
408 router.has_collisions()
409 }
410
411 #[test]
412 fn test_no_manual_ranked_collisions() {
413 assert!(!ranked_collisions(&[(1, "/a/<b>"), (2, "/a/<b>")]));
414 assert!(!ranked_collisions(&[(0, "/a/<b>"), (2, "/a/<b>")]));
415 assert!(!ranked_collisions(&[(5, "/a/<b>"), (2, "/a/<b>")]));
416 assert!(!ranked_collisions(&[(1, "/a/<b>"), (1, "/b/<b>")]));
417 assert!(!ranked_collisions(&[(1, "/a/<b..>"), (2, "/a/<b..>")]));
418 assert!(!ranked_collisions(&[(0, "/a/<b..>"), (2, "/a/<b..>")]));
419 assert!(!ranked_collisions(&[(5, "/a/<b..>"), (2, "/a/<b..>")]));
420 assert!(!ranked_collisions(&[(1, "/<a..>"), (2, "/<a..>")]));
421 }
422
423 #[test]
424 fn test_ranked_collisions() {
425 assert!(ranked_collisions(&[(2, "/a/<b..>"), (2, "/a/<b..>")]));
426 assert!(ranked_collisions(&[(2, "/a/c/<b..>"), (2, "/a/<b..>")]));
427 assert!(ranked_collisions(&[(2, "/<b..>"), (2, "/a/<b..>")]));
428 }
429
430 macro_rules! assert_ranked_routing {
431 (to: $to:expr, with: $routes:expr, expect: $($want:expr),+) => ({
432 let router = router_with_ranked_routes(&$routes);
433 let routed_to = matches(&router, Get, $to);
434 let expected = &[$($want),+];
435 assert!(routed_to.len() == expected.len());
436 for (got, expected) in routed_to.iter().zip(expected.iter()) {
437 assert_eq!(got.rank, expected.0);
438 assert_eq!(got.uri.to_string(), expected.1.to_string());
439 }
440 })
441 }
442
443 #[test]
444 fn test_ranked_routing() {
445 assert_ranked_routing!(
446 to: "/a/b",
447 with: [(1, "/a/<b>"), (2, "/a/<b>")],
448 expect: (1, "/a/<b>"), (2, "/a/<b>")
449 );
450
451 assert_ranked_routing!(
452 to: "/b/b",
453 with: [(1, "/a/<b>"), (2, "/b/<b>"), (3, "/b/b")],
454 expect: (2, "/b/<b>"), (3, "/b/b")
455 );
456
457 assert_ranked_routing!(
458 to: "/b/b",
459 with: [(2, "/b/<b>"), (1, "/a/<b>"), (3, "/b/b")],
460 expect: (2, "/b/<b>"), (3, "/b/b")
461 );
462
463 assert_ranked_routing!(
464 to: "/b/b",
465 with: [(3, "/b/b"), (2, "/b/<b>"), (1, "/a/<b>")],
466 expect: (2, "/b/<b>"), (3, "/b/b")
467 );
468
469 assert_ranked_routing!(
470 to: "/b/b",
471 with: [(1, "/a/<b>"), (2, "/b/<b>"), (0, "/b/b")],
472 expect: (0, "/b/b"), (2, "/b/<b>")
473 );
474
475 assert_ranked_routing!(
476 to: "/profile/sergio/edit",
477 with: [(1, "/<a>/<b>/edit"), (2, "/profile/<d>"), (0, "/<a>/<b>/<c>")],
478 expect: (0, "/<a>/<b>/<c>"), (1, "/<a>/<b>/edit")
479 );
480
481 assert_ranked_routing!(
482 to: "/profile/sergio/edit",
483 with: [(0, "/<a>/<b>/edit"), (2, "/profile/<d>"), (5, "/<a>/<b>/<c>")],
484 expect: (0, "/<a>/<b>/edit"), (5, "/<a>/<b>/<c>")
485 );
486
487 assert_ranked_routing!(
488 to: "/a/b",
489 with: [(0, "/a/b"), (1, "/a/<b..>")],
490 expect: (0, "/a/b"), (1, "/a/<b..>")
491 );
492
493 assert_ranked_routing!(
494 to: "/a/b/c/d/e/f",
495 with: [(1, "/a/<b..>"), (2, "/a/b/<c..>")],
496 expect: (1, "/a/<b..>"), (2, "/a/b/<c..>")
497 );
498
499 assert_ranked_routing!(
500 to: "/hi",
501 with: [(1, "/hi/<foo..>"), (0, "/hi/<foo>")],
502 expect: (1, "/hi/<foo..>")
503 );
504 }
505
506 macro_rules! assert_default_ranked_routing {
507 (to: $to:expr, with: $routes:expr, expect: $($want:expr),+) => ({
508 let router = router_with_routes(&$routes);
509 let routed_to = matches(&router, Get, $to);
510 let expected = &[$($want),+];
511 assert!(routed_to.len() == expected.len());
512 for (got, expected) in routed_to.iter().zip(expected.iter()) {
513 assert_eq!(got.uri.to_string(), expected.to_string());
514 }
515 })
516 }
517
518 #[test]
519 fn test_default_ranked_routing() {
520 assert_default_ranked_routing!(
521 to: "/a/b?v=1",
522 with: ["/a/<b>", "/a/b"],
523 expect: "/a/b", "/a/<b>"
524 );
525
526 assert_default_ranked_routing!(
527 to: "/a/b?v=1",
528 with: ["/a/<b>", "/a/b", "/a/b?<v>"],
529 expect: "/a/b?<v>", "/a/b", "/a/<b>"
530 );
531
532 assert_default_ranked_routing!(
533 to: "/a/b?v=1",
534 with: ["/a/<b>", "/a/b", "/a/b?<v>", "/a/<b>?<v>"],
535 expect: "/a/b?<v>", "/a/b", "/a/<b>?<v>", "/a/<b>"
536 );
537
538 assert_default_ranked_routing!(
539 to: "/a/b",
540 with: ["/a/<b>", "/a/b", "/a/b?<v>", "/a/<b>?<v>"],
541 expect: "/a/b?<v>", "/a/b", "/a/<b>?<v>", "/a/<b>"
542 );
543
544 assert_default_ranked_routing!(
545 to: "/a/b?c",
546 with: ["/a/b", "/a/b?<c>", "/a/b?c", "/a/<b>?c", "/a/<b>?<c>", "/<a>/<b>"],
547 expect: "/a/b?c", "/a/b?<c>", "/a/b", "/a/<b>?c", "/a/<b>?<c>", "/<a>/<b>"
548 );
549 }
550
551 fn router_with_catchers(catchers: &[(Option<u16>, &str)]) -> Router {
552 let mut router = Router::new();
553 for (code, base) in catchers {
554 let catcher = Catcher::new(*code, crate::catcher::dummy_handler);
555 router.add_catcher(catcher.map_base(|_| base.to_string()).unwrap());
556 }
557
558 router
559 }
560
561 fn catcher<'a>(router: &'a Router, status: Status, uri: &str) -> Option<&'a Catcher> {
562 let client = Client::debug_with(vec![]).expect("client");
563 let request = client.get(Origin::parse(uri).unwrap());
564 router.catch(status, &request)
565 }
566
567 macro_rules! assert_catcher_routing {
568 (
569 catch: [$(($code:expr, $uri:expr)),+],
570 reqs: [$($r:expr),+],
571 with: [$(($ecode:expr, $euri:expr)),+]
572 ) => ({
573 let catchers = vec![$(($code.into(), $uri)),+];
574 let requests = vec![$($r),+];
575 let expected = vec![$(($ecode.into(), $euri)),+];
576
577 let router = router_with_catchers(&catchers);
578 for (req, expected) in requests.iter().zip(expected.iter()) {
579 let req_status = Status::from_code(req.0).expect("valid status");
580 let catcher = catcher(&router, req_status, req.1).expect("some catcher");
581 assert_eq!(catcher.code, expected.0, "<- got, expected ->");
582 assert_eq!(catcher.base.path(), expected.1, "<- got, expected ->");
583 }
584 })
585 }
586
587 #[test]
588 fn test_catcher_routing() {
589 assert_catcher_routing! {
591 catch: [(None, "/")],
592 reqs: [(404, "/a/b/c"), (500, "/a/b"), (415, "/a/b/d"), (422, "/a/b/c/d?foo")],
593 with: [(None, "/"), (None, "/"), (None, "/"), (None, "/")]
594 }
595
596 assert_catcher_routing! {
598 catch: [(None, "/"), (None, "/a"), (None, "/a/b")],
599 reqs: [
600 (404, "/"), (500, "/"),
601 (404, "/a"), (500, "/a"),
602 (404, "/a/b"), (500, "/a/b")
603 ],
604 with: [
605 (None, "/"), (None, "/"),
606 (None, "/a"), (None, "/a"),
607 (None, "/a/b"), (None, "/a/b")
608 ]
609 }
610
611 assert_catcher_routing! {
613 catch: [(None, "/"), (None, "/a"), (None, "/a/b")],
614 reqs: [
615 (404, "/foo"), (500, "/bar"), (422, "/baz/bar"), (418, "/poodle?yes"),
616 (404, "/a/foo"), (500, "/a/bar/baz"), (510, "/a/c"), (423, "/a/c/b"),
617 (404, "/a/b/c"), (500, "/a/b/c/d"), (500, "/a/b?foo"), (400, "/a/b/yes")
618 ],
619 with: [
620 (None, "/"), (None, "/"), (None, "/"), (None, "/"),
621 (None, "/a"), (None, "/a"), (None, "/a"), (None, "/a"),
622 (None, "/a/b"), (None, "/a/b"), (None, "/a/b"), (None, "/a/b")
623 ]
624 }
625
626 assert_catcher_routing! {
628 catch: [(400, "/"), (404, "/"), (None, "/")],
629 reqs: [
630 (400, "/"), (400, "/bar"), (400, "/foo/bar"),
631 (404, "/"), (404, "/bar"), (404, "/foo/bar"),
632 (405, "/"), (405, "/bar"), (406, "/foo/bar")
633 ],
634 with: [
635 (400, "/"), (400, "/"), (400, "/"),
636 (404, "/"), (404, "/"), (404, "/"),
637 (None, "/"), (None, "/"), (None, "/")
638 ]
639 }
640
641 assert_catcher_routing! {
643 catch: [(None, "/a/b"), (404, "/a"), (422, "/a")],
644 reqs: [
645 (404, "/a/b"), (404, "/a/b/c"), (422, "/a/b/c"),
646 (404, "/a"), (404, "/a/c"), (404, "/a/cat/bar"),
647 (422, "/a"), (422, "/a/c"), (422, "/a/cat/bar")
648 ],
649 with: [
650 (None, "/a/b"), (None, "/a/b"), (None, "/a/b"),
651 (404, "/a"), (404, "/a"), (404, "/a"),
652 (422, "/a"), (422, "/a"), (422, "/a")
653 ]
654 }
655
656 assert_catcher_routing! {
658 catch: [(None, "/"), (None, "/a/b"), (500, "/a/b/c"), (500, "/a/b")],
659 reqs: [(404, "/a/b/c"), (500, "/a/b"), (400, "/a/b/d"), (500, "/a/b/c/d?foo")],
660 with: [(None, "/a/b"), (500, "/a/b"), (None, "/a/b"), (500, "/a/b/c")]
661 }
662 }
663}