impl rustls acceptor; update filter trait

This commit is contained in:
Nikolay Kim 2021-12-19 01:43:43 +06:00
parent d7083c15d8
commit 1af728eb01
30 changed files with 1184 additions and 306 deletions

9
ntex-io/CHANGES.md Normal file
View 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

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;

View file

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

View file

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

View file

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

View file

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

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

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

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

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

View file

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

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

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.0"
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-----
MIIJKQIBAAKCAgEAryUL1k7npaMOck9OO+EjzeL0FoysOP5JrgRh+8BoPY7WPyL5
6oFPaCYKp2YMucmvFh/VZSyupC75JJNIaW0fvcIe4Euzy2Ex0VukPxYteRicaWRs
xSIdo5RNNHd7JOf3ZWIMqkxmDhPNnqSGHcnVs/14+I5IbJCoba+KNElmL9CrL3gQ
kqNYJf2FSIgou5j1OthEdnQpiRxSRLmJ7gXtvpFGgj4AnrHGsMAPHueeop6yOX6e
gFnw2cwp98c/0tMOUsXnDU1MTGF11+4UVr043SruZKU7bvhMZRcf4NTR2MNin0b3
DYJ+JbTn+HgPhhhx3mrsWRyCvfP23jzwnV/222o+U46i7tNYYrDN8vXIM17gtIvK
rv2FCLTJE6tsp0xAi6dT+J+AIVqkJntrsxqx2CuOYGOOkPPc4rSf64bwOR1mikdv
ZCnVNwGEXcH3nBRFMlk5bByCW0kUy03QNakiUEF+PoFzLrCL+V+21Q6Fd7Jmw06B
zVFV2YtsqFcSo7HXW91XJTDVJCPnrMJOooKQ9Fbq4zbQM0Lv02LyJWyR+0PMBzy4
FfkWZWz10g3w+CITL/MQ65fsBBc9hRHC3QBWetj3puqM8DlPwqPhgmCA5zo8AWx7
CogRV66ukkeBYXYFHwV5uDJTX91tbwYesOL43rlDT905aV0VbaAyDZflipMCAwEA
AQKCAgBoOnqt4a0XNE8PlcRv/A6Loskxdiuzixib133cDOe74nn7frwNY0C3MRRc
BG4ETlLErtMWb53KlS2tJ30LSGaATbqELmjj2oaEGa5H4NHU4+GJErtsIV5UD5hW
ZdhB4U2n5s60tdxx+jT+eNhbd9aWU3yfJkVRXlDtXW64qQmH4P1OtXvfWBfIG/Qq
cuUSpvchOrybZYumTdVjkqrTnHGcW+YC8hT6W79rRhB5issr6ZcUghafOWcMpeQ/
0TJZK0K13ZIfp2WFeuZfRw6Rg/AIJllSScZxxo/oBPfym5P6FGRndxrkzkh19g+q
HQDYA0oYW7clXMMtebbrEIb8kLRdaIHDiwyFXmyywvuAAk0jHbA8snM2dyeJWSRr
WQjvQFccGF4z390ZGUCN0ZeESskndg12r4jYaL/aQ8dQZ1ivS69F8bmbQtQNU2Ej
hscTUzEMOnrBTxvRQTjI9nnrbsbklagKmJHXOc/fj13g6/FkcfmeTrjuB30LxJyH
j+xXAi8AGv/oZRk6s/txas5hXpcFXnQDRobVoJjV8kuomcDTt1j33H+05ACFyvHM
/2jxJ1f3xbFx3fqivL89+Z4r8RYxLoWLg7QuqQLdtRgThEKUG0t3lt59fUo+JVVJ
CgRbj/OM3n5udgiIeBAyMAMZjVPUKhvLIFpiUY2vKnYx/97L0QKCAQEA4QUt3dEh
P0L4eQEAzg/J8JuleH7io5VxoK5c2oulhCdQdRDF5HWSesPKJmCmgJRmIXi7zseo
Sbg7Hd2xt/QnaPhRnASXJOdn7ddtoZ1M6Zb0y+d6mmcG+mK6PshtMCQ5S3Lqhsuh
tYQbwawNlCFzwzCzwGb3aD9lBKQYts7KFrMT3Goexg3Qqv374XGn6Eg1LMhXWYbT
M5gcPOYnOT+RugeaTxMnJ6nr6E7kyrLIS+xASXKwXGxSUsQG9VWH7jDuzzARrPEU
aeyxWdbDkBn2vzW+wDpMPMqzoShZsRC9NnFfncXRZfUC5DJWGzwA/xZaR0ZNNng2
OE7rILyAH/aZSQKCAQEAx0ICGi7y94vn5KWdaNVol3nPid4aMnk4LDcX5m0tiqUG
7LIqnFDOOjEdxTf13n7Cv4gotOQNluOypswSDZI4tI0xQ/dJ8PI+vwmA0oHSzf7U
ZPO2gzIOzububPllQsCrKHN++2SyyNlKyYFu/akmlu6yIN3EMRLqYKvZaIL5z9Lk
pTU7eS0AsXJyqD54zRLFkw6S9omQHJXrEzYAuZI+Ue/Arlgyq95mUMsHYRHgaTq4
GDMDLHNyrdKUhW+ZiZ9dhX+aRghHgNiXDk/Eh2/RZrLhKdVk94dJQbfGu/aiSk71
dXPEAaQ7o1MDwQgu4TsCVCzac/CeqvmcoMFyx3NA+wKCAQEAoLfLR8hsH7wcroiZ
45QBXzo8WLD//WjrDKIdLfdaE+bkn4iIX6HeKpMXGowjwGi9/aA3O/z85RKSHsXO
fp4DXAUofPAGaFRjtcwNwMYSPjEUzWKa/hciM8o6TkdnPWBSD+KXQgnFiVk/Xfge
hrPR9BMgAAdLJIlLBKKUCFXwn3/uaprdOgZ6CPd5ZU+BZvXUDRVW1lnnFc3KNXEJ
iOkvk5iEjYAXkkvadEWNQn2pdBjc3djtwEWaEwVyFt6tROJsX01tAoH6W6G0Fn+/
lHgG9hFUGgZJl44L+MpSLZbQHkehzJWS92ilVQni2HbmG0wC1S+QTJxV1agAZpRc
SvgeCQKCAQB3PnVrnfUhV8Sq/MG63xv8qpUc+KHM2uZW75GKAIRkmGYQeH8vlNwV
zxb104t8X3fEj4Ns3Z2UUyey0iVrobn1sxlshyzk2NPcF5/UWoUBaiNJVuA+m1Jp
V6IP7SBAVnUXfCbd42Fq+T7cYG0/uF6zrJ1FNfIXPC6vM6ij9t3xFVBn3fd9iQUF
LGyZaul4MGe0neAtUh3APae0k3jTlUVeW5B/xaBtYmbwqs/7s2sNDmrlcIHRtDVI
+OCRCjxkM88P+VEl4AaKgRPFKM+ADdbPEvXUxzPpPjkE7yorimmM9rvGUkVWhiZ6
k0+H0ZHckCfQoBcLk1AhGcg2HA7IdZzJAoIBAQDAicb6CWlNdaIcJfADKSNK4+BF
JFbH+lXYrTxVSTV+Ubdi0w8Kwk0bzf20EstJnaOCyLDCjcxafjbmuGBVbw7an0lt
Yxjx0fWXxMfvb9/3vKuJVUySA4iq/zfXKlokRaFoqbdRfod3PVGUsynCV7HmImf3
RZA0WkcSwzbg2E2QNKQ3CPd3cHtPpBX8TwRCotg/R5yCR9lihVfkSyULikwBFvrm
2UKZm4pPESWSfMHBToJoAeO0g67itbwwpNhwvgUdyjaj8u46qyjN1FMx3mBiv7Yq
CIE+H0qNu0jmFhoqPrgxfFrGCi6eDPYjRS86536Nc4m8y24z2hie8JLK8QKQ
-----END RSA PRIVATE KEY-----

View file

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

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