1 // Copyright (c) 2025 Huawei Device Co., Ltd. 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 use std::io; 15 use std::net::{SocketAddr, ToSocketAddrs}; 16 use std::time::{Duration, Instant}; 17 18 use crate::async_impl::dns::resolver::{DefaultDnsFuture, DnsManager, DnsResult, ResolvedAddrs}; 19 use crate::async_impl::{Resolver, SocketFuture}; 20 21 /// Default dns resolver used by the `Client`. 22 /// DefaultDnsResolver provides DNS resolver with caching mechanism. 23 /// 24 /// # Examples 25 /// 26 /// ``` 27 /// use ylong_http_client::async_impl::{Client, DefaultDnsResolver}; 28 /// 29 /// let default_resolver = DefaultDnsResolver::new(); 30 /// let _client = Client::builder() 31 /// .dns_resolver(default_resolver) 32 /// .build() 33 /// .unwrap(); 34 /// ``` 35 pub struct DefaultDnsResolver { 36 /// Use global if None. 37 manager: Option<DnsManager>, 38 connector: DefaultDnsConnector, 39 } 40 41 impl Default for DefaultDnsResolver { 42 // Default constructor for `DefaultDnsResolver`, with a default TTL of 60 43 // seconds. default() -> Self44 fn default() -> Self { 45 DefaultDnsResolver { 46 manager: Some(DnsManager::default()), 47 connector: DefaultDnsConnector {}, 48 } 49 } 50 } 51 52 impl DefaultDnsResolver { 53 /// Creates a new DefaultDnsResolver. 54 /// 55 /// # Examples 56 /// 57 /// ``` 58 /// use ylong_http_client::async_impl::DefaultDnsResolver; 59 /// 60 /// let res = DefaultDnsResolver::new(); 61 /// ``` new() -> Self62 pub fn new() -> Self { 63 DefaultDnsResolver { 64 manager: Some(DnsManager::default()), 65 connector: DefaultDnsConnector {}, 66 } 67 } 68 69 /// Sets whether to use global DNS cache, default is false. 70 /// 71 /// # Examples 72 /// 73 /// ``` 74 /// use ylong_http_client::async_impl::DefaultDnsResolver; 75 /// 76 /// let res = DefaultDnsResolver::new().global_dns_cache(true); 77 /// ``` global_dns_cache(mut self, use_global: bool) -> Self78 pub fn global_dns_cache(mut self, use_global: bool) -> Self { 79 self.manager = (!use_global).then(DnsManager::default); 80 self 81 } 82 83 /// Sets DNS ttl, default is 60 second. 84 /// 85 /// This will does nothing if `global_dns_cache` is set to true. 86 /// 87 /// # Examples 88 /// 89 /// ``` 90 /// use std::time::Duration; 91 /// 92 /// use ylong_http_client::async_impl::DefaultDnsResolver; 93 /// 94 /// let res = DefaultDnsResolver::new().set_ttl(Duration::from_secs(30)); 95 /// ``` set_ttl(mut self, ttl: Duration) -> Self96 pub fn set_ttl(mut self, ttl: Duration) -> Self { 97 if let Some(manager) = self.manager.as_mut() { 98 manager.ttl = ttl 99 } 100 self 101 } 102 } 103 104 #[derive(Clone)] 105 struct DefaultDnsConnector {} 106 107 impl DefaultDnsConnector { 108 // Resolves the authority to a list of socket addresses get_socket_addrs(&self, authority: &str) -> Result<Vec<SocketAddr>, io::Error>109 fn get_socket_addrs(&self, authority: &str) -> Result<Vec<SocketAddr>, io::Error> { 110 authority 111 .to_socket_addrs() 112 .map(|addrs| addrs.collect()) 113 .map_err(|err| io::Error::new(io::ErrorKind::Other, err)) 114 } 115 } 116 117 impl Resolver for DefaultDnsResolver { resolve(&self, authority: &str) -> SocketFuture118 fn resolve(&self, authority: &str) -> SocketFuture { 119 let authority = authority.to_string(); 120 let (map, ttl) = match &self.manager { 121 None => { 122 let manager = DnsManager::global_dns_manager(); 123 let manager_guard = manager.lock().unwrap(); 124 manager_guard.clean_expired_entries(); 125 (manager_guard.map.clone(), manager_guard.ttl) 126 } 127 Some(manager) => { 128 manager.clean_expired_entries(); 129 (manager.map.clone(), manager.ttl) 130 } 131 }; 132 let connector = self.connector.clone(); 133 134 let handle = crate::runtime::spawn_blocking(move || { 135 let mut map_lock = map.lock().unwrap(); 136 if let Some(addrs) = map_lock.get(&authority) { 137 if addrs.is_valid() { 138 return Ok(ResolvedAddrs::new(addrs.addr.clone().into_iter())); 139 } 140 } 141 match connector.get_socket_addrs(&authority) { 142 Ok(addrs) => { 143 let dns_result = DnsResult::new(addrs.clone(), Instant::now() + ttl); 144 map_lock.insert(authority, dns_result); 145 Ok(ResolvedAddrs::new(addrs.into_iter())) 146 } 147 Err(err) => Err(io::Error::new(io::ErrorKind::Other, err)), 148 } 149 }); 150 Box::pin(DefaultDnsFuture::new(handle)) 151 } 152 } 153 154 #[cfg(test)] 155 mod ut_dns_test { 156 use super::*; 157 158 /// UT test case for `DefaultDnsResolver::global_dns_cache()` 159 /// 160 /// # Brief 161 /// 1. Creates a new `DefaultDnsResolver` instance. 162 /// 2. Verifies the default `manager` is None. 163 /// 3. Calls `global_dns_cache` and check manager. 164 #[test] ut_dns_resolver_global()165 fn ut_dns_resolver_global() { 166 let mut resolver = DefaultDnsResolver::new(); 167 assert!(resolver.manager.is_some()); 168 resolver = resolver.global_dns_cache(true); 169 assert!(resolver.manager.is_none()); 170 resolver = resolver.global_dns_cache(false); 171 assert!(resolver.manager.is_some()); 172 } 173 174 /// UT test case for `DefaultDnsResolver::set_ttl()` 175 /// 176 /// # Brief 177 /// 1. Creates a new `DefaultDnsResolver` instance. 178 /// 2. Verifies the default `ttl` is 60 second. 179 /// 3. Calls `set_ttl` and check ttl. 180 #[test] ut_dns_resolver_ttl()181 fn ut_dns_resolver_ttl() { 182 let mut resolver = DefaultDnsResolver::new(); 183 assert!(resolver.manager.is_some()); 184 assert_eq!( 185 resolver.manager.as_ref().unwrap().ttl, 186 Duration::from_secs(60) 187 ); 188 resolver = resolver.set_ttl(Duration::from_secs(30)); 189 assert_eq!( 190 resolver.manager.as_ref().unwrap().ttl, 191 Duration::from_secs(30) 192 ); 193 } 194 195 /// UT test case for `DefaultDnsResolver::resolve` 196 /// 197 /// # Brief 198 /// 1. Creates a default dns resolver with 50ms ttl. 199 /// 2. Calls resolve to get socket address twice. 200 /// 3. Verifies the second resolver is faster than the first one. 201 /// 4. Verifies the second resolver result as same as the first one. 202 #[tokio::test] 203 #[cfg(feature = "tokio_base")] ut_defualt_dns_resolver_resolve()204 async fn ut_defualt_dns_resolver_resolve() { 205 let authority = "example.com:0"; 206 let resolver = DefaultDnsResolver::new().set_ttl(Duration::from_secs(50)); 207 let start1 = Instant::now(); 208 let addrs1 = resolver.resolve(authority).await; 209 let duration1 = start1.elapsed(); 210 assert!(addrs1.is_ok()); 211 tokio::time::sleep(Duration::from_millis(10)).await; 212 let start2 = Instant::now(); 213 let addrs2 = resolver.resolve(authority).await; 214 let duration2 = start2.elapsed(); 215 assert!(duration1 > duration2); 216 assert!(addrs2.is_ok()); 217 if let (Ok(addr1), Ok(addr2)) = (addrs1, addrs2) { 218 let vec1: Vec<SocketAddr> = addr1.collect(); 219 let vec2: Vec<SocketAddr> = addr2.collect(); 220 assert_eq!(vec1, vec2); 221 } 222 } 223 } 224