Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sockaddr authority #624

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
107 changes: 107 additions & 0 deletions src/uri/authority.rs
Expand Up @@ -2,6 +2,7 @@ use std::convert::TryFrom;
use std::hash::{Hash, Hasher};
use std::str::FromStr;
use std::{cmp, fmt, str};
use std::net::{SocketAddr};

use bytes::Bytes;

Expand Down Expand Up @@ -50,6 +51,49 @@ impl Authority {
.expect("static str is not valid authority")
}

/// Attempt to create an `Authority` from SockAddr
///
/// This function will convert the IP address, scope and port number found
/// in a SockAddr into an appropriately formatted URI authority.
///
/// This includes formatting the IPv4 or IPv6 into a string, adding the scope for IPv6 addresses,
/// enclosing it in [], and then adding any port number present.
///
/// # Examples
///
/// ```
/// # use http::uri::Authority;
/// let authority = Authority::from_static("example.com");
/// assert_eq!(authority.host(), "example.com");
/// ```
pub fn from_sockaddr(sa: SocketAddr) -> Result<Self, InvalidUri> {
let x: ByteStr = match sa {
SocketAddr::V4(v4) => {
if v4.port() != 0 {
(v4.ip().to_string() + ":" + &v4.port().to_string()).into()
} else {
v4.ip().to_string().into()
}
},
SocketAddr::V6(v6) => {
let base = if v6.scope_id() != 0 {
"[".to_owned() + &v6.ip().to_string() + "%" + &v6.scope_id().to_string() + "]"
} else {
"[".to_owned() + &v6.ip().to_string() + "]"
};
if v6.port() != 0 {
(base + ":" + &v6.port().to_string()).into()
} else {
base.into()
}
}
};

Ok(Authority {
data: x
})
}

/// Attempt to convert a `Bytes` buffer to a `Authority`.
///
/// This will try to prevent a copy if the type passed is the type used
Expand Down Expand Up @@ -531,6 +575,7 @@ where
#[cfg(test)]
mod tests {
use super::*;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV6};

#[test]
fn parse_empty_string_is_error() {
Expand All @@ -546,6 +591,14 @@ mod tests {
assert_eq!(authority2, authority1);
}

#[test]
fn equal_to_self_of_same_authority_with_port() {
let authority1: Authority = "example.com:80".parse().unwrap();
let authority2: Authority = "EXAMPLE.COM:80".parse().unwrap();
assert_eq!(authority1, authority2);
assert_eq!(authority2, authority1);
}

#[test]
fn not_equal_to_self_of_different_authority() {
let authority1: Authority = "example.com".parse().unwrap();
Expand Down Expand Up @@ -681,4 +734,58 @@ mod tests {
let err = Authority::parse_non_empty(b"]o[").unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidAuthority);
}

#[test]
fn allows_from_simplest_ipv4() {
let localhost0 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0);

let auth1: Authority = Authority::from_sockaddr(localhost0).unwrap();
assert_eq!(auth1.port(), None);
assert_eq!(auth1.host(), "127.0.0.1");
}

#[test]
fn allows_from_simple_ipv4() {
let localhost8080 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);

let auth1: Authority = Authority::from_sockaddr(localhost8080).unwrap();
assert_eq!(auth1.port().unwrap(), 8080);
assert_eq!(auth1.host(), "127.0.0.1");
}

#[test]
fn allows_from_simple_ipv6() {
let example8080 = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0x2001, 0x0db8, 0,0,
0,0,0,1)), 8080);

let auth1: Authority = Authority::from_sockaddr(example8080).unwrap();
assert_eq!(auth1.port().unwrap(), 8080);
assert_eq!(auth1.host(), "[2001:db8::1]");
}

#[test]
fn allows_from_scoped_ipv6() {
let example0scope2 = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0x0db8, 0,0,
0,0,0,1),
0, /* port number */
0, /* flowid */
2 /* scopeid */);
let auth1: Authority = Authority::from_sockaddr(std::net::SocketAddr::V6(example0scope2)).unwrap();
assert_eq!(auth1.port(), None);
assert_eq!(auth1.host(), "[2001:db8::1%2]");

}

#[test]
fn allows_from_complex_ipv6() {
let example8080scope1 = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0x0db8, 0,0,
0,0,0,1),
8080, /* port number */
0, /* flowid */
1 /* scopeid */);

let auth1: Authority = Authority::from_sockaddr(std::net::SocketAddr::V6(example8080scope1)).unwrap();
assert_eq!(auth1.port().unwrap(), 8080);
assert_eq!(auth1.host(), "[2001:db8::1%1]");
}
}