mirror of
https://github.com/fafhrd91/actix-net
synced 2025-03-20 23:05:16 +01:00
change default name resolver and allow custom resolvers (#248)
This commit is contained in:
parent
6112a47529
commit
874e5f2e50
@ -9,9 +9,6 @@ use std::{fmt, thread};
|
|||||||
|
|
||||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
|
||||||
use tokio::sync::oneshot::{channel, error::RecvError as Canceled, Sender};
|
use tokio::sync::oneshot::{channel, error::RecvError as Canceled, Sender};
|
||||||
// use futures_util::stream::FuturesUnordered;
|
|
||||||
// use tokio::task::JoinHandle;
|
|
||||||
// use tokio::stream::StreamExt;
|
|
||||||
use tokio::task::LocalSet;
|
use tokio::task::LocalSet;
|
||||||
|
|
||||||
use crate::runtime::Runtime;
|
use crate::runtime::Runtime;
|
||||||
@ -19,12 +16,6 @@ use crate::system::System;
|
|||||||
|
|
||||||
thread_local!(
|
thread_local!(
|
||||||
static ADDR: RefCell<Option<Arbiter>> = RefCell::new(None);
|
static ADDR: RefCell<Option<Arbiter>> = RefCell::new(None);
|
||||||
// TODO: Commented out code are for Arbiter::local_join function.
|
|
||||||
// It can be safely removed if this function is not used in actix-*.
|
|
||||||
//
|
|
||||||
// /// stores join handle for spawned async tasks.
|
|
||||||
// static HANDLE: RefCell<FuturesUnordered<JoinHandle<()>>> =
|
|
||||||
// RefCell::new(FuturesUnordered::new());
|
|
||||||
static STORAGE: RefCell<HashMap<TypeId, Box<dyn Any>>> = RefCell::new(HashMap::new());
|
static STORAGE: RefCell<HashMap<TypeId, Box<dyn Any>>> = RefCell::new(HashMap::new());
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -154,11 +145,6 @@ impl Arbiter {
|
|||||||
where
|
where
|
||||||
F: Future<Output = ()> + 'static,
|
F: Future<Output = ()> + 'static,
|
||||||
{
|
{
|
||||||
// HANDLE.with(|handle| {
|
|
||||||
// let handle = handle.borrow();
|
|
||||||
// handle.push(tokio::task::spawn_local(future));
|
|
||||||
// });
|
|
||||||
// let _ = tokio::task::spawn_local(CleanupPending);
|
|
||||||
let _ = tokio::task::spawn_local(future);
|
let _ = tokio::task::spawn_local(future);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,32 +263,12 @@ impl Arbiter {
|
|||||||
|
|
||||||
/// Returns a future that will be completed once all currently spawned futures
|
/// Returns a future that will be completed once all currently spawned futures
|
||||||
/// have completed.
|
/// have completed.
|
||||||
#[deprecated(since = "1.2.0", note = "Arbiter::local_join function is removed.")]
|
#[deprecated(since = "2.0.0", note = "Arbiter::local_join function is removed.")]
|
||||||
pub async fn local_join() {
|
pub async fn local_join() {
|
||||||
// let handle = HANDLE.with(|fut| std::mem::take(&mut *fut.borrow_mut()));
|
|
||||||
// async move {
|
|
||||||
// handle.collect::<Vec<_>>().await;
|
|
||||||
// }
|
|
||||||
unimplemented!("Arbiter::local_join function is removed.")
|
unimplemented!("Arbiter::local_join function is removed.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// Future used for cleaning-up already finished `JoinHandle`s
|
|
||||||
// /// from the `PENDING` list so the vector doesn't grow indefinitely
|
|
||||||
// struct CleanupPending;
|
|
||||||
//
|
|
||||||
// impl Future for CleanupPending {
|
|
||||||
// type Output = ();
|
|
||||||
//
|
|
||||||
// fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
||||||
// HANDLE.with(move |handle| {
|
|
||||||
// recycle_join_handle(&mut *handle.borrow_mut(), cx);
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// Poll::Ready(())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
struct ArbiterController {
|
struct ArbiterController {
|
||||||
rx: UnboundedReceiver<ArbiterCommand>,
|
rx: UnboundedReceiver<ArbiterCommand>,
|
||||||
}
|
}
|
||||||
@ -330,11 +296,6 @@ impl Future for ArbiterController {
|
|||||||
Poll::Ready(Some(item)) => match item {
|
Poll::Ready(Some(item)) => match item {
|
||||||
ArbiterCommand::Stop => return Poll::Ready(()),
|
ArbiterCommand::Stop => return Poll::Ready(()),
|
||||||
ArbiterCommand::Execute(fut) => {
|
ArbiterCommand::Execute(fut) => {
|
||||||
// HANDLE.with(|handle| {
|
|
||||||
// let mut handle = handle.borrow_mut();
|
|
||||||
// handle.push(tokio::task::spawn_local(fut));
|
|
||||||
// recycle_join_handle(&mut *handle, cx);
|
|
||||||
// });
|
|
||||||
tokio::task::spawn_local(fut);
|
tokio::task::spawn_local(fut);
|
||||||
}
|
}
|
||||||
ArbiterCommand::ExecuteFn(f) => {
|
ArbiterCommand::ExecuteFn(f) => {
|
||||||
@ -347,20 +308,6 @@ impl Future for ArbiterController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn recycle_join_handle(handle: &mut FuturesUnordered<JoinHandle<()>>, cx: &mut Context<'_>) {
|
|
||||||
// let _ = Pin::new(&mut *handle).poll_next(cx);
|
|
||||||
//
|
|
||||||
// // Try to recycle more join handles and free up memory.
|
|
||||||
// //
|
|
||||||
// // this is a guess. The yield limit for FuturesUnordered is 32.
|
|
||||||
// // So poll an extra 3 times would make the total poll below 128.
|
|
||||||
// if handle.len() > 64 {
|
|
||||||
// (0..3).for_each(|_| {
|
|
||||||
// let _ = Pin::new(&mut *handle).poll_next(cx);
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum SystemCommand {
|
pub(crate) enum SystemCommand {
|
||||||
Exit(i32),
|
Exit(i32),
|
||||||
|
@ -66,7 +66,7 @@ pub mod time {
|
|||||||
pub use tokio::time::{timeout, Timeout};
|
pub use tokio::time::{timeout, Timeout};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Blocking task management.
|
/// Task management.
|
||||||
pub mod task {
|
pub mod task {
|
||||||
pub use tokio::task::{spawn_blocking, yield_now, JoinHandle};
|
pub use tokio::task::{spawn_blocking, yield_now, JoinHandle};
|
||||||
}
|
}
|
||||||
|
@ -62,43 +62,6 @@ fn join_another_arbiter() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn join_current_arbiter() {
|
|
||||||
// let time = Duration::from_secs(2);
|
|
||||||
//
|
|
||||||
// let instant = Instant::now();
|
|
||||||
// actix_rt::System::new("test_join_current_arbiter").block_on(async move {
|
|
||||||
// actix_rt::spawn(async move {
|
|
||||||
// tokio::time::delay_for(time).await;
|
|
||||||
// actix_rt::Arbiter::current().stop();
|
|
||||||
// });
|
|
||||||
// actix_rt::Arbiter::local_join().await;
|
|
||||||
// });
|
|
||||||
// assert!(
|
|
||||||
// instant.elapsed() >= time,
|
|
||||||
// "Join on current arbiter should wait for all spawned futures"
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// let large_timer = Duration::from_secs(20);
|
|
||||||
// let instant = Instant::now();
|
|
||||||
// actix_rt::System::new("test_join_current_arbiter").block_on(async move {
|
|
||||||
// actix_rt::spawn(async move {
|
|
||||||
// tokio::time::delay_for(time).await;
|
|
||||||
// actix_rt::Arbiter::current().stop();
|
|
||||||
// });
|
|
||||||
// let f = actix_rt::Arbiter::local_join();
|
|
||||||
// actix_rt::spawn(async move {
|
|
||||||
// tokio::time::delay_for(large_timer).await;
|
|
||||||
// actix_rt::Arbiter::current().stop();
|
|
||||||
// });
|
|
||||||
// f.await;
|
|
||||||
// });
|
|
||||||
// assert!(
|
|
||||||
// instant.elapsed() < large_timer,
|
|
||||||
// "local_join should await only for the already spawned futures"
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn non_static_block_on() {
|
fn non_static_block_on() {
|
||||||
let string = String::from("test_str");
|
let string = String::from("test_str");
|
||||||
|
4
actix-server/Cargo.toml
Normal file → Executable file
4
actix-server/Cargo.toml
Normal file → Executable file
@ -24,11 +24,11 @@ default = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.4.0-beta.1"
|
actix-codec = "0.4.0-beta.1"
|
||||||
actix-rt = "2.0.0-beta.2"
|
actix-rt = { version = "2.0.0-beta.2", default-features = false }
|
||||||
actix-service = "2.0.0-beta.3"
|
actix-service = "2.0.0-beta.3"
|
||||||
actix-utils = "3.0.0-beta.1"
|
actix-utils = "3.0.0-beta.1"
|
||||||
|
|
||||||
futures-core = { version = "0.3.7", default-features = false }
|
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
mio = { version = "0.7.6", features = ["os-poll", "net"] }
|
mio = { version = "0.7.6", features = ["os-poll", "net"] }
|
||||||
num_cpus = "1.13"
|
num_cpus = "1.13"
|
||||||
|
@ -1,6 +1,16 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
|
* Remove `trust-dns-proto` and `trust-dns-resolver` [#248]
|
||||||
|
* Use `tokio::net::lookup_host` as simple and basic default resolver [#248]
|
||||||
|
* Add `Resolve` trait for custom dns resolver. [#248]
|
||||||
|
* Add `Resolver::new_custom` function to construct custom resolvers. [#248]
|
||||||
|
* Export `webpki_roots::TLS_SERVER_ROOTS` in `actix_tls::connect` mod and remove
|
||||||
|
the export from `actix_tls::accept` [#248]
|
||||||
|
* Remove `ConnectTakeAddrsIter`. `Connect::take_addrs` would return
|
||||||
|
`ConnectAddrsIter<'static>` as owned iterator. [#248]
|
||||||
|
|
||||||
|
[#248]: https://github.com/actix/actix-net/pull/248
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.2 - 2021-xx-xx
|
## 3.0.0-beta.2 - 2021-xx-xx
|
||||||
|
15
actix-tls/Cargo.toml
Normal file → Executable file
15
actix-tls/Cargo.toml
Normal file → Executable file
@ -29,7 +29,7 @@ default = ["accept", "connect", "uri"]
|
|||||||
accept = []
|
accept = []
|
||||||
|
|
||||||
# enable connector services
|
# enable connector services
|
||||||
connect = ["trust-dns-proto/tokio-runtime", "trust-dns-resolver/tokio-runtime", "trust-dns-resolver/system-config"]
|
connect = []
|
||||||
|
|
||||||
# use openssl impls
|
# use openssl impls
|
||||||
openssl = ["tls-openssl", "tokio-openssl"]
|
openssl = ["tls-openssl", "tokio-openssl"]
|
||||||
@ -45,20 +45,15 @@ uri = ["http"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.4.0-beta.1"
|
actix-codec = "0.4.0-beta.1"
|
||||||
actix-rt = "2.0.0-beta.2"
|
actix-rt = { version = "2.0.0-beta.2", default-features = false }
|
||||||
actix-service = "2.0.0-beta.3"
|
actix-service = "2.0.0-beta.3"
|
||||||
actix-utils = "3.0.0-beta.1"
|
actix-utils = "3.0.0-beta.1"
|
||||||
|
|
||||||
derive_more = "0.99.5"
|
derive_more = "0.99.5"
|
||||||
either = "1.6"
|
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
|
||||||
futures-util = { version = "0.3.7", default-features = false }
|
http = { version = "0.2.3", optional = true }
|
||||||
http = { version = "0.2.2", optional = true }
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
||||||
# resolver
|
|
||||||
trust-dns-proto = { version = "0.20.0", default-features = false, optional = true }
|
|
||||||
trust-dns-resolver = { version = "0.20.0", default-features = false, optional = true }
|
|
||||||
|
|
||||||
# openssl
|
# openssl
|
||||||
tls-openssl = { package = "openssl", version = "0.10", optional = true }
|
tls-openssl = { package = "openssl", version = "0.10", optional = true }
|
||||||
tokio-openssl = { version = "0.6", optional = true }
|
tokio-openssl = { version = "0.6", optional = true }
|
||||||
@ -76,8 +71,10 @@ tls-native-tls = { package = "native-tls", version = "0.2", optional = true }
|
|||||||
tokio-native-tls = { version = "0.3", optional = true }
|
tokio-native-tls = { version = "0.3", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
actix-rt = "2.0.0-beta.2"
|
||||||
actix-server = "2.0.0-beta.2"
|
actix-server = "2.0.0-beta.2"
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
env_logger = "0.8"
|
env_logger = "0.8"
|
||||||
futures-util = { version = "0.3.7", default-features = false, features = ["sink"] }
|
futures-util = { version = "0.3.7", default-features = false, features = ["sink"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
trust-dns-resolver = "0.20.0"
|
@ -3,7 +3,7 @@ use std::task::{Context, Poll};
|
|||||||
use actix_codec::{AsyncRead, AsyncWrite};
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
use actix_service::{Service, ServiceFactory};
|
use actix_service::{Service, ServiceFactory};
|
||||||
use actix_utils::counter::Counter;
|
use actix_utils::counter::Counter;
|
||||||
use futures_util::future::{ready, LocalBoxFuture, Ready};
|
use futures_core::future::LocalBoxFuture;
|
||||||
|
|
||||||
pub use native_tls::Error;
|
pub use native_tls::Error;
|
||||||
pub use tokio_native_tls::{TlsAcceptor, TlsStream};
|
pub use tokio_native_tls::{TlsAcceptor, TlsStream};
|
||||||
@ -44,15 +44,16 @@ where
|
|||||||
|
|
||||||
type Service = NativeTlsAcceptorService;
|
type Service = NativeTlsAcceptorService;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
|
||||||
|
|
||||||
fn new_service(&self, _: ()) -> Self::Future {
|
fn new_service(&self, _: ()) -> Self::Future {
|
||||||
MAX_CONN_COUNTER.with(|conns| {
|
let res = MAX_CONN_COUNTER.with(|conns| {
|
||||||
ready(Ok(NativeTlsAcceptorService {
|
Ok(NativeTlsAcceptorService {
|
||||||
acceptor: self.acceptor.clone(),
|
acceptor: self.acceptor.clone(),
|
||||||
conns: conns.clone(),
|
conns: conns.clone(),
|
||||||
}))
|
|
||||||
})
|
})
|
||||||
|
});
|
||||||
|
Box::pin(async { res })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
use std::future::Future;
|
use std::{
|
||||||
use std::pin::Pin;
|
future::Future,
|
||||||
use std::task::{Context, Poll};
|
pin::Pin,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
use actix_codec::{AsyncRead, AsyncWrite};
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
use actix_service::{Service, ServiceFactory};
|
use actix_service::{Service, ServiceFactory};
|
||||||
use actix_utils::counter::{Counter, CounterGuard};
|
use actix_utils::counter::{Counter, CounterGuard};
|
||||||
use futures_util::{
|
use futures_core::{future::LocalBoxFuture, ready};
|
||||||
future::{ready, Ready},
|
|
||||||
ready,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use openssl::ssl::{
|
pub use openssl::ssl::{
|
||||||
AlpnError, Error as SslError, HandshakeError, Ssl, SslAcceptor, SslAcceptorBuilder,
|
AlpnError, Error as SslError, HandshakeError, Ssl, SslAcceptor, SslAcceptorBuilder,
|
||||||
@ -50,15 +49,16 @@ where
|
|||||||
type Config = ();
|
type Config = ();
|
||||||
type Service = AcceptorService;
|
type Service = AcceptorService;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
|
||||||
|
|
||||||
fn new_service(&self, _: ()) -> Self::Future {
|
fn new_service(&self, _: ()) -> Self::Future {
|
||||||
MAX_CONN_COUNTER.with(|conns| {
|
let res = MAX_CONN_COUNTER.with(|conns| {
|
||||||
ready(Ok(AcceptorService {
|
Ok(AcceptorService {
|
||||||
acceptor: self.acceptor.clone(),
|
acceptor: self.acceptor.clone(),
|
||||||
conns: conns.clone(),
|
conns: conns.clone(),
|
||||||
}))
|
|
||||||
})
|
})
|
||||||
|
});
|
||||||
|
Box::pin(async { res })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
use std::future::Future;
|
use std::{
|
||||||
use std::io;
|
future::Future,
|
||||||
use std::pin::Pin;
|
io,
|
||||||
use std::sync::Arc;
|
pin::Pin,
|
||||||
use std::task::{Context, Poll};
|
sync::Arc,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
use actix_codec::{AsyncRead, AsyncWrite};
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
use actix_service::{Service, ServiceFactory};
|
use actix_service::{Service, ServiceFactory};
|
||||||
use actix_utils::counter::{Counter, CounterGuard};
|
use actix_utils::counter::{Counter, CounterGuard};
|
||||||
use futures_util::future::{ready, Ready};
|
use futures_core::future::LocalBoxFuture;
|
||||||
use tokio_rustls::{Accept, TlsAcceptor};
|
use tokio_rustls::{Accept, TlsAcceptor};
|
||||||
|
|
||||||
pub use rustls::{ServerConfig, Session};
|
pub use rustls::{ServerConfig, Session};
|
||||||
pub use tokio_rustls::server::TlsStream;
|
pub use tokio_rustls::server::TlsStream;
|
||||||
pub use webpki_roots::TLS_SERVER_ROOTS;
|
|
||||||
|
|
||||||
use super::MAX_CONN_COUNTER;
|
use super::MAX_CONN_COUNTER;
|
||||||
|
|
||||||
@ -52,15 +53,16 @@ where
|
|||||||
|
|
||||||
type Service = AcceptorService;
|
type Service = AcceptorService;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
|
||||||
|
|
||||||
fn new_service(&self, _: ()) -> Self::Future {
|
fn new_service(&self, _: ()) -> Self::Future {
|
||||||
MAX_CONN_COUNTER.with(|conns| {
|
let res = MAX_CONN_COUNTER.with(|conns| {
|
||||||
ready(Ok(AcceptorService {
|
Ok(AcceptorService {
|
||||||
acceptor: self.config.clone().into(),
|
acceptor: self.config.clone().into(),
|
||||||
conns: conns.clone(),
|
conns: conns.clone(),
|
||||||
}))
|
|
||||||
})
|
})
|
||||||
|
});
|
||||||
|
Box::pin(async { res })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
119
actix-tls/src/connect/connect.rs
Normal file → Executable file
119
actix-tls/src/connect/connect.rs
Normal file → Executable file
@ -1,9 +1,9 @@
|
|||||||
use std::collections::{vec_deque, VecDeque};
|
use std::{
|
||||||
use std::fmt;
|
collections::{vec_deque, VecDeque},
|
||||||
use std::iter::{FromIterator, FusedIterator};
|
fmt,
|
||||||
use std::net::SocketAddr;
|
iter::{FromIterator, FusedIterator},
|
||||||
|
net::SocketAddr,
|
||||||
use either::Either;
|
};
|
||||||
|
|
||||||
/// Connect request
|
/// Connect request
|
||||||
pub trait Address: Unpin + 'static {
|
pub trait Address: Unpin + 'static {
|
||||||
@ -39,7 +39,25 @@ impl Address for &'static str {
|
|||||||
pub struct Connect<T> {
|
pub struct Connect<T> {
|
||||||
pub(crate) req: T,
|
pub(crate) req: T,
|
||||||
pub(crate) port: u16,
|
pub(crate) port: u16,
|
||||||
pub(crate) addr: Option<Either<SocketAddr, VecDeque<SocketAddr>>>,
|
pub(crate) addr: ConnectAddrs,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Debug, Hash)]
|
||||||
|
pub(crate) enum ConnectAddrs {
|
||||||
|
One(Option<SocketAddr>),
|
||||||
|
Multi(VecDeque<SocketAddr>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConnectAddrs {
|
||||||
|
pub(crate) fn is_none(&self) -> bool {
|
||||||
|
matches!(*self, Self::One(None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ConnectAddrs {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::One(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Address> Connect<T> {
|
impl<T: Address> Connect<T> {
|
||||||
@ -49,7 +67,7 @@ impl<T: Address> Connect<T> {
|
|||||||
Connect {
|
Connect {
|
||||||
req,
|
req,
|
||||||
port: port.unwrap_or(0),
|
port: port.unwrap_or(0),
|
||||||
addr: None,
|
addr: ConnectAddrs::One(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +77,7 @@ impl<T: Address> Connect<T> {
|
|||||||
Connect {
|
Connect {
|
||||||
req,
|
req,
|
||||||
port: 0,
|
port: 0,
|
||||||
addr: Some(Either::Left(addr)),
|
addr: ConnectAddrs::One(Some(addr)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,9 +91,7 @@ impl<T: Address> Connect<T> {
|
|||||||
|
|
||||||
/// Use address.
|
/// Use address.
|
||||||
pub fn set_addr(mut self, addr: Option<SocketAddr>) -> Self {
|
pub fn set_addr(mut self, addr: Option<SocketAddr>) -> Self {
|
||||||
if let Some(addr) = addr {
|
self.addr = ConnectAddrs::One(addr);
|
||||||
self.addr = Some(Either::Left(addr));
|
|
||||||
}
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,9 +102,9 @@ impl<T: Address> Connect<T> {
|
|||||||
{
|
{
|
||||||
let mut addrs = VecDeque::from_iter(addrs);
|
let mut addrs = VecDeque::from_iter(addrs);
|
||||||
self.addr = if addrs.len() < 2 {
|
self.addr = if addrs.len() < 2 {
|
||||||
addrs.pop_front().map(Either::Left)
|
ConnectAddrs::One(addrs.pop_front())
|
||||||
} else {
|
} else {
|
||||||
Some(Either::Right(addrs))
|
ConnectAddrs::Multi(addrs)
|
||||||
};
|
};
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -105,24 +121,18 @@ impl<T: Address> Connect<T> {
|
|||||||
|
|
||||||
/// Pre-resolved addresses of the request.
|
/// Pre-resolved addresses of the request.
|
||||||
pub fn addrs(&self) -> ConnectAddrsIter<'_> {
|
pub fn addrs(&self) -> ConnectAddrsIter<'_> {
|
||||||
let inner = match self.addr {
|
match self.addr {
|
||||||
None => Either::Left(None),
|
ConnectAddrs::One(addr) => ConnectAddrsIter::One(addr),
|
||||||
Some(Either::Left(addr)) => Either::Left(Some(addr)),
|
ConnectAddrs::Multi(ref addrs) => ConnectAddrsIter::Multi(addrs.iter()),
|
||||||
Some(Either::Right(ref addrs)) => Either::Right(addrs.iter()),
|
}
|
||||||
};
|
|
||||||
|
|
||||||
ConnectAddrsIter { inner }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes pre-resolved addresses of the request.
|
/// Takes pre-resolved addresses of the request.
|
||||||
pub fn take_addrs(&mut self) -> ConnectTakeAddrsIter {
|
pub fn take_addrs(&mut self) -> ConnectAddrsIter<'static> {
|
||||||
let inner = match self.addr.take() {
|
match std::mem::take(&mut self.addr) {
|
||||||
None => Either::Left(None),
|
ConnectAddrs::One(addr) => ConnectAddrsIter::One(addr),
|
||||||
Some(Either::Left(addr)) => Either::Left(Some(addr)),
|
ConnectAddrs::Multi(addrs) => ConnectAddrsIter::MultiOwned(addrs.into_iter()),
|
||||||
Some(Either::Right(addrs)) => Either::Right(addrs.into_iter()),
|
}
|
||||||
};
|
|
||||||
|
|
||||||
ConnectTakeAddrsIter { inner }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,25 +150,29 @@ impl<T: Address> fmt::Display for Connect<T> {
|
|||||||
|
|
||||||
/// Iterator over addresses in a [`Connect`] request.
|
/// Iterator over addresses in a [`Connect`] request.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ConnectAddrsIter<'a> {
|
pub enum ConnectAddrsIter<'a> {
|
||||||
inner: Either<Option<SocketAddr>, vec_deque::Iter<'a, SocketAddr>>,
|
One(Option<SocketAddr>),
|
||||||
|
Multi(vec_deque::Iter<'a, SocketAddr>),
|
||||||
|
MultiOwned(vec_deque::IntoIter<SocketAddr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for ConnectAddrsIter<'_> {
|
impl Iterator for ConnectAddrsIter<'_> {
|
||||||
type Item = SocketAddr;
|
type Item = SocketAddr;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
match self.inner {
|
match *self {
|
||||||
Either::Left(ref mut opt) => opt.take(),
|
Self::One(ref mut addr) => addr.take(),
|
||||||
Either::Right(ref mut iter) => iter.next().copied(),
|
Self::Multi(ref mut iter) => iter.next().copied(),
|
||||||
|
Self::MultiOwned(ref mut iter) => iter.next(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
match self.inner {
|
match *self {
|
||||||
Either::Left(Some(_)) => (1, Some(1)),
|
Self::One(None) => (0, Some(0)),
|
||||||
Either::Left(None) => (0, Some(0)),
|
Self::One(Some(_)) => (1, Some(1)),
|
||||||
Either::Right(ref iter) => iter.size_hint(),
|
Self::Multi(ref iter) => iter.size_hint(),
|
||||||
|
Self::MultiOwned(ref iter) => iter.size_hint(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,35 +187,6 @@ impl ExactSizeIterator for ConnectAddrsIter<'_> {}
|
|||||||
|
|
||||||
impl FusedIterator for ConnectAddrsIter<'_> {}
|
impl FusedIterator for ConnectAddrsIter<'_> {}
|
||||||
|
|
||||||
/// Owned iterator over addresses in a [`Connect`] request.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ConnectTakeAddrsIter {
|
|
||||||
inner: Either<Option<SocketAddr>, vec_deque::IntoIter<SocketAddr>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for ConnectTakeAddrsIter {
|
|
||||||
type Item = SocketAddr;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
match self.inner {
|
|
||||||
Either::Left(ref mut opt) => opt.take(),
|
|
||||||
Either::Right(ref mut iter) => iter.next(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
match self.inner {
|
|
||||||
Either::Left(Some(_)) => (1, Some(1)),
|
|
||||||
Either::Left(None) => (0, Some(0)),
|
|
||||||
Either::Right(ref iter) => iter.size_hint(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExactSizeIterator for ConnectTakeAddrsIter {}
|
|
||||||
|
|
||||||
impl FusedIterator for ConnectTakeAddrsIter {}
|
|
||||||
|
|
||||||
fn parse(host: &str) -> (&str, Option<u16>) {
|
fn parse(host: &str) -> (&str, Option<u16>) {
|
||||||
let mut parts_iter = host.splitn(2, ':');
|
let mut parts_iter = host.splitn(2, ':');
|
||||||
if let Some(host) = parts_iter.next() {
|
if let Some(host) = parts_iter.next() {
|
||||||
|
97
actix-tls/src/connect/connector.rs
Normal file → Executable file
97
actix-tls/src/connect/connector.rs
Normal file → Executable file
@ -1,76 +1,50 @@
|
|||||||
use std::collections::VecDeque;
|
use std::{
|
||||||
use std::future::Future;
|
collections::VecDeque,
|
||||||
use std::io;
|
future::Future,
|
||||||
use std::marker::PhantomData;
|
io,
|
||||||
use std::net::SocketAddr;
|
net::SocketAddr,
|
||||||
use std::pin::Pin;
|
pin::Pin,
|
||||||
use std::task::{Context, Poll};
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
use actix_rt::net::TcpStream;
|
use actix_rt::net::TcpStream;
|
||||||
use actix_service::{Service, ServiceFactory};
|
use actix_service::{Service, ServiceFactory};
|
||||||
use futures_util::future::{ready, Ready};
|
use futures_core::future::LocalBoxFuture;
|
||||||
use log::{error, trace};
|
use log::{error, trace};
|
||||||
|
|
||||||
use super::connect::{Address, Connect, Connection};
|
use super::connect::{Address, Connect, ConnectAddrs, Connection};
|
||||||
use super::error::ConnectError;
|
use super::error::ConnectError;
|
||||||
|
|
||||||
/// TCP connector service factory
|
/// TCP connector service factory
|
||||||
#[derive(Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct TcpConnectorFactory<T>(PhantomData<T>);
|
pub struct TcpConnectorFactory;
|
||||||
|
|
||||||
impl<T> TcpConnectorFactory<T> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
TcpConnectorFactory(PhantomData)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
impl TcpConnectorFactory {
|
||||||
/// Create TCP connector service
|
/// Create TCP connector service
|
||||||
pub fn service(&self) -> TcpConnector<T> {
|
pub fn service(&self) -> TcpConnector {
|
||||||
TcpConnector(PhantomData)
|
TcpConnector
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Default for TcpConnectorFactory<T> {
|
impl<T: Address> ServiceFactory<Connect<T>> for TcpConnectorFactory {
|
||||||
fn default() -> Self {
|
|
||||||
TcpConnectorFactory(PhantomData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Clone for TcpConnectorFactory<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
TcpConnectorFactory(PhantomData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Address> ServiceFactory<Connect<T>> for TcpConnectorFactory<T> {
|
|
||||||
type Response = Connection<T, TcpStream>;
|
type Response = Connection<T, TcpStream>;
|
||||||
type Error = ConnectError;
|
type Error = ConnectError;
|
||||||
type Config = ();
|
type Config = ();
|
||||||
type Service = TcpConnector<T>;
|
type Service = TcpConnector;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
|
||||||
|
|
||||||
fn new_service(&self, _: ()) -> Self::Future {
|
fn new_service(&self, _: ()) -> Self::Future {
|
||||||
ready(Ok(self.service()))
|
let service = self.service();
|
||||||
|
Box::pin(async move { Ok(service) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TCP connector service
|
/// TCP connector service
|
||||||
#[derive(Default, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct TcpConnector<T>(PhantomData<T>);
|
pub struct TcpConnector;
|
||||||
|
|
||||||
impl<T> TcpConnector<T> {
|
impl<T: Address> Service<Connect<T>> for TcpConnector {
|
||||||
pub fn new() -> Self {
|
|
||||||
TcpConnector(PhantomData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Clone for TcpConnector<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
TcpConnector(PhantomData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Address> Service<Connect<T>> for TcpConnector<T> {
|
|
||||||
type Response = Connection<T, TcpStream>;
|
type Response = Connection<T, TcpStream>;
|
||||||
type Error = ConnectError;
|
type Error = ConnectError;
|
||||||
type Future = TcpConnectorResponse<T>;
|
type Future = TcpConnectorResponse<T>;
|
||||||
@ -81,17 +55,10 @@ impl<T: Address> Service<Connect<T>> for TcpConnector<T> {
|
|||||||
let port = req.port();
|
let port = req.port();
|
||||||
let Connect { req, addr, .. } = req;
|
let Connect { req, addr, .. } = req;
|
||||||
|
|
||||||
if let Some(addr) = addr {
|
|
||||||
TcpConnectorResponse::new(req, port, addr)
|
TcpConnectorResponse::new(req, port, addr)
|
||||||
} else {
|
|
||||||
error!("TCP connector: got unresolved address");
|
|
||||||
TcpConnectorResponse::Error(Some(ConnectError::Unresolved))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type LocalBoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
/// TCP stream connector response future
|
/// TCP stream connector response future
|
||||||
pub enum TcpConnectorResponse<T> {
|
pub enum TcpConnectorResponse<T> {
|
||||||
@ -105,11 +72,7 @@ pub enum TcpConnectorResponse<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Address> TcpConnectorResponse<T> {
|
impl<T: Address> TcpConnectorResponse<T> {
|
||||||
pub fn new(
|
pub(crate) fn new(req: T, port: u16, addr: ConnectAddrs) -> TcpConnectorResponse<T> {
|
||||||
req: T,
|
|
||||||
port: u16,
|
|
||||||
addr: either::Either<SocketAddr, VecDeque<SocketAddr>>,
|
|
||||||
) -> TcpConnectorResponse<T> {
|
|
||||||
trace!(
|
trace!(
|
||||||
"TCP connector - connecting to {:?} port:{}",
|
"TCP connector - connecting to {:?} port:{}",
|
||||||
req.host(),
|
req.host(),
|
||||||
@ -117,13 +80,19 @@ impl<T: Address> TcpConnectorResponse<T> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
match addr {
|
match addr {
|
||||||
either::Either::Left(addr) => TcpConnectorResponse::Response {
|
ConnectAddrs::One(None) => {
|
||||||
|
error!("TCP connector: got unresolved address");
|
||||||
|
TcpConnectorResponse::Error(Some(ConnectError::Unresolved))
|
||||||
|
}
|
||||||
|
ConnectAddrs::One(Some(addr)) => TcpConnectorResponse::Response {
|
||||||
req: Some(req),
|
req: Some(req),
|
||||||
port,
|
port,
|
||||||
addrs: None,
|
addrs: None,
|
||||||
stream: Some(Box::pin(TcpStream::connect(addr))),
|
stream: Some(Box::pin(TcpStream::connect(addr))),
|
||||||
},
|
},
|
||||||
either::Either::Right(addrs) => TcpConnectorResponse::Response {
|
// when resolver returns multiple socket addr for request they would be popped from
|
||||||
|
// front end of queue and returns with the first successful tcp connection.
|
||||||
|
ConnectAddrs::Multi(addrs) => TcpConnectorResponse::Response {
|
||||||
req: Some(req),
|
req: Some(req),
|
||||||
port,
|
port,
|
||||||
addrs: Some(addrs),
|
addrs: Some(addrs),
|
||||||
@ -165,7 +134,7 @@ impl<T: Address> Future for TcpConnectorResponse<T> {
|
|||||||
port,
|
port,
|
||||||
);
|
);
|
||||||
if addrs.is_none() || addrs.as_ref().unwrap().is_empty() {
|
if addrs.is_none() || addrs.as_ref().unwrap().is_empty() {
|
||||||
return Poll::Ready(Err(err.into()));
|
return Poll::Ready(Err(ConnectError::Io(err)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use derive_more::{Display, From};
|
use derive_more::Display;
|
||||||
use trust_dns_resolver::error::ResolveError;
|
|
||||||
|
|
||||||
#[derive(Debug, From, Display)]
|
#[derive(Debug, Display)]
|
||||||
pub enum ConnectError {
|
pub enum ConnectError {
|
||||||
/// Failed to resolve the hostname
|
/// Failed to resolve the hostname
|
||||||
#[display(fmt = "Failed resolving hostname: {}", _0)]
|
#[display(fmt = "Failed resolving hostname: {}", _0)]
|
||||||
Resolver(ResolveError),
|
Resolver(Box<dyn std::error::Error>),
|
||||||
|
|
||||||
/// No dns records
|
/// No dns records
|
||||||
#[display(fmt = "No dns records found for the input")]
|
#[display(fmt = "No dns records found for the input")]
|
||||||
|
@ -4,6 +4,17 @@
|
|||||||
//!
|
//!
|
||||||
//! * `openssl` - enables TLS support via `openssl` crate
|
//! * `openssl` - enables TLS support via `openssl` crate
|
||||||
//! * `rustls` - enables TLS support via `rustls` crate
|
//! * `rustls` - enables TLS support via `rustls` crate
|
||||||
|
//!
|
||||||
|
//! ## Workflow of connector service:
|
||||||
|
//! - resolve [`Address`](self::connect::Address) with given [`Resolver`](self::resolve::Resolver)
|
||||||
|
//! and collect [`SocketAddrs`](std::net::SocketAddr).
|
||||||
|
//! - establish Tcp connection and return [`TcpStream`](tokio::net::TcpStream).
|
||||||
|
//!
|
||||||
|
//! ## Workflow of tls connector services:
|
||||||
|
//! - Establish [`TcpStream`](tokio::net::TcpStream) with connector service.
|
||||||
|
//! - Wrap around the stream and do connect handshake with remote address.
|
||||||
|
//! - Return certain stream type impl [`AsyncRead`](tokio::io::AsyncRead) and
|
||||||
|
//! [`AsyncWrite`](tokio::io::AsyncWrite)
|
||||||
|
|
||||||
mod connect;
|
mod connect;
|
||||||
mod connector;
|
mod connector;
|
||||||
@ -14,67 +25,26 @@ pub mod ssl;
|
|||||||
#[cfg(feature = "uri")]
|
#[cfg(feature = "uri")]
|
||||||
mod uri;
|
mod uri;
|
||||||
|
|
||||||
use actix_rt::{net::TcpStream, Arbiter};
|
use actix_rt::net::TcpStream;
|
||||||
use actix_service::{pipeline, pipeline_factory, Service, ServiceFactory};
|
use actix_service::{pipeline, pipeline_factory, Service, ServiceFactory};
|
||||||
use trust_dns_resolver::config::{ResolverConfig, ResolverOpts};
|
|
||||||
use trust_dns_resolver::system_conf::read_system_conf;
|
|
||||||
use trust_dns_resolver::TokioAsyncResolver as AsyncResolver;
|
|
||||||
|
|
||||||
pub mod resolver {
|
|
||||||
pub use trust_dns_resolver::config::{ResolverConfig, ResolverOpts};
|
|
||||||
pub use trust_dns_resolver::system_conf::read_system_conf;
|
|
||||||
pub use trust_dns_resolver::{error::ResolveError, AsyncResolver};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use self::connect::{Address, Connect, Connection};
|
pub use self::connect::{Address, Connect, Connection};
|
||||||
pub use self::connector::{TcpConnector, TcpConnectorFactory};
|
pub use self::connector::{TcpConnector, TcpConnectorFactory};
|
||||||
pub use self::error::ConnectError;
|
pub use self::error::ConnectError;
|
||||||
pub use self::resolve::{Resolver, ResolverFactory};
|
pub use self::resolve::{Resolve, Resolver, ResolverFactory};
|
||||||
pub use self::service::{ConnectService, ConnectServiceFactory, TcpConnectService};
|
pub use self::service::{ConnectService, ConnectServiceFactory, TcpConnectService};
|
||||||
|
|
||||||
pub async fn start_resolver(
|
|
||||||
cfg: ResolverConfig,
|
|
||||||
opts: ResolverOpts,
|
|
||||||
) -> Result<AsyncResolver, ConnectError> {
|
|
||||||
Ok(AsyncResolver::tokio(cfg, opts)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DefaultResolver(AsyncResolver);
|
|
||||||
|
|
||||||
pub(crate) async fn get_default_resolver() -> Result<AsyncResolver, ConnectError> {
|
|
||||||
if Arbiter::contains_item::<DefaultResolver>() {
|
|
||||||
Ok(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 = AsyncResolver::tokio(cfg, opts)?;
|
|
||||||
|
|
||||||
Arbiter::set_item(DefaultResolver(resolver.clone()));
|
|
||||||
Ok(resolver)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn start_default_resolver() -> Result<AsyncResolver, ConnectError> {
|
|
||||||
get_default_resolver().await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create TCP connector service.
|
/// Create TCP connector service.
|
||||||
pub fn new_connector<T: Address + 'static>(
|
pub fn new_connector<T: Address + 'static>(
|
||||||
resolver: AsyncResolver,
|
resolver: Resolver,
|
||||||
) -> impl Service<Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError> + Clone
|
) -> impl Service<Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError> + Clone
|
||||||
{
|
{
|
||||||
pipeline(Resolver::new(resolver)).and_then(TcpConnector::new())
|
pipeline(resolver).and_then(TcpConnector)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create TCP connector service factory.
|
/// Create TCP connector service factory.
|
||||||
pub fn new_connector_factory<T: Address + 'static>(
|
pub fn new_connector_factory<T: Address + 'static>(
|
||||||
resolver: AsyncResolver,
|
resolver: Resolver,
|
||||||
) -> impl ServiceFactory<
|
) -> impl ServiceFactory<
|
||||||
Connect<T>,
|
Connect<T>,
|
||||||
Config = (),
|
Config = (),
|
||||||
@ -82,14 +52,14 @@ pub fn new_connector_factory<T: Address + 'static>(
|
|||||||
Error = ConnectError,
|
Error = ConnectError,
|
||||||
InitError = (),
|
InitError = (),
|
||||||
> + Clone {
|
> + Clone {
|
||||||
pipeline_factory(ResolverFactory::new(resolver)).and_then(TcpConnectorFactory::new())
|
pipeline_factory(ResolverFactory::new(resolver)).and_then(TcpConnectorFactory)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create connector service with default parameters.
|
/// Create connector service with default parameters.
|
||||||
pub fn default_connector<T: Address + 'static>(
|
pub fn default_connector<T: Address + 'static>(
|
||||||
) -> impl Service<Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError> + Clone
|
) -> impl Service<Connect<T>, Response = Connection<T, TcpStream>, Error = ConnectError> + Clone
|
||||||
{
|
{
|
||||||
pipeline(Resolver::default()).and_then(TcpConnector::new())
|
new_connector(Resolver::Default)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create connector service factory with default parameters.
|
/// Create connector service factory with default parameters.
|
||||||
@ -100,5 +70,5 @@ pub fn default_connector_factory<T: Address + 'static>() -> impl ServiceFactory<
|
|||||||
Error = ConnectError,
|
Error = ConnectError,
|
||||||
InitError = (),
|
InitError = (),
|
||||||
> + Clone {
|
> + Clone {
|
||||||
pipeline_factory(ResolverFactory::default()).and_then(TcpConnectorFactory::new())
|
new_connector_factory(Resolver::Default)
|
||||||
}
|
}
|
||||||
|
308
actix-tls/src/connect/resolve.rs
Normal file → Executable file
308
actix-tls/src/connect/resolve.rs
Normal file → Executable file
@ -1,184 +1,225 @@
|
|||||||
use std::future::Future;
|
use std::{
|
||||||
use std::marker::PhantomData;
|
future::Future,
|
||||||
use std::net::SocketAddr;
|
io,
|
||||||
use std::pin::Pin;
|
net::SocketAddr,
|
||||||
use std::task::{Context, Poll};
|
pin::Pin,
|
||||||
|
rc::Rc,
|
||||||
|
task::{Context, Poll},
|
||||||
|
vec::IntoIter,
|
||||||
|
};
|
||||||
|
|
||||||
|
use actix_rt::task::{spawn_blocking, JoinHandle};
|
||||||
use actix_service::{Service, ServiceFactory};
|
use actix_service::{Service, ServiceFactory};
|
||||||
use futures_util::future::{ok, Either, Ready};
|
use futures_core::{future::LocalBoxFuture, ready};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use trust_dns_resolver::TokioAsyncResolver as AsyncResolver;
|
|
||||||
use trust_dns_resolver::{error::ResolveError, lookup_ip::LookupIp};
|
|
||||||
|
|
||||||
use super::connect::{Address, Connect};
|
use super::connect::{Address, Connect};
|
||||||
use super::error::ConnectError;
|
use super::error::ConnectError;
|
||||||
use super::get_default_resolver;
|
|
||||||
|
|
||||||
/// DNS Resolver Service factory
|
/// DNS Resolver Service factory
|
||||||
pub struct ResolverFactory<T> {
|
#[derive(Clone)]
|
||||||
resolver: Option<AsyncResolver>,
|
pub struct ResolverFactory {
|
||||||
_t: PhantomData<T>,
|
resolver: Resolver,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ResolverFactory<T> {
|
impl ResolverFactory {
|
||||||
/// Create new resolver instance with custom configuration and options.
|
pub fn new(resolver: Resolver) -> Self {
|
||||||
pub fn new(resolver: AsyncResolver) -> Self {
|
Self { resolver }
|
||||||
ResolverFactory {
|
|
||||||
resolver: Some(resolver),
|
|
||||||
_t: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn service(&self) -> Resolver<T> {
|
pub fn service(&self) -> Resolver {
|
||||||
Resolver {
|
self.resolver.clone()
|
||||||
resolver: self.resolver.clone(),
|
|
||||||
_t: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Default for ResolverFactory<T> {
|
impl<T: Address> ServiceFactory<Connect<T>> for ResolverFactory {
|
||||||
fn default() -> Self {
|
|
||||||
ResolverFactory {
|
|
||||||
resolver: None,
|
|
||||||
_t: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Clone for ResolverFactory<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
ResolverFactory {
|
|
||||||
resolver: self.resolver.clone(),
|
|
||||||
_t: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Address> ServiceFactory<Connect<T>> for ResolverFactory<T> {
|
|
||||||
type Response = Connect<T>;
|
type Response = Connect<T>;
|
||||||
type Error = ConnectError;
|
type Error = ConnectError;
|
||||||
type Config = ();
|
type Config = ();
|
||||||
type Service = Resolver<T>;
|
type Service = Resolver;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
|
||||||
|
|
||||||
fn new_service(&self, _: ()) -> Self::Future {
|
fn new_service(&self, _: ()) -> Self::Future {
|
||||||
ok(self.service())
|
let service = self.resolver.clone();
|
||||||
|
Box::pin(async { Ok(service) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DNS Resolver Service
|
/// DNS Resolver Service
|
||||||
pub struct Resolver<T> {
|
#[derive(Clone)]
|
||||||
resolver: Option<AsyncResolver>,
|
pub enum Resolver {
|
||||||
_t: PhantomData<T>,
|
Default,
|
||||||
|
Custom(Rc<dyn Resolve>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Resolver<T> {
|
/// trait for custom lookup with self defined resolver.
|
||||||
/// Create new resolver instance with custom configuration and options.
|
///
|
||||||
pub fn new(resolver: AsyncResolver) -> Self {
|
/// # Example:
|
||||||
Resolver {
|
/// ```rust
|
||||||
resolver: Some(resolver),
|
/// use std::net::SocketAddr;
|
||||||
_t: PhantomData,
|
///
|
||||||
|
/// use actix_tls::connect::{Resolve, Resolver};
|
||||||
|
/// use futures_util::future::LocalBoxFuture;
|
||||||
|
///
|
||||||
|
/// // use trust_dns_resolver as custom resolver.
|
||||||
|
/// use trust_dns_resolver::TokioAsyncResolver;
|
||||||
|
///
|
||||||
|
/// struct MyResolver {
|
||||||
|
/// trust_dns: TokioAsyncResolver,
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // impl Resolve trait and convert given host address str and port to SocketAddr.
|
||||||
|
/// impl Resolve for MyResolver {
|
||||||
|
/// fn lookup<'a>(
|
||||||
|
/// &'a self,
|
||||||
|
/// host: &'a str,
|
||||||
|
/// port: u16,
|
||||||
|
/// ) -> LocalBoxFuture<'a, Result<Vec<SocketAddr>, Box<dyn std::error::Error>>> {
|
||||||
|
/// Box::pin(async move {
|
||||||
|
/// let res = self
|
||||||
|
/// .trust_dns
|
||||||
|
/// .lookup_ip(host)
|
||||||
|
/// .await?
|
||||||
|
/// .iter()
|
||||||
|
/// .map(|ip| SocketAddr::new(ip, port))
|
||||||
|
/// .collect();
|
||||||
|
/// Ok(res)
|
||||||
|
/// })
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let resolver = MyResolver {
|
||||||
|
/// trust_dns: TokioAsyncResolver::tokio_from_system_conf().unwrap(),
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // construct custom resolver
|
||||||
|
/// let resolver = Resolver::new_custom(resolver);
|
||||||
|
///
|
||||||
|
/// // pass custom resolver to connector builder.
|
||||||
|
/// // connector would then be usable as a service or awc's connector.
|
||||||
|
/// let connector = actix_tls::connect::new_connector::<&str>(resolver.clone());
|
||||||
|
///
|
||||||
|
/// // resolver can be passed to connector factory where returned service factory
|
||||||
|
/// // can be used to construct new connector services.
|
||||||
|
/// let factory = actix_tls::connect::new_connector_factory::<&str>(resolver);
|
||||||
|
///```
|
||||||
|
pub trait Resolve {
|
||||||
|
fn lookup<'a>(
|
||||||
|
&'a self,
|
||||||
|
host: &'a str,
|
||||||
|
port: u16,
|
||||||
|
) -> LocalBoxFuture<'a, Result<Vec<SocketAddr>, Box<dyn std::error::Error>>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resolver {
|
||||||
|
/// Constructor for custom Resolve trait object and use it as resolver.
|
||||||
|
pub fn new_custom(resolver: impl Resolve + 'static) -> Self {
|
||||||
|
Self::Custom(Rc::new(resolver))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// look up with default resolver variant.
|
||||||
|
fn look_up<T: Address>(req: &Connect<T>) -> JoinHandle<io::Result<IntoIter<SocketAddr>>> {
|
||||||
|
let host = req.host();
|
||||||
|
// TODO: Connect should always return host with port if possible.
|
||||||
|
let host = if req
|
||||||
|
.host()
|
||||||
|
.splitn(2, ':')
|
||||||
|
.last()
|
||||||
|
.and_then(|p| p.parse::<u16>().ok())
|
||||||
|
.map(|p| p == req.port())
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
host.to_string()
|
||||||
|
} else {
|
||||||
|
format!("{}:{}", host, req.port())
|
||||||
|
};
|
||||||
|
|
||||||
|
spawn_blocking(move || std::net::ToSocketAddrs::to_socket_addrs(&host))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Default for Resolver<T> {
|
impl<T: Address> Service<Connect<T>> for Resolver {
|
||||||
fn default() -> Self {
|
|
||||||
Resolver {
|
|
||||||
resolver: None,
|
|
||||||
_t: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Clone for Resolver<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Resolver {
|
|
||||||
resolver: self.resolver.clone(),
|
|
||||||
_t: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Address> Service<Connect<T>> for Resolver<T> {
|
|
||||||
type Response = Connect<T>;
|
type Response = Connect<T>;
|
||||||
type Error = ConnectError;
|
type Error = ConnectError;
|
||||||
#[allow(clippy::type_complexity)]
|
type Future = ResolverFuture<T>;
|
||||||
type Future = Either<
|
|
||||||
Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>,
|
|
||||||
Ready<Result<Connect<T>, Self::Error>>,
|
|
||||||
>;
|
|
||||||
|
|
||||||
actix_service::always_ready!();
|
actix_service::always_ready!();
|
||||||
|
|
||||||
fn call(&mut self, mut req: Connect<T>) -> Self::Future {
|
fn call(&mut self, req: Connect<T>) -> Self::Future {
|
||||||
if req.addr.is_some() {
|
if !req.addr.is_none() {
|
||||||
Either::Right(ok(req))
|
ResolverFuture::Connected(Some(req))
|
||||||
} else if let Ok(ip) = req.host().parse() {
|
} else if let Ok(ip) = req.host().parse() {
|
||||||
req.addr = Some(either::Either::Left(SocketAddr::new(ip, req.port())));
|
let addr = SocketAddr::new(ip, req.port());
|
||||||
Either::Right(ok(req))
|
let req = req.set_addr(Some(addr));
|
||||||
|
ResolverFuture::Connected(Some(req))
|
||||||
} else {
|
} else {
|
||||||
let resolver = self.resolver.as_ref().map(AsyncResolver::clone);
|
|
||||||
Either::Left(Box::pin(async move {
|
|
||||||
trace!("DNS resolver: resolving host {:?}", req.host());
|
trace!("DNS resolver: resolving host {:?}", req.host());
|
||||||
let resolver = if let Some(resolver) = resolver {
|
|
||||||
resolver
|
match self {
|
||||||
} else {
|
Self::Default => {
|
||||||
get_default_resolver()
|
let fut = Self::look_up(&req);
|
||||||
|
ResolverFuture::LookUp(fut, Some(req))
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::Custom(resolver) => {
|
||||||
|
let resolver = Rc::clone(&resolver);
|
||||||
|
ResolverFuture::LookupCustom(Box::pin(async move {
|
||||||
|
let addrs = resolver
|
||||||
|
.lookup(req.host(), req.port())
|
||||||
.await
|
.await
|
||||||
.expect("Failed to get default resolver")
|
.map_err(ConnectError::Resolver)?;
|
||||||
};
|
|
||||||
ResolverFuture::new(req, &resolver).await
|
let req = req.set_addrs(addrs);
|
||||||
|
|
||||||
|
if req.addr.is_none() {
|
||||||
|
Err(ConnectError::NoRecords)
|
||||||
|
} else {
|
||||||
|
Ok(req)
|
||||||
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
type LookupIpFuture = Pin<Box<dyn Future<Output = Result<LookupIp, ResolveError>>>>;
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
/// Resolver future
|
|
||||||
pub struct ResolverFuture<T: Address> {
|
|
||||||
req: Option<Connect<T>>,
|
|
||||||
lookup: LookupIpFuture,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Address> ResolverFuture<T> {
|
|
||||||
pub fn new(req: Connect<T>, resolver: &AsyncResolver) -> Self {
|
|
||||||
let host = if let Some(host) = req.host().splitn(2, ':').next() {
|
|
||||||
host
|
|
||||||
} else {
|
|
||||||
req.host()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clone data to be moved to the lookup future
|
|
||||||
let host_clone = host.to_owned();
|
|
||||||
let resolver_clone = resolver.clone();
|
|
||||||
|
|
||||||
ResolverFuture {
|
|
||||||
lookup: Box::pin(async move {
|
|
||||||
let resolver = resolver_clone;
|
|
||||||
resolver.lookup_ip(host_clone).await
|
|
||||||
}),
|
|
||||||
req: Some(req),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ResolverFuture<T: Address> {
|
||||||
|
Connected(Option<Connect<T>>),
|
||||||
|
LookUp(
|
||||||
|
JoinHandle<io::Result<IntoIter<SocketAddr>>>,
|
||||||
|
Option<Connect<T>>,
|
||||||
|
),
|
||||||
|
LookupCustom(LocalBoxFuture<'static, Result<Connect<T>, ConnectError>>),
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Address> Future for ResolverFuture<T> {
|
impl<T: Address> Future for ResolverFuture<T> {
|
||||||
type Output = Result<Connect<T>, ConnectError>;
|
type Output = Result<Connect<T>, ConnectError>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let this = self.get_mut();
|
match self.get_mut() {
|
||||||
|
Self::Connected(conn) => Poll::Ready(Ok(conn
|
||||||
|
.take()
|
||||||
|
.expect("ResolverFuture polled after finished"))),
|
||||||
|
Self::LookUp(fut, req) => {
|
||||||
|
let res = match ready!(Pin::new(fut).poll(cx)) {
|
||||||
|
Ok(Ok(res)) => Ok(res),
|
||||||
|
Ok(Err(e)) => Err(ConnectError::Resolver(Box::new(e))),
|
||||||
|
Err(e) => Err(ConnectError::Io(e.into())),
|
||||||
|
};
|
||||||
|
|
||||||
match Pin::new(&mut this.lookup).poll(cx) {
|
let req = req.take().unwrap();
|
||||||
Poll::Pending => Poll::Pending,
|
|
||||||
Poll::Ready(Ok(ips)) => {
|
let addrs = res.map_err(|e| {
|
||||||
let req = this.req.take().unwrap();
|
trace!(
|
||||||
let port = req.port();
|
"DNS resolver: failed to resolve host {:?} err: {:?}",
|
||||||
let req = req.set_addrs(ips.iter().map(|ip| SocketAddr::new(ip, port)));
|
req.host(),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
e
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let req = req.set_addrs(addrs);
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
"DNS resolver: host {:?} resolved to {:?}",
|
"DNS resolver: host {:?} resolved to {:?}",
|
||||||
@ -192,14 +233,7 @@ impl<T: Address> Future for ResolverFuture<T> {
|
|||||||
Poll::Ready(Ok(req))
|
Poll::Ready(Ok(req))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Poll::Ready(Err(e)) => {
|
Self::LookupCustom(fut) => fut.as_mut().poll(cx),
|
||||||
trace!(
|
|
||||||
"DNS resolver: failed to resolve host {:?} err: {}",
|
|
||||||
this.req.as_ref().unwrap().host(),
|
|
||||||
e
|
|
||||||
);
|
|
||||||
Poll::Ready(Err(e.into()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
183
actix-tls/src/connect/service.rs
Normal file → Executable file
183
actix-tls/src/connect/service.rs
Normal file → Executable file
@ -1,42 +1,34 @@
|
|||||||
use std::future::Future;
|
use std::{
|
||||||
use std::pin::Pin;
|
future::Future,
|
||||||
use std::task::{Context, Poll};
|
pin::Pin,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
use actix_rt::net::TcpStream;
|
use actix_rt::net::TcpStream;
|
||||||
use actix_service::{Service, ServiceFactory};
|
use actix_service::{Service, ServiceFactory};
|
||||||
use either::Either;
|
use futures_core::{future::LocalBoxFuture, ready};
|
||||||
use futures_util::future::{ok, Ready};
|
|
||||||
use trust_dns_resolver::TokioAsyncResolver as AsyncResolver;
|
|
||||||
|
|
||||||
use super::connect::{Address, Connect, Connection};
|
use super::connect::{Address, Connect, Connection};
|
||||||
use super::connector::{TcpConnector, TcpConnectorFactory};
|
use super::connector::{TcpConnector, TcpConnectorFactory};
|
||||||
use super::error::ConnectError;
|
use super::error::ConnectError;
|
||||||
use super::resolve::{Resolver, ResolverFactory};
|
use super::resolve::{Resolver, ResolverFactory};
|
||||||
|
|
||||||
pub struct ConnectServiceFactory<T> {
|
pub struct ConnectServiceFactory {
|
||||||
tcp: TcpConnectorFactory<T>,
|
tcp: TcpConnectorFactory,
|
||||||
resolver: ResolverFactory<T>,
|
resolver: ResolverFactory,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ConnectServiceFactory<T> {
|
impl ConnectServiceFactory {
|
||||||
/// Construct new ConnectService factory
|
/// Construct new ConnectService factory
|
||||||
pub fn new() -> Self {
|
pub fn new(resolver: Resolver) -> Self {
|
||||||
ConnectServiceFactory {
|
ConnectServiceFactory {
|
||||||
tcp: TcpConnectorFactory::default(),
|
tcp: TcpConnectorFactory,
|
||||||
resolver: ResolverFactory::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct new connect service with custom dns resolver
|
|
||||||
pub fn with_resolver(resolver: AsyncResolver) -> Self {
|
|
||||||
ConnectServiceFactory {
|
|
||||||
tcp: TcpConnectorFactory::default(),
|
|
||||||
resolver: ResolverFactory::new(resolver),
|
resolver: ResolverFactory::new(resolver),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct new service
|
/// Construct new service
|
||||||
pub fn service(&self) -> ConnectService<T> {
|
pub fn service(&self) -> ConnectService {
|
||||||
ConnectService {
|
ConnectService {
|
||||||
tcp: self.tcp.service(),
|
tcp: self.tcp.service(),
|
||||||
resolver: self.resolver.service(),
|
resolver: self.resolver.service(),
|
||||||
@ -44,7 +36,7 @@ impl<T> ConnectServiceFactory<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Construct new tcp stream service
|
/// Construct new tcp stream service
|
||||||
pub fn tcp_service(&self) -> TcpConnectService<T> {
|
pub fn tcp_service(&self) -> TcpConnectService {
|
||||||
TcpConnectService {
|
TcpConnectService {
|
||||||
tcp: self.tcp.service(),
|
tcp: self.tcp.service(),
|
||||||
resolver: self.resolver.service(),
|
resolver: self.resolver.service(),
|
||||||
@ -52,44 +44,36 @@ impl<T> ConnectServiceFactory<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Default for ConnectServiceFactory<T> {
|
impl Clone for ConnectServiceFactory {
|
||||||
fn default() -> Self {
|
|
||||||
ConnectServiceFactory {
|
|
||||||
tcp: TcpConnectorFactory::default(),
|
|
||||||
resolver: ResolverFactory::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Clone for ConnectServiceFactory<T> {
|
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
ConnectServiceFactory {
|
ConnectServiceFactory {
|
||||||
tcp: self.tcp.clone(),
|
tcp: self.tcp,
|
||||||
resolver: self.resolver.clone(),
|
resolver: self.resolver.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Address> ServiceFactory<Connect<T>> for ConnectServiceFactory<T> {
|
impl<T: Address> ServiceFactory<Connect<T>> for ConnectServiceFactory {
|
||||||
type Response = Connection<T, TcpStream>;
|
type Response = Connection<T, TcpStream>;
|
||||||
type Error = ConnectError;
|
type Error = ConnectError;
|
||||||
type Config = ();
|
type Config = ();
|
||||||
type Service = ConnectService<T>;
|
type Service = ConnectService;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
|
||||||
|
|
||||||
fn new_service(&self, _: ()) -> Self::Future {
|
fn new_service(&self, _: ()) -> Self::Future {
|
||||||
ok(self.service())
|
let service = self.service();
|
||||||
|
Box::pin(async move { Ok(service) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ConnectService<T> {
|
pub struct ConnectService {
|
||||||
tcp: TcpConnector<T>,
|
tcp: TcpConnector,
|
||||||
resolver: Resolver<T>,
|
resolver: Resolver,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Address> Service<Connect<T>> for ConnectService<T> {
|
impl<T: Address> Service<Connect<T>> for ConnectService {
|
||||||
type Response = Connection<T, TcpStream>;
|
type Response = Connection<T, TcpStream>;
|
||||||
type Error = ConnectError;
|
type Error = ConnectError;
|
||||||
type Future = ConnectServiceResponse<T>;
|
type Future = ConnectServiceResponse<T>;
|
||||||
@ -98,65 +82,67 @@ impl<T: Address> Service<Connect<T>> for ConnectService<T> {
|
|||||||
|
|
||||||
fn call(&mut self, req: Connect<T>) -> Self::Future {
|
fn call(&mut self, req: Connect<T>) -> Self::Future {
|
||||||
ConnectServiceResponse {
|
ConnectServiceResponse {
|
||||||
state: ConnectState::Resolve(self.resolver.call(req)),
|
fut: ConnectFuture::Resolve(self.resolver.call(req)),
|
||||||
tcp: self.tcp.clone(),
|
tcp: self.tcp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ConnectState<T: Address> {
|
// helper enum to generic over futures of resolve and connect phase.
|
||||||
Resolve(<Resolver<T> as Service<Connect<T>>>::Future),
|
pub(crate) enum ConnectFuture<T: Address> {
|
||||||
Connect(<TcpConnector<T> as Service<Connect<T>>>::Future),
|
Resolve(<Resolver as Service<Connect<T>>>::Future),
|
||||||
|
Connect(<TcpConnector as Service<Connect<T>>>::Future),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Address> ConnectState<T> {
|
// helper enum to contain the future output of ConnectFuture
|
||||||
#[allow(clippy::type_complexity)]
|
pub(crate) enum ConnectOutput<T: Address> {
|
||||||
fn poll(
|
Resolved(Connect<T>),
|
||||||
|
Connected(Connection<T, TcpStream>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Address> ConnectFuture<T> {
|
||||||
|
fn poll_connect(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
) -> Either<Poll<Result<Connection<T, TcpStream>, ConnectError>>, Connect<T>> {
|
) -> Poll<Result<ConnectOutput<T>, ConnectError>> {
|
||||||
match self {
|
match self {
|
||||||
ConnectState::Resolve(ref mut fut) => match Pin::new(fut).poll(cx) {
|
ConnectFuture::Resolve(ref mut fut) => {
|
||||||
Poll::Pending => Either::Left(Poll::Pending),
|
Pin::new(fut).poll(cx).map_ok(ConnectOutput::Resolved)
|
||||||
Poll::Ready(Ok(res)) => Either::Right(res),
|
}
|
||||||
Poll::Ready(Err(err)) => Either::Left(Poll::Ready(Err(err))),
|
ConnectFuture::Connect(ref mut fut) => {
|
||||||
},
|
Pin::new(fut).poll(cx).map_ok(ConnectOutput::Connected)
|
||||||
ConnectState::Connect(ref mut fut) => Either::Left(Pin::new(fut).poll(cx)),
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConnectServiceResponse<T: Address> {
|
pub struct ConnectServiceResponse<T: Address> {
|
||||||
state: ConnectState<T>,
|
fut: ConnectFuture<T>,
|
||||||
tcp: TcpConnector<T>,
|
tcp: TcpConnector,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Address> Future for ConnectServiceResponse<T> {
|
impl<T: Address> Future for ConnectServiceResponse<T> {
|
||||||
type Output = Result<Connection<T, TcpStream>, ConnectError>;
|
type Output = Result<Connection<T, TcpStream>, ConnectError>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let res = match self.state.poll(cx) {
|
loop {
|
||||||
Either::Right(res) => {
|
match ready!(self.fut.poll_connect(cx))? {
|
||||||
self.state = ConnectState::Connect(self.tcp.call(res));
|
ConnectOutput::Resolved(res) => {
|
||||||
self.state.poll(cx)
|
self.fut = ConnectFuture::Connect(self.tcp.call(res));
|
||||||
|
}
|
||||||
|
ConnectOutput::Connected(res) => return Poll::Ready(Ok(res)),
|
||||||
}
|
}
|
||||||
Either::Left(res) => return res,
|
|
||||||
};
|
|
||||||
|
|
||||||
match res {
|
|
||||||
Either::Left(res) => res,
|
|
||||||
Either::Right(_) => panic!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TcpConnectService<T> {
|
pub struct TcpConnectService {
|
||||||
tcp: TcpConnector<T>,
|
tcp: TcpConnector,
|
||||||
resolver: Resolver<T>,
|
resolver: Resolver,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Address + 'static> Service<Connect<T>> for TcpConnectService<T> {
|
impl<T: Address> Service<Connect<T>> for TcpConnectService {
|
||||||
type Response = TcpStream;
|
type Response = TcpStream;
|
||||||
type Error = ConnectError;
|
type Error = ConnectError;
|
||||||
type Future = TcpConnectServiceResponse<T>;
|
type Future = TcpConnectServiceResponse<T>;
|
||||||
@ -165,61 +151,28 @@ impl<T: Address + 'static> Service<Connect<T>> for TcpConnectService<T> {
|
|||||||
|
|
||||||
fn call(&mut self, req: Connect<T>) -> Self::Future {
|
fn call(&mut self, req: Connect<T>) -> Self::Future {
|
||||||
TcpConnectServiceResponse {
|
TcpConnectServiceResponse {
|
||||||
state: TcpConnectState::Resolve(self.resolver.call(req)),
|
fut: ConnectFuture::Resolve(self.resolver.call(req)),
|
||||||
tcp: self.tcp.clone(),
|
tcp: self.tcp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TcpConnectState<T: Address> {
|
|
||||||
Resolve(<Resolver<T> as Service<Connect<T>>>::Future),
|
|
||||||
Connect(<TcpConnector<T> as Service<Connect<T>>>::Future),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Address> TcpConnectState<T> {
|
|
||||||
fn poll(
|
|
||||||
&mut self,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Either<Poll<Result<TcpStream, ConnectError>>, Connect<T>> {
|
|
||||||
match self {
|
|
||||||
TcpConnectState::Resolve(ref mut fut) => match Pin::new(fut).poll(cx) {
|
|
||||||
Poll::Pending => (),
|
|
||||||
Poll::Ready(Ok(res)) => return Either::Right(res),
|
|
||||||
Poll::Ready(Err(err)) => return Either::Left(Poll::Ready(Err(err))),
|
|
||||||
},
|
|
||||||
TcpConnectState::Connect(ref mut fut) => {
|
|
||||||
if let Poll::Ready(res) = Pin::new(fut).poll(cx) {
|
|
||||||
return match res {
|
|
||||||
Ok(conn) => Either::Left(Poll::Ready(Ok(conn.into_parts().0))),
|
|
||||||
Err(err) => Either::Left(Poll::Ready(Err(err))),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Either::Left(Poll::Pending)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TcpConnectServiceResponse<T: Address> {
|
pub struct TcpConnectServiceResponse<T: Address> {
|
||||||
state: TcpConnectState<T>,
|
fut: ConnectFuture<T>,
|
||||||
tcp: TcpConnector<T>,
|
tcp: TcpConnector,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Address> Future for TcpConnectServiceResponse<T> {
|
impl<T: Address> Future for TcpConnectServiceResponse<T> {
|
||||||
type Output = Result<TcpStream, ConnectError>;
|
type Output = Result<TcpStream, ConnectError>;
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let res = match self.state.poll(cx) {
|
loop {
|
||||||
Either::Right(res) => {
|
match ready!(self.fut.poll_connect(cx))? {
|
||||||
self.state = TcpConnectState::Connect(self.tcp.call(res));
|
ConnectOutput::Resolved(res) => {
|
||||||
self.state.poll(cx)
|
self.fut = ConnectFuture::Connect(self.tcp.call(res));
|
||||||
|
}
|
||||||
|
ConnectOutput::Connected(conn) => return Poll::Ready(Ok(conn.into_parts().0)),
|
||||||
}
|
}
|
||||||
Either::Left(res) => return res,
|
|
||||||
};
|
|
||||||
|
|
||||||
match res {
|
|
||||||
Either::Left(res) => res,
|
|
||||||
Either::Right(_) => panic!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
87
actix-tls/src/connect/ssl/openssl.rs
Normal file → Executable file
87
actix-tls/src/connect/ssl/openssl.rs
Normal file → Executable file
@ -1,23 +1,23 @@
|
|||||||
use std::future::Future;
|
use std::{
|
||||||
use std::marker::PhantomData;
|
fmt,
|
||||||
use std::pin::Pin;
|
future::Future,
|
||||||
use std::task::{Context, Poll};
|
io,
|
||||||
use std::{fmt, io};
|
pin::Pin,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
use actix_codec::{AsyncRead, AsyncWrite};
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
use actix_rt::net::TcpStream;
|
use actix_rt::net::TcpStream;
|
||||||
use actix_service::{Service, ServiceFactory};
|
use actix_service::{Service, ServiceFactory};
|
||||||
use futures_util::{
|
use futures_core::{future::LocalBoxFuture, ready};
|
||||||
future::{ready, Either, Ready},
|
|
||||||
ready,
|
|
||||||
};
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
pub use openssl::ssl::{Error as SslError, HandshakeError, SslConnector, SslMethod};
|
pub use openssl::ssl::{Error as SslError, HandshakeError, SslConnector, SslMethod};
|
||||||
pub use tokio_openssl::SslStream;
|
pub use tokio_openssl::SslStream;
|
||||||
use trust_dns_resolver::TokioAsyncResolver as AsyncResolver;
|
|
||||||
|
|
||||||
|
use crate::connect::resolve::Resolve;
|
||||||
use crate::connect::{
|
use crate::connect::{
|
||||||
Address, Connect, ConnectError, ConnectService, ConnectServiceFactory, Connection,
|
Address, Connect, ConnectError, ConnectService, ConnectServiceFactory, Connection, Resolver,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// OpenSSL connector factory
|
/// OpenSSL connector factory
|
||||||
@ -29,9 +29,7 @@ impl OpensslConnector {
|
|||||||
pub fn new(connector: SslConnector) -> Self {
|
pub fn new(connector: SslConnector) -> Self {
|
||||||
OpensslConnector { connector }
|
OpensslConnector { connector }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl OpensslConnector {
|
|
||||||
pub fn service(connector: SslConnector) -> OpensslConnectorService {
|
pub fn service(connector: SslConnector) -> OpensslConnectorService {
|
||||||
OpensslConnectorService { connector }
|
OpensslConnectorService { connector }
|
||||||
}
|
}
|
||||||
@ -55,12 +53,11 @@ where
|
|||||||
type Config = ();
|
type Config = ();
|
||||||
type Service = OpensslConnectorService;
|
type Service = OpensslConnectorService;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
|
||||||
|
|
||||||
fn new_service(&self, _: ()) -> Self::Future {
|
fn new_service(&self, _: ()) -> Self::Future {
|
||||||
ready(Ok(OpensslConnectorService {
|
let connector = self.connector.clone();
|
||||||
connector: self.connector.clone(),
|
Box::pin(async { Ok(OpensslConnectorService { connector }) })
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,29 +80,27 @@ where
|
|||||||
{
|
{
|
||||||
type Response = Connection<T, SslStream<U>>;
|
type Response = Connection<T, SslStream<U>>;
|
||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
#[allow(clippy::type_complexity)]
|
type Future = ConnectAsyncExt<T, U>;
|
||||||
type Future = Either<ConnectAsyncExt<T, U>, Ready<Result<Self::Response, Self::Error>>>;
|
|
||||||
|
|
||||||
actix_service::always_ready!();
|
actix_service::always_ready!();
|
||||||
|
|
||||||
fn call(&mut self, stream: Connection<T, U>) -> Self::Future {
|
fn call(&mut self, stream: Connection<T, U>) -> Self::Future {
|
||||||
trace!("SSL Handshake start for: {:?}", stream.host());
|
trace!("SSL Handshake start for: {:?}", stream.host());
|
||||||
let (io, stream) = stream.replace(());
|
let (io, stream) = stream.replace(());
|
||||||
let host = stream.host().to_string();
|
let host = stream.host();
|
||||||
|
|
||||||
match self.connector.configure() {
|
let config = self
|
||||||
Err(e) => Either::Right(ready(Err(io::Error::new(io::ErrorKind::Other, e)))),
|
.connector
|
||||||
Ok(config) => {
|
.configure()
|
||||||
let ssl = config
|
|
||||||
.into_ssl(&host)
|
|
||||||
.expect("SSL connect configuration was invalid.");
|
.expect("SSL connect configuration was invalid.");
|
||||||
|
|
||||||
Either::Left(ConnectAsyncExt {
|
let ssl = config
|
||||||
|
.into_ssl(host)
|
||||||
|
.expect("SSL connect configuration was invalid.");
|
||||||
|
|
||||||
|
ConnectAsyncExt {
|
||||||
io: Some(SslStream::new(ssl, io).unwrap()),
|
io: Some(SslStream::new(ssl, io).unwrap()),
|
||||||
stream: Some(stream),
|
stream: Some(stream),
|
||||||
_t: PhantomData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,7 +108,6 @@ where
|
|||||||
pub struct ConnectAsyncExt<T, U> {
|
pub struct ConnectAsyncExt<T, U> {
|
||||||
io: Option<SslStream<U>>,
|
io: Option<SslStream<U>>,
|
||||||
stream: Option<Connection<T, ()>>,
|
stream: Option<Connection<T, ()>>,
|
||||||
_t: PhantomData<U>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Address, U> Future for ConnectAsyncExt<T, U>
|
impl<T: Address, U> Future for ConnectAsyncExt<T, U>
|
||||||
@ -139,30 +133,30 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OpensslConnectServiceFactory<T> {
|
pub struct OpensslConnectServiceFactory {
|
||||||
tcp: ConnectServiceFactory<T>,
|
tcp: ConnectServiceFactory,
|
||||||
openssl: OpensslConnector,
|
openssl: OpensslConnector,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> OpensslConnectServiceFactory<T> {
|
impl OpensslConnectServiceFactory {
|
||||||
/// Construct new OpensslConnectService factory
|
/// Construct new OpensslConnectService factory
|
||||||
pub fn new(connector: SslConnector) -> Self {
|
pub fn new(connector: SslConnector) -> Self {
|
||||||
OpensslConnectServiceFactory {
|
OpensslConnectServiceFactory {
|
||||||
tcp: ConnectServiceFactory::default(),
|
tcp: ConnectServiceFactory::new(Resolver::Default),
|
||||||
openssl: OpensslConnector::new(connector),
|
openssl: OpensslConnector::new(connector),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct new connect service with custom DNS resolver
|
/// Construct new connect service with custom DNS resolver
|
||||||
pub fn with_resolver(connector: SslConnector, resolver: AsyncResolver) -> Self {
|
pub fn with_resolver(connector: SslConnector, resolver: impl Resolve + 'static) -> Self {
|
||||||
OpensslConnectServiceFactory {
|
OpensslConnectServiceFactory {
|
||||||
tcp: ConnectServiceFactory::with_resolver(resolver),
|
tcp: ConnectServiceFactory::new(Resolver::new_custom(resolver)),
|
||||||
openssl: OpensslConnector::new(connector),
|
openssl: OpensslConnector::new(connector),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct OpenSSL connect service
|
/// Construct OpenSSL connect service
|
||||||
pub fn service(&self) -> OpensslConnectService<T> {
|
pub fn service(&self) -> OpensslConnectService {
|
||||||
OpensslConnectService {
|
OpensslConnectService {
|
||||||
tcp: self.tcp.service(),
|
tcp: self.tcp.service(),
|
||||||
openssl: OpensslConnectorService {
|
openssl: OpensslConnectorService {
|
||||||
@ -172,7 +166,7 @@ impl<T> OpensslConnectServiceFactory<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Clone for OpensslConnectServiceFactory<T> {
|
impl Clone for OpensslConnectServiceFactory {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
OpensslConnectServiceFactory {
|
OpensslConnectServiceFactory {
|
||||||
tcp: self.tcp.clone(),
|
tcp: self.tcp.clone(),
|
||||||
@ -181,26 +175,27 @@ impl<T> Clone for OpensslConnectServiceFactory<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Address + 'static> ServiceFactory<Connect<T>> for OpensslConnectServiceFactory<T> {
|
impl<T: Address + 'static> ServiceFactory<Connect<T>> for OpensslConnectServiceFactory {
|
||||||
type Response = SslStream<TcpStream>;
|
type Response = SslStream<TcpStream>;
|
||||||
type Error = ConnectError;
|
type Error = ConnectError;
|
||||||
type Config = ();
|
type Config = ();
|
||||||
type Service = OpensslConnectService<T>;
|
type Service = OpensslConnectService;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
|
||||||
|
|
||||||
fn new_service(&self, _: ()) -> Self::Future {
|
fn new_service(&self, _: ()) -> Self::Future {
|
||||||
ready(Ok(self.service()))
|
let service = self.service();
|
||||||
|
Box::pin(async { Ok(service) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct OpensslConnectService<T> {
|
pub struct OpensslConnectService {
|
||||||
tcp: ConnectService<T>,
|
tcp: ConnectService,
|
||||||
openssl: OpensslConnectorService,
|
openssl: OpensslConnectorService,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Address + 'static> Service<Connect<T>> for OpensslConnectService<T> {
|
impl<T: Address + 'static> Service<Connect<T>> for OpensslConnectService {
|
||||||
type Response = SslStream<TcpStream>;
|
type Response = SslStream<TcpStream>;
|
||||||
type Error = ConnectError;
|
type Error = ConnectError;
|
||||||
type Future = OpensslConnectServiceResponse<T>;
|
type Future = OpensslConnectServiceResponse<T>;
|
||||||
@ -217,7 +212,7 @@ impl<T: Address + 'static> Service<Connect<T>> for OpensslConnectService<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct OpensslConnectServiceResponse<T: Address + 'static> {
|
pub struct OpensslConnectServiceResponse<T: Address + 'static> {
|
||||||
fut1: Option<<ConnectService<T> as Service<Connect<T>>>::Future>,
|
fut1: Option<<ConnectService as Service<Connect<T>>>::Future>,
|
||||||
fut2: Option<<OpensslConnectorService as Service<Connection<T, TcpStream>>>::Future>,
|
fut2: Option<<OpensslConnectorService as Service<Connection<T, TcpStream>>>::Future>,
|
||||||
openssl: OpensslConnectorService,
|
openssl: OpensslConnectorService,
|
||||||
}
|
}
|
||||||
|
25
actix-tls/src/connect/ssl/rustls.rs
Normal file → Executable file
25
actix-tls/src/connect/ssl/rustls.rs
Normal file → Executable file
@ -1,18 +1,18 @@
|
|||||||
use std::fmt;
|
use std::{
|
||||||
use std::future::Future;
|
fmt,
|
||||||
use std::pin::Pin;
|
future::Future,
|
||||||
use std::sync::Arc;
|
pin::Pin,
|
||||||
use std::task::{Context, Poll};
|
sync::Arc,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
pub use rustls::Session;
|
pub use rustls::Session;
|
||||||
pub use tokio_rustls::{client::TlsStream, rustls::ClientConfig};
|
pub use tokio_rustls::{client::TlsStream, rustls::ClientConfig};
|
||||||
|
pub use webpki_roots::TLS_SERVER_ROOTS;
|
||||||
|
|
||||||
use actix_codec::{AsyncRead, AsyncWrite};
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
use actix_service::{Service, ServiceFactory};
|
use actix_service::{Service, ServiceFactory};
|
||||||
use futures_util::{
|
use futures_core::{future::LocalBoxFuture, ready};
|
||||||
future::{ready, Ready},
|
|
||||||
ready,
|
|
||||||
};
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use tokio_rustls::{Connect, TlsConnector};
|
use tokio_rustls::{Connect, TlsConnector};
|
||||||
use webpki::DNSNameRef;
|
use webpki::DNSNameRef;
|
||||||
@ -53,12 +53,11 @@ where
|
|||||||
type Config = ();
|
type Config = ();
|
||||||
type Service = RustlsConnectorService;
|
type Service = RustlsConnectorService;
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
|
||||||
|
|
||||||
fn new_service(&self, _: ()) -> Self::Future {
|
fn new_service(&self, _: ()) -> Self::Future {
|
||||||
ready(Ok(RustlsConnectorService {
|
let connector = self.connector.clone();
|
||||||
connector: self.connector.clone(),
|
Box::pin(async { Ok(RustlsConnectorService { connector }) })
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
64
actix-tls/tests/test_connect.rs
Normal file → Executable file
64
actix-tls/tests/test_connect.rs
Normal file → Executable file
@ -1,17 +1,15 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
use actix_codec::{BytesCodec, Framed};
|
use actix_codec::{BytesCodec, Framed};
|
||||||
use actix_rt::net::TcpStream;
|
use actix_rt::net::TcpStream;
|
||||||
use actix_server::TestServer;
|
use actix_server::TestServer;
|
||||||
use actix_service::{fn_service, Service, ServiceFactory};
|
use actix_service::{fn_service, Service, ServiceFactory};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
use futures_core::future::LocalBoxFuture;
|
||||||
use futures_util::sink::SinkExt;
|
use futures_util::sink::SinkExt;
|
||||||
|
|
||||||
use actix_tls::connect::{
|
use actix_tls::connect::{self as actix_connect, Connect, Resolve, Resolver};
|
||||||
self as actix_connect,
|
|
||||||
resolver::{ResolverConfig, ResolverOpts},
|
|
||||||
Connect,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(all(feature = "connect", feature = "openssl"))]
|
#[cfg(all(feature = "connect", feature = "openssl"))]
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
@ -57,14 +55,13 @@ async fn test_static_str() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let resolver = actix_connect::start_default_resolver().await.unwrap();
|
let mut conn = actix_connect::default_connector();
|
||||||
let mut conn = actix_connect::new_connector(resolver.clone());
|
|
||||||
|
|
||||||
let con = conn.call(Connect::with("10", srv.addr())).await.unwrap();
|
let con = conn.call(Connect::with("10", srv.addr())).await.unwrap();
|
||||||
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
||||||
|
|
||||||
let connect = Connect::new(srv.host().to_owned());
|
let connect = Connect::new(srv.host().to_owned());
|
||||||
let mut conn = actix_connect::new_connector(resolver);
|
let mut conn = actix_connect::default_connector();
|
||||||
let con = conn.call(connect).await;
|
let con = conn.call(connect).await;
|
||||||
assert!(con.is_err());
|
assert!(con.is_err());
|
||||||
}
|
}
|
||||||
@ -79,10 +76,53 @@ async fn test_new_service() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let resolver =
|
let factory = actix_connect::default_connector_factory();
|
||||||
actix_connect::start_resolver(ResolverConfig::default(), ResolverOpts::default())
|
|
||||||
.await
|
let mut conn = factory.new_service(()).await.unwrap();
|
||||||
.unwrap();
|
let con = conn.call(Connect::with("10", srv.addr())).await.unwrap();
|
||||||
|
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_custom_resolver() {
|
||||||
|
use trust_dns_resolver::TokioAsyncResolver;
|
||||||
|
|
||||||
|
let srv = TestServer::with(|| {
|
||||||
|
fn_service(|io: TcpStream| async {
|
||||||
|
let mut framed = Framed::new(io, BytesCodec);
|
||||||
|
framed.send(Bytes::from_static(b"test")).await?;
|
||||||
|
Ok::<_, io::Error>(())
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
struct MyResolver {
|
||||||
|
trust_dns: TokioAsyncResolver,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resolve for MyResolver {
|
||||||
|
fn lookup<'a>(
|
||||||
|
&'a self,
|
||||||
|
host: &'a str,
|
||||||
|
port: u16,
|
||||||
|
) -> LocalBoxFuture<'a, Result<Vec<SocketAddr>, Box<dyn std::error::Error>>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let res = self
|
||||||
|
.trust_dns
|
||||||
|
.lookup_ip(host)
|
||||||
|
.await?
|
||||||
|
.iter()
|
||||||
|
.map(|ip| SocketAddr::new(ip, port))
|
||||||
|
.collect();
|
||||||
|
Ok(res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let resolver = MyResolver {
|
||||||
|
trust_dns: TokioAsyncResolver::tokio_from_system_conf().unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let resolver = Resolver::new_custom(resolver);
|
||||||
|
|
||||||
let factory = actix_connect::new_connector_factory(resolver);
|
let factory = actix_connect::new_connector_factory(resolver);
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ path = "src/lib.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.4.0-beta.1"
|
actix-codec = "0.4.0-beta.1"
|
||||||
actix-rt = "2.0.0-beta.2"
|
actix-rt = { version = "2.0.0-beta.2", default-features = false }
|
||||||
actix-service = "2.0.0-beta.3"
|
actix-service = "2.0.0-beta.3"
|
||||||
|
|
||||||
futures-core = { version = "0.3.7", default-features = false }
|
futures-core = { version = "0.3.7", default-features = false }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user