//! Native-TLS based connector service. //! //! See [`TlsConnector`] for main connector service factory docs. use std::io; use actix_rt::net::ActixStream; use actix_service::{Service, ServiceFactory}; use actix_utils::future::{ok, Ready}; use futures_core::future::LocalBoxFuture; use log::trace; use tokio_native_tls::{ native_tls::TlsConnector as NativeTlsConnector, TlsConnector as AsyncNativeTlsConnector, TlsStream as AsyncTlsStream, }; use crate::connect::{Connection, Host}; pub mod reexports { //! Re-exports from `native-tls` and `tokio-native-tls` that are useful for connectors. pub use tokio_native_tls::native_tls::TlsConnector; pub use tokio_native_tls::TlsStream as AsyncTlsStream; } /// Connector service and factory using `native-tls`. #[derive(Clone)] pub struct TlsConnector { connector: AsyncNativeTlsConnector, } impl TlsConnector { /// Constructs new connector service from a `native-tls` connector. /// /// This type is it's own service factory, so it can be used in that setting, too. pub fn new(connector: NativeTlsConnector) -> Self { Self { connector: AsyncNativeTlsConnector::from(connector), } } } impl ServiceFactory> for TlsConnector where IO: ActixStream + 'static, { type Response = Connection>; type Error = io::Error; type Config = (); type Service = Self; type InitError = (); type Future = Ready>; fn new_service(&self, _: ()) -> Self::Future { ok(self.clone()) } } /// The `native-tls` connector is both it's ServiceFactory and Service impl type. /// As the factory and service share the same type and state. impl Service> for TlsConnector where R: Host, IO: ActixStream + 'static, { type Response = Connection>; type Error = io::Error; type Future = LocalBoxFuture<'static, Result>; actix_service::always_ready!(); fn call(&self, stream: Connection) -> Self::Future { let (io, stream) = stream.replace_io(()); let connector = self.connector.clone(); Box::pin(async move { trace!("SSL Handshake start for: {:?}", stream.hostname()); connector .connect(stream.hostname(), io) .await .map(|res| { trace!("SSL Handshake success: {:?}", stream.hostname()); stream.replace_io(res).1 }) .map_err(|e| { trace!("SSL Handshake error: {:?}", e); io::Error::new(io::ErrorKind::Other, format!("{}", e)) }) }) } }