Skip to content

Commit 912d599

Browse files
committed
upgrade to native-tls 0.2
1 parent 16bcecd commit 912d599

File tree

4 files changed

+119
-45
lines changed

4 files changed

+119
-45
lines changed

Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ documentation = "https://docs.rs/hyper-tls"
1212
[dependencies]
1313
bytes = "0.4"
1414
futures = "0.1.21"
15-
native-tls = "0.1"
15+
native-tls = "0.2"
1616
hyper = "0.12"
1717
tokio-io = "0.1"
18-
tokio-tls = { version = "0.1.4", default-features = false }
1918

2019
[dev-dependencies]
2120
tokio = "0.1.5"

src/client.rs

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,22 @@
11
use std::fmt;
22
use std::io;
3-
use std::sync::Arc;
43

5-
use futures::{Future, future, Poll};
4+
use futures::{Async, Future, future, Poll};
65
use hyper::client::connect::{Connect, Connected, Destination, HttpConnector};
76
pub use native_tls::Error;
8-
use native_tls::TlsConnector;
9-
use tokio_tls::TlsConnectorExt;
7+
use native_tls::{self, HandshakeError, TlsConnector};
108

11-
use stream::MaybeHttpsStream;
9+
use stream::{MaybeHttpsStream, TlsStream};
1210

1311
/// A Connector for the `https` scheme.
1412
#[derive(Clone)]
1513
pub struct HttpsConnector<T> {
16-
hostname_verification: bool,
1714
force_https: bool,
1815
http: T,
19-
tls: Arc<TlsConnector>,
16+
tls: TlsConnector,
2017
}
2118

2219
impl HttpsConnector<HttpConnector> {
23-
2420
/// Construct a new HttpsConnector.
2521
///
2622
/// Takes number of DNS worker threads.
@@ -29,35 +25,35 @@ impl HttpsConnector<HttpConnector> {
2925
/// If you wish to use something besides the defaults, use `From::from`.
3026
///
3127
/// # Note
32-
/// By default this connector will use plain HTTP if the URL provded
33-
/// uses the HTTP scheme (eg: http://example.com/).
34-
/// If you would like to force the use of HTTPS
35-
/// then call force_https(true) on the returned connector.
28+
///
29+
/// By default this connector will use plain HTTP if the URL provded uses
30+
/// the HTTP scheme (eg: http://example.com/).
31+
///
32+
/// If you would like to force the use of HTTPS then call force_https(true)
33+
/// on the returned connector.
3634
pub fn new(threads: usize) -> Result<Self, Error> {
35+
TlsConnector::builder()
36+
.build()
37+
.map(|tls| HttpsConnector::new_(threads, tls))
38+
}
39+
40+
fn new_(threads: usize, tls: TlsConnector) -> Self {
3741
let mut http = HttpConnector::new(threads);
3842
http.enforce_http(false);
39-
let tls = TlsConnector::builder()?.build()?;
40-
Ok(HttpsConnector::from((http, tls)))
43+
HttpsConnector::from((http, tls))
4144
}
4245
}
4346

4447
impl<T> HttpsConnector<T> {
45-
/// Disable hostname verification when connecting.
46-
///
47-
/// # Warning
48+
/// Force the use of HTTPS when connecting.
4849
///
49-
/// You should think very carefully before you use this method. If hostname
50-
/// verification is not used, any valid certificate for any site will be
51-
/// trusted for use from any other. This introduces a significant
52-
/// vulnerability to man-in-the-middle attacks.
53-
pub fn danger_disable_hostname_verification(&mut self, disable: bool) {
54-
self.hostname_verification = !disable;
50+
/// If a URL is not `https` when connecting, an error is returned.
51+
pub fn https_only(&mut self, enable: bool) {
52+
self.force_https = enable;
5553
}
56-
}
5754

58-
impl<T> HttpsConnector<T> {
59-
/// Force the use of HTTPS when connecting.
60-
/// If HTTPS cannot be used the connection will be aborted.
55+
#[doc(hidden)]
56+
#[deprecated(since = "0.3", note = "use `https_only` method instead")]
6157
pub fn force_https(&mut self, enable: bool) {
6258
self.force_https = enable;
6359
}
@@ -66,18 +62,16 @@ impl<T> HttpsConnector<T> {
6662
impl<T> From<(T, TlsConnector)> for HttpsConnector<T> {
6763
fn from(args: (T, TlsConnector)) -> HttpsConnector<T> {
6864
HttpsConnector {
69-
hostname_verification: true,
7065
force_https: false,
7166
http: args.0,
72-
tls: Arc::new(args.1),
67+
tls: args.1,
7368
}
7469
}
7570
}
7671

7772
impl<T: fmt::Debug> fmt::Debug for HttpsConnector<T> {
7873
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7974
f.debug_struct("HttpsConnector")
80-
.field("hostname_verification", &self.hostname_verification)
8175
.field("force_https", &self.force_https)
8276
.field("http", &self.http)
8377
.finish()
@@ -101,20 +95,17 @@ where
10195
let err = io::Error::new(io::ErrorKind::Other, "HTTPS scheme forced but can't be used");
10296
return HttpsConnecting(Box::new(future::err(err)));
10397
}
104-
98+
10599
let host = dst.host().to_owned();
106100
let connecting = self.http.connect(dst);
107101
let tls = self.tls.clone();
108-
let verification = self.hostname_verification;
109102
let fut: BoxedFut<T::Transport> = if is_https {
110103
let fut = connecting.and_then(move |(tcp, connected)| {
111-
let handshake = if verification {
112-
tls.connect_async(&host, tcp)
113-
} else {
114-
tls.danger_connect_async_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp)
104+
let handshake = Handshaking {
105+
inner: Some(tls.connect(&host, tcp)),
115106
};
116107
handshake
117-
.map(|conn| (MaybeHttpsStream::Https(conn), connected))
108+
.map(|conn| (MaybeHttpsStream::Https(TlsStream::new(conn)), connected))
118109
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
119110
});
120111
Box::new(fut)
@@ -149,3 +140,28 @@ impl<T> fmt::Debug for HttpsConnecting<T> {
149140
}
150141
}
151142

143+
struct Handshaking<T> {
144+
inner: Option<Result<native_tls::TlsStream<T>, HandshakeError<T>>>,
145+
}
146+
147+
impl<T: io::Read + io::Write> Future for Handshaking<T> {
148+
type Item = native_tls::TlsStream<T>;
149+
type Error = native_tls::Error;
150+
151+
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
152+
match self.inner.take().expect("polled after ready") {
153+
Ok(stream) => Ok(stream.into()),
154+
Err(HandshakeError::WouldBlock(mid)) => {
155+
match mid.handshake() {
156+
Ok(stream) => Ok(stream.into()),
157+
Err(HandshakeError::Failure(err)) => Err(err),
158+
Err(HandshakeError::WouldBlock(mid)) => {
159+
self.inner = Some(Err(HandshakeError::WouldBlock(mid)));
160+
Ok(Async::NotReady)
161+
}
162+
}
163+
},
164+
Err(HandshakeError::Failure(err)) => Err(err),
165+
}
166+
}
167+
}

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ extern crate bytes;
4040
extern crate futures;
4141
extern crate hyper;
4242
extern crate native_tls;
43+
#[macro_use]
4344
extern crate tokio_io;
44-
extern crate tokio_tls;
4545

4646
pub use client::{HttpsConnector, HttpsConnecting, Error};
47-
pub use stream::MaybeHttpsStream;
47+
pub use stream::{MaybeHttpsStream, TlsStream};
4848

4949
mod client;
5050
mod stream;

src/stream.rs

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::io::{self, Read, Write};
33

44
use bytes::{Buf, BufMut};
55
use futures::Poll;
6+
use native_tls;
67
use tokio_io::{AsyncRead, AsyncWrite};
7-
use tokio_tls::TlsStream;
88

99
/// A stream that might be protected with TLS.
1010
pub enum MaybeHttpsStream<T> {
@@ -14,11 +14,26 @@ pub enum MaybeHttpsStream<T> {
1414
Https(TlsStream<T>),
1515
}
1616

17-
impl<T> fmt::Debug for MaybeHttpsStream<T> {
17+
/// A stream protected with TLS.
18+
pub struct TlsStream<T> {
19+
inner: native_tls::TlsStream<T>,
20+
}
21+
22+
// ===== impl MaybeHttpsStream =====
23+
24+
impl<T: fmt::Debug> fmt::Debug for MaybeHttpsStream<T> {
1825
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1926
match *self {
20-
MaybeHttpsStream::Http(..) => f.pad("Http(..)"),
21-
MaybeHttpsStream::Https(..) => f.pad("Https(..)"),
27+
MaybeHttpsStream::Http(ref s) => {
28+
f.debug_tuple("Http")
29+
.field(s)
30+
.finish()
31+
},
32+
MaybeHttpsStream::Https(ref s) => {
33+
f.debug_tuple("Https")
34+
.field(s)
35+
.finish()
36+
},
2237
}
2338
}
2439
}
@@ -86,3 +101,47 @@ impl<T: AsyncWrite + AsyncRead> AsyncWrite for MaybeHttpsStream<T> {
86101
}
87102
}
88103
}
104+
105+
// ===== impl TlsStream =====
106+
107+
impl<T> TlsStream<T> {
108+
pub(crate) fn new(inner: native_tls::TlsStream<T>) -> Self {
109+
TlsStream {
110+
inner,
111+
}
112+
}
113+
}
114+
115+
impl<T: fmt::Debug> fmt::Debug for TlsStream<T> {
116+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117+
fmt::Debug::fmt(&self.inner, f)
118+
}
119+
}
120+
121+
impl<T: Read + Write> Read for TlsStream<T> {
122+
#[inline]
123+
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
124+
self.inner.read(buf)
125+
}
126+
}
127+
128+
impl<T: Read + Write> Write for TlsStream<T> {
129+
#[inline]
130+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
131+
self.inner.write(buf)
132+
}
133+
134+
#[inline]
135+
fn flush(&mut self) -> io::Result<()> {
136+
self.inner.flush()
137+
}
138+
}
139+
140+
impl<T: AsyncRead + AsyncWrite> AsyncRead for TlsStream<T> {}
141+
142+
impl<T: AsyncWrite + AsyncRead> AsyncWrite for TlsStream<T> {
143+
fn shutdown(&mut self) -> Poll<(), io::Error> {
144+
try_nb!(self.inner.shutdown());
145+
self.inner.get_mut().shutdown()
146+
}
147+
}

0 commit comments

Comments
 (0)