mirror of
https://github.com/ntex-rs/ntex.git
synced 2025-04-03 21:07:39 +03:00
impl rustls acceptor; update filter trait
This commit is contained in:
parent
d7083c15d8
commit
1af728eb01
30 changed files with 1184 additions and 306 deletions
9
ntex-io/CHANGES.md
Normal file
9
ntex-io/CHANGES.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Changes
|
||||
|
||||
## [0.1.0-b.1] - 2021-12-18
|
||||
|
||||
* Modify filter's release_read/write_buf return type
|
||||
|
||||
## [0.1.0-b.0] - 2021-12-18
|
||||
|
||||
* Refactor ntex::framed to ntex-io
|
|
@ -339,7 +339,6 @@ where
|
|||
|
||||
if slf.shared.inflight.get() == 0 {
|
||||
slf.st.set(DispatcherState::Shutdown);
|
||||
state.init_shutdown(cx);
|
||||
} else {
|
||||
state.register_dispatcher(cx);
|
||||
return Poll::Pending;
|
||||
|
|
|
@ -69,7 +69,7 @@ impl ReadFilter for DefaultFilter {
|
|||
&self,
|
||||
buf: BytesMut,
|
||||
new_bytes: usize,
|
||||
) -> Result<(), io::Error> {
|
||||
) -> Result<bool, io::Error> {
|
||||
let mut flags = self.0.flags.get();
|
||||
|
||||
if new_bytes > 0 {
|
||||
|
@ -86,7 +86,7 @@ impl ReadFilter for DefaultFilter {
|
|||
}
|
||||
|
||||
self.0.read_buf.set(Some(buf));
|
||||
Ok(())
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ impl WriteFilter for DefaultFilter {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn release_write_buf(&self, buf: BytesMut) -> Result<(), io::Error> {
|
||||
fn release_write_buf(&self, buf: BytesMut) -> Result<bool, io::Error> {
|
||||
let pool = self.0.pool.get();
|
||||
if buf.is_empty() {
|
||||
pool.release_write_buf(buf);
|
||||
|
@ -141,7 +141,7 @@ impl WriteFilter for DefaultFilter {
|
|||
self.0.write_buf.set(Some(buf));
|
||||
self.0.write_task.wake();
|
||||
}
|
||||
Ok(())
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,8 +176,8 @@ impl ReadFilter for NullFilter {
|
|||
None
|
||||
}
|
||||
|
||||
fn release_read_buf(&self, _: BytesMut, _: usize) -> Result<(), io::Error> {
|
||||
Ok(())
|
||||
fn release_read_buf(&self, _: BytesMut, _: usize) -> Result<bool, io::Error> {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,7 +192,7 @@ impl WriteFilter for NullFilter {
|
|||
None
|
||||
}
|
||||
|
||||
fn release_write_buf(&self, _: BytesMut) -> Result<(), io::Error> {
|
||||
Ok(())
|
||||
fn release_write_buf(&self, _: BytesMut) -> Result<bool, io::Error> {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,8 +43,7 @@ pub trait ReadFilter {
|
|||
|
||||
fn get_read_buf(&self) -> Option<BytesMut>;
|
||||
|
||||
fn release_read_buf(&self, buf: BytesMut, new_bytes: usize)
|
||||
-> Result<(), io::Error>;
|
||||
fn release_read_buf(&self, buf: BytesMut, nbytes: usize) -> Result<bool, io::Error>;
|
||||
}
|
||||
|
||||
pub trait WriteFilter {
|
||||
|
@ -55,7 +54,7 @@ pub trait WriteFilter {
|
|||
|
||||
fn get_write_buf(&self) -> Option<BytesMut>;
|
||||
|
||||
fn release_write_buf(&self, buf: BytesMut) -> Result<(), io::Error>;
|
||||
fn release_write_buf(&self, buf: BytesMut) -> Result<bool, io::Error>;
|
||||
}
|
||||
|
||||
pub trait Filter: ReadFilter + WriteFilter + 'static {
|
||||
|
|
|
@ -124,6 +124,28 @@ impl IoStateInner {
|
|||
self.notify_disconnect();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Gracefully shutdown read and write io tasks
|
||||
pub(super) fn init_shutdown(&self, cx: Option<&mut Context<'_>>, st: &IoRef) {
|
||||
let mut flags = self.flags.get();
|
||||
|
||||
if !flags.intersects(Flags::IO_ERR | Flags::IO_SHUTDOWN | Flags::IO_FILTERS) {
|
||||
log::trace!("initiate io shutdown {:?}", flags);
|
||||
flags.insert(Flags::IO_FILTERS);
|
||||
if let Err(err) = self.shutdown_filters(st) {
|
||||
self.error.set(Some(err));
|
||||
flags.insert(Flags::IO_ERR);
|
||||
}
|
||||
|
||||
self.flags.set(flags);
|
||||
self.read_task.wake();
|
||||
self.write_task.wake();
|
||||
if let Some(cx) = cx {
|
||||
self.dispatch_task.register(cx.waker());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn shutdown_filters(&self, st: &IoRef) -> Result<(), io::Error> {
|
||||
let mut flags = self.flags.get();
|
||||
|
@ -328,13 +350,13 @@ impl IoRef {
|
|||
#[inline]
|
||||
/// Get api for read task
|
||||
pub fn read(&'_ self) -> ReadRef<'_> {
|
||||
ReadRef(self.0.as_ref())
|
||||
ReadRef(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Get api for write task
|
||||
pub fn write(&'_ self) -> WriteRef<'_> {
|
||||
WriteRef(self.0.as_ref())
|
||||
WriteRef(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -425,7 +447,7 @@ impl IoRef {
|
|||
Poll::Ready(Ok(()))
|
||||
} else {
|
||||
if !flags.contains(Flags::IO_FILTERS) {
|
||||
self.init_shutdown(cx);
|
||||
self.0.init_shutdown(Some(cx), self);
|
||||
}
|
||||
|
||||
if let Some(err) = self.0.error.take() {
|
||||
|
@ -465,25 +487,6 @@ impl IoRef {
|
|||
Err(err) => Poll::Ready(Err(Either::Left(err))),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Gracefully shutdown read and write io tasks
|
||||
pub(super) fn init_shutdown(&self, cx: &mut Context<'_>) {
|
||||
let flags = self.0.flags.get();
|
||||
|
||||
if !flags.intersects(Flags::IO_ERR | Flags::IO_SHUTDOWN | Flags::IO_FILTERS) {
|
||||
log::trace!("initiate io shutdown {:?}", flags);
|
||||
self.0.insert_flags(Flags::IO_FILTERS);
|
||||
if let Err(err) = self.0.shutdown_filters(self) {
|
||||
self.0.error.set(Some(err));
|
||||
self.0.insert_flags(Flags::IO_ERR);
|
||||
}
|
||||
|
||||
self.0.read_task.wake();
|
||||
self.0.write_task.wake();
|
||||
self.0.dispatch_task.register(cx.waker());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for IoRef {
|
||||
|
@ -539,10 +542,10 @@ impl<F: Filter> Io<F> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn map_filter<T, U>(mut self, map: U) -> Result<Io<T::Filter>, T::Error>
|
||||
pub fn map_filter<T, U, E>(mut self, map: U) -> Result<Io<T>, E>
|
||||
where
|
||||
T: FilterFactory<F>,
|
||||
U: FnOnce(F) -> Result<T::Filter, T::Error>,
|
||||
T: Filter,
|
||||
U: FnOnce(F) -> Result<T, E>,
|
||||
{
|
||||
// replace current filter
|
||||
let filter = unsafe {
|
||||
|
@ -610,22 +613,22 @@ impl<F> Deref for Io<F> {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct WriteRef<'a>(pub(super) &'a IoStateInner);
|
||||
pub struct WriteRef<'a>(pub(super) &'a IoRef);
|
||||
|
||||
impl<'a> WriteRef<'a> {
|
||||
#[inline]
|
||||
/// Check if write task is ready
|
||||
pub fn is_ready(&self) -> bool {
|
||||
!self.0.flags.get().contains(Flags::WR_BACKPRESSURE)
|
||||
!self.0 .0.flags.get().contains(Flags::WR_BACKPRESSURE)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Check if write buffer is full
|
||||
pub fn is_full(&self) -> bool {
|
||||
if let Some(buf) = self.0.read_buf.take() {
|
||||
let hw = self.0.pool.get().write_params_high();
|
||||
if let Some(buf) = self.0 .0.read_buf.take() {
|
||||
let hw = self.0 .0.pool.get().write_params_high();
|
||||
let result = buf.len() >= hw;
|
||||
self.0.write_buf.set(Some(buf));
|
||||
self.0 .0.write_buf.set(Some(buf));
|
||||
result
|
||||
} else {
|
||||
false
|
||||
|
@ -635,7 +638,7 @@ impl<'a> WriteRef<'a> {
|
|||
#[inline]
|
||||
/// Wake dispatcher task
|
||||
pub fn wake_dispatcher(&self) {
|
||||
self.0.dispatch_task.wake();
|
||||
self.0 .0.dispatch_task.wake();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -644,9 +647,9 @@ impl<'a> WriteRef<'a> {
|
|||
/// Write task must be waken up separately.
|
||||
pub fn enable_backpressure(&self, cx: Option<&mut Context<'_>>) {
|
||||
log::trace!("enable write back-pressure {:?}", cx.is_some());
|
||||
self.0.insert_flags(Flags::WR_BACKPRESSURE);
|
||||
self.0 .0.insert_flags(Flags::WR_BACKPRESSURE);
|
||||
if let Some(cx) = cx {
|
||||
self.0.dispatch_task.register(cx.waker());
|
||||
self.0 .0.dispatch_task.register(cx.waker());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -656,16 +659,19 @@ impl<'a> WriteRef<'a> {
|
|||
where
|
||||
F: FnOnce(&mut BytesMut) -> R,
|
||||
{
|
||||
let filter = self.0.filter.get();
|
||||
let filter = self.0 .0.filter.get();
|
||||
let mut buf = filter
|
||||
.get_write_buf()
|
||||
.unwrap_or_else(|| self.0.pool.get().get_write_buf());
|
||||
.unwrap_or_else(|| self.0 .0.pool.get().get_write_buf());
|
||||
if buf.is_empty() {
|
||||
self.0.write_task.wake();
|
||||
self.0 .0.write_task.wake();
|
||||
}
|
||||
|
||||
let result = f(&mut buf);
|
||||
filter.release_write_buf(buf)?;
|
||||
let close = filter.release_write_buf(buf)?;
|
||||
if close {
|
||||
self.0 .0.init_shutdown(None, self.0);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
|
@ -681,15 +687,15 @@ impl<'a> WriteRef<'a> {
|
|||
where
|
||||
U: Encoder,
|
||||
{
|
||||
let flags = self.0.flags.get();
|
||||
let flags = self.0 .0.flags.get();
|
||||
|
||||
if !flags.intersects(Flags::IO_ERR | Flags::IO_SHUTDOWN) {
|
||||
let filter = self.0.filter.get();
|
||||
let filter = self.0 .0.filter.get();
|
||||
let mut buf = filter
|
||||
.get_write_buf()
|
||||
.unwrap_or_else(|| self.0.pool.get().get_write_buf());
|
||||
.unwrap_or_else(|| self.0 .0.pool.get().get_write_buf());
|
||||
let is_write_sleep = buf.is_empty();
|
||||
let (hw, lw) = self.0.pool.get().write_params().unpack();
|
||||
let (hw, lw) = self.0 .0.pool.get().write_params().unpack();
|
||||
|
||||
// make sure we've got room
|
||||
let remaining = buf.capacity() - buf.len();
|
||||
|
@ -700,12 +706,19 @@ impl<'a> WriteRef<'a> {
|
|||
// encode item and wake write task
|
||||
let result = codec.encode(item, &mut buf).map(|_| {
|
||||
if is_write_sleep {
|
||||
self.0.write_task.wake();
|
||||
self.0 .0.write_task.wake();
|
||||
}
|
||||
buf.len() < hw
|
||||
});
|
||||
if let Err(err) = filter.release_write_buf(buf) {
|
||||
self.0.set_error(Some(err));
|
||||
match filter.release_write_buf(buf) {
|
||||
Err(err) => {
|
||||
self.0 .0.set_error(Some(err));
|
||||
}
|
||||
Ok(close) => {
|
||||
if close {
|
||||
self.0 .0.init_shutdown(None, self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
} else {
|
||||
|
@ -718,24 +731,24 @@ impl<'a> WriteRef<'a> {
|
|||
///
|
||||
/// Returns write buffer state, false is returned if write buffer if full.
|
||||
pub fn write(&self, src: &[u8]) -> Result<bool, io::Error> {
|
||||
let flags = self.0.flags.get();
|
||||
let flags = self.0 .0.flags.get();
|
||||
|
||||
if !flags.intersects(Flags::IO_ERR | Flags::IO_SHUTDOWN) {
|
||||
let filter = self.0.filter.get();
|
||||
let filter = self.0 .0.filter.get();
|
||||
let mut buf = filter
|
||||
.get_write_buf()
|
||||
.unwrap_or_else(|| self.0.pool.get().get_write_buf());
|
||||
.unwrap_or_else(|| self.0 .0.pool.get().get_write_buf());
|
||||
let is_write_sleep = buf.is_empty();
|
||||
|
||||
// write and wake write task
|
||||
buf.extend_from_slice(src);
|
||||
let result = buf.len() < self.0.pool.get().write_params_high();
|
||||
let result = buf.len() < self.0 .0.pool.get().write_params_high();
|
||||
if is_write_sleep {
|
||||
self.0.write_task.wake();
|
||||
self.0 .0.write_task.wake();
|
||||
}
|
||||
|
||||
if let Err(err) = filter.release_write_buf(buf) {
|
||||
self.0.set_error(Some(err));
|
||||
self.0 .0.set_error(Some(err));
|
||||
}
|
||||
Ok(result)
|
||||
} else {
|
||||
|
@ -755,27 +768,27 @@ impl<'a> WriteRef<'a> {
|
|||
full: bool,
|
||||
) -> Poll<Result<(), io::Error>> {
|
||||
// check io error
|
||||
if !self.0.is_io_open() {
|
||||
return Poll::Ready(Err(self.0.error.take().unwrap_or_else(|| {
|
||||
if !self.0 .0.is_io_open() {
|
||||
return Poll::Ready(Err(self.0 .0.error.take().unwrap_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::Other, "disconnected")
|
||||
})));
|
||||
}
|
||||
|
||||
if let Some(buf) = self.0.write_buf.take() {
|
||||
if let Some(buf) = self.0 .0.write_buf.take() {
|
||||
let len = buf.len();
|
||||
if len != 0 {
|
||||
self.0.write_buf.set(Some(buf));
|
||||
self.0 .0.write_buf.set(Some(buf));
|
||||
|
||||
if full {
|
||||
self.0.insert_flags(Flags::WR_WAIT);
|
||||
self.0.dispatch_task.register(cx.waker());
|
||||
self.0 .0.insert_flags(Flags::WR_WAIT);
|
||||
self.0 .0.dispatch_task.register(cx.waker());
|
||||
return Poll::Pending;
|
||||
} else if len >= self.0.pool.get().write_params_high() << 1 {
|
||||
self.0.insert_flags(Flags::WR_BACKPRESSURE);
|
||||
self.0.dispatch_task.register(cx.waker());
|
||||
} else if len >= self.0 .0.pool.get().write_params_high() << 1 {
|
||||
self.0 .0.insert_flags(Flags::WR_BACKPRESSURE);
|
||||
self.0 .0.dispatch_task.register(cx.waker());
|
||||
return Poll::Pending;
|
||||
} else {
|
||||
self.0.remove_flags(Flags::WR_BACKPRESSURE);
|
||||
self.0 .0.remove_flags(Flags::WR_BACKPRESSURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -793,21 +806,30 @@ impl<'a> WriteRef<'a> {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ReadRef<'a>(&'a IoStateInner);
|
||||
pub struct ReadRef<'a>(&'a IoRef);
|
||||
|
||||
impl<'a> ReadRef<'a> {
|
||||
#[inline]
|
||||
/// Check if read buffer has new data
|
||||
pub fn is_ready(&self) -> bool {
|
||||
self.0.flags.get().contains(Flags::RD_READY)
|
||||
self.0 .0.flags.get().contains(Flags::RD_READY)
|
||||
}
|
||||
|
||||
/// Reset readiness state, returns previous state
|
||||
pub fn take_readiness(&self) -> bool {
|
||||
let mut flags = self.0 .0.flags.get();
|
||||
let ready = flags.contains(Flags::RD_READY);
|
||||
flags.remove(Flags::RD_READY);
|
||||
self.0 .0.flags.set(flags);
|
||||
ready
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Check if read buffer is full
|
||||
pub fn is_full(&self) -> bool {
|
||||
if let Some(buf) = self.0.read_buf.take() {
|
||||
let result = buf.len() >= self.0.pool.get().read_params_high();
|
||||
self.0.read_buf.set(Some(buf));
|
||||
if let Some(buf) = self.0 .0.read_buf.take() {
|
||||
let result = buf.len() >= self.0 .0.pool.get().read_params_high();
|
||||
self.0 .0.read_buf.set(Some(buf));
|
||||
result
|
||||
} else {
|
||||
false
|
||||
|
@ -817,17 +839,17 @@ impl<'a> ReadRef<'a> {
|
|||
#[inline]
|
||||
/// Pause read task
|
||||
pub fn pause(&self, cx: &mut Context<'_>) {
|
||||
self.0.insert_flags(Flags::RD_PAUSED);
|
||||
self.0.dispatch_task.register(cx.waker());
|
||||
self.0 .0.insert_flags(Flags::RD_PAUSED);
|
||||
self.0 .0.dispatch_task.register(cx.waker());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Wake read io task if it is paused
|
||||
pub fn resume(&self) -> bool {
|
||||
let flags = self.0.flags.get();
|
||||
let flags = self.0 .0.flags.get();
|
||||
if flags.contains(Flags::RD_PAUSED) {
|
||||
self.0.remove_flags(Flags::RD_PAUSED);
|
||||
self.0.read_task.wake();
|
||||
self.0 .0.remove_flags(Flags::RD_PAUSED);
|
||||
self.0 .0.read_task.wake();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
@ -846,9 +868,9 @@ impl<'a> ReadRef<'a> {
|
|||
where
|
||||
U: Decoder,
|
||||
{
|
||||
if let Some(mut buf) = self.0.read_buf.take() {
|
||||
if let Some(mut buf) = self.0 .0.read_buf.take() {
|
||||
let result = codec.decode(&mut buf);
|
||||
self.0.read_buf.set(Some(buf));
|
||||
self.0 .0.read_buf.set(Some(buf));
|
||||
return result;
|
||||
}
|
||||
Ok(None)
|
||||
|
@ -862,14 +884,15 @@ impl<'a> ReadRef<'a> {
|
|||
{
|
||||
let mut buf = self
|
||||
.0
|
||||
.0
|
||||
.read_buf
|
||||
.take()
|
||||
.unwrap_or_else(|| self.0.pool.get().get_read_buf());
|
||||
.unwrap_or_else(|| self.0 .0.pool.get().get_read_buf());
|
||||
let res = f(&mut buf);
|
||||
if buf.is_empty() {
|
||||
self.0.pool.get().release_read_buf(buf);
|
||||
self.0 .0.pool.get().release_read_buf(buf);
|
||||
} else {
|
||||
self.0.read_buf.set(Some(buf));
|
||||
self.0 .0.read_buf.set(Some(buf));
|
||||
}
|
||||
res
|
||||
}
|
||||
|
@ -883,23 +906,23 @@ impl<'a> ReadRef<'a> {
|
|||
&self,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Result<(), Option<io::Error>> {
|
||||
let mut flags = self.0.flags.get();
|
||||
let mut flags = self.0 .0.flags.get();
|
||||
|
||||
if !self.0.is_io_open() {
|
||||
Err(self.0.error.take())
|
||||
if !self.0 .0.is_io_open() {
|
||||
Err(self.0 .0.error.take())
|
||||
} else {
|
||||
if flags.contains(Flags::RD_BUF_FULL) {
|
||||
log::trace!("read back-pressure is disabled, wake io task");
|
||||
flags.remove(Flags::RD_READY | Flags::RD_BUF_FULL);
|
||||
self.0.flags.set(flags);
|
||||
self.0.read_task.wake();
|
||||
self.0 .0.flags.set(flags);
|
||||
self.0 .0.read_task.wake();
|
||||
} else if flags.contains(Flags::RD_READY) {
|
||||
log::trace!("waking up io read task");
|
||||
flags.remove(Flags::RD_READY);
|
||||
self.0.flags.set(flags);
|
||||
self.0.read_task.wake();
|
||||
self.0 .0.flags.set(flags);
|
||||
self.0 .0.read_task.wake();
|
||||
}
|
||||
self.0.dispatch_task.register(cx.waker());
|
||||
self.0 .0.dispatch_task.register(cx.waker());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,10 +49,12 @@ impl ReadContext {
|
|||
self.0 .0.dispatch_task.wake();
|
||||
}
|
||||
|
||||
self.0 .0.filter.get().release_read_buf(buf, new_bytes)?;
|
||||
let close = self.0 .0.filter.get().release_read_buf(buf, new_bytes)?;
|
||||
|
||||
if flags.contains(Flags::IO_FILTERS) {
|
||||
self.0 .0.shutdown_filters(&self.0)?;
|
||||
} else if close {
|
||||
self.0 .0.init_shutdown(None, &self.0);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -170,6 +170,7 @@ impl Future for WriteTask {
|
|||
}
|
||||
}
|
||||
Poll::Ready(Err(WriteReadiness::Timeout(time))) => {
|
||||
log::trace!("initiate timeout delay for {:?}", time);
|
||||
if delay.is_none() {
|
||||
*delay = Some(sleep(time));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ntex-tls"
|
||||
version = "0.1.0"
|
||||
version = "0.1.0-b.0"
|
||||
authors = ["ntex contributors <team@ntex.rs>"]
|
||||
description = "An implementation of SSL streams for ntex backed by OpenSSL"
|
||||
keywords = ["network", "framework", "async", "futures"]
|
||||
|
@ -22,7 +22,7 @@ default = []
|
|||
openssl = ["tls_openssl"]
|
||||
|
||||
# rustls support
|
||||
rustls = ["tls_rust", "webpki-roots"]
|
||||
rustls = ["tls_rust"]
|
||||
|
||||
[dependencies]
|
||||
ntex-bytes = "0.1.8"
|
||||
|
@ -36,9 +36,9 @@ tls_openssl = { version="0.10", package = "openssl", optional = true }
|
|||
|
||||
# rustls
|
||||
tls_rust = { version = "0.20", package = "rustls", optional = true }
|
||||
webpki-roots = { version = "0.22", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
ntex = { version = "0.5.0-b.0", features = ["openssl", "rustls"] }
|
||||
log = "0.4"
|
||||
env_logger = "0.9"
|
||||
rustls-pemfile = { version = "0.2" }
|
||||
|
|
|
@ -1,16 +1,31 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
Ing=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
|
@ -1,28 +1,51 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDQYw/djMNUVaA2
|
||||
FGIed953X3bXfVmLbenxaK62d4P0jlY7jZzv185ezEtaf7YdKo+8I8cgEugxfyj2
|
||||
WALG3Y/8lQIBZusTYS6+GQytaTr+rvEHbXVdlh+eSp23uYDSMxQLmjfYBfd7Djnp
|
||||
MCrk/xh2r0f+pd1G0C8oPRB2QV+rx48KKo6Fyppxn81a9rtHgd2BOdsvUNFCMYFe
|
||||
zMjTs/3XLDwY7Kbjq7E0dG6NCneVgSFzVXclMX2QROlIEfIQCRDxYfEZ/xQEcOGH
|
||||
uFxz4ogkcyVVjLnAO/hkl5ixjWsPr+fi3J3evTLMEzntQZ/qqtVkRiYsHslp37wN
|
||||
/m8igaFbAgMBAAECggEAJI278rkGany6pcHdlEqik34DcrliQ7r8FoSuYQOF+hgd
|
||||
uESXCttoL+jWLwHICEW3AOGlxFKMuGH95Xh6xDeJUl0xBN3wzm11rZLnTmPvHU3C
|
||||
qfLha5Ex6qpcECZSGo0rLv3WXeZuCv/r2KPCYnj86ZTFpD2kGw/Ztc1AXf4Jsi/1
|
||||
478Mf23QmAvCAPimGCyjLQx2c9/vg/6K7WnDevY4tDuDKLeSJxKZBSHUn3cM1Bwj
|
||||
2QzaHfSFA5XljOF5PLeR3cY5ncrrVLWChT9XuGt9YMdLAcSQxgE6kWV1RSCq+lbj
|
||||
e6OOe879IrrqwBvMQfKQqnm1kl8OrfPMT5CNWKvEgQKBgQD8q5E4x9taDS9RmhRO
|
||||
07ptsr/I795tX8CaJd/jc4xGuCGBqpNw/hVebyNNYQvpiYzDNBSEhtd59957VyET
|
||||
hcrGyxD0ByKm8F/lPgFw5y6wi3RUnucCV/jxkMHmxVzYMbFUEGCQ0pIU9/GFS7RZ
|
||||
9VjqRDeE86U3yHO+WCFoHtd8aQKBgQDTIhi0uq0oY87bUGnWbrrkR0UVRNPDG1BT
|
||||
cuXACYlv/DV/XpxPC8iPK1UwG4XaOVxodtIRjdBqvb8fUM6HSY6qll64N/4/1jre
|
||||
Ho+d4clE4tK6a9WU96CKxwHn2BrWUZJPtoldaCZJFJ7SfiHuLlqW7TtYFrOfPIjN
|
||||
ADiqK+bHIwKBgQCpfIiAVwebo0Z/bWR77+iZFxMwvT4tjdJLVGaXUvXgpjjLmtkm
|
||||
LTm2S8SZbiSodfz3H+M3dp/pj8wsXiiwyMlZifOITZT/+DPLOUmMK3cVM6ZH8QMy
|
||||
fkJd/+UhYHhECSlTI10zKByXdi4LZNnIkhwfoLzBMRI9lfeV0dYu2qlfKQKBgEVI
|
||||
kRbtk1kHt5/ceX62g3nZsV/TYDJMSkW4FJC6EHHBL8UGRQDjewMQUzogLgJ4hEx7
|
||||
gV/lS5lbftZF7CAVEU4FXjvRlAtav6KYIMTMjQGf9UrbjBEAWZxwxb1Q+y2NQxgJ
|
||||
bHZMcRPWQnAMmBHTAEM6whicCoGcmb+77Nxa37ZFAoGBALBuUNeD3fKvQR8v6GoA
|
||||
spv+RYL9TB4wz2Oe9EYSp9z5EiWlTmuvFz3zk8pHDSpntxYH5O5HJ/3OzwhHz9ym
|
||||
+DNE9AP9LW9hAzMuu7Gob1h8ShGwJVYwrQN3q/83ooUL7WSAuVOLpzJ7BFFlcCjp
|
||||
MhFvd9iOt/R0N30/3AbQXkOp
|
||||
-----END PRIVATE KEY-----
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
|
72
ntex-tls/examples/rustls-server.rs
Normal file
72
ntex-tls/examples/rustls-server.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
use std::{fs::File, io, io::BufReader, sync::Arc};
|
||||
|
||||
use ntex::service::{fn_service, pipeline_factory};
|
||||
use ntex::{codec, io::filter_factory, io::Io, server, util::Either};
|
||||
use ntex_tls::rustls::TlsAcceptor;
|
||||
use rustls_pemfile::{certs, rsa_private_keys};
|
||||
use tls_rust::{Certificate, PrivateKey, ServerConfig};
|
||||
// use tls_openssl::ssl::{self, SslFiletype, SslMethod};
|
||||
|
||||
#[ntex::main]
|
||||
async fn main() -> io::Result<()> {
|
||||
std::env::set_var("RUST_LOG", "trace");
|
||||
env_logger::init();
|
||||
|
||||
println!("Started openssl echp server: 127.0.0.1:8443");
|
||||
|
||||
// load ssl keys
|
||||
let cert_file =
|
||||
&mut BufReader::new(File::open("../ntex-tls/examples/cert.pem").unwrap());
|
||||
let key_file =
|
||||
&mut BufReader::new(File::open("../ntex-tls/examples/key.pem").unwrap());
|
||||
let keys = PrivateKey(rsa_private_keys(key_file).unwrap().remove(0));
|
||||
let cert_chain = certs(cert_file)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|c| Certificate(c.to_vec()))
|
||||
.collect();
|
||||
let tls_config = Arc::new(
|
||||
ServerConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_no_client_auth()
|
||||
.with_single_cert(cert_chain, keys)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
// start server
|
||||
server::ServerBuilder::new()
|
||||
.bind("basic", "127.0.0.1:8443", move || {
|
||||
pipeline_factory(filter_factory(TlsAcceptor::new(tls_config.clone())))
|
||||
.and_then(fn_service(|io: Io<_>| async move {
|
||||
println!("New client is connected");
|
||||
|
||||
io.send(
|
||||
ntex_bytes::Bytes::from_static(b"Welcome!\n"),
|
||||
&codec::BytesCodec,
|
||||
)
|
||||
.await
|
||||
.map_err(Either::into_inner)?;
|
||||
|
||||
loop {
|
||||
match io.next(&codec::BytesCodec).await {
|
||||
Ok(Some(msg)) => {
|
||||
println!("Got message: {:?}", msg);
|
||||
io.send(msg.freeze(), &codec::BytesCodec)
|
||||
.await
|
||||
.map_err(Either::into_inner)?;
|
||||
}
|
||||
Ok(None) => break,
|
||||
Err(e) => {
|
||||
println!("Got error: {:?}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("Client is disconnected");
|
||||
Ok(())
|
||||
}))
|
||||
})?
|
||||
.workers(1)
|
||||
.run()
|
||||
.await
|
||||
}
|
|
@ -49,7 +49,7 @@ impl<F: Filter> io::Read for IoInner<F> {
|
|||
impl<F: Filter> io::Write for IoInner<F> {
|
||||
fn write(&mut self, src: &[u8]) -> io::Result<usize> {
|
||||
let mut buf = if let Some(mut buf) = self.inner.get_write_buf() {
|
||||
buf.reserve(buf.len());
|
||||
buf.reserve(src.len());
|
||||
buf
|
||||
} else {
|
||||
BytesMut::with_capacity_in(src.len(), self.pool)
|
||||
|
@ -127,7 +127,7 @@ impl<F: Filter> ReadFilter for SslFilter<F> {
|
|||
&self,
|
||||
src: BytesMut,
|
||||
new_bytes: usize,
|
||||
) -> Result<(), io::Error> {
|
||||
) -> Result<bool, io::Error> {
|
||||
// store to read_buf
|
||||
let pool = {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
|
@ -135,7 +135,7 @@ impl<F: Filter> ReadFilter for SslFilter<F> {
|
|||
inner.get_ref().pool
|
||||
};
|
||||
if new_bytes == 0 {
|
||||
return Ok(());
|
||||
return Ok(false);
|
||||
}
|
||||
let (hw, lw) = pool.read_params().unpack();
|
||||
|
||||
|
@ -171,8 +171,7 @@ impl<F: Filter> ReadFilter for SslFilter<F> {
|
|||
.borrow()
|
||||
.get_ref()
|
||||
.inner
|
||||
.release_read_buf(buf, new_bytes)?;
|
||||
Ok(())
|
||||
.release_read_buf(buf, new_bytes)
|
||||
}
|
||||
Err(e) => Err(map_to_ioerr(e)),
|
||||
};
|
||||
|
@ -201,7 +200,7 @@ impl<F: Filter> WriteFilter for SslFilter<F> {
|
|||
None
|
||||
}
|
||||
|
||||
fn release_write_buf(&self, mut buf: BytesMut) -> Result<(), io::Error> {
|
||||
fn release_write_buf(&self, mut buf: BytesMut) -> Result<bool, io::Error> {
|
||||
let ssl_result = self.inner.borrow_mut().ssl_write(&buf);
|
||||
let result = match ssl_result {
|
||||
Ok(v) => {
|
||||
|
@ -209,11 +208,11 @@ impl<F: Filter> WriteFilter for SslFilter<F> {
|
|||
buf.split_to(v);
|
||||
self.inner.borrow_mut().get_mut().write_buf = Some(buf);
|
||||
}
|
||||
Ok(())
|
||||
Ok(false)
|
||||
}
|
||||
Err(e) => match e.code() {
|
||||
ssl::ErrorCode::WANT_READ | ssl::ErrorCode::WANT_WRITE => Ok(()),
|
||||
_ => (Err(map_to_ioerr(e))),
|
||||
ssl::ErrorCode::WANT_READ | ssl::ErrorCode::WANT_WRITE => Ok(false),
|
||||
_ => Err(map_to_ioerr(e)),
|
||||
},
|
||||
};
|
||||
result
|
||||
|
@ -266,7 +265,7 @@ impl<F: Filter + 'static> FilterFactory<F> for SslAcceptor {
|
|||
time::timeout(timeout, async {
|
||||
let ssl = ctx_result.map_err(map_to_ioerr)?;
|
||||
let pool = st.memory_pool();
|
||||
let st = st.map_filter::<Self, _>(|inner: F| {
|
||||
let st = st.map_filter(|inner: F| {
|
||||
let inner = IoInner {
|
||||
pool,
|
||||
inner,
|
||||
|
@ -275,7 +274,7 @@ impl<F: Filter + 'static> FilterFactory<F> for SslAcceptor {
|
|||
};
|
||||
let ssl_stream = ssl::SslStream::new(ssl, inner)?;
|
||||
|
||||
Ok(SslFilter {
|
||||
Ok::<_, Box<dyn Error>>(SslFilter {
|
||||
inner: RefCell::new(ssl_stream),
|
||||
})
|
||||
})?;
|
||||
|
@ -317,7 +316,7 @@ impl<F: Filter + 'static> FilterFactory<F> for SslConnector {
|
|||
Box::pin(async move {
|
||||
let ssl = self.ssl;
|
||||
let pool = st.memory_pool();
|
||||
let st = st.map_filter::<Self, _>(|inner: F| {
|
||||
let st = st.map_filter(|inner: F| {
|
||||
let inner = IoInner {
|
||||
pool,
|
||||
inner,
|
||||
|
@ -326,7 +325,7 @@ impl<F: Filter + 'static> FilterFactory<F> for SslConnector {
|
|||
};
|
||||
let ssl_stream = ssl::SslStream::new(ssl, inner)?;
|
||||
|
||||
Ok(SslFilter {
|
||||
Ok::<_, Box<dyn Error>>(SslFilter {
|
||||
inner: RefCell::new(ssl_stream),
|
||||
})
|
||||
})?;
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use std::task::{Context, Poll};
|
||||
use std::{error::Error, future::Future, marker::PhantomData, pin::Pin};
|
||||
use std::{future::Future, io, marker::PhantomData, pin::Pin, sync::Arc};
|
||||
|
||||
use tls_rust::ServerConfig;
|
||||
use webpki_roots::TLS_SERVER_ROOTS;
|
||||
|
||||
use ntex_io::{Filter, FilterFactory, Io};
|
||||
use ntex_service::{Service, ServiceFactory};
|
||||
|
@ -21,7 +20,7 @@ pub struct Acceptor<F> {
|
|||
|
||||
impl<F> Acceptor<F> {
|
||||
/// Create rustls based `Acceptor` service factory
|
||||
pub fn new(config: ServerConfig) -> Self {
|
||||
pub fn new(config: Arc<ServerConfig>) -> Self {
|
||||
Acceptor {
|
||||
inner: TlsAcceptor::new(config),
|
||||
_t: PhantomData,
|
||||
|
@ -37,6 +36,12 @@ impl<F> Acceptor<F> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<F> From<ServerConfig> for Acceptor<F> {
|
||||
fn from(cfg: ServerConfig) -> Self {
|
||||
Self::new(Arc::new(cfg))
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Clone for Acceptor<F> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
|
@ -49,7 +54,7 @@ impl<F> Clone for Acceptor<F> {
|
|||
impl<F: Filter> ServiceFactory for Acceptor<F> {
|
||||
type Request = Io<F>;
|
||||
type Response = Io<TlsFilter<F>>;
|
||||
type Error = Box<dyn Error>;
|
||||
type Error = io::Error;
|
||||
type Service = AcceptorService<F>;
|
||||
|
||||
type Config = ();
|
||||
|
@ -77,7 +82,7 @@ pub struct AcceptorService<F> {
|
|||
impl<F: Filter> Service for AcceptorService<F> {
|
||||
type Request = Io<F>;
|
||||
type Response = Io<TlsFilter<F>>;
|
||||
type Error = Box<dyn Error>;
|
||||
type Error = io::Error;
|
||||
type Future = AcceptorServiceFut<F>;
|
||||
|
||||
#[inline]
|
||||
|
@ -110,7 +115,7 @@ pin_project_lite::pin_project! {
|
|||
}
|
||||
|
||||
impl<F: Filter> Future for AcceptorServiceFut<F> {
|
||||
type Output = Result<Io<TlsFilter<F>>, Box<dyn Error>>;
|
||||
type Output = Result<Io<TlsFilter<F>>, io::Error>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
self.project().fut.poll(cx)
|
||||
|
|
307
ntex-tls/src/rustls/client.rs
Normal file
307
ntex-tls/src/rustls/client.rs
Normal file
|
@ -0,0 +1,307 @@
|
|||
//! An implementation of SSL streams for ntex backed by OpenSSL
|
||||
use std::io::{self, Read as IoRead, Write as IoWrite};
|
||||
use std::sync::Arc;
|
||||
use std::{any, cell::RefCell, cmp, task::Context, task::Poll};
|
||||
|
||||
use ntex_bytes::{BufMut, BytesMut, PoolRef};
|
||||
use ntex_io::{Filter, Io, IoRef, ReadFilter, WriteFilter, WriteReadiness};
|
||||
use ntex_util::future::poll_fn;
|
||||
use tls_rust::{ClientConfig, ClientConnection, ServerName};
|
||||
|
||||
use super::TlsFilter;
|
||||
use crate::types;
|
||||
|
||||
/// An implementation of SSL streams
|
||||
pub struct TlsClientFilter<F> {
|
||||
inner: RefCell<IoInner<F>>,
|
||||
session: RefCell<ClientConnection>,
|
||||
}
|
||||
|
||||
struct IoInner<F> {
|
||||
inner: F,
|
||||
pool: PoolRef,
|
||||
read_buf: Option<BytesMut>,
|
||||
write_buf: Option<BytesMut>,
|
||||
}
|
||||
|
||||
impl<F: Filter> Filter for TlsClientFilter<F> {
|
||||
fn shutdown(&self, st: &IoRef) -> Poll<Result<(), io::Error>> {
|
||||
self.inner.borrow().inner.shutdown(st)
|
||||
}
|
||||
|
||||
fn query(&self, id: any::TypeId) -> Option<Box<dyn any::Any>> {
|
||||
const H2: &[u8] = b"h2";
|
||||
|
||||
if id == any::TypeId::of::<types::HttpProtocol>() {
|
||||
let h2 = self
|
||||
.session
|
||||
.borrow()
|
||||
.alpn_protocol()
|
||||
.map(|protos| protos.windows(2).any(|w| w == H2))
|
||||
.unwrap_or(false);
|
||||
|
||||
let proto = if h2 {
|
||||
types::HttpProtocol::Http2
|
||||
} else {
|
||||
types::HttpProtocol::Http1
|
||||
};
|
||||
Some(Box::new(proto))
|
||||
} else {
|
||||
self.inner.borrow().inner.query(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Filter> ReadFilter for TlsClientFilter<F> {
|
||||
fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
|
||||
self.inner.borrow().inner.poll_read_ready(cx)
|
||||
}
|
||||
|
||||
fn read_closed(&self, err: Option<io::Error>) {
|
||||
self.inner.borrow().inner.read_closed(err)
|
||||
}
|
||||
|
||||
fn get_read_buf(&self) -> Option<BytesMut> {
|
||||
if let Some(buf) = self.inner.borrow_mut().read_buf.take() {
|
||||
if !buf.is_empty() {
|
||||
return Some(buf);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn release_read_buf(
|
||||
&self,
|
||||
mut src: BytesMut,
|
||||
_nb: usize,
|
||||
) -> Result<bool, io::Error> {
|
||||
let mut session = self.session.borrow_mut();
|
||||
if session.is_handshaking() {
|
||||
self.inner.borrow_mut().read_buf = Some(src);
|
||||
Ok(false)
|
||||
} else {
|
||||
if src.is_empty() {
|
||||
return Ok(false);
|
||||
}
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let (hw, lw) = inner.pool.read_params().unpack();
|
||||
|
||||
// get inner filter buffer
|
||||
let mut buf = if let Some(buf) = inner.inner.get_read_buf() {
|
||||
buf
|
||||
} else {
|
||||
BytesMut::with_capacity_in(lw, inner.pool)
|
||||
};
|
||||
|
||||
let mut new_bytes = 0;
|
||||
loop {
|
||||
// make sure we've got room
|
||||
let remaining = buf.remaining_mut();
|
||||
if remaining < lw {
|
||||
buf.reserve(hw - remaining);
|
||||
}
|
||||
|
||||
let mut cursor = io::Cursor::new(&src);
|
||||
let n = session.read_tls(&mut cursor)?;
|
||||
src.split_to(n);
|
||||
let state = session
|
||||
.process_new_packets()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||
|
||||
let new_b = state.plaintext_bytes_to_read();
|
||||
if new_b > 0 {
|
||||
buf.reserve(new_b);
|
||||
let chunk: &mut [u8] =
|
||||
unsafe { std::mem::transmute(&mut *buf.chunk_mut()) };
|
||||
let v = session.reader().read(chunk)?;
|
||||
unsafe { buf.advance_mut(v) };
|
||||
new_bytes += v;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !src.is_empty() {
|
||||
inner.read_buf = Some(src);
|
||||
}
|
||||
inner.inner.release_read_buf(buf, new_bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Filter> WriteFilter for TlsClientFilter<F> {
|
||||
fn poll_write_ready(
|
||||
&self,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Result<(), WriteReadiness>> {
|
||||
self.inner.borrow().inner.poll_write_ready(cx)
|
||||
}
|
||||
|
||||
fn write_closed(&self, err: Option<io::Error>) {
|
||||
self.inner.borrow().inner.read_closed(err)
|
||||
}
|
||||
|
||||
fn get_write_buf(&self) -> Option<BytesMut> {
|
||||
if let Some(buf) = self.inner.borrow_mut().write_buf.take() {
|
||||
if !buf.is_empty() {
|
||||
return Some(buf);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn release_write_buf(&self, mut src: BytesMut) -> Result<bool, io::Error> {
|
||||
let mut session = self.session.borrow_mut();
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let mut io = Wrapper(&mut *inner);
|
||||
|
||||
loop {
|
||||
if !src.is_empty() {
|
||||
let n = session.writer().write(&src)?;
|
||||
src.split_to(n);
|
||||
}
|
||||
|
||||
let n = session.write_tls(&mut io)?;
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !src.is_empty() {
|
||||
self.inner.borrow_mut().write_buf = Some(src);
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
struct Wrapper<'a, F>(&'a mut IoInner<F>);
|
||||
|
||||
impl<'a, F: Filter> io::Read for Wrapper<'a, F> {
|
||||
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
|
||||
if let Some(read_buf) = self.0.read_buf.as_mut() {
|
||||
let len = cmp::min(read_buf.len(), dst.len());
|
||||
if len > 0 {
|
||||
dst[..len].copy_from_slice(&read_buf.split_to(len));
|
||||
Ok(len)
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
|
||||
}
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, F: Filter> io::Write for Wrapper<'a, F> {
|
||||
fn write(&mut self, src: &[u8]) -> io::Result<usize> {
|
||||
let mut buf = if let Some(mut buf) = self.0.inner.get_write_buf() {
|
||||
buf.reserve(src.len());
|
||||
buf
|
||||
} else {
|
||||
BytesMut::with_capacity_in(src.len(), self.0.pool)
|
||||
};
|
||||
buf.extend_from_slice(src);
|
||||
self.0.inner.release_write_buf(buf)?;
|
||||
Ok(src.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Filter> TlsClientFilter<F> {
|
||||
pub(crate) async fn create(
|
||||
st: Io<F>,
|
||||
cfg: Arc<ClientConfig>,
|
||||
domain: ServerName,
|
||||
) -> Result<Io<TlsFilter<F>>, io::Error> {
|
||||
let pool = st.memory_pool();
|
||||
let session = match ClientConnection::new(cfg, domain) {
|
||||
Ok(session) => session,
|
||||
Err(error) => return Err(io::Error::new(io::ErrorKind::Other, error)),
|
||||
};
|
||||
let st = st.map_filter(|inner: F| {
|
||||
let inner = IoInner {
|
||||
pool,
|
||||
inner,
|
||||
read_buf: None,
|
||||
write_buf: None,
|
||||
};
|
||||
|
||||
Ok::<_, io::Error>(TlsFilter::new_client(TlsClientFilter {
|
||||
inner: RefCell::new(inner),
|
||||
session: RefCell::new(session),
|
||||
}))
|
||||
})?;
|
||||
|
||||
let filter = st.filter();
|
||||
let read = st.read();
|
||||
|
||||
loop {
|
||||
let (result, wants_read) = {
|
||||
let mut session = filter.client().session.borrow_mut();
|
||||
let mut inner = filter.client().inner.borrow_mut();
|
||||
let mut io = Wrapper(&mut *inner);
|
||||
let result = session.complete_io(&mut io);
|
||||
let wants_read = session.wants_read();
|
||||
|
||||
if session.wants_write() {
|
||||
loop {
|
||||
let n = session.write_tls(&mut io)?;
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if result.is_ok() && wants_read {
|
||||
poll_fn(|cx| {
|
||||
read.poll_read_ready(cx).map_err(|e| {
|
||||
e.unwrap_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::Other, "disconnected")
|
||||
})
|
||||
})?;
|
||||
Poll::Ready(Ok::<_, io::Error>(()))
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
(result, wants_read)
|
||||
};
|
||||
match result {
|
||||
Ok(_) => return Ok(st),
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
if wants_read {
|
||||
read.take_readiness();
|
||||
}
|
||||
poll_fn(|cx| {
|
||||
let read_ready = if wants_read {
|
||||
if read.is_ready() {
|
||||
true
|
||||
} else {
|
||||
read.poll_read_ready(cx).map_err(|e| {
|
||||
e.unwrap_or_else(|| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"disconnected",
|
||||
)
|
||||
})
|
||||
})?;
|
||||
false
|
||||
}
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if read_ready {
|
||||
Poll::Ready(Ok::<_, io::Error>(()))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,56 +1,103 @@
|
|||
#![allow(dead_code, unused_imports, clippy::type_complexity)]
|
||||
#![allow(clippy::type_complexity)]
|
||||
//! An implementation of SSL streams for ntex backed by OpenSSL
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
any, cmp, error::Error, future::Future, io, pin::Pin, task::Context, task::Poll,
|
||||
};
|
||||
use std::{any, future::Future, io, pin::Pin, task::Context, task::Poll};
|
||||
|
||||
use ntex_bytes::{BufMut, BytesMut};
|
||||
use ntex_bytes::BytesMut;
|
||||
use ntex_io::{
|
||||
Filter, FilterFactory, Io, IoRef, ReadFilter, WriteFilter, WriteReadiness,
|
||||
};
|
||||
use ntex_util::{future::Ready, time::Millis};
|
||||
use ntex_util::time::Millis;
|
||||
use tls_rust::{ClientConfig, ServerConfig, ServerName};
|
||||
|
||||
use super::types;
|
||||
|
||||
mod accept;
|
||||
mod client;
|
||||
mod server;
|
||||
pub use accept::{Acceptor, AcceptorService};
|
||||
|
||||
use self::client::TlsClientFilter;
|
||||
use self::server::TlsServerFilter;
|
||||
|
||||
/// An implementation of SSL streams
|
||||
pub struct TlsFilter<F> {
|
||||
inner: F,
|
||||
inner: InnerTlsFilter<F>,
|
||||
}
|
||||
|
||||
enum InnerTlsFilter<F> {
|
||||
Server(TlsServerFilter<F>),
|
||||
Client(TlsClientFilter<F>),
|
||||
}
|
||||
|
||||
impl<F> TlsFilter<F> {
|
||||
fn new_server(server: TlsServerFilter<F>) -> Self {
|
||||
TlsFilter {
|
||||
inner: InnerTlsFilter::Server(server),
|
||||
}
|
||||
}
|
||||
fn new_client(client: TlsClientFilter<F>) -> Self {
|
||||
TlsFilter {
|
||||
inner: InnerTlsFilter::Client(client),
|
||||
}
|
||||
}
|
||||
fn server(&self) -> &TlsServerFilter<F> {
|
||||
match self.inner {
|
||||
InnerTlsFilter::Server(ref server) => server,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
fn client(&self) -> &TlsClientFilter<F> {
|
||||
match self.inner {
|
||||
InnerTlsFilter::Client(ref server) => server,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Filter> Filter for TlsFilter<F> {
|
||||
#[inline]
|
||||
fn shutdown(&self, st: &IoRef) -> Poll<Result<(), io::Error>> {
|
||||
self.inner.shutdown(st)
|
||||
match self.inner {
|
||||
InnerTlsFilter::Server(ref f) => f.shutdown(st),
|
||||
InnerTlsFilter::Client(ref f) => f.shutdown(st),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn query(&self, id: any::TypeId) -> Option<Box<dyn any::Any>> {
|
||||
self.inner.query(id)
|
||||
match self.inner {
|
||||
InnerTlsFilter::Server(ref f) => f.query(id),
|
||||
InnerTlsFilter::Client(ref f) => f.query(id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Filter> ReadFilter for TlsFilter<F> {
|
||||
fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
|
||||
self.inner.poll_read_ready(cx)
|
||||
match self.inner {
|
||||
InnerTlsFilter::Server(ref f) => f.poll_read_ready(cx),
|
||||
InnerTlsFilter::Client(ref f) => f.poll_read_ready(cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_closed(&self, err: Option<io::Error>) {
|
||||
self.inner.read_closed(err)
|
||||
match self.inner {
|
||||
InnerTlsFilter::Server(ref f) => f.read_closed(err),
|
||||
InnerTlsFilter::Client(ref f) => f.read_closed(err),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_read_buf(&self) -> Option<BytesMut> {
|
||||
self.inner.get_read_buf()
|
||||
match self.inner {
|
||||
InnerTlsFilter::Server(ref f) => f.get_read_buf(),
|
||||
InnerTlsFilter::Client(ref f) => f.get_read_buf(),
|
||||
}
|
||||
}
|
||||
|
||||
fn release_read_buf(
|
||||
&self,
|
||||
src: BytesMut,
|
||||
new_bytes: usize,
|
||||
) -> Result<(), io::Error> {
|
||||
self.inner.release_read_buf(src, new_bytes)
|
||||
fn release_read_buf(&self, src: BytesMut, nb: usize) -> Result<bool, io::Error> {
|
||||
match self.inner {
|
||||
InnerTlsFilter::Server(ref f) => f.release_read_buf(src, nb),
|
||||
InnerTlsFilter::Client(ref f) => f.release_read_buf(src, nb),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,19 +106,31 @@ impl<F: Filter> WriteFilter for TlsFilter<F> {
|
|||
&self,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Result<(), WriteReadiness>> {
|
||||
self.inner.poll_write_ready(cx)
|
||||
match self.inner {
|
||||
InnerTlsFilter::Server(ref f) => f.poll_write_ready(cx),
|
||||
InnerTlsFilter::Client(ref f) => f.poll_write_ready(cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_closed(&self, err: Option<io::Error>) {
|
||||
self.inner.read_closed(err)
|
||||
match self.inner {
|
||||
InnerTlsFilter::Server(ref f) => f.write_closed(err),
|
||||
InnerTlsFilter::Client(ref f) => f.write_closed(err),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_write_buf(&self) -> Option<BytesMut> {
|
||||
self.inner.get_write_buf()
|
||||
match self.inner {
|
||||
InnerTlsFilter::Server(ref f) => f.get_write_buf(),
|
||||
InnerTlsFilter::Client(ref f) => f.get_write_buf(),
|
||||
}
|
||||
}
|
||||
|
||||
fn release_write_buf(&self, buf: BytesMut) -> Result<(), io::Error> {
|
||||
self.inner.release_write_buf(buf)
|
||||
fn release_write_buf(&self, src: BytesMut) -> Result<bool, io::Error> {
|
||||
match self.inner {
|
||||
InnerTlsFilter::Server(ref f) => f.release_write_buf(src),
|
||||
InnerTlsFilter::Client(ref f) => f.release_write_buf(src),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,9 +141,9 @@ pub struct TlsAcceptor {
|
|||
|
||||
impl TlsAcceptor {
|
||||
/// Create openssl acceptor filter factory
|
||||
pub fn new(cfg: ServerConfig) -> Self {
|
||||
pub fn new(cfg: Arc<ServerConfig>) -> Self {
|
||||
TlsAcceptor {
|
||||
cfg: Arc::new(cfg),
|
||||
cfg,
|
||||
timeout: Millis(5_000),
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +157,12 @@ impl TlsAcceptor {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ServerConfig> for TlsAcceptor {
|
||||
fn from(cfg: ServerConfig) -> Self {
|
||||
Self::new(Arc::new(cfg))
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for TlsAcceptor {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
|
@ -110,12 +175,14 @@ impl Clone for TlsAcceptor {
|
|||
impl<F: Filter + 'static> FilterFactory<F> for TlsAcceptor {
|
||||
type Filter = TlsFilter<F>;
|
||||
|
||||
type Error = Box<dyn Error>;
|
||||
type Future = Ready<Io<Self::Filter>, Self::Error>;
|
||||
type Error = io::Error;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<Io<Self::Filter>, io::Error>>>>;
|
||||
|
||||
fn create(self, st: Io<F>) -> Self::Future {
|
||||
st.map_filter::<Self, _>(|inner: F| Ok(TlsFilter { inner }))
|
||||
.into()
|
||||
let cfg = self.cfg.clone();
|
||||
let timeout = self.timeout;
|
||||
|
||||
Box::pin(async move { TlsServerFilter::create(st, cfg, timeout).await })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,8 +192,16 @@ pub struct TlsConnector {
|
|||
|
||||
impl TlsConnector {
|
||||
/// Create openssl connector filter factory
|
||||
pub fn new(cfg: ClientConfig) -> Self {
|
||||
TlsConnector { cfg: Arc::new(cfg) }
|
||||
pub fn new(cfg: Arc<ClientConfig>) -> Self {
|
||||
TlsConnector { cfg }
|
||||
}
|
||||
|
||||
/// Set server name
|
||||
pub fn server_name(self, server_name: ServerName) -> TlsConnectorConfigured {
|
||||
TlsConnectorConfigured {
|
||||
server_name,
|
||||
cfg: self.cfg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,14 +213,30 @@ impl Clone for TlsConnector {
|
|||
}
|
||||
}
|
||||
|
||||
impl<F: Filter + 'static> FilterFactory<F> for TlsConnector {
|
||||
type Filter = TlsFilter<F>;
|
||||
pub struct TlsConnectorConfigured {
|
||||
cfg: Arc<ClientConfig>,
|
||||
server_name: ServerName,
|
||||
}
|
||||
|
||||
type Error = Box<dyn Error>;
|
||||
type Future = Ready<Io<Self::Filter>, Self::Error>;
|
||||
|
||||
fn create(self, st: Io<F>) -> Self::Future {
|
||||
st.map_filter::<Self, _>(|inner| Ok(TlsFilter { inner }))
|
||||
.into()
|
||||
impl Clone for TlsConnectorConfigured {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
cfg: self.cfg.clone(),
|
||||
server_name: self.server_name.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Filter + 'static> FilterFactory<F> for TlsConnectorConfigured {
|
||||
type Filter = TlsFilter<F>;
|
||||
|
||||
type Error = io::Error;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<Io<Self::Filter>, io::Error>>>>;
|
||||
|
||||
fn create(self, st: Io<F>) -> Self::Future {
|
||||
let cfg = self.cfg;
|
||||
let server_name = self.server_name;
|
||||
|
||||
Box::pin(async move { TlsClientFilter::create(st, cfg, server_name).await })
|
||||
}
|
||||
}
|
||||
|
|
312
ntex-tls/src/rustls/server.rs
Normal file
312
ntex-tls/src/rustls/server.rs
Normal file
|
@ -0,0 +1,312 @@
|
|||
//! An implementation of SSL streams for ntex backed by OpenSSL
|
||||
use std::io::{self, Read as IoRead, Write as IoWrite};
|
||||
use std::sync::Arc;
|
||||
use std::{any, cell::RefCell, cmp, task::Context, task::Poll};
|
||||
|
||||
use ntex_bytes::{BufMut, BytesMut, PoolRef};
|
||||
use ntex_io::{Filter, Io, IoRef, ReadFilter, WriteFilter, WriteReadiness};
|
||||
use ntex_util::{future::poll_fn, time, time::Millis};
|
||||
use tls_rust::{ServerConfig, ServerConnection};
|
||||
|
||||
use super::TlsFilter;
|
||||
use crate::types;
|
||||
|
||||
/// An implementation of SSL streams
|
||||
pub struct TlsServerFilter<F> {
|
||||
inner: RefCell<IoInner<F>>,
|
||||
session: RefCell<ServerConnection>,
|
||||
}
|
||||
|
||||
struct IoInner<F> {
|
||||
inner: F,
|
||||
pool: PoolRef,
|
||||
read_buf: Option<BytesMut>,
|
||||
write_buf: Option<BytesMut>,
|
||||
}
|
||||
|
||||
impl<F: Filter> Filter for TlsServerFilter<F> {
|
||||
fn shutdown(&self, st: &IoRef) -> Poll<Result<(), io::Error>> {
|
||||
self.inner.borrow().inner.shutdown(st)
|
||||
}
|
||||
|
||||
fn query(&self, id: any::TypeId) -> Option<Box<dyn any::Any>> {
|
||||
const H2: &[u8] = b"h2";
|
||||
|
||||
if id == any::TypeId::of::<types::HttpProtocol>() {
|
||||
let h2 = self
|
||||
.session
|
||||
.borrow()
|
||||
.alpn_protocol()
|
||||
.map(|protos| protos.windows(2).any(|w| w == H2))
|
||||
.unwrap_or(false);
|
||||
|
||||
let proto = if h2 {
|
||||
types::HttpProtocol::Http2
|
||||
} else {
|
||||
types::HttpProtocol::Http1
|
||||
};
|
||||
Some(Box::new(proto))
|
||||
} else {
|
||||
self.inner.borrow().inner.query(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Filter> ReadFilter for TlsServerFilter<F> {
|
||||
fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
|
||||
self.inner.borrow().inner.poll_read_ready(cx)
|
||||
}
|
||||
|
||||
fn read_closed(&self, err: Option<io::Error>) {
|
||||
self.inner.borrow().inner.read_closed(err)
|
||||
}
|
||||
|
||||
fn get_read_buf(&self) -> Option<BytesMut> {
|
||||
if let Some(buf) = self.inner.borrow_mut().read_buf.take() {
|
||||
if !buf.is_empty() {
|
||||
return Some(buf);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn release_read_buf(
|
||||
&self,
|
||||
mut src: BytesMut,
|
||||
_nb: usize,
|
||||
) -> Result<bool, io::Error> {
|
||||
let mut session = self.session.borrow_mut();
|
||||
if session.is_handshaking() {
|
||||
self.inner.borrow_mut().read_buf = Some(src);
|
||||
Ok(false)
|
||||
} else {
|
||||
if src.is_empty() {
|
||||
return Ok(false);
|
||||
}
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let (hw, lw) = inner.pool.read_params().unpack();
|
||||
|
||||
// get inner filter buffer
|
||||
let mut buf = if let Some(buf) = inner.inner.get_read_buf() {
|
||||
buf
|
||||
} else {
|
||||
BytesMut::with_capacity_in(lw, inner.pool)
|
||||
};
|
||||
|
||||
let mut new_bytes = 0;
|
||||
loop {
|
||||
// make sure we've got room
|
||||
let remaining = buf.remaining_mut();
|
||||
if remaining < lw {
|
||||
buf.reserve(hw - remaining);
|
||||
}
|
||||
|
||||
let mut cursor = io::Cursor::new(&src);
|
||||
let n = session.read_tls(&mut cursor)?;
|
||||
src.split_to(n);
|
||||
let state = session
|
||||
.process_new_packets()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||
|
||||
let new_b = state.plaintext_bytes_to_read();
|
||||
if new_b > 0 {
|
||||
buf.reserve(new_b);
|
||||
let chunk: &mut [u8] =
|
||||
unsafe { std::mem::transmute(&mut *buf.chunk_mut()) };
|
||||
let v = session.reader().read(chunk)?;
|
||||
unsafe { buf.advance_mut(v) };
|
||||
new_bytes += v;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !src.is_empty() {
|
||||
inner.read_buf = Some(src);
|
||||
}
|
||||
inner.inner.release_read_buf(buf, new_bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Filter> WriteFilter for TlsServerFilter<F> {
|
||||
fn poll_write_ready(
|
||||
&self,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Result<(), WriteReadiness>> {
|
||||
self.inner.borrow().inner.poll_write_ready(cx)
|
||||
}
|
||||
|
||||
fn write_closed(&self, err: Option<io::Error>) {
|
||||
self.inner.borrow().inner.read_closed(err)
|
||||
}
|
||||
|
||||
fn get_write_buf(&self) -> Option<BytesMut> {
|
||||
if let Some(buf) = self.inner.borrow_mut().write_buf.take() {
|
||||
if !buf.is_empty() {
|
||||
return Some(buf);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn release_write_buf(&self, mut src: BytesMut) -> Result<bool, io::Error> {
|
||||
let mut session = self.session.borrow_mut();
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let mut io = Wrapper(&mut *inner);
|
||||
|
||||
loop {
|
||||
if !src.is_empty() {
|
||||
let n = session.writer().write(&src)?;
|
||||
src.split_to(n);
|
||||
}
|
||||
|
||||
let n = session.write_tls(&mut io)?;
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !src.is_empty() {
|
||||
self.inner.borrow_mut().write_buf = Some(src);
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
struct Wrapper<'a, F>(&'a mut IoInner<F>);
|
||||
|
||||
impl<'a, F: Filter> io::Read for Wrapper<'a, F> {
|
||||
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
|
||||
if let Some(read_buf) = self.0.read_buf.as_mut() {
|
||||
let len = cmp::min(read_buf.len(), dst.len());
|
||||
if len > 0 {
|
||||
dst[..len].copy_from_slice(&read_buf.split_to(len));
|
||||
Ok(len)
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
|
||||
}
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, F: Filter> io::Write for Wrapper<'a, F> {
|
||||
fn write(&mut self, src: &[u8]) -> io::Result<usize> {
|
||||
let mut buf = if let Some(mut buf) = self.0.inner.get_write_buf() {
|
||||
buf.reserve(src.len());
|
||||
buf
|
||||
} else {
|
||||
BytesMut::with_capacity_in(src.len(), self.0.pool)
|
||||
};
|
||||
buf.extend_from_slice(src);
|
||||
self.0.inner.release_write_buf(buf)?;
|
||||
Ok(src.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Filter> TlsServerFilter<F> {
|
||||
pub(crate) async fn create(
|
||||
st: Io<F>,
|
||||
cfg: Arc<ServerConfig>,
|
||||
timeout: Millis,
|
||||
) -> Result<Io<TlsFilter<F>>, io::Error> {
|
||||
time::timeout(timeout, async {
|
||||
let pool = st.memory_pool();
|
||||
let session = match ServerConnection::new(cfg) {
|
||||
Ok(session) => session,
|
||||
Err(error) => return Err(io::Error::new(io::ErrorKind::Other, error)),
|
||||
};
|
||||
let st = st.map_filter(|inner: F| {
|
||||
let inner = IoInner {
|
||||
pool,
|
||||
inner,
|
||||
read_buf: None,
|
||||
write_buf: None,
|
||||
};
|
||||
|
||||
Ok::<_, io::Error>(TlsFilter::new_server(TlsServerFilter {
|
||||
inner: RefCell::new(inner),
|
||||
session: RefCell::new(session),
|
||||
}))
|
||||
})?;
|
||||
|
||||
let filter = st.filter();
|
||||
let read = st.read();
|
||||
|
||||
loop {
|
||||
let (result, wants_read) = {
|
||||
let mut session = filter.server().session.borrow_mut();
|
||||
let mut inner = filter.server().inner.borrow_mut();
|
||||
let mut io = Wrapper(&mut *inner);
|
||||
let result = session.complete_io(&mut io);
|
||||
let wants_read = session.wants_read();
|
||||
|
||||
if session.wants_write() {
|
||||
loop {
|
||||
let n = session.write_tls(&mut io)?;
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if result.is_ok() && wants_read {
|
||||
poll_fn(|cx| {
|
||||
read.poll_read_ready(cx).map_err(|e| {
|
||||
e.unwrap_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::Other, "disconnected")
|
||||
})
|
||||
})?;
|
||||
Poll::Ready(Ok::<_, io::Error>(()))
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
(result, wants_read)
|
||||
};
|
||||
match result {
|
||||
Ok(_) => return Ok(st),
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
if wants_read {
|
||||
read.take_readiness();
|
||||
}
|
||||
poll_fn(|cx| {
|
||||
let read_ready = if wants_read {
|
||||
if read.is_ready() {
|
||||
true
|
||||
} else {
|
||||
read.poll_read_ready(cx).map_err(|e| {
|
||||
e.unwrap_or_else(|| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"disconnected",
|
||||
)
|
||||
})
|
||||
})?;
|
||||
false
|
||||
}
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if read_ready {
|
||||
Poll::Ready(Ok::<_, io::Error>(()))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::TimedOut, "rustls handshake timeout"))
|
||||
.and_then(|item| item)
|
||||
}
|
||||
}
|
|
@ -45,8 +45,8 @@ ntex-service = "0.2.1"
|
|||
ntex-macros = "0.1.3"
|
||||
ntex-util = "0.1.3"
|
||||
ntex-bytes = "0.1.8"
|
||||
ntex-tls = "0.1"
|
||||
ntex-io = { version = "0.1.0-b.0", features = ["tokio"] }
|
||||
ntex-tls = "0.1.0-b.0"
|
||||
ntex-io = "0.1.0-b.0"
|
||||
ntex-rt = { version = "0.4.0-b.0", default-features = false, features = ["tokio"] }
|
||||
|
||||
base64 = "0.13"
|
||||
|
|
|
@ -20,7 +20,7 @@ pub struct Connector<T> {
|
|||
impl<T> Connector<T> {
|
||||
pub fn new(config: ClientConfig) -> Self {
|
||||
Connector {
|
||||
inner: TlsConnector::new(config),
|
||||
inner: TlsConnector::new(std::sync::Arc::new(config)),
|
||||
connector: BaseConnector::default(),
|
||||
}
|
||||
}
|
||||
|
@ -55,8 +55,9 @@ impl<T: Address + 'static> Connector<T> {
|
|||
let io = conn.await?;
|
||||
trace!("SSL Handshake start for: {:?}", host);
|
||||
|
||||
let _host = ServerName::try_from(host.as_str())
|
||||
let host = ServerName::try_from(host.as_str())
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("{}", e)))?;
|
||||
let connector = connector.server_name(host.clone());
|
||||
|
||||
match io.add_filter(connector).await {
|
||||
Ok(io) => {
|
||||
|
|
|
@ -23,6 +23,12 @@ impl From<usize> for KeepAlive {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Seconds> for KeepAlive {
|
||||
fn from(keepalive: Seconds) -> Self {
|
||||
KeepAlive::Timeout(keepalive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Option<usize>> for KeepAlive {
|
||||
fn from(keepalive: Option<usize>) -> Self {
|
||||
if let Some(keepalive) = keepalive {
|
||||
|
@ -56,8 +62,8 @@ impl Default for ServiceConfig {
|
|||
fn default() -> Self {
|
||||
Self::new(
|
||||
KeepAlive::Timeout(Seconds(5)),
|
||||
Millis::ZERO,
|
||||
Seconds::ZERO,
|
||||
Millis(1_000),
|
||||
Seconds::ONE,
|
||||
Millis(5_000),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -722,7 +722,7 @@ mod tests {
|
|||
use crate::io::{self as nio, DefaultFilter};
|
||||
use crate::service::{boxed, fn_service, IntoService};
|
||||
use crate::util::{lazy, next, Bytes, BytesMut};
|
||||
use crate::{codec::Decoder, testing::Io, time::sleep, time::Millis};
|
||||
use crate::{codec::Decoder, testing::Io, time::sleep, time::Millis, time::Seconds};
|
||||
|
||||
const BUFFER_SIZE: usize = 32_768;
|
||||
|
||||
|
@ -738,10 +738,16 @@ mod tests {
|
|||
S::Response: Into<Response<B>>,
|
||||
B: MessageBody,
|
||||
{
|
||||
let config = ServiceConfig::new(
|
||||
Seconds(5).into(),
|
||||
Millis(1_000),
|
||||
Seconds::ZERO,
|
||||
Millis(5_000),
|
||||
);
|
||||
Dispatcher::new(
|
||||
nio::Io::new(stream),
|
||||
Rc::new(DispatcherConfig::new(
|
||||
ServiceConfig::default(),
|
||||
config,
|
||||
service.into_service(),
|
||||
ExpectHandler,
|
||||
None,
|
||||
|
@ -788,10 +794,16 @@ mod tests {
|
|||
|
||||
let data = Rc::new(Cell::new(false));
|
||||
let data2 = data.clone();
|
||||
let config = ServiceConfig::new(
|
||||
Seconds(5).into(),
|
||||
Millis(1_000),
|
||||
Seconds::ZERO,
|
||||
Millis(5_000),
|
||||
);
|
||||
let mut h1 = Dispatcher::<_, _, _, _, UpgradeHandler<DefaultFilter>>::new(
|
||||
nio::Io::new(server),
|
||||
Rc::new(DispatcherConfig::new(
|
||||
ServiceConfig::default(),
|
||||
config,
|
||||
fn_service(|_| {
|
||||
Box::pin(async { Ok::<_, io::Error>(Response::Ok().finish()) })
|
||||
}),
|
||||
|
|
|
@ -146,9 +146,9 @@ mod rustls {
|
|||
InitError = (),
|
||||
> {
|
||||
pipeline_factory(
|
||||
Acceptor::new(config)
|
||||
Acceptor::from(config)
|
||||
.timeout(self.handshake_timeout)
|
||||
.map_err(SslError::Ssl)
|
||||
.map_err(|e| SslError::Ssl(Box::new(e)))
|
||||
.map_init_err(|_| panic!()),
|
||||
)
|
||||
.and_then(self.map_err(SslError::Service))
|
||||
|
|
|
@ -109,7 +109,7 @@ mod rustls {
|
|||
/// Create openssl based service
|
||||
pub fn rustls(
|
||||
self,
|
||||
config: ServerConfig,
|
||||
mut config: ServerConfig,
|
||||
) -> impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = Io<F>,
|
||||
|
@ -117,10 +117,13 @@ mod rustls {
|
|||
Error = SslError<DispatchError>,
|
||||
InitError = S::InitError,
|
||||
> {
|
||||
let protos = vec!["h2".to_string().into()];
|
||||
config.alpn_protocols = protos;
|
||||
|
||||
pipeline_factory(
|
||||
Acceptor::new(config)
|
||||
Acceptor::from(config)
|
||||
.timeout(self.handshake_timeout)
|
||||
.map_err(SslError::Ssl)
|
||||
.map_err(|e| SslError::Ssl(Box::new(e)))
|
||||
.map_init_err(|_| panic!()),
|
||||
)
|
||||
.and_then(self.map_err(SslError::Service))
|
||||
|
|
|
@ -59,7 +59,7 @@ where
|
|||
let cfg = ServiceConfig::new(
|
||||
KeepAlive::Timeout(Seconds(5)),
|
||||
Millis(5_000),
|
||||
Seconds::ZERO,
|
||||
Seconds::ONE,
|
||||
Millis(5_000),
|
||||
);
|
||||
|
||||
|
@ -242,7 +242,7 @@ mod rustls {
|
|||
/// Create openssl based service
|
||||
pub fn rustls(
|
||||
self,
|
||||
config: ServerConfig,
|
||||
mut config: ServerConfig,
|
||||
) -> impl ServiceFactory<
|
||||
Config = (),
|
||||
Request = Io<F>,
|
||||
|
@ -250,10 +250,13 @@ mod rustls {
|
|||
Error = SslError<DispatchError>,
|
||||
InitError = (),
|
||||
> {
|
||||
let protos = vec!["h2".to_string().into(), "http/1.1".to_string().into()];
|
||||
config.alpn_protocols = protos;
|
||||
|
||||
pipeline_factory(
|
||||
Acceptor::new(config)
|
||||
Acceptor::from(config)
|
||||
.timeout(self.cfg.0.ssl_handshake_timeout)
|
||||
.map_err(SslError::Ssl)
|
||||
.map_err(|e| SslError::Ssl(Box::new(e)))
|
||||
.map_init_err(|_| panic!()),
|
||||
)
|
||||
.and_then(self.map_err(SslError::Service))
|
||||
|
|
|
@ -32,7 +32,6 @@ pub use ntex_macros::{rt_main as main, rt_test as test};
|
|||
#[cfg(test)]
|
||||
pub(crate) use ntex_macros::rt_test2 as rt_test;
|
||||
|
||||
//pub mod channel;
|
||||
pub mod connect;
|
||||
pub mod http;
|
||||
pub mod server;
|
||||
|
|
|
@ -1186,33 +1186,6 @@ mod tests {
|
|||
assert_eq!(srv.load_body(res).await.unwrap(), Bytes::new());
|
||||
}
|
||||
|
||||
// TODO!
|
||||
// #[crate::rt_test]
|
||||
// async fn test_h2_tcp() {
|
||||
// let srv = server_with(TestServerConfig::default().h2(), || {
|
||||
// App::new().service(
|
||||
// web::resource("/").route(web::get().to(|| async { HttpResponse::Ok() })),
|
||||
// )
|
||||
// });
|
||||
|
||||
// let client = Client::build()
|
||||
// .connector(
|
||||
// Connector::default()
|
||||
// .secure_connector(Service::map(
|
||||
// crate::connect::Connector::default(),
|
||||
// |stream| stream,
|
||||
// ))
|
||||
// .finish(),
|
||||
// )
|
||||
// .timeout(Seconds(30))
|
||||
// .finish();
|
||||
|
||||
// let url = format!("https://localhost:{}/", srv.addr.port());
|
||||
// let response = client.get(url).send().await.unwrap();
|
||||
// assert_eq!(response.version(), Version::HTTP_2);
|
||||
// assert!(response.status().is_success());
|
||||
// }
|
||||
|
||||
#[cfg(feature = "cookie")]
|
||||
#[test]
|
||||
fn test_response_cookies() {
|
||||
|
|
|
@ -1,19 +1,31 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDEDCCAfgCCQCQdmIZc/Ib/jANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQGEwJ1
|
||||
czELMAkGA1UECAwCY2ExCzAJBgNVBAcMAnNmMSEwHwYJKoZIhvcNAQkBFhJmYWZo
|
||||
cmQ5MUBnbWFpbC5jb20wHhcNMTkxMTE5MTEwNjU1WhcNMjkxMTE2MTEwNjU1WjBK
|
||||
MQswCQYDVQQGEwJ1czELMAkGA1UECAwCY2ExCzAJBgNVBAcMAnNmMSEwHwYJKoZI
|
||||
hvcNAQkBFhJmYWZocmQ5MUBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
||||
DwAwggEKAoIBAQDcnaz12CKzUL7248V7Axhms/O9UQXfAdw0yolEfC3P5jADa/1C
|
||||
+kLWKjAc2coqDSbGsrsR6KiH2g06Kunx+tSGqUO+Sct7HEehmxndiSwx/hfMWezy
|
||||
XRe/olcHFTeCk/Tllz4xGEplhPua6GLhJygLOhAMiV8cwCYrgyPqsDduExLDFCqc
|
||||
K2xntIPreumXpiE3QY4+MWyteiJko4IWDFf/UwwsdCY5MlFfw1F/Uv9vz7FfOfvu
|
||||
GccHd/ex8cOwotUqd6emZb+0bVE24Sv8U+yLnHIVx/tOkxgMAnJEpAnf2G3Wp3zU
|
||||
b2GJosbmfGaf+xTfnGGhTLLL7kCtva+NvZr5AgMBAAEwDQYJKoZIhvcNAQELBQAD
|
||||
ggEBANftoL8zDGrjCwWvct8kOOqset2ukK8vjIGwfm88CKsy0IfSochNz2qeIu9R
|
||||
ZuO7c0pfjmRkir9ZQdq9vXgG3ccL9UstFsferPH9W3YJ83kgXg3fa0EmCiN/0hwz
|
||||
6Ij1ZBiN1j3+d6+PJPgyYFNu2nGwox5mJ9+aRAGe0/9c63PEOY8P2TI4HsiPmYSl
|
||||
fFR8k/03vr6e+rTKW85BgctjvYKe/TnFxeCQ7dZ+na7vlEtch4tNmy6O/vEk2kCt
|
||||
5jW0DUxhmRsv2wGmfFRI0+LotHjoXQQZi6nN5aGL3odaGF3gYwIVlZNd3AdkwDQz
|
||||
BzG0ZwXuDDV9bSs3MfWEWcy4xuU=
|
||||
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
|
||||
Ing=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
|
@ -94,16 +94,13 @@ async fn test_connection_reuse_h2() {
|
|||
|
||||
// req 1
|
||||
let _response = client.get(srv.surl("/")).send().await;
|
||||
|
||||
// let response = request.await.unwrap();
|
||||
// assert!(response.status().is_success());
|
||||
|
||||
// req 2
|
||||
let _response = client.post(srv.surl("/")).send().await;
|
||||
// let response = req.send().await.unwrap();
|
||||
//assert!(response.status().is_success());
|
||||
//assert_eq!(response.version(), Version::HTTP_2);
|
||||
|
||||
// one connection
|
||||
// assert_eq!(num.load(Ordering::Relaxed), 1);
|
||||
//assert_eq!(num.load(Ordering::Relaxed), 1);
|
||||
}
|
||||
|
|
|
@ -1,28 +1,51 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDcnaz12CKzUL72
|
||||
48V7Axhms/O9UQXfAdw0yolEfC3P5jADa/1C+kLWKjAc2coqDSbGsrsR6KiH2g06
|
||||
Kunx+tSGqUO+Sct7HEehmxndiSwx/hfMWezyXRe/olcHFTeCk/Tllz4xGEplhPua
|
||||
6GLhJygLOhAMiV8cwCYrgyPqsDduExLDFCqcK2xntIPreumXpiE3QY4+MWyteiJk
|
||||
o4IWDFf/UwwsdCY5MlFfw1F/Uv9vz7FfOfvuGccHd/ex8cOwotUqd6emZb+0bVE2
|
||||
4Sv8U+yLnHIVx/tOkxgMAnJEpAnf2G3Wp3zUb2GJosbmfGaf+xTfnGGhTLLL7kCt
|
||||
va+NvZr5AgMBAAECggEBAKoU0UwzVgVCQgca8Jt2dnBvWYDhnxIfYAI/BvaKedMm
|
||||
1ms87OKfB7oOiksjyI0E2JklH72dzZf2jm4CuZt5UjGC+xwPzlTaJ4s6hQVbBHyC
|
||||
NRyxU1BCXtW5tThbrhD4OjxqjmLRJEIB9OunLtwAEQoeuFLB8Va7+HFhR+Zd9k3f
|
||||
7aVA93pC5A50NRbZlke4miJ3Q8n7ZF0+UmxkBfm3fbqLk7aMWkoEKwLLTadjRlu1
|
||||
bBp0YDStX66I/p1kujqBOdh6VpPvxFOa1sV9pq0jeiGc9YfSkzRSKzIn8GoyviFB
|
||||
fHeszQdNlcnrSDSNnMABAw+ZpxUO7SCaftjwejEmKZUCgYEA+TY43VpmV95eY7eo
|
||||
WKwGepiHE0fwQLuKGELmZdZI80tFi73oZMuiB5WzwmkaKGcJmm7KGE9KEvHQCo9j
|
||||
xvmktBR0VEZH8pmVfun+4h6+0H7m/NKMBBeOyv/IK8jBgHjkkB6e6nmeR7CqTxCw
|
||||
tf9tbajl1QN8gNzXZSjBDT/lanMCgYEA4qANOKOSiEARtgwyXQeeSJcM2uPv6zF3
|
||||
ffM7vjSedtuEOHUSVeyBP/W8KDt7zyPppO/WNbURHS+HV0maS9yyj6zpVS2HGmbs
|
||||
3fetswsQ+zYVdokW89x4oc2z4XOGHd1LcSlyhRwPt0u2g1E9L0irwTQLWU0npFmG
|
||||
PRf7sN9+LeMCgYAGkDUDL2ROoB6gRa/7Vdx90hKMoXJkYgwLA4gJ2pDlR3A3c/Lw
|
||||
5KQJyxmG3zm/IqeQF6be6QesZA30mT4peV2rGHbP2WH/s6fKReNelSy1VQJEWk8x
|
||||
tGUgV4gwDwN5nLV4TjYlOrq+bJqvpmLhCC8bmj0jVQosYqSRl3cuICasnQKBgGlV
|
||||
VO/Xb1su1EyWPK5qxRIeSxZOTYw2sMB01nbgxCqge0M2fvA6/hQ5ZlwY0cIEgits
|
||||
YlcSMsMq/TAAANxz1vbaupUhlSMbZcsBvNV0Nk9c4vr2Wxm7hsJF9u66IEMvQUp2
|
||||
pkjiMxfR9CHzF4orr9EcHI5EQ0Grbq5kwFKEfoRbAoGAcWoFPILeJOlp2yW/Ds3E
|
||||
g2fQdI9BAamtEZEaslJmZMmsDTg5ACPcDkOSFEQIaJ7wLPXeZy74FVk/NrY5F8Gz
|
||||
bjX9OD/xzwp852yW5L9r62vYJakAlXef5jI6CFdYKDDCcarU0S7W5k6kq9n+wrBR
|
||||
i1NklYmUAMr2q59uJA5zsic=
|
||||
-----END PRIVATE KEY-----
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
|
|
@ -142,8 +142,6 @@ async fn test_openssl() {
|
|||
sys.stop();
|
||||
}
|
||||
|
||||
// TODO! fix
|
||||
#[ignore]
|
||||
#[ntex::test]
|
||||
#[cfg(all(feature = "rustls", feature = "openssl"))]
|
||||
async fn test_rustls() {
|
||||
|
|
|
@ -847,14 +847,12 @@ async fn test_brotli_encoding_large_openssl_h2() {
|
|||
assert_eq!(bytes, Bytes::from(data));
|
||||
}
|
||||
|
||||
// TODO fix
|
||||
#[ignore]
|
||||
#[cfg(all(feature = "rustls", feature = "openssl"))]
|
||||
#[ntex::test]
|
||||
async fn test_reading_deflate_encoding_large_random_rustls() {
|
||||
use std::{fs::File, io::BufReader};
|
||||
|
||||
use rustls_pemfile::{certs, pkcs8_private_keys};
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use tls_rustls::{Certificate, PrivateKey, ServerConfig};
|
||||
|
||||
let data = rand::thread_rng()
|
||||
|
@ -907,8 +905,6 @@ async fn test_reading_deflate_encoding_large_random_rustls() {
|
|||
assert_eq!(bytes, Bytes::from(data));
|
||||
}
|
||||
|
||||
// TODO fix
|
||||
#[ignore]
|
||||
#[cfg(all(feature = "rustls", feature = "openssl"))]
|
||||
#[ntex::test]
|
||||
async fn test_reading_deflate_encoding_large_random_rustls_h1() {
|
||||
|
@ -967,8 +963,6 @@ async fn test_reading_deflate_encoding_large_random_rustls_h1() {
|
|||
assert_eq!(bytes, Bytes::from(data));
|
||||
}
|
||||
|
||||
// TODO fix
|
||||
#[ignore]
|
||||
#[cfg(all(feature = "rustls", feature = "openssl"))]
|
||||
#[ntex::test]
|
||||
async fn test_reading_deflate_encoding_large_random_rustls_h2() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue