From 725d5a9e68df1062c4f6e42a7f558b6ed0265c54 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Thu, 16 Jan 2025 11:04:08 +0800 Subject: [PATCH] fix: redirect /dashboard to /dashboard/ (#5369) * fix: redirect /dashboard to /dashboard/ * test: update integration test --- src/servers/src/http.rs | 25 ++++++++++++++++++++----- src/servers/src/http/dashboard.rs | 10 +--------- tests-integration/tests/http.rs | 6 ++++-- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/servers/src/http.rs b/src/servers/src/http.rs index 0b6d275c3c..fe3a46b33b 100644 --- a/src/servers/src/http.rs +++ b/src/servers/src/http.rs @@ -673,15 +673,30 @@ impl HttpServer { { if !self.options.disable_dashboard { info!("Enable dashboard service at '/dashboard'"); - router = router.nest("/dashboard", dashboard::dashboard()); + // redirect /dashboard to /dashboard/ + router = router.route( + "/dashboard", + routing::get(|uri: axum::http::uri::Uri| async move { + let path = uri.path(); + let query = uri.query().map(|q| format!("?{}", q)).unwrap_or_default(); + + let new_uri = format!("{}/{}", path, query); + axum::response::Redirect::permanent(&new_uri) + }), + ); // "/dashboard" and "/dashboard/" are two different paths in Axum. // We cannot nest "/dashboard/", because we already mapping "/dashboard/*x" while nesting "/dashboard". // So we explicitly route "/dashboard/" here. - router = router.route( - "/dashboard/", - routing::get(dashboard::static_handler).post(dashboard::static_handler), - ); + router = router + .route( + "/dashboard/", + routing::get(dashboard::static_handler).post(dashboard::static_handler), + ) + .route( + "/dashboard/*x", + routing::get(dashboard::static_handler).post(dashboard::static_handler), + ); } } diff --git a/src/servers/src/http/dashboard.rs b/src/servers/src/http/dashboard.rs index 90b8a48aca..36ec2f9b30 100644 --- a/src/servers/src/http/dashboard.rs +++ b/src/servers/src/http/dashboard.rs @@ -15,8 +15,6 @@ use axum::body::{boxed, Full}; use axum::http::{header, StatusCode, Uri}; use axum::response::Response; -use axum::routing; -use axum::routing::Router; use common_telemetry::debug; use rust_embed::RustEmbed; use snafu::ResultExt; @@ -27,17 +25,11 @@ use crate::error::{BuildHttpResponseSnafu, Result}; #[folder = "dashboard/dist/"] pub struct Assets; -pub(crate) fn dashboard() -> Router { - Router::new() - .route("/", routing::get(static_handler).post(static_handler)) - .route("/*x", routing::get(static_handler).post(static_handler)) -} - #[axum_macros::debug_handler] pub async fn static_handler(uri: Uri) -> Result { debug!("[dashboard] requesting: {}", uri.path()); - let mut path = uri.path().trim_start_matches('/'); + let mut path = uri.path().trim_start_matches("/dashboard/"); if path.is_empty() { path = "index.html"; } diff --git a/tests-integration/tests/http.rs b/tests-integration/tests/http.rs index 8aa3254d2a..becf8cd529 100644 --- a/tests-integration/tests/http.rs +++ b/tests-integration/tests/http.rs @@ -999,9 +999,11 @@ pub async fn test_dashboard_path(store_type: StorageType) { let (app, _guard) = setup_test_http_app_with_frontend(store_type, "dashboard_path").await; let client = TestClient::new(app); - let res_post = client.post("/dashboard").send().await; - assert_eq!(res_post.status(), StatusCode::OK); let res_get = client.get("/dashboard").send().await; + assert_eq!(res_get.status(), StatusCode::PERMANENT_REDIRECT); + let res_post = client.post("/dashboard/").send().await; + assert_eq!(res_post.status(), StatusCode::OK); + let res_get = client.get("/dashboard/").send().await; assert_eq!(res_get.status(), StatusCode::OK); // both `GET` and `POST` method return same result