From f5e7f2058f9165bb7400d10c3f0da07e0d616d40 Mon Sep 17 00:00:00 2001 From: Sahand Date: Tue, 5 Nov 2024 16:20:40 +0330 Subject: [PATCH] perf(ext/fetch): use `trust_dns_resolver` instead of default `GaiResolver` --- Cargo.lock | 1 + Cargo.toml | 1 + ext/fetch/Cargo.toml | 1 + ext/fetch/dns.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++ ext/fetch/lib.rs | 10 ++++-- ext/net/Cargo.toml | 2 +- 6 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 ext/fetch/dns.rs diff --git a/Cargo.lock b/Cargo.lock index 29fe91641d57df..97aa4230769532 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1560,6 +1560,7 @@ dependencies = [ "tower", "tower-http", "tower-service", + "trust-dns-resolver", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 28ef2829e0f55f..365d1fb1ef2786 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -196,6 +196,7 @@ tower = { version = "0.4.13", default-features = false, features = ["util"] } tower-http = { version = "0.6.1", features = ["decompression-br", "decompression-gzip"] } tower-lsp = { package = "deno_tower_lsp", version = "0.1.0", features = ["proposed"] } tower-service = "0.3.2" +trust-dns-resolver = { version = "0.23", features = ["tokio-runtime", "serde-config"] } twox-hash = "=1.6.3" # Upgrading past 2.4.1 may cause WPT failures url = { version = "< 2.5.0", features = ["serde", "expose_internals"] } diff --git a/ext/fetch/Cargo.toml b/ext/fetch/Cargo.toml index 93fc88ae6435b0..be0df71551dd44 100644 --- a/ext/fetch/Cargo.toml +++ b/ext/fetch/Cargo.toml @@ -40,6 +40,7 @@ tokio-util = { workspace = true, features = ["io"] } tower.workspace = true tower-http.workspace = true tower-service.workspace = true +trust-dns-resolver.workspace = true [dev-dependencies] fast-socks5.workspace = true diff --git a/ext/fetch/dns.rs b/ext/fetch/dns.rs new file mode 100644 index 00000000000000..309784b2ee6734 --- /dev/null +++ b/ext/fetch/dns.rs @@ -0,0 +1,82 @@ +use std::future::Future; +use std::io; +use std::net::SocketAddr; +use std::pin::Pin; +use std::task::Poll; +use std::task::{self}; +use std::vec; + +use hyper_util::client::legacy::connect::dns::Name; +use tokio::task::JoinHandle; +use tower::Service; +use trust_dns_resolver::error::ResolveError; +use trust_dns_resolver::name_server::GenericConnector; +use trust_dns_resolver::name_server::TokioRuntimeProvider; +use trust_dns_resolver::AsyncResolver; + +#[derive(Clone)] +pub struct TrustResolver { + resolver: AsyncResolver>, +} + +impl TrustResolver { + pub fn new() -> Result { + Ok(Self { + resolver: trust_dns_resolver::AsyncResolver::tokio_from_system_conf()?, + }) + } +} + +type SocketAddrs = vec::IntoIter; + +pub struct AltResolverFut { + inner: JoinHandle>, +} + +impl Future for AltResolverFut { + type Output = Result; + + fn poll( + mut self: Pin<&mut Self>, + cx: &mut task::Context<'_>, + ) -> Poll { + Pin::new(&mut self.inner).poll(cx).map(|res| match res { + Ok(Ok(addrs)) => Ok(addrs), + Ok(Err(e)) => Err(e.into()), + Err(join_err) => { + if join_err.is_cancelled() { + Err(io::Error::new(io::ErrorKind::Interrupted, join_err)) + } else { + panic!("gai background task failed: {:?}", join_err) + } + } + }) + } +} + +impl Service for TrustResolver { + type Response = SocketAddrs; + type Error = io::Error; + type Future = AltResolverFut; + + fn poll_ready( + &mut self, + _cx: &mut task::Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, name: Name) -> Self::Future { + let resolver = self.resolver.clone(); + let task = tokio::spawn(async move { + let result = resolver.lookup_ip(name.as_str()).await?; + + let x: Vec<_> = + result.into_iter().map(|x| SocketAddr::new(x, 0)).collect(); + let iter: SocketAddrs = x.into_iter(); + Ok(iter) + }); + + AltResolverFut { inner: task } + } +} diff --git a/ext/fetch/lib.rs b/ext/fetch/lib.rs index 7ef26431c2b091..83147694a48a4f 100644 --- a/ext/fetch/lib.rs +++ b/ext/fetch/lib.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +mod dns; mod fs_fetch_handler; mod proxy; #[cfg(test)] @@ -78,6 +79,7 @@ pub use data_url; pub use proxy::basic_auth; pub use fs_fetch_handler::FsFetchHandler; +use trust_dns_resolver::error::ResolveError; #[derive(Clone)] pub struct Options { @@ -943,6 +945,8 @@ pub enum HttpClientCreateError { InvalidProxyUrl, #[error("Cannot create Http Client: either `http1` or `http2` needs to be set to true")] HttpVersionSelectionInvalid, + #[error("Cannot initialize trust dns resolver")] + Resolver(ResolveError), #[error(transparent)] RootCertStore(deno_core::error::AnyError), } @@ -976,7 +980,9 @@ pub fn create_http_client( tls_config.alpn_protocols = alpn_protocols; let tls_config = Arc::from(tls_config); - let mut http_connector = HttpConnector::new(); + let mut http_connector = HttpConnector::new_with_resolver( + dns::TrustResolver::new().map_err(HttpClientCreateError::Resolver)?, + ); http_connector.enforce_http(false); let user_agent = user_agent.parse::().map_err(|_| { @@ -1051,7 +1057,7 @@ pub struct Client { user_agent: HeaderValue, } -type Connector = proxy::ProxyConnector; +type Connector = proxy::ProxyConnector>; // clippy is wrong here #[allow(clippy::declare_interior_mutable_const)] diff --git a/ext/net/Cargo.toml b/ext/net/Cargo.toml index 5ffd1b45047b4f..cdaf3b5d0f86a8 100644 --- a/ext/net/Cargo.toml +++ b/ext/net/Cargo.toml @@ -24,4 +24,4 @@ socket2.workspace = true thiserror.workspace = true tokio.workspace = true trust-dns-proto = "0.23" -trust-dns-resolver = { version = "0.23", features = ["tokio-runtime", "serde-config"] } +trust-dns-resolver.workspace = true