@@ -2,6 +2,7 @@ use std::convert::TryFrom;
22use std:: hash:: { Hash , Hasher } ;
33use std:: str:: FromStr ;
44use std:: { cmp, fmt, str} ;
5+ use std:: net:: { SocketAddr } ;
56
67use bytes:: Bytes ;
78
@@ -50,6 +51,49 @@ impl Authority {
5051 . expect ( "static str is not valid authority" )
5152 }
5253
54+ /// Attempt to create an `Authority` from SockAddr
55+ ///
56+ /// This function will convert the IP address, scope and port number found
57+ /// in a SockAddr into an appropriately formatted URI authority.
58+ ///
59+ /// This includes formatting the IPv4 or IPv6 into a string, adding the scope for IPv6 addresses,
60+ /// enclosing it in [], and then adding any port number present.
61+ ///
62+ /// # Examples
63+ ///
64+ /// ```
65+ /// # use http::uri::Authority;
66+ /// let authority = Authority::from_static("example.com");
67+ /// assert_eq!(authority.host(), "example.com");
68+ /// ```
69+ pub fn from_sockaddr ( sa : SocketAddr ) -> Result < Self , InvalidUri > {
70+ let x: ByteStr = match sa {
71+ SocketAddr :: V4 ( v4) => {
72+ if v4. port ( ) != 0 {
73+ ( v4. ip ( ) . to_string ( ) + ":" + & v4. port ( ) . to_string ( ) ) . into ( )
74+ } else {
75+ v4. ip ( ) . to_string ( ) . into ( )
76+ }
77+ } ,
78+ SocketAddr :: V6 ( v6) => {
79+ let base = if v6. scope_id ( ) != 0 {
80+ "[" . to_owned ( ) + & v6. ip ( ) . to_string ( ) + "%" + & v6. scope_id ( ) . to_string ( ) + "]"
81+ } else {
82+ "[" . to_owned ( ) + & v6. ip ( ) . to_string ( ) + "]"
83+ } ;
84+ if v6. port ( ) != 0 {
85+ ( base + ":" + & v6. port ( ) . to_string ( ) ) . into ( )
86+ } else {
87+ base. into ( )
88+ }
89+ }
90+ } ;
91+
92+ Ok ( Authority {
93+ data : x
94+ } )
95+ }
96+
5397 /// Attempt to convert a `Bytes` buffer to a `Authority`.
5498 ///
5599 /// This will try to prevent a copy if the type passed is the type used
@@ -531,6 +575,7 @@ where
531575#[ cfg( test) ]
532576mod tests {
533577 use super :: * ;
578+ use std:: net:: { IpAddr , Ipv4Addr , Ipv6Addr , SocketAddrV6 } ;
534579
535580 #[ test]
536581 fn parse_empty_string_is_error ( ) {
@@ -689,4 +734,36 @@ mod tests {
689734 let err = Authority :: parse_non_empty ( b"]o[" ) . unwrap_err ( ) ;
690735 assert_eq ! ( err. 0 , ErrorKind :: InvalidAuthority ) ;
691736 }
737+
738+ #[ test]
739+ fn allows_from_simple_ipv4 ( ) {
740+ let localhost8080 = SocketAddr :: new ( IpAddr :: V4 ( Ipv4Addr :: new ( 127 , 0 , 0 , 1 ) ) , 8080 ) ;
741+
742+ let auth1: Authority = Authority :: from_sockaddr ( localhost8080) . unwrap ( ) ;
743+ assert_eq ! ( auth1. port( ) . unwrap( ) , 8080 ) ;
744+ assert_eq ! ( auth1. host( ) , "127.0.0.1" ) ;
745+ }
746+
747+ #[ test]
748+ fn allows_from_simple_ipv6 ( ) {
749+ let example8080 = SocketAddr :: new ( IpAddr :: V6 ( Ipv6Addr :: new ( 0x2001 , 0x0db8 , 0 , 0 ,
750+ 0 , 0 , 0 , 1 ) ) , 8080 ) ;
751+
752+ let auth1: Authority = Authority :: from_sockaddr ( example8080) . unwrap ( ) ;
753+ assert_eq ! ( auth1. port( ) . unwrap( ) , 8080 ) ;
754+ assert_eq ! ( auth1. host( ) , "[2001:db8::1]" ) ;
755+ }
756+
757+ #[ test]
758+ fn allows_from_complex_ipv6 ( ) {
759+ let example8080scope1 = SocketAddrV6 :: new ( Ipv6Addr :: new ( 0x2001 , 0x0db8 , 0 , 0 ,
760+ 0 , 0 , 0 , 1 ) ,
761+ 8080 , /* port number */
762+ 0 , /* flowid */
763+ 1 /* scopeid */ ) ;
764+
765+ let auth1: Authority = Authority :: from_sockaddr ( std:: net:: SocketAddr :: V6 ( example8080scope1) ) . unwrap ( ) ;
766+ assert_eq ! ( auth1. port( ) . unwrap( ) , 8080 ) ;
767+ assert_eq ! ( auth1. host( ) , "[2001:db8::1%1]" ) ;
768+ }
692769}
0 commit comments