Stricter path deserialization for tuples and tuple structs (#2931)

This commit is contained in:
Hytak 2024-09-24 19:17:16 +02:00 committed by GitHub
parent 068c9a3e96
commit 4179d11797
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 47 additions and 16 deletions

View file

@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
# Unreleased
- **breaking:** The tuple and tuple_struct `Path` extractor deserializers now check that the number of parameters matches the tuple length exactly ([#2931])
[#2931]: https://github.com/tokio-rs/axum/pull/2931
# 0.7.6 # 0.7.6
- **change:** Avoid cloning `Arc` during deserialization of `Path` - **change:** Avoid cloning `Arc` during deserialization of `Path`

View file

@ -140,7 +140,7 @@ impl<'de> Deserializer<'de> for PathDeserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
if self.url_params.len() < len { if self.url_params.len() != len {
return Err(PathDeserializationError::wrong_number_of_parameters() return Err(PathDeserializationError::wrong_number_of_parameters()
.got(self.url_params.len()) .got(self.url_params.len())
.expected(len)); .expected(len));
@ -160,7 +160,7 @@ impl<'de> Deserializer<'de> for PathDeserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
if self.url_params.len() < len { if self.url_params.len() != len {
return Err(PathDeserializationError::wrong_number_of_parameters() return Err(PathDeserializationError::wrong_number_of_parameters()
.got(self.url_params.len()) .got(self.url_params.len())
.expected(len)); .expected(len));
@ -773,20 +773,6 @@ mod tests {
); );
} }
#[test]
fn test_parse_tuple_ignoring_additional_fields() {
let url_params = create_url_params(vec![
("a", "abc"),
("b", "true"),
("c", "1"),
("d", "false"),
]);
assert_eq!(
<(&str, bool, u32)>::deserialize(PathDeserializer::new(&url_params)).unwrap(),
("abc", true, 1)
);
}
#[test] #[test]
fn test_parse_map() { fn test_parse_map() {
let url_params = create_url_params(vec![("a", "1"), ("b", "true"), ("c", "abc")]); let url_params = create_url_params(vec![("a", "1"), ("b", "true"), ("c", "abc")]);
@ -813,6 +799,18 @@ mod tests {
}; };
} }
#[test]
fn test_parse_tuple_too_many_fields() {
test_parse_error!(
vec![("a", "abc"), ("b", "true"), ("c", "1"), ("d", "false"),],
(&str, bool, u32),
ErrorKind::WrongNumberOfParameters {
got: 4,
expected: 3,
}
);
}
#[test] #[test]
fn test_wrong_number_of_parameters_error() { fn test_wrong_number_of_parameters_error() {
test_parse_error!( test_parse_error!(

View file

@ -747,6 +747,33 @@ mod tests {
); );
} }
#[crate::test]
async fn tuple_param_matches_exactly() {
#[allow(dead_code)]
#[derive(Deserialize)]
struct Tuple(String, String);
let app = Router::new()
.route("/foo/:a/:b/:c", get(|_: Path<(String, String)>| async {}))
.route("/bar/:a/:b/:c", get(|_: Path<Tuple>| async {}));
let client = TestClient::new(app);
let res = client.get("/foo/a/b/c").await;
assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
assert_eq!(
res.text().await,
"Wrong number of path arguments for `Path`. Expected 2 but got 3",
);
let res = client.get("/bar/a/b/c").await;
assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
assert_eq!(
res.text().await,
"Wrong number of path arguments for `Path`. Expected 2 but got 3",
);
}
#[crate::test] #[crate::test]
async fn deserialize_into_vec_of_tuples() { async fn deserialize_into_vec_of_tuples() {
let app = Router::new().route( let app = Router::new().route(