Skip to content

Commit ec74ddb

Browse files
Added support to parse ipv6 address
1 parent 57a6a70 commit ec74ddb

File tree

1 file changed

+26
-48
lines changed

1 file changed

+26
-48
lines changed

src/client/options.rs

Lines changed: 26 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use serde::{de::Unexpected, Deserialize, Deserializer, Serialize};
2323
use serde_with::skip_serializing_none;
2424
use strsim::jaro_winkler;
2525
use typed_builder::TypedBuilder;
26+
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
2627

2728
#[cfg(any(
2829
feature = "zstd-compression",
@@ -197,60 +198,37 @@ impl ServerAddress {
197198
});
198199
}
199200
}
200-
let mut parts = address.split(':');
201-
let hostname = match parts.next() {
202-
Some(part) => {
203-
if part.is_empty() {
204-
return Err(ErrorKind::InvalidArgument {
205-
message: format!(
206-
"invalid server address: \"{}\"; hostname cannot be empty",
207-
address
208-
),
209-
}
210-
.into());
211-
}
212-
part
201+
202+
// Check if the address is IPv6, indicated by square brackets
203+
let (hostname, port_str) = if address.starts_with('[') && address.ends_with(']') {
204+
// Strip brackets for IPv6
205+
let addr_without_brackets = &address[1..address.len() - 1];
206+
match addr_without_brackets.rsplit_once(':') {
207+
Some((host, port)) => (host, Some(port)),
208+
None => (addr_without_brackets, None),
213209
}
214-
None => {
215-
return Err(ErrorKind::InvalidArgument {
216-
message: format!("invalid server address: \"{}\"", address),
217-
}
218-
.into())
210+
} else {
211+
match address.rsplit_once(':') {
212+
Some((host, port)) => (host, Some(port)),
213+
None => (address, None),
219214
}
220215
};
221216

222-
let port = match parts.next() {
223-
Some(part) => {
224-
let port = u16::from_str(part).map_err(|_| ErrorKind::InvalidArgument {
225-
message: format!(
226-
"port must be valid 16-bit unsigned integer, instead got: {}",
227-
part
228-
),
229-
})?;
230-
231-
if port == 0 {
232-
return Err(ErrorKind::InvalidArgument {
233-
message: format!(
234-
"invalid server address: \"{}\"; port must be non-zero",
235-
address
236-
),
237-
}
238-
.into());
239-
}
240-
if parts.next().is_some() {
241-
return Err(ErrorKind::InvalidArgument {
242-
message: format!(
243-
"address \"{}\" contains more than one unescaped ':'",
244-
address
245-
),
246-
}
247-
.into());
217+
// Validate that the hostname is either a valid IPv4 or IPv6 address
218+
print!("Parsing address: {}\n", hostname);
219+
let is_ipv4 = Ipv4Addr::from_str(hostname).is_ok();
220+
let is_ipv6 = Ipv6Addr::from_str(hostname).is_ok();
221+
let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
222+
let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
223+
if !is_ipv4 && !is_ipv6 && "127.0.0.1".parse() != Ok(localhost_v4) && "::1".parse() != Ok(localhost_v6) {
224+
return Err(ErrorKind::InvalidArgument {
225+
message: format!("invalid hostname: \"{}\"", hostname),
248226
}
227+
.into())
228+
}
249229

250-
Some(port)
251-
}
252-
None => None,
253-
};
230+
// If there's a port, try to parse it
231+
let port = port_str.and_then(|port| port.parse::<u16>().ok());
254232

255233
Ok(ServerAddress::Tcp {
256234
host: hostname.to_lowercase(),

0 commit comments

Comments
 (0)