Merge pull request #73 from ntex-rs/rustls-impl

Add rustls filter
This commit is contained in:
Nikolay Kim 2021-12-19 11:20:56 +06:00 committed by GitHub
commit a5d734fe47
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 1326 additions and 552 deletions

9
ntex-io/CHANGES.md Normal file
View file

@ -0,0 +1,9 @@
# Changes
## [0.1.0-b.1] - 2021-12-19
* Remove ReadFilter/WriteFilter traits.
## [0.1.0-b.0] - 2021-12-18
* Refactor ntex::framed to ntex-io

View file

@ -1,6 +1,6 @@
[package]
name = "ntex-io"
version = "0.1.0-b.0"
version = "0.1.0-b.1"
authors = ["ntex contributors <team@ntex.rs>"]
description = "Utilities for encoding and decoding frames"
keywords = ["network", "framework", "async", "futures"]

View file

@ -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;
@ -528,28 +527,28 @@ mod tests {
use ntex_util::time::{sleep, Millis};
use crate::testing::IoTest;
use crate::{state::Flags, state::IoStateInner, Io, IoStream, WriteRef};
use crate::{state::Flags, Io, IoRef, IoStream, WriteRef};
use super::*;
pub(crate) struct State(Rc<IoStateInner>);
pub(crate) struct State(IoRef);
impl State {
fn flags(&self) -> Flags {
self.0.flags.get()
self.0.flags()
}
fn write(&'_ self) -> WriteRef<'_> {
WriteRef(self.0.as_ref())
WriteRef(&self.0)
}
fn close(&self) {
self.0.insert_flags(Flags::DSP_STOP);
self.0.dispatch_task.wake();
self.0 .0.insert_flags(Flags::DSP_STOP);
self.0 .0.dispatch_task.wake();
}
fn set_memory_pool(&self, pool: PoolRef) {
self.0.pool.set(pool);
self.0 .0.pool.set(pool);
}
}
@ -573,7 +572,7 @@ mod tests {
error: Cell::new(None),
inflight: Cell::new(0),
});
let inner = State(state.0 .0.clone());
let inner = State(state.get_ref());
let expire = ka_updated + Duration::from_millis(500);
timer.register(expire, expire, &state);
@ -873,7 +872,7 @@ mod tests {
.keepalive_timeout(Seconds(1))
.await;
});
state.0.disconnect_timeout.set(Millis::ONE_SEC);
state.0 .0.disconnect_timeout.set(Millis::ONE_SEC);
let buf = client.read().await.unwrap();
assert_eq!(buf, Bytes::from_static(b"GET /test HTTP/1\r\n\r\n"));

View file

@ -1,14 +1,14 @@
use std::{any, io, rc::Rc, task::Context, task::Poll};
use std::{any, io, task::Context, task::Poll};
use ntex_bytes::BytesMut;
use super::state::{Flags, IoRef, IoStateInner};
use super::{Filter, ReadFilter, WriteFilter, WriteReadiness};
use super::state::{Flags, IoRef};
use super::{Filter, WriteReadiness};
pub struct DefaultFilter(Rc<IoStateInner>);
pub struct DefaultFilter(IoRef);
impl DefaultFilter {
pub(crate) fn new(inner: Rc<IoStateInner>) -> Self {
pub(crate) fn new(inner: IoRef) -> Self {
DefaultFilter(inner)
}
}
@ -16,64 +16,95 @@ impl DefaultFilter {
impl Filter for DefaultFilter {
#[inline]
fn shutdown(&self, _: &IoRef) -> Poll<Result<(), io::Error>> {
let mut flags = self.0.flags.get();
let mut flags = self.0.flags();
if !flags.intersects(Flags::IO_ERR | Flags::IO_SHUTDOWN) {
flags.insert(Flags::IO_SHUTDOWN);
self.0.flags.set(flags);
self.0.read_task.wake();
self.0.write_task.wake();
self.0.set_flags(flags);
self.0 .0.read_task.wake();
self.0 .0.write_task.wake();
}
Poll::Ready(Ok(()))
}
#[inline]
fn closed(&self, err: Option<io::Error>) {
self.0 .0.set_error(err);
self.0 .0.handle.take();
self.0 .0.insert_flags(Flags::IO_CLOSED);
self.0 .0.dispatch_task.wake();
}
#[inline]
fn query(&self, id: any::TypeId) -> Option<Box<dyn any::Any>> {
if let Some(hnd) = self.0.handle.take() {
if let Some(hnd) = self.0 .0.handle.take() {
let res = hnd.query(id);
self.0.handle.set(Some(hnd));
self.0 .0.handle.set(Some(hnd));
res
} else {
None
}
}
}
impl ReadFilter for DefaultFilter {
#[inline]
fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
let flags = self.0.flags.get();
let flags = self.0.flags();
if flags.intersects(Flags::IO_ERR | Flags::IO_SHUTDOWN) {
Poll::Ready(Err(()))
} else if flags.intersects(Flags::RD_PAUSED) {
self.0.read_task.register(cx.waker());
self.0 .0.read_task.register(cx.waker());
Poll::Pending
} else {
self.0.read_task.register(cx.waker());
self.0 .0.read_task.register(cx.waker());
Poll::Ready(Ok(()))
}
}
#[inline]
fn read_closed(&self, err: Option<io::Error>) {
self.0.set_error(err);
fn poll_write_ready(
&self,
cx: &mut Context<'_>,
) -> Poll<Result<(), WriteReadiness>> {
let mut flags = self.0.flags();
if flags.contains(Flags::IO_ERR) {
Poll::Ready(Err(WriteReadiness::Terminate))
} else if flags.intersects(Flags::IO_SHUTDOWN) {
Poll::Ready(Err(WriteReadiness::Shutdown(
self.0 .0.disconnect_timeout.get(),
)))
} else if flags.contains(Flags::IO_FILTERS)
&& !flags.contains(Flags::IO_FILTERS_TO)
{
flags.insert(Flags::IO_FILTERS_TO);
self.0.set_flags(flags);
self.0 .0.write_task.register(cx.waker());
Poll::Ready(Err(WriteReadiness::Timeout(
self.0 .0.disconnect_timeout.get(),
)))
} else {
self.0 .0.write_task.register(cx.waker());
Poll::Ready(Ok(()))
}
}
#[inline]
fn get_read_buf(&self) -> Option<BytesMut> {
self.0.read_buf.take()
self.0 .0.read_buf.take()
}
#[inline]
fn release_read_buf(
&self,
buf: BytesMut,
new_bytes: usize,
) -> Result<(), io::Error> {
let mut flags = self.0.flags.get();
fn get_write_buf(&self) -> Option<BytesMut> {
self.0 .0.write_buf.take()
}
if new_bytes > 0 {
if buf.len() > self.0.pool.get().read_params().high as usize {
#[inline]
fn release_read_buf(&self, buf: BytesMut, nbytes: usize) -> Result<(), io::Error> {
let mut flags = self.0.flags();
if nbytes > 0 {
if buf.len() > self.0.memory_pool().read_params().high as usize {
log::trace!(
"buffer is too large {}, enable read back-pressure",
buf.len()
@ -82,64 +113,21 @@ impl ReadFilter for DefaultFilter {
} else {
flags.insert(Flags::RD_READY);
}
self.0.flags.set(flags);
self.0.set_flags(flags);
}
self.0.read_buf.set(Some(buf));
self.0 .0.read_buf.set(Some(buf));
Ok(())
}
}
impl WriteFilter for DefaultFilter {
#[inline]
fn poll_write_ready(
&self,
cx: &mut Context<'_>,
) -> Poll<Result<(), WriteReadiness>> {
let mut flags = self.0.flags.get();
if flags.contains(Flags::IO_ERR) {
Poll::Ready(Err(WriteReadiness::Terminate))
} else if flags.intersects(Flags::IO_SHUTDOWN) {
Poll::Ready(Err(WriteReadiness::Shutdown(
self.0.disconnect_timeout.get(),
)))
} else if flags.contains(Flags::IO_FILTERS)
&& !flags.contains(Flags::IO_FILTERS_TO)
{
flags.insert(Flags::IO_FILTERS_TO);
self.0.flags.set(flags);
self.0.write_task.register(cx.waker());
Poll::Ready(Err(WriteReadiness::Timeout(
self.0.disconnect_timeout.get(),
)))
} else {
self.0.write_task.register(cx.waker());
Poll::Ready(Ok(()))
}
}
#[inline]
fn write_closed(&self, err: Option<io::Error>) {
self.0.set_error(err);
self.0.handle.take();
self.0.insert_flags(Flags::IO_CLOSED);
self.0.dispatch_task.wake();
}
#[inline]
fn get_write_buf(&self) -> Option<BytesMut> {
self.0.write_buf.take()
}
#[inline]
fn release_write_buf(&self, buf: BytesMut) -> Result<(), io::Error> {
let pool = self.0.pool.get();
let pool = self.0.memory_pool();
if buf.is_empty() {
pool.release_write_buf(buf);
} else {
self.0.write_buf.set(Some(buf));
self.0.write_task.wake();
self.0 .0.write_buf.set(Some(buf));
self.0 .0.write_task.wake();
}
Ok(())
}
@ -160,37 +148,31 @@ impl Filter for NullFilter {
Poll::Ready(Ok(()))
}
fn closed(&self, _: Option<io::Error>) {}
fn query(&self, _: any::TypeId) -> Option<Box<dyn any::Any>> {
None
}
}
impl ReadFilter for NullFilter {
fn poll_read_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), ()>> {
Poll::Ready(Err(()))
}
fn read_closed(&self, _: Option<io::Error>) {}
fn poll_write_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), WriteReadiness>> {
Poll::Ready(Err(WriteReadiness::Terminate))
}
fn get_read_buf(&self) -> Option<BytesMut> {
None
}
fn get_write_buf(&self) -> Option<BytesMut> {
None
}
fn release_read_buf(&self, _: BytesMut, _: usize) -> Result<(), io::Error> {
Ok(())
}
}
impl WriteFilter for NullFilter {
fn poll_write_ready(&self, _: &mut Context<'_>) -> Poll<Result<(), WriteReadiness>> {
Poll::Ready(Err(WriteReadiness::Terminate))
}
fn write_closed(&self, _: Option<io::Error>) {}
fn get_write_buf(&self) -> Option<BytesMut> {
None
}
fn release_write_buf(&self, _: BytesMut) -> Result<(), io::Error> {
Ok(())

View file

@ -36,34 +36,27 @@ pub enum WriteReadiness {
Terminate,
}
pub trait ReadFilter {
pub trait Filter: 'static {
fn shutdown(&self, st: &IoRef) -> Poll<Result<(), io::Error>>;
fn closed(&self, err: Option<io::Error>);
fn query(&self, id: TypeId) -> Option<Box<dyn Any>>;
fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), ()>>;
fn read_closed(&self, err: Option<io::Error>);
fn get_read_buf(&self) -> Option<BytesMut>;
fn release_read_buf(&self, buf: BytesMut, new_bytes: usize)
-> Result<(), io::Error>;
}
pub trait WriteFilter {
fn poll_write_ready(&self, cx: &mut Context<'_>)
-> Poll<Result<(), WriteReadiness>>;
fn write_closed(&self, err: Option<io::Error>);
fn get_read_buf(&self) -> Option<BytesMut>;
fn get_write_buf(&self) -> Option<BytesMut>;
fn release_read_buf(&self, buf: BytesMut, nbytes: usize) -> Result<(), io::Error>;
fn release_write_buf(&self, buf: BytesMut) -> Result<(), io::Error>;
}
pub trait Filter: ReadFilter + WriteFilter + 'static {
fn shutdown(&self, st: &IoRef) -> Poll<Result<(), io::Error>>;
fn query(&self, id: TypeId) -> Option<Box<dyn Any>>;
}
pub trait FilterFactory<F: Filter>: Sized {
type Filter: Filter;

View file

@ -65,7 +65,7 @@ pub(crate) struct IoStateInner {
pub(super) dispatch_task: LocalWaker,
pub(super) read_buf: Cell<Option<BytesMut>>,
pub(super) write_buf: Cell<Option<BytesMut>>,
pub(super) filter: Cell<&'static dyn Filter>,
filter: Cell<&'static dyn Filter>,
pub(super) handle: Cell<Option<Box<dyn Handle>>>,
on_disconnect: RefCell<Vec<Option<LocalWaker>>>,
}
@ -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();
@ -203,7 +225,7 @@ impl Io {
on_disconnect: RefCell::new(Vec::new()),
});
let filter = Box::new(DefaultFilter::new(inner.clone()));
let filter = Box::new(DefaultFilter::new(IoRef(inner.clone())));
let filter_ref: &'static dyn Filter = unsafe {
let filter: &dyn Filter = filter.as_ref();
std::mem::transmute(filter)
@ -271,6 +293,18 @@ impl IoRef {
self.0.flags.get()
}
#[inline]
/// Set flags
pub(crate) fn set_flags(&self, flags: Flags) {
self.0.flags.set(flags)
}
#[inline]
/// Get memory pool
pub(crate) fn filter(&self) -> &dyn Filter {
self.0.filter.get()
}
#[inline]
/// Get memory pool
pub fn memory_pool(&self) -> PoolRef {
@ -328,13 +362,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]
@ -367,7 +401,7 @@ impl IoRef {
#[inline]
/// Query specific data
pub fn query<T: 'static>(&self) -> types::QueryItem<T> {
if let Some(item) = self.0.filter.get().query(any::TypeId::of::<T>()) {
if let Some(item) = self.filter().query(any::TypeId::of::<T>()) {
types::QueryItem::new(item)
} else {
types::QueryItem::empty()
@ -398,10 +432,10 @@ impl IoRef {
where
U: Encoder,
{
let filter = self.0.filter.get();
let filter = self.filter();
let mut buf = filter
.get_write_buf()
.unwrap_or_else(|| self.0.pool.get().get_write_buf());
.unwrap_or_else(|| self.memory_pool().get_write_buf());
let is_write_sleep = buf.is_empty();
codec.encode(item, &mut buf).map_err(Either::Left)?;
@ -425,7 +459,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 +499,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 +554,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 +625,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.memory_pool().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 +650,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 +659,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,12 +671,12 @@ impl<'a> WriteRef<'a> {
where
F: FnOnce(&mut BytesMut) -> R,
{
let filter = self.0.filter.get();
let filter = self.0.filter();
let mut buf = filter
.get_write_buf()
.unwrap_or_else(|| self.0.pool.get().get_write_buf());
.unwrap_or_else(|| self.0.memory_pool().get_write_buf());
if buf.is_empty() {
self.0.write_task.wake();
self.0 .0.write_task.wake();
}
let result = f(&mut buf);
@ -681,15 +696,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.filter();
let mut buf = filter
.get_write_buf()
.unwrap_or_else(|| self.0.pool.get().get_write_buf());
.unwrap_or_else(|| self.0.memory_pool().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.memory_pool().write_params().unpack();
// make sure we've got room
let remaining = buf.capacity() - buf.len();
@ -700,12 +715,12 @@ 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));
self.0 .0.set_error(Some(err));
}
result
} else {
@ -718,24 +733,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.filter();
let mut buf = filter
.get_write_buf()
.unwrap_or_else(|| self.0.pool.get().get_write_buf());
.unwrap_or_else(|| self.0.memory_pool().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.memory_pool().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 +770,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.memory_pool().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 +808,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.memory_pool().read_params_high();
self.0 .0.read_buf.set(Some(buf));
result
} else {
false
@ -817,17 +841,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 +870,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 +886,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.memory_pool().get_read_buf());
let res = f(&mut buf);
if buf.is_empty() {
self.0.pool.get().release_read_buf(buf);
self.0.memory_pool().release_read_buf(buf);
} else {
self.0.read_buf.set(Some(buf));
self.0 .0.read_buf.set(Some(buf));
}
res
}
@ -883,23 +908,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(())
}
}
@ -982,7 +1007,7 @@ mod tests {
use super::*;
use crate::testing::IoTest;
use crate::{Filter, FilterFactory, ReadFilter, WriteFilter, WriteReadiness};
use crate::{Filter, FilterFactory, WriteReadiness};
const BIN: &[u8] = b"GET /test HTTP/1\r\n\r\n";
const TEXT: &str = "GET /test HTTP/1\r\n\r\n";
@ -1091,7 +1116,7 @@ mod tests {
in_bytes: Rc<Cell<usize>>,
out_bytes: Rc<Cell<usize>>,
}
impl<F: ReadFilter + WriteFilter + 'static> Filter for Counter<F> {
impl<F: Filter> Filter for Counter<F> {
fn shutdown(&self, _: &IoRef) -> Poll<Result<(), io::Error>> {
Poll::Ready(Ok(()))
}
@ -1099,15 +1124,13 @@ mod tests {
fn query(&self, _: std::any::TypeId) -> Option<Box<dyn std::any::Any>> {
None
}
}
impl<F: ReadFilter> ReadFilter for Counter<F> {
fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
self.inner.poll_read_ready(cx)
}
fn read_closed(&self, err: Option<io::Error>) {
self.inner.read_closed(err)
fn closed(&self, err: Option<io::Error>) {
self.inner.closed(err)
}
fn get_read_buf(&self) -> Option<BytesMut> {
@ -1122,9 +1145,7 @@ mod tests {
self.in_bytes.set(self.in_bytes.get() + new_bytes);
self.inner.release_read_buf(buf, new_bytes)
}
}
impl<F: WriteFilter> WriteFilter for Counter<F> {
fn poll_write_ready(
&self,
cx: &mut Context<'_>,
@ -1132,10 +1153,6 @@ mod tests {
self.inner.poll_write_ready(cx)
}
fn write_closed(&self, err: Option<io::Error>) {
self.inner.write_closed(err)
}
fn get_write_buf(&self) -> Option<BytesMut> {
if let Some(buf) = self.inner.get_write_buf() {
self.out_bytes.set(self.out_bytes.get() - buf.len());
@ -1163,8 +1180,8 @@ mod tests {
let in_bytes = self.0.clone();
let out_bytes = self.1.clone();
Ready::Ok(
io.map_filter::<CounterFactory, _>(|inner| {
Ok(Counter {
io.map_filter(|inner| {
Ok::<_, ()>(Counter {
inner,
in_bytes,
out_bytes,

View file

@ -9,27 +9,25 @@ pub struct ReadContext(pub(super) IoRef);
impl ReadContext {
#[inline]
pub fn memory_pool(&self) -> PoolRef {
self.0 .0.pool.get()
self.0.memory_pool()
}
#[inline]
pub fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
self.0 .0.filter.get().poll_read_ready(cx)
self.0.filter().poll_read_ready(cx)
}
#[inline]
pub fn close(&self, err: Option<io::Error>) {
self.0 .0.filter.get().read_closed(err);
self.0.filter().closed(err);
}
#[inline]
pub fn get_read_buf(&self) -> BytesMut {
self.0
.0
.filter
.get()
.filter()
.get_read_buf()
.unwrap_or_else(|| self.0 .0.pool.get().get_read_buf())
.unwrap_or_else(|| self.0.memory_pool().get_read_buf())
}
#[inline]
@ -39,17 +37,17 @@ impl ReadContext {
new_bytes: usize,
) -> Result<(), io::Error> {
if buf.is_empty() {
self.0 .0.pool.get().release_read_buf(buf);
self.0.memory_pool().release_read_buf(buf);
Ok(())
} else {
let mut flags = self.0 .0.flags.get();
let mut flags = self.0.flags();
if new_bytes > 0 {
flags.insert(Flags::RD_READY);
self.0 .0.flags.set(flags);
self.0.set_flags(flags);
self.0 .0.dispatch_task.wake();
}
self.0 .0.filter.get().release_read_buf(buf, new_bytes)?;
self.0.filter().release_read_buf(buf, new_bytes)?;
if flags.contains(Flags::IO_FILTERS) {
self.0 .0.shutdown_filters(&self.0)?;
@ -64,17 +62,17 @@ pub struct WriteContext(pub(super) IoRef);
impl WriteContext {
#[inline]
pub fn memory_pool(&self) -> PoolRef {
self.0 .0.pool.get()
self.0.memory_pool()
}
#[inline]
pub fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), WriteReadiness>> {
self.0 .0.filter.get().poll_write_ready(cx)
self.0.filter().poll_write_ready(cx)
}
#[inline]
pub fn close(&self, err: Option<io::Error>) {
self.0 .0.filter.get().write_closed(err)
self.0.filter().closed(err)
}
#[inline]
@ -84,14 +82,14 @@ impl WriteContext {
#[inline]
pub fn release_write_buf(&self, buf: BytesMut) -> Result<(), io::Error> {
let pool = self.0 .0.pool.get();
let mut flags = self.0 .0.flags.get();
let pool = self.0.memory_pool();
let mut flags = self.0.flags();
if buf.is_empty() {
pool.release_write_buf(buf);
if flags.intersects(Flags::WR_WAIT | Flags::WR_BACKPRESSURE) {
flags.remove(Flags::WR_WAIT | Flags::WR_BACKPRESSURE);
self.0 .0.flags.set(flags);
self.0.set_flags(flags);
self.0 .0.dispatch_task.wake();
}
} else {
@ -100,7 +98,7 @@ impl WriteContext {
&& buf.len() < pool.write_params_high() << 1
{
flags.remove(Flags::WR_BACKPRESSURE);
self.0 .0.flags.set(flags);
self.0.set_flags(flags);
self.0 .0.dispatch_task.wake();
}
self.0 .0.write_buf.set(Some(buf))

View file

@ -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));
}

View file

@ -23,7 +23,7 @@ tokio = ["tok-io", "ntex-io/tokio"]
[dependencies]
ntex-bytes = "0.1.8"
ntex-io = "0.1.0-b.0"
ntex-io = "0.1.0-b.1"
ntex-util = "0.1.3"
async-oneshot = "0.5.0"
async-channel = "1.6.1"

5
ntex-tls/CHANGES.md Normal file
View file

@ -0,0 +1,5 @@
# Changes
## [0.1.0-b.0] - 2021-12-19
* Initial impl

View file

@ -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" }

View file

@ -1,16 +1,31 @@
-----BEGIN CERTIFICATE-----
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
Ing=
-----END CERTIFICATE-----

View file

@ -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-----

View 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
}

View file

@ -6,9 +6,7 @@ use std::{
};
use ntex_bytes::{BufMut, BytesMut, PoolRef};
use ntex_io::{
Filter, FilterFactory, Io, IoRef, ReadFilter, WriteFilter, WriteReadiness,
};
use ntex_io::{Filter, FilterFactory, Io, IoRef, WriteReadiness};
use ntex_util::{future::poll_fn, time, time::Millis};
use tls_openssl::ssl::{self, SslStream};
@ -49,7 +47,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)
@ -103,17 +101,26 @@ impl<F: Filter> Filter for SslFilter<F> {
self.inner.borrow().get_ref().inner.query(id)
}
}
}
impl<F: Filter> ReadFilter for SslFilter<F> {
#[inline]
fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
self.inner.borrow().get_ref().inner.poll_read_ready(cx)
}
fn read_closed(&self, err: Option<io::Error>) {
self.inner.borrow().get_ref().inner.read_closed(err)
#[inline]
fn poll_write_ready(
&self,
cx: &mut Context<'_>,
) -> Poll<Result<(), WriteReadiness>> {
self.inner.borrow().get_ref().inner.poll_write_ready(cx)
}
#[inline]
fn closed(&self, err: Option<io::Error>) {
self.inner.borrow().get_ref().inner.closed(err)
}
#[inline]
fn get_read_buf(&self) -> Option<BytesMut> {
if let Some(buf) = self.inner.borrow_mut().get_mut().read_buf.take() {
if !buf.is_empty() {
@ -123,18 +130,24 @@ impl<F: Filter> ReadFilter for SslFilter<F> {
None
}
fn release_read_buf(
&self,
src: BytesMut,
new_bytes: usize,
) -> Result<(), io::Error> {
#[inline]
fn get_write_buf(&self) -> Option<BytesMut> {
if let Some(buf) = self.inner.borrow_mut().get_mut().write_buf.take() {
if !buf.is_empty() {
return Some(buf);
}
}
None
}
fn release_read_buf(&self, src: BytesMut, nbytes: usize) -> Result<(), io::Error> {
// store to read_buf
let pool = {
let mut inner = self.inner.borrow_mut();
inner.get_mut().read_buf = Some(src);
inner.get_ref().pool
};
if new_bytes == 0 {
if nbytes == 0 {
return Ok(());
}
let (hw, lw) = pool.read_params().unpack();
@ -171,35 +184,12 @@ 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)),
};
}
}
}
impl<F: Filter> WriteFilter for SslFilter<F> {
fn poll_write_ready(
&self,
cx: &mut Context<'_>,
) -> Poll<Result<(), WriteReadiness>> {
self.inner.borrow().get_ref().inner.poll_write_ready(cx)
}
fn write_closed(&self, err: Option<io::Error>) {
self.inner.borrow().get_ref().inner.read_closed(err)
}
fn get_write_buf(&self) -> Option<BytesMut> {
if let Some(buf) = self.inner.borrow_mut().get_mut().write_buf.take() {
if !buf.is_empty() {
return Some(buf);
}
}
None
}
fn release_write_buf(&self, mut buf: BytesMut) -> Result<(), io::Error> {
let ssl_result = self.inner.borrow_mut().ssl_write(&buf);
@ -213,7 +203,7 @@ impl<F: Filter> WriteFilter for SslFilter<F> {
}
Err(e) => match e.code() {
ssl::ErrorCode::WANT_READ | ssl::ErrorCode::WANT_WRITE => Ok(()),
_ => (Err(map_to_ioerr(e))),
_ => Err(map_to_ioerr(e)),
},
};
result
@ -266,7 +256,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 +265,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 +307,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 +316,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),
})
})?;

View file

@ -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)

View file

@ -0,0 +1,301 @@
//! 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, 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> {
#[inline]
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)
}
}
#[inline]
fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
self.inner.borrow().inner.poll_read_ready(cx)
}
#[inline]
fn poll_write_ready(
&self,
cx: &mut Context<'_>,
) -> Poll<Result<(), WriteReadiness>> {
self.inner.borrow().inner.poll_write_ready(cx)
}
#[inline]
fn closed(&self, err: Option<io::Error>) {
self.inner.borrow().inner.closed(err)
}
#[inline]
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
}
#[inline]
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_read_buf(&self, mut src: BytesMut, _nb: usize) -> Result<(), io::Error> {
let mut session = self.session.borrow_mut();
if session.is_handshaking() {
self.inner.borrow_mut().read_buf = Some(src);
Ok(())
} else {
if src.is_empty() {
return Ok(());
}
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)
}
}
fn release_write_buf(&self, mut src: BytesMut) -> Result<(), 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(())
}
}
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),
}
}
}
}

View file

@ -1,77 +1,130 @@
#![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_io::{
Filter, FilterFactory, Io, IoRef, ReadFilter, WriteFilter, WriteReadiness,
};
use ntex_util::{future::Ready, time::Millis};
use ntex_bytes::BytesMut;
use ntex_io::{Filter, FilterFactory, Io, IoRef, WriteReadiness};
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> {
#[inline]
fn closed(&self, err: Option<io::Error>) {
match self.inner {
InnerTlsFilter::Server(ref f) => f.closed(err),
InnerTlsFilter::Client(ref f) => f.closed(err),
}
}
#[inline]
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)
}
fn get_read_buf(&self) -> Option<BytesMut> {
self.inner.get_read_buf()
}
fn release_read_buf(
&self,
src: BytesMut,
new_bytes: usize,
) -> Result<(), io::Error> {
self.inner.release_read_buf(src, new_bytes)
}
}
impl<F: Filter> WriteFilter for TlsFilter<F> {
#[inline]
fn poll_write_ready(
&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)
#[inline]
fn get_read_buf(&self) -> Option<BytesMut> {
match self.inner {
InnerTlsFilter::Server(ref f) => f.get_read_buf(),
InnerTlsFilter::Client(ref f) => f.get_read_buf(),
}
}
#[inline]
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)
#[inline]
fn release_read_buf(&self, src: BytesMut, nb: usize) -> Result<(), 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),
}
}
#[inline]
fn release_write_buf(&self, src: BytesMut) -> Result<(), 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 +135,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 +151,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 +169,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 +186,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 +207,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 })
}
}

View file

@ -0,0 +1,305 @@
//! 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, WriteReadiness};
use ntex_util::{future::poll_fn, time, time::Millis};
use tls_rust::{ServerConfig, ServerConnection};
use crate::{rustls::TlsFilter, 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> {
#[inline]
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)
}
}
#[inline]
fn closed(&self, err: Option<io::Error>) {
self.inner.borrow().inner.closed(err)
}
#[inline]
fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
self.inner.borrow().inner.poll_read_ready(cx)
}
#[inline]
fn poll_write_ready(
&self,
cx: &mut Context<'_>,
) -> Poll<Result<(), WriteReadiness>> {
self.inner.borrow().inner.poll_write_ready(cx)
}
#[inline]
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
}
#[inline]
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_read_buf(&self, mut src: BytesMut, _nb: usize) -> Result<(), io::Error> {
let mut session = self.session.borrow_mut();
if session.is_handshaking() {
self.inner.borrow_mut().read_buf = Some(src);
Ok(())
} else {
if src.is_empty() {
return Ok(());
}
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)
}
}
fn release_write_buf(&self, mut src: BytesMut) -> Result<(), 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(())
}
}
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)
}
}

View file

@ -230,10 +230,10 @@ impl<T> SendError<T> {
#[cfg(test)]
mod tests {
use super::*;
use crate::{util::lazy, util::next, Stream};
use crate::{future::lazy, future::next, Stream};
use futures_sink::Sink;
#[crate::rt_test]
#[ntex_macros::rt_test2]
async fn test_mpsc() {
let (tx, mut rx) = channel();
assert!(format!("{:?}", tx).contains("Sender"));
@ -282,7 +282,7 @@ mod tests {
assert_eq!(err.into_inner(), "test");
}
#[crate::rt_test]
#[ntex_macros::rt_test2]
async fn test_sink() {
let (mut tx, mut rx) = channel();
lazy(|cx| {
@ -296,7 +296,7 @@ mod tests {
assert_eq!(next(&mut rx).await, None);
}
#[crate::rt_test]
#[ntex_macros::rt_test2]
async fn test_close() {
let (tx, rx) = channel::<()>();
assert!(!tx.is_closed());

View file

@ -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.1"
ntex-rt = { version = "0.4.0-b.0", default-features = false, features = ["tokio"] }
base64 = "0.13"

View file

@ -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) => {

View file

@ -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),
)
}

View file

@ -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()) })
}),

View file

@ -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))

View file

@ -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))

View file

@ -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))

View file

@ -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;

View file

@ -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() {

View file

@ -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=
MIIFPjCCAyYCCQDWGwiaSniPcTANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJV
UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAlNGMRAwDgYDVQQKDAdDb21wYW55MQww
CgYDVQQLDANPcmcxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0yMTEyMTgx
NjMwNDlaFw0yMjEyMTgxNjMwNDlaMGExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJD
QTELMAkGA1UEBwwCU0YxEDAOBgNVBAoMB0NvbXBhbnkxDDAKBgNVBAsMA09yZzEY
MBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
MIICCgKCAgEAryUL1k7npaMOck9OO+EjzeL0FoysOP5JrgRh+8BoPY7WPyL56oFP
aCYKp2YMucmvFh/VZSyupC75JJNIaW0fvcIe4Euzy2Ex0VukPxYteRicaWRsxSId
o5RNNHd7JOf3ZWIMqkxmDhPNnqSGHcnVs/14+I5IbJCoba+KNElmL9CrL3gQkqNY
Jf2FSIgou5j1OthEdnQpiRxSRLmJ7gXtvpFGgj4AnrHGsMAPHueeop6yOX6egFnw
2cwp98c/0tMOUsXnDU1MTGF11+4UVr043SruZKU7bvhMZRcf4NTR2MNin0b3DYJ+
JbTn+HgPhhhx3mrsWRyCvfP23jzwnV/222o+U46i7tNYYrDN8vXIM17gtIvKrv2F
CLTJE6tsp0xAi6dT+J+AIVqkJntrsxqx2CuOYGOOkPPc4rSf64bwOR1mikdvZCnV
NwGEXcH3nBRFMlk5bByCW0kUy03QNakiUEF+PoFzLrCL+V+21Q6Fd7Jmw06BzVFV
2YtsqFcSo7HXW91XJTDVJCPnrMJOooKQ9Fbq4zbQM0Lv02LyJWyR+0PMBzy4FfkW
ZWz10g3w+CITL/MQ65fsBBc9hRHC3QBWetj3puqM8DlPwqPhgmCA5zo8AWx7CogR
V66ukkeBYXYFHwV5uDJTX91tbwYesOL43rlDT905aV0VbaAyDZflipMCAwEAATAN
BgkqhkiG9w0BAQsFAAOCAgEAWeq502+YKMHrk8YD4L2mzY/AHSEWf6XubMgkNRbh
s72+zJs2SrAzu+y+iv5La4JXOxrWEvZOUCKAK0sRG/+ESQxul5mbyPQLWFJgSqv5
O2RmhQ65l+O6RjPZbHPNJMTLMMlkFrKctgGIg5ysKHWPEZZ7ZlS3maxon+X75/b5
uI3BxBpJTWcg6zOxh0+zIxhesgEbRmaEz6qu3ZSktBeUQFpTElreCcbkntlFbr+9
SiKkaO4l6qEwRDhA595/7/JRZo4R5U1MifU6JhTMOyXTsH3BV1aVeS81/9jGPHl8
kgVxeKSpL/jDwuSJdr+dMxs/TJHV6fsnVewFFFmigLWThYGDnKmXqJQNyt8utRpe
6vvReWSSIece1EdBActy0rtjPaUJNTTdYk1UYo63OIbCguLWQD1XYN1qJg4KWJzB
PjS6KCOLmJvYrAxRMED4XeZ17+PxC3xr2IpAL+loRhZUuxXV4GhccGZ4z89OIdOU
x97x2BjjV5Nnnt6eBfF3vP5sOz31QpAS/8tzdlGD+6Xq2/i1ZKMPrwgs2dhTyah0
kCBfdE88Zew/A79z55IsVNiYJ4MrD8WTFjcM2j8SgI7tg+M+X/unj+wnzYT0L0dg
BEfzPd7zWdDOPInlTV9zUj1WOsLHX9odOh/Jj5X0FV5vZtcyQ0sGJAhdgTaXDvXs
Ing=
-----END CERTIFICATE-----

View file

@ -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);
}

View file

@ -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-----

View file

@ -142,15 +142,13 @@ async fn test_openssl() {
sys.stop();
}
// TODO! fix
#[ignore]
#[ntex::test]
#[cfg(all(feature = "rustls", feature = "openssl"))]
async fn test_rustls() {
use std::{fs::File, io::BufReader};
use ntex::web::HttpRequest;
use rustls_pemfile::{certs, pkcs8_private_keys};
use rustls_pemfile::{certs, rsa_private_keys};
use tls_rustls::{Certificate, PrivateKey, ServerConfig as RustlsServerConfig};
let addr = TestServer::unused_addr();
@ -167,7 +165,7 @@ async fn test_rustls() {
.iter()
.map(|c| Certificate(c.to_vec()))
.collect();
let keys = PrivateKey(pkcs8_private_keys(key_file).unwrap().remove(0));
let keys = PrivateKey(rsa_private_keys(key_file).unwrap().remove(0));
let config = RustlsServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()

View file

@ -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 rustls_pemfile::{certs, pkcs8_private_keys};
use std::fs::File;
use std::io::BufReader;
use std::{fs::File, io::BufReader};
use rustls_pemfile::{certs, rsa_private_keys};
use tls_rustls::{Certificate, PrivateKey, ServerConfig};
let data = rand::thread_rng()
@ -871,7 +869,7 @@ async fn test_reading_deflate_encoding_large_random_rustls() {
.iter()
.map(|c| Certificate(c.to_vec()))
.collect();
let keys = PrivateKey(pkcs8_private_keys(key_file).unwrap().remove(0));
let keys = PrivateKey(rsa_private_keys(key_file).unwrap().remove(0));
let config = ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()
@ -907,12 +905,10 @@ 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() {
use rustls_pemfile::{certs, pkcs8_private_keys};
use rustls_pemfile::{certs, rsa_private_keys};
use std::fs::File;
use std::io::BufReader;
use tls_rustls::{Certificate, PrivateKey, ServerConfig};
@ -931,7 +927,7 @@ async fn test_reading_deflate_encoding_large_random_rustls_h1() {
.iter()
.map(|c| Certificate(c.to_vec()))
.collect();
let keys = PrivateKey(pkcs8_private_keys(key_file).unwrap().remove(0));
let keys = PrivateKey(rsa_private_keys(key_file).unwrap().remove(0));
let config = ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()
@ -967,14 +963,12 @@ 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() {
use std::{fs::File, io::BufReader};
use rustls_pemfile::{certs, pkcs8_private_keys};
use rustls_pemfile::{certs, rsa_private_keys};
use tls_rustls::{Certificate, PrivateKey, ServerConfig};
let data = rand::thread_rng()
@ -991,7 +985,7 @@ async fn test_reading_deflate_encoding_large_random_rustls_h2() {
.iter()
.map(|c| Certificate(c.to_vec()))
.collect();
let keys = PrivateKey(pkcs8_private_keys(key_file).unwrap().remove(0));
let keys = PrivateKey(rsa_private_keys(key_file).unwrap().remove(0));
let config = ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()

View file

@ -1,19 +0,0 @@
-----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=
-----END CERTIFICATE-----

View file

@ -1,28 +0,0 @@
-----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-----