Skip to content

Commit

Permalink
Stricter path deserialization for tuples and tuple structs (#2931)
Browse files Browse the repository at this point in the history
  • Loading branch information
LHolten authored Sep 24, 2024
1 parent 068c9a3 commit 4179d11
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 16 deletions.
6 changes: 6 additions & 0 deletions axum/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/),
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

- **change:** Avoid cloning `Arc` during deserialization of `Path`
Expand Down
30 changes: 14 additions & 16 deletions axum/src/extract/path/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ impl<'de> Deserializer<'de> for PathDeserializer<'de> {
where
V: Visitor<'de>,
{
if self.url_params.len() < len {
if self.url_params.len() != len {
return Err(PathDeserializationError::wrong_number_of_parameters()
.got(self.url_params.len())
.expected(len));
Expand All @@ -160,7 +160,7 @@ impl<'de> Deserializer<'de> for PathDeserializer<'de> {
where
V: Visitor<'de>,
{
if self.url_params.len() < len {
if self.url_params.len() != len {
return Err(PathDeserializationError::wrong_number_of_parameters()
.got(self.url_params.len())
.expected(len));
Expand Down Expand Up @@ -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]
fn test_parse_map() {
let url_params = create_url_params(vec![("a", "1"), ("b", "true"), ("c", "abc")]);
Expand All @@ -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]
fn test_wrong_number_of_parameters_error() {
test_parse_error!(
Expand Down
27 changes: 27 additions & 0 deletions axum/src/extract/path/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
async fn deserialize_into_vec_of_tuples() {
let app = Router::new().route(
Expand Down

0 comments on commit 4179d11

Please sign in to comment.