Skip to content

Commit 7bc4e83

Browse files
committed
Merge pull request #518 from mlalic/fix-client-ssl-verifier
fix(client): keep the underlying connector when setting an SSL verifier
2 parents 390b9fa + f4556d5 commit 7bc4e83

File tree

5 files changed

+116
-10
lines changed

5 files changed

+116
-10
lines changed

benches/client.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::fmt;
88
use std::io::{self, Read, Write, Cursor};
99
use std::net::SocketAddr;
1010

11-
use hyper::net;
11+
use hyper::net::{self, ContextVerifier};
1212

1313
static README: &'static [u8] = include_bytes!("../README.md");
1414

@@ -83,6 +83,9 @@ impl net::NetworkConnector for MockConnector {
8383
Ok(MockStream::new())
8484
}
8585

86+
fn set_ssl_verifier(&mut self, _verifier: ContextVerifier) {
87+
// pass
88+
}
8689
}
8790

8891
#[bench]

src/client/mod.rs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use url::ParseError as UrlError;
4141
use header::{Headers, Header, HeaderFormat};
4242
use header::{ContentLength, Location};
4343
use method::Method;
44-
use net::{NetworkConnector, NetworkStream, HttpConnector, ContextVerifier};
44+
use net::{NetworkConnector, NetworkStream, ContextVerifier};
4545
use status::StatusClass::Redirection;
4646
use {Url};
4747
use Error;
@@ -85,10 +85,7 @@ impl Client {
8585

8686
/// Set the SSL verifier callback for use with OpenSSL.
8787
pub fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
88-
self.connector = with_connector(Pool::with_connector(
89-
Default::default(),
90-
HttpConnector(Some(verifier))
91-
));
88+
self.connector.set_ssl_verifier(verifier);
9289
}
9390

9491
/// Set the RedirectPolicy.
@@ -147,6 +144,10 @@ impl<C: NetworkConnector<Stream=S> + Send, S: NetworkStream + Send> NetworkConne
147144
-> ::Result<Box<NetworkStream + Send>> {
148145
Ok(try!(self.0.connect(host, port, scheme)).into())
149146
}
147+
#[inline]
148+
fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
149+
self.0.set_ssl_verifier(verifier);
150+
}
150151
}
151152

152153
struct Connector(Box<NetworkConnector<Stream=Box<NetworkStream + Send>> + Send>);
@@ -158,6 +159,10 @@ impl NetworkConnector for Connector {
158159
-> ::Result<Box<NetworkStream + Send>> {
159160
Ok(try!(self.0.connect(host, port, scheme)).into())
160161
}
162+
#[inline]
163+
fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
164+
self.0.set_ssl_verifier(verifier);
165+
}
161166
}
162167

163168
/// Options for an individual Request.
@@ -399,6 +404,8 @@ mod tests {
399404
use header::Server;
400405
use super::{Client, RedirectPolicy};
401406
use url::Url;
407+
use mock::ChannelMockConnector;
408+
use std::sync::mpsc::{self, TryRecvError};
402409

403410
mock_connector!(MockRedirectPolicy {
404411
"http://127.0.0.1" => "HTTP/1.1 301 Redirect\r\n\
@@ -445,4 +452,30 @@ mod tests {
445452
assert_eq!(res.headers.get(), Some(&Server("mock2".to_string())));
446453
}
447454

455+
/// Tests that the `Client::set_ssl_verifier` method does not drop the
456+
/// old connector, but rather delegates the change to the connector itself.
457+
#[test]
458+
fn test_client_set_ssl_verifer() {
459+
let (tx, rx) = mpsc::channel();
460+
let mut client = Client::with_connector(ChannelMockConnector::new(tx));
461+
462+
client.set_ssl_verifier(Box::new(|_| {}));
463+
464+
// Make sure that the client called the `set_ssl_verifier` method
465+
match rx.try_recv() {
466+
Ok(meth) => {
467+
assert_eq!(meth, "set_ssl_verifier");
468+
},
469+
_ => panic!("Expected a call to `set_ssl_verifier`"),
470+
};
471+
// Now make sure that no other method was called, as well as that
472+
// the connector is still alive (i.e. wasn't dropped by the client).
473+
match rx.try_recv() {
474+
Err(TryRecvError::Empty) => {},
475+
Err(TryRecvError::Disconnected) => {
476+
panic!("Expected the connector to still be alive.");
477+
},
478+
Ok(_) => panic!("Did not expect any more method calls."),
479+
};
480+
}
448481
}

src/client/pool.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::io::{self, Read, Write};
55
use std::net::{SocketAddr, Shutdown};
66
use std::sync::{Arc, Mutex};
77

8-
use net::{NetworkConnector, NetworkStream, HttpConnector};
8+
use net::{NetworkConnector, NetworkStream, HttpConnector, ContextVerifier};
99

1010
/// The `NetworkConnector` that behaves as a connection pool used by hyper's `Client`.
1111
pub struct Pool<C: NetworkConnector> {
@@ -120,6 +120,10 @@ impl<C: NetworkConnector<Stream=S>, S: NetworkStream + Send> NetworkConnector fo
120120
pool: self.inner.clone()
121121
})
122122
}
123+
#[inline]
124+
fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
125+
self.connector.set_ssl_verifier(verifier);
126+
}
123127
}
124128

125129
/// A Stream that will try to be returned to the Pool when dropped.
@@ -185,8 +189,9 @@ impl<S> Drop for PooledStream<S> {
185189
#[cfg(test)]
186190
mod tests {
187191
use std::net::Shutdown;
188-
use mock::MockConnector;
192+
use mock::{MockConnector, ChannelMockConnector};
189193
use net::{NetworkConnector, NetworkStream};
194+
use std::sync::mpsc;
190195

191196
use super::{Pool, key};
192197

@@ -224,5 +229,19 @@ mod tests {
224229
assert_eq!(locked.conns.len(), 0);
225230
}
226231

232+
/// Tests that the `Pool::set_ssl_verifier` method sets the SSL verifier of
233+
/// the underlying `Connector` instance that it uses.
234+
#[test]
235+
fn test_set_ssl_verifier_delegates_to_connector() {
236+
let (tx, rx) = mpsc::channel();
237+
let mut pool = Pool::with_connector(
238+
Default::default(), ChannelMockConnector::new(tx));
239+
240+
pool.set_ssl_verifier(Box::new(|_| { }));
227241

242+
match rx.try_recv() {
243+
Ok(meth) => assert_eq!(meth, "set_ssl_verifier"),
244+
_ => panic!("Expected a call to `set_ssl_verifier`"),
245+
};
246+
}
228247
}

src/mock.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use std::fmt;
22
use std::io::{self, Read, Write, Cursor};
33
use std::net::SocketAddr;
4+
use std::sync::mpsc::Sender;
45

5-
use net::{NetworkStream, NetworkConnector};
6+
use net::{NetworkStream, NetworkConnector, ContextVerifier};
67

78
pub struct MockStream {
89
pub read: Cursor<Vec<u8>>,
@@ -76,6 +77,39 @@ impl NetworkConnector for MockConnector {
7677
fn connect(&mut self, _host: &str, _port: u16, _scheme: &str) -> ::Result<MockStream> {
7778
Ok(MockStream::new())
7879
}
80+
81+
fn set_ssl_verifier(&mut self, _verifier: ContextVerifier) {
82+
// pass
83+
}
84+
}
85+
86+
/// A mock implementation of the `NetworkConnector` trait that keeps track of all calls to its
87+
/// methods by sending corresponding messages onto a channel.
88+
///
89+
/// Otherwise, it behaves the same as `MockConnector`.
90+
pub struct ChannelMockConnector {
91+
calls: Sender<String>,
92+
}
93+
94+
impl ChannelMockConnector {
95+
pub fn new(calls: Sender<String>) -> ChannelMockConnector {
96+
ChannelMockConnector { calls: calls }
97+
}
98+
}
99+
100+
impl NetworkConnector for ChannelMockConnector {
101+
type Stream = MockStream;
102+
#[inline]
103+
fn connect(&mut self, _host: &str, _port: u16, _scheme: &str)
104+
-> ::Result<MockStream> {
105+
self.calls.send("connect".into()).unwrap();
106+
Ok(MockStream::new())
107+
}
108+
109+
#[inline]
110+
fn set_ssl_verifier(&mut self, _verifier: ContextVerifier) {
111+
self.calls.send("set_ssl_verifier".into()).unwrap();
112+
}
79113
}
80114

81115
/// new connectors must be created if you wish to intercept requests.
@@ -107,6 +141,9 @@ macro_rules! mock_connector (
107141
}
108142
}
109143

144+
fn set_ssl_verifier(&mut self, _verifier: ::net::ContextVerifier) {
145+
// pass
146+
}
110147
}
111148

112149
)

src/net.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ pub trait NetworkConnector {
7070
type Stream: Into<Box<NetworkStream + Send>>;
7171
/// Connect to a remote address.
7272
fn connect(&mut self, host: &str, port: u16, scheme: &str) -> ::Result<Self::Stream>;
73+
/// Sets the given `ContextVerifier` to be used when verifying the SSL context
74+
/// on the establishment of a new connection.
75+
fn set_ssl_verifier(&mut self, verifier: ContextVerifier);
7376
}
7477

7578
impl<T: NetworkStream + Send> From<T> for Box<NetworkStream + Send> {
@@ -344,12 +347,15 @@ impl NetworkConnector for HttpConnector {
344347
}
345348
}))
346349
}
350+
fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
351+
self.0 = Some(verifier);
352+
}
347353
}
348354

349355
#[cfg(test)]
350356
mod tests {
351357
use mock::MockStream;
352-
use super::NetworkStream;
358+
use super::{NetworkStream, HttpConnector, NetworkConnector};
353359

354360
#[test]
355361
fn test_downcast_box_stream() {
@@ -371,4 +377,12 @@ mod tests {
371377

372378
}
373379

380+
#[test]
381+
fn test_http_connector_set_ssl_verifier() {
382+
let mut connector = HttpConnector(None);
383+
384+
connector.set_ssl_verifier(Box::new(|_| {}));
385+
386+
assert!(connector.0.is_some());
387+
}
374388
}

0 commit comments

Comments
 (0)