actix_tls/connect/
rustls_0_22.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_025 as tokio_rustls;
23
24use crate::connect::{Connection, Host};
25
26pub mod reexports {
27 pub use tokio_rustls_025::{client::TlsStream as AsyncTlsStream, rustls::ClientConfig};
30 #[cfg(feature = "rustls-0_22-webpki-roots")]
31 pub use webpki_roots_026::TLS_SERVER_ROOTS;
32}
33
34#[cfg(feature = "rustls-0_22-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 let certs = rustls_native_certs_08::load_native_certs();
44 if let Some(err) = certs.errors.into_iter().next() {
45 return Err(io::Error::other(err));
46 }
47
48 for cert in certs.certs {
49 root_certs.add(cert).unwrap();
50 }
51
52 Ok(root_certs)
53}
54
55#[cfg(feature = "rustls-0_22-webpki-roots")]
57pub fn webpki_roots_cert_store() -> tokio_rustls::rustls::RootCertStore {
58 let mut root_certs = tokio_rustls::rustls::RootCertStore::empty();
59 root_certs.extend(webpki_roots_026::TLS_SERVER_ROOTS.to_owned());
60 root_certs
61}
62
63#[derive(Clone)]
65pub struct TlsConnector {
66 connector: Arc<ClientConfig>,
67}
68
69impl TlsConnector {
70 pub fn new(connector: Arc<ClientConfig>) -> Self {
72 TlsConnector { connector }
73 }
74
75 pub fn service(connector: Arc<ClientConfig>) -> TlsConnectorService {
77 TlsConnectorService { connector }
78 }
79}
80
81impl<R, IO> ServiceFactory<Connection<R, IO>> for TlsConnector
82where
83 R: Host,
84 IO: ActixStream + 'static,
85{
86 type Response = Connection<R, AsyncTlsStream<IO>>;
87 type Error = io::Error;
88 type Config = ();
89 type Service = TlsConnectorService;
90 type InitError = ();
91 type Future = Ready<Result<Self::Service, Self::InitError>>;
92
93 fn new_service(&self, _: ()) -> Self::Future {
94 ok(TlsConnectorService {
95 connector: self.connector.clone(),
96 })
97 }
98}
99
100#[derive(Clone)]
102pub struct TlsConnectorService {
103 connector: Arc<ClientConfig>,
104}
105
106impl<R, IO> Service<Connection<R, IO>> for TlsConnectorService
107where
108 R: Host,
109 IO: ActixStream,
110{
111 type Response = Connection<R, AsyncTlsStream<IO>>;
112 type Error = io::Error;
113 type Future = ConnectFut<R, IO>;
114
115 actix_service::always_ready!();
116
117 fn call(&self, connection: Connection<R, IO>) -> Self::Future {
118 tracing::trace!("TLS handshake start for: {:?}", connection.hostname());
119 let (stream, conn) = connection.replace_io(());
120
121 match ServerName::try_from(conn.hostname()) {
122 Ok(host) => ConnectFut::Future {
123 connect: RustlsTlsConnector::from(Arc::clone(&self.connector))
124 .connect(host.to_owned(), stream),
125 connection: Some(conn),
126 },
127 Err(_) => ConnectFut::InvalidServerName,
128 }
129 }
130}
131
132#[doc(hidden)]
134#[allow(clippy::large_enum_variant)]
135pub enum ConnectFut<R, IO> {
136 InvalidServerName,
137 Future {
138 connect: RustlsConnect<IO>,
139 connection: Option<Connection<R, ()>>,
140 },
141}
142
143impl<R, IO> Future for ConnectFut<R, IO>
144where
145 R: Host,
146 IO: ActixStream,
147{
148 type Output = io::Result<Connection<R, AsyncTlsStream<IO>>>;
149
150 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
151 match self.get_mut() {
152 Self::InvalidServerName => Poll::Ready(Err(io::Error::new(
153 io::ErrorKind::InvalidInput,
154 "connection parameters specified invalid server name",
155 ))),
156
157 Self::Future {
158 connect,
159 connection,
160 } => {
161 let stream = ready!(Pin::new(connect).poll(cx))?;
162 let connection = connection.take().unwrap();
163 tracing::trace!("TLS handshake success: {:?}", connection.hostname());
164 Poll::Ready(Ok(connection.replace_io(stream).1))
165 }
166 }
167 }
168}