mirror of
https://github.com/tokio-rs/axum.git
synced 2025-01-06 02:35:42 +01:00
Show path in panic message when merging overlapping MethodRouter
s (#1306)
This commit is contained in:
parent
fa51cf5266
commit
0e04260a27
3 changed files with 57 additions and 15 deletions
|
@ -877,16 +877,30 @@ where
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc = include_str!("../docs/method_routing/merge.md")]
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn merge(mut self, other: MethodRouter<S, B, E>) -> Self {
|
pub(crate) fn merge_for_path(
|
||||||
|
mut self,
|
||||||
|
path: Option<&str>,
|
||||||
|
other: MethodRouter<S, B, E>,
|
||||||
|
) -> Self {
|
||||||
// written using inner functions to generate less IR
|
// written using inner functions to generate less IR
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn merge_inner<T>(name: &str, first: Option<T>, second: Option<T>) -> Option<T> {
|
fn merge_inner<T>(
|
||||||
|
path: Option<&str>,
|
||||||
|
name: &str,
|
||||||
|
first: Option<T>,
|
||||||
|
second: Option<T>,
|
||||||
|
) -> Option<T> {
|
||||||
match (first, second) {
|
match (first, second) {
|
||||||
(Some(_), Some(_)) => panic!(
|
(Some(_), Some(_)) => {
|
||||||
"Overlapping method route. Cannot merge two method routes that both define `{}`", name
|
if let Some(path) = path {
|
||||||
),
|
panic!(
|
||||||
|
"Overlapping method route. Handler for `{name} {path}` already exists"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
panic!("Overlapping method route. Cannot merge two method routes that both define `{name}`")
|
||||||
|
}
|
||||||
|
}
|
||||||
(Some(svc), None) => Some(svc),
|
(Some(svc), None) => Some(svc),
|
||||||
(None, Some(svc)) => Some(svc),
|
(None, Some(svc)) => Some(svc),
|
||||||
(None, None) => None,
|
(None, None) => None,
|
||||||
|
@ -908,14 +922,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.get = merge_inner("get", self.get, other.get);
|
self.get = merge_inner(path, "GET", self.get, other.get);
|
||||||
self.head = merge_inner("head", self.head, other.head);
|
self.head = merge_inner(path, "HEAD", self.head, other.head);
|
||||||
self.delete = merge_inner("delete", self.delete, other.delete);
|
self.delete = merge_inner(path, "DELETE", self.delete, other.delete);
|
||||||
self.options = merge_inner("options", self.options, other.options);
|
self.options = merge_inner(path, "OPTIONS", self.options, other.options);
|
||||||
self.patch = merge_inner("patch", self.patch, other.patch);
|
self.patch = merge_inner(path, "PATCH", self.patch, other.patch);
|
||||||
self.post = merge_inner("post", self.post, other.post);
|
self.post = merge_inner(path, "POST", self.post, other.post);
|
||||||
self.put = merge_inner("put", self.put, other.put);
|
self.put = merge_inner(path, "PUT", self.put, other.put);
|
||||||
self.trace = merge_inner("trace", self.trace, other.trace);
|
self.trace = merge_inner(path, "TRACE", self.trace, other.trace);
|
||||||
|
|
||||||
self.fallback = merge_fallback(self.fallback, other.fallback);
|
self.fallback = merge_fallback(self.fallback, other.fallback);
|
||||||
|
|
||||||
|
@ -924,6 +938,12 @@ where
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc = include_str!("../docs/method_routing/merge.md")]
|
||||||
|
#[track_caller]
|
||||||
|
pub fn merge(self, other: MethodRouter<S, B, E>) -> Self {
|
||||||
|
self.merge_for_path(None, other)
|
||||||
|
}
|
||||||
|
|
||||||
/// Apply a [`HandleErrorLayer`].
|
/// Apply a [`HandleErrorLayer`].
|
||||||
///
|
///
|
||||||
/// This is a convenience method for doing `self.layer(HandleErrorLayer::new(f))`.
|
/// This is a convenience method for doing `self.layer(HandleErrorLayer::new(f))`.
|
||||||
|
@ -948,6 +968,7 @@ where
|
||||||
T::Future: Send + 'static,
|
T::Future: Send + 'static,
|
||||||
{
|
{
|
||||||
// written using an inner function to generate less IR
|
// written using an inner function to generate less IR
|
||||||
|
#[track_caller]
|
||||||
fn set_service<T>(
|
fn set_service<T>(
|
||||||
method_name: &str,
|
method_name: &str,
|
||||||
out: &mut Option<T>,
|
out: &mut Option<T>,
|
||||||
|
|
|
@ -173,7 +173,11 @@ where
|
||||||
{
|
{
|
||||||
// if we're adding a new `MethodRouter` to a route that already has one just
|
// if we're adding a new `MethodRouter` to a route that already has one just
|
||||||
// merge them. This makes `.route("/", get(_)).route("/", post(_))` work
|
// merge them. This makes `.route("/", get(_)).route("/", post(_))` work
|
||||||
let service = Endpoint::MethodRouter(prev_method_router.clone().merge(method_router));
|
let service = Endpoint::MethodRouter(
|
||||||
|
prev_method_router
|
||||||
|
.clone()
|
||||||
|
.merge_for_path(Some(path), method_router),
|
||||||
|
);
|
||||||
self.routes.insert(route_id, service);
|
self.routes.insert(route_id, service);
|
||||||
return self;
|
return self;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -504,6 +504,23 @@ async fn merging_routers_with_fallbacks_panics() {
|
||||||
TestClient::new(one.merge(two));
|
TestClient::new(one.merge(two));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Overlapping method route. Handler for `GET /foo/bar` already exists")]
|
||||||
|
fn routes_with_overlapping_method_routes() {
|
||||||
|
async fn handler() {}
|
||||||
|
let _: Router = Router::new()
|
||||||
|
.route("/foo/bar", get(handler))
|
||||||
|
.route("/foo/bar", get(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Overlapping method route. Handler for `GET /foo/bar` already exists")]
|
||||||
|
fn merging_with_overlapping_method_routes() {
|
||||||
|
async fn handler() {}
|
||||||
|
let app: Router = Router::new().route("/foo/bar", get(handler));
|
||||||
|
app.clone().merge(app);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn merging_routers_with_same_paths_but_different_methods() {
|
async fn merging_routers_with_same_paths_but_different_methods() {
|
||||||
let one = Router::new().route("/", get(|| async { "GET" }));
|
let one = Router::new().route("/", get(|| async { "GET" }));
|
||||||
|
|
Loading…
Reference in a new issue