From 9d4bc344736136fc404bbd4d46d62b0842268e87 Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Tue, 19 Jan 2021 12:00:18 +0800 Subject: [PATCH] rework awc dns resolver --- Cargo.toml | 2 + actix-http-test/src/lib.rs | 1 - actix-http/src/client/error.rs | 3 +- awc/CHANGES.md | 4 ++ awc/Cargo.toml | 7 +++ awc/src/connector.rs | 84 ++++++++++++++++++++++++++++++++++ awc/src/lib.rs | 5 +- awc/tests/test_client.rs | 4 +- 8 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 awc/src/connector.rs diff --git a/Cargo.toml b/Cargo.toml index bae6cb6cb..be08a3c39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -132,6 +132,8 @@ actix-multipart = { path = "actix-multipart" } actix-files = { path = "actix-files" } awc = { path = "awc" } +actix-tls = { git = "https://github.com/actix/actix-net", branch = "refactor/resolver" } + [[bench]] name = "server" harness = false diff --git a/actix-http-test/src/lib.rs b/actix-http-test/src/lib.rs index 4fd74d6eb..83164e454 100644 --- a/actix-http-test/src/lib.rs +++ b/actix-http-test/src/lib.rs @@ -106,7 +106,6 @@ pub async fn test_server_with_addr>( Client::builder().connector(connector).finish() }; - actix_tls::connect::start_default_resolver().await.unwrap(); TestServer { addr, diff --git a/actix-http/src/client/error.rs b/actix-http/src/client/error.rs index a5f1b2e8e..8d609f546 100644 --- a/actix-http/src/client/error.rs +++ b/actix-http/src/client/error.rs @@ -1,6 +1,5 @@ use std::io; -use actix_tls::connect::resolver::ResolveError; use derive_more::{Display, From}; #[cfg(feature = "openssl")] @@ -23,7 +22,7 @@ pub enum ConnectError { /// Failed to resolve the hostname #[display(fmt = "Failed resolving hostname: {}", _0)] - Resolver(ResolveError), + Resolver(Box), /// No dns records #[display(fmt = "No dns records found for the input")] diff --git a/awc/CHANGES.md b/awc/CHANGES.md index c5c1185be..1380f2f19 100644 --- a/awc/CHANGES.md +++ b/awc/CHANGES.md @@ -4,8 +4,12 @@ ### Added * `ClientRequest::insert_header` method which allows using typed headers. [#1869] * `ClientRequest::append_header` method which allows using typed headers. [#1869] +* `trust-dns` option feature to use it as default dns resolver. +* `connector::default_connector` function to get a default connector type + that uses current dns resolver feature. ### Removed +* `trust-dns` removed from default dns resolver * `ClientRequest::set`; use `ClientRequest::insert_header`. [#1869] * `ClientRequest::set_header`; use `ClientRequest::insert_header`. [#1869] * `ClientRequest::set_header_if_none`; use `ClientRequest::insert_header_if_none`. [#1869] diff --git a/awc/Cargo.toml b/awc/Cargo.toml index 90f33c9ba..920e24a34 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -36,12 +36,18 @@ rustls = ["rust-tls", "actix-http/rustls"] # content-encoding support compress = ["actix-http/compress"] +# trust-dns as dns resolver +trust-dns = ["trust-dns-resolver/tokio-runtime", "trust-dns-resolver/system-config"] + [dependencies] actix-codec = "0.4.0-beta.1" actix-service = "2.0.0-beta.3" actix-http = "3.0.0-beta.1" actix-rt = "2.0.0-beta.2" +# TODO: temporary import actix-tls to bypass some actix-http mods +actix-tls = { version = "3.0.0-beta.2", default-features = false, features = ["connect"] } + base64 = "0.13" bytes = "1" cfg-if = "1.0" @@ -56,6 +62,7 @@ serde_json = "1.0" serde_urlencoded = "0.7" open-ssl = { version = "0.10", package = "openssl", optional = true } rust-tls = { version = "0.19.0", package = "rustls", optional = true, features = ["dangerous_configuration"] } +trust-dns-resolver = { version = "0.20.0", default-features = false, optional = true } [dev-dependencies] # TODO: actix is temporary added as dev dep for actix-macro reason. diff --git a/awc/src/connector.rs b/awc/src/connector.rs new file mode 100644 index 000000000..b474ef1e1 --- /dev/null +++ b/awc/src/connector.rs @@ -0,0 +1,84 @@ +// TODO: this mod bypass actix-http and use actix_tls::connect directly. +// Future refactor should change this mod if actix-http still used as upstream dep of awc. + +pub(crate) use connector_impl::*; + +#[cfg(not(features = "trust-dns"))] +pub(crate) mod connector_impl { + pub(crate) use actix_tls::connect::default_connector; +} + +#[cfg(features = "trust-dns")] +pub(crate) mod connector_impl { + // resolver implementation using trust-dns crate. + use std::net::SocketAddr; + + use actix_rt::{net::TcpStream, Arbiter}; + use actix_service::ServiceFactory; + use actix_tls::connect::{Connect, ConnectError, Connection, Resolve, Resolver}; + use futures_core::future::LocalBoxFuture; + use trust_dns_resolver::{ + config::{ResolverConfig, ResolverOpts}, + system_conf::read_system_conf, + TokioAsyncResolver, + }; + + pub struct TrustDnsResolver { + resolver: TokioAsyncResolver, + } + + impl TrustDnsResolver { + fn new() -> Self { + // dns struct is cached in Arbiter thread local map. + // so new client constructor can reuse the dns resolver on local thread. + + if Arbiter::contains_item::() { + Arbiter::get_item(|item: &TokioAsyncResolver| TrustDnsResolver { + resolver: item.clone(), + }) + } else { + let (cfg, opts) = match read_system_conf() { + Ok((cfg, opts)) => (cfg, opts), + Err(e) => { + log::error!("TRust-DNS can not load system config: {}", e); + (ResolverConfig::default(), ResolverOpts::default()) + } + }; + + let resolver = TokioAsyncResolver::tokio(cfg, opts).unwrap(); + Arbiter::set_item(resolver.clone()); + resolver + } + } + } + + impl Resolve for TrustDnsResolver { + fn lookup<'a>( + &'a self, + host: &'a str, + port: u16, + ) -> LocalBoxFuture<'a, Result, Box>> + { + Box::pin(async move { + let res = self + .trust_dns + .lookup_ip(host) + .await? + .iter() + .map(|ip| SocketAddr::new(ip, port)) + .collect(); + Ok(res) + }) + } + } + + pub(crate) fn default_connector() -> impl ServiceFactory< + Connect, + Config = (), + Response = Connection, + Error = ConnectError, + InitError = (), + > + Clone { + actix_tls::connect::new_connector(Resolver::new_custom(TrustDnsResolver::new())) + } +} diff --git a/awc/src/lib.rs b/awc/src/lib.rs index f750a3df2..2035d69ab 100644 --- a/awc/src/lib.rs +++ b/awc/src/lib.rs @@ -105,6 +105,7 @@ use actix_http::RequestHead; mod builder; mod connect; +mod connector; pub mod error; mod frozen; mod request; @@ -154,7 +155,9 @@ impl Default for Client { fn default() -> Self { Client(Rc::new(ClientConfig { connector: RefCell::new(Box::new(ConnectorWrapper( - Connector::new().finish(), + Connector::new() + .connector(connector::default_connector()) + .finish(), ))), headers: HeaderMap::new(), timeout: Some(Duration::from_secs(5)), diff --git a/awc/tests/test_client.rs b/awc/tests/test_client.rs index 88987e639..23ecda173 100644 --- a/awc/tests/test_client.rs +++ b/awc/tests/test_client.rs @@ -120,9 +120,7 @@ async fn test_timeout() { }); let connector = awc::Connector::new() - .connector(actix_tls::connect::new_connector( - actix_tls::connect::start_default_resolver().await.unwrap(), - )) + .connector(actix_tls::connect::default_connector()) .timeout(Duration::from_secs(15)) .finish();