Merge pull request #506 from hyperium/error-ssl
feat(error): add Ssl variant to hyper::Error
This commit is contained in:
		| @@ -79,7 +79,7 @@ struct MockConnector; | |||||||
|  |  | ||||||
| impl net::NetworkConnector for MockConnector { | impl net::NetworkConnector for MockConnector { | ||||||
|     type Stream = MockStream; |     type Stream = MockStream; | ||||||
|     fn connect(&mut self, _: &str, _: u16, _: &str) -> io::Result<MockStream> { |     fn connect(&mut self, _: &str, _: u16, _: &str) -> hyper::Result<MockStream> { | ||||||
|         Ok(MockStream::new()) |         Ok(MockStream::new()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -144,7 +144,7 @@ impl<C: NetworkConnector<Stream=S> + Send, S: NetworkStream + Send> NetworkConne | |||||||
|     type Stream = Box<NetworkStream + Send>; |     type Stream = Box<NetworkStream + Send>; | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn connect(&mut self, host: &str, port: u16, scheme: &str) |     fn connect(&mut self, host: &str, port: u16, scheme: &str) | ||||||
|         -> io::Result<Box<NetworkStream + Send>> { |         -> ::Result<Box<NetworkStream + Send>> { | ||||||
|         Ok(try!(self.0.connect(host, port, scheme)).into()) |         Ok(try!(self.0.connect(host, port, scheme)).into()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -155,7 +155,7 @@ impl NetworkConnector for Connector { | |||||||
|     type Stream = Box<NetworkStream + Send>; |     type Stream = Box<NetworkStream + Send>; | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn connect(&mut self, host: &str, port: u16, scheme: &str) |     fn connect(&mut self, host: &str, port: u16, scheme: &str) | ||||||
|         -> io::Result<Box<NetworkStream + Send>> { |         -> ::Result<Box<NetworkStream + Send>> { | ||||||
|         Ok(try!(self.0.connect(host, port, scheme)).into()) |         Ok(try!(self.0.connect(host, port, scheme)).into()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -98,7 +98,7 @@ impl<S> PoolImpl<S> { | |||||||
|  |  | ||||||
| impl<C: NetworkConnector<Stream=S>, S: NetworkStream + Send> NetworkConnector for Pool<C> { | impl<C: NetworkConnector<Stream=S>, S: NetworkStream + Send> NetworkConnector for Pool<C> { | ||||||
|     type Stream = PooledStream<S>; |     type Stream = PooledStream<S>; | ||||||
|     fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<PooledStream<S>> { |     fn connect(&mut self, host: &str, port: u16, scheme: &str) -> ::Result<PooledStream<S>> { | ||||||
|         let key = key(host, port, scheme); |         let key = key(host, port, scheme); | ||||||
|         let mut locked = self.inner.lock().unwrap(); |         let mut locked = self.inner.lock().unwrap(); | ||||||
|         let mut should_remove = false; |         let mut should_remove = false; | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								src/error.rs
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								src/error.rs
									
									
									
									
									
								
							| @@ -4,11 +4,19 @@ use std::fmt; | |||||||
| use std::io::Error as IoError; | use std::io::Error as IoError; | ||||||
|  |  | ||||||
| use httparse; | use httparse; | ||||||
|  | use openssl::ssl::error::SslError; | ||||||
| use url; | use url; | ||||||
|  |  | ||||||
| use self::Error::{Method, Uri, Version, | use self::Error::{ | ||||||
|                       Header, Status, Io, |     Method, | ||||||
|                       TooLarge}; |     Uri, | ||||||
|  |     Version, | ||||||
|  |     Header, | ||||||
|  |     Status, | ||||||
|  |     Io, | ||||||
|  |     Ssl, | ||||||
|  |     TooLarge | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| /// Result type often returned from methods that can have hyper `Error`s. | /// Result type often returned from methods that can have hyper `Error`s. | ||||||
| @@ -29,8 +37,10 @@ pub enum Error { | |||||||
|     TooLarge, |     TooLarge, | ||||||
|     /// An invalid `Status`, such as `1337 ELITE`. |     /// An invalid `Status`, such as `1337 ELITE`. | ||||||
|     Status, |     Status, | ||||||
|     /// An `IoError` that occurred while trying to read or write to a network stream. |     /// An `io::Error` that occurred while trying to read or write to a network stream. | ||||||
|     Io(IoError), |     Io(IoError), | ||||||
|  |     /// An error from the `openssl` library. | ||||||
|  |     Ssl(SslError) | ||||||
| } | } | ||||||
|  |  | ||||||
| impl fmt::Display for Error { | impl fmt::Display for Error { | ||||||
| @@ -48,13 +58,15 @@ impl StdError for Error { | |||||||
|             Header => "Invalid Header provided", |             Header => "Invalid Header provided", | ||||||
|             TooLarge => "Message head is too large", |             TooLarge => "Message head is too large", | ||||||
|             Status => "Invalid Status provided", |             Status => "Invalid Status provided", | ||||||
|             Io(_) => "An IoError occurred while connecting to the specified network", |             Io(ref e) => e.description(), | ||||||
|  |             Ssl(ref e) => e.description(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn cause(&self) -> Option<&StdError> { |     fn cause(&self) -> Option<&StdError> { | ||||||
|         match *self { |         match *self { | ||||||
|             Io(ref error) => Some(error), |             Io(ref error) => Some(error), | ||||||
|  |             Ssl(ref error) => Some(error), | ||||||
|             Uri(ref error) => Some(error), |             Uri(ref error) => Some(error), | ||||||
|             _ => None, |             _ => None, | ||||||
|         } |         } | ||||||
| @@ -73,6 +85,15 @@ impl From<url::ParseError> for Error { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl From<SslError> for Error { | ||||||
|  |     fn from(err: SslError) -> Error { | ||||||
|  |         match err { | ||||||
|  |             SslError::StreamError(err) => Io(err), | ||||||
|  |             err => Ssl(err), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| impl From<httparse::Error> for Error { | impl From<httparse::Error> for Error { | ||||||
|     fn from(err: httparse::Error) -> Error { |     fn from(err: httparse::Error) -> Error { | ||||||
|         match err { |         match err { | ||||||
|   | |||||||
| @@ -73,7 +73,7 @@ pub struct MockConnector; | |||||||
| impl NetworkConnector for MockConnector { | impl NetworkConnector for MockConnector { | ||||||
|     type Stream = MockStream; |     type Stream = MockStream; | ||||||
|  |  | ||||||
|     fn connect(&mut self, _host: &str, _port: u16, _scheme: &str) -> io::Result<MockStream> { |     fn connect(&mut self, _host: &str, _port: u16, _scheme: &str) -> ::Result<MockStream> { | ||||||
|         Ok(MockStream::new()) |         Ok(MockStream::new()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -88,7 +88,7 @@ macro_rules! mock_connector ( | |||||||
|  |  | ||||||
|         impl ::net::NetworkConnector for $name { |         impl ::net::NetworkConnector for $name { | ||||||
|             type Stream = ::mock::MockStream; |             type Stream = ::mock::MockStream; | ||||||
|             fn connect(&mut self, host: &str, port: u16, scheme: &str) -> ::std::io::Result<::mock::MockStream> { |             fn connect(&mut self, host: &str, port: u16, scheme: &str) -> $crate::Result<::mock::MockStream> { | ||||||
|                 use std::collections::HashMap; |                 use std::collections::HashMap; | ||||||
|                 use std::io::Cursor; |                 use std::io::Cursor; | ||||||
|                 debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme); |                 debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme); | ||||||
| @@ -99,7 +99,7 @@ macro_rules! mock_connector ( | |||||||
|                 let key = format!("{}://{}", scheme, host); |                 let key = format!("{}://{}", scheme, host); | ||||||
|                 // ignore port for now |                 // ignore port for now | ||||||
|                 match map.get(&*key) { |                 match map.get(&*key) { | ||||||
|                     Some(res) => Ok(::mock::MockStream { |                     Some(res) => Ok($crate::mock::MockStream { | ||||||
|                         write: vec![], |                         write: vec![], | ||||||
|                         read: Cursor::new(res.to_string().into_bytes()), |                         read: Cursor::new(res.to_string().into_bytes()), | ||||||
|                     }), |                     }), | ||||||
|   | |||||||
							
								
								
									
										66
									
								
								src/net.rs
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								src/net.rs
									
									
									
									
									
								
							| @@ -9,7 +9,7 @@ use std::sync::Arc; | |||||||
|  |  | ||||||
| use openssl::ssl::{Ssl, SslStream, SslContext, SSL_VERIFY_NONE}; | use openssl::ssl::{Ssl, SslStream, SslContext, SSL_VERIFY_NONE}; | ||||||
| use openssl::ssl::SslMethod::Sslv23; | use openssl::ssl::SslMethod::Sslv23; | ||||||
| use openssl::ssl::error::{SslError, StreamError, OpenSslErrors, SslSessionClosed}; | use openssl::ssl::error::StreamError as SslIoError; | ||||||
| use openssl::x509::X509FileType; | use openssl::x509::X509FileType; | ||||||
|  |  | ||||||
| use typeable::Typeable; | use typeable::Typeable; | ||||||
| @@ -29,7 +29,7 @@ pub trait NetworkListener: Clone { | |||||||
|     //fn listen<To: ToSocketAddrs>(&mut self, addr: To) -> io::Result<Self::Acceptor>; |     //fn listen<To: ToSocketAddrs>(&mut self, addr: To) -> io::Result<Self::Acceptor>; | ||||||
|  |  | ||||||
|     /// Returns an iterator of streams. |     /// Returns an iterator of streams. | ||||||
|     fn accept(&mut self) -> io::Result<Self::Stream>; |     fn accept(&mut self) -> ::Result<Self::Stream>; | ||||||
|  |  | ||||||
|     /// Get the address this Listener ended up listening on. |     /// Get the address this Listener ended up listening on. | ||||||
|     fn local_addr(&mut self) -> io::Result<SocketAddr>; |     fn local_addr(&mut self) -> io::Result<SocketAddr>; | ||||||
| @@ -47,8 +47,8 @@ pub trait NetworkListener: Clone { | |||||||
| pub struct NetworkConnections<'a, N: NetworkListener + 'a>(&'a mut N); | pub struct NetworkConnections<'a, N: NetworkListener + 'a>(&'a mut N); | ||||||
|  |  | ||||||
| impl<'a, N: NetworkListener + 'a> Iterator for NetworkConnections<'a, N> { | impl<'a, N: NetworkListener + 'a> Iterator for NetworkConnections<'a, N> { | ||||||
|     type Item = io::Result<N::Stream>; |     type Item = ::Result<N::Stream>; | ||||||
|     fn next(&mut self) -> Option<io::Result<N::Stream>> { |     fn next(&mut self) -> Option<::Result<N::Stream>> { | ||||||
|         Some(self.0.accept()) |         Some(self.0.accept()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -58,6 +58,7 @@ pub trait NetworkStream: Read + Write + Any + Send + Typeable { | |||||||
|     /// Get the remote address of the underlying connection. |     /// Get the remote address of the underlying connection. | ||||||
|     fn peer_addr(&mut self) -> io::Result<SocketAddr>; |     fn peer_addr(&mut self) -> io::Result<SocketAddr>; | ||||||
|     /// This will be called when Stream should no longer be kept alive. |     /// This will be called when Stream should no longer be kept alive. | ||||||
|  |     #[inline] | ||||||
|     fn close(&mut self, _how: Shutdown) -> io::Result<()> { |     fn close(&mut self, _how: Shutdown) -> io::Result<()> { | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| @@ -68,7 +69,7 @@ pub trait NetworkConnector { | |||||||
|     /// Type of Stream to create |     /// Type of Stream to create | ||||||
|     type Stream: Into<Box<NetworkStream + Send>>; |     type Stream: Into<Box<NetworkStream + Send>>; | ||||||
|     /// Connect to a remote address. |     /// Connect to a remote address. | ||||||
|     fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<Self::Stream>; |     fn connect(&mut self, host: &str, port: u16, scheme: &str) -> ::Result<Self::Stream>; | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T: NetworkStream + Send> From<T> for Box<NetworkStream + Send> { | impl<T: NetworkStream + Send> From<T> for Box<NetworkStream + Send> { | ||||||
| @@ -158,22 +159,22 @@ impl Clone for HttpListener { | |||||||
| impl HttpListener { | impl HttpListener { | ||||||
|  |  | ||||||
|     /// Start listening to an address over HTTP. |     /// Start listening to an address over HTTP. | ||||||
|     pub fn http<To: ToSocketAddrs>(addr: To) -> io::Result<HttpListener> { |     pub fn http<To: ToSocketAddrs>(addr: To) -> ::Result<HttpListener> { | ||||||
|         Ok(HttpListener::Http(try!(TcpListener::bind(addr)))) |         Ok(HttpListener::Http(try!(TcpListener::bind(addr)))) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Start listening to an address over HTTPS. |     /// Start listening to an address over HTTPS. | ||||||
|     pub fn https<To: ToSocketAddrs>(addr: To, cert: &Path, key: &Path) -> io::Result<HttpListener> { |     pub fn https<To: ToSocketAddrs>(addr: To, cert: &Path, key: &Path) -> ::Result<HttpListener> { | ||||||
|         let mut ssl_context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error)); |         let mut ssl_context = try!(SslContext::new(Sslv23)); | ||||||
|         try!(ssl_context.set_cipher_list("DEFAULT").map_err(lift_ssl_error)); |         try!(ssl_context.set_cipher_list("DEFAULT")); | ||||||
|         try!(ssl_context.set_certificate_file(cert, X509FileType::PEM).map_err(lift_ssl_error)); |         try!(ssl_context.set_certificate_file(cert, X509FileType::PEM)); | ||||||
|         try!(ssl_context.set_private_key_file(key, X509FileType::PEM).map_err(lift_ssl_error)); |         try!(ssl_context.set_private_key_file(key, X509FileType::PEM)); | ||||||
|         ssl_context.set_verify(SSL_VERIFY_NONE, None); |         ssl_context.set_verify(SSL_VERIFY_NONE, None); | ||||||
|         HttpListener::https_with_context(addr, ssl_context) |         HttpListener::https_with_context(addr, ssl_context) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Start listening to an address of HTTPS using the given SslContext |     /// Start listening to an address of HTTPS using the given SslContext | ||||||
|     pub fn https_with_context<To: ToSocketAddrs>(addr: To, ssl_context: SslContext) -> io::Result<HttpListener> { |     pub fn https_with_context<To: ToSocketAddrs>(addr: To, ssl_context: SslContext) -> ::Result<HttpListener> { | ||||||
|         Ok(HttpListener::Https(try!(TcpListener::bind(addr)), Arc::new(ssl_context))) |         Ok(HttpListener::Https(try!(TcpListener::bind(addr)), Arc::new(ssl_context))) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -182,21 +183,20 @@ impl NetworkListener for HttpListener { | |||||||
|     type Stream = HttpStream; |     type Stream = HttpStream; | ||||||
|  |  | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn accept(&mut self) -> io::Result<HttpStream> { |     fn accept(&mut self) -> ::Result<HttpStream> { | ||||||
|         Ok(match *self { |         match *self { | ||||||
|             HttpListener::Http(ref mut tcp) => HttpStream::Http(CloneTcpStream(try!(tcp.accept()).0)), |             HttpListener::Http(ref mut tcp) => Ok(HttpStream::Http(CloneTcpStream(try!(tcp.accept()).0))), | ||||||
|             HttpListener::Https(ref mut tcp, ref ssl_context) => { |             HttpListener::Https(ref mut tcp, ref ssl_context) => { | ||||||
|                 let stream = CloneTcpStream(try!(tcp.accept()).0); |                 let stream = CloneTcpStream(try!(tcp.accept()).0); | ||||||
|                 match SslStream::new_server(&**ssl_context, stream) { |                 match SslStream::new_server(&**ssl_context, stream) { | ||||||
|                     Ok(ssl_stream) => HttpStream::Https(ssl_stream), |                     Ok(ssl_stream) => Ok(HttpStream::Https(ssl_stream)), | ||||||
|                     Err(StreamError(e)) => { |                     Err(SslIoError(e)) => { | ||||||
|                         return Err(io::Error::new(io::ErrorKind::ConnectionAborted, |                         Err(io::Error::new(io::ErrorKind::ConnectionAborted, e).into()) | ||||||
|                                                   e)); |  | ||||||
|                     }, |                     }, | ||||||
|                     Err(e) => return Err(lift_ssl_error(e)) |                     Err(e) => Err(e.into()) | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         }) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[inline] |     #[inline] | ||||||
| @@ -308,9 +308,9 @@ pub type ContextVerifier = Box<FnMut(&mut SslContext) -> () + Send>; | |||||||
| impl NetworkConnector for HttpConnector { | impl NetworkConnector for HttpConnector { | ||||||
|     type Stream = HttpStream; |     type Stream = HttpStream; | ||||||
|  |  | ||||||
|     fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<HttpStream> { |     fn connect(&mut self, host: &str, port: u16, scheme: &str) -> ::Result<HttpStream> { | ||||||
|         let addr = &(host, port); |         let addr = &(host, port); | ||||||
|         match scheme { |         Ok(try!(match scheme { | ||||||
|             "http" => { |             "http" => { | ||||||
|                 debug!("http scheme"); |                 debug!("http scheme"); | ||||||
|                 Ok(HttpStream::Http(CloneTcpStream(try!(TcpStream::connect(addr))))) |                 Ok(HttpStream::Http(CloneTcpStream(try!(TcpStream::connect(addr))))) | ||||||
| @@ -318,30 +318,20 @@ impl NetworkConnector for HttpConnector { | |||||||
|             "https" => { |             "https" => { | ||||||
|                 debug!("https scheme"); |                 debug!("https scheme"); | ||||||
|                 let stream = CloneTcpStream(try!(TcpStream::connect(addr))); |                 let stream = CloneTcpStream(try!(TcpStream::connect(addr))); | ||||||
|                 let mut context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error)); |                 let mut context = try!(SslContext::new(Sslv23)); | ||||||
|                 if let Some(ref mut verifier) = self.0 { |                 if let Some(ref mut verifier) = self.0 { | ||||||
|                     verifier(&mut context); |                     verifier(&mut context); | ||||||
|                 } |                 } | ||||||
|                 let ssl = try!(Ssl::new(&context).map_err(lift_ssl_error)); |                 let ssl = try!(Ssl::new(&context)); | ||||||
|                 try!(ssl.set_hostname(host).map_err(lift_ssl_error)); |                 try!(ssl.set_hostname(host)); | ||||||
|                 let stream = try!(SslStream::new(&context, stream).map_err(lift_ssl_error)); |                 let stream = try!(SslStream::new(&context, stream)); | ||||||
|                 Ok(HttpStream::Https(stream)) |                 Ok(HttpStream::Https(stream)) | ||||||
|             }, |             }, | ||||||
|             _ => { |             _ => { | ||||||
|                 Err(io::Error::new(io::ErrorKind::InvalidInput, |                 Err(io::Error::new(io::ErrorKind::InvalidInput, | ||||||
|                                 "Invalid scheme for Http")) |                                 "Invalid scheme for Http")) | ||||||
|             } |             } | ||||||
|         } |         })) | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| fn lift_ssl_error(ssl: SslError) -> io::Error { |  | ||||||
|     debug!("lift_ssl_error: {:?}", ssl); |  | ||||||
|     match ssl { |  | ||||||
|         StreamError(err) => err, |  | ||||||
|         SslSessionClosed => io::Error::new(io::ErrorKind::ConnectionAborted, |  | ||||||
|                                          "SSL Connection Closed"), |  | ||||||
|         e@OpenSslErrors(..) => io::Error::new(io::ErrorKind::Other, e) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user