hyper_system_resolver/
system.rs1use std::{io, net::SocketAddr, vec};
4
5use dns_lookup::AddrInfoHints;
6use hyper_util::client::legacy::connect::dns::Name;
7use tokio::task::JoinHandle;
8
9use crate::background;
10
11#[derive(Debug, Default, Clone)]
17#[cfg_attr(feature = "builder", derive(derive_builder::Builder))]
18pub struct System {
19 pub addr_info_hints: Option<AddrInfoHints>,
26
27 pub service: Option<String>,
36}
37
38impl background::Resolve for System {
39 type Iter = vec::IntoIter<SocketAddr>;
40
41 fn resolve(&mut self, name: Name) -> JoinHandle<io::Result<Self::Iter>> {
42 let addr_info_hints = self.addr_info_hints;
43 let service = self.service.clone();
44 tokio::task::spawn_blocking(move || {
45 debug!("resolving host={:?} service={:?}", name, service);
46
47 let iter =
48 dns_lookup::getaddrinfo(Some(name.as_str()), service.as_deref(), addr_info_hints)?;
49 let list = iter
50 .map(|result| result.map(|addr_info| addr_info.sockaddr))
51 .collect::<Result<Vec<_>, _>>()?;
52 Ok(list.into_iter())
53 })
54 }
55}
56
57pub type Resolver = background::Resolver<System>;
59
60impl System {
61 pub fn resolver(self) -> Resolver {
63 Resolver::new(self)
64 }
65}
66
67impl From<System> for Resolver {
68 fn from(system: System) -> Self {
69 system.resolver()
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use std::{
76 net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6},
77 str::FromStr,
78 };
79
80 use tower_service::Service;
81
82 use super::*;
83
84 #[tokio::test]
85 async fn test_resolve_ipv4() {
86 let mut resolver = background::Resolver::new(System {
87 addr_info_hints: Some(AddrInfoHints {
88 address: dns_lookup::AddrFamily::Inet.into(),
89 ..Default::default()
90 }),
91 service: None,
92 });
93
94 let addrs: Vec<_> = resolver
95 .call(Name::from_str("localhost").unwrap())
96 .await
97 .unwrap()
98 .collect();
99
100 let localhost = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 0));
101
102 assert!(!addrs.is_empty());
103 for addr in addrs {
104 assert_eq!(addr, localhost);
105 }
106 }
107
108 #[tokio::test]
109 async fn test_resolve_ipv6() {
110 let mut resolver = background::Resolver::new(System {
111 addr_info_hints: Some(AddrInfoHints {
112 address: dns_lookup::AddrFamily::Inet6.into(),
113 ..Default::default()
114 }),
115 service: None,
116 });
117
118 let addrs: Vec<_> = resolver
119 .call(Name::from_str("localhost").unwrap())
120 .await
121 .unwrap()
122 .collect();
123
124 let localhost = SocketAddr::V6(SocketAddrV6::new(
125 Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1),
126 0,
127 0,
128 0,
129 ));
130
131 assert!(!addrs.is_empty());
132 for addr in addrs {
133 assert_eq!(addr, localhost);
134 }
135 }
136}