Skip to content

Commit 25fac01

Browse files
committed
Fix panic location for overlapping method routes
1 parent 291b62e commit 25fac01

File tree

2 files changed

+32
-23
lines changed

2 files changed

+32
-23
lines changed

axum/src/routing/method_routing.rs

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::{
1515
use axum_core::{extract::Request, response::IntoResponse, BoxError};
1616
use bytes::BytesMut;
1717
use std::{
18+
borrow::Cow,
1819
convert::Infallible,
1920
fmt,
2021
task::{Context, Poll},
@@ -1031,58 +1032,66 @@ where
10311032
self
10321033
}
10331034

1034-
#[track_caller]
1035-
pub(crate) fn merge_for_path(mut self, path: Option<&str>, other: MethodRouter<S, E>) -> Self {
1035+
pub(crate) fn merge_for_path(
1036+
mut self,
1037+
path: Option<&str>,
1038+
other: MethodRouter<S, E>,
1039+
) -> Result<Self, Cow<'static, str>> {
10361040
// written using inner functions to generate less IR
1037-
#[track_caller]
10381041
fn merge_inner<S, E>(
10391042
path: Option<&str>,
10401043
name: &str,
10411044
first: MethodEndpoint<S, E>,
10421045
second: MethodEndpoint<S, E>,
1043-
) -> MethodEndpoint<S, E> {
1046+
) -> Result<MethodEndpoint<S, E>, Cow<'static, str>> {
10441047
match (first, second) {
1045-
(MethodEndpoint::None, MethodEndpoint::None) => MethodEndpoint::None,
1046-
(pick, MethodEndpoint::None) | (MethodEndpoint::None, pick) => pick,
1048+
(MethodEndpoint::None, MethodEndpoint::None) => Ok(MethodEndpoint::None),
1049+
(pick, MethodEndpoint::None) | (MethodEndpoint::None, pick) => Ok(pick),
10471050
_ => {
10481051
if let Some(path) = path {
1049-
panic!(
1052+
Err(format!(
10501053
"Overlapping method route. Handler for `{name} {path}` already exists"
1051-
);
1054+
)
1055+
.into())
10521056
} else {
1053-
panic!(
1057+
Err(format!(
10541058
"Overlapping method route. Cannot merge two method routes that both \
10551059
define `{name}`"
1056-
);
1060+
)
1061+
.into())
10571062
}
10581063
}
10591064
}
10601065
}
10611066

1062-
self.get = merge_inner(path, "GET", self.get, other.get);
1063-
self.head = merge_inner(path, "HEAD", self.head, other.head);
1064-
self.delete = merge_inner(path, "DELETE", self.delete, other.delete);
1065-
self.options = merge_inner(path, "OPTIONS", self.options, other.options);
1066-
self.patch = merge_inner(path, "PATCH", self.patch, other.patch);
1067-
self.post = merge_inner(path, "POST", self.post, other.post);
1068-
self.put = merge_inner(path, "PUT", self.put, other.put);
1069-
self.trace = merge_inner(path, "TRACE", self.trace, other.trace);
1070-
self.connect = merge_inner(path, "CONNECT", self.connect, other.connect);
1067+
self.get = merge_inner(path, "GET", self.get, other.get)?;
1068+
self.head = merge_inner(path, "HEAD", self.head, other.head)?;
1069+
self.delete = merge_inner(path, "DELETE", self.delete, other.delete)?;
1070+
self.options = merge_inner(path, "OPTIONS", self.options, other.options)?;
1071+
self.patch = merge_inner(path, "PATCH", self.patch, other.patch)?;
1072+
self.post = merge_inner(path, "POST", self.post, other.post)?;
1073+
self.put = merge_inner(path, "PUT", self.put, other.put)?;
1074+
self.trace = merge_inner(path, "TRACE", self.trace, other.trace)?;
1075+
self.connect = merge_inner(path, "CONNECT", self.connect, other.connect)?;
10711076

10721077
self.fallback = self
10731078
.fallback
10741079
.merge(other.fallback)
1075-
.expect("Cannot merge two `MethodRouter`s that both have a fallback");
1080+
.ok_or("Cannot merge two `MethodRouter`s that both have a fallback")?;
10761081

10771082
self.allow_header = self.allow_header.merge(other.allow_header);
10781083

1079-
self
1084+
Ok(self)
10801085
}
10811086

10821087
#[doc = include_str!("../docs/method_routing/merge.md")]
10831088
#[track_caller]
10841089
pub fn merge(self, other: MethodRouter<S, E>) -> Self {
1085-
self.merge_for_path(None, other)
1090+
match self.merge_for_path(None, other) {
1091+
Ok(t) => t,
1092+
// not using unwrap or unwrap_or_else to get a clean panic message + the right location
1093+
Err(e) => panic!("{e}"),
1094+
}
10861095
}
10871096

10881097
/// Apply a [`HandleErrorLayer`].

axum/src/routing/path_router.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ where
9898
let service = Endpoint::MethodRouter(
9999
prev_method_router
100100
.clone()
101-
.merge_for_path(Some(path), method_router),
101+
.merge_for_path(Some(path), method_router)?,
102102
);
103103
self.routes.insert(route_id, service);
104104
return Ok(());

0 commit comments

Comments
 (0)