Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions src/uri/authority.rs
Original file line number Diff line number Diff line change
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 @@ -68,6 +69,49 @@ impl 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");
Comment on lines +83 to +85
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example is not for the function.

/// ```
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 @@ -572,6 +616,7 @@ const fn validate_authority_bytes(s: &[u8]) -> Result<usize, AuthorityError> {
#[cfg(test)]
mod tests {
use super::*;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV6};

#[test]
fn parse_empty_string_is_error() {
Expand All @@ -587,6 +632,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 @@ -722,4 +775,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]");
}
}