@@ -80,16 +80,38 @@ where
8080}
8181
8282fn parse_host_port ( target : & str ) -> Result < ( String , u16 ) > {
83- let parts: Vec < & str > = target. split ( ':' ) . collect ( ) ;
84- match parts. len ( ) {
85- 1 => Ok ( ( parts[ 0 ] . to_string ( ) , 443 ) ) ,
86- 2 => {
87- let port = parts[ 1 ]
83+ // IPv6
84+ if target. starts_with ( '[' ) {
85+ if let Some ( bracket_end) = target. find ( "]:" ) {
86+ let host = target[ 1 ..bracket_end] . to_string ( ) ;
87+ let port_str = & target[ bracket_end + 2 ..] ;
88+ let port = port_str
8889 . parse :: < u16 > ( )
89- . map_err ( |_| anyhow:: anyhow!( "Invalid port: {}" , parts[ 1 ] ) ) ?;
90- Ok ( ( parts[ 0 ] . to_string ( ) , port) )
90+ . map_err ( |_| anyhow:: anyhow!( "Invalid port: {}" , port_str) ) ?;
91+ return Ok ( ( host, port) ) ;
92+ } else if target. ends_with ( ']' ) {
93+ let host = target[ 1 ..target. len ( ) - 1 ] . to_string ( ) ;
94+ return Ok ( ( host, 443 ) ) ;
95+ } else {
96+ return Err ( anyhow:: anyhow!( "Invalid IPv6 format: {}" , target) ) ;
9197 }
92- _ => Err ( anyhow:: anyhow!( "Invalid target format: {}" , target) ) ,
98+ }
99+
100+ // IPv6 without port or IPv4 with port
101+ if let Some ( colon_pos) = target. rfind ( ':' ) {
102+ let colon_count = target. matches ( ':' ) . count ( ) ;
103+ if colon_count > 1 {
104+ return Ok ( ( target. to_string ( ) , 443 ) ) ;
105+ }
106+
107+ let host = target[ ..colon_pos] . to_string ( ) ;
108+ let port_str = & target[ colon_pos + 1 ..] ;
109+ let port = port_str
110+ . parse :: < u16 > ( )
111+ . map_err ( |_| anyhow:: anyhow!( "Invalid port: {}" , port_str) ) ?;
112+ Ok ( ( host, port) )
113+ } else {
114+ Ok ( ( target. to_string ( ) , 443 ) )
93115 }
94116}
95117
@@ -127,15 +149,9 @@ mod tests {
127149
128150 #[ test]
129151 fn test_parse_host_port_ipv6 ( ) {
130- // TODO: Fix this to support IPv6 addresses
131- let result = parse_host_port ( "[::1]:8080" ) ;
132- assert ! ( result. is_err( ) ) ;
133- assert ! (
134- result
135- . unwrap_err( )
136- . to_string( )
137- . contains( "Invalid target format" )
138- ) ;
152+ let result = parse_host_port ( "[::1]:8080" ) . unwrap ( ) ;
153+ assert_eq ! ( result. 0 , "::1" ) ;
154+ assert_eq ! ( result. 1 , 8080 ) ;
139155 }
140156
141157 #[ test]
@@ -153,14 +169,42 @@ mod tests {
153169 }
154170
155171 #[ test]
156- fn test_parse_host_port_too_many_colons ( ) {
157- let result = parse_host_port ( "example.com:8080:extra" ) ;
172+ fn test_parse_host_port_ipv6_with_brackets_and_port ( ) {
173+ let result = parse_host_port ( "[2001:db8::1]:8080" ) . unwrap ( ) ;
174+ assert_eq ! ( result. 0 , "2001:db8::1" ) ;
175+ assert_eq ! ( result. 1 , 8080 ) ;
176+ }
177+
178+ #[ test]
179+ fn test_parse_host_port_ipv6_with_brackets_no_port ( ) {
180+ let result = parse_host_port ( "[2001:db8::1]" ) . unwrap ( ) ;
181+ assert_eq ! ( result. 0 , "2001:db8::1" ) ;
182+ assert_eq ! ( result. 1 , 443 ) ;
183+ }
184+
185+ #[ test]
186+ fn test_parse_host_port_ipv6_without_brackets ( ) {
187+ let result = parse_host_port ( "2001:db8::1" ) . unwrap ( ) ;
188+ assert_eq ! ( result. 0 , "2001:db8::1" ) ;
189+ assert_eq ! ( result. 1 , 443 ) ;
190+ }
191+
192+ #[ test]
193+ fn test_parse_host_port_ipv6_localhost ( ) {
194+ let result = parse_host_port ( "[::1]:3000" ) . unwrap ( ) ;
195+ assert_eq ! ( result. 0 , "::1" ) ;
196+ assert_eq ! ( result. 1 , 3000 ) ;
197+ }
198+
199+ #[ test]
200+ fn test_parse_host_port_invalid_ipv6_brackets ( ) {
201+ let result = parse_host_port ( "[2001:db8::1:invalid" ) ;
158202 assert ! ( result. is_err( ) ) ;
159203 assert ! (
160204 result
161205 . unwrap_err( )
162206 . to_string( )
163- . contains( "Invalid target format" )
207+ . contains( "Invalid IPv6 format" )
164208 ) ;
165209 }
166210
0 commit comments