//! A collection of traits abstracting over Listeners and Streams. use std::io::{self, Read, Write}; use std::net::{SocketAddr}; use rotor::mio::tcp::{TcpStream, TcpListener}; use rotor::mio::{Selector, Token, Evented, EventSet, PollOpt, TryAccept}; #[cfg(feature = "openssl")] pub use self::openssl::{Openssl, OpensslStream}; #[cfg(feature = "security-framework")] pub use self::security_framework::{SecureTransport, SecureTransportClient, SecureTransportServer}; /// A trait representing a socket transport that can be used in a Client or Server. #[cfg(not(windows))] pub trait Transport: Read + Write + Evented + ::vecio::Writev { /// Takes a socket error when event polling notices an `events.is_error()`. fn take_socket_error(&mut self) -> io::Result<()>; /// Returns if the this transport is blocked on read or write. /// /// By default, the user will declare whether they wish to wait on read /// or write events. However, some transports, such as those protected by /// TLS, may be blocked on reading before it can write, or vice versa. fn blocked(&self) -> Option { None } } /// A trait representing a socket transport that can be used in a Client or Server. #[cfg(windows)] pub trait Transport: Read + Write + Evented { /// Takes a socket error when event polling notices an `events.is_error()`. fn take_socket_error(&mut self) -> io::Result<()>; /// Returns if the this transport is blocked on read or write. /// /// By default, the user will declare whether they wish to wait on read /// or write events. However, some transports, such as those protected by /// TLS, may be blocked on reading before it can write, or vice versa. fn blocked(&self) -> Option { None } } /// Declares when a transport is blocked from any further action, until the /// corresponding event has occured. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Blocked { /// Blocked on reading Read, /// blocked on writing Write, } impl Transport for HttpStream { fn take_socket_error(&mut self) -> io::Result<()> { self.0.take_socket_error() } } /// Accepts sockets asynchronously. pub trait Accept: Evented { /// The transport type that is accepted. type Output: Transport; /// Accept a socket from the listener, if it doesn not block. fn accept(&self) -> io::Result>; /// Return the local `SocketAddr` of this listener. fn local_addr(&self) -> io::Result; } /// An alias to `mio::tcp::TcpStream`. #[derive(Debug)] pub struct HttpStream(pub TcpStream); impl Read for HttpStream { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } } impl Write for HttpStream { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } #[inline] fn flush(&mut self) -> io::Result<()> { self.0.flush() } } impl Evented for HttpStream { #[inline] fn register(&self, selector: &mut Selector, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> { self.0.register(selector, token, interest, opts) } #[inline] fn reregister(&self, selector: &mut Selector, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> { self.0.reregister(selector, token, interest, opts) } #[inline] fn deregister(&self, selector: &mut Selector) -> io::Result<()> { self.0.deregister(selector) } } #[cfg(not(windows))] impl ::vecio::Writev for HttpStream { #[inline] fn writev(&mut self, bufs: &[&[u8]]) -> io::Result { use ::vecio::Rawv; self.0.writev(bufs) } } /// An alias to `mio::tcp::TcpListener`. #[derive(Debug)] pub struct HttpListener(pub TcpListener); impl HttpListener { /// Bind to a socket address. pub fn bind(addr: &SocketAddr) -> io::Result { TcpListener::bind(addr) .map(HttpListener) } /// Try to duplicate the underlying listening socket. pub fn try_clone(&self) -> io::Result { self.0.try_clone().map(HttpListener) } } impl Accept for HttpListener { type Output = HttpStream; #[inline] fn accept(&self) -> io::Result> { TryAccept::accept(&self.0).map(|ok| ok.map(HttpStream)) } #[inline] fn local_addr(&self) -> io::Result { self.0.local_addr() } } impl Evented for HttpListener { #[inline] fn register(&self, selector: &mut Selector, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> { self.0.register(selector, token, interest, opts) } #[inline] fn reregister(&self, selector: &mut Selector, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> { self.0.reregister(selector, token, interest, opts) } #[inline] fn deregister(&self, selector: &mut Selector) -> io::Result<()> { self.0.deregister(selector) } } /// Deprecated /// /// Use `SslClient` and `SslServer` instead. pub trait Ssl { /// The protected stream. type Stream: Transport; /// Wrap a client stream with SSL. fn wrap_client(&self, stream: HttpStream, host: &str) -> ::Result; /// Wrap a server stream with SSL. fn wrap_server(&self, stream: HttpStream) -> ::Result; } /// An abstraction to allow any SSL implementation to be used with client-side HttpsStreams. pub trait SslClient { /// The protected stream. type Stream: Transport; /// Wrap a client stream with SSL. fn wrap_client(&self, stream: HttpStream, host: &str) -> ::Result; } /// An abstraction to allow any SSL implementation to be used with server-side HttpsStreams. pub trait SslServer { /// The protected stream. type Stream: Transport; /// Wrap a server stream with SSL. fn wrap_server(&self, stream: HttpStream) -> ::Result; } impl SslClient for S { type Stream = ::Stream; fn wrap_client(&self, stream: HttpStream, host: &str) -> ::Result { Ssl::wrap_client(self, stream, host) } } impl SslServer for S { type Stream = ::Stream; fn wrap_server(&self, stream: HttpStream) -> ::Result { Ssl::wrap_server(self, stream) } } /// A stream over the HTTP protocol, possibly protected by TLS. #[derive(Debug)] pub enum HttpsStream { /// A plain text stream. Http(HttpStream), /// A stream protected by TLS. Https(S) } impl Read for HttpsStream { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { match *self { HttpsStream::Http(ref mut s) => s.read(buf), HttpsStream::Https(ref mut s) => s.read(buf) } } } impl Write for HttpsStream { #[inline] fn write(&mut self, msg: &[u8]) -> io::Result { match *self { HttpsStream::Http(ref mut s) => s.write(msg), HttpsStream::Https(ref mut s) => s.write(msg) } } #[inline] fn flush(&mut self) -> io::Result<()> { match *self { HttpsStream::Http(ref mut s) => s.flush(), HttpsStream::Https(ref mut s) => s.flush() } } } #[cfg(not(windows))] impl ::vecio::Writev for HttpsStream { #[inline] fn writev(&mut self, bufs: &[&[u8]]) -> io::Result { match *self { HttpsStream::Http(ref mut s) => s.writev(bufs), HttpsStream::Https(ref mut s) => s.writev(bufs) } } } #[cfg(unix)] impl ::std::os::unix::io::AsRawFd for HttpStream { #[inline] fn as_raw_fd(&self) -> ::std::os::unix::io::RawFd { self.0.as_raw_fd() } } #[cfg(unix)] impl ::std::os::unix::io::AsRawFd for HttpsStream { #[inline] fn as_raw_fd(&self) -> ::std::os::unix::io::RawFd { match *self { HttpsStream::Http(ref s) => s.as_raw_fd(), HttpsStream::Https(ref s) => s.as_raw_fd(), } } } impl Evented for HttpsStream { #[inline] fn register(&self, selector: &mut Selector, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> { match *self { HttpsStream::Http(ref s) => s.register(selector, token, interest, opts), HttpsStream::Https(ref s) => s.register(selector, token, interest, opts), } } #[inline] fn reregister(&self, selector: &mut Selector, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> { match *self { HttpsStream::Http(ref s) => s.reregister(selector, token, interest, opts), HttpsStream::Https(ref s) => s.reregister(selector, token, interest, opts), } } #[inline] fn deregister(&self, selector: &mut Selector) -> io::Result<()> { match *self { HttpsStream::Http(ref s) => s.deregister(selector), HttpsStream::Https(ref s) => s.deregister(selector), } } } impl Transport for HttpsStream { #[inline] fn take_socket_error(&mut self) -> io::Result<()> { match *self { HttpsStream::Http(ref mut s) => s.take_socket_error(), HttpsStream::Https(ref mut s) => s.take_socket_error(), } } #[inline] fn blocked(&self) -> Option { match *self { HttpsStream::Http(ref s) => s.blocked(), HttpsStream::Https(ref s) => s.blocked(), } } } /// A Http Listener over SSL. #[derive(Debug)] pub struct HttpsListener { listener: TcpListener, ssl: S, } impl HttpsListener { /// Start listening to an address over HTTPS. #[inline] pub fn new(addr: &SocketAddr, ssl: S) -> io::Result> { TcpListener::bind(addr).map(|l| HttpsListener { listener: l, ssl: ssl }) } /// Construct an HttpsListener from a bound `TcpListener`. pub fn with_listener(listener: TcpListener, ssl: S) -> HttpsListener { HttpsListener { listener: listener, ssl: ssl } } } impl Accept for HttpsListener { type Output = S::Stream; #[inline] fn accept(&self) -> io::Result> { self.listener.accept().and_then(|s| match s { Some((s, _)) => self.ssl.wrap_server(HttpStream(s)).map(Some).map_err(|e| { match e { ::Error::Io(e) => e, _ => io::Error::new(io::ErrorKind::Other, e), } }), None => Ok(None), }) } #[inline] fn local_addr(&self) -> io::Result { self.listener.local_addr() } } impl Evented for HttpsListener { #[inline] fn register(&self, selector: &mut Selector, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> { self.listener.register(selector, token, interest, opts) } #[inline] fn reregister(&self, selector: &mut Selector, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> { self.listener.reregister(selector, token, interest, opts) } #[inline] fn deregister(&self, selector: &mut Selector) -> io::Result<()> { self.listener.deregister(selector) } } fn _assert_transport() { fn _assert() {} _assert::>(); } /* #[cfg(all(not(feature = "openssl"), not(feature = "security-framework")))] #[doc(hidden)] pub type DefaultConnector = HttpConnector; #[cfg(feature = "openssl")] #[doc(hidden)] pub type DefaultConnector = HttpsConnector; #[cfg(all(feature = "security-framework", not(feature = "openssl")))] pub type DefaultConnector = HttpsConnector; #[doc(hidden)] pub type DefaultTransport = ::Output; */ #[cfg(feature = "openssl")] mod openssl { use std::io::{self, Write}; use std::path::Path; use rotor::mio::{Selector, Token, Evented, EventSet, PollOpt}; use openssl::ssl::{Ssl, SslContext, SslStream, SslMethod, SSL_VERIFY_PEER, SSL_OP_NO_SSLV2, SSL_OP_NO_SSLV3, SSL_OP_NO_COMPRESSION}; use openssl::ssl::error::StreamError as SslIoError; use openssl::ssl::error::SslError; use openssl::ssl::error::Error as OpensslError; use openssl::x509::X509FileType; use super::{HttpStream, Blocked}; /// An implementation of `Ssl` for OpenSSL. /// /// # Example /// /// ```no_run /// use hyper::Server; /// use hyper::net::Openssl; /// /// let ssl = Openssl::with_cert_and_key("/home/foo/cert", "/home/foo/key").unwrap(); /// Server::https(&"0.0.0.0:443".parse().unwrap(), ssl).unwrap(); /// ``` /// /// For complete control, create a `SslContext` with the options you desire /// and then create `Openssl { context: ctx } #[derive(Debug, Clone)] pub struct Openssl { /// The `SslContext` from openssl crate. pub context: SslContext } /// A client-specific implementation of OpenSSL. #[derive(Debug, Clone)] pub struct OpensslClient(SslContext); impl Default for OpensslClient { fn default() -> OpensslClient { let mut ctx = SslContext::new(SslMethod::Sslv23).unwrap(); ctx.set_default_verify_paths().unwrap(); ctx.set_options(SSL_OP_NO_SSLV2 | SSL_OP_NO_SSLV3 | SSL_OP_NO_COMPRESSION); // cipher list taken from curl: // https://github.com/curl/curl/blob/5bf5f6ebfcede78ef7c2b16daa41c4b7ba266087/lib/vtls/openssl.h#L120 ctx.set_cipher_list("ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW!RC4@STRENGTH").unwrap(); OpensslClient::new(ctx) } } impl OpensslClient { /// Creates a new OpensslClient with a custom SslContext pub fn new(ctx: SslContext) -> OpensslClient { OpensslClient(ctx) } } impl super::SslClient for OpensslClient { type Stream = OpensslStream; #[cfg(not(windows))] fn wrap_client(&self, stream: HttpStream, host: &str) -> ::Result { let mut ssl = try!(Ssl::new(&self.0)); try!(ssl.set_hostname(host)); let host = host.to_owned(); ssl.set_verify_callback(SSL_VERIFY_PEER, move |p, x| ::openssl_verify::verify_callback(&host, p, x)); SslStream::connect(ssl, stream) .map(openssl_stream) .map_err(From::from) } #[cfg(windows)] fn wrap_client(&self, stream: HttpStream, host: &str) -> ::Result { let mut ssl = try!(Ssl::new(&self.0)); try!(ssl.set_hostname(host)); SslStream::connect(ssl, stream) .map(openssl_stream) .map_err(From::from) } } impl Default for Openssl { fn default() -> Openssl { Openssl { context: SslContext::new(SslMethod::Sslv23).unwrap_or_else(|e| { // if we cannot create a SslContext, that's because of a // serious problem. just crash. panic!("{}", e) }) } } } impl Openssl { /// Ease creating an `Openssl` with a certificate and key. pub fn with_cert_and_key(cert: C, key: K) -> Result where C: AsRef, K: AsRef { let mut ctx = try!(SslContext::new(SslMethod::Sslv23)); try!(ctx.set_cipher_list("ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW!RC4@STRENGTH")); try!(ctx.set_certificate_file(cert.as_ref(), X509FileType::PEM)); try!(ctx.set_private_key_file(key.as_ref(), X509FileType::PEM)); Ok(Openssl { context: ctx }) } } impl super::Ssl for Openssl { type Stream = OpensslStream; fn wrap_client(&self, stream: HttpStream, host: &str) -> ::Result { let ssl = try!(Ssl::new(&self.context)); try!(ssl.set_hostname(host)); SslStream::connect(ssl, stream) .map(openssl_stream) .map_err(From::from) } fn wrap_server(&self, stream: HttpStream) -> ::Result { match SslStream::accept(&self.context, stream) { Ok(ssl_stream) => Ok(openssl_stream(ssl_stream)), Err(SslIoError(e)) => { Err(io::Error::new(io::ErrorKind::ConnectionAborted, e).into()) }, Err(e) => Err(e.into()) } } } /// A transport protected by OpenSSL. #[derive(Debug)] pub struct OpensslStream { stream: SslStream, blocked: Option, } fn openssl_stream(inner: SslStream) -> OpensslStream { OpensslStream { stream: inner, blocked: None, } } impl io::Read for OpensslStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.blocked = None; self.stream.ssl_read(buf).or_else(|e| match e { OpensslError::ZeroReturn => Ok(0), OpensslError::WantWrite(e) => { self.blocked = Some(Blocked::Write); Err(e) }, OpensslError::WantRead(e) | OpensslError::Stream(e) => Err(e), e => Err(io::Error::new(io::ErrorKind::Other, e)) }) } } impl io::Write for OpensslStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.blocked = None; self.stream.ssl_write(buf).or_else(|e| match e { OpensslError::ZeroReturn => Ok(0), OpensslError::WantRead(e) => { self.blocked = Some(Blocked::Read); Err(e) }, OpensslError::WantWrite(e) | OpensslError::Stream(e) => Err(e), e => Err(io::Error::new(io::ErrorKind::Other, e)) }) } fn flush(&mut self) -> io::Result<()> { self.stream.flush() } } impl Evented for OpensslStream { #[inline] fn register(&self, selector: &mut Selector, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> { self.stream.get_ref().register(selector, token, interest, opts) } #[inline] fn reregister(&self, selector: &mut Selector, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> { self.stream.get_ref().reregister(selector, token, interest, opts) } #[inline] fn deregister(&self, selector: &mut Selector) -> io::Result<()> { self.stream.get_ref().deregister(selector) } } impl ::vecio::Writev for OpensslStream { fn writev(&mut self, bufs: &[&[u8]]) -> io::Result { let vec = bufs.concat(); self.write(&vec) } } impl super::Transport for OpensslStream { fn take_socket_error(&mut self) -> io::Result<()> { self.stream.get_mut().take_socket_error() } } } #[cfg(feature = "security-framework")] mod security_framework { use std::io::{self, Read, Write}; use error::Error; use net::{SslClient, SslServer, HttpStream, Transport, Blocked}; use security_framework::secure_transport::SslStream; pub use security_framework::secure_transport::{ClientBuilder as SecureTransportClient, ServerBuilder as SecureTransportServer}; use rotor::mio::{Selector, Token, Evented, EventSet, PollOpt}; impl SslClient for SecureTransportClient { type Stream = SecureTransport; fn wrap_client(&self, stream: HttpStream, host: &str) -> ::Result { match self.handshake(host, journal(stream)) { Ok(s) => Ok(SecureTransport(s)), Err(e) => Err(Error::Ssl(e.into())), } } } impl SslServer for SecureTransportServer { type Stream = SecureTransport; fn wrap_server(&self, stream: HttpStream) -> ::Result { match self.handshake(journal(stream)) { Ok(s) => Ok(SecureTransport(s)), Err(e) => Err(Error::Ssl(e.into())), } } } /// A transport protected by Security Framework. #[derive(Debug)] pub struct SecureTransport(SslStream>); impl io::Read for SecureTransport { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } } impl io::Write for SecureTransport { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } #[inline] fn flush(&mut self) -> io::Result<()> { self.0.flush() } } impl Evented for SecureTransport { #[inline] fn register(&self, selector: &mut Selector, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> { self.0.get_ref().inner.register(selector, token, interest, opts) } #[inline] fn reregister(&self, selector: &mut Selector, token: Token, interest: EventSet, opts: PollOpt) -> io::Result<()> { self.0.get_ref().inner.reregister(selector, token, interest, opts) } #[inline] fn deregister(&self, selector: &mut Selector) -> io::Result<()> { self.0.get_ref().inner.deregister(selector) } } impl ::vecio::Writev for SecureTransport { fn writev(&mut self, bufs: &[&[u8]]) -> io::Result { let vec = bufs.concat(); self.write(&vec) } } impl Transport for SecureTransport { fn take_socket_error(&mut self) -> io::Result<()> { self.0.get_mut().inner.take_socket_error() } fn blocked(&self) -> Option { self.0.get_ref().blocked } } // Records if this object was blocked on reading or writing. #[derive(Debug)] struct Journal { inner: T, blocked: Option, } fn journal(inner: T) -> Journal { Journal { inner: inner, blocked: None, } } impl Read for Journal { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.blocked = None; self.inner.read(buf).map_err(|e| match e.kind() { io::ErrorKind::WouldBlock => { self.blocked = Some(Blocked::Read); e }, _ => e }) } } impl Write for Journal { fn write(&mut self, buf: &[u8]) -> io::Result { self.blocked = None; self.inner.write(buf).map_err(|e| match e.kind() { io::ErrorKind::WouldBlock => { self.blocked = Some(Blocked::Write); e }, _ => e }) } fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } }