From 39f91b55717ad1dad05223ce1dd09a1e2c6f4cfc Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 18 Dec 2024 17:30:14 +0100 Subject: [PATCH] axum/extract/query: Use `serde_path_to_error` to report key that failed to parse --- axum/Cargo.toml | 3 ++- axum/src/extract/query.rs | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/axum/Cargo.toml b/axum/Cargo.toml index 5d9b0edb6d0..8f2335f37d5 100644 --- a/axum/Cargo.toml +++ b/axum/Cargo.toml @@ -31,7 +31,7 @@ macros = ["dep:axum-macros"] matched-path = [] multipart = ["dep:multer"] original-uri = [] -query = ["dep:serde_urlencoded"] +query = ["dep:form_urlencoded", "dep:serde_urlencoded", "dep:serde_path_to_error"] tokio = ["dep:hyper-util", "dep:tokio", "tokio/net", "tokio/rt", "tower/make", "tokio/macros"] tower-log = ["tower/log"] tracing = ["dep:tracing", "axum-core/tracing"] @@ -68,6 +68,7 @@ tower-service = "0.3" # optional dependencies axum-macros = { path = "../axum-macros", version = "0.5.0-rc.1", optional = true } base64 = { version = "0.22.1", optional = true } +form_urlencoded = { version = "1.1.0", optional = true } hyper = { version = "1.1.0", optional = true } hyper-util = { version = "0.1.3", features = ["tokio", "server", "service"], optional = true } multer = { version = "3.0.0", optional = true } diff --git a/axum/src/extract/query.rs b/axum/src/extract/query.rs index 7998b2b6e5d..b89d5d8c4e1 100644 --- a/axum/src/extract/query.rs +++ b/axum/src/extract/query.rs @@ -87,7 +87,8 @@ where _state: &S, ) -> Result, Self::Rejection> { if let Some(query) = parts.uri.query() { - let value = serde_urlencoded::from_str(query) + let deserializer = serde_urlencoded::Deserializer::new(form_urlencoded::parse(query.as_bytes())); + let value = serde_path_to_error::deserialize(deserializer) .map_err(FailedToDeserializeQueryString::from_err)?; Ok(Some(Self(value))) } else { @@ -121,8 +122,9 @@ where /// ``` pub fn try_from_uri(value: &Uri) -> Result { let query = value.query().unwrap_or_default(); + let deserializer = serde_urlencoded::Deserializer::new(form_urlencoded::parse(query.as_bytes())); let params = - serde_urlencoded::from_str(query).map_err(FailedToDeserializeQueryString::from_err)?; + serde_path_to_error::deserialize(deserializer).map_err(FailedToDeserializeQueryString::from_err)?; Ok(Query(params)) } } @@ -201,7 +203,7 @@ mod tests { let res = client.get("/?n=hi").await; assert_eq!(res.status(), StatusCode::BAD_REQUEST); - assert_eq!(res.text().await, "Failed to deserialize query string: invalid digit found in string"); + assert_eq!(res.text().await, "Failed to deserialize query string: n: invalid digit found in string"); } #[test]