feat(client): add HttpConnector::set_local_addresses to set both IPv6 and IPv4 local addrs (#2172)
Currently HttpConnector::set_local_address method accepts a single argument. Server might not support IPv6 or IPv4. Therefore, the only solution at the moment is to manually perform DNS resolution and pick appropriate local address family. This is inefficient, as leads to 2 DNS lookups per request. This commit allows specifying both IPv4 and IPv6, so connector can decide which one to use based on DNS resolution results.
This commit is contained in:
@@ -200,27 +200,33 @@ impl IpAddrs {
|
||||
None
|
||||
}
|
||||
|
||||
pub(super) fn split_by_preference(self, local_addr: Option<IpAddr>) -> (IpAddrs, IpAddrs) {
|
||||
if let Some(local_addr) = local_addr {
|
||||
let preferred = self
|
||||
.iter
|
||||
.filter(|addr| addr.is_ipv6() == local_addr.is_ipv6())
|
||||
.collect();
|
||||
#[inline]
|
||||
fn filter(self, predicate: impl FnMut(&SocketAddr) -> bool) -> IpAddrs {
|
||||
IpAddrs::new(self.iter.filter(predicate).collect())
|
||||
}
|
||||
|
||||
(IpAddrs::new(preferred), IpAddrs::new(vec![]))
|
||||
} else {
|
||||
let preferring_v6 = self
|
||||
.iter
|
||||
.as_slice()
|
||||
.first()
|
||||
.map(SocketAddr::is_ipv6)
|
||||
.unwrap_or(false);
|
||||
pub(super) fn split_by_preference(
|
||||
self,
|
||||
local_addr_ipv4: Option<Ipv4Addr>,
|
||||
local_addr_ipv6: Option<Ipv6Addr>,
|
||||
) -> (IpAddrs, IpAddrs) {
|
||||
match (local_addr_ipv4, local_addr_ipv6) {
|
||||
(Some(_), None) => (self.filter(SocketAddr::is_ipv4), IpAddrs::new(vec![])),
|
||||
(None, Some(_)) => (self.filter(SocketAddr::is_ipv6), IpAddrs::new(vec![])),
|
||||
_ => {
|
||||
let preferring_v6 = self
|
||||
.iter
|
||||
.as_slice()
|
||||
.first()
|
||||
.map(SocketAddr::is_ipv6)
|
||||
.unwrap_or(false);
|
||||
|
||||
let (preferred, fallback) = self
|
||||
.iter
|
||||
.partition::<Vec<_>, _>(|addr| addr.is_ipv6() == preferring_v6);
|
||||
let (preferred, fallback) = self
|
||||
.iter
|
||||
.partition::<Vec<_>, _>(|addr| addr.is_ipv6() == preferring_v6);
|
||||
|
||||
(IpAddrs::new(preferred), IpAddrs::new(fallback))
|
||||
(IpAddrs::new(preferred), IpAddrs::new(fallback))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,34 +361,50 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_ip_addrs_split_by_preference() {
|
||||
let v4_addr = (Ipv4Addr::new(127, 0, 0, 1), 80).into();
|
||||
let v6_addr = (Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 80).into();
|
||||
let ip_v4 = Ipv4Addr::new(127, 0, 0, 1);
|
||||
let ip_v6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
|
||||
let v4_addr = (ip_v4, 80).into();
|
||||
let v6_addr = (ip_v6, 80).into();
|
||||
|
||||
let (mut preferred, mut fallback) = IpAddrs {
|
||||
iter: vec![v4_addr, v6_addr].into_iter(),
|
||||
}
|
||||
.split_by_preference(None);
|
||||
.split_by_preference(None, None);
|
||||
assert!(preferred.next().unwrap().is_ipv4());
|
||||
assert!(fallback.next().unwrap().is_ipv6());
|
||||
|
||||
let (mut preferred, mut fallback) = IpAddrs {
|
||||
iter: vec![v6_addr, v4_addr].into_iter(),
|
||||
}
|
||||
.split_by_preference(None);
|
||||
.split_by_preference(None, None);
|
||||
assert!(preferred.next().unwrap().is_ipv6());
|
||||
assert!(fallback.next().unwrap().is_ipv4());
|
||||
|
||||
let (mut preferred, mut fallback) = IpAddrs {
|
||||
iter: vec![v4_addr, v6_addr].into_iter(),
|
||||
}
|
||||
.split_by_preference(Some(ip_v4), Some(ip_v6));
|
||||
assert!(preferred.next().unwrap().is_ipv4());
|
||||
assert!(fallback.next().unwrap().is_ipv6());
|
||||
|
||||
let (mut preferred, mut fallback) = IpAddrs {
|
||||
iter: vec![v6_addr, v4_addr].into_iter(),
|
||||
}
|
||||
.split_by_preference(Some(ip_v4), Some(ip_v6));
|
||||
assert!(preferred.next().unwrap().is_ipv6());
|
||||
assert!(fallback.next().unwrap().is_ipv4());
|
||||
|
||||
let (mut preferred, fallback) = IpAddrs {
|
||||
iter: vec![v4_addr, v6_addr].into_iter(),
|
||||
}
|
||||
.split_by_preference(Some(v4_addr.ip()));
|
||||
.split_by_preference(Some(ip_v4), None);
|
||||
assert!(preferred.next().unwrap().is_ipv4());
|
||||
assert!(fallback.is_empty());
|
||||
|
||||
let (mut preferred, fallback) = IpAddrs {
|
||||
iter: vec![v4_addr, v6_addr].into_iter(),
|
||||
}
|
||||
.split_by_preference(Some(v6_addr.ip()));
|
||||
.split_by_preference(None, Some(ip_v6));
|
||||
assert!(preferred.next().unwrap().is_ipv6());
|
||||
assert!(fallback.is_empty());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user