actix_tls/connect/
native_tls.rs

1//! Native-TLS based connector service.
2//!
3//! See [`TlsConnector`] for main connector service factory docs.
4
5use std::io;
6
7use actix_rt::net::ActixStream;
8use actix_service::{Service, ServiceFactory};
9use actix_utils::future::{ok, Ready};
10use futures_core::future::LocalBoxFuture;
11use tokio_native_tls::{
12    native_tls::TlsConnector as NativeTlsConnector, TlsConnector as AsyncNativeTlsConnector,
13    TlsStream as AsyncTlsStream,
14};
15use tracing::trace;
16
17use crate::connect::{Connection, Host};
18
19pub mod reexports {
20    //! Re-exports from `native-tls` and `tokio-native-tls` that are useful for connectors.
21
22    pub use tokio_native_tls::{native_tls::TlsConnector, TlsStream as AsyncTlsStream};
23}
24
25/// Connector service and factory using `native-tls`.
26#[derive(Clone)]
27pub struct TlsConnector {
28    connector: AsyncNativeTlsConnector,
29}
30
31impl TlsConnector {
32    /// Constructs new connector service from a `native-tls` connector.
33    ///
34    /// This type is it's own service factory, so it can be used in that setting, too.
35    pub fn new(connector: NativeTlsConnector) -> Self {
36        Self {
37            connector: AsyncNativeTlsConnector::from(connector),
38        }
39    }
40}
41
42impl<R: Host, IO> ServiceFactory<Connection<R, IO>> for TlsConnector
43where
44    IO: ActixStream + 'static,
45{
46    type Response = Connection<R, AsyncTlsStream<IO>>;
47    type Error = io::Error;
48    type Config = ();
49    type Service = Self;
50    type InitError = ();
51    type Future = Ready<Result<Self::Service, Self::InitError>>;
52
53    fn new_service(&self, _: ()) -> Self::Future {
54        ok(self.clone())
55    }
56}
57
58/// The `native-tls` connector is both it's ServiceFactory and Service impl type.
59/// As the factory and service share the same type and state.
60impl<R, IO> Service<Connection<R, IO>> for TlsConnector
61where
62    R: Host,
63    IO: ActixStream + 'static,
64{
65    type Response = Connection<R, AsyncTlsStream<IO>>;
66    type Error = io::Error;
67    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
68
69    actix_service::always_ready!();
70
71    fn call(&self, stream: Connection<R, IO>) -> Self::Future {
72        let (io, stream) = stream.replace_io(());
73        let connector = self.connector.clone();
74
75        Box::pin(async move {
76            trace!("TLS handshake start for: {:?}", stream.hostname());
77            connector
78                .connect(stream.hostname(), io)
79                .await
80                .map(|res| {
81                    trace!("TLS handshake success: {:?}", stream.hostname());
82                    stream.replace_io(res).1
83                })
84                .map_err(|err| {
85                    trace!("TLS handshake error: {err:?}");
86                    io::Error::other(format!("{err}"))
87                })
88        })
89    }
90}