1use crate::alpn::encode_alpn;
2use OpenSslClientTransportInner::{Tcp, Tls};
3use async_openssl::SslStream;
4use openssl::ssl::{SslConnector, SslMethod};
5use std::{
6 fmt::{self, Debug, Formatter},
7 io::{Error, IoSliceMut, Result},
8 net::SocketAddr,
9 pin::Pin,
10 sync::Arc,
11 task::{Context, Poll},
12};
13use trillium_server_common::{AsyncRead, AsyncWrite, Connector, Destination, Transport, Url};
14
15#[derive(Clone, Debug)]
20pub struct OpenSslClientConfig(Arc<SslConnector>);
21
22impl OpenSslClientConfig {
23 pub fn as_inner(&self) -> &SslConnector {
25 &self.0
26 }
27}
28
29impl Default for OpenSslClientConfig {
30 fn default() -> Self {
31 let mut builder =
32 SslConnector::builder(SslMethod::tls_client()).expect("could not build SslConnector");
33 let alpn_wire = encode_alpn(&[b"h2".to_vec(), b"http/1.1".to_vec()]);
34 builder
35 .set_alpn_protos(&alpn_wire)
36 .expect("could not set ALPN protocols");
37 Self(Arc::new(builder.build()))
38 }
39}
40
41impl From<SslConnector> for OpenSslClientConfig {
42 fn from(connector: SslConnector) -> Self {
43 Self(Arc::new(connector))
44 }
45}
46
47impl From<Arc<SslConnector>> for OpenSslClientConfig {
48 fn from(connector: Arc<SslConnector>) -> Self {
49 Self(connector)
50 }
51}
52
53#[derive(Clone, Default)]
55pub struct OpenSslConfig<Config> {
56 pub tcp_config: Config,
58
59 pub ssl_config: OpenSslClientConfig,
61}
62
63impl<C: Connector> OpenSslConfig<C> {
64 pub fn new(ssl_config: impl Into<OpenSslClientConfig>, tcp_config: C) -> Self {
66 Self {
67 tcp_config,
68 ssl_config: ssl_config.into(),
69 }
70 }
71
72 #[must_use]
74 pub fn with_tcp_config(mut self, config: C) -> Self {
75 self.tcp_config = config;
76 self
77 }
78}
79
80impl<Config: Debug> Debug for OpenSslConfig<Config> {
81 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
82 f.debug_struct("OpenSslConfig")
83 .field("tcp_config", &self.tcp_config)
84 .field("ssl_config", &self.ssl_config)
85 .finish()
86 }
87}
88
89impl<C> AsRef<C> for OpenSslConfig<C> {
90 fn as_ref(&self) -> &C {
91 &self.tcp_config
92 }
93}
94
95impl<C: Connector> OpenSslConfig<C> {
96 async fn tls_connect<S: Transport>(
97 &self,
98 host: &str,
99 alpn_wire: Option<&[u8]>,
100 inner: S,
101 ) -> Result<OpenSslClientTransport<S>> {
102 let mut ssl = self
105 .ssl_config
106 .as_inner()
107 .configure()
108 .map_err(Error::other)?
109 .into_ssl(host)
110 .map_err(Error::other)?;
111
112 if let Some(alpn_wire) = alpn_wire {
115 ssl.set_alpn_protos(alpn_wire).map_err(Error::other)?;
116 }
117
118 let mut stream = SslStream::new(ssl, inner).map_err(Error::other)?;
119 Pin::new(&mut stream)
120 .connect()
121 .await
122 .map_err(Error::other)?;
123 Ok(OpenSslClientTransport(Tls(Box::new(stream))))
124 }
125}
126
127impl<C: Connector> Connector for OpenSslConfig<C> {
128 type Runtime = C::Runtime;
129 type Transport = OpenSslClientTransport<C::Transport>;
130 type Udp = C::Udp;
131
132 async fn connect(&self, url: &Url) -> Result<Self::Transport> {
133 self.connect_to(Destination::from_url(url)?).await
134 }
135
136 async fn connect_to(&self, destination: Destination) -> Result<Self::Transport> {
137 if !destination.secure() {
138 return self
139 .tcp_config
140 .connect_to(destination)
141 .await
142 .map(|t| OpenSslClientTransport(Tcp(t)));
143 }
144
145 let domain = destination.host().map(str::to_owned);
149 let alpn_wire = destination.alpn().map(encode_alpn);
150 let inner = self
151 .tcp_config
152 .connect_to(destination.with_secure(false))
153 .await?;
154 let host = match domain {
155 Some(domain) => domain,
156 None => inner
157 .peer_addr()?
158 .ok_or_else(|| Error::other("no peer address for bare-ip destination"))?
159 .ip()
160 .to_string(),
161 };
162
163 self.tls_connect(&host, alpn_wire.as_deref(), inner).await
164 }
165
166 async fn connect_over(
167 &self,
168 transport: Box<dyn Transport>,
169 destination: Destination,
170 ) -> Result<Box<dyn Transport>> {
171 if !destination.secure() {
172 return self.tcp_config.connect_over(transport, destination).await;
173 }
174
175 let host = if let Some(host) = destination.host() {
176 host.to_owned()
177 } else {
178 destination
179 .addrs()
180 .first()
181 .ok_or_else(|| {
182 Error::new(
183 std::io::ErrorKind::InvalidInput,
184 "bare-ip destination has no socket address",
185 )
186 })?
187 .ip()
188 .to_string()
189 };
190 let alpn_wire = destination.alpn().map(encode_alpn);
191 let stream = self
192 .tls_connect(&host, alpn_wire.as_deref(), transport)
193 .await?;
194 Ok(Box::new(stream))
195 }
196
197 fn runtime(&self) -> Self::Runtime {
198 self.tcp_config.runtime()
199 }
200
201 async fn resolve(&self, host: &str, port: u16) -> Result<Vec<SocketAddr>> {
202 self.tcp_config.resolve(host, port).await
203 }
204}
205
206#[derive(Debug)]
207enum OpenSslClientTransportInner<T: Unpin> {
208 Tcp(T),
209 Tls(Box<SslStream<T>>),
210}
211
212#[derive(Debug)]
217pub struct OpenSslClientTransport<T: Unpin>(OpenSslClientTransportInner<T>);
218
219impl<T: Unpin> OpenSslClientTransport<T> {
220 pub fn as_tls(&self) -> Option<&SslStream<T>> {
222 match &self.0 {
223 Tcp(_) => None,
224 Tls(s) => Some(s),
225 }
226 }
227}
228
229impl<T: Unpin> AsRef<T> for OpenSslClientTransport<T> {
230 fn as_ref(&self) -> &T {
231 match &self.0 {
232 Tcp(t) => t,
233 Tls(s) => s.get_ref(),
234 }
235 }
236}
237
238impl<T: AsyncRead + AsyncWrite + Unpin> AsyncRead for OpenSslClientTransport<T> {
239 fn poll_read(
240 mut self: Pin<&mut Self>,
241 cx: &mut Context<'_>,
242 buf: &mut [u8],
243 ) -> Poll<Result<usize>> {
244 match &mut self.0 {
245 Tcp(t) => Pin::new(t).poll_read(cx, buf),
246 Tls(s) => Pin::new(&mut **s).poll_read(cx, buf),
247 }
248 }
249
250 fn poll_read_vectored(
251 mut self: Pin<&mut Self>,
252 cx: &mut Context<'_>,
253 bufs: &mut [IoSliceMut<'_>],
254 ) -> Poll<Result<usize>> {
255 match &mut self.0 {
256 Tcp(t) => Pin::new(t).poll_read_vectored(cx, bufs),
257 Tls(s) => Pin::new(&mut **s).poll_read_vectored(cx, bufs),
258 }
259 }
260}
261
262impl<T: AsyncRead + AsyncWrite + Unpin> AsyncWrite for OpenSslClientTransport<T> {
263 fn poll_write(
264 mut self: Pin<&mut Self>,
265 cx: &mut Context<'_>,
266 buf: &[u8],
267 ) -> Poll<Result<usize>> {
268 match &mut self.0 {
269 Tcp(t) => Pin::new(t).poll_write(cx, buf),
270 Tls(s) => Pin::new(&mut **s).poll_write(cx, buf),
271 }
272 }
273
274 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
275 match &mut self.0 {
276 Tcp(t) => Pin::new(t).poll_flush(cx),
277 Tls(s) => Pin::new(&mut **s).poll_flush(cx),
278 }
279 }
280
281 fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
282 match &mut self.0 {
283 Tcp(t) => Pin::new(t).poll_close(cx),
284 Tls(s) => Pin::new(&mut **s).poll_close(cx),
285 }
286 }
287}
288
289impl<T: Transport> Transport for OpenSslClientTransport<T> {
290 fn peer_addr(&self) -> Result<Option<SocketAddr>> {
291 self.as_ref().peer_addr()
292 }
293
294 fn negotiated_alpn(&self) -> Option<std::borrow::Cow<'_, [u8]>> {
295 match &self.0 {
296 Tcp(_) => None,
297 Tls(s) => s
298 .ssl()
299 .selected_alpn_protocol()
300 .map(std::borrow::Cow::Borrowed),
301 }
302 }
303}