fix(mysql): strip IPv6 brackets before TCP connect

This commit is contained in:
t8y2 2026-07-07 15:47:37 +08:00
parent d90847bbba
commit 23d268450c
1 changed files with 34 additions and 0 deletions

View File

@ -496,6 +496,7 @@ fn create_pool(
let tls_url = mysql_tls_url(url)?;
let opts =
mysql_async::Opts::from_url(&mysql_async_url(&tls_url.url)).map_err(|e| format!("Invalid MySQL URL: {e}"))?;
let tcp_host = mysql_async_tcp_host(opts.ip_or_hostname()).to_string();
let base_ssl_opts = opts.ssl_opts().cloned();
let max_connections = max_connections.max(1);
// Single-connection pools (max_connections == 1) are client session pools that
@ -512,6 +513,7 @@ fn create_pool(
None => mysql_setup_queries(url, extra_setup_queries),
};
let mut builder = mysql_async::OptsBuilder::from_opts(opts)
.ip_or_hostname(tcp_host)
.stmt_cache_size(0)
.prefer_socket(false)
.pool_opts(Some(pool_opts))
@ -523,6 +525,17 @@ fn create_pool(
Ok(MySqlPool::new(builder))
}
fn mysql_async_tcp_host(host: &str) -> &str {
if let Some(inner) = host.strip_prefix('[').and_then(|value| value.strip_suffix(']')) {
// mysql_async preserves IPv6 brackets when converting URL opts into an
// OptsBuilder, but the builder TCP path resolves host strings directly.
if inner.parse::<std::net::Ipv6Addr>().is_ok() {
return inner;
}
}
host
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct MySqlTlsUrl {
url: String,
@ -3711,6 +3724,27 @@ UNIQUE KEY(`tenant_id`, `name``part`)
assert!(MYSQL_TCP_KEEPALIVE_MS >= 1_000);
}
#[test]
fn mysql_async_builder_host_strips_ipv6_url_brackets() {
let opts = mysql_async::Opts::from_url("mysql://root:secret@[2001:db8::1]:3306/app").unwrap();
assert_eq!(opts.ip_or_hostname(), "[2001:db8::1]");
assert_eq!(mysql_async_tcp_host(opts.ip_or_hostname()), "2001:db8::1");
let builder_opts = mysql_async::Opts::from(
mysql_async::OptsBuilder::from_opts(opts).ip_or_hostname(mysql_async_tcp_host("[2001:db8::1]").to_string()),
);
assert_eq!(builder_opts.ip_or_hostname(), "2001:db8::1");
assert_eq!(builder_opts.tcp_port(), 3306);
}
#[test]
fn mysql_async_builder_host_only_strips_valid_ipv6_literals() {
assert_eq!(mysql_async_tcp_host("2001:db8::1"), "2001:db8::1");
assert_eq!(mysql_async_tcp_host("[mysql.example.com]"), "[mysql.example.com]");
assert_eq!(mysql_async_tcp_host("mysql.example.com"), "mysql.example.com");
}
#[test]
fn mysql_tls_url_strips_client_identity_params_before_driver_parse() {
let dir = std::env::temp_dir();