1 use super::*;
2 use crate::{body::boxed, extract::Extension};
3 use std::collections::HashMap;
4 use tower_http::services::ServeDir;
5 
6 #[crate::test]
nesting_apps()7 async fn nesting_apps() {
8     let api_routes = Router::new()
9         .route(
10             "/users",
11             get(|| async { "users#index" }).post(|| async { "users#create" }),
12         )
13         .route(
14             "/users/:id",
15             get(
16                 |params: extract::Path<HashMap<String, String>>| async move {
17                     format!(
18                         "{}: users#show ({})",
19                         params.get("version").unwrap(),
20                         params.get("id").unwrap()
21                     )
22                 },
23             ),
24         )
25         .route(
26             "/games/:id",
27             get(
28                 |params: extract::Path<HashMap<String, String>>| async move {
29                     format!(
30                         "{}: games#show ({})",
31                         params.get("version").unwrap(),
32                         params.get("id").unwrap()
33                     )
34                 },
35             ),
36         );
37 
38     let app = Router::new()
39         .route("/", get(|| async { "hi" }))
40         .nest("/:version/api", api_routes);
41 
42     let client = TestClient::new(app);
43 
44     let res = client.get("/").send().await;
45     assert_eq!(res.status(), StatusCode::OK);
46     assert_eq!(res.text().await, "hi");
47 
48     let res = client.get("/v0/api/users").send().await;
49     assert_eq!(res.status(), StatusCode::OK);
50     assert_eq!(res.text().await, "users#index");
51 
52     let res = client.get("/v0/api/users/123").send().await;
53     assert_eq!(res.status(), StatusCode::OK);
54     assert_eq!(res.text().await, "v0: users#show (123)");
55 
56     let res = client.get("/v0/api/games/123").send().await;
57     assert_eq!(res.status(), StatusCode::OK);
58     assert_eq!(res.text().await, "v0: games#show (123)");
59 }
60 
61 #[crate::test]
wrong_method_nest()62 async fn wrong_method_nest() {
63     let nested_app = Router::new().route("/", get(|| async {}));
64     let app = Router::new().nest("/", nested_app);
65 
66     let client = TestClient::new(app);
67 
68     let res = client.get("/").send().await;
69     assert_eq!(res.status(), StatusCode::OK);
70 
71     let res = client.post("/").send().await;
72     assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
73     assert_eq!(res.headers()[ALLOW], "GET,HEAD");
74 
75     let res = client.patch("/foo").send().await;
76     assert_eq!(res.status(), StatusCode::NOT_FOUND);
77 }
78 
79 #[crate::test]
nesting_router_at_root()80 async fn nesting_router_at_root() {
81     let nested = Router::new().route("/foo", get(|uri: Uri| async move { uri.to_string() }));
82     let app = Router::new().nest("/", nested);
83 
84     let client = TestClient::new(app);
85 
86     let res = client.get("/").send().await;
87     assert_eq!(res.status(), StatusCode::NOT_FOUND);
88 
89     let res = client.get("/foo").send().await;
90     assert_eq!(res.status(), StatusCode::OK);
91     assert_eq!(res.text().await, "/foo");
92 
93     let res = client.get("/foo/bar").send().await;
94     assert_eq!(res.status(), StatusCode::NOT_FOUND);
95 }
96 
97 #[crate::test]
nesting_router_at_empty_path()98 async fn nesting_router_at_empty_path() {
99     let nested = Router::new().route("/foo", get(|uri: Uri| async move { uri.to_string() }));
100     let app = Router::new().nest("", nested);
101 
102     let client = TestClient::new(app);
103 
104     let res = client.get("/").send().await;
105     assert_eq!(res.status(), StatusCode::NOT_FOUND);
106 
107     let res = client.get("/foo").send().await;
108     assert_eq!(res.status(), StatusCode::OK);
109     assert_eq!(res.text().await, "/foo");
110 
111     let res = client.get("/foo/bar").send().await;
112     assert_eq!(res.status(), StatusCode::NOT_FOUND);
113 }
114 
115 #[crate::test]
nesting_handler_at_root()116 async fn nesting_handler_at_root() {
117     let app = Router::new().nest_service("/", get(|uri: Uri| async move { uri.to_string() }));
118 
119     let client = TestClient::new(app);
120 
121     let res = client.get("/").send().await;
122     assert_eq!(res.status(), StatusCode::OK);
123     assert_eq!(res.text().await, "/");
124 
125     let res = client.get("/foo").send().await;
126     assert_eq!(res.status(), StatusCode::OK);
127     assert_eq!(res.text().await, "/foo");
128 
129     let res = client.get("/foo/bar").send().await;
130     assert_eq!(res.status(), StatusCode::OK);
131     assert_eq!(res.text().await, "/foo/bar");
132 }
133 
134 #[crate::test]
nested_url_extractor()135 async fn nested_url_extractor() {
136     let app = Router::new().nest(
137         "/foo",
138         Router::new().nest(
139             "/bar",
140             Router::new()
141                 .route("/baz", get(|uri: Uri| async move { uri.to_string() }))
142                 .route(
143                     "/qux",
144                     get(|req: Request<Body>| async move { req.uri().to_string() }),
145                 ),
146         ),
147     );
148 
149     let client = TestClient::new(app);
150 
151     let res = client.get("/foo/bar/baz").send().await;
152     assert_eq!(res.status(), StatusCode::OK);
153     assert_eq!(res.text().await, "/baz");
154 
155     let res = client.get("/foo/bar/qux").send().await;
156     assert_eq!(res.status(), StatusCode::OK);
157     assert_eq!(res.text().await, "/qux");
158 }
159 
160 #[crate::test]
nested_url_original_extractor()161 async fn nested_url_original_extractor() {
162     let app = Router::new().nest(
163         "/foo",
164         Router::new().nest(
165             "/bar",
166             Router::new().route(
167                 "/baz",
168                 get(|uri: extract::OriginalUri| async move { uri.0.to_string() }),
169             ),
170         ),
171     );
172 
173     let client = TestClient::new(app);
174 
175     let res = client.get("/foo/bar/baz").send().await;
176     assert_eq!(res.status(), StatusCode::OK);
177     assert_eq!(res.text().await, "/foo/bar/baz");
178 }
179 
180 #[crate::test]
nested_service_sees_stripped_uri()181 async fn nested_service_sees_stripped_uri() {
182     let app = Router::new().nest(
183         "/foo",
184         Router::new().nest(
185             "/bar",
186             Router::new().route_service(
187                 "/baz",
188                 service_fn(|req: Request<Body>| async move {
189                     let body = boxed(Body::from(req.uri().to_string()));
190                     Ok::<_, Infallible>(Response::new(body))
191                 }),
192             ),
193         ),
194     );
195 
196     let client = TestClient::new(app);
197 
198     let res = client.get("/foo/bar/baz").send().await;
199     assert_eq!(res.status(), StatusCode::OK);
200     assert_eq!(res.text().await, "/baz");
201 }
202 
203 #[crate::test]
nest_static_file_server()204 async fn nest_static_file_server() {
205     let app = Router::new().nest_service("/static", ServeDir::new("."));
206 
207     let client = TestClient::new(app);
208 
209     let res = client.get("/static/README.md").send().await;
210     assert_eq!(res.status(), StatusCode::OK);
211 }
212 
213 #[crate::test]
nested_multiple_routes()214 async fn nested_multiple_routes() {
215     let app = Router::new()
216         .nest(
217             "/api",
218             Router::new()
219                 .route("/users", get(|| async { "users" }))
220                 .route("/teams", get(|| async { "teams" })),
221         )
222         .route("/", get(|| async { "root" }));
223 
224     let client = TestClient::new(app);
225 
226     assert_eq!(client.get("/").send().await.text().await, "root");
227     assert_eq!(client.get("/api/users").send().await.text().await, "users");
228     assert_eq!(client.get("/api/teams").send().await.text().await, "teams");
229 }
230 
231 #[test]
232 #[should_panic = "Invalid route \"/\": insertion failed due to conflict with previously registered route: /*__private__axum_nest_tail_param"]
nested_service_at_root_with_other_routes()233 fn nested_service_at_root_with_other_routes() {
234     let _: Router = Router::new()
235         .nest_service("/", Router::new().route("/users", get(|| async {})))
236         .route("/", get(|| async {}));
237 }
238 
239 #[test]
nested_at_root_with_other_routes()240 fn nested_at_root_with_other_routes() {
241     let _: Router = Router::new()
242         .nest("/", Router::new().route("/users", get(|| async {})))
243         .route("/", get(|| async {}));
244 }
245 
246 #[crate::test]
multiple_top_level_nests()247 async fn multiple_top_level_nests() {
248     let app = Router::new()
249         .nest(
250             "/one",
251             Router::new().route("/route", get(|| async { "one" })),
252         )
253         .nest(
254             "/two",
255             Router::new().route("/route", get(|| async { "two" })),
256         );
257 
258     let client = TestClient::new(app);
259 
260     assert_eq!(client.get("/one/route").send().await.text().await, "one");
261     assert_eq!(client.get("/two/route").send().await.text().await, "two");
262 }
263 
264 #[crate::test]
265 #[should_panic(expected = "Invalid route: nested routes cannot contain wildcards (*)")]
nest_cannot_contain_wildcards()266 async fn nest_cannot_contain_wildcards() {
267     _ = Router::<(), Body>::new().nest("/one/*rest", Router::new());
268 }
269 
270 #[crate::test]
outer_middleware_still_see_whole_url()271 async fn outer_middleware_still_see_whole_url() {
272     #[derive(Clone)]
273     struct SetUriExtension<S>(S);
274 
275     #[derive(Clone)]
276     struct Uri(http::Uri);
277 
278     impl<S, B> Service<Request<B>> for SetUriExtension<S>
279     where
280         S: Service<Request<B>>,
281     {
282         type Response = S::Response;
283         type Error = S::Error;
284         type Future = S::Future;
285 
286         fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
287             self.0.poll_ready(cx)
288         }
289 
290         fn call(&mut self, mut req: Request<B>) -> Self::Future {
291             let uri = Uri(req.uri().clone());
292             req.extensions_mut().insert(uri);
293             self.0.call(req)
294         }
295     }
296 
297     async fn handler(Extension(Uri(middleware_uri)): Extension<Uri>) -> impl IntoResponse {
298         middleware_uri.to_string()
299     }
300 
301     let app = Router::new()
302         .route("/", get(handler))
303         .route("/foo", get(handler))
304         .route("/foo/bar", get(handler))
305         .nest("/one", Router::new().route("/two", get(handler)))
306         .fallback(handler)
307         .layer(tower::layer::layer_fn(SetUriExtension));
308 
309     let client = TestClient::new(app);
310 
311     assert_eq!(client.get("/").send().await.text().await, "/");
312     assert_eq!(client.get("/foo").send().await.text().await, "/foo");
313     assert_eq!(client.get("/foo/bar").send().await.text().await, "/foo/bar");
314     assert_eq!(
315         client.get("/not-found").send().await.text().await,
316         "/not-found"
317     );
318     assert_eq!(client.get("/one/two").send().await.text().await, "/one/two");
319 }
320 
321 #[crate::test]
nest_at_capture()322 async fn nest_at_capture() {
323     let api_routes = Router::new().route(
324         "/:b",
325         get(|Path((a, b)): Path<(String, String)>| async move { format!("a={a} b={b}") }),
326     );
327 
328     let app = Router::new().nest("/:a", api_routes);
329 
330     let client = TestClient::new(app);
331 
332     let res = client.get("/foo/bar").send().await;
333     assert_eq!(res.status(), StatusCode::OK);
334     assert_eq!(res.text().await, "a=foo b=bar");
335 }
336 
337 #[crate::test]
nest_with_and_without_trailing()338 async fn nest_with_and_without_trailing() {
339     let app = Router::new().nest_service("/foo", get(|| async {}));
340 
341     let client = TestClient::new(app);
342 
343     let res = client.get("/foo").send().await;
344     assert_eq!(res.status(), StatusCode::OK);
345 
346     let res = client.get("/foo/").send().await;
347     assert_eq!(res.status(), StatusCode::OK);
348 
349     let res = client.get("/foo/bar").send().await;
350     assert_eq!(res.status(), StatusCode::OK);
351 }
352 
353 #[tokio::test]
nesting_with_root_inner_router()354 async fn nesting_with_root_inner_router() {
355     let app = Router::new()
356         .nest_service("/service", Router::new().route("/", get(|| async {})))
357         .nest("/router", Router::new().route("/", get(|| async {})))
358         .nest("/router-slash/", Router::new().route("/", get(|| async {})));
359 
360     let client = TestClient::new(app);
361 
362     // `/service/` does match the `/service` prefix and the remaining path is technically
363     // empty, which is the same as `/` which matches `.route("/", _)`
364     let res = client.get("/service").send().await;
365     assert_eq!(res.status(), StatusCode::OK);
366 
367     // `/service/` does match the `/service` prefix and the remaining path is `/`
368     // which matches `.route("/", _)`
369     //
370     // this is perhaps a little surprising but don't think there is much we can do
371     let res = client.get("/service/").send().await;
372     assert_eq!(res.status(), StatusCode::OK);
373 
374     // at least it does work like you'd expect when using `nest`
375 
376     let res = client.get("/router").send().await;
377     assert_eq!(res.status(), StatusCode::OK);
378 
379     let res = client.get("/router/").send().await;
380     assert_eq!(res.status(), StatusCode::NOT_FOUND);
381 
382     let res = client.get("/router-slash").send().await;
383     assert_eq!(res.status(), StatusCode::NOT_FOUND);
384 
385     let res = client.get("/router-slash/").send().await;
386     assert_eq!(res.status(), StatusCode::OK);
387 }
388 
389 macro_rules! nested_route_test {
390     (
391         $name:ident,
392         // the path we nest the inner router at
393         nest = $nested_path:literal,
394         // the route the inner router accepts
395         route = $route_path:literal,
396         // the route we expect to be able to call
397         expected = $expected_path:literal $(,)?
398     ) => {
399         #[crate::test]
400         async fn $name() {
401             let inner = Router::new().route($route_path, get(|| async {}));
402             let app = Router::new().nest($nested_path, inner);
403             let client = TestClient::new(app);
404             let res = client.get($expected_path).send().await;
405             let status = res.status();
406             assert_eq!(status, StatusCode::OK, "Router");
407         }
408     };
409 }
410 
411 // test cases taken from https://github.com/tokio-rs/axum/issues/714#issuecomment-1058144460
412 nested_route_test!(nest_1, nest = "", route = "/", expected = "/");
413 nested_route_test!(nest_2, nest = "", route = "/a", expected = "/a");
414 nested_route_test!(nest_3, nest = "", route = "/a/", expected = "/a/");
415 nested_route_test!(nest_4, nest = "/", route = "/", expected = "/");
416 nested_route_test!(nest_5, nest = "/", route = "/a", expected = "/a");
417 nested_route_test!(nest_6, nest = "/", route = "/a/", expected = "/a/");
418 nested_route_test!(nest_7, nest = "/a", route = "/", expected = "/a");
419 nested_route_test!(nest_8, nest = "/a", route = "/a", expected = "/a/a");
420 nested_route_test!(nest_9, nest = "/a", route = "/a/", expected = "/a/a/");
421 nested_route_test!(nest_11, nest = "/a/", route = "/", expected = "/a/");
422 nested_route_test!(nest_12, nest = "/a/", route = "/a", expected = "/a/a");
423 nested_route_test!(nest_13, nest = "/a/", route = "/a/", expected = "/a/a/");
424