From e4865e17fa66ed01e62293b2791be213320b653c Mon Sep 17 00:00:00 2001 From: Kristopher Wuollett Date: Wed, 2 Aug 2023 13:57:15 -0500 Subject: [PATCH] Add empty path capture docs and tests (#2127) --- axum/src/docs/routing/route.md | 3 +- axum/src/extract/path/mod.rs | 59 +++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/axum/src/docs/routing/route.md b/axum/src/docs/routing/route.md index a4491897..eefbb21b 100644 --- a/axum/src/docs/routing/route.md +++ b/axum/src/docs/routing/route.md @@ -22,7 +22,8 @@ be called. # Captures Paths can contain segments like `/:key` which matches any single segment and -will store the value captured at `key`. +will store the value captured at `key`. The value captured can be zero-length +except for in the invalid path `//`. Examples: diff --git a/axum/src/extract/path/mod.rs b/axum/src/extract/path/mod.rs index 5f7c7107..dd9acccc 100644 --- a/axum/src/extract/path/mod.rs +++ b/axum/src/extract/path/mod.rs @@ -629,7 +629,7 @@ mod tests { } #[crate::test] - async fn captures_dont_match_empty_segments() { + async fn captures_dont_match_empty_path() { let app = Router::new().route("/:key", get(|| async {})); let client = TestClient::new(app); @@ -641,6 +641,63 @@ mod tests { assert_eq!(res.status(), StatusCode::OK); } + #[crate::test] + async fn captures_match_empty_inner_segments() { + let app = Router::new().route( + "/:key/method", + get(|Path(param): Path| async move { param.to_string() }), + ); + + let client = TestClient::new(app); + + let res = client.get("/abc/method").send().await; + assert_eq!(res.text().await, "abc"); + + let res = client.get("//method").send().await; + assert_eq!(res.text().await, ""); + } + + #[crate::test] + async fn captures_match_empty_inner_segments_near_end() { + let app = Router::new().route( + "/method/:key/", + get(|Path(param): Path| async move { param.to_string() }), + ); + + let client = TestClient::new(app); + + let res = client.get("/method/abc").send().await; + assert_eq!(res.status(), StatusCode::NOT_FOUND); + + let res = client.get("/method/abc/").send().await; + assert_eq!(res.text().await, "abc"); + + let res = client.get("/method//").send().await; + assert_eq!(res.text().await, ""); + } + + #[crate::test] + async fn captures_match_empty_trailing_segment() { + let app = Router::new().route( + "/method/:key", + get(|Path(param): Path| async move { param.to_string() }), + ); + + let client = TestClient::new(app); + + let res = client.get("/method/abc/").send().await; + assert_eq!(res.status(), StatusCode::NOT_FOUND); + + let res = client.get("/method/abc").send().await; + assert_eq!(res.text().await, "abc"); + + let res = client.get("/method/").send().await; + assert_eq!(res.text().await, ""); + + let res = client.get("/method").send().await; + assert_eq!(res.status(), StatusCode::NOT_FOUND); + } + #[crate::test] async fn str_reference_deserialize() { struct Param(String);