isahc/config/
dns.rs

1//! Configuration of DNS resolution.
2
3use super::SetOpt;
4use curl::easy::Easy2;
5use std::{net::IpAddr, time::Duration};
6
7/// DNS caching configuration.
8///
9/// The default configuration is for caching to be enabled with a 60 second
10/// entry timeout.
11///
12/// See [`HttpClientBuilder::dns_cache`](crate::HttpClientBuilder::dns_cache)
13/// for configuring a client's DNS cache.
14#[derive(Clone, Debug)]
15pub enum DnsCache {
16    /// Disable DNS caching entirely.
17    Disable,
18
19    /// Enable DNS caching and keep entries in the cache for the given duration.
20    Timeout(Duration),
21
22    /// Enable DNS caching and cache entries forever.
23    Forever,
24}
25
26impl Default for DnsCache {
27    fn default() -> Self {
28        // Match curl's default.
29        Duration::from_secs(60).into()
30    }
31}
32
33impl From<Duration> for DnsCache {
34    fn from(duration: Duration) -> Self {
35        DnsCache::Timeout(duration)
36    }
37}
38
39impl SetOpt for DnsCache {
40    #[allow(unsafe_code)]
41    fn set_opt<H>(&self, easy: &mut Easy2<H>) -> Result<(), curl::Error> {
42        let value = match self {
43            DnsCache::Disable => 0,
44            DnsCache::Timeout(duration) => duration.as_secs() as i64,
45            DnsCache::Forever => -1,
46        };
47
48        // Use unsafe API, because safe API doesn't let us set to -1.
49        unsafe {
50            match curl_sys::curl_easy_setopt(easy.raw(), curl_sys::CURLOPT_DNS_CACHE_TIMEOUT, value)
51            {
52                curl_sys::CURLE_OK => Ok(()),
53                code => Err(curl::Error::new(code)),
54            }
55        }
56    }
57}
58
59/// A mapping of host and port pairs to IP addresses.
60///
61/// Entries added to this map can be used to override how DNS is resolved for a
62/// request and use specific IP addresses instead of using the default name
63/// resolver.
64#[derive(Clone, Debug, Default)]
65pub struct ResolveMap(Vec<String>);
66
67impl ResolveMap {
68    /// Create a new empty resolve map.
69    pub const fn new() -> Self {
70        ResolveMap(Vec::new())
71    }
72
73    /// Add a DNS mapping for a given host and port pair.
74    #[must_use = "builders have no effect if unused"]
75    pub fn add<H, A>(mut self, host: H, port: u16, addr: A) -> Self
76    where
77        H: AsRef<str>,
78        A: Into<IpAddr>,
79    {
80        self.0
81            .push(format!("{}:{}:{}", host.as_ref(), port, addr.into()));
82        self
83    }
84}
85
86impl SetOpt for ResolveMap {
87    fn set_opt<H>(&self, easy: &mut curl::easy::Easy2<H>) -> Result<(), curl::Error> {
88        let mut list = curl::easy::List::new();
89
90        for entry in self.0.iter() {
91            list.append(entry)?;
92        }
93
94        easy.resolve(list)
95    }
96}