From 24aa6dc0b2f11d88771a07c22b2875c805c48763 Mon Sep 17 00:00:00 2001 From: ospab Date: Tue, 26 May 2026 22:17:27 +0300 Subject: [PATCH] fix: redirect exact webpath to trailing slash and fix empty webpath static handler prefix --- ostp-server/src/api.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/ostp-server/src/api.rs b/ostp-server/src/api.rs index 56f35b6..fbca15a 100644 --- a/ostp-server/src/api.rs +++ b/ostp-server/src/api.rs @@ -153,7 +153,14 @@ struct Assets; async fn static_handler(State(state): State, uri: Uri) -> impl IntoResponse { let mut path = uri.path(); - let prefix = format!("/{}", state.webpath); + + let webpath = state.webpath.trim_matches('/'); + let prefix = if webpath.is_empty() { + "/panel".to_string() + } else { + format!("/{}", webpath) + }; + if path.starts_with(&prefix) { path = &path[prefix.len()..]; } @@ -206,17 +213,27 @@ pub fn create_api_router(state: ApiState) -> Router { let webpath = state.webpath.clone(); let webpath = webpath.trim_matches('/'); - - // If no webpath is provided, default to random path to hide panel + let base_route = if webpath.is_empty() { "/panel".to_string() } else { format!("/{}", webpath) }; + let redirect_target = format!("{}/", base_route); + let redirect_route = base_route.clone(); + Router::new() + // Exact /{webpath} → redirect to /{webpath}/ (so relative asset paths work) + .route(&redirect_route, get(move || { + let target = redirect_target.clone(); + async move { axum::response::Redirect::permanent(&target) } + })) + // /{webpath}/ and /{webpath}/** → serve embedded static files + .route(&format!("{}/", base_route), get(static_handler.clone())) + .route(&format!("{}/*path", base_route), get(static_handler)) + // /{webpath}/api/* → API handlers .nest(&format!("{}/api", base_route), api_router) - .nest(&base_route, Router::new().fallback(get(static_handler))) .layer(cors) .with_state(state) }