@@ -170,12 +170,42 @@ fn require_nonempty(endpoint: &str, target: &str) -> ClientResult<()> {
170170fn require_tcp_target ( endpoint : & str , target : & str ) -> ClientResult < ( ) > {
171171 require_nonempty ( endpoint, target) ?;
172172
173- let Some ( ( host, port) ) = target. rsplit_once ( ':' ) else {
174- return Err ( ClientError :: unsupported_endpoint (
175- endpoint,
176- "missing TCP port" ,
177- ) ) ;
173+ let ( host, port) = if let Some ( rest) = target. strip_prefix ( '[' ) {
174+ let Some ( ( host, after_host) ) = rest. split_once ( ']' ) else {
175+ return Err ( ClientError :: unsupported_endpoint (
176+ endpoint,
177+ "missing closing bracket for IPv6 TCP host" ,
178+ ) ) ;
179+ } ;
180+ let Some ( port) = after_host. strip_prefix ( ':' ) else {
181+ return Err ( ClientError :: unsupported_endpoint (
182+ endpoint,
183+ "missing TCP port" ,
184+ ) ) ;
185+ } ;
186+ ( host, port)
187+ } else {
188+ if target. matches ( ':' ) . count ( ) > 1 {
189+ return Err ( ClientError :: unsupported_endpoint (
190+ endpoint,
191+ "IPv6 TCP hosts must be bracketed, e.g. tcp://[::1]:7001" ,
192+ ) ) ;
193+ }
194+ let Some ( ( host, port) ) = target. split_once ( ':' ) else {
195+ return Err ( ClientError :: unsupported_endpoint (
196+ endpoint,
197+ "missing TCP port" ,
198+ ) ) ;
199+ } ;
200+ if host. contains ( [ '[' , ']' ] ) {
201+ return Err ( ClientError :: unsupported_endpoint (
202+ endpoint,
203+ "malformed TCP host" ,
204+ ) ) ;
205+ }
206+ ( host, port)
178207 } ;
208+
179209 if host. is_empty ( ) {
180210 return Err ( ClientError :: unsupported_endpoint (
181211 endpoint,
@@ -268,6 +298,14 @@ mod tests {
268298 let p = parse_endpoint ( "tcp://localhost:7001" ) . expect ( "parse" ) ;
269299 assert_eq ! ( p. scheme, Scheme :: Tcp ) ;
270300 assert_eq ! ( p. target, "localhost:7001" ) ;
301+
302+ let p = parse_endpoint ( "tcp://[::1]:7001" ) . expect ( "parse" ) ;
303+ assert_eq ! ( p. scheme, Scheme :: Tcp ) ;
304+ assert_eq ! ( p. target, "[::1]:7001" ) ;
305+
306+ let p = parse_endpoint ( "tcp://[fe80::1]:7001" ) . expect ( "parse" ) ;
307+ assert_eq ! ( p. scheme, Scheme :: Tcp ) ;
308+ assert_eq ! ( p. target, "[fe80::1]:7001" ) ;
271309 }
272310
273311 #[ test]
@@ -277,6 +315,10 @@ mod tests {
277315 assert ! ( parse_endpoint( "tcp://host" ) . is_err( ) ) ;
278316 assert ! ( parse_endpoint( "tcp://:1234" ) . is_err( ) ) ;
279317 assert ! ( parse_endpoint( "tcp://host:fast" ) . is_err( ) ) ;
318+ assert ! ( parse_endpoint( "tcp://fe80::1" ) . is_err( ) ) ;
319+ assert ! ( parse_endpoint( "tcp://[fe80::1]" ) . is_err( ) ) ;
320+ assert ! ( parse_endpoint( "tcp://[]:7001" ) . is_err( ) ) ;
321+ assert ! ( parse_endpoint( "tcp://[fe80::1:7001" ) . is_err( ) ) ;
280322 // Empty + empty target.
281323 assert ! ( parse_endpoint( "" ) . is_err( ) ) ;
282324 assert ! ( parse_endpoint( "unix://" ) . is_err( ) ) ;
0 commit comments