Skip to main content

pkarr_client/extra/
reqwest.rs

1//! implementation of Reqwest [Resolve] using Pkarr's [Endpoints](https://pkarr.org/endpoints) spec.
2//!
3
4use reqwest::dns::{Addrs, Resolve};
5
6use crate::{Client, PublicKey};
7
8use std::net::ToSocketAddrs;
9
10impl Resolve for Client {
11    fn resolve(&self, name: reqwest::dns::Name) -> reqwest::dns::Resolving {
12        let client = self.clone();
13        Box::pin(resolve(client, name))
14    }
15}
16
17async fn resolve(
18    client: Client,
19    name: reqwest::dns::Name,
20) -> Result<Addrs, Box<dyn std::error::Error + Send + Sync>> {
21    let name = name.as_str();
22
23    if PublicKey::try_from(name).is_ok() {
24        let endpoint = client
25            .resolve_https_endpoint(name)
26            .await
27            .map_err(|_| CouldNotResolveHost)?;
28
29        let addrs = endpoint.to_socket_addrs().into_iter();
30
31        tracing::trace!(?name, ?endpoint, ?addrs, "Resolved an endpoint");
32
33        return Ok(Box::new(addrs.into_iter()));
34    };
35
36    Ok(Box::new(format!("{name}:0").to_socket_addrs()?))
37}
38
39#[derive(Debug)]
40/// pkarr could not resolve host.
41pub struct CouldNotResolveHost;
42
43impl std::error::Error for CouldNotResolveHost {}
44
45impl std::fmt::Display for CouldNotResolveHost {
46    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47        write!(f, "pkarr could not resolve host")
48    }
49}
50
51#[cfg(feature = "reqwest-builder")]
52mod reqwest_builder {
53    impl From<crate::Client> for ::reqwest::ClientBuilder {
54        /// Create a [reqwest::ClientBuilder] from this Pkarr client,
55        /// using it as a [dns_resolver][::reqwest::ClientBuilder::dns_resolver],
56        /// and a [preconfigured_tls][::reqwest::ClientBuilder::use_preconfigured_tls] client
57        /// config that uses [rustls::crypto::ring::default_provider()] and follows the
58        /// [tls for pkarr domains](https://pkarr.org/tls) spec.
59        fn from(client: crate::Client) -> Self {
60            ::reqwest::ClientBuilder::new()
61                .dns_resolver(std::sync::Arc::new(client.clone()))
62                .use_preconfigured_tls(rustls::ClientConfig::from(client))
63        }
64    }
65}