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