mirror of
https://github.com/tokio-rs/axum.git
synced 2025-01-16 22:43:03 +01:00
Don't allow extracting MatchedPath
in fallbacks (#1934)
This commit is contained in:
parent
e97462d452
commit
2c87d65f17
5 changed files with 60 additions and 20 deletions
|
@ -7,7 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
- None.
|
- **fixed:** Don't allow extracting `MatchedPath` in fallbacks ([#1934])
|
||||||
|
- **fixed:** Fix panic if `Router` with something nested at `/` was used as a fallback ([#1934])
|
||||||
|
|
||||||
|
[#1934]: https://github.com/tokio-rs/axum/pull/1934
|
||||||
|
|
||||||
# 0.6.15 (12. April, 2023)
|
# 0.6.15 (12. April, 2023)
|
||||||
|
|
||||||
|
|
|
@ -176,6 +176,7 @@ mod tests {
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use http::{Request, StatusCode};
|
use http::{Request, StatusCode};
|
||||||
|
use hyper::Body;
|
||||||
|
|
||||||
#[crate::test]
|
#[crate::test]
|
||||||
async fn extracting_on_handler() {
|
async fn extracting_on_handler() {
|
||||||
|
@ -353,4 +354,19 @@ mod tests {
|
||||||
let res = client.get("/foo/bar").send().await;
|
let res = client.get("/foo/bar").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[crate::test]
|
||||||
|
async fn cant_extract_in_fallback() {
|
||||||
|
async fn handler(path: Option<MatchedPath>, req: Request<Body>) {
|
||||||
|
assert!(path.is_none());
|
||||||
|
assert!(req.extensions().get::<MatchedPath>().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
let app = Router::new().fallback(handler);
|
||||||
|
|
||||||
|
let client = TestClient::new(app);
|
||||||
|
|
||||||
|
let res = client.get("/foo/bar").send().await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,8 +57,8 @@ pub(crate) struct RouteId(u32);
|
||||||
/// The router type for composing handlers and services.
|
/// The router type for composing handlers and services.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct Router<S = (), B = Body> {
|
pub struct Router<S = (), B = Body> {
|
||||||
path_router: PathRouter<S, B>,
|
path_router: PathRouter<S, B, false>,
|
||||||
fallback_router: PathRouter<S, B>,
|
fallback_router: PathRouter<S, B, true>,
|
||||||
default_fallback: bool,
|
default_fallback: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,7 +499,7 @@ impl<S, B> fmt::Debug for Endpoint<S, B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SuperFallback<S, B>(SyncWrapper<PathRouter<S, B>>);
|
struct SuperFallback<S, B>(SyncWrapper<PathRouter<S, B, true>>);
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(warnings)]
|
#[allow(warnings)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::body::{Body, HttpBody};
|
use crate::body::HttpBody;
|
||||||
use axum_core::response::IntoResponse;
|
use axum_core::response::IntoResponse;
|
||||||
use http::Request;
|
use http::Request;
|
||||||
use matchit::MatchError;
|
use matchit::MatchError;
|
||||||
|
@ -11,13 +11,13 @@ use super::{
|
||||||
RouteId, NEST_TAIL_PARAM,
|
RouteId, NEST_TAIL_PARAM,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) struct PathRouter<S = (), B = Body> {
|
pub(super) struct PathRouter<S, B, const IS_FALLBACK: bool> {
|
||||||
routes: HashMap<RouteId, Endpoint<S, B>>,
|
routes: HashMap<RouteId, Endpoint<S, B>>,
|
||||||
node: Arc<Node>,
|
node: Arc<Node>,
|
||||||
prev_route_id: RouteId,
|
prev_route_id: RouteId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B> PathRouter<S, B>
|
impl<S, B, const IS_FALLBACK: bool> PathRouter<S, B, IS_FALLBACK>
|
||||||
where
|
where
|
||||||
B: HttpBody + Send + 'static,
|
B: HttpBody + Send + 'static,
|
||||||
S: Clone + Send + Sync + 'static,
|
S: Clone + Send + Sync + 'static,
|
||||||
|
@ -107,7 +107,10 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn merge(&mut self, other: PathRouter<S, B>) -> Result<(), Cow<'static, str>> {
|
pub(super) fn merge(
|
||||||
|
&mut self,
|
||||||
|
other: PathRouter<S, B, IS_FALLBACK>,
|
||||||
|
) -> Result<(), Cow<'static, str>> {
|
||||||
let PathRouter {
|
let PathRouter {
|
||||||
routes,
|
routes,
|
||||||
node,
|
node,
|
||||||
|
@ -131,7 +134,7 @@ where
|
||||||
pub(super) fn nest(
|
pub(super) fn nest(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &str,
|
path: &str,
|
||||||
router: PathRouter<S, B>,
|
router: PathRouter<S, B, IS_FALLBACK>,
|
||||||
) -> Result<(), Cow<'static, str>> {
|
) -> Result<(), Cow<'static, str>> {
|
||||||
let prefix = validate_nest_path(path);
|
let prefix = validate_nest_path(path);
|
||||||
|
|
||||||
|
@ -193,7 +196,7 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn layer<L, NewReqBody>(self, layer: L) -> PathRouter<S, NewReqBody>
|
pub(super) fn layer<L, NewReqBody>(self, layer: L) -> PathRouter<S, NewReqBody, IS_FALLBACK>
|
||||||
where
|
where
|
||||||
L: Layer<Route<B>> + Clone + Send + 'static,
|
L: Layer<Route<B>> + Clone + Send + 'static,
|
||||||
L::Service: Service<Request<NewReqBody>> + Clone + Send + 'static,
|
L::Service: Service<Request<NewReqBody>> + Clone + Send + 'static,
|
||||||
|
@ -250,7 +253,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn with_state<S2>(self, state: S) -> PathRouter<S2, B> {
|
pub(super) fn with_state<S2>(self, state: S) -> PathRouter<S2, B, IS_FALLBACK> {
|
||||||
let routes = self
|
let routes = self
|
||||||
.routes
|
.routes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -293,12 +296,14 @@ where
|
||||||
Ok(match_) => {
|
Ok(match_) => {
|
||||||
let id = *match_.value;
|
let id = *match_.value;
|
||||||
|
|
||||||
#[cfg(feature = "matched-path")]
|
if !IS_FALLBACK {
|
||||||
crate::extract::matched_path::set_matched_path_for_request(
|
#[cfg(feature = "matched-path")]
|
||||||
id,
|
crate::extract::matched_path::set_matched_path_for_request(
|
||||||
&self.node.route_id_to_path,
|
id,
|
||||||
req.extensions_mut(),
|
&self.node.route_id_to_path,
|
||||||
);
|
req.extensions_mut(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
url_params::insert_url_params(req.extensions_mut(), match_.params);
|
url_params::insert_url_params(req.extensions_mut(), match_.params);
|
||||||
|
|
||||||
|
@ -347,7 +352,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, S> Default for PathRouter<S, B> {
|
impl<B, S, const IS_FALLBACK: bool> Default for PathRouter<S, B, IS_FALLBACK> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
routes: Default::default(),
|
routes: Default::default(),
|
||||||
|
@ -357,7 +362,7 @@ impl<B, S> Default for PathRouter<S, B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B> fmt::Debug for PathRouter<S, B> {
|
impl<S, B, const IS_FALLBACK: bool> fmt::Debug for PathRouter<S, B, IS_FALLBACK> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("PathRouter")
|
f.debug_struct("PathRouter")
|
||||||
.field("routes", &self.routes)
|
.field("routes", &self.routes)
|
||||||
|
@ -366,7 +371,7 @@ impl<S, B> fmt::Debug for PathRouter<S, B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B> Clone for PathRouter<S, B> {
|
impl<S, B, const IS_FALLBACK: bool> Clone for PathRouter<S, B, IS_FALLBACK> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
routes: self.routes.clone(),
|
routes: self.routes.clone(),
|
||||||
|
|
|
@ -225,3 +225,19 @@ async fn nest_fallback_on_inner() {
|
||||||
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||||
assert_eq!(res.text().await, "inner fallback");
|
assert_eq!(res.text().await, "inner fallback");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/tokio-rs/axum/issues/1931
|
||||||
|
#[crate::test]
|
||||||
|
async fn doesnt_panic_if_used_with_nested_router() {
|
||||||
|
async fn handler() {}
|
||||||
|
|
||||||
|
let routes_static =
|
||||||
|
Router::new().nest_service("/", crate::routing::get_service(handler.into_service()));
|
||||||
|
|
||||||
|
let routes_all = Router::new().fallback_service(routes_static);
|
||||||
|
|
||||||
|
let client = TestClient::new(routes_all);
|
||||||
|
|
||||||
|
let res = client.get("/foobar").send().await;
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue