replace trust-dns with blocking code

This commit is contained in:
Nikolay Kim 2021-04-03 14:45:27 +06:00
parent cb9e3ffeda
commit 111e4ec717
15 changed files with 90 additions and 152 deletions

View file

@ -1,5 +1,9 @@
# Changes
## [0.4.3] - 2021-04-03
* Disable some of regex features
## [0.4.2] - 2021-03-16
* Use `IntoPattern` for prefix resources

View file

@ -1,6 +1,6 @@
[package]
name = "ntex-router"
version = "0.4.2"
version = "0.4.3"
authors = ["ntex contributors <team@ntex.rs>"]
description = "Path router"
keywords = ["ntex"]
@ -17,11 +17,11 @@ path = "src/lib.rs"
default = ["http"]
[dependencies]
regex = "1.4"
serde = "1.0"
bytestring = "1.0"
log = "0.4"
http = { version = "0.2", optional = true }
regex = { version = "1.4.5", default-features = false, features = ["std"] }
[dev-dependencies]
http = "0.2"

View file

@ -6,6 +6,8 @@
* util: add custom Ready, Either future and several helper functions
* drop trust-dns, use blocking calls
* reduce futures crate dependencies
## [0.3.13] - 2021-03-26

View file

@ -62,7 +62,7 @@ num_cpus = "1.13"
nanorand = "0.5"
percent-encoding = "2.1"
pin-project-lite = "0.2"
regex = "1.4"
regex = { version = "1.4.5", default-features = false, features = ["std"] }
sha-1 = "0.9"
slab = "0.4"
serde = { version = "1.0", features=["derive"] }
@ -73,10 +73,6 @@ url = "2.1"
coo-kie = { version = "0.15", package = "cookie", optional = true }
tokio = { version = "1", default-features=false, features = ["sync"] }
# resolver
trust-dns-proto = { version = "0.20", default-features = false }
trust-dns-resolver = { version = "0.20", default-features = false, features=["system-config", "tokio-runtime"] }
# openssl
open-ssl = { version="0.10", package = "openssl", optional = true }
tokio-openssl = { version = "0.6.1", optional = true }

View file

@ -1,13 +1,13 @@
use std::io;
use derive_more::{Display, From};
use trust_dns_resolver::error::ResolveError;
#[derive(Debug, From, Display)]
pub enum ConnectError {
/// Failed to resolve the hostname
#[from(ignore)]
#[display(fmt = "Failed resolving hostname: {}", _0)]
Resolver(ResolveError),
Resolver(io::Error),
/// No dns records
#[display(fmt = "No dns records found for the input")]

View file

@ -13,42 +13,13 @@ pub mod openssl;
#[cfg(feature = "rustls")]
pub mod rustls;
pub use trust_dns_resolver::config::{self, ResolverConfig, ResolverOpts};
use trust_dns_resolver::system_conf::read_system_conf;
pub use trust_dns_resolver::{error::ResolveError, TokioAsyncResolver as DnsResolver};
use crate::rt::{net::TcpStream, Arbiter};
use crate::rt::net::TcpStream;
pub use self::error::ConnectError;
pub use self::message::{Address, Connect};
pub use self::resolve::Resolver;
pub use self::service::Connector;
pub fn start_resolver(cfg: ResolverConfig, opts: ResolverOpts) -> DnsResolver {
DnsResolver::tokio(cfg, opts).unwrap()
}
struct DefaultResolver(DnsResolver);
pub fn default_resolver() -> DnsResolver {
if Arbiter::contains_item::<DefaultResolver>() {
Arbiter::get_item(|item: &DefaultResolver| item.0.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 = DnsResolver::tokio(cfg, opts).unwrap();
Arbiter::set_item(DefaultResolver(resolver.clone()));
resolver
}
}
/// Resolve and connect to remote host
pub fn connect<T, U>(message: U) -> impl Future<Output = Result<TcpStream, ConnectError>>
where
@ -56,6 +27,6 @@ where
Connect<T>: From<U>,
{
service::ConnectServiceResponse::new(Box::pin(
Resolver::new(default_resolver()).lookup(message.into()),
Resolver::new().lookup(message.into()),
))
}

View file

@ -7,7 +7,7 @@ use crate::rt::net::TcpStream;
use crate::service::{Service, ServiceFactory};
use crate::util::Ready;
use super::{Address, Connect, ConnectError, Connector, DnsResolver};
use super::{Address, Connect, ConnectError, Connector};
pub struct OpensslConnector<T> {
connector: Connector<T>,
@ -22,14 +22,6 @@ impl<T> OpensslConnector<T> {
openssl: connector,
}
}
/// Construct new connect service with custom dns resolver
pub fn with_resolver(connector: SslConnector, resolver: DnsResolver) -> Self {
OpensslConnector {
connector: Connector::new(resolver),
openssl: connector,
}
}
}
impl<T: Address + 'static> OpensslConnector<T> {

View file

@ -1,33 +1,22 @@
use std::{
fmt, future::Future, marker::PhantomData, net::SocketAddr, pin::Pin, rc::Rc,
task::Context, task::Poll,
};
use std::{fmt, future::Future, io, marker, net, pin::Pin, task::Context, task::Poll};
use super::{default_resolver, Address, Connect, ConnectError, DnsResolver};
use super::{Address, Connect, ConnectError};
use crate::service::{Service, ServiceFactory};
use crate::util::{Either, Ready};
/// DNS Resolver Service
pub struct Resolver<T> {
resolver: Rc<DnsResolver>,
_t: PhantomData<T>,
}
pub struct Resolver<T>(marker::PhantomData<T>);
impl<T> fmt::Debug for Resolver<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Resolver")
.field("resolver", &self.resolver)
.finish()
f.debug_struct("Resolver").finish()
}
}
impl<T> Resolver<T> {
/// Create new resolver instance with custom configuration and options.
pub fn new(resolver: DnsResolver) -> Self {
Resolver {
resolver: Rc::new(resolver),
_t: PhantomData,
}
pub fn new() -> Self {
Resolver(marker::PhantomData)
}
}
@ -40,24 +29,29 @@ impl<T: Address> Resolver<T> {
if req.addr.is_some() || req.req.addr().is_some() {
Either::Right(Ready::ok(req))
} else if let Ok(ip) = req.host().parse() {
req.addr = Some(Either::Left(SocketAddr::new(ip, req.port())));
req.addr = Some(Either::Left(net::SocketAddr::new(ip, req.port())));
Either::Right(Ready::ok(req))
} else {
trace!("DNS resolver: resolving host {:?}", req.host());
let resolver = self.resolver.clone();
Either::Left(async move {
let fut = if let Some(host) = req.host().splitn(2, ':').next() {
resolver.lookup_ip(host)
let host = if req.host().contains(':') {
req.host().to_string()
} else {
resolver.lookup_ip(req.host())
format!("{}:{}", req.host(), req.port())
};
let fut = crate::rt::task::spawn_blocking(move || {
net::ToSocketAddrs::to_socket_addrs(&host)
});
match fut.await {
Ok(ips) => {
Ok(Ok(ips)) => {
let port = req.port();
let req = req
.set_addrs(ips.iter().map(|ip| SocketAddr::new(ip, port)));
let req = req.set_addrs(ips.map(|mut ip| {
ip.set_port(port);
ip
}));
trace!(
"DNS resolver: host {:?} resolved to {:?}",
@ -71,13 +65,24 @@ impl<T: Address> Resolver<T> {
Ok(req)
}
}
Ok(Err(e)) => {
trace!(
"DNS resolver: failed to resolve host {:?} err: {}",
req.host(),
e
);
Err(ConnectError::Resolver(e))
}
Err(e) => {
trace!(
"DNS resolver: failed to resolve host {:?} err: {}",
req.host(),
e
);
Err(e.into())
Err(ConnectError::Resolver(io::Error::new(
io::ErrorKind::Other,
e,
)))
}
}
})
@ -87,19 +92,13 @@ impl<T: Address> Resolver<T> {
impl<T> Default for Resolver<T> {
fn default() -> Resolver<T> {
Resolver {
resolver: Rc::new(default_resolver()),
_t: PhantomData,
}
Resolver(marker::PhantomData)
}
}
impl<T> Clone for Resolver<T> {
fn clone(&self) -> Self {
Resolver {
resolver: self.resolver.clone(),
_t: PhantomData,
}
Resolver(marker::PhantomData)
}
}
@ -141,7 +140,7 @@ mod tests {
#[crate::rt_test]
async fn resolver() {
let resolver = Resolver::new(DnsResolver::tokio_from_system_conf().unwrap());
let resolver = Resolver::new();
assert!(format!("{:?}", resolver).contains("Resolver"));
let srv = resolver.new_service(()).await.unwrap();
assert!(lazy(|cx| srv.poll_ready(cx)).await.is_ready());
@ -152,7 +151,7 @@ mod tests {
let res = srv.call(Connect::new("---11213")).await;
assert!(res.is_err());
let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let addr: net::SocketAddr = "127.0.0.1:8080".parse().unwrap();
let res = srv
.call(Connect::new("www.rust-lang.org").set_addrs(vec![addr]))
.await

View file

@ -10,7 +10,7 @@ use crate::rt::net::TcpStream;
use crate::service::{Service, ServiceFactory};
use crate::util::Ready;
use super::{Address, Connect, ConnectError, Connector, DnsResolver};
use super::{Address, Connect, ConnectError, Connector};
/// Rustls connector factory
pub struct RustlsConnector<T> {
@ -25,14 +25,6 @@ impl<T> RustlsConnector<T> {
connector: Connector::default(),
}
}
/// Construct new connect service with custom dns resolver
pub fn with_resolver(config: Arc<ClientConfig>, resolver: DnsResolver) -> Self {
RustlsConnector {
config,
connector: Connector::new(resolver),
}
}
}
impl<T: Address + 'static> RustlsConnector<T> {

View file

@ -5,7 +5,7 @@ use crate::rt::net::TcpStream;
use crate::service::{Service, ServiceFactory};
use crate::util::{Either, Ready};
use super::{Address, Connect, ConnectError, DnsResolver, Resolver};
use super::{Address, Connect, ConnectError, Resolver};
pub struct Connector<T> {
resolver: Resolver<T>,
@ -13,9 +13,9 @@ pub struct Connector<T> {
impl<T> Connector<T> {
/// Construct new connect service with custom dns resolver
pub fn new(resolver: DnsResolver) -> Self {
pub fn new() -> Self {
Connector {
resolver: Resolver::new(resolver),
resolver: Resolver::new(),
}
}
}

View file

@ -1,7 +1,7 @@
use std::{rc::Rc, task::Context, task::Poll, time::Duration};
use crate::codec::{AsyncRead, AsyncWrite};
use crate::connect::{self, Connect as TcpConnect, Connector as TcpConnector};
use crate::connect::{Connect as TcpConnect, Connector as TcpConnector};
use crate::http::{Protocol, Uri};
use crate::service::{apply_fn, boxed, Service};
use crate::util::timeout::{TimeoutError, TimeoutService};
@ -44,8 +44,6 @@ pub struct Connector {
limit: usize,
connector: BoxedConnector,
ssl_connector: Option<BoxedConnector>,
#[allow(dead_code)]
resolver: connect::DnsResolver,
}
trait Io: AsyncRead + AsyncWrite + Unpin {}
@ -53,15 +51,15 @@ impl<T: AsyncRead + AsyncWrite + Unpin> Io for T {}
impl Default for Connector {
fn default() -> Self {
Connector::new(connect::default_resolver())
Connector::new()
}
}
impl Connector {
pub fn new(resolver: connect::DnsResolver) -> Connector {
pub fn new() -> Connector {
let conn = Connector {
connector: boxed::service(
TcpConnector::new(resolver.clone())
TcpConnector::new()
.map(|io| (Box::new(io) as Box<dyn Io>, Protocol::Http1))
.map_err(ConnectError::from),
),
@ -71,7 +69,6 @@ impl Connector {
conn_keep_alive: Duration::from_secs(15),
disconnect_timeout: Duration::from_millis(3000),
limit: 100,
resolver,
};
#[cfg(feature = "openssl")]
@ -114,11 +111,8 @@ impl Connector {
pub fn openssl(self, connector: OpensslConnector) -> Self {
use crate::connect::openssl::OpensslConnector;
let resolver = self.resolver.clone();
const H2: &[u8] = b"h2";
self.secure_connector(OpensslConnector::with_resolver(connector, resolver).map(
|sock| {
self.secure_connector(OpensslConnector::new(connector).map(|sock| {
let h2 = sock
.ssl()
.selected_alpn_protocol()
@ -129,8 +123,7 @@ impl Connector {
} else {
(sock, Protocol::Http1)
}
},
))
}))
}
#[cfg(feature = "rustls")]
@ -138,11 +131,8 @@ impl Connector {
pub fn rustls(self, connector: Arc<ClientConfig>) -> Self {
use crate::connect::rustls::{RustlsConnector, Session};
let resolver = self.resolver.clone();
const H2: &[u8] = b"h2";
self.secure_connector(RustlsConnector::with_resolver(connector, resolver).map(
|sock| {
self.secure_connector(RustlsConnector::new(connector).map(|sock| {
let h2 = sock
.get_ref()
.1
@ -154,8 +144,7 @@ impl Connector {
} else {
(Box::new(sock) as Box<dyn Io>, Protocol::Http1)
}
},
))
}))
}
/// Set total number of simultaneous connections per type of scheme.

View file

@ -6,7 +6,6 @@ use serde_json::error::Error as JsonError;
#[cfg(feature = "openssl")]
use crate::connect::openssl::{HandshakeError, SslError};
use crate::connect::ResolveError;
use crate::http::error::{HttpError, ParseError, PayloadError};
use crate::http::header::HeaderValue;
@ -91,8 +90,9 @@ pub enum ConnectError {
SslHandshakeError(String),
/// Failed to resolve the hostname
#[from(ignore)]
#[display(fmt = "Failed resolving hostname: {}", _0)]
Resolver(ResolveError),
Resolver(io::Error),
/// No dns records
#[display(fmt = "No dns records found for the input")]

View file

@ -4,7 +4,7 @@ use bytes::Bytes;
use futures::SinkExt;
use ntex::codec::{BytesCodec, Framed};
use ntex::connect::{Connect, ResolverConfig, ResolverOpts};
use ntex::connect::Connect;
use ntex::rt::net::TcpStream;
use ntex::server::test_server;
use ntex::service::{fn_service, Service, ServiceFactory};
@ -53,14 +53,13 @@ async fn test_static_str() {
})
});
let resolver = ntex::connect::default_resolver();
let conn = ntex::connect::Connector::new(resolver.clone());
let conn = ntex::connect::Connector::new();
let con = conn.call(Connect::with("10", srv.addr())).await.unwrap();
assert_eq!(con.peer_addr().unwrap(), srv.addr());
let connect = Connect::new("127.0.0.1".to_owned());
let conn = ntex::connect::Connector::new(resolver);
let conn = ntex::connect::Connector::new();
let con = conn.call(connect).await;
assert!(con.is_err());
}
@ -75,13 +74,7 @@ async fn test_new_service() {
})
});
let resolver = ntex::connect::start_resolver(
ResolverConfig::default(),
ResolverOpts::default(),
);
let factory = ntex::connect::Connector::new(resolver);
let factory = ntex::connect::Connector::new();
let conn = factory.new_service(()).await.unwrap();
let con = conn.call(Connect::with("10", srv.addr())).await.unwrap();
assert_eq!(con.peer_addr().unwrap(), srv.addr());

View file

@ -176,7 +176,7 @@ async fn test_timeout() {
let connector = Connector::default()
.connector(
ntex::connect::Connector::new(ntex::connect::default_resolver())
ntex::connect::Connector::new()
.map(|sock| (sock, ntex::http::Protocol::Http1)),
)
.timeout(Duration::from_secs(15))

View file

@ -143,7 +143,7 @@ async fn test_chunked_payload() {
let mut data = String::new();
let _ = stream.read_to_string(&mut data);
let re = Regex::new(r"size=(\d+)").unwrap();
let re = Regex::new(r"size=([0-9]+)").unwrap();
let size: usize = match re.captures(&data) {
Some(caps) => caps.get(1).unwrap().as_str().parse().unwrap(),
None => panic!("Failed to find size in HTTP Response: {}", data),