actix_tls/connect/
rustls_0_23.rs1use std::{
6 future::Future,
7 io,
8 pin::Pin,
9 sync::Arc,
10 task::{Context, Poll},
11};
12
13use actix_rt::net::ActixStream;
14use actix_service::{Service, ServiceFactory};
15use actix_utils::future::{ok, Ready};
16use futures_core::ready;
17use rustls_pki_types_1::ServerName;
18use tokio_rustls::{
19 client::TlsStream as AsyncTlsStream, rustls::ClientConfig, Connect as RustlsConnect,
20 TlsConnector as RustlsTlsConnector,
21};
22use tokio_rustls_026 as tokio_rustls;
23
24use crate::connect::{Connection, Host};
25
26pub mod reexports {
27 pub use tokio_rustls_026::{client::TlsStream as AsyncTlsStream, rustls::ClientConfig};
30 #[cfg(feature = "rustls-0_23-webpki-roots")]
31 pub use webpki_roots_026::TLS_SERVER_ROOTS;
32}
33
34#[cfg(feature = "rustls-0_23-native-roots")]
40pub fn native_roots_cert_store() -> io::Result<tokio_rustls::rustls::RootCertStore> {
41 let mut root_certs = tokio_rustls::rustls::RootCertStore::empty();
42
43 for cert in rustls_native_certs_07::load_native_certs()? {
44 root_certs.add(cert).unwrap();
45 }
46
47 Ok(root_certs)
48}
49
50#[cfg(feature = "rustls-0_23-webpki-roots")]
52pub fn webpki_roots_cert_store() -> tokio_rustls::rustls::RootCertStore {
53 let mut root_certs = tokio_rustls::rustls::RootCertStore::empty();
54 root_certs.extend(webpki_roots_026::TLS_SERVER_ROOTS.to_owned());
55 root_certs
56}
57
58#[derive(Clone)]
60pub struct TlsConnector {
61 connector: Arc<ClientConfig>,
62}
63
64impl TlsConnector {
65 pub fn new(connector: Arc<ClientConfig>) -> Self {
67 TlsConnector { connector }
68 }
69
70 pub fn service(connector: Arc<ClientConfig>) -> TlsConnectorService {
72 TlsConnectorService { connector }
73 }
74}
75
76impl<R, IO> ServiceFactory<Connection<R, IO>> for TlsConnector
77where
78 R: Host,
79 IO: ActixStream + 'static,
80{
81 type Response = Connection<R, AsyncTlsStream<IO>>;
82 type Error = io::Error;
83 type Config = ();
84 type Service = TlsConnectorService;
85 type InitError = ();
86 type Future = Ready<Result<Self::Service, Self::InitError>>;
87
88 fn new_service(&self, _: ()) -> Self::Future {
89 ok(TlsConnectorService {
90 connector: self.connector.clone(),
91 })
92 }
93}
94
95#[derive(Clone)]
97pub struct TlsConnectorService {
98 connector: Arc<ClientConfig>,
99}
100
101impl<R, IO> Service<Connection<R, IO>> for TlsConnectorService
102where
103 R: Host,
104 IO: ActixStream,
105{
106 type Response = Connection<R, AsyncTlsStream<IO>>;
107 type Error = io::Error;
108 type Future = ConnectFut<R, IO>;
109
110 actix_service::always_ready!();
111
112 fn call(&self, connection: Connection<R, IO>) -> Self::Future {
113 tracing::trace!("TLS handshake start for: {:?}", connection.hostname());
114 let (stream, conn) = connection.replace_io(());
115
116 match ServerName::try_from(conn.hostname()) {
117 Ok(host) => ConnectFut::Future {
118 connect: RustlsTlsConnector::from(Arc::clone(&self.connector))
119 .connect(host.to_owned(), stream),
120 connection: Some(conn),
121 },
122 Err(_) => ConnectFut::InvalidServerName,
123 }
124 }
125}
126
127#[doc(hidden)]
129#[allow(clippy::large_enum_variant)]
130pub enum ConnectFut<R, IO> {
131 InvalidServerName,
132 Future {
133 connect: RustlsConnect<IO>,
134 connection: Option<Connection<R, ()>>,
135 },
136}
137
138impl<R, IO> Future for ConnectFut<R, IO>
139where
140 R: Host,
141 IO: ActixStream,
142{
143 type Output = io::Result<Connection<R, AsyncTlsStream<IO>>>;
144
145 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
146 match self.get_mut() {
147 Self::InvalidServerName => Poll::Ready(Err(io::Error::new(
148 io::ErrorKind::InvalidInput,
149 "connection parameters specified invalid server name",
150 ))),
151
152 Self::Future {
153 connect,
154 connection,
155 } => {
156 let stream = ready!(Pin::new(connect).poll(cx))?;
157 let connection = connection.take().unwrap();
158 tracing::trace!("TLS handshake success: {:?}", connection.hostname());
159 Poll::Ready(Ok(connection.replace_io(stream).1))
160 }
161 }
162 }
163}