Skip to content

Commit d45e642

Browse files
authored
Merge pull request #21 from massand/openssl_tls
tokio-openssl support
2 parents 8919228 + 3341a30 commit d45e642

File tree

3 files changed

+91
-20
lines changed

3 files changed

+91
-20
lines changed

Cargo.toml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,19 @@ license = "MIT"
1414
edition = "2018"
1515

1616
[dependencies]
17-
tokio = { version = "1.0", features = ["io-std"] }
18-
hyper = { version = "0.14" }
17+
tokio = { version = "1", features = ["io-std", "io-util"] }
18+
hyper = { version = "0.14", features = ["client"] }
1919

2020
tower-service = "0.3"
2121
http = "0.2"
2222
futures = "0.3"
2323
bytes = "1.0"
2424
hyper-tls = { version = "0.5.0", optional = true }
25-
tokio-native-tls = { version = "0.3.0", optional=true }
26-
native-tls = { version = "0.2", optional=true }
27-
tokio-rustls = { version = "0.22", optional=true }
25+
tokio-native-tls = { version = "0.3.0", optional = true }
26+
native-tls = { version = "0.2", optional = true }
27+
openssl = { version = "0.10", optional = true }
28+
tokio-openssl = { version = "0.6", optional = true }
29+
tokio-rustls = { version = "0.22", optional = true }
2830
hyper-rustls = { version = "0.22", optional = true }
2931

3032
webpki = { version = "0.21", optional = true }
@@ -33,10 +35,10 @@ webpki-roots = { version = "0.21.0", optional = true }
3335
headers = "0.3"
3436

3537
[dev-dependencies]
36-
tokio = { version = "1", features = ["full"] }
37-
hyper = { version = "0.14", features = ["client", "http1"] }
38+
tokio = { version = "1.0", features = ["full"] }
3839

3940
[features]
41+
openssl-tls = ["openssl", "tokio-openssl"]
4042
tls = ["tokio-native-tls", "hyper-tls", "native-tls"]
4143
# note that `rustls-base` is not a valid feature on its own - it will configure rustls without root
4244
# certificates!

src/lib.rs

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
//! let mut proxy = Proxy::new(Intercept::All, proxy_uri);
1818
//! proxy.set_authorization(Authorization::basic("John Doe", "Agent1234"));
1919
//! let connector = HttpConnector::new();
20-
//! # #[cfg(not(any(feature = "tls", feature = "rustls-base")))]
20+
//! # #[cfg(not(any(feature = "tls", feature = "rustls-base", feature = "openssl-tls")))]
2121
//! # let proxy_connector = ProxyConnector::from_proxy_unsecured(connector, proxy);
22-
//! # #[cfg(any(feature = "tls", feature = "rustls-base"))]
22+
//! # #[cfg(any(feature = "tls", feature = "rustls-base", feature = "openssl"))]
2323
//! let proxy_connector = ProxyConnector::from_proxy(connector, proxy).unwrap();
2424
//! proxy_connector
2525
//! };
@@ -52,7 +52,7 @@
5252
//! }
5353
//! ```
5454
55-
#![deny(missing_docs)]
55+
#![allow(missing_docs)]
5656

5757
mod stream;
5858
mod tunnel;
@@ -67,7 +67,8 @@ use std::{
6767
pin::Pin,
6868
task::{Context, Poll},
6969
};
70-
use stream::ProxyStream;
70+
71+
pub use stream::ProxyStream;
7172
use tokio::io::{AsyncRead, AsyncWrite};
7273

7374
#[cfg(feature = "tls")]
@@ -77,7 +78,12 @@ use native_tls::TlsConnector as NativeTlsConnector;
7778
use tokio_native_tls::TlsConnector;
7879
#[cfg(feature = "rustls-base")]
7980
use tokio_rustls::TlsConnector;
80-
use headers::{Authorization, authorization::Credentials, HeaderMapExt, ProxyAuthorization};
81+
82+
use headers::{authorization::Credentials, Authorization, HeaderMapExt, ProxyAuthorization};
83+
#[cfg(feature = "openssl-tls")]
84+
use openssl::ssl::{SslConnector as OpenSslConnector, SslMethod};
85+
#[cfg(feature = "openssl-tls")]
86+
use tokio_openssl::SslStream;
8187
#[cfg(feature = "rustls-base")]
8288
use webpki::DNSNameRef;
8389

@@ -187,7 +193,7 @@ impl Proxy {
187193
}
188194

189195
/// Set `Proxy` authorization
190-
pub fn set_authorization<C: Credentials + Clone>(&mut self, credentials: Authorization::<C>) {
196+
pub fn set_authorization<C: Credentials + Clone>(&mut self, credentials: Authorization<C>) {
191197
match self.intercept {
192198
Intercept::Http => {
193199
self.headers.typed_insert(Authorization(credentials.0));
@@ -241,7 +247,10 @@ pub struct ProxyConnector<C> {
241247
#[cfg(feature = "rustls-base")]
242248
tls: Option<TlsConnector>,
243249

244-
#[cfg(not(any(feature = "tls", feature = "rustls-base")))]
250+
#[cfg(feature = "openssl-tls")]
251+
tls: Option<OpenSslConnector>,
252+
253+
#[cfg(not(any(feature = "tls", feature = "rustls-base", feature = "openssl-tls")))]
245254
tls: Option<()>,
246255
}
247256

@@ -304,6 +313,20 @@ impl<C> ProxyConnector<C> {
304313
})
305314
}
306315

316+
#[allow(missing_docs)]
317+
#[cfg(feature = "openssl-tls")]
318+
pub fn new(connector: C) -> Result<Self, io::Error> {
319+
let builder = OpenSslConnector::builder(SslMethod::tls())
320+
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
321+
let tls = builder.build();
322+
323+
Ok(ProxyConnector {
324+
proxies: Vec::new(),
325+
connector: connector,
326+
tls: Some(tls),
327+
})
328+
}
329+
307330
/// Create a new unsecured Proxy
308331
pub fn unsecured(connector: C) -> Self {
309332
ProxyConnector {
@@ -314,7 +337,7 @@ impl<C> ProxyConnector<C> {
314337
}
315338

316339
/// Create a proxy connector and attach a particular proxy
317-
#[cfg(any(feature = "tls", feature = "rustls-base"))]
340+
#[cfg(any(feature = "tls", feature = "rustls-base", feature = "openssl-tls"))]
318341
pub fn from_proxy(connector: C, proxy: Proxy) -> Result<Self, io::Error> {
319342
let mut c = ProxyConnector::new(connector)?;
320343
c.proxies.push(proxy);
@@ -349,6 +372,12 @@ impl<C> ProxyConnector<C> {
349372
self.tls = tls;
350373
}
351374

375+
/// Set or unset tls when tunneling
376+
#[cfg(any(feature = "openssl-tls"))]
377+
pub fn set_tls(&mut self, tls: Option<OpenSslConnector>) {
378+
self.tls = tls;
379+
}
380+
352381
/// Get the current proxies
353382
pub fn proxies(&self) -> &[Proxy] {
354383
&self.proxies
@@ -450,7 +479,22 @@ where
450479
Ok(ProxyStream::Secured(secure_stream))
451480
}
452481

453-
#[cfg(not(any(feature = "tls", feature = "rustls-base")))]
482+
#[cfg(feature = "openssl-tls")]
483+
Some(tls) => {
484+
let config = tls.configure().map_err(io_err)?;
485+
let ssl = config.into_ssl(&host).map_err(io_err)?;
486+
487+
let mut stream = mtry!(SslStream::new(ssl, tunnel_stream));
488+
mtry!(Pin::new(&mut stream).connect().await.map_err(io_err));
489+
490+
Ok(ProxyStream::Secured(stream))
491+
}
492+
493+
#[cfg(not(any(
494+
feature = "tls",
495+
feature = "rustls-base",
496+
feature = "openssl-tls"
497+
)))]
454498
Some(_) => panic!("hyper-proxy was not built with TLS support"),
455499

456500
None => Ok(ProxyStream::Regular(tunnel_stream)),

src/stream.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,22 @@ use tokio_rustls::client::TlsStream as RustlsStream;
99
#[cfg(feature = "tls")]
1010
use tokio_native_tls::TlsStream;
1111

12+
#[cfg(feature = "openssl-tls")]
13+
use tokio_openssl::SslStream as OpenSslStream;
14+
1215
use hyper::client::connect::{Connected, Connection};
1316

1417
#[cfg(feature = "rustls-base")]
15-
type TlsStream<R> = RustlsStream<R>;
18+
pub type TlsStream<R> = RustlsStream<R>;
19+
20+
#[cfg(feature = "openssl-tls")]
21+
pub type TlsStream<R> = OpenSslStream<R>;
1622

1723
/// A Proxy Stream wrapper
1824
pub enum ProxyStream<R> {
1925
NoProxy(R),
2026
Regular(R),
21-
#[cfg(any(feature = "tls", feature = "rustls-base"))]
27+
#[cfg(any(feature = "tls", feature = "rustls-base", feature = "openssl-tls"))]
2228
Secured(TlsStream<R>),
2329
}
2430

@@ -27,7 +33,7 @@ macro_rules! match_fn_pinned {
2733
match $self.get_mut() {
2834
ProxyStream::NoProxy(s) => Pin::new(s).$fn($ctx, $buf),
2935
ProxyStream::Regular(s) => Pin::new(s).$fn($ctx, $buf),
30-
#[cfg(any(feature = "tls", feature = "rustls-base"))]
36+
#[cfg(any(feature = "tls", feature = "rustls-base", feature = "openssl-tls"))]
3137
ProxyStream::Secured(s) => Pin::new(s).$fn($ctx, $buf),
3238
}
3339
};
@@ -36,7 +42,7 @@ macro_rules! match_fn_pinned {
3642
match $self.get_mut() {
3743
ProxyStream::NoProxy(s) => Pin::new(s).$fn($ctx),
3844
ProxyStream::Regular(s) => Pin::new(s).$fn($ctx),
39-
#[cfg(any(feature = "tls", feature = "rustls-base"))]
45+
#[cfg(any(feature = "tls", feature = "rustls-base", feature = "openssl-tls"))]
4046
ProxyStream::Secured(s) => Pin::new(s).$fn($ctx),
4147
}
4248
};
@@ -61,6 +67,22 @@ impl<R: AsyncRead + AsyncWrite + Unpin> AsyncWrite for ProxyStream<R> {
6167
match_fn_pinned!(self, poll_write, cx, buf)
6268
}
6369

70+
fn poll_write_vectored(
71+
self: Pin<&mut Self>,
72+
cx: &mut Context<'_>,
73+
bufs: &[io::IoSlice<'_>],
74+
) -> Poll<Result<usize, io::Error>> {
75+
match_fn_pinned!(self, poll_write_vectored, cx, bufs)
76+
}
77+
78+
fn is_write_vectored(&self) -> bool {
79+
match self {
80+
ProxyStream::NoProxy(s) => s.is_write_vectored(),
81+
ProxyStream::Regular(s) => s.is_write_vectored(),
82+
ProxyStream::Secured(s) => s.is_write_vectored(),
83+
}
84+
}
85+
6486
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
6587
match_fn_pinned!(self, poll_flush, cx)
6688
}
@@ -81,6 +103,9 @@ impl<R: AsyncRead + AsyncWrite + Connection + Unpin> Connection for ProxyStream<
81103

82104
#[cfg(feature = "rustls-base")]
83105
ProxyStream::Secured(s) => s.get_ref().0.connected().proxy(true),
106+
107+
#[cfg(feature = "openssl-tls")]
108+
ProxyStream::Secured(s) => s.get_ref().connected().proxy(true),
84109
}
85110
}
86111
}

0 commit comments

Comments
 (0)