diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e177a1..3248579 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - QIDO-RS and MWL services now support `uid-list-matching` syntax for match query parameters. +### Changed + +- Trailing slashes in URLs are now trimmed for all endpoints before processing (`/studies/` and `/studies` are equivalent). + ## [0.3.0] ### Added diff --git a/Cargo.toml b/Cargo.toml index 57331e7..26f0a32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ axum-extra = { version = "0.10.3", features = ["query"] } axum-streams = { version = "0.23.1", features = ["json"] } futures = "0.3.31" mime = "0.3.17" -tower-http = { version = "0.6.6", features = ["trace", "cors", "timeout"] } +tower-http = { version = "0.6.6", features = ["trace", "cors", "timeout", "normalize-path"] } tower = { version = "0.5.2", features = ["limit"] } url = "2.5.7" async-trait = "0.1.89" diff --git a/src/main.rs b/src/main.rs index 74413bb..e326254 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,11 +13,15 @@ use crate::types::AE; use association::pool::AssociationPools; use axum::extract::{DefaultBodyLimit, Request}; use axum::response::Response; +use axum::routing::IntoMakeService; +use axum::ServiceExt; use std::net::SocketAddr; use std::time::Duration; use tokio::net::TcpListener; use tokio::signal; +use tower::Layer; use tower_http::cors::CorsLayer; +use tower_http::normalize_path::NormalizePathLayer; use tower_http::timeout::TimeoutLayer; use tower_http::trace; use tracing::{error, info, level_filters::LevelFilter, Level}; @@ -144,6 +148,9 @@ async fn run(config: AppConfig) -> anyhow::Result<()> { ))) .with_state(app_state); + let app = NormalizePathLayer::trim_trailing_slash().layer(app); + let service = ServiceExt::::into_make_service(app); + let HttpServerConfig { interface: host, port, @@ -159,11 +166,11 @@ async fn run(config: AppConfig) -> anyhow::Result<()> { "Started DICOMweb server" ); if config.server.http.graceful_shutdown { - axum::serve(listener, app) + axum::serve(listener, service) .with_graceful_shutdown(shutdown_signal()) .await?; } else { - axum::serve(listener, app).await?; + axum::serve(listener, service).await?; } Ok(())