fix(axum): deduplicate methods in the Allow header after merging MethodRouters (#3836)

This commit is contained in:
Zane Wang
2026-07-16 11:16:22 +02:00
committed by GitHub
parent 98aea470f9
commit b7e3788993
2 changed files with 28 additions and 5 deletions
+3
View File
@@ -26,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **changed:** `Redirect` constructors now accept any `impl Into<String>` ([#3635])
- **changed:** Updated `matchit` allowing for routes with captures and static prefixes and suffixes ([#3702])
- **fixed:** Responses to `HEAD` will not accidentally reply with `content-length: 0` anymore ([#3742])
- **fixed:** `MethodRouter::merge` no longer lists a method twice in the `Allow`
header after merging `get` and `head` ([#3836])
[#3158]: https://github.com/tokio-rs/axum/pull/3158
[#3261]: https://github.com/tokio-rs/axum/pull/3261
@@ -38,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#3702]: https://github.com/tokio-rs/axum/pull/3702
[#3721]: https://github.com/tokio-rs/axum/pull/3721
[#3742]: https://github.com/tokio-rs/axum/pull/3742
[#3836]: https://github.com/tokio-rs/axum/pull/3836
[#3757]: https://github.com/tokio-rs/axum/pull/3757
# 0.8.9
+25 -5
View File
@@ -574,10 +574,19 @@ impl AllowHeader {
(Self::Skip, _) | (_, Self::Skip) => Self::Skip,
(Self::None, Self::None) => Self::None,
(Self::None, Self::Bytes(pick)) | (Self::Bytes(pick), Self::None) => Self::Bytes(pick),
(Self::Bytes(mut a), Self::Bytes(b)) => {
a.extend_from_slice(b",");
a.extend_from_slice(&b);
Self::Bytes(a)
(mut this @ Self::Bytes(_), Self::Bytes(b)) => {
match std::str::from_utf8(&b) {
Ok(methods) => {
for method in methods.split(',') {
append_allow_header(&mut this, method);
}
}
Err(_) => {
#[cfg(debug_assertions)]
panic!("`allow_header` contained invalid utf-8. This should never happen")
}
}
this
}
}
}
@@ -1222,7 +1231,7 @@ where
}
}
fn append_allow_header(allow_header: &mut AllowHeader, method: &'static str) {
fn append_allow_header(allow_header: &mut AllowHeader, method: &str) {
match allow_header {
AllowHeader::None => {
*allow_header = AllowHeader::Bytes(BytesMut::from(method));
@@ -1545,6 +1554,17 @@ mod tests {
assert_eq!(headers[ALLOW], "PUT,PATCH,GET,HEAD");
}
#[crate::test]
async fn allow_header_merging_get_into_head() {
let a = get(ok);
let b = head(created);
let mut svc = a.merge(b);
let (status, headers, _) = call(Method::DELETE, &mut svc).await;
assert_eq!(status, StatusCode::METHOD_NOT_ALLOWED);
assert_eq!(headers[ALLOW], "GET,HEAD");
}
#[crate::test]
async fn allow_header_any() {
let mut svc = any(ok);