#
actix_tls/connect/
native_tls.rs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90

    //! 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 tokio_native_tls::{
        native_tls::TlsConnector as NativeTlsConnector, TlsConnector as AsyncNativeTlsConnector,
        TlsStream as AsyncTlsStream,
    };
    use tracing::trace;

    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, 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<R: Host, IO> ServiceFactory<Connection<R, IO>> for TlsConnector
    where
        IO: ActixStream + 'static,
    {
        type Response = Connection<R, AsyncTlsStream<IO>>;
        type Error = io::Error;
        type Config = ();
        type Service = Self;
        type InitError = ();
        type Future = Ready<Result<Self::Service, Self::InitError>>;

        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<R, IO> Service<Connection<R, IO>> for TlsConnector
    where
        R: Host,
        IO: ActixStream + 'static,
    {
        type Response = Connection<R, AsyncTlsStream<IO>>;
        type Error = io::Error;
        type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;

        actix_service::always_ready!();

        fn call(&self, stream: Connection<R, IO>) -> Self::Future {
            let (io, stream) = stream.replace_io(());
            let connector = self.connector.clone();

            Box::pin(async move {
                trace!("TLS handshake start for: {:?}", stream.hostname());
                connector
                    .connect(stream.hostname(), io)
                    .await
                    .map(|res| {
                        trace!("TLS handshake success: {:?}", stream.hostname());
                        stream.replace_io(res).1
                    })
                    .map_err(|e| {
                        trace!("TLS handshake error: {:?}", e);
                        io::Error::new(io::ErrorKind::Other, format!("{}", e))
                    })
            })
        }
    }