//! A collection of traits abstracting over Listeners and Streams. use std::any::{Any, TypeId}; use std::fmt; use std::io::{self, Read, Write}; use std::net::{SocketAddr, ToSocketAddrs, TcpStream, TcpListener}; use std::mem; use std::path::Path; use std::raw::{self, TraitObject}; use std::sync::Arc; use openssl::ssl::{Ssl, SslStream, SslContext}; use openssl::ssl::SslVerifyMode::SslVerifyNone; use openssl::ssl::SslMethod::Sslv23; use openssl::ssl::error::{SslError, StreamError, OpenSslErrors, SslSessionClosed}; use openssl::x509::X509FileType; macro_rules! try_some { ($expr:expr) => (match $expr { Some(val) => { return Err(val); }, _ => {} }) } /// The write-status indicating headers have not been written. pub enum Fresh {} /// The write-status indicating headers have been written. pub enum Streaming {} /// An abstraction to listen for connections on a certain port. pub trait NetworkListener: Clone { /// The stream produced for each connection. type Stream: NetworkStream + Send + Clone; /// Listens on a socket. //fn listen(&mut self, addr: To) -> io::Result; /// Returns an iterator of streams. fn accept(&mut self) -> io::Result; /// Get the address this Listener ended up listening on. fn socket_addr(&mut self) -> io::Result; /// Closes the Acceptor, so no more incoming connections will be handled. // fn close(&mut self) -> io::Result<()>; /// Returns an iterator over incoming connections. fn incoming(&mut self) -> NetworkConnections { NetworkConnections(self) } } /// An iterator wrapper over a NetworkAcceptor. pub struct NetworkConnections<'a, N: NetworkListener + 'a>(&'a mut N); impl<'a, N: NetworkListener + 'a> Iterator for NetworkConnections<'a, N> { type Item = io::Result; fn next(&mut self) -> Option> { Some(self.0.accept()) } } /// An abstraction over streams that a Server can utilize. pub trait NetworkStream: Read + Write + Any + StreamClone + Send { /// Get the remote address of the underlying connection. fn peer_addr(&mut self) -> io::Result; } #[doc(hidden)] pub trait StreamClone { fn clone_box(&self) -> Box; } impl StreamClone for T { #[inline] fn clone_box(&self) -> Box { Box::new(self.clone()) } } /// A connector creates a NetworkStream. pub trait NetworkConnector { /// Type of Stream to create type Stream: NetworkStream + Send; /// Connect to a remote address. fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result; } impl fmt::Debug for Box { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.pad("Box") } } impl Clone for Box { #[inline] fn clone(&self) -> Box { self.clone_box() } } impl NetworkStream { unsafe fn downcast_ref_unchecked(&self) -> &T { mem::transmute(mem::transmute::<&NetworkStream, raw::TraitObject>(self).data) } unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { mem::transmute(mem::transmute::<&mut NetworkStream, raw::TraitObject>(self).data) } unsafe fn downcast_unchecked(self: Box) -> Box { mem::transmute(mem::transmute::, raw::TraitObject>(self).data) } } impl NetworkStream { /// Is the underlying type in this trait object a T? #[inline] pub fn is(&self) -> bool { self.get_type_id() == TypeId::of::() } /// If the underlying type is T, get a reference to the contained data. #[inline] pub fn downcast_ref(&self) -> Option<&T> { if self.is::() { Some(unsafe { self.downcast_ref_unchecked() }) } else { None } } /// If the underlying type is T, get a mutable reference to the contained /// data. #[inline] pub fn downcast_mut(&mut self) -> Option<&mut T> { if self.is::() { Some(unsafe { self.downcast_mut_unchecked() }) } else { None } } /// If the underlying type is T, extract it. pub fn downcast(self: Box) -> Result, Box> { if self.is::() { Ok(unsafe { self.downcast_unchecked() }) } else { Err(self) } } } /// A `NetworkListener` for `HttpStream`s. pub enum HttpListener { /// Http variant. Http(TcpListener), /// Https variant. The two paths point to the certificate and key PEM files, in that order. Https(TcpListener, Arc) } impl Clone for HttpListener { fn clone(&self) -> HttpListener { match *self { HttpListener::Http(ref tcp) => HttpListener::Http(tcp.try_clone().unwrap()), HttpListener::Https(ref tcp, ref ssl) => HttpListener::Https(tcp.try_clone().unwrap(), ssl.clone()), } } } impl HttpListener { /// Start listening to an address over HTTP. pub fn http(addr: &To) -> io::Result { Ok(HttpListener::Http(try!(TcpListener::bind(addr)))) } /// Start listening to an address over HTTPS. pub fn https(addr: &To, cert: &Path, key: &Path) -> io::Result { let mut ssl_context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error)); try_some!(ssl_context.set_cipher_list("DEFAULT").map(lift_ssl_error)); try_some!(ssl_context.set_certificate_file( cert, X509FileType::PEM).map(lift_ssl_error)); try_some!(ssl_context.set_private_key_file( key, X509FileType::PEM).map(lift_ssl_error)); ssl_context.set_verify(SslVerifyNone, None); Ok(HttpListener::Https(try!(TcpListener::bind(addr)), Arc::new(ssl_context))) } } impl NetworkListener for HttpListener { type Stream = HttpStream; #[inline] fn accept(&mut self) -> io::Result { Ok(match *self { HttpListener::Http(ref mut tcp) => HttpStream::Http(CloneTcpStream(try!(tcp.accept()).0)), HttpListener::Https(ref mut tcp, ref ssl_context) => { let stream = CloneTcpStream(try!(tcp.accept()).0); match SslStream::new_server(&**ssl_context, stream) { Ok(ssl_stream) => HttpStream::Https(ssl_stream), Err(StreamError(ref e)) => { return Err(io::Error::new(io::ErrorKind::ConnectionAborted, "SSL Handshake Interrupted", Some(e.to_string()))); }, Err(e) => return Err(lift_ssl_error(e)) } } }) } #[inline] fn socket_addr(&mut self) -> io::Result { match *self { HttpListener::Http(ref mut tcp) => tcp.socket_addr(), HttpListener::Https(ref mut tcp, _) => tcp.socket_addr(), } } } #[doc(hidden)] pub struct CloneTcpStream(TcpStream); impl Clone for CloneTcpStream{ #[inline] fn clone(&self) -> CloneTcpStream { CloneTcpStream(self.0.try_clone().unwrap()) } } impl Read for CloneTcpStream { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } } impl Write for CloneTcpStream { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } #[inline] fn flush(&mut self) -> io::Result<()> { self.0.flush() } } /// A wrapper around a TcpStream. #[derive(Clone)] pub enum HttpStream { /// A stream over the HTTP protocol. Http(CloneTcpStream), /// A stream over the HTTP protocol, protected by SSL. Https(SslStream), } impl Read for HttpStream { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { match *self { HttpStream::Http(ref mut inner) => inner.read(buf), HttpStream::Https(ref mut inner) => inner.read(buf) } } } impl Write for HttpStream { #[inline] fn write(&mut self, msg: &[u8]) -> io::Result { match *self { HttpStream::Http(ref mut inner) => inner.write(msg), HttpStream::Https(ref mut inner) => inner.write(msg) } } #[inline] fn flush(&mut self) -> io::Result<()> { match *self { HttpStream::Http(ref mut inner) => inner.flush(), HttpStream::Https(ref mut inner) => inner.flush(), } } } impl NetworkStream for HttpStream { fn peer_addr(&mut self) -> io::Result { match *self { HttpStream::Http(ref mut inner) => inner.0.peer_addr(), HttpStream::Https(ref mut inner) => inner.get_mut().0.peer_addr() } } } /// A connector that will produce HttpStreams. #[allow(missing_copy_implementations)] pub struct HttpConnector<'v>(pub Option>); /// A method that can set verification methods on an SSL context pub type ContextVerifier<'v> = Box ()+'v>; impl<'v> NetworkConnector for HttpConnector<'v> { type Stream = HttpStream; fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result { let addr = &(host, port); match scheme { "http" => { debug!("http scheme"); Ok(HttpStream::Http(CloneTcpStream(try!(TcpStream::connect(addr))))) }, "https" => { debug!("https scheme"); let stream = CloneTcpStream(try!(TcpStream::connect(addr))); let mut context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error)); if let Some(ref mut verifier) = self.0 { verifier(&mut context); } let ssl = try!(Ssl::new(&context).map_err(lift_ssl_error)); try!(ssl.set_hostname(host).map_err(lift_ssl_error)); let stream = try!(SslStream::new(&context, stream).map_err(lift_ssl_error)); Ok(HttpStream::Https(stream)) }, _ => { Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid scheme for Http", None)) } } } } 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", None), // Unfortunately throw this away. No way to support this // detail without a better Error abstraction. OpenSslErrors(errs) => io::Error::new(io::ErrorKind::Other, "Error in OpenSSL", Some(format!("{:?}", errs))) } } #[cfg(test)] mod tests { use mock::MockStream; use super::NetworkStream; #[test] fn test_downcast_box_stream() { let stream = box MockStream::new() as Box; let mock = stream.downcast::().ok().unwrap(); assert_eq!(mock, box MockStream::new()); } #[test] fn test_downcast_unchecked_box_stream() { let stream = box MockStream::new() as Box; let mock = unsafe { stream.downcast_unchecked::() }; assert_eq!(mock, box MockStream::new()); } }