Skip to content

Commit 81ed4f4

Browse files
committed
feat: allow for creation of Authority from SocketAddr
1 parent 1e78821 commit 81ed4f4

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

src/uri/authority.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::convert::TryFrom;
22
use std::hash::{Hash, Hasher};
33
use std::str::FromStr;
44
use std::{cmp, fmt, str};
5+
use std::net::{SocketAddr};
56

67
use 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)]
532576
mod 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

Comments
 (0)