Skip to content

Commit 972b3a3

Browse files
committed
feat(error): add Ssl variant to hyper::Error
The errors from openssl were previously boxed into a Box<std::error::Error>, which lost some specifics and made it difficult to match against. To solve this, an `Ssl` variant is added to the `Error` enum of hyper, and is returned when openssl returns specific errors. Closes #483 BREAKING CHANGE: Adds a variant to `hyper::Error`, which may break any exhaustive matches.
1 parent 18f7dd7 commit 972b3a3

File tree

6 files changed

+61
-50
lines changed

6 files changed

+61
-50
lines changed

benches/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ struct MockConnector;
7979

8080
impl net::NetworkConnector for MockConnector {
8181
type Stream = MockStream;
82-
fn connect(&mut self, _: &str, _: u16, _: &str) -> io::Result<MockStream> {
82+
fn connect(&mut self, _: &str, _: u16, _: &str) -> hyper::Result<MockStream> {
8383
Ok(MockStream::new())
8484
}
8585

src/client/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ impl<C: NetworkConnector<Stream=S> + Send, S: NetworkStream + Send> NetworkConne
144144
type Stream = Box<NetworkStream + Send>;
145145
#[inline]
146146
fn connect(&mut self, host: &str, port: u16, scheme: &str)
147-
-> io::Result<Box<NetworkStream + Send>> {
147+
-> ::Result<Box<NetworkStream + Send>> {
148148
Ok(try!(self.0.connect(host, port, scheme)).into())
149149
}
150150
}
@@ -155,7 +155,7 @@ impl NetworkConnector for Connector {
155155
type Stream = Box<NetworkStream + Send>;
156156
#[inline]
157157
fn connect(&mut self, host: &str, port: u16, scheme: &str)
158-
-> io::Result<Box<NetworkStream + Send>> {
158+
-> ::Result<Box<NetworkStream + Send>> {
159159
Ok(try!(self.0.connect(host, port, scheme)).into())
160160
}
161161
}

src/client/pool.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ impl<S> PoolImpl<S> {
9898

9999
impl<C: NetworkConnector<Stream=S>, S: NetworkStream + Send> NetworkConnector for Pool<C> {
100100
type Stream = PooledStream<S>;
101-
fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<PooledStream<S>> {
101+
fn connect(&mut self, host: &str, port: u16, scheme: &str) -> ::Result<PooledStream<S>> {
102102
let key = key(host, port, scheme);
103103
let mut locked = self.inner.lock().unwrap();
104104
let mut should_remove = false;

src/error.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,19 @@ use std::fmt;
44
use std::io::Error as IoError;
55

66
use httparse;
7+
use openssl::ssl::error::SslError;
78
use url;
89

9-
use self::Error::{Method, Uri, Version,
10-
Header, Status, Io,
11-
TooLarge};
10+
use self::Error::{
11+
Method,
12+
Uri,
13+
Version,
14+
Header,
15+
Status,
16+
Io,
17+
Ssl,
18+
TooLarge
19+
};
1220

1321

1422
/// Result type often returned from methods that can have hyper `Error`s.
@@ -29,8 +37,10 @@ pub enum Error {
2937
TooLarge,
3038
/// An invalid `Status`, such as `1337 ELITE`.
3139
Status,
32-
/// An `IoError` that occurred while trying to read or write to a network stream.
40+
/// An `io::Error` that occurred while trying to read or write to a network stream.
3341
Io(IoError),
42+
/// An error from the `openssl` library.
43+
Ssl(SslError)
3444
}
3545

3646
impl fmt::Display for Error {
@@ -48,13 +58,15 @@ impl StdError for Error {
4858
Header => "Invalid Header provided",
4959
TooLarge => "Message head is too large",
5060
Status => "Invalid Status provided",
51-
Io(_) => "An IoError occurred while connecting to the specified network",
61+
Io(ref e) => e.description(),
62+
Ssl(ref e) => e.description(),
5263
}
5364
}
5465

5566
fn cause(&self) -> Option<&StdError> {
5667
match *self {
5768
Io(ref error) => Some(error),
69+
Ssl(ref error) => Some(error),
5870
Uri(ref error) => Some(error),
5971
_ => None,
6072
}
@@ -73,6 +85,15 @@ impl From<url::ParseError> for Error {
7385
}
7486
}
7587

88+
impl From<SslError> for Error {
89+
fn from(err: SslError) -> Error {
90+
match err {
91+
SslError::StreamError(err) => Io(err),
92+
err => Ssl(err),
93+
}
94+
}
95+
}
96+
7697
impl From<httparse::Error> for Error {
7798
fn from(err: httparse::Error) -> Error {
7899
match err {

src/mock.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ pub struct MockConnector;
7373
impl NetworkConnector for MockConnector {
7474
type Stream = MockStream;
7575

76-
fn connect(&mut self, _host: &str, _port: u16, _scheme: &str) -> io::Result<MockStream> {
76+
fn connect(&mut self, _host: &str, _port: u16, _scheme: &str) -> ::Result<MockStream> {
7777
Ok(MockStream::new())
7878
}
7979
}
@@ -88,7 +88,7 @@ macro_rules! mock_connector (
8888

8989
impl ::net::NetworkConnector for $name {
9090
type Stream = ::mock::MockStream;
91-
fn connect(&mut self, host: &str, port: u16, scheme: &str) -> ::std::io::Result<::mock::MockStream> {
91+
fn connect(&mut self, host: &str, port: u16, scheme: &str) -> $crate::Result<::mock::MockStream> {
9292
use std::collections::HashMap;
9393
use std::io::Cursor;
9494
debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme);
@@ -99,7 +99,7 @@ macro_rules! mock_connector (
9999
let key = format!("{}://{}", scheme, host);
100100
// ignore port for now
101101
match map.get(&*key) {
102-
Some(res) => Ok(::mock::MockStream {
102+
Some(res) => Ok($crate::mock::MockStream {
103103
write: vec![],
104104
read: Cursor::new(res.to_string().into_bytes()),
105105
}),

src/net.rs

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::sync::Arc;
99

1010
use openssl::ssl::{Ssl, SslStream, SslContext, SSL_VERIFY_NONE};
1111
use openssl::ssl::SslMethod::Sslv23;
12-
use openssl::ssl::error::{SslError, StreamError, OpenSslErrors, SslSessionClosed};
12+
use openssl::ssl::error::StreamError as SslIoError;
1313
use openssl::x509::X509FileType;
1414

1515
use typeable::Typeable;
@@ -29,7 +29,7 @@ pub trait NetworkListener: Clone {
2929
//fn listen<To: ToSocketAddrs>(&mut self, addr: To) -> io::Result<Self::Acceptor>;
3030

3131
/// Returns an iterator of streams.
32-
fn accept(&mut self) -> io::Result<Self::Stream>;
32+
fn accept(&mut self) -> ::Result<Self::Stream>;
3333

3434
/// Get the address this Listener ended up listening on.
3535
fn local_addr(&mut self) -> io::Result<SocketAddr>;
@@ -47,8 +47,8 @@ pub trait NetworkListener: Clone {
4747
pub struct NetworkConnections<'a, N: NetworkListener + 'a>(&'a mut N);
4848

4949
impl<'a, N: NetworkListener + 'a> Iterator for NetworkConnections<'a, N> {
50-
type Item = io::Result<N::Stream>;
51-
fn next(&mut self) -> Option<io::Result<N::Stream>> {
50+
type Item = ::Result<N::Stream>;
51+
fn next(&mut self) -> Option<::Result<N::Stream>> {
5252
Some(self.0.accept())
5353
}
5454
}
@@ -58,6 +58,7 @@ pub trait NetworkStream: Read + Write + Any + Send + Typeable {
5858
/// Get the remote address of the underlying connection.
5959
fn peer_addr(&mut self) -> io::Result<SocketAddr>;
6060
/// This will be called when Stream should no longer be kept alive.
61+
#[inline]
6162
fn close(&mut self, _how: Shutdown) -> io::Result<()> {
6263
Ok(())
6364
}
@@ -68,7 +69,7 @@ pub trait NetworkConnector {
6869
/// Type of Stream to create
6970
type Stream: Into<Box<NetworkStream + Send>>;
7071
/// Connect to a remote address.
71-
fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<Self::Stream>;
72+
fn connect(&mut self, host: &str, port: u16, scheme: &str) -> ::Result<Self::Stream>;
7273
}
7374

7475
impl<T: NetworkStream + Send> From<T> for Box<NetworkStream + Send> {
@@ -158,22 +159,22 @@ impl Clone for HttpListener {
158159
impl HttpListener {
159160

160161
/// Start listening to an address over HTTP.
161-
pub fn http<To: ToSocketAddrs>(addr: To) -> io::Result<HttpListener> {
162+
pub fn http<To: ToSocketAddrs>(addr: To) -> ::Result<HttpListener> {
162163
Ok(HttpListener::Http(try!(TcpListener::bind(addr))))
163164
}
164165

165166
/// Start listening to an address over HTTPS.
166-
pub fn https<To: ToSocketAddrs>(addr: To, cert: &Path, key: &Path) -> io::Result<HttpListener> {
167-
let mut ssl_context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
168-
try!(ssl_context.set_cipher_list("DEFAULT").map_err(lift_ssl_error));
169-
try!(ssl_context.set_certificate_file(cert, X509FileType::PEM).map_err(lift_ssl_error));
170-
try!(ssl_context.set_private_key_file(key, X509FileType::PEM).map_err(lift_ssl_error));
167+
pub fn https<To: ToSocketAddrs>(addr: To, cert: &Path, key: &Path) -> ::Result<HttpListener> {
168+
let mut ssl_context = try!(SslContext::new(Sslv23));
169+
try!(ssl_context.set_cipher_list("DEFAULT"));
170+
try!(ssl_context.set_certificate_file(cert, X509FileType::PEM));
171+
try!(ssl_context.set_private_key_file(key, X509FileType::PEM));
171172
ssl_context.set_verify(SSL_VERIFY_NONE, None);
172173
HttpListener::https_with_context(addr, ssl_context)
173174
}
174175

175176
/// Start listening to an address of HTTPS using the given SslContext
176-
pub fn https_with_context<To: ToSocketAddrs>(addr: To, ssl_context: SslContext) -> io::Result<HttpListener> {
177+
pub fn https_with_context<To: ToSocketAddrs>(addr: To, ssl_context: SslContext) -> ::Result<HttpListener> {
177178
Ok(HttpListener::Https(try!(TcpListener::bind(addr)), Arc::new(ssl_context)))
178179
}
179180
}
@@ -182,21 +183,20 @@ impl NetworkListener for HttpListener {
182183
type Stream = HttpStream;
183184

184185
#[inline]
185-
fn accept(&mut self) -> io::Result<HttpStream> {
186-
Ok(match *self {
187-
HttpListener::Http(ref mut tcp) => HttpStream::Http(CloneTcpStream(try!(tcp.accept()).0)),
186+
fn accept(&mut self) -> ::Result<HttpStream> {
187+
match *self {
188+
HttpListener::Http(ref mut tcp) => Ok(HttpStream::Http(CloneTcpStream(try!(tcp.accept()).0))),
188189
HttpListener::Https(ref mut tcp, ref ssl_context) => {
189190
let stream = CloneTcpStream(try!(tcp.accept()).0);
190191
match SslStream::new_server(&**ssl_context, stream) {
191-
Ok(ssl_stream) => HttpStream::Https(ssl_stream),
192-
Err(StreamError(e)) => {
193-
return Err(io::Error::new(io::ErrorKind::ConnectionAborted,
194-
e));
192+
Ok(ssl_stream) => Ok(HttpStream::Https(ssl_stream)),
193+
Err(SslIoError(e)) => {
194+
Err(io::Error::new(io::ErrorKind::ConnectionAborted, e).into())
195195
},
196-
Err(e) => return Err(lift_ssl_error(e))
196+
Err(e) => Err(e.into())
197197
}
198198
}
199-
})
199+
}
200200
}
201201

202202
#[inline]
@@ -308,40 +308,30 @@ pub type ContextVerifier = Box<FnMut(&mut SslContext) -> () + Send>;
308308
impl NetworkConnector for HttpConnector {
309309
type Stream = HttpStream;
310310

311-
fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<HttpStream> {
311+
fn connect(&mut self, host: &str, port: u16, scheme: &str) -> ::Result<HttpStream> {
312312
let addr = &(host, port);
313-
match scheme {
313+
Ok(try!(match scheme {
314314
"http" => {
315315
debug!("http scheme");
316316
Ok(HttpStream::Http(CloneTcpStream(try!(TcpStream::connect(addr)))))
317317
},
318318
"https" => {
319319
debug!("https scheme");
320320
let stream = CloneTcpStream(try!(TcpStream::connect(addr)));
321-
let mut context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
321+
let mut context = try!(SslContext::new(Sslv23));
322322
if let Some(ref mut verifier) = self.0 {
323323
verifier(&mut context);
324324
}
325-
let ssl = try!(Ssl::new(&context).map_err(lift_ssl_error));
326-
try!(ssl.set_hostname(host).map_err(lift_ssl_error));
327-
let stream = try!(SslStream::new(&context, stream).map_err(lift_ssl_error));
325+
let ssl = try!(Ssl::new(&context));
326+
try!(ssl.set_hostname(host));
327+
let stream = try!(SslStream::new(&context, stream));
328328
Ok(HttpStream::Https(stream))
329329
},
330330
_ => {
331331
Err(io::Error::new(io::ErrorKind::InvalidInput,
332332
"Invalid scheme for Http"))
333333
}
334-
}
335-
}
336-
}
337-
338-
fn lift_ssl_error(ssl: SslError) -> io::Error {
339-
debug!("lift_ssl_error: {:?}", ssl);
340-
match ssl {
341-
StreamError(err) => err,
342-
SslSessionClosed => io::Error::new(io::ErrorKind::ConnectionAborted,
343-
"SSL Connection Closed"),
344-
e@OpenSslErrors(..) => io::Error::new(io::ErrorKind::Other, e)
334+
}))
345335
}
346336
}
347337

0 commit comments

Comments
 (0)