1
0
mirror of https://github.com/actix/actix-extras.git synced 2025-06-26 02:19:22 +02:00

add rustls

This commit is contained in:
Marat Safin
2018-07-29 09:43:04 +03:00
parent b4ed564e5d
commit 196da6d570
9 changed files with 413 additions and 47 deletions

View File

@ -22,12 +22,25 @@ use openssl::ssl::{Error as OpensslError, SslConnector, SslMethod};
use tokio_openssl::SslConnectorExt;
#[cfg(all(feature = "tls", not(feature = "alpn")))]
use native_tls::{Error as TlsError, TlsConnector};
use native_tls::{Error as TlsError, TlsConnector, TlsStream};
#[cfg(all(feature = "tls", not(feature = "alpn")))]
use tokio_tls::TlsConnectorExt;
#[cfg(all(feature = "rust-tls", not(any(feature = "alpn", feature = "tls"))))]
use rustls::ClientConfig;
#[cfg(all(feature = "rust-tls", not(any(feature = "alpn", feature = "tls"))))]
use std::io::Error as TLSError;
#[cfg(all(feature = "rust-tls", not(any(feature = "alpn", feature = "tls"))))]
use std::sync::Arc;
#[cfg(all(feature = "rust-tls", not(any(feature = "alpn", feature = "tls"))))]
use tokio_rustls::ClientConfigExt;
#[cfg(all(feature = "rust-tls", not(any(feature = "alpn", feature = "tls"))))]
use webpki::DNSNameRef;
#[cfg(all(feature = "rust-tls", not(any(feature = "alpn", feature = "tls"))))]
use webpki_roots;
use server::IoStream;
use {HAS_OPENSSL, HAS_TLS};
use {HAS_OPENSSL, HAS_TLS, HAS_RUSTLS};
/// Client connector usage stats
#[derive(Default, Message)]
@ -139,6 +152,11 @@ pub enum ClientConnectorError {
#[fail(display = "{}", _0)]
SslError(#[cause] TlsError),
/// SSL error
#[cfg(all(feature = "rust-tls", not(any(feature = "alpn", feature = "tls"))))]
#[fail(display = "{}", _0)]
SslError(#[cause] TLSError),
/// Resolver error
#[fail(display = "{}", _0)]
Resolver(#[cause] ResolverError),
@ -193,6 +211,8 @@ pub struct ClientConnector {
connector: SslConnector,
#[cfg(all(feature = "tls", not(feature = "alpn")))]
connector: TlsConnector,
#[cfg(all(feature = "rust-tls", not(any(feature = "alpn", feature = "tls"))))]
connector: Arc<ClientConfig>,
stats: ClientConnectorStats,
subscriber: Option<Recipient<ClientConnectorStats>>,
@ -262,8 +282,16 @@ impl Default for ClientConnector {
paused: Paused::No,
}
}
#[cfg(all(feature = "rust-tls", not(any(feature = "alpn", feature = "tls"))))]
{
let mut config = ClientConfig::new();
config
.root_store
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
ClientConnector::with_connector(Arc::new(config))
}
#[cfg(not(any(feature = "alpn", feature = "tls")))]
#[cfg(not(any(feature = "alpn", feature = "tls", feature = "rust-tls")))]
{
let (tx, rx) = mpsc::unbounded();
ClientConnector {
@ -325,7 +353,7 @@ impl ClientConnector {
/// # actix::System::current().stop();
/// Ok(())
/// })
/// );
/// });
/// }
/// ```
pub fn with_connector(connector: SslConnector) -> ClientConnector {
@ -352,6 +380,75 @@ impl ClientConnector {
}
}
#[cfg(all(feature = "rust-tls", not(any(feature = "alpn", feature = "tls"))))]
/// Create `ClientConnector` actor with custom `SslConnector` instance.
///
/// By default `ClientConnector` uses very a simple SSL configuration.
/// With `with_connector` method it is possible to use a custom
/// `SslConnector` object.
///
/// ```rust
/// # #![cfg(feature = "rust-tls")]
/// # extern crate actix_web;
/// # extern crate futures;
/// # extern crate tokio;
/// # use futures::{future, Future};
/// # use std::io::Write;
/// # use std::process;
/// # use actix_web::actix::Actor;
/// extern crate rustls;
/// extern crate webpki_roots;
/// use actix_web::{actix, client::ClientConnector, client::Connect};
///
/// use rustls::ClientConfig;
/// use std::sync::Arc;
///
/// fn main() {
/// actix::run(|| {
/// // Start `ClientConnector` with custom `ClientConfig`
/// let mut config = ClientConfig::new();
/// config
/// .root_store
/// .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
/// let conn = ClientConnector::with_connector(Arc::new(config)).start();
///
/// conn.send(
/// Connect::new("https://www.rust-lang.org").unwrap()) // <- connect to host
/// .map_err(|_| ())
/// .and_then(|res| {
/// if let Ok(mut stream) = res {
/// stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
/// }
/// # actix::System::current().stop();
/// Ok(())
/// })
/// });
/// }
/// ```
pub fn with_connector(connector: Arc<ClientConfig>) -> ClientConnector {
let (tx, rx) = mpsc::unbounded();
ClientConnector {
connector,
stats: ClientConnectorStats::default(),
subscriber: None,
acq_tx: tx,
acq_rx: Some(rx),
resolver: None,
conn_lifetime: Duration::from_secs(75),
conn_keep_alive: Duration::from_secs(15),
limit: 100,
limit_per_host: 0,
acquired: 0,
acquired_per_host: HashMap::new(),
available: HashMap::new(),
to_close: Vec::new(),
waiters: Some(HashMap::new()),
wait_timeout: None,
paused: Paused::No,
}
}
/// Set total number of simultaneous connections.
///
/// If limit is 0, the connector has no limit.
@ -709,7 +806,51 @@ impl ClientConnector {
}
}
#[cfg(not(any(feature = "alpn", feature = "tls")))]
#[cfg(all(feature = "rust-tls", not(any(feature = "alpn", feature = "tls"))))]
match res {
Err(err) => {
let _ = waiter.tx.send(Err(err.into()));
fut::Either::B(fut::err(()))
}
Ok(stream) => {
act.stats.opened += 1;
if conn.0.ssl {
let host = DNSNameRef::try_from_ascii_str(&key.host).unwrap();
fut::Either::A(
act.connector
.connect_async(host, stream)
.into_actor(act)
.then(move |res, _, _| {
match res {
Err(e) => {
let _ = waiter.tx.send(Err(
ClientConnectorError::SslError(e),
));
}
Ok(stream) => {
let _ =
waiter.tx.send(Ok(Connection::new(
conn.0.clone(),
Some(conn),
Box::new(stream),
)));
}
}
fut::ok(())
}),
)
} else {
let _ = waiter.tx.send(Ok(Connection::new(
conn.0.clone(),
Some(conn),
Box::new(stream),
)));
fut::Either::B(fut::ok(()))
}
}
}
#[cfg(not(any(feature = "alpn", feature = "tls", feature = "rust-tls")))]
match res {
Err(err) => {
let _ = waiter.tx.send(Err(err.into()));
@ -784,7 +925,7 @@ impl Handler<Connect> for ClientConnector {
};
// check ssl availability
if proto.is_secure() && !HAS_OPENSSL && !HAS_TLS {
if proto.is_secure() && !HAS_OPENSSL && !HAS_TLS && !HAS_RUSTLS {
return ActorResponse::reply(Err(ClientConnectorError::SslIsNotSupported));
}