@@ -2,6 +2,7 @@ use std::convert::TryFrom;
2
2
use std:: hash:: { Hash , Hasher } ;
3
3
use std:: str:: FromStr ;
4
4
use std:: { cmp, fmt, str} ;
5
+ use std:: net:: { SocketAddr } ;
5
6
6
7
use bytes:: Bytes ;
7
8
@@ -50,6 +51,50 @@ impl Authority {
50
51
. expect ( "static str is not valid authority" )
51
52
}
52
53
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 sa = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0);
67
+ /// let authority = Authority::from_sockaddr(sa);
68
+ /// assert_eq!(authority.host(), "localhost");
69
+ /// ```
70
+ pub fn from_sockaddr ( sa : SocketAddr ) -> Result < Self , InvalidUri > {
71
+ let x: ByteStr = match sa {
72
+ SocketAddr :: V4 ( v4) => {
73
+ if v4. port ( ) != 0 {
74
+ ( v4. ip ( ) . to_string ( ) + ":" + & v4. port ( ) . to_string ( ) ) . into ( )
75
+ } else {
76
+ v4. ip ( ) . to_string ( ) . into ( )
77
+ }
78
+ } ,
79
+ SocketAddr :: V6 ( v6) => {
80
+ let base = if v6. scope_id ( ) != 0 {
81
+ "[" . to_owned ( ) + & v6. ip ( ) . to_string ( ) + "%" + & v6. scope_id ( ) . to_string ( ) + "]"
82
+ } else {
83
+ "[" . to_owned ( ) + & v6. ip ( ) . to_string ( ) + "]"
84
+ } ;
85
+ if v6. port ( ) != 0 {
86
+ ( base + ":" + & v6. port ( ) . to_string ( ) ) . into ( )
87
+ } else {
88
+ base. into ( )
89
+ }
90
+ }
91
+ } ;
92
+
93
+ Ok ( Authority {
94
+ data : x
95
+ } )
96
+ }
97
+
53
98
/// Attempt to convert a `Bytes` buffer to a `Authority`.
54
99
///
55
100
/// This will try to prevent a copy if the type passed is the type used
@@ -531,6 +576,7 @@ where
531
576
#[ cfg( test) ]
532
577
mod tests {
533
578
use super :: * ;
579
+ use std:: net:: { IpAddr , Ipv4Addr , Ipv6Addr , SocketAddrV6 } ;
534
580
535
581
#[ test]
536
582
fn parse_empty_string_is_error ( ) {
@@ -689,4 +735,36 @@ mod tests {
689
735
let err = Authority :: parse_non_empty ( b"]o[" ) . unwrap_err ( ) ;
690
736
assert_eq ! ( err. 0 , ErrorKind :: InvalidAuthority ) ;
691
737
}
738
+
739
+ #[ test]
740
+ fn allows_from_simple_ipv4 ( ) {
741
+ let localhost8080 = SocketAddr :: new ( IpAddr :: V4 ( Ipv4Addr :: new ( 127 , 0 , 0 , 1 ) ) , 8080 ) ;
742
+
743
+ let auth1: Authority = Authority :: from_sockaddr ( localhost8080) . unwrap ( ) ;
744
+ assert_eq ! ( auth1. port( ) . unwrap( ) , 8080 ) ;
745
+ assert_eq ! ( auth1. host( ) , "127.0.0.1" ) ;
746
+ }
747
+
748
+ #[ test]
749
+ fn allows_from_simple_ipv6 ( ) {
750
+ let example8080 = SocketAddr :: new ( IpAddr :: V6 ( Ipv6Addr :: new ( 0x2001 , 0x0db8 , 0 , 0 ,
751
+ 0 , 0 , 0 , 1 ) ) , 8080 ) ;
752
+
753
+ let auth1: Authority = Authority :: from_sockaddr ( example8080) . unwrap ( ) ;
754
+ assert_eq ! ( auth1. port( ) . unwrap( ) , 8080 ) ;
755
+ assert_eq ! ( auth1. host( ) , "[2001:db8::1]" ) ;
756
+ }
757
+
758
+ #[ test]
759
+ fn allows_from_complex_ipv6 ( ) {
760
+ let example8080scope1 = SocketAddrV6 :: new ( Ipv6Addr :: new ( 0x2001 , 0x0db8 , 0 , 0 ,
761
+ 0 , 0 , 0 , 1 ) ,
762
+ 8080 , /* port number */
763
+ 0 , /* flowid */
764
+ 1 /* scopeid */ ) ;
765
+
766
+ let auth1: Authority = Authority :: from_sockaddr ( std:: net:: SocketAddr :: V6 ( example8080scope1) ) . unwrap ( ) ;
767
+ assert_eq ! ( auth1. port( ) . unwrap( ) , 8080 ) ;
768
+ assert_eq ! ( auth1. host( ) , "[2001:db8::1%1]" ) ;
769
+ }
692
770
}
0 commit comments