mirror of
https://github.com/ntex-rs/ntex.git
synced 2025-04-04 21:37:58 +03:00
replace trust-dns with blocking code
This commit is contained in:
parent
cb9e3ffeda
commit
111e4ec717
15 changed files with 90 additions and 152 deletions
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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()),
|
||||
))
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,23 +111,19 @@ 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| {
|
||||
let h2 = sock
|
||||
.ssl()
|
||||
.selected_alpn_protocol()
|
||||
.map(|protos| protos.windows(2).any(|w| w == H2))
|
||||
.unwrap_or(false);
|
||||
if h2 {
|
||||
(sock, Protocol::Http2)
|
||||
} else {
|
||||
(sock, Protocol::Http1)
|
||||
}
|
||||
},
|
||||
))
|
||||
self.secure_connector(OpensslConnector::new(connector).map(|sock| {
|
||||
let h2 = sock
|
||||
.ssl()
|
||||
.selected_alpn_protocol()
|
||||
.map(|protos| protos.windows(2).any(|w| w == H2))
|
||||
.unwrap_or(false);
|
||||
if h2 {
|
||||
(sock, Protocol::Http2)
|
||||
} else {
|
||||
(sock, Protocol::Http1)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustls")]
|
||||
|
@ -138,24 +131,20 @@ 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| {
|
||||
let h2 = sock
|
||||
.get_ref()
|
||||
.1
|
||||
.get_alpn_protocol()
|
||||
.map(|protos| protos.windows(2).any(|w| w == H2))
|
||||
.unwrap_or(false);
|
||||
if h2 {
|
||||
(Box::new(sock) as Box<dyn Io>, Protocol::Http2)
|
||||
} else {
|
||||
(Box::new(sock) as Box<dyn Io>, Protocol::Http1)
|
||||
}
|
||||
},
|
||||
))
|
||||
self.secure_connector(RustlsConnector::new(connector).map(|sock| {
|
||||
let h2 = sock
|
||||
.get_ref()
|
||||
.1
|
||||
.get_alpn_protocol()
|
||||
.map(|protos| protos.windows(2).any(|w| w == H2))
|
||||
.unwrap_or(false);
|
||||
if h2 {
|
||||
(Box::new(sock) as Box<dyn Io>, Protocol::Http2)
|
||||
} else {
|
||||
(Box::new(sock) as Box<dyn Io>, Protocol::Http1)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
/// Set total number of simultaneous connections per type of scheme.
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue