From 519d7f2b8ab323b34071c8eedce03f89e4fde6d0 Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Tue, 9 Feb 2021 02:41:20 -0800 Subject: [PATCH] add trust-dns optional feature for actix-http and awc (#1969) --- Cargo.toml | 1 - actix-http/CHANGES.md | 4 ++ actix-http/Cargo.toml | 7 +-- actix-http/src/client/connector.rs | 84 ++++++++++++++++++++++++++++-- actix-http/src/error.rs | 6 --- awc/CHANGES.md | 2 + awc/Cargo.toml | 3 ++ src/test.rs | 6 ++- 8 files changed, 98 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 479a89f87..80187c8a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,7 +109,6 @@ smallvec = "1.6" [dev-dependencies] actix = { version = "0.11.0-beta.2", default-features = false } -actix-http = { version = "3.0.0-beta.1", features = ["actors"] } rand = "0.8" env_logger = "0.8" serde_derive = "1.0" diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md index 52980fb5d..ba8cc6e6d 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -7,6 +7,7 @@ * `ResponseBuilder::append_header` method which allows using typed headers. [#1869] * `TestRequest::insert_header` method which allows using typed headers. [#1869] * `ContentEncoding` implements all necessary header traits. [#1912] +* `trust-dns` optional feature to enable `trust-dns-resolver` as client dns resolver. [#1969] ### Changed * `ResponseBuilder::content_type` now takes an `impl IntoHeaderValue` to support using typed @@ -26,6 +27,8 @@ * `ResponseBuilder::header`; use `ResponseBuilder::append_header`. [#1869] * `TestRequest::with_hdr`; use `TestRequest::default().insert_header()`. [#1869] * `TestRequest::with_header`; use `TestRequest::default().insert_header()`. [#1869] +* `actors` optional feature. [#1969] +* `ResponseError` impl for `actix::MailboxError`. [#1969] [#1869]: https://github.com/actix/actix-web/pull/1869 [#1894]: https://github.com/actix/actix-web/pull/1894 @@ -34,6 +37,7 @@ [#1905]: https://github.com/actix/actix-web/pull/1905 [#1912]: https://github.com/actix/actix-web/pull/1912 [#1957]: https://github.com/actix/actix-web/pull/1957 +[#1969]: https://github.com/actix/actix-web/pull/1969 ## 3.0.0-beta.1 - 2021-01-07 diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 22a54f569..9f62639f8 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -36,8 +36,8 @@ compress = ["flate2", "brotli2"] # support for secure cookies secure-cookies = ["cookie/secure"] -# support for actix Actor messages -actors = ["actix"] +# trust-dns as client dns resolver +trust-dns = ["trust-dns-resolver"] [dependencies] actix-service = "2.0.0-beta.4" @@ -45,7 +45,6 @@ actix-codec = "0.4.0-beta.1" actix-utils = "3.0.0-beta.2" actix-rt = "2" actix-tls = "3.0.0-beta.2" -actix = { version = "0.11.0-beta.2", default-features = false, optional = true } base64 = "0.13" bitflags = "1.2" @@ -84,6 +83,8 @@ time = { version = "0.2.23", default-features = false, features = ["std"] } brotli2 = { version="0.3.2", optional = true } flate2 = { version = "1.0.13", optional = true } +trust-dns-resolver = { version = "0.20.0", optional = true } + [dev-dependencies] actix-server = "2.0.0-beta.3" actix-http-test = { version = "3.0.0-beta.1", features = ["openssl"] } diff --git a/actix-http/src/client/connector.rs b/actix-http/src/client/connector.rs index 425ee0f70..7c8e2b2a0 100644 --- a/actix-http/src/client/connector.rs +++ b/actix-http/src/client/connector.rs @@ -6,7 +6,7 @@ use actix_codec::{AsyncRead, AsyncWrite}; use actix_rt::net::TcpStream; use actix_service::{apply_fn, Service, ServiceExt}; use actix_tls::connect::{ - default_connector, Connect as TcpConnect, Connection as TcpConnection, + new_connector, Connect as TcpConnect, Connection as TcpConnection, Resolver, }; use actix_utils::timeout::{TimeoutError, TimeoutService}; use http::Uri; @@ -19,7 +19,6 @@ use super::Connect; #[cfg(feature = "openssl")] use actix_tls::connect::ssl::openssl::SslConnector as OpensslConnector; - #[cfg(feature = "rustls")] use actix_tls::connect::ssl::rustls::ClientConfig; #[cfg(feature = "rustls")] @@ -70,7 +69,7 @@ impl Connector<(), ()> { > { Connector { ssl: Self::build_ssl(vec![b"h2".to_vec(), b"http/1.1".to_vec()]), - connector: default_connector(), + connector: new_connector(resolver::resolver()), config: ConnectorConfig::default(), _phantom: PhantomData, } @@ -532,3 +531,82 @@ mod connect_impl { } } } + +#[cfg(not(feature = "trust-dns"))] +mod resolver { + use super::*; + + pub(super) fn resolver() -> Resolver { + Resolver::Default + } +} + +#[cfg(feature = "trust-dns")] +mod resolver { + use std::{cell::RefCell, net::SocketAddr}; + + use actix_tls::connect::Resolve; + use futures_core::future::LocalBoxFuture; + use trust_dns_resolver::{ + config::{ResolverConfig, ResolverOpts}, + system_conf::read_system_conf, + TokioAsyncResolver, + }; + + use super::*; + + pub(super) fn resolver() -> Resolver { + // new type for impl Resolve trait for TokioAsyncResolver. + struct TrustDnsResolver(TokioAsyncResolver); + + 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 + .0 + .lookup_ip(host) + .await? + .iter() + .map(|ip| SocketAddr::new(ip, port)) + .collect(); + Ok(res) + }) + } + } + + // dns struct is cached in thread local. + // so new client constructor can reuse the existing dns resolver. + thread_local! { + static TRUST_DNS_RESOLVER: RefCell> = RefCell::new(None); + } + + // get from thread local or construct a new trust-dns resolver. + TRUST_DNS_RESOLVER.with(|local| { + let resolver = local.borrow().as_ref().map(Clone::clone); + match resolver { + Some(resolver) => resolver, + None => { + 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(); + + // box trust dns resolver and put it in thread local. + let resolver = Resolver::new_custom(TrustDnsResolver(resolver)); + *local.borrow_mut() = Some(resolver.clone()); + resolver + } + } + }) + } +} diff --git a/actix-http/src/error.rs b/actix-http/src/error.rs index 7beedc3ba..cea1f5d4f 100644 --- a/actix-http/src/error.rs +++ b/actix-http/src/error.rs @@ -968,12 +968,6 @@ where InternalError::new(err, StatusCode::NETWORK_AUTHENTICATION_REQUIRED).into() } -#[cfg(feature = "actors")] -/// Returns [`StatusCode::INTERNAL_SERVER_ERROR`] for [`actix::MailboxError`]. -/// -/// This is only supported when the feature `actors` is enabled. -impl ResponseError for actix::MailboxError {} - #[cfg(test)] mod tests { use super::*; diff --git a/awc/CHANGES.md b/awc/CHANGES.md index 16ec7ad1a..80895f46d 100644 --- a/awc/CHANGES.md +++ b/awc/CHANGES.md @@ -4,6 +4,7 @@ ### Added * `ClientRequest::insert_header` method which allows using typed headers. [#1869] * `ClientRequest::append_header` method which allows using typed headers. [#1869] +* `trust-dns` optional feature to enable `trust-dns-resolver` as client dns resolver. [#1969] ### Changed * Relax default timeout for `Connector` to 5 seconds(original 1 second). [#1905] @@ -16,6 +17,7 @@ [#1869]: https://github.com/actix/actix-web/pull/1869 [#1905]: https://github.com/actix/actix-web/pull/1905 +[#1969]: https://github.com/actix/actix-web/pull/1969 ## 3.0.0-beta.1 - 2021-01-07 diff --git a/awc/Cargo.toml b/awc/Cargo.toml index 7a9130780..483e04968 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -36,6 +36,9 @@ rustls = ["tls-rustls", "actix-http/rustls"] # content-encoding support compress = ["actix-http/compress"] +# trust-dns as dns resolver +trust-dns = ["actix-http/trust-dns"] + [dependencies] actix-codec = "0.4.0-beta.1" actix-service = "2.0.0-beta.4" diff --git a/src/test.rs b/src/test.rs index 62c329c91..5da100b81 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1277,8 +1277,10 @@ mod tests { async fn actor_handler( addr: Data>, ) -> Result { - // `?` operator tests "actors" feature flag on actix-http - let res = addr.send(Num(1)).await?; + let res = addr + .send(Num(1)) + .await + .map_err(crate::error::ErrorInternalServerError)?; if res == 1 { Ok(HttpResponse::Ok())