-
Notifications
You must be signed in to change notification settings - Fork 145
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Heinz N. Gies <heinz@licenser.net> Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl> Co-authored-by: Daniel McCarney <daniel@binaryparadox.net>
- Loading branch information
1 parent
a0dd811
commit 286e1fa
Showing
7 changed files
with
319 additions
and
142 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
use core::task::{Context, Poll}; | ||
use std::future::Future; | ||
use std::io; | ||
use std::pin::Pin; | ||
use std::sync::Arc; | ||
|
||
use futures_util::ready; | ||
use hyper::server::{ | ||
accept::Accept, | ||
conn::{AddrIncoming, AddrStream}, | ||
}; | ||
use rustls::ServerConfig; | ||
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; | ||
|
||
mod builder; | ||
pub use builder::AcceptorBuilder; | ||
use builder::WantsTlsConfig; | ||
|
||
enum State { | ||
Handshaking(tokio_rustls::Accept<AddrStream>), | ||
Streaming(tokio_rustls::server::TlsStream<AddrStream>), | ||
} | ||
|
||
// tokio_rustls::server::TlsStream doesn't expose constructor methods, | ||
// so we have to TlsAcceptor::accept and handshake to have access to it | ||
// TlsStream implements AsyncRead/AsyncWrite by handshaking with tokio_rustls::Accept first | ||
pub struct TlsStream { | ||
state: State, | ||
} | ||
|
||
impl TlsStream { | ||
fn new(stream: AddrStream, config: Arc<ServerConfig>) -> TlsStream { | ||
let accept = tokio_rustls::TlsAcceptor::from(config).accept(stream); | ||
TlsStream { | ||
state: State::Handshaking(accept), | ||
} | ||
} | ||
} | ||
|
||
impl AsyncRead for TlsStream { | ||
fn poll_read( | ||
self: Pin<&mut Self>, | ||
cx: &mut Context, | ||
buf: &mut ReadBuf, | ||
) -> Poll<io::Result<()>> { | ||
let pin = self.get_mut(); | ||
match pin.state { | ||
State::Handshaking(ref mut accept) => match ready!(Pin::new(accept).poll(cx)) { | ||
Ok(mut stream) => { | ||
let result = Pin::new(&mut stream).poll_read(cx, buf); | ||
pin.state = State::Streaming(stream); | ||
result | ||
} | ||
Err(err) => Poll::Ready(Err(err)), | ||
}, | ||
State::Streaming(ref mut stream) => Pin::new(stream).poll_read(cx, buf), | ||
} | ||
} | ||
} | ||
|
||
impl AsyncWrite for TlsStream { | ||
fn poll_write( | ||
self: Pin<&mut Self>, | ||
cx: &mut Context<'_>, | ||
buf: &[u8], | ||
) -> Poll<io::Result<usize>> { | ||
let pin = self.get_mut(); | ||
match pin.state { | ||
State::Handshaking(ref mut accept) => match ready!(Pin::new(accept).poll(cx)) { | ||
Ok(mut stream) => { | ||
let result = Pin::new(&mut stream).poll_write(cx, buf); | ||
pin.state = State::Streaming(stream); | ||
result | ||
} | ||
Err(err) => Poll::Ready(Err(err)), | ||
}, | ||
State::Streaming(ref mut stream) => Pin::new(stream).poll_write(cx, buf), | ||
} | ||
} | ||
|
||
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { | ||
match self.state { | ||
State::Handshaking(_) => Poll::Ready(Ok(())), | ||
State::Streaming(ref mut stream) => Pin::new(stream).poll_flush(cx), | ||
} | ||
} | ||
|
||
fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { | ||
match self.state { | ||
State::Handshaking(_) => Poll::Ready(Ok(())), | ||
State::Streaming(ref mut stream) => Pin::new(stream).poll_shutdown(cx), | ||
} | ||
} | ||
} | ||
|
||
/// A TLS acceptor that can be used with hyper servers. | ||
pub struct TlsAcceptor { | ||
config: Arc<ServerConfig>, | ||
incoming: AddrIncoming, | ||
} | ||
|
||
/// An Acceptor for the `https` scheme. | ||
impl TlsAcceptor { | ||
/// Provides a builder for a `TlsAcceptor`. | ||
pub fn builder() -> AcceptorBuilder<WantsTlsConfig> { | ||
AcceptorBuilder::new() | ||
} | ||
/// Creates a new `TlsAcceptor` from a `ServerConfig` and an `AddrIncoming`. | ||
pub fn new(config: Arc<ServerConfig>, incoming: AddrIncoming) -> TlsAcceptor { | ||
TlsAcceptor { config, incoming } | ||
} | ||
} | ||
|
||
impl<C, I> From<(C, I)> for TlsAcceptor | ||
where | ||
C: Into<Arc<ServerConfig>>, | ||
I: Into<AddrIncoming>, | ||
{ | ||
fn from((config, incoming): (C, I)) -> TlsAcceptor { | ||
TlsAcceptor::new(config.into(), incoming.into()) | ||
} | ||
} | ||
|
||
impl Accept for TlsAcceptor { | ||
type Conn = TlsStream; | ||
type Error = io::Error; | ||
|
||
fn poll_accept( | ||
self: Pin<&mut Self>, | ||
cx: &mut Context<'_>, | ||
) -> Poll<Option<Result<Self::Conn, Self::Error>>> { | ||
let pin = self.get_mut(); | ||
match ready!(Pin::new(&mut pin.incoming).poll_accept(cx)) { | ||
Some(Ok(sock)) => Poll::Ready(Some(Ok(TlsStream::new(sock, pin.config.clone())))), | ||
Some(Err(e)) => Poll::Ready(Some(Err(e))), | ||
None => Poll::Ready(None), | ||
} | ||
} | ||
} |
Oops, something went wrong.