fix(sdk): allow hostnames in server address configuration#2923
fix(sdk): allow hostnames in server address configuration#2923felixfaisal wants to merge 9 commits intoapache:masterfrom
Conversation
Signed-off-by: Faisal Ahmed <faisalahmedfarooq46@gmail.com>
Signed-off-by: Faisal Ahmed <faisalahmedfarooq46@gmail.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2923 +/- ##
============================================
+ Coverage 71.74% 71.81% +0.06%
Complexity 943 943
============================================
Files 1121 1122 +1
Lines 93800 93976 +176
Branches 71124 71313 +189
============================================
+ Hits 67301 67485 +184
+ Misses 23863 23839 -24
- Partials 2636 2652 +16
🚀 New features to boost your workflow:
|
hubcio
left a comment
There was a problem hiding this comment.
hey, thanks for the pr! the intent is solid but there's a fundamental issue with the approach.
to_socket_addrs() calls getaddrinfo() under the hood, which is a synchronous blocking dns lookup. doing this inside build() means config construction now requires network access and can block the thread for seconds if dns is slow. config builders hould be pure/deterministic - th quic builder already gets this right by doing zero address validation in build(). we cannot accept this resolution.
validate the format only (valid host:port structure, port is a valid u16) and leave actual dns resolution to connect time. TcpStream::connect already does resolution internally anyway.
|
hello @felixfaisal do you plan to continue? |
Hey @hubcio Sorry for not paying attention here, I was a bit caught up this week, I plan to address the comments and update the logic by tonight or late tomorrow. I mostly agree with your review and will do the changes. |
Signed-off-by: Faisal Ahmed <faisalahmedfarooq46@gmail.com>
core/common/src/utils/net.rs
Outdated
| "".to_string(), | ||
| ))?; | ||
|
|
||
| if host.is_empty() { |
There was a problem hiding this comment.
currently only empty host and bare colons are rejected, but any other characters pass - e.g. "!!!:8080" is accepted. would be good to add basic hostname character validation per RFC 952/1123 (alphanumeric, hyphens, dots) to catch obviously invalid addresses at config time rather than deferring everything to DNS resolution at connect time.
There was a problem hiding this comment.
Created a separate function, to check if valid IPv4 address and if not check if valid hostname, added a couple of unit tests using claude. ✅
I was thinking if i should use regex or not, and ultimately decided to do it this way.
|
@felixfaisal both of these comments are not fixed. do you plan do to so? |
Signed-off-by: Faisal Ahmed <faisalahmedfarooq46@gmail.com>
| @@ -105,11 +104,7 @@ impl TcpClientConfigBuilder { | |||
| /// Builds the TCP client configuration. | |||
| pub fn build(self) -> Result<TcpClientConfig, IggyError> { | |||
| let addr = self.config.server_address.trim(); | |||
There was a problem hiding this comment.
build() validates the trimmed addr but returns self.config with the original untrimmed server_address. if someone passes " localhost:8090 ", validation passes but TcpStream::connect later gets the whitespace-padded string. same issue in websocket_client_config_builder.rs.
fix: self.config.server_address = self.config.server_address.trim().to_string(); before validating.
core/common/src/utils/net.rs
Outdated
| /// - Bare IPv6 without brackets (e.g. `::1:8080`) — ambiguous due to colons | ||
| /// - Missing port (e.g. `localhost`) | ||
| /// - Invalid port (e.g. `localhost:abc`, `localhost:65536`) | ||
| pub fn parse_server_address(addr: &str) -> Result<(), IggyError> { |
There was a problem hiding this comment.
the function name says "parse" but it returns Result<(), IggyError> - it validates, it doesn't parse anything. validate_server_address would be more accurate for a public API, or return a structured type like (host, port) to make the parse useful.
There was a problem hiding this comment.
Updated to validate_server_address ✅
core/common/src/utils/net.rs
Outdated
| addr.to_string(), | ||
| "".to_string(), | ||
| ))?; | ||
| let ipv6_str = &rest[0..close]; |
There was a problem hiding this comment.
&rest[0..close] - the 0.. is redundant, &rest[..close] is idiomatic.
core/sdk/src/prelude.rs
Outdated
| TcpClientReconnectionConfig, Topic, TopicDetails, TopicPermissions, TransportEndpoints, | ||
| TransportProtocol, UserId, UserStatus, Validatable, WebSocketClientConfig, | ||
| WebSocketClientConfigBuilder, WebSocketClientReconnectionConfig, defaults, locking, | ||
| parse_server_address, |
There was a problem hiding this comment.
parse_server_address is a low-level validation utility. the builders already call it internally, so SDK consumers rarely need it directly. consider keeping it importable from iggy_common without putting it in the prelude - prelude is for iggy users.
core/common/src/utils/mod.rs
Outdated
| pub(crate) mod duration; | ||
| pub(crate) mod expiry; | ||
| pub(crate) mod hash; | ||
| pub mod net; |
There was a problem hiding this comment.
pub mod net but the sibling modules are pub(crate). since only parse_server_address is re-exported in lib.rs, this could be pub(crate) mod net to match the pattern.
- Rename function to better reflect its purpose (validation only, not parsing) - Make net module private and only export validate_server_address publicly - Update config builders to normalize and validate server addresses - Remove duplicate address validation from examples Signed-off-by: Faisal Ahmed <faisalahmedfarooq46@gmail.com>
Which issue does this PR close?
Closes #2882
Rationale
Server address validation previously required a literal socket address, preventing the use of DNS hostnames. This change allows hostnames (e.g.,
localhost:8080) in addition to IP addresses.What changed?
Server address validation previously relied on
SocketAddrparsing, which only accepts literal IP addresses and rejected DNS hostnames (e.g.,localhost:8080). This prevented using hostnames when configuring client connections.Validation now uses
ToSocketAddrs, which performs address resolution and returns the list of socket addresses for a given host.TcpStream::connect(...)already performs this resolution internally and attempts to connect to each resolved address.Local Execution
AI Usage
If AI tools were used, please answer:
cargo buildTCPConfigBuilderand added an additional unit test, also modifying another