feat(lib): redesign API to use Futures and Tokio
There are many changes involved with this, but let's just talk about
user-facing changes.
- Creating a `Client` and `Server` now needs a Tokio `Core` event loop
to attach to.
- `Request` and `Response` both no longer implement the
`std::io::{Read,Write}` traits, but instead represent their bodies as a
`futures::Stream` of items, where each item is a `Chunk`.
- The `Client.request` method now takes a `Request`, instead of being
used as a builder, and returns a `Future` that resolves to `Response`.
- The `Handler` trait for servers is no more, and instead the Tokio
`Service` trait is used. This allows interoperability with generic
middleware.
BREAKING CHANGE: A big sweeping set of breaking changes.
This commit is contained in:
605
src/net.rs
605
src/net.rs
@@ -3,77 +3,12 @@ use std::io::{self, Read, Write};
|
||||
use std::net::{SocketAddr};
|
||||
use std::option;
|
||||
|
||||
use rotor::mio::tcp::{TcpStream, TcpListener};
|
||||
use rotor::mio::{Selector, Token, Evented, EventSet, PollOpt, TryAccept};
|
||||
use std::net::{TcpStream, TcpListener};
|
||||
|
||||
#[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<Blocked> {
|
||||
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<Blocked> {
|
||||
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,
|
||||
}
|
||||
|
||||
|
||||
/// 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<Option<Self::Output>>;
|
||||
/// Return the local `SocketAddr` of this listener.
|
||||
fn local_addr(&self) -> io::Result<SocketAddr>;
|
||||
}
|
||||
|
||||
/// An alias to `mio::tcp::TcpStream`.
|
||||
#[derive(Debug)]
|
||||
pub struct HttpStream(pub TcpStream);
|
||||
|
||||
impl Transport for HttpStream {
|
||||
fn take_socket_error(&mut self) -> io::Result<()> {
|
||||
self.0.take_socket_error()
|
||||
}
|
||||
}
|
||||
//#[derive(Debug)]
|
||||
pub struct HttpStream(pub ::tokio::net::TcpStream);
|
||||
|
||||
impl Read for HttpStream {
|
||||
#[inline]
|
||||
@@ -94,23 +29,7 @@ impl Write for HttpStream {
|
||||
}
|
||||
}
|
||||
|
||||
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]
|
||||
@@ -119,6 +38,7 @@ impl ::vecio::Writev for HttpStream {
|
||||
self.0.writev(bufs)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/// An alias to `mio::tcp::TcpListener`.
|
||||
#[derive(Debug)]
|
||||
@@ -137,59 +57,7 @@ impl HttpListener {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Accept for HttpListener {
|
||||
type Output = HttpStream;
|
||||
|
||||
#[inline]
|
||||
fn accept(&self) -> io::Result<Option<HttpStream>> {
|
||||
TryAccept::accept(&self.0).map(|ok| ok.map(HttpStream))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn local_addr(&self) -> io::Result<SocketAddr> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for HttpListener {
|
||||
type Item = Self;
|
||||
type IntoIter = option::IntoIter<Self>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
Some(self).into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<Self::Stream>;
|
||||
/// Wrap a server stream with SSL.
|
||||
fn wrap_server(&self, stream: HttpStream) -> ::Result<Self::Stream>;
|
||||
}
|
||||
|
||||
/*
|
||||
/// An abstraction to allow any SSL implementation to be used with client-side `HttpsStream`s.
|
||||
pub trait SslClient {
|
||||
/// The protected stream.
|
||||
@@ -206,21 +74,6 @@ pub trait SslServer {
|
||||
fn wrap_server(&self, stream: HttpStream) -> ::Result<Self::Stream>;
|
||||
}
|
||||
|
||||
impl<S: Ssl> SslClient for S {
|
||||
type Stream = <S as Ssl>::Stream;
|
||||
|
||||
fn wrap_client(&self, stream: HttpStream, host: &str) -> ::Result<Self::Stream> {
|
||||
Ssl::wrap_client(self, stream, host)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Ssl> SslServer for S {
|
||||
type Stream = <S as Ssl>::Stream;
|
||||
|
||||
fn wrap_server(&self, stream: HttpStream) -> ::Result<Self::Stream> {
|
||||
Ssl::wrap_server(self, stream)
|
||||
}
|
||||
}
|
||||
|
||||
/// A stream over the HTTP protocol, possibly protected by TLS.
|
||||
#[derive(Debug)]
|
||||
@@ -259,6 +112,7 @@ impl<S: Transport> Write for HttpsStream<S> {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(not(windows))]
|
||||
impl<S: Transport> ::vecio::Writev for HttpsStream<S> {
|
||||
#[inline]
|
||||
@@ -269,8 +123,10 @@ impl<S: Transport> ::vecio::Writev for HttpsStream<S> {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
#[cfg(unix)]
|
||||
impl ::std::os::unix::io::AsRawFd for HttpStream {
|
||||
#[inline]
|
||||
@@ -289,50 +145,7 @@ impl<S: Transport + ::std::os::unix::io::AsRawFd> ::std::os::unix::io::AsRawFd f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Transport> Evented for HttpsStream<S> {
|
||||
#[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<S: Transport> Transport for HttpsStream<S> {
|
||||
#[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<Blocked> {
|
||||
match *self {
|
||||
HttpsStream::Http(ref s) => s.blocked(),
|
||||
HttpsStream::Https(ref s) => s.blocked(),
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/// An `HttpListener` over SSL.
|
||||
#[derive(Debug)]
|
||||
@@ -360,6 +173,7 @@ impl<S: SslServer> HttpsListener<S> {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl<S: SslServer> Accept for HttpsListener<S> {
|
||||
type Output = S::Stream;
|
||||
|
||||
@@ -382,401 +196,6 @@ impl<S: SslServer> Accept for HttpsListener<S> {
|
||||
self.listener.local_addr()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: SslServer> Evented for HttpsListener<S> {
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: SslServer> IntoIterator for HttpsListener<S> {
|
||||
type Item = Self;
|
||||
type IntoIter = option::IntoIter<Self>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
Some(self).into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
fn _assert_transport() {
|
||||
fn _assert<T: Transport>() {}
|
||||
_assert::<HttpsStream<HttpStream>>();
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(all(not(feature = "openssl"), not(feature = "security-framework")))]
|
||||
#[doc(hidden)]
|
||||
pub type DefaultConnector = HttpConnector;
|
||||
|
||||
#[cfg(feature = "openssl")]
|
||||
#[doc(hidden)]
|
||||
pub type DefaultConnector = HttpsConnector<self::openssl::OpensslClient>;
|
||||
|
||||
#[cfg(all(feature = "security-framework", not(feature = "openssl")))]
|
||||
pub type DefaultConnector = HttpsConnector<self::security_framework::ClientWrapper>;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub type DefaultTransport = <DefaultConnector as Connect>::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<HttpStream>;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn wrap_client(&self, stream: HttpStream, host: &str) -> ::Result<Self::Stream> {
|
||||
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<Self::Stream> {
|
||||
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<C, K>(cert: C, key: K) -> Result<Openssl, SslError>
|
||||
where C: AsRef<Path>, K: AsRef<Path> {
|
||||
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<HttpStream>;
|
||||
|
||||
fn wrap_client(&self, stream: HttpStream, host: &str) -> ::Result<Self::Stream> {
|
||||
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<Self::Stream> {
|
||||
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<T> {
|
||||
stream: SslStream<T>,
|
||||
blocked: Option<Blocked>,
|
||||
}
|
||||
|
||||
fn openssl_stream<T>(inner: SslStream<T>) -> OpensslStream<T> {
|
||||
OpensslStream {
|
||||
stream: inner,
|
||||
blocked: None,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: super::Transport> io::Read for OpensslStream<T> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
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<T: super::Transport> io::Write for OpensslStream<T> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
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<T: super::Transport> Evented for OpensslStream<T> {
|
||||
#[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<T: super::Transport> ::vecio::Writev for OpensslStream<T> {
|
||||
fn writev(&mut self, bufs: &[&[u8]]) -> io::Result<usize> {
|
||||
let vec = bufs.concat();
|
||||
self.write(&vec)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: super::Transport> super::Transport for OpensslStream<T> {
|
||||
fn take_socket_error(&mut self) -> io::Result<()> {
|
||||
self.stream.get_mut().take_socket_error()
|
||||
}
|
||||
|
||||
fn blocked(&self) -> Option<super::Blocked> {
|
||||
self.blocked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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<HttpStream>;
|
||||
|
||||
fn wrap_client(&self, stream: HttpStream, host: &str) -> ::Result<Self::Stream> {
|
||||
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<HttpStream>;
|
||||
|
||||
fn wrap_server(&self, stream: HttpStream) -> ::Result<Self::Stream> {
|
||||
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<T>(SslStream<Journal<T>>);
|
||||
|
||||
impl<T: Transport> io::Read for SecureTransport<T> {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Transport> io::Write for SecureTransport<T> {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buf)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.0.flush()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T: Transport> Evented for SecureTransport<T> {
|
||||
#[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<T: Transport> ::vecio::Writev for SecureTransport<T> {
|
||||
fn writev(&mut self, bufs: &[&[u8]]) -> io::Result<usize> {
|
||||
let vec = bufs.concat();
|
||||
self.write(&vec)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Transport> Transport for SecureTransport<T> {
|
||||
fn take_socket_error(&mut self) -> io::Result<()> {
|
||||
self.0.get_mut().inner.take_socket_error()
|
||||
}
|
||||
|
||||
fn blocked(&self) -> Option<super::Blocked> {
|
||||
self.0.get_ref().blocked
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Records if this object was blocked on reading or writing.
|
||||
#[derive(Debug)]
|
||||
struct Journal<T> {
|
||||
inner: T,
|
||||
blocked: Option<Blocked>,
|
||||
}
|
||||
|
||||
fn journal<T: Read + Write>(inner: T) -> Journal<T> {
|
||||
Journal {
|
||||
inner: inner,
|
||||
blocked: None,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Read> Read for Journal<T> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.blocked = None;
|
||||
self.inner.read(buf).map_err(|e| match e.kind() {
|
||||
io::ErrorKind::WouldBlock => {
|
||||
self.blocked = Some(Blocked::Read);
|
||||
e
|
||||
},
|
||||
_ => e
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Write> Write for Journal<T> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user