actix_tls/connect/
openssl.rs1use std::{
6 future::Future,
7 io,
8 pin::Pin,
9 task::{Context, Poll},
10};
11
12use actix_rt::net::ActixStream;
13use actix_service::{Service, ServiceFactory};
14use actix_utils::future::{ok, Ready};
15use futures_core::ready;
16use openssl::ssl::SslConnector;
17use tokio_openssl::SslStream as AsyncSslStream;
18use tracing::trace;
19
20use crate::connect::{Connection, Host};
21
22pub mod reexports {
23 pub use openssl::ssl::{Error, HandshakeError, SslConnector, SslConnectorBuilder, SslMethod};
26 pub use tokio_openssl::SslStream as AsyncSslStream;
27}
28
29pub struct TlsConnector {
31 connector: SslConnector,
32}
33
34impl TlsConnector {
35 pub fn new(connector: SslConnector) -> Self {
37 TlsConnector { connector }
38 }
39
40 pub fn service(connector: SslConnector) -> TlsConnectorService {
42 TlsConnectorService { connector }
43 }
44}
45
46impl Clone for TlsConnector {
47 fn clone(&self) -> Self {
48 Self {
49 connector: self.connector.clone(),
50 }
51 }
52}
53
54impl<R, IO> ServiceFactory<Connection<R, IO>> for TlsConnector
55where
56 R: Host,
57 IO: ActixStream + 'static,
58{
59 type Response = Connection<R, AsyncSslStream<IO>>;
60 type Error = io::Error;
61 type Config = ();
62 type Service = TlsConnectorService;
63 type InitError = ();
64 type Future = Ready<Result<Self::Service, Self::InitError>>;
65
66 fn new_service(&self, _: ()) -> Self::Future {
67 ok(TlsConnectorService {
68 connector: self.connector.clone(),
69 })
70 }
71}
72
73pub struct TlsConnectorService {
75 connector: SslConnector,
76}
77
78impl Clone for TlsConnectorService {
79 fn clone(&self) -> Self {
80 Self {
81 connector: self.connector.clone(),
82 }
83 }
84}
85
86impl<R, IO> Service<Connection<R, IO>> for TlsConnectorService
87where
88 R: Host,
89 IO: ActixStream,
90{
91 type Response = Connection<R, AsyncSslStream<IO>>;
92 type Error = io::Error;
93 type Future = ConnectFut<R, IO>;
94
95 actix_service::always_ready!();
96
97 fn call(&self, stream: Connection<R, IO>) -> Self::Future {
98 trace!("TLS handshake start for: {:?}", stream.hostname());
99
100 let (io, stream) = stream.replace_io(());
101 let host = stream.hostname();
102
103 let config = self
104 .connector
105 .configure()
106 .expect("SSL connect configuration was invalid.");
107
108 let ssl = config
109 .into_ssl(host)
110 .expect("SSL connect configuration was invalid.");
111
112 ConnectFut {
113 io: Some(AsyncSslStream::new(ssl, io).unwrap()),
114 stream: Some(stream),
115 }
116 }
117}
118
119#[doc(hidden)]
121pub struct ConnectFut<R, IO> {
122 io: Option<AsyncSslStream<IO>>,
123 stream: Option<Connection<R, ()>>,
124}
125
126impl<R: Host, IO> Future for ConnectFut<R, IO>
127where
128 R: Host,
129 IO: ActixStream,
130{
131 type Output = Result<Connection<R, AsyncSslStream<IO>>, io::Error>;
132
133 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
134 let this = self.get_mut();
135
136 match ready!(Pin::new(this.io.as_mut().unwrap()).poll_connect(cx)) {
137 Ok(_) => {
138 let stream = this.stream.take().unwrap();
139 trace!("TLS handshake success: {:?}", stream.hostname());
140 Poll::Ready(Ok(stream.replace_io(this.io.take().unwrap()).1))
141 }
142 Err(err) => {
143 trace!("TLS handshake error: {:?}", err);
144 Poll::Ready(Err(io::Error::other(format!("{err}"))))
145 }
146 }
147 }
148}