Skip to content

Commit

Permalink
perf(ext/fetch): use trust_dns_resolver instead of default `GaiReso…
Browse files Browse the repository at this point in the history
…lver`
  • Loading branch information
sahandevs committed Nov 6, 2024
1 parent 770ef14 commit d806f7a
Show file tree
Hide file tree
Showing 11 changed files with 145 additions and 3 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down
2 changes: 2 additions & 0 deletions cli/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ impl CliMainWorkerFactory {
npm_process_state_provider: Some(shared.npm_process_state_provider()),
blob_store: shared.blob_store.clone(),
broadcast_channel: shared.broadcast_channel.clone(),
fetch_resolver: Default::default(),
shared_array_buffer_store: Some(shared.shared_array_buffer_store.clone()),
compiled_wasm_module_store: Some(
shared.compiled_wasm_module_store.clone(),
Expand Down Expand Up @@ -834,6 +835,7 @@ mod tests {
node_services: Default::default(),
npm_process_state_provider: Default::default(),
root_cert_store_provider: Default::default(),
fetch_resolver: Default::default(),
shared_array_buffer_store: Default::default(),
compiled_wasm_module_store: Default::default(),
v8_code_cache: Default::default(),
Expand Down
1 change: 1 addition & 0 deletions ext/fetch/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
116 changes: 116 additions & 0 deletions ext/fetch/dns.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
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::GaiResolver;
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, Debug)]
pub enum Resolver {
/// A resolver using blocking `getaddrinfo` calls in a threadpool.
Gai(GaiResolver),
/// trust_dns_resolver userspace resolver.
Trust(AsyncResolver<GenericConnector<TokioRuntimeProvider>>),
}

impl Default for Resolver {
fn default() -> Self {
Self::gai()
}
}

impl Resolver {
pub fn gai() -> Self {
Self::Gai(GaiResolver::new())
}

/// Create a [`AsyncResolver`] from system conf.
pub fn trust() -> Result<Self, ResolveError> {
Ok(Self::Trust(
trust_dns_resolver::AsyncResolver::tokio_from_system_conf()?,
))
}

pub fn trust_from_async_resolver(
resolver: AsyncResolver<GenericConnector<TokioRuntimeProvider>>,
) -> Self {
Self::Trust(resolver)
}
}

type SocketAddrs = vec::IntoIter<SocketAddr>;

pub struct ResolveFut {
inner: JoinHandle<Result<SocketAddrs, io::Error>>,
}

impl Future for ResolveFut {
type Output = Result<SocketAddrs, io::Error>;

fn poll(
mut self: Pin<&mut Self>,
cx: &mut task::Context<'_>,
) -> Poll<Self::Output> {
Pin::new(&mut self.inner).poll(cx).map(|res| match res {
Ok(Ok(addrs)) => Ok(addrs),
Ok(Err(e)) => Err(e),
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<Name> for Resolver {
type Response = SocketAddrs;
type Error = io::Error;
type Future = ResolveFut;

fn poll_ready(
&mut self,
_cx: &mut task::Context<'_>,
) -> Poll<Result<(), io::Error>> {
Poll::Ready(Ok(()))
}

fn call(&mut self, name: Name) -> Self::Future {
let task = match self {
Resolver::Gai(gai_resolver) => {
let mut resolver = gai_resolver.clone();
tokio::spawn(async move {
let result = resolver.call(name).await?;
let x: Vec<_> = result.into_iter().collect();
let iter: SocketAddrs = x.into_iter();
Ok(iter)
})
}
Resolver::Trust(async_resolver) => {
let resolver = async_resolver.clone();
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)
})
}
};
ResolveFut { inner: task }
}
}
20 changes: 18 additions & 2 deletions ext/fetch/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

pub mod dns;
mod fs_fetch_handler;
mod proxy;
#[cfg(test)]
Expand Down Expand Up @@ -91,6 +92,7 @@ pub struct Options {
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
pub client_cert_chain_and_key: TlsKeys,
pub file_fetch_handler: Rc<dyn FetchHandler>,
pub resolver: dns::Resolver,
}

impl Options {
Expand All @@ -114,6 +116,7 @@ impl Default for Options {
unsafely_ignore_certificate_errors: None,
client_cert_chain_and_key: TlsKeys::Null,
file_fetch_handler: Rc::new(DefaultFileFetchHandler),
resolver: dns::Resolver::default(),
}
}
}
Expand Down Expand Up @@ -255,6 +258,7 @@ pub fn create_client_from_options(
.map_err(HttpClientCreateError::RootCertStore)?,
ca_certs: vec![],
proxy: options.proxy.clone(),
resolver: options.resolver.clone(),
unsafely_ignore_certificate_errors: options
.unsafely_ignore_certificate_errors
.clone(),
Expand Down Expand Up @@ -835,6 +839,8 @@ pub struct CreateHttpClientArgs {
proxy: Option<Proxy>,
pool_max_idle_per_host: Option<usize>,
pool_idle_timeout: Option<serde_json::Value>,
#[serde(default)]
use_trust_resolver: bool,
#[serde(default = "default_true")]
http1: bool,
#[serde(default = "default_true")]
Expand Down Expand Up @@ -878,6 +884,13 @@ where
.map_err(HttpClientCreateError::RootCertStore)?,
ca_certs,
proxy: args.proxy,
resolver: if args.use_trust_resolver {
dns::Resolver::trust()
.map_err(deno_core::error::AnyError::new)
.map_err(FetchError::Resource)?
} else {
dns::Resolver::default()
},
unsafely_ignore_certificate_errors: options
.unsafely_ignore_certificate_errors
.clone(),
Expand Down Expand Up @@ -909,6 +922,7 @@ pub struct CreateHttpClientOptions {
pub root_cert_store: Option<RootCertStore>,
pub ca_certs: Vec<Vec<u8>>,
pub proxy: Option<Proxy>,
pub resolver: dns::Resolver,
pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
pub client_cert_chain_and_key: Option<TlsKey>,
pub pool_max_idle_per_host: Option<usize>,
Expand All @@ -923,6 +937,7 @@ impl Default for CreateHttpClientOptions {
root_cert_store: None,
ca_certs: vec![],
proxy: None,
resolver: dns::Resolver::default(),
unsafely_ignore_certificate_errors: None,
client_cert_chain_and_key: None,
pool_max_idle_per_host: None,
Expand Down Expand Up @@ -976,7 +991,8 @@ 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(options.resolver.clone());
http_connector.enforce_http(false);

let user_agent = user_agent.parse::<HeaderValue>().map_err(|_| {
Expand Down Expand Up @@ -1051,7 +1067,7 @@ pub struct Client {
user_agent: HeaderValue,
}

type Connector = proxy::ProxyConnector<HttpConnector>;
type Connector = proxy::ProxyConnector<HttpConnector<dns::Resolver>>;

// clippy is wrong here
#[allow(clippy::declare_interior_mutable_const)]
Expand Down
1 change: 1 addition & 0 deletions ext/fetch/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ async fn run_test_client(
client_cert_chain_and_key: None,
pool_max_idle_per_host: None,
pool_idle_timeout: None,
resolver: Default::default(),
http1: true,
http2: true,
},
Expand Down
1 change: 1 addition & 0 deletions ext/kv/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ impl<P: RemoteDbHandlerPermissions + 'static> DatabaseHandler
root_cert_store: options.root_cert_store()?,
ca_certs: vec![],
proxy: options.proxy.clone(),
resolver: Default::default(),
unsafely_ignore_certificate_errors: options
.unsafely_ignore_certificate_errors
.clone(),
Expand Down
2 changes: 1 addition & 1 deletion ext/net/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions runtime/examples/extension/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ async fn main() -> Result<(), AnyError> {
node_services: Default::default(),
npm_process_state_provider: Default::default(),
root_cert_store_provider: Default::default(),
fetch_resolver: Default::default(),
shared_array_buffer_store: Default::default(),
compiled_wasm_module_store: Default::default(),
v8_code_cache: Default::default(),
Expand Down
2 changes: 2 additions & 0 deletions runtime/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ pub struct WorkerServiceOptions {
pub npm_process_state_provider: Option<NpmProcessStateProviderRc>,
pub permissions: PermissionsContainer,
pub root_cert_store_provider: Option<Arc<dyn RootCertStoreProvider>>,
pub fetch_resolver: deno_fetch::dns::Resolver,

/// The store to use for transferring SharedArrayBuffers between isolates.
/// If multiple isolates should have the possibility of sharing
Expand Down Expand Up @@ -363,6 +364,7 @@ impl MainWorker {
.unsafely_ignore_certificate_errors
.clone(),
file_fetch_handler: Rc::new(deno_fetch::FsFetchHandler),
resolver: services.fetch_resolver,
..Default::default()
},
),
Expand Down

0 comments on commit d806f7a

Please sign in to comment.