Merge branch 'fix/fix/normalize-host-ipv6'

This commit is contained in:
2026-06-12 04:41:20 +00:00
4 changed files with 78 additions and 40 deletions

View File

@@ -50,8 +50,14 @@ pub fn build_routing_table(sites: &[SiteConfig]) -> HashMap<String, SiteConfig>
} }
pub fn normalize_host(host: &str) -> String { pub fn normalize_host(host: &str) -> String {
let lower = host.to_lowercase(); let stripped = crate::utils::strip_port_from_host(host);
lower.split(':').next().unwrap_or(&lower).to_string() let lower = stripped.to_lowercase();
lower
.strip_prefix('[')
.unwrap_or(&lower)
.strip_suffix(']')
.unwrap_or(&lower)
.to_string()
} }
#[derive(Debug, Deserialize, Clone, PartialEq)] #[derive(Debug, Deserialize, Clone, PartialEq)]
@@ -361,6 +367,26 @@ mod tests {
assert_eq!(normalize_host(""), ""); assert_eq!(normalize_host(""), "");
} }
#[test]
fn normalize_host_ipv6_with_port() {
assert_eq!(normalize_host("[::1]:443"), "::1");
}
#[test]
fn normalize_host_ipv6_long_with_port() {
assert_eq!(normalize_host("[2001:db8::1]:8080"), "2001:db8::1");
}
#[test]
fn normalize_host_ipv6_bare() {
assert_eq!(normalize_host("[::1]"), "::1");
}
#[test]
fn normalize_host_ipv6_uppercase() {
assert_eq!(normalize_host("[2001:DB8::1]:443"), "2001:db8::1");
}
#[test] #[test]
fn routing_table_lookup_finds_site() { fn routing_table_lookup_finds_site() {
let config = test_fixtures::test_dynamic_config(); let config = test_fixtures::test_dynamic_config();

View File

@@ -8,3 +8,4 @@ pub mod rate_limit;
pub mod server; pub mod server;
pub mod shutdown; pub mod shutdown;
pub mod tls; pub mod tls;
pub mod utils;

View File

@@ -13,19 +13,7 @@ use crate::config::static_config::ListenerConfig;
const ACME_CHALLENGE_PREFIX: &str = "/.well-known/acme-challenge/"; const ACME_CHALLENGE_PREFIX: &str = "/.well-known/acme-challenge/";
fn strip_port_from_host(host: &str) -> &str { use crate::utils::strip_port_from_host;
if host.starts_with('[') {
if let Some(bracket_end) = host.find(']') {
&host[..bracket_end + 1]
} else {
host
}
} else if let Some(colon_pos) = host.rfind(':') {
&host[..colon_pos]
} else {
host
}
}
pub fn build_redirect_url(host: &str, https_port: u16, path: &str, query: &str) -> String { pub fn build_redirect_url(host: &str, https_port: u16, path: &str, query: &str) -> String {
let hostname = strip_port_from_host(host); let hostname = strip_port_from_host(host);
@@ -218,29 +206,4 @@ mod tests {
let url = build_redirect_url("203.0.113.10", 443, "/", ""); let url = build_redirect_url("203.0.113.10", 443, "/", "");
assert_eq!(url, "https://203.0.113.10/"); assert_eq!(url, "https://203.0.113.10/");
} }
#[test]
fn test_strip_port_from_host_plain() {
assert_eq!(strip_port_from_host("example.com"), "example.com");
}
#[test]
fn test_strip_port_from_host_with_port() {
assert_eq!(strip_port_from_host("example.com:8080"), "example.com");
}
#[test]
fn test_strip_port_from_host_ipv6_bare() {
assert_eq!(strip_port_from_host("[::1]"), "[::1]");
}
#[test]
fn test_strip_port_from_host_ipv6_with_port() {
assert_eq!(strip_port_from_host("[::1]:8080"), "[::1]");
}
#[test]
fn test_strip_port_from_host_ipv4_with_port() {
assert_eq!(strip_port_from_host("192.168.1.1:8080"), "192.168.1.1");
}
} }

48
src/utils.rs Normal file
View File

@@ -0,0 +1,48 @@
pub fn strip_port_from_host(host: &str) -> &str {
if host.starts_with('[') {
if let Some(bracket_end) = host.find(']') {
&host[..bracket_end + 1]
} else {
host
}
} else if let Some(colon_pos) = host.rfind(':') {
&host[..colon_pos]
} else {
host
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn strip_port_plain() {
assert_eq!(strip_port_from_host("example.com"), "example.com");
}
#[test]
fn strip_port_with_port() {
assert_eq!(strip_port_from_host("example.com:8080"), "example.com");
}
#[test]
fn strip_port_ipv6_bare() {
assert_eq!(strip_port_from_host("[::1]"), "[::1]");
}
#[test]
fn strip_port_ipv6_with_port() {
assert_eq!(strip_port_from_host("[::1]:8080"), "[::1]");
}
#[test]
fn strip_port_ipv6_with_long_address() {
assert_eq!(strip_port_from_host("[2001:db8::1]:8080"), "[2001:db8::1]");
}
#[test]
fn strip_port_ipv4_with_port() {
assert_eq!(strip_port_from_host("192.168.1.1:8080"), "192.168.1.1");
}
}