mirror of
https://github.com/fafhrd91/actix-net
synced 2024-11-30 18:44:36 +01:00
add rustls support for connect (#31)
This commit is contained in:
parent
41145040e1
commit
f913872159
@ -1,5 +1,9 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
|
## [0.2.2] - 2019-07-24
|
||||||
|
|
||||||
|
* Add `rustls` support
|
||||||
|
|
||||||
## [0.2.1] - 2019-07-17
|
## [0.2.1] - 2019-07-17
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -26,6 +26,9 @@ default = ["uri"]
|
|||||||
# openssl
|
# openssl
|
||||||
ssl = ["openssl", "tokio-openssl"]
|
ssl = ["openssl", "tokio-openssl"]
|
||||||
|
|
||||||
|
#rustls
|
||||||
|
rust-tls = ["rustls", "tokio-rustls", "webpki"]
|
||||||
|
|
||||||
# support http::Uri as connect address
|
# support http::Uri as connect address
|
||||||
uri = ["http"]
|
uri = ["http"]
|
||||||
|
|
||||||
@ -46,6 +49,11 @@ trust-dns-resolver = { version="0.11.0", default-features = false }
|
|||||||
openssl = { version="0.10", optional = true }
|
openssl = { version="0.10", optional = true }
|
||||||
tokio-openssl = { version="0.3", optional = true }
|
tokio-openssl = { version="0.3", optional = true }
|
||||||
|
|
||||||
|
#rustls
|
||||||
|
rustls = { version = "0.15.2", optional = true }
|
||||||
|
tokio-rustls = { version = "0.9.1", optional = true }
|
||||||
|
webpki = { version = "0.19", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
bytes = "0.4"
|
bytes = "0.4"
|
||||||
actix-test-server = { version="0.2.2", features=["ssl"] }
|
actix-test-server = { version="0.2.2", features=["ssl"] }
|
||||||
|
@ -4,3 +4,7 @@
|
|||||||
mod openssl;
|
mod openssl;
|
||||||
#[cfg(feature = "ssl")]
|
#[cfg(feature = "ssl")]
|
||||||
pub use self::openssl::OpensslConnector;
|
pub use self::openssl::OpensslConnector;
|
||||||
|
#[cfg(feature = "rust-tls")]
|
||||||
|
mod rustls;
|
||||||
|
#[cfg(feature = "rust-tls")]
|
||||||
|
pub use self::rustls::RustlsConnector;
|
||||||
|
130
actix-connect/src/ssl/rustls.rs
Normal file
130
actix-connect/src/ssl/rustls.rs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
use std::fmt;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
|
use actix_service::{NewService, Service};
|
||||||
|
use futures::{future::ok, future::FutureResult, Async, Future, Poll};
|
||||||
|
use webpki::DNSNameRef;
|
||||||
|
use tokio_rustls::{TlsConnector, TlsStream, Connect, rustls::{ClientConfig, ClientSession}};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{Address, Connection};
|
||||||
|
|
||||||
|
/// Rustls connector factory
|
||||||
|
pub struct RustlsConnector<T, U> {
|
||||||
|
connector: Arc<ClientConfig>,
|
||||||
|
_t: PhantomData<(T, U)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> RustlsConnector<T, U> {
|
||||||
|
pub fn new(connector: Arc<ClientConfig>) -> Self {
|
||||||
|
RustlsConnector {
|
||||||
|
connector,
|
||||||
|
_t: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> RustlsConnector<T, U>
|
||||||
|
where
|
||||||
|
T: Address,
|
||||||
|
U: AsyncRead + AsyncWrite + fmt::Debug,
|
||||||
|
{
|
||||||
|
pub fn service(
|
||||||
|
connector: Arc<ClientConfig>,
|
||||||
|
) -> impl Service<
|
||||||
|
Request = Connection<T, U>,
|
||||||
|
Response = Connection<T, TlsStream<U, ClientSession>>,
|
||||||
|
Error = std::io::Error,
|
||||||
|
> {
|
||||||
|
RustlsConnectorService {
|
||||||
|
connector: connector,
|
||||||
|
_t: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> Clone for RustlsConnector<T, U> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
connector: self.connector.clone(),
|
||||||
|
_t: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Address, U> NewService for RustlsConnector<T, U>
|
||||||
|
where
|
||||||
|
U: AsyncRead + AsyncWrite + fmt::Debug,
|
||||||
|
{
|
||||||
|
type Request = Connection<T, U>;
|
||||||
|
type Response = Connection<T, TlsStream<U, ClientSession>>;
|
||||||
|
type Error = std::io::Error;
|
||||||
|
type Config = ();
|
||||||
|
type Service = RustlsConnectorService<T, U>;
|
||||||
|
type InitError = ();
|
||||||
|
type Future = FutureResult<Self::Service, Self::InitError>;
|
||||||
|
|
||||||
|
fn new_service(&self, _: &()) -> Self::Future {
|
||||||
|
ok(RustlsConnectorService {
|
||||||
|
connector: self.connector.clone(),
|
||||||
|
_t: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RustlsConnectorService<T, U> {
|
||||||
|
connector: Arc<ClientConfig>,
|
||||||
|
_t: PhantomData<(T, U)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Address, U> Service for RustlsConnectorService<T, U>
|
||||||
|
where
|
||||||
|
U: AsyncRead + AsyncWrite + fmt::Debug,
|
||||||
|
{
|
||||||
|
type Request = Connection<T, U>;
|
||||||
|
type Response = Connection<T, TlsStream<U, ClientSession>>;
|
||||||
|
type Error = std::io::Error;
|
||||||
|
type Future = ConnectAsyncExt<T, U>;
|
||||||
|
|
||||||
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
|
Ok(Async::Ready(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self, stream: Connection<T, U>) -> Self::Future {
|
||||||
|
trace!("SSL Handshake start for: {:?}", stream.host());
|
||||||
|
let (io, stream) = stream.replace(());
|
||||||
|
let host = DNSNameRef::try_from_ascii_str(stream.host()).unwrap();
|
||||||
|
ConnectAsyncExt {
|
||||||
|
fut: TlsConnector::from(self.connector.clone()).connect(host, io),
|
||||||
|
stream: Some(stream),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ConnectAsyncExt<T, U> {
|
||||||
|
fut: Connect<U>,
|
||||||
|
stream: Option<Connection<T, ()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Address, U> Future for ConnectAsyncExt<T, U>
|
||||||
|
where
|
||||||
|
U: AsyncRead + AsyncWrite + fmt::Debug,
|
||||||
|
{
|
||||||
|
type Item = Connection<T, TlsStream<U, ClientSession>>;
|
||||||
|
type Error = std::io::Error;
|
||||||
|
|
||||||
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
|
match self.fut.poll().map_err(|e| {
|
||||||
|
trace!("SSL Handshake error: {:?}", e);
|
||||||
|
e
|
||||||
|
})? {
|
||||||
|
Async::Ready(stream) => {
|
||||||
|
let s = self.stream.take().unwrap();
|
||||||
|
trace!("SSL Handshake success: {:?}", s.host());
|
||||||
|
Ok(Async::Ready(s.replace(stream).1))
|
||||||
|
}
|
||||||
|
Async::NotReady => Ok(Async::NotReady),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,22 @@ fn test_string() {
|
|||||||
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rust-tls")]
|
||||||
|
#[test]
|
||||||
|
fn test_rustls_string() {
|
||||||
|
let mut srv = TestServer::with(|| {
|
||||||
|
service_fn(|io: Io<tokio_tcp::TcpStream>| {
|
||||||
|
Framed::new(io.into_parts().0, BytesCodec)
|
||||||
|
.send(Bytes::from_static(b"test"))
|
||||||
|
.then(|_| Ok::<_, ()>(()))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut conn = default_connector();
|
||||||
|
let addr = format!("localhost:{}", srv.port());
|
||||||
|
let con = srv.run_on(move || conn.call(addr.into())).unwrap();
|
||||||
|
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_static_str() {
|
fn test_static_str() {
|
||||||
let mut srv = TestServer::with(|| {
|
let mut srv = TestServer::with(|| {
|
||||||
@ -107,3 +123,20 @@ fn test_uri() {
|
|||||||
let con = srv.run_on(move || conn.call(addr.into())).unwrap();
|
let con = srv.run_on(move || conn.call(addr.into())).unwrap();
|
||||||
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rust-tls")]
|
||||||
|
#[test]
|
||||||
|
fn test_rustls_uri() {
|
||||||
|
let mut srv = TestServer::with(|| {
|
||||||
|
service_fn(|io: Io<tokio_tcp::TcpStream>| {
|
||||||
|
Framed::new(io.into_parts().0, BytesCodec)
|
||||||
|
.send(Bytes::from_static(b"test"))
|
||||||
|
.then(|_| Ok::<_, ()>(()))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut conn = default_connector();
|
||||||
|
let addr = Uri::try_from(format!("https://localhost:{}", srv.port())).unwrap();
|
||||||
|
let con = srv.run_on(move || conn.call(addr.into())).unwrap();
|
||||||
|
assert_eq!(con.peer_addr().unwrap(), srv.addr());
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user