From 20dfe6645d2c840d07b079d2e819d6e483aa4169 Mon Sep 17 00:00:00 2001 From: Tomaz Canabrava Date: Thu, 19 Mar 2026 12:42:00 +0100 Subject: [PATCH] Improve typed path by disallowing deprecated variable definitions (#3618) --- axum-extra/CHANGELOG.md | 3 +++ axum-extra/src/routing/mod.rs | 39 ++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/axum-extra/CHANGELOG.md b/axum-extra/CHANGELOG.md index 9ebd3a2f..9b09a65f 100644 --- a/axum-extra/CHANGELOG.md +++ b/axum-extra/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning]. - **fixed:** Escape backslashes and double quotes in `Content-Disposition` filenames to prevent header parameter injection in `Attachment` and `FileStream` ([#3664]) +- `vpath!` macro now stops the compilation if your path is using deprecated + path variables in the old `107` format, such as `:var` and `*var`. the + only allowed way now is `{var}`. - **breaking:** Remove the deprecated `Host`, `Scheme` and `OptionalPath` extractors ([#3599]) - Also remove `HostRejection` which only had `FailedToResolveHost` diff --git a/axum-extra/src/routing/mod.rs b/axum-extra/src/routing/mod.rs index d32f4bbc..3b3cdc67 100644 --- a/axum-extra/src/routing/mod.rs +++ b/axum-extra/src/routing/mod.rs @@ -36,6 +36,20 @@ pub const fn __private_validate_static_path(path: &'static str) -> &'static str if path.as_bytes()[0] != b'/' { panic!("Paths must start with /"); } + + // Checks if we have a path in 107 format. + let size: usize = path.len() - 1; + let mut curr: usize = 0; + let bytes = path.as_bytes(); + while curr < size { + if bytes[curr] == b'/' && (bytes[curr + 1] == b'*' || bytes[curr + 1] == b':') { + panic!( + "You have a path with a deprecated format, move your ':var' or '*var' to '{{var}}'" + ); + } + curr += 1; + } + path } @@ -61,12 +75,35 @@ pub const fn __private_validate_static_path(path: &'static str) -> &'static str /// use axum_extra::vpath; /// /// let router = axum::Router::<()>::new() -/// .route(vpath!("/valid_path"), get(root)) +/// .route(vpath!("/valid_path/{id}"), get(root)) /// .to_owned(); /// /// async fn root() {} /// ``` /// +/// It also checks for deprecated usage of variables within the path: +/// +/// ```compile_fail +/// use axum::routing::{Router, get}; +/// use axum_extra::vpath; +/// +/// let router = axum::Router::<()>::new() +/// .route(vpath!("/users/:id"), get(root)) +/// .to_owned(); +/// +/// async fn root() {} +/// ``` +/// +/// ```compile_fail +/// use axum::routing::{Router, get}; +/// use axum_extra::vpath; +/// +/// let router = axum::Router::<()>::new() +/// .route(vpath!("/users/*id"), get(root)) +/// .to_owned(); +/// +/// async fn root() {} +/// ``` /// This macro is available only on rust versions 1.80 and above. #[cfg_attr(docsrs, doc(cfg(feature = "routing")))] #[rustversion::since(1.80)]