@@ -8,6 +8,7 @@ use rust_i18n::t;
88use serde_json:: Value ;
99use super :: Function ;
1010use url:: Url ;
11+ use std:: net:: Ipv6Addr ;
1112
1213#[ derive( Debug , Default ) ]
1314pub struct Uri { }
@@ -48,19 +49,24 @@ impl Function for Uri {
4849 return Err ( DscError :: Parser ( t ! ( "functions.uri.invalidRelativeUri" ) . to_string ( ) ) ) ;
4950 }
5051
51- if let Some ( uri_without_slashes) = relative_uri. strip_prefix ( "//" ) {
52- let scheme = base. scheme ( ) ;
53-
54- if uri_without_slashes. contains ( '/' ) {
55- return Ok ( Value :: String ( format ! ( "{scheme}:{relative_uri}" ) ) ) ;
56- }
57- return Ok ( Value :: String ( format ! ( "{scheme}:{relative_uri}/" ) ) ) ;
58- }
59-
6052 let result = base. join ( relative_uri)
6153 . map_err ( |e| DscError :: Parser ( format ! ( "{}: {}" , t!( "functions.uri.invalidRelativeUri" ) , e) ) ) ?;
6254
63- Ok ( Value :: String ( result. to_string ( ) ) )
55+ let final_result = if let Some ( url:: Host :: Ipv6 ( ipv6_addr) ) = result. host ( ) {
56+ let segments = ipv6_addr. segments ( ) ;
57+ let expanded = format ! ( "{:04X}:{:04X}:{:04X}:{:04X}:{:04X}:{:04X}:{:04X}:{:04X}" ,
58+ segments[ 0 ] , segments[ 1 ] , segments[ 2 ] , segments[ 3 ] ,
59+ segments[ 4 ] , segments[ 5 ] , segments[ 6 ] , segments[ 7 ]
60+ ) ;
61+
62+ let addr = Ipv6Addr :: from ( segments) ;
63+ let compressed = addr. to_string ( ) ;
64+ result. to_string ( ) . replace ( & compressed, & expanded)
65+ } else {
66+ result. to_string ( )
67+ } ;
68+
69+ Ok ( Value :: String ( final_result) )
6470 }
6571}
6672
@@ -217,4 +223,34 @@ mod tests {
217223 let result = parser. parse_and_execute ( "[uri('https://example.com/', '//foo/bar')]" , & Context :: new ( ) ) . unwrap ( ) ;
218224 assert_eq ! ( result, "https://foo/bar" ) ;
219225 }
226+
227+ #[ test]
228+ fn test_uri_ipv6_localhost ( ) {
229+ let mut parser = Statement :: new ( ) . unwrap ( ) ;
230+ let result = parser. parse_and_execute ( "[uri('https://[::1]/', 'path')]" , & Context :: new ( ) ) . unwrap ( ) ;
231+ // IPv6 should be expanded to match .NET behavior
232+ assert_eq ! ( result, "https://[0000:0000:0000:0000:0000:0000:0000:0001]/path" ) ;
233+ }
234+
235+ #[ test]
236+ fn test_uri_ipv6_address ( ) {
237+ let mut parser = Statement :: new ( ) . unwrap ( ) ;
238+ let result = parser. parse_and_execute ( "[uri('https://[2001:db8::1]/', 'api/v1')]" , & Context :: new ( ) ) . unwrap ( ) ;
239+ // IPv6 should be expanded to match .NET behavior
240+ assert_eq ! ( result, "https://[2001:0DB8:0000:0000:0000:0000:0000:0001]/api/v1" ) ;
241+ }
242+
243+ #[ test]
244+ fn test_uri_ipv6_with_port ( ) {
245+ let mut parser = Statement :: new ( ) . unwrap ( ) ;
246+ let result = parser. parse_and_execute ( "[uri('https://[2001:db8::1]:8080/', 'api')]" , & Context :: new ( ) ) . unwrap ( ) ;
247+ assert_eq ! ( result, "https://[2001:0DB8:0000:0000:0000:0000:0000:0001]:8080/api" ) ;
248+ }
249+
250+ #[ test]
251+ fn test_uri_ipv4_address ( ) {
252+ let mut parser = Statement :: new ( ) . unwrap ( ) ;
253+ let result = parser. parse_and_execute ( "[uri('http://192.168.1.1/', 'api/v1')]" , & Context :: new ( ) ) . unwrap ( ) ;
254+ assert_eq ! ( result, "http://192.168.1.1/api/v1" ) ;
255+ }
220256}
0 commit comments