From 168b2f227d1959252dc47518641da7d214a81ed3 Mon Sep 17 00:00:00 2001 From: Aravinth Manivannan Date: Tue, 31 Aug 2021 02:20:40 +0530 Subject: [PATCH] compile time validation of path (#2350) * compile time validation of path * added trybuild err message * Update Cargo.toml * add changelog entry * test more cases of path validation * fmt Co-authored-by: Rob Ede --- actix-router/src/resource.rs | 5 ++- actix-web-codegen/CHANGES.md | 3 ++ actix-web-codegen/Cargo.toml | 1 + actix-web-codegen/src/route.rs | 2 + actix-web-codegen/tests/trybuild.rs | 1 + .../trybuild/route-malformed-path-fail.rs | 33 +++++++++++++++ .../trybuild/route-malformed-path-fail.stderr | 42 +++++++++++++++++++ 7 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 actix-web-codegen/tests/trybuild/route-malformed-path-fail.rs create mode 100644 actix-web-codegen/tests/trybuild/route-malformed-path-fail.stderr diff --git a/actix-router/src/resource.rs b/actix-router/src/resource.rs index fbf29cc7..57ce3680 100644 --- a/actix-router/src/resource.rs +++ b/actix-router/src/resource.rs @@ -967,7 +967,10 @@ impl ResourceDef { _ => false, }) .unwrap_or_else(|| { - panic!(r#"path "{}" contains malformed dynamic segment"#, pattern) + panic!( + r#"pattern "{}" contains malformed dynamic segment"#, + pattern + ) }); let (mut param, mut unprocessed) = pattern.split_at(close_idx + 1); diff --git a/actix-web-codegen/CHANGES.md b/actix-web-codegen/CHANGES.md index a8a901f7..4fd393b4 100644 --- a/actix-web-codegen/CHANGES.md +++ b/actix-web-codegen/CHANGES.md @@ -1,6 +1,9 @@ # Changes ## Unreleased - 2021-xx-xx +* In routing macros, paths are now validated at compile time. [#2350] + +[#2350]: https://github.com/actix/actix-web/pull/2350 ## 0.5.0-beta.3 - 2021-06-17 diff --git a/actix-web-codegen/Cargo.toml b/actix-web-codegen/Cargo.toml index 4d0fd5e2..66f7acf6 100644 --- a/actix-web-codegen/Cargo.toml +++ b/actix-web-codegen/Cargo.toml @@ -17,6 +17,7 @@ proc-macro = true quote = "1" syn = { version = "1", features = ["full", "parsing"] } proc-macro2 = "1" +actix-router = "0.5.0-beta.1" [dev-dependencies] actix-rt = "2.2" diff --git a/actix-web-codegen/src/route.rs b/actix-web-codegen/src/route.rs index 74704252..c2f851a0 100644 --- a/actix-web-codegen/src/route.rs +++ b/actix-web-codegen/src/route.rs @@ -3,6 +3,7 @@ extern crate proc_macro; use std::collections::HashSet; use std::convert::TryFrom; +use actix_router::ResourceDef; use proc_macro::TokenStream; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{format_ident, quote, ToTokens, TokenStreamExt}; @@ -101,6 +102,7 @@ impl Args { match arg { NestedMeta::Lit(syn::Lit::Str(lit)) => match path { None => { + let _ = ResourceDef::new(lit.value()); path = Some(lit); } _ => { diff --git a/actix-web-codegen/tests/trybuild.rs b/actix-web-codegen/tests/trybuild.rs index 12e848cf..c97211e9 100644 --- a/actix-web-codegen/tests/trybuild.rs +++ b/actix-web-codegen/tests/trybuild.rs @@ -10,6 +10,7 @@ fn compile_macros() { t.compile_fail("tests/trybuild/route-missing-method-fail.rs"); t.compile_fail("tests/trybuild/route-duplicate-method-fail.rs"); t.compile_fail("tests/trybuild/route-unexpected-method-fail.rs"); + t.compile_fail("tests/trybuild/route-malformed-path-fail.rs"); t.pass("tests/trybuild/docstring-ok.rs"); } diff --git a/actix-web-codegen/tests/trybuild/route-malformed-path-fail.rs b/actix-web-codegen/tests/trybuild/route-malformed-path-fail.rs new file mode 100644 index 00000000..1258a6f2 --- /dev/null +++ b/actix-web-codegen/tests/trybuild/route-malformed-path-fail.rs @@ -0,0 +1,33 @@ +use actix_web_codegen::get; + +#[get("/{")] +async fn zero() -> &'static str { + "malformed resource def" +} + +#[get("/{foo")] +async fn one() -> &'static str { + "malformed resource def" +} + +#[get("/{}")] +async fn two() -> &'static str { + "malformed resource def" +} + +#[get("/*")] +async fn three() -> &'static str { + "malformed resource def" +} + +#[get("/{tail:\\d+}*")] +async fn four() -> &'static str { + "malformed resource def" +} + +#[get("/{a}/{b}/{c}/{d}/{e}/{f}/{g}/{h}/{i}/{j}/{k}/{l}/{m}/{n}/{o}/{p}/{q}")] +async fn five() -> &'static str { + "malformed resource def" +} + +fn main() {} diff --git a/actix-web-codegen/tests/trybuild/route-malformed-path-fail.stderr b/actix-web-codegen/tests/trybuild/route-malformed-path-fail.stderr new file mode 100644 index 00000000..93c51010 --- /dev/null +++ b/actix-web-codegen/tests/trybuild/route-malformed-path-fail.stderr @@ -0,0 +1,42 @@ +error: custom attribute panicked + --> $DIR/route-malformed-path-fail.rs:3:1 + | +3 | #[get("/{")] + | ^^^^^^^^^^^^ + | + = help: message: pattern "{" contains malformed dynamic segment + +error: custom attribute panicked + --> $DIR/route-malformed-path-fail.rs:8:1 + | +8 | #[get("/{foo")] + | ^^^^^^^^^^^^^^^ + | + = help: message: pattern "{foo" contains malformed dynamic segment + +error: custom attribute panicked + --> $DIR/route-malformed-path-fail.rs:13:1 + | +13 | #[get("/{}")] + | ^^^^^^^^^^^^^ + | + = help: message: Wrong path pattern: "/{}" regex parse error: + ((?s-m)^/(?P<>[^/]+))$ + ^ + error: empty capture group name + +error: custom attribute panicked + --> $DIR/route-malformed-path-fail.rs:23:1 + | +23 | #[get("/{tail:\\d+}*")] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: message: custom regex is not supported for tail match + +error: custom attribute panicked + --> $DIR/route-malformed-path-fail.rs:28:1 + | +28 | #[get("/{a}/{b}/{c}/{d}/{e}/{f}/{g}/{h}/{i}/{j}/{k}/{l}/{m}/{n}/{o}/{p}/{q}")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: message: Only 16 dynamic segments are allowed, provided: 17