• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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