From 8abe7836776dd4ddb9f27b3feb2f6548047389b9 Mon Sep 17 00:00:00 2001 From: Maurus Decimus <11444311+mdecimus@users.noreply.github.com> Date: Tue, 21 Apr 2026 15:27:02 +0200 Subject: [PATCH] Do not include port number when constructing HTTP base URLs --- CHANGELOG.md | 2 +- crates/common/src/config/network.rs | 23 +++++++++++------------ crates/http-proto/src/context.rs | 22 +++------------------- crates/http/src/auth/oauth/auth.rs | 2 +- crates/http/src/auth/oauth/openid.rs | 2 +- crates/http/src/auth/oauth/token.rs | 4 +++- crates/http/src/request.rs | 2 +- crates/store/src/build/registry.rs | 6 ------ crates/store/src/lib.rs | 1 - crates/store/src/registry/local.rs | 4 ---- 10 files changed, 21 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cae16d3..1e1055e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,11 @@ All notable changes to this project will be documented in this file. This projec This version includes **multiple breaking changes**. If you are upgrading from v0.15.x and below, please read the [upgrading documentation](https://github.com/stalwartlabs/stalwart/blob/main/UPGRADING/v0_16.md) for more information on how to upgrade from previous versions. ## Added -- New `STALWART_HTTP_PORT` to override the HTTP port used in URLs advertised via JMAP and OAuth. ## Changed ## Fixed +- Do not include port number when constructing HTTP base URLs. - OSS builds. - Cloudflare `CAA` record updates. diff --git a/crates/common/src/config/network.rs b/crates/common/src/config/network.rs index 41c262fc..cea7ca3d 100644 --- a/crates/common/src/config/network.rs +++ b/crates/common/src/config/network.rs @@ -366,6 +366,10 @@ impl Network { } impl Http { + #[cfg_attr( + any(feature = "dev_mode", feature = "test_mode"), + allow(unused_variables) + )] pub async fn parse(bp: &mut Bootstrap, server_name: &str) -> Self { let http = bp.setting_infallible::().await; @@ -426,22 +430,17 @@ impl Http { )); } + #[cfg(any(feature = "dev_mode", feature = "test_mode"))] + let server_name = "127.0.0.1:8080"; + Http { - url_https: if !bp.registry.is_bootstrap_mode() { - if let Some(port) = bp.registry.http_port() { - format!("https://{}:{}", server_name, port) - } else { - format!("https://{}", server_name) - } + url_https: if !bp.registry.is_recovery_mode() { + format!("https://{server_name}") } else { String::new() }, - url_http: if !bp.registry.is_bootstrap_mode() { - if let Some(port) = bp.registry.http_port() { - format!("http://{}:{}", server_name, port) - } else { - format!("http://{}", server_name) - } + url_http: if !bp.registry.is_recovery_mode() { + format!("http://{server_name}") } else { String::new() }, diff --git a/crates/http-proto/src/context.rs b/crates/http-proto/src/context.rs index a2ac2d46..d4c72e88 100644 --- a/crates/http-proto/src/context.rs +++ b/crates/http-proto/src/context.rs @@ -19,27 +19,11 @@ impl<'x> HttpContext<'x> { } #[allow(unused_variables)] - pub fn resolve_response_url(&self, server: &Server) -> String { + pub fn resolve_response_url<'y>(&self, server: &'y Server) -> &'y str { if self.session.is_tls { - #[cfg(not(any(feature = "dev_mode", feature = "test_mode")))] - { - server.core.network.http.url_https.clone() - } - - #[cfg(any(feature = "dev_mode", feature = "test_mode"))] - { - format!("https://127.0.0.1:{}", self.session.local_port) - } + &server.core.network.http.url_https } else { - #[cfg(not(any(feature = "dev_mode", feature = "test_mode")))] - { - server.core.network.http.url_http.clone() - } - - #[cfg(any(feature = "dev_mode", feature = "test_mode"))] - { - format!("http://127.0.0.1:{}", self.session.local_port) - } + &server.core.network.http.url_http } } diff --git a/crates/http/src/auth/oauth/auth.rs b/crates/http/src/auth/oauth/auth.rs index 25ea6247..45748bb2 100644 --- a/crates/http/src/auth/oauth/auth.rs +++ b/crates/http/src/auth/oauth/auth.rs @@ -464,7 +464,7 @@ impl OAuthApiHandler for Server { "urn:ietf:params:jmap:vacationresponse", ], code_challenge_methods_supported: &["S256"], - issuer: base_url, + issuer: base_url.to_string(), }) .into_http_response()) } diff --git a/crates/http/src/auth/oauth/openid.rs b/crates/http/src/auth/oauth/openid.rs index 747846d0..d4488582 100644 --- a/crates/http/src/auth/oauth/openid.rs +++ b/crates/http/src/auth/oauth/openid.rs @@ -90,7 +90,7 @@ impl OpenIdHandler for Server { "email_verified", ], code_challenge_methods_supported: &["S256"], - issuer: base_url, + issuer: base_url.to_string(), }) .into_http_response()) } diff --git a/crates/http/src/auth/oauth/token.rs b/crates/http/src/auth/oauth/token.rs index 99f2b1d5..8842ee68 100644 --- a/crates/http/src/auth/oauth/token.rs +++ b/crates/http/src/auth/oauth/token.rs @@ -64,7 +64,9 @@ impl TokenHandler for Server { let mut response = TokenResponse::error(ErrorType::InvalidGrant); - let issuer = HttpContext::new(&session, req).resolve_response_url(self); + let issuer = HttpContext::new(&session, req) + .resolve_response_url(self) + .to_string(); if grant_type.eq_ignore_ascii_case("authorization_code") { response = if let (Some(code), Some(client_id), Some(redirect_uri)) = ( diff --git a/crates/http/src/request.rs b/crates/http/src/request.rs index ad859a22..44a7b76b 100644 --- a/crates/http/src/request.rs +++ b/crates/http/src/request.rs @@ -197,7 +197,7 @@ impl ParseHttp for Server { self.authenticate_headers(&req, &session).await?; self.handle_session_resource( - ctx.resolve_response_url(self), + ctx.resolve_response_url(self).to_string(), &access_token, ) .await diff --git a/crates/store/src/build/registry.rs b/crates/store/src/build/registry.rs index 9336520c..1efdab35 100644 --- a/crates/store/src/build/registry.rs +++ b/crates/store/src/build/registry.rs @@ -275,11 +275,6 @@ impl RegistryStore { &self.0.env_hostname } - #[inline(always)] - pub fn http_port(&self) -> Option { - self.0.env_http_port - } - #[inline(always)] pub fn is_recovery_mode(&self) -> bool { self.0.env_recovery_mode @@ -323,7 +318,6 @@ impl RegistryStore { env_cluster_role: cluster_role, env_push_shard_id: push_shard_id, env_hostname: hostname, - env_http_port: None, id_generator: utils::snowflake::SnowflakeIdGenerator::new(), }) .await diff --git a/crates/store/src/lib.rs b/crates/store/src/lib.rs index 4151bf83..9c3829f9 100644 --- a/crates/store/src/lib.rs +++ b/crates/store/src/lib.rs @@ -217,7 +217,6 @@ pub struct RegistryStoreInner { pub(crate) env_cluster_role: Option, pub(crate) env_push_shard_id: u32, pub(crate) env_hostname: String, - pub(crate) env_http_port: Option, pub(crate) id_generator: SnowflakeIdGenerator, } diff --git a/crates/store/src/registry/local.rs b/crates/store/src/registry/local.rs index 374eb24a..ae18ec14 100644 --- a/crates/store/src/registry/local.rs +++ b/crates/store/src/registry/local.rs @@ -52,10 +52,6 @@ impl RegistryStoreInner { "localhost".to_string() } }), - env_http_port: std::env::var("STALWART_HTTP_PORT") - .ok() - .and_then(|v| v.trim().parse::().ok()) - .filter(|&u| u != 0), } }