Refactor io buffers api (#169)

* Refactor io buffers api
This commit is contained in:
Nikolay Kim 2023-01-29 23:02:12 +06:00 committed by GitHub
parent 3b6cf6a3ef
commit 0f8387c3ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 573 additions and 553 deletions

View file

@ -31,7 +31,7 @@ impl fmt::Debug for BsDebug<'_> {
} else if (0x20..0x7f).contains(&c) { } else if (0x20..0x7f).contains(&c) {
write!(fmt, "{}", c as char)?; write!(fmt, "{}", c as char)?;
} else { } else {
write!(fmt, "\\x{:02x}", c)?; write!(fmt, "\\x{c:02x}")?;
} }
} }
write!(fmt, "\"")?; write!(fmt, "\"")?;

View file

@ -6,7 +6,7 @@ struct BytesRef<'a>(&'a [u8]);
impl<'a> LowerHex for BytesRef<'a> { impl<'a> LowerHex for BytesRef<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result { fn fmt(&self, f: &mut Formatter<'_>) -> Result {
for b in self.0 { for b in self.0 {
write!(f, "{:02x}", b)?; write!(f, "{b:02x}")?;
} }
Ok(()) Ok(())
} }
@ -15,7 +15,7 @@ impl<'a> LowerHex for BytesRef<'a> {
impl<'a> UpperHex for BytesRef<'a> { impl<'a> UpperHex for BytesRef<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result { fn fmt(&self, f: &mut Formatter<'_>) -> Result {
for b in self.0 { for b in self.0 {
write!(f, "{:02X}", b)?; write!(f, "{b:02X}")?;
} }
Ok(()) Ok(())
} }

View file

@ -1,5 +1,9 @@
# Changes # Changes
## [0.2.7] - 2023-01-29
* Refactor buffer api
## [0.2.6] - 2023-01-27 ## [0.2.6] - 2023-01-27
* Add IoRef::with_rw_buf() helper * Add IoRef::with_rw_buf() helper

View file

@ -1,6 +1,6 @@
[package] [package]
name = "ntex-io" name = "ntex-io"
version = "0.2.6" version = "0.2.7"
authors = ["ntex contributors <team@ntex.rs>"] authors = ["ntex contributors <team@ntex.rs>"]
description = "Utilities for encoding and decoding frames" description = "Utilities for encoding and decoding frames"
keywords = ["network", "framework", "async", "futures"] keywords = ["network", "framework", "async", "futures"]
@ -29,4 +29,4 @@ pin-project-lite = "0.2"
rand = "0.8" rand = "0.8"
env_logger = "0.10" env_logger = "0.10"
ntex = { version = "0.6.2", features = ["tokio"] } ntex = { version = "0.6.3", features = ["tokio"] }

View file

@ -1,14 +1,15 @@
use std::cell::Cell;
use ntex_bytes::{BytesVec, PoolRef}; use ntex_bytes::{BytesVec, PoolRef};
use ntex_util::future::Either; use ntex_util::future::Either;
use crate::IoRef; use crate::IoRef;
type BufferLine = (Option<BytesVec>, Option<BytesVec>); type Buffer = (Cell<Option<BytesVec>>, Cell<Option<BytesVec>>);
#[derive(Debug)]
pub struct Stack { pub struct Stack {
len: usize, len: usize,
buffers: Either<[BufferLine; 3], Vec<BufferLine>>, buffers: Either<[Buffer; 3], Vec<Buffer>>,
} }
impl Stack { impl Stack {
@ -22,153 +23,204 @@ impl Stack {
pub(crate) fn add_layer(&mut self) { pub(crate) fn add_layer(&mut self) {
match &mut self.buffers { match &mut self.buffers {
Either::Left(b) => { Either::Left(b) => {
// move to vec
if self.len == 3 { if self.len == 3 {
// move to vec let mut vec = vec![(Cell::new(None), Cell::new(None))];
let mut vec = vec![(None, None)];
for item in b.iter_mut().take(self.len) { for item in b.iter_mut().take(self.len) {
vec.push((item.0.take(), item.1.take())); vec.push((Cell::new(item.0.take()), Cell::new(item.1.take())));
} }
self.len += 1; self.len += 1;
self.buffers = Either::Right(vec); self.buffers = Either::Right(vec);
} else { } else {
let mut idx = self.len; let mut idx = self.len;
while idx > 0 { while idx > 0 {
let item = (b[idx - 1].0.take(), b[idx - 1].1.take()); let item = (
Cell::new(b[idx - 1].0.take()),
Cell::new(b[idx - 1].1.take()),
);
b[idx] = item; b[idx] = item;
idx -= 1; idx -= 1;
} }
b[0] = (None, None); b[0] = (Cell::new(None), Cell::new(None));
self.len += 1; self.len += 1;
} }
} }
Either::Right(vec) => { Either::Right(vec) => {
self.len += 1; self.len += 1;
vec.insert(0, (None, None)); vec.insert(0, (Cell::new(None), Cell::new(None)));
} }
} }
} }
fn get_buffers<F, R>(&mut self, idx: usize, f: F) -> R fn get_buffers<F, R>(&self, idx: usize, f: F) -> R
where where
F: FnOnce(&mut BufferLine, &mut BufferLine) -> R, F: FnOnce(&Buffer, &Buffer) -> R,
{ {
let buffers = match self.buffers { let buffers = match self.buffers {
Either::Left(ref mut b) => &mut b[..], Either::Left(ref b) => &b[..],
Either::Right(ref mut b) => &mut b[..], Either::Right(ref b) => &b[..],
}; };
let pos = idx + 1; let next = idx + 1;
if self.len > pos { if self.len > next {
let (curr, next) = buffers.split_at_mut(pos); f(&buffers[idx], &buffers[next])
f(&mut curr[idx], &mut next[0])
} else { } else {
let mut curr = (buffers[idx].0.take(), None); let curr = (Cell::new(buffers[idx].0.take()), Cell::new(None));
let mut next = (None, buffers[idx].1.take()); let next = (Cell::new(None), Cell::new(buffers[idx].1.take()));
let result = f(&mut curr, &mut next); let result = f(&curr, &next);
buffers[idx].0 = curr.0; buffers[idx].0.set(curr.0.take());
buffers[idx].1 = next.1; buffers[idx].1.set(next.1.take());
result result
} }
} }
fn get_first_level(&mut self) -> &mut BufferLine { fn get_first_level(&self) -> &Buffer {
match &mut self.buffers { match &self.buffers {
Either::Left(b) => &mut b[0], Either::Left(b) => &b[0],
Either::Right(b) => &mut b[0], Either::Right(b) => &b[0],
} }
} }
fn get_last_level(&mut self) -> &mut BufferLine { fn get_last_level(&self) -> &Buffer {
match &mut self.buffers { match &self.buffers {
Either::Left(b) => &mut b[self.len - 1], Either::Left(b) => &b[self.len - 1],
Either::Right(b) => &mut b[self.len - 1], Either::Right(b) => &b[self.len - 1],
} }
} }
pub(crate) fn read_buf<F, R>( pub(crate) fn read_buf<F, R>(&self, io: &IoRef, idx: usize, nbytes: usize, f: F) -> R
&mut self,
io: &IoRef,
idx: usize,
nbytes: usize,
f: F,
) -> R
where where
F: FnOnce(&mut ReadBuf<'_>) -> R, F: FnOnce(&ReadBuf<'_>) -> R,
{ {
self.get_buffers(idx, |curr, next| { self.get_buffers(idx, |curr, next| {
let mut buf = ReadBuf { let buf = ReadBuf {
io, io,
nbytes, nbytes,
curr, curr,
next, next,
need_write: false, need_write: Cell::new(false),
}; };
f(&mut buf) f(&buf)
}) })
} }
pub(crate) fn write_buf<F, R>(&mut self, io: &IoRef, idx: usize, f: F) -> R pub(crate) fn write_buf<F, R>(&self, io: &IoRef, idx: usize, f: F) -> R
where where
F: FnOnce(&mut WriteBuf<'_>) -> R, F: FnOnce(&WriteBuf<'_>) -> R,
{ {
self.get_buffers(idx, |curr, next| { self.get_buffers(idx, |curr, next| {
let mut buf = WriteBuf { let buf = WriteBuf {
io, io,
curr, curr,
next, next,
need_write: false, need_write: Cell::new(false),
}; };
f(&mut buf) f(&buf)
}) })
} }
pub(crate) fn first_read_buf_size(&mut self) -> usize { pub(crate) fn with_read_source<F, R>(&self, io: &IoRef, f: F) -> R
self.get_first_level()
.0
.as_ref()
.map(|b| b.len())
.unwrap_or(0)
}
pub(crate) fn with_rw_buf<F, R>(&mut self, io: &IoRef, f: F) -> R
where where
F: FnOnce(&mut BytesVec, &mut BytesVec) -> R, F: FnOnce(&mut BytesVec) -> R,
{ {
let lvl = self.get_first_level(); let item = self.get_last_level();
if lvl.0.is_none() { let mut rb = item.0.take();
lvl.0 = Some(io.memory_pool().get_read_buf()); if rb.is_none() {
rb = Some(io.memory_pool().get_read_buf());
} }
if lvl.1.is_none() {
lvl.1 = Some(io.memory_pool().get_write_buf()); let result = f(rb.as_mut().unwrap());
if let Some(b) = rb {
if b.is_empty() {
io.memory_pool().release_read_buf(b);
} else {
item.0.set(Some(b));
}
} }
f(lvl.0.as_mut().unwrap(), lvl.1.as_mut().unwrap()) result
} }
pub(crate) fn first_read_buf(&mut self) -> &mut Option<BytesVec> { pub(crate) fn with_read_destination<F, R>(&self, io: &IoRef, f: F) -> R
&mut self.get_first_level().0 where
} F: FnOnce(&mut BytesVec) -> R,
{
pub(crate) fn first_write_buf(&mut self, io: &IoRef) -> &mut BytesVec { let item = self.get_first_level();
let item = &mut self.get_first_level().1; let mut rb = item.0.take();
if item.is_none() { if rb.is_none() {
*item = Some(io.memory_pool().get_write_buf()); rb = Some(io.memory_pool().get_read_buf());
} }
item.as_mut().unwrap()
let result = f(rb.as_mut().unwrap());
if let Some(b) = rb {
if b.is_empty() {
io.memory_pool().release_read_buf(b);
} else {
item.0.set(Some(b));
}
}
result
} }
pub(crate) fn last_read_buf(&mut self) -> &mut Option<BytesVec> { pub(crate) fn with_write_source<F, R>(&self, io: &IoRef, f: F) -> R
&mut self.get_last_level().0 where
F: FnOnce(&mut BytesVec) -> R,
{
let item = self.get_first_level();
let mut wb = item.1.take();
if wb.is_none() {
wb = Some(io.memory_pool().get_write_buf());
}
let result = f(wb.as_mut().unwrap());
if let Some(b) = wb {
if b.is_empty() {
io.memory_pool().release_write_buf(b);
} else {
item.1.set(Some(b));
}
}
result
} }
pub(crate) fn last_write_buf(&mut self) -> &mut Option<BytesVec> { pub(crate) fn with_write_destination<F, R>(&self, io: &IoRef, f: F) -> R
&mut self.get_last_level().1 where
F: FnOnce(&mut Option<BytesVec>) -> R,
{
let item = self.get_last_level();
let mut wb = item.1.take();
let result = f(&mut wb);
if let Some(b) = wb {
if b.is_empty() {
io.memory_pool().release_write_buf(b);
} else {
item.1.set(Some(b));
}
}
result
} }
pub(crate) fn release(&mut self, pool: PoolRef) { pub(crate) fn read_destination_size(&self) -> usize {
let items = match &mut self.buffers { let item = self.get_first_level();
Either::Left(b) => &mut b[..], let rb = item.0.take();
Either::Right(b) => &mut b[..], let size = rb.as_ref().map(|b| b.len()).unwrap_or(0);
item.0.set(rb);
size
}
pub(crate) fn write_destination_size(&self) -> usize {
let item = self.get_last_level();
let wb = item.1.take();
let size = wb.as_ref().map(|b| b.len()).unwrap_or(0);
item.1.set(wb);
size
}
pub(crate) fn release(&self, pool: PoolRef) {
let items = match &self.buffers {
Either::Left(b) => &b[..],
Either::Right(b) => &b[..],
}; };
for item in items { for item in items {
@ -181,29 +233,31 @@ impl Stack {
} }
} }
pub(crate) fn set_memory_pool(&mut self, pool: PoolRef) { pub(crate) fn set_memory_pool(&self, pool: PoolRef) {
let items = match &mut self.buffers { let items = match &self.buffers {
Either::Left(b) => &mut b[..], Either::Left(b) => &b[..],
Either::Right(b) => &mut b[..], Either::Right(b) => &b[..],
}; };
for buf in items { for item in items {
if let Some(ref mut b) = buf.0 { if let Some(mut b) = item.0.take() {
pool.move_vec_in(b); pool.move_vec_in(&mut b);
item.0.set(Some(b));
} }
if let Some(ref mut b) = buf.1 { if let Some(mut b) = item.1.take() {
pool.move_vec_in(b); pool.move_vec_in(&mut b);
item.1.set(Some(b));
} }
} }
} }
} }
#[derive(Debug)] // #[derive(Debug)]
pub struct ReadBuf<'a> { pub struct ReadBuf<'a> {
pub(crate) io: &'a IoRef, pub(crate) io: &'a IoRef,
pub(crate) curr: &'a mut BufferLine, pub(crate) curr: &'a Buffer,
pub(crate) next: &'a mut BufferLine, pub(crate) next: &'a Buffer,
pub(crate) nbytes: usize, pub(crate) nbytes: usize,
pub(crate) need_write: bool, pub(crate) need_write: Cell<bool>,
} }
impl<'a> ReadBuf<'a> { impl<'a> ReadBuf<'a> {
@ -219,27 +273,68 @@ impl<'a> ReadBuf<'a> {
self.io.want_shutdown() self.io.want_shutdown()
} }
#[inline]
/// Make sure buffer has enough free space
pub fn resize_buf(&self, buf: &mut BytesVec) {
self.io.memory_pool().resize_read_buf(buf);
}
#[inline] #[inline]
/// Get reference to source read buffer /// Get reference to source read buffer
pub fn get_src(&mut self) -> &mut BytesVec { pub fn with_src<F, R>(&self, f: F) -> R
if self.next.0.is_none() { where
self.next.0 = Some(self.io.memory_pool().get_read_buf()); F: FnOnce(&mut Option<BytesVec>) -> R,
{
let mut item = self.next.0.take();
let result = f(&mut item);
if let Some(b) = item {
if b.is_empty() {
self.io.memory_pool().release_read_buf(b);
} else {
self.next.0.set(Some(b));
}
} }
self.next.0.as_mut().unwrap() result
}
#[inline]
/// Get reference to destination read buffer
pub fn with_dst<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut BytesVec) -> R,
{
let mut item = self.curr.0.take();
if item.is_none() {
item = Some(self.io.memory_pool().get_read_buf());
}
let result = f(item.as_mut().unwrap());
if let Some(b) = item {
if b.is_empty() {
self.io.memory_pool().release_read_buf(b);
} else {
self.curr.0.set(Some(b));
}
}
result
} }
#[inline] #[inline]
/// Take source read buffer /// Take source read buffer
pub fn take_src(&mut self) -> Option<BytesVec> { pub fn take_src(&self) -> Option<BytesVec> {
self.next self.next.0.take().and_then(|b| {
.0 if b.is_empty() {
.take() self.io.memory_pool().release_read_buf(b);
.and_then(|b| if b.is_empty() { None } else { Some(b) }) None
} else {
Some(b)
}
})
} }
#[inline] #[inline]
/// Set source read buffer /// Set source read buffer
pub fn set_src(&mut self, src: Option<BytesVec>) { pub fn set_src(&self, src: Option<BytesVec>) {
if let Some(buf) = self.next.0.take() { if let Some(buf) = self.next.0.take() {
self.io.memory_pool().release_read_buf(buf); self.io.memory_pool().release_read_buf(buf);
} }
@ -247,23 +342,14 @@ impl<'a> ReadBuf<'a> {
if src.is_empty() { if src.is_empty() {
self.io.memory_pool().release_read_buf(src); self.io.memory_pool().release_read_buf(src);
} else { } else {
self.next.0 = Some(src); self.next.0.set(Some(src));
} }
} }
} }
#[inline]
/// Get reference to destination read buffer
pub fn get_dst(&mut self) -> &mut BytesVec {
if self.curr.0.is_none() {
self.curr.0 = Some(self.io.memory_pool().get_read_buf());
}
self.curr.0.as_mut().unwrap()
}
#[inline] #[inline]
/// Take destination read buffer /// Take destination read buffer
pub fn take_dst(&mut self) -> BytesVec { pub fn take_dst(&self) -> BytesVec {
self.curr self.curr
.0 .0
.take() .take()
@ -272,7 +358,7 @@ impl<'a> ReadBuf<'a> {
#[inline] #[inline]
/// Set destination read buffer /// Set destination read buffer
pub fn set_dst(&mut self, dst: Option<BytesVec>) { pub fn set_dst(&self, dst: Option<BytesVec>) {
if let Some(buf) = self.curr.0.take() { if let Some(buf) = self.curr.0.take() {
self.io.memory_pool().release_read_buf(buf); self.io.memory_pool().release_read_buf(buf);
} }
@ -280,46 +366,34 @@ impl<'a> ReadBuf<'a> {
if dst.is_empty() { if dst.is_empty() {
self.io.memory_pool().release_read_buf(dst); self.io.memory_pool().release_read_buf(dst);
} else { } else {
self.curr.0 = Some(dst); self.curr.0.set(Some(dst));
} }
} }
} }
#[inline] #[inline]
/// Get reference to source and destination read buffers (src, dst) pub fn with_write_buf<'b, F, R>(&'b self, f: F) -> R
pub fn get_pair(&mut self) -> (&mut BytesVec, &mut BytesVec) {
if self.next.0.is_none() {
self.next.0 = Some(self.io.memory_pool().get_read_buf());
}
if self.curr.0.is_none() {
self.curr.0 = Some(self.io.memory_pool().get_read_buf());
}
(self.next.0.as_mut().unwrap(), self.curr.0.as_mut().unwrap())
}
#[inline]
pub fn with_write_buf<'b, F, R>(&'b mut self, f: F) -> R
where where
F: FnOnce(&mut WriteBuf<'b>) -> R, F: FnOnce(&WriteBuf<'b>) -> R,
{ {
let mut buf = WriteBuf { let mut buf = WriteBuf {
io: self.io, io: self.io,
curr: self.curr, curr: self.curr,
next: self.next, next: self.next,
need_write: self.need_write, need_write: Cell::new(self.need_write.get()),
}; };
let result = f(&mut buf); let result = f(&mut buf);
self.need_write = buf.need_write; self.need_write.set(buf.need_write.get());
result result
} }
} }
#[derive(Debug)] // #[derive(Debug)]
pub struct WriteBuf<'a> { pub struct WriteBuf<'a> {
pub(crate) io: &'a IoRef, pub(crate) io: &'a IoRef,
pub(crate) curr: &'a mut BufferLine, pub(crate) curr: &'a Buffer,
pub(crate) next: &'a mut BufferLine, pub(crate) next: &'a Buffer,
pub(crate) need_write: bool, pub(crate) need_write: Cell<bool>,
} }
impl<'a> WriteBuf<'a> { impl<'a> WriteBuf<'a> {
@ -329,57 +403,85 @@ impl<'a> WriteBuf<'a> {
self.io.want_shutdown() self.io.want_shutdown()
} }
#[inline]
/// Make sure buffer has enough free space
pub fn resize_buf(&self, buf: &mut BytesVec) {
self.io.memory_pool().resize_write_buf(buf);
}
#[inline] #[inline]
/// Get reference to source write buffer /// Get reference to source write buffer
pub fn get_src(&mut self) -> &mut BytesVec { pub fn with_src<F, R>(&self, f: F) -> R
if self.curr.1.is_none() { where
self.curr.1 = Some(self.io.memory_pool().get_write_buf()); F: FnOnce(&mut Option<BytesVec>) -> R,
{
let mut item = self.curr.1.take();
let result = f(&mut item);
if let Some(b) = item {
if b.is_empty() {
self.io.memory_pool().release_write_buf(b);
} else {
self.curr.1.set(Some(b));
}
} }
self.curr.1.as_mut().unwrap() result
}
#[inline]
/// Get reference to destination write buffer
pub fn with_dst<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut BytesVec) -> R,
{
let mut item = self.next.1.take();
if item.is_none() {
item = Some(self.io.memory_pool().get_write_buf());
}
let buf = item.as_mut().unwrap();
let total = buf.len();
let result = f(buf);
if buf.is_empty() {
self.io.memory_pool().release_write_buf(item.unwrap());
} else {
self.need_write
.set(self.need_write.get() | (total != buf.len()));
self.next.1.set(item);
}
result
} }
#[inline] #[inline]
/// Take source write buffer /// Take source write buffer
pub fn take_src(&mut self) -> Option<BytesVec> { pub fn take_src(&self) -> Option<BytesVec> {
self.curr self.curr.1.take().and_then(|b| {
.1 if b.is_empty() {
.take() self.io.memory_pool().release_write_buf(b);
.and_then(|b| if b.is_empty() { None } else { Some(b) }) None
} else {
Some(b)
}
})
} }
#[inline] #[inline]
/// Set source write buffer /// Set source write buffer
pub fn set_src(&mut self, src: Option<BytesVec>) { pub fn set_src(&self, src: Option<BytesVec>) {
if let Some(buf) = self.curr.1.take() { if let Some(buf) = self.curr.1.take() {
self.io.memory_pool().release_read_buf(buf); self.io.memory_pool().release_write_buf(buf);
} }
if let Some(buf) = src { if let Some(buf) = src {
if buf.is_empty() { if buf.is_empty() {
self.io.memory_pool().release_read_buf(buf); self.io.memory_pool().release_write_buf(buf);
} else { } else {
self.curr.1 = Some(buf); self.curr.1.set(Some(buf));
} }
} }
} }
#[inline]
/// Get reference to destination write buffer
pub fn with_dst_buf<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut BytesVec) -> R,
{
if self.next.1.is_none() {
self.next.1 = Some(self.io.memory_pool().get_write_buf());
}
let buf = self.next.1.as_mut().unwrap();
let r = f(buf);
self.need_write |= !buf.is_empty();
r
}
#[inline] #[inline]
/// Take destination write buffer /// Take destination write buffer
pub fn take_dst(&mut self) -> BytesVec { pub fn take_dst(&self) -> BytesVec {
self.next self.next
.1 .1
.take() .take()
@ -388,7 +490,7 @@ impl<'a> WriteBuf<'a> {
#[inline] #[inline]
/// Set destination write buffer /// Set destination write buffer
pub fn set_dst(&mut self, dst: Option<BytesVec>) { pub fn set_dst(&self, dst: Option<BytesVec>) {
if let Some(buf) = self.next.1.take() { if let Some(buf) = self.next.1.take() {
self.io.memory_pool().release_write_buf(buf); self.io.memory_pool().release_write_buf(buf);
} }
@ -396,26 +498,26 @@ impl<'a> WriteBuf<'a> {
if dst.is_empty() { if dst.is_empty() {
self.io.memory_pool().release_write_buf(dst); self.io.memory_pool().release_write_buf(dst);
} else { } else {
self.need_write |= !dst.is_empty(); self.need_write.set(self.need_write.get() | !dst.is_empty());
self.next.1 = Some(dst); self.next.1.set(Some(dst));
} }
} }
} }
#[inline] #[inline]
pub fn with_read_buf<'b, F, R>(&'b mut self, f: F) -> R pub fn with_read_buf<'b, F, R>(&'b self, f: F) -> R
where where
F: FnOnce(&mut ReadBuf<'b>) -> R, F: FnOnce(&ReadBuf<'b>) -> R,
{ {
let mut buf = ReadBuf { let mut buf = ReadBuf {
io: self.io, io: self.io,
curr: self.curr, curr: self.curr,
next: self.next, next: self.next,
nbytes: 0, nbytes: 0,
need_write: self.need_write, need_write: Cell::new(self.need_write.get()),
}; };
let result = f(&mut buf); let result = f(&mut buf);
self.need_write = buf.need_write; self.need_write.set(buf.need_write.get());
result result
} }
} }

View file

@ -41,21 +41,16 @@ pub trait Filter: 'static {
fn process_read_buf( fn process_read_buf(
&self, &self,
io: &IoRef, io: &IoRef,
stack: &mut Stack, stack: &Stack,
idx: usize, idx: usize,
nbytes: usize, nbytes: usize,
) -> io::Result<FilterReadStatus>; ) -> io::Result<FilterReadStatus>;
/// Process write buffer /// Process write buffer
fn process_write_buf( fn process_write_buf(&self, io: &IoRef, stack: &Stack, idx: usize) -> io::Result<()>;
&self,
io: &IoRef,
stack: &mut Stack,
idx: usize,
) -> io::Result<()>;
/// Gracefully shutdown filter /// Gracefully shutdown filter
fn shutdown(&self, io: &IoRef, stack: &mut Stack, idx: usize) -> io::Result<Poll<()>>; fn shutdown(&self, io: &IoRef, stack: &Stack, idx: usize) -> io::Result<Poll<()>>;
/// Check readiness for read operations /// Check readiness for read operations
fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<ReadStatus>; fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<ReadStatus>;
@ -115,7 +110,7 @@ impl Filter for Base {
fn process_read_buf( fn process_read_buf(
&self, &self,
_: &IoRef, _: &IoRef,
_: &mut Stack, _: &Stack,
_: usize, _: usize,
nbytes: usize, nbytes: usize,
) -> io::Result<FilterReadStatus> { ) -> io::Result<FilterReadStatus> {
@ -126,22 +121,24 @@ impl Filter for Base {
} }
#[inline] #[inline]
fn process_write_buf(&self, _: &IoRef, s: &mut Stack, _: usize) -> io::Result<()> { fn process_write_buf(&self, io: &IoRef, s: &Stack, _: usize) -> io::Result<()> {
if let Some(buf) = s.last_write_buf() { s.with_write_destination(io, |buf| {
let len = buf.len(); if let Some(buf) = buf {
if len > 0 && self.0.flags().contains(Flags::WR_PAUSED) { let len = buf.len();
self.0 .0.remove_flags(Flags::WR_PAUSED); if len > 0 && self.0.flags().contains(Flags::WR_PAUSED) {
self.0 .0.write_task.wake(); self.0 .0.remove_flags(Flags::WR_PAUSED);
self.0 .0.write_task.wake();
}
if len >= self.0.memory_pool().write_params_high() {
self.0 .0.insert_flags(Flags::WR_BACKPRESSURE);
}
} }
if len >= self.0.memory_pool().write_params_high() { });
self.0 .0.insert_flags(Flags::WR_BACKPRESSURE);
}
}
Ok(()) Ok(())
} }
#[inline] #[inline]
fn shutdown(&self, _: &IoRef, _: &mut Stack, _: usize) -> io::Result<Poll<()>> { fn shutdown(&self, _: &IoRef, _: &Stack, _: usize) -> io::Result<Poll<()>> {
Ok(Poll::Ready(())) Ok(Poll::Ready(()))
} }
} }
@ -157,7 +154,7 @@ where
} }
#[inline] #[inline]
fn shutdown(&self, io: &IoRef, stack: &mut Stack, idx: usize) -> io::Result<Poll<()>> { fn shutdown(&self, io: &IoRef, stack: &Stack, idx: usize) -> io::Result<Poll<()>> {
let result1 = stack.write_buf(io, idx, |buf| self.0.shutdown(buf))?; let result1 = stack.write_buf(io, idx, |buf| self.0.shutdown(buf))?;
self.process_write_buf(io, stack, idx)?; self.process_write_buf(io, stack, idx)?;
@ -178,7 +175,7 @@ where
fn process_read_buf( fn process_read_buf(
&self, &self,
io: &IoRef, io: &IoRef,
stack: &mut Stack, stack: &Stack,
idx: usize, idx: usize,
nbytes: usize, nbytes: usize,
) -> io::Result<FilterReadStatus> { ) -> io::Result<FilterReadStatus> {
@ -190,18 +187,13 @@ where
stack.read_buf(io, idx, status.nbytes, |buf| { stack.read_buf(io, idx, status.nbytes, |buf| {
self.0.process_read_buf(buf).map(|nbytes| FilterReadStatus { self.0.process_read_buf(buf).map(|nbytes| FilterReadStatus {
nbytes, nbytes,
need_write: status.need_write || buf.need_write, need_write: status.need_write || buf.need_write.get(),
}) })
}) })
} }
#[inline] #[inline]
fn process_write_buf( fn process_write_buf(&self, io: &IoRef, stack: &Stack, idx: usize) -> io::Result<()> {
&self,
io: &IoRef,
stack: &mut Stack,
idx: usize,
) -> io::Result<()> {
stack.write_buf(io, idx, |buf| self.0.process_write_buf(buf))?; stack.write_buf(io, idx, |buf| self.0.process_write_buf(buf))?;
if F::BUFFERS { if F::BUFFERS {
@ -270,7 +262,7 @@ impl Filter for NullFilter {
fn process_read_buf( fn process_read_buf(
&self, &self,
_: &IoRef, _: &IoRef,
_: &mut Stack, _: &Stack,
_: usize, _: usize,
_: usize, _: usize,
) -> io::Result<FilterReadStatus> { ) -> io::Result<FilterReadStatus> {
@ -278,12 +270,12 @@ impl Filter for NullFilter {
} }
#[inline] #[inline]
fn process_write_buf(&self, _: &IoRef, _: &mut Stack, _: usize) -> io::Result<()> { fn process_write_buf(&self, _: &IoRef, _: &Stack, _: usize) -> io::Result<()> {
Ok(()) Ok(())
} }
#[inline] #[inline]
fn shutdown(&self, _: &IoRef, _: &mut Stack, _: usize) -> io::Result<Poll<()>> { fn shutdown(&self, _: &IoRef, _: &Stack, _: usize) -> io::Result<Poll<()>> {
Ok(Poll::Ready(())) Ok(Poll::Ready(()))
} }
} }

View file

@ -1,4 +1,4 @@
use std::cell::{Cell, RefCell}; use std::cell::Cell;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use std::{fmt, future::Future, hash, io, marker, mem, ops, pin::Pin, ptr, rc::Rc, time}; use std::{fmt, future::Future, hash, io, marker, mem, ops, pin::Pin, ptr, rc::Rc, time};
@ -62,7 +62,7 @@ pub(crate) struct IoState {
pub(super) read_task: LocalWaker, pub(super) read_task: LocalWaker,
pub(super) write_task: LocalWaker, pub(super) write_task: LocalWaker,
pub(super) dispatch_task: LocalWaker, pub(super) dispatch_task: LocalWaker,
pub(super) buffer: RefCell<Stack>, pub(super) buffer: Stack,
pub(super) filter: Cell<&'static dyn Filter>, pub(super) filter: Cell<&'static dyn Filter>,
pub(super) handle: Cell<Option<Box<dyn Handle>>>, pub(super) handle: Cell<Option<Box<dyn Handle>>>,
#[allow(clippy::box_collection)] #[allow(clippy::box_collection)]
@ -149,7 +149,7 @@ impl hash::Hash for IoState {
impl Drop for IoState { impl Drop for IoState {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
self.buffer.borrow_mut().release(self.pool.get()); self.buffer.release(self.pool.get());
} }
} }
@ -171,7 +171,7 @@ impl Io {
dispatch_task: LocalWaker::new(), dispatch_task: LocalWaker::new(),
read_task: LocalWaker::new(), read_task: LocalWaker::new(),
write_task: LocalWaker::new(), write_task: LocalWaker::new(),
buffer: RefCell::new(Stack::new()), buffer: Stack::new(),
filter: Cell::new(NullFilter::get()), filter: Cell::new(NullFilter::get()),
handle: Cell::new(None), handle: Cell::new(None),
on_disconnect: Cell::new(None), on_disconnect: Cell::new(None),
@ -199,7 +199,7 @@ impl<F> Io<F> {
#[inline] #[inline]
/// Set memory pool /// Set memory pool
pub fn set_memory_pool(&self, pool: PoolRef) { pub fn set_memory_pool(&self, pool: PoolRef) {
self.0 .0.buffer.borrow_mut().set_memory_pool(pool); self.0 .0.buffer.set_memory_pool(pool);
self.0 .0.pool.set(pool); self.0 .0.pool.set(pool);
} }
@ -227,7 +227,7 @@ impl<F> Io<F> {
dispatch_task: LocalWaker::new(), dispatch_task: LocalWaker::new(),
read_task: LocalWaker::new(), read_task: LocalWaker::new(),
write_task: LocalWaker::new(), write_task: LocalWaker::new(),
buffer: RefCell::new(Stack::new()), buffer: Stack::new(),
filter: Cell::new(NullFilter::get()), filter: Cell::new(NullFilter::get()),
handle: Cell::new(None), handle: Cell::new(None),
on_disconnect: Cell::new(None), on_disconnect: Cell::new(None),
@ -292,7 +292,12 @@ impl<F: Filter> Io<F> {
{ {
// add layer to buffers // add layer to buffers
if U::BUFFERS { if U::BUFFERS {
self.0 .0.buffer.borrow_mut().add_layer(); // Safety: .add_layer() modifies internal buffers
// there is no api that holds references into buffers storage
// all apis first removes buffer from storage and then work with it
unsafe { &mut *(Rc::as_ptr(&self.0 .0) as *mut IoState) }
.buffer
.add_layer();
} }
// replace current filter // replace current filter
@ -489,14 +494,7 @@ impl<F> Io<F> {
Poll::Ready(self.error().map(Err).unwrap_or(Ok(()))) Poll::Ready(self.error().map(Err).unwrap_or(Ok(())))
} else { } else {
let inner = &self.0 .0; let inner = &self.0 .0;
let len = inner let len = inner.buffer.write_destination_size();
.buffer
.borrow_mut()
.last_write_buf()
.as_ref()
.map(|b| b.len())
.unwrap_or(0);
if len > 0 { if len > 0 {
if full { if full {
inner.insert_flags(Flags::WR_WAIT); inner.insert_flags(Flags::WR_WAIT);

View file

@ -1,9 +1,9 @@
use std::{any, cell, fmt, hash, io, time}; use std::{any, fmt, hash, io, time};
use ntex_bytes::{BytesVec, PoolRef}; use ntex_bytes::{BytesVec, PoolRef};
use ntex_codec::{Decoder, Encoder}; use ntex_codec::{Decoder, Encoder};
use super::{buf::Stack, io::Flags, timer, types, Filter, IoRef, OnDisconnect, WriteBuf}; use super::{io::Flags, timer, types, Filter, IoRef, OnDisconnect, WriteBuf};
impl IoRef { impl IoRef {
#[inline] #[inline]
@ -132,11 +132,9 @@ impl IoRef {
where where
U: Decoder, U: Decoder,
{ {
borrow_buffer(&self.0.buffer) self.0
.first_read_buf() .buffer
.as_mut() .with_read_destination(self, |buf| codec.decode_vec(buf))
.map(|b| codec.decode_vec(b))
.unwrap_or(Ok(None))
} }
#[inline] #[inline]
@ -152,59 +150,40 @@ impl IoRef {
} }
#[inline] #[inline]
/// Get mut access to write buffer /// Get access to write buffer
pub fn with_buf<F, R>(&self, f: F) -> io::Result<R> pub fn with_buf<F, R>(&self, f: F) -> io::Result<R>
where where
F: FnOnce(&mut WriteBuf<'_>) -> R, F: FnOnce(&WriteBuf<'_>) -> R,
{ {
let mut buffer = borrow_buffer(&self.0.buffer); let result = self.0.buffer.write_buf(self, 0, f);
let result = buffer.write_buf(self, 0, f);
self.0 self.0
.filter .filter
.get() .get()
.process_write_buf(self, &mut buffer, 0)?; .process_write_buf(self, &self.0.buffer, 0)?;
Ok(result) Ok(result)
} }
#[inline] #[inline]
/// Get mut access to write buffer /// Get mut access to source write buffer
pub fn with_write_buf<F, R>(&self, f: F) -> io::Result<R> pub fn with_write_buf<F, R>(&self, f: F) -> io::Result<R>
where where
F: FnOnce(&mut BytesVec) -> R, F: FnOnce(&mut BytesVec) -> R,
{ {
let mut buffer = borrow_buffer(&self.0.buffer); let result = self.0.buffer.with_write_source(self, f);
let result = f(buffer.first_write_buf(self));
self.0 self.0
.filter .filter
.get() .get()
.process_write_buf(self, &mut buffer, 0)?; .process_write_buf(self, &self.0.buffer, 0)?;
Ok(result) Ok(result)
} }
#[inline] #[inline]
/// Get mut access to read buffer /// Get mut access to source read buffer
pub fn with_read_buf<F, R>(&self, f: F) -> R pub fn with_read_buf<F, R>(&self, f: F) -> R
where where
F: FnOnce(&mut BytesVec) -> R, F: FnOnce(&mut BytesVec) -> R,
{ {
// use top most buffer self.0.buffer.with_read_destination(self, f)
let mut buffer = borrow_buffer(&self.0.buffer);
let buf = buffer.first_read_buf();
if buf.is_none() {
*buf = Some(self.memory_pool().get_read_buf());
}
f(buf.as_mut().unwrap())
}
#[inline]
/// Get mut access to read and write buffer
pub fn with_rw_buf<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut BytesVec, &mut BytesVec) -> R,
{
borrow_buffer(&self.0.buffer).with_rw_buf(self, f)
} }
#[inline] #[inline]
@ -260,14 +239,6 @@ impl fmt::Debug for IoRef {
} }
} }
fn borrow_buffer(buf: &cell::RefCell<Stack>) -> cell::RefMut<'_, Stack> {
if let Ok(r) = buf.try_borrow_mut() {
r
} else {
panic!("Nested access to read/write buffers are not allowed");
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
@ -411,16 +382,16 @@ mod tests {
impl FilterLayer for Counter { impl FilterLayer for Counter {
const BUFFERS: bool = false; const BUFFERS: bool = false;
fn process_read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<usize> { fn process_read_buf(&self, buf: &ReadBuf<'_>) -> io::Result<usize> {
self.read_order.borrow_mut().push(self.idx); self.read_order.borrow_mut().push(self.idx);
self.in_bytes.set(self.in_bytes.get() + buf.nbytes()); self.in_bytes.set(self.in_bytes.get() + buf.nbytes());
Ok(buf.nbytes()) Ok(buf.nbytes())
} }
fn process_write_buf(&self, buf: &mut WriteBuf<'_>) -> io::Result<()> { fn process_write_buf(&self, buf: &WriteBuf<'_>) -> io::Result<()> {
self.write_order.borrow_mut().push(self.idx); self.write_order.borrow_mut().push(self.idx);
self.out_bytes self.out_bytes
.set(self.out_bytes.get() + buf.with_dst_buf(|b| b.len())); .set(self.out_bytes.get() + buf.with_dst(|b| b.len()));
Ok(()) Ok(())
} }
} }

View file

@ -71,10 +71,10 @@ pub trait FilterLayer: 'static {
/// ///
/// Inner filter must process buffer before current. /// Inner filter must process buffer before current.
/// Returns number of new bytes. /// Returns number of new bytes.
fn process_read_buf(&self, buf: &mut ReadBuf<'_>) -> sio::Result<usize>; fn process_read_buf(&self, buf: &ReadBuf<'_>) -> sio::Result<usize>;
/// Process write buffer /// Process write buffer
fn process_write_buf(&self, buf: &mut WriteBuf<'_>) -> sio::Result<()>; fn process_write_buf(&self, buf: &WriteBuf<'_>) -> sio::Result<()>;
#[inline] #[inline]
/// Query internal filter data /// Query internal filter data
@ -84,7 +84,7 @@ pub trait FilterLayer: 'static {
#[inline] #[inline]
/// Gracefully shutdown filter /// Gracefully shutdown filter
fn shutdown(&self, buf: &mut WriteBuf<'_>) -> sio::Result<Poll<()>> { fn shutdown(&self, buf: &WriteBuf<'_>) -> sio::Result<Poll<()>> {
Ok(Poll::Ready(())) Ok(Poll::Ready(()))
} }
} }

View file

@ -24,71 +24,59 @@ impl ReadContext {
F: FnOnce(&mut BytesVec, usize, usize) -> Poll<io::Result<()>>, F: FnOnce(&mut BytesVec, usize, usize) -> Poll<io::Result<()>>,
{ {
let inner = &self.0 .0; let inner = &self.0 .0;
let mut stack = inner.buffer.borrow_mut();
let mut buf = stack
.last_read_buf()
.take()
.unwrap_or_else(|| self.0.memory_pool().get_read_buf());
let total = buf.len();
let (hw, lw) = self.0.memory_pool().read_params().unpack(); let (hw, lw) = self.0.memory_pool().read_params().unpack();
let (result, nbytes, total) = inner.buffer.with_read_source(&self.0, |buf| {
let total = buf.len();
// call provided callback // call provided callback
let result = f(&mut buf, hw, lw); let result = f(buf, hw, lw);
// handle buffer changes
if buf.is_empty() {
self.0.memory_pool().release_read_buf(buf);
} else {
let total2 = buf.len(); let total2 = buf.len();
let nbytes = if total2 > total { total2 - total } else { 0 }; let nbytes = if total2 > total { total2 - total } else { 0 };
*stack.last_read_buf() = Some(buf); (result, nbytes, total2)
});
if nbytes > 0 { // handle buffer changes
let buf_full = nbytes >= hw; if nbytes > 0 {
let filter = self.0.filter(); let buf_full = nbytes >= hw;
let _ = filter.process_read_buf(&self.0, &mut stack, 0, nbytes) let filter = self.0.filter();
.and_then(|status| { let _ = filter
if status.nbytes > 0 { .process_read_buf(&self.0, &inner.buffer, 0, nbytes)
if buf_full || stack.first_read_buf_size() >= hw { .and_then(|status| {
log::trace!( if status.nbytes > 0 {
"io read buffer is too large {}, enable read back-pressure", if buf_full || inner.buffer.read_destination_size() >= hw {
total2
);
inner.insert_flags(Flags::RD_READY | Flags::RD_BUF_FULL);
} else {
inner.insert_flags(Flags::RD_READY);
}
log::trace!( log::trace!(
"new {} bytes available, wakeup dispatcher", "io read buffer is too large {}, enable read back-pressure",
nbytes, total
); );
inner.dispatch_task.wake(); inner.insert_flags(Flags::RD_READY | Flags::RD_BUF_FULL);
} else if buf_full {
// read task is paused because of read back-pressure
// but there is no new data in top most read buffer
// so we need to wake up read task to read more data
// otherwise read task would sleep forever
inner.read_task.wake();
}
// while reading, filter wrote some data
// in that case filters need to process write buffers
// and potentialy wake write task
if status.need_write {
filter.process_write_buf(&self.0, &mut stack, 0)
} else { } else {
Ok(()) inner.insert_flags(Flags::RD_READY);
} }
}) log::trace!("new {} bytes available, wakeup dispatcher", nbytes,);
.map_err(|err| {
inner.dispatch_task.wake(); inner.dispatch_task.wake();
inner.insert_flags(Flags::RD_READY); } else if buf_full {
inner.io_stopped(Some(err)); // read task is paused because of read back-pressure
}); // but there is no new data in top most read buffer
} // so we need to wake up read task to read more data
// otherwise read task would sleep forever
inner.read_task.wake();
}
// while reading, filter wrote some data
// in that case filters need to process write buffers
// and potentialy wake write task
if status.need_write {
filter.process_write_buf(&self.0, &inner.buffer, 0)
} else {
Ok(())
}
})
.map_err(|err| {
inner.dispatch_task.wake();
inner.insert_flags(Flags::RD_READY);
inner.io_stopped(Some(err));
});
} }
drop(stack);
match result { match result {
Poll::Ready(Ok(())) => { Poll::Ready(Ok(())) => {
@ -135,20 +123,12 @@ impl WriteContext {
F: FnOnce(&mut Option<BytesVec>) -> Poll<io::Result<()>>, F: FnOnce(&mut Option<BytesVec>) -> Poll<io::Result<()>>,
{ {
let inner = &self.0 .0; let inner = &self.0 .0;
let mut stack = inner.buffer.borrow_mut();
let buf = stack.last_write_buf();
// call provided callback // call provided callback
let result = f(buf); let (result, len) = inner.buffer.with_write_destination(&self.0, |buf| {
let result = f(buf);
let mut len = 0; (result, buf.as_ref().map(|b| b.len()).unwrap_or(0))
if let Some(b) = buf { });
if b.is_empty() {
inner.pool.get().release_write_buf(buf.take().unwrap());
} else {
len = b.len();
}
}
// if write buffer is smaller than high watermark value, turn off back-pressure // if write buffer is smaller than high watermark value, turn off back-pressure
let mut flags = inner.flags.get(); let mut flags = inner.flags.get();
@ -191,8 +171,7 @@ fn shutdown_filters(io: &IoRef) {
if !flags.intersects(Flags::IO_STOPPED | Flags::IO_STOPPING) { if !flags.intersects(Flags::IO_STOPPED | Flags::IO_STOPPING) {
let filter = io.filter(); let filter = io.filter();
let mut buffer = st.buffer.borrow_mut(); match filter.shutdown(io, &st.buffer, 0) {
match filter.shutdown(io, &mut buffer, 0) {
Ok(Poll::Ready(())) => { Ok(Poll::Ready(())) => {
st.dispatch_task.wake(); st.dispatch_task.wake();
st.insert_flags(Flags::IO_STOPPING); st.insert_flags(Flags::IO_STOPPING);
@ -211,7 +190,7 @@ fn shutdown_filters(io: &IoRef) {
st.io_stopped(Some(err)); st.io_stopped(Some(err));
} }
} }
if let Err(err) = filter.process_write_buf(io, &mut buffer, 0) { if let Err(err) = filter.process_write_buf(io, &st.buffer, 0) {
st.io_stopped(Some(err)); st.io_stopped(Some(err));
} }
} }

View file

@ -118,11 +118,11 @@ mod tests {
pub(crate) struct TestFilter; pub(crate) struct TestFilter;
impl FilterLayer for TestFilter { impl FilterLayer for TestFilter {
fn process_read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<usize> { fn process_read_buf(&self, buf: &ReadBuf<'_>) -> io::Result<usize> {
Ok(buf.nbytes()) Ok(buf.nbytes())
} }
fn process_write_buf(&self, _: &mut WriteBuf<'_>) -> io::Result<()> { fn process_write_buf(&self, _: &WriteBuf<'_>) -> io::Result<()> {
Ok(()) Ok(())
} }
} }

View file

@ -1,5 +1,9 @@
# Changes # Changes
## [0.2.4] - 2023-01-29
* Update buffer api
## [0.2.3] - 2023-01-25 ## [0.2.3] - 2023-01-25
* Fix double buf cleanup * Fix double buf cleanup

View file

@ -1,6 +1,6 @@
[package] [package]
name = "ntex-tls" name = "ntex-tls"
version = "0.2.3" version = "0.2.4"
authors = ["ntex contributors <team@ntex.rs>"] authors = ["ntex contributors <team@ntex.rs>"]
description = "An implementation of SSL streams for ntex backed by OpenSSL" description = "An implementation of SSL streams for ntex backed by OpenSSL"
keywords = ["network", "framework", "async", "futures"] keywords = ["network", "framework", "async", "futures"]
@ -26,7 +26,7 @@ rustls = ["tls_rust"]
[dependencies] [dependencies]
ntex-bytes = "0.1.19" ntex-bytes = "0.1.19"
ntex-io = "0.2.3" ntex-io = "0.2.7"
ntex-util = "0.2.0" ntex-util = "0.2.0"
ntex-service = "1.0.0" ntex-service = "1.0.0"
log = "0.4" log = "0.4"
@ -39,7 +39,7 @@ tls_openssl = { version="0.10", package = "openssl", optional = true }
tls_rust = { version = "0.20", package = "rustls", optional = true } tls_rust = { version = "0.20", package = "rustls", optional = true }
[dev-dependencies] [dev-dependencies]
ntex = { version = "0.6.1", features = ["openssl", "rustls", "tokio"] } ntex = { version = "0.6.3", features = ["openssl", "rustls", "tokio"] }
env_logger = "0.10" env_logger = "0.10"
rustls-pemfile = { version = "1.0" } rustls-pemfile = { version = "1.0" }
webpki-roots = { version = "0.22" } webpki-roots = { version = "0.22" }

View file

@ -2,7 +2,7 @@
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::{any, cmp, error::Error, io, task::Context, task::Poll}; use std::{any, cmp, error::Error, io, task::Context, task::Poll};
use ntex_bytes::{BufMut, BytesVec, PoolRef}; use ntex_bytes::{BufMut, BytesVec};
use ntex_io::{types, Filter, FilterFactory, FilterLayer, Io, Layer, ReadBuf, WriteBuf}; use ntex_io::{types, Filter, FilterFactory, FilterLayer, Io, Layer, ReadBuf, WriteBuf};
use ntex_util::{future::poll_fn, future::BoxFuture, ready, time, time::Millis}; use ntex_util::{future::poll_fn, future::BoxFuture, ready, time, time::Millis};
use tls_openssl::ssl::{self, NameType, SslStream}; use tls_openssl::ssl::{self, NameType, SslStream};
@ -24,25 +24,22 @@ pub struct PeerCertChain(pub Vec<X509>);
/// An implementation of SSL streams /// An implementation of SSL streams
pub struct SslFilter { pub struct SslFilter {
inner: RefCell<SslStream<IoInner>>, inner: RefCell<SslStream<IoInner>>,
pool: PoolRef,
handshake: Cell<bool>, handshake: Cell<bool>,
} }
struct IoInner { struct IoInner {
source: Option<BytesVec>, source: Option<BytesVec>,
destination: Option<BytesVec>, destination: Option<BytesVec>,
pool: PoolRef,
} }
impl io::Read for IoInner { impl io::Read for IoInner {
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> { fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
if let Some(mut buf) = self.source.take() { if let Some(ref mut buf) = self.source {
if buf.is_empty() { if buf.is_empty() {
Err(io::Error::from(io::ErrorKind::WouldBlock)) Err(io::Error::from(io::ErrorKind::WouldBlock))
} else { } else {
let len = cmp::min(buf.len(), dst.len()); let len = cmp::min(buf.len(), dst.len());
dst[..len].copy_from_slice(&buf.split_to(len)); dst[..len].copy_from_slice(&buf.split_to(len));
self.source = Some(buf);
Ok(len) Ok(len)
} }
} else { } else {
@ -53,13 +50,7 @@ impl io::Read for IoInner {
impl io::Write for IoInner { impl io::Write for IoInner {
fn write(&mut self, src: &[u8]) -> io::Result<usize> { fn write(&mut self, src: &[u8]) -> io::Result<usize> {
let mut buf = if let Some(buf) = self.destination.take() { self.destination.as_mut().unwrap().extend_from_slice(src);
buf
} else {
BytesVec::with_capacity_in(src.len(), self.pool)
};
buf.extend_from_slice(src);
self.destination = Some(buf);
Ok(src.len()) Ok(src.len())
} }
@ -69,7 +60,7 @@ impl io::Write for IoInner {
} }
impl SslFilter { impl SslFilter {
fn with_buffers<F, R>(&self, buf: &mut WriteBuf<'_>, f: F) -> R fn with_buffers<F, R>(&self, buf: &WriteBuf<'_>, f: F) -> R
where where
F: FnOnce() -> R, F: FnOnce() -> R,
{ {
@ -80,16 +71,6 @@ impl SslFilter {
buf.with_read_buf(|b| b.set_src(self.inner.borrow_mut().get_mut().source.take())); buf.with_read_buf(|b| b.set_src(self.inner.borrow_mut().get_mut().source.take()));
result result
} }
fn set_buffers(&self, buf: &mut WriteBuf<'_>) {
self.inner.borrow_mut().get_mut().destination = Some(buf.take_dst());
self.inner.borrow_mut().get_mut().source = buf.with_read_buf(|b| b.take_src());
}
fn unset_buffers(&self, buf: &mut WriteBuf<'_>) {
buf.set_dst(self.inner.borrow_mut().get_mut().destination.take());
buf.with_read_buf(|b| b.set_src(self.inner.borrow_mut().get_mut().source.take()));
}
} }
impl FilterLayer for SslFilter { impl FilterLayer for SslFilter {
@ -141,7 +122,7 @@ impl FilterLayer for SslFilter {
} }
} }
fn shutdown(&self, buf: &mut WriteBuf<'_>) -> io::Result<Poll<()>> { fn shutdown(&self, buf: &WriteBuf<'_>) -> io::Result<Poll<()>> {
let ssl_result = self.with_buffers(buf, || self.inner.borrow_mut().shutdown()); let ssl_result = self.with_buffers(buf, || self.inner.borrow_mut().shutdown());
match ssl_result { match ssl_result {
@ -160,75 +141,72 @@ impl FilterLayer for SslFilter {
} }
} }
fn process_read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<usize> { fn process_read_buf(&self, buf: &ReadBuf<'_>) -> io::Result<usize> {
buf.with_write_buf(|b| self.set_buffers(b)); buf.with_write_buf(|b| {
self.with_buffers(b, || {
buf.with_dst(|dst| {
let mut new_bytes = usize::from(self.handshake.get());
loop {
buf.resize_buf(dst);
let dst = buf.get_dst(); let chunk: &mut [u8] =
//let mut new_bytes = usize::from(self.handshake.get()); unsafe { std::mem::transmute(&mut *dst.chunk_mut()) };
let mut new_bytes = 1; let ssl_result = self.inner.borrow_mut().ssl_read(chunk);
loop { let result = match ssl_result {
// make sure we've got room Ok(v) => {
self.pool.resize_read_buf(dst); unsafe { dst.advance_mut(v) };
new_bytes += v;
let chunk: &mut [u8] = unsafe { std::mem::transmute(&mut *dst.chunk_mut()) }; continue;
let ssl_result = self.inner.borrow_mut().ssl_read(chunk); }
let result = match ssl_result { Err(ref e)
Ok(v) => { if e.code() == ssl::ErrorCode::WANT_READ
unsafe { dst.advance_mut(v) }; || e.code() == ssl::ErrorCode::WANT_WRITE =>
new_bytes += v; {
continue; Ok(new_bytes)
} }
Err(ref e) Err(ref e) if e.code() == ssl::ErrorCode::ZERO_RETURN => {
if e.code() == ssl::ErrorCode::WANT_READ buf.want_shutdown();
|| e.code() == ssl::ErrorCode::WANT_WRITE => Ok(new_bytes)
{ }
Ok(new_bytes) Err(e) => {
} log::trace!("SSL Error: {:?}", e);
Err(ref e) if e.code() == ssl::ErrorCode::ZERO_RETURN => { Err(map_to_ioerr(e))
buf.want_shutdown(); }
Ok(new_bytes) };
} return result;
Err(e) => { }
log::trace!("SSL Error: {:?}", e); })
Err(map_to_ioerr(e)) })
} })
};
buf.with_write_buf(|b| self.unset_buffers(b));
return result;
}
} }
fn process_write_buf(&self, buf: &mut WriteBuf<'_>) -> io::Result<()> { fn process_write_buf(&self, wb: &WriteBuf<'_>) -> io::Result<()> {
if let Some(mut src) = buf.take_src() { wb.with_src(|b| {
self.set_buffers(buf); if let Some(src) = b {
self.with_buffers(wb, || loop {
loop { if src.is_empty() {
if src.is_empty() { return Ok(());
self.unset_buffers(buf);
return Ok(());
}
let ssl_result = self.inner.borrow_mut().ssl_write(&src);
match ssl_result {
Ok(v) => {
src.split_to(v);
continue;
} }
Err(e) => { let ssl_result = self.inner.borrow_mut().ssl_write(src);
buf.set_src(Some(src)); match ssl_result {
self.unset_buffers(buf); Ok(v) => {
return match e.code() { src.split_to(v);
ssl::ErrorCode::WANT_READ | ssl::ErrorCode::WANT_WRITE => { continue;
Ok(()) }
} Err(e) => {
_ => Err(map_to_ioerr(e)), return match e.code() {
}; ssl::ErrorCode::WANT_READ | ssl::ErrorCode::WANT_WRITE => {
Ok(())
}
_ => Err(map_to_ioerr(e)),
};
}
} }
} })
} else {
Ok(())
} }
} else { })
Ok(())
}
} }
} }
@ -278,12 +256,10 @@ impl<F: Filter> FilterFactory<F> for SslAcceptor {
time::timeout(timeout, async { time::timeout(timeout, async {
let ssl = ctx_result.map_err(map_to_ioerr)?; let ssl = ctx_result.map_err(map_to_ioerr)?;
let inner = IoInner { let inner = IoInner {
pool: io.memory_pool(),
source: None, source: None,
destination: None, destination: None,
}; };
let filter = SslFilter { let filter = SslFilter {
pool: io.memory_pool(),
handshake: Cell::new(true), handshake: Cell::new(true),
inner: RefCell::new(ssl::SslStream::new(ssl, inner)?), inner: RefCell::new(ssl::SslStream::new(ssl, inner)?),
}; };
@ -336,12 +312,10 @@ impl<F: Filter> FilterFactory<F> for SslConnector {
fn create(self, io: Io<F>) -> Self::Future { fn create(self, io: Io<F>) -> Self::Future {
Box::pin(async move { Box::pin(async move {
let inner = IoInner { let inner = IoInner {
pool: io.memory_pool(),
source: None, source: None,
destination: None, destination: None,
}; };
let filter = SslFilter { let filter = SslFilter {
pool: io.memory_pool(),
handshake: Cell::new(true), handshake: Cell::new(true),
inner: RefCell::new(ssl::SslStream::new(self.ssl, inner)?), inner: RefCell::new(ssl::SslStream::new(self.ssl, inner)?),
}; };

View file

@ -56,62 +56,60 @@ impl FilterLayer for TlsClientFilter {
} }
} }
fn process_read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<usize> { fn process_read_buf(&self, buf: &ReadBuf<'_>) -> io::Result<usize> {
let mut session = self.session.borrow_mut(); let mut session = self.session.borrow_mut();
let mut new_bytes = usize::from(self.inner.handshake.get());
// get processed buffer // get processed buffer
let (src, dst) = buf.get_pair(); buf.with_src(|src| {
let mut new_bytes = usize::from(self.inner.handshake.get()); if let Some(src) = src {
loop { buf.with_dst(|dst| {
// make sure we've got room loop {
self.inner.pool.resize_read_buf(dst); 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 mut cursor = io::Cursor::new(&src); let new_b = state.plaintext_bytes_to_read();
let n = session.read_tls(&mut cursor)?; if new_b > 0 {
src.split_to(n); dst.reserve(new_b);
let state = session let chunk: &mut [u8] =
.process_new_packets() unsafe { std::mem::transmute(&mut *dst.chunk_mut()) };
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; let v = session.reader().read(chunk)?;
unsafe { dst.advance_mut(v) };
let new_b = state.plaintext_bytes_to_read(); new_bytes += v;
if new_b > 0 { } else {
dst.reserve(new_b); break;
let chunk: &mut [u8] = }
unsafe { std::mem::transmute(&mut *dst.chunk_mut()) }; }
let v = session.reader().read(chunk)?; Ok::<_, io::Error>(())
unsafe { dst.advance_mut(v) }; })?;
new_bytes += v;
} else {
break;
} }
} Ok(new_bytes)
})
Ok(new_bytes)
} }
fn process_write_buf(&self, buf: &mut WriteBuf<'_>) -> io::Result<()> { fn process_write_buf(&self, buf: &WriteBuf<'_>) -> io::Result<()> {
if let Some(mut src) = buf.take_src() { buf.with_src(|src| {
let mut session = self.session.borrow_mut(); if let Some(src) = src {
let mut io = Wrapper(&self.inner, buf); let mut session = self.session.borrow_mut();
let mut io = Wrapper(&self.inner, buf);
loop { loop {
if !src.is_empty() { if !src.is_empty() {
let n = session.writer().write(&src)?; src.split_to(session.writer().write(src)?);
src.split_to(n); }
} if session.wants_write() {
session.complete_io(&mut io)?;
if session.wants_write() { } else {
session.complete_io(&mut io)?; break;
} else { }
break;
} }
} }
buf.set_src(Some(src));
Ok(()) Ok(())
} else { })
Ok(())
}
} }
} }
@ -125,7 +123,6 @@ impl TlsClientFilter {
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?; .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
let filter = TlsFilter::new_client(TlsClientFilter { let filter = TlsFilter::new_client(TlsClientFilter {
inner: IoInner { inner: IoInner {
pool: io.memory_pool(),
handshake: Cell::new(true), handshake: Cell::new(true),
}, },
session: RefCell::new(session), session: RefCell::new(session),

View file

@ -2,7 +2,6 @@
//! An implementation of SSL streams for ntex backed by OpenSSL //! An implementation of SSL streams for ntex backed by OpenSSL
use std::{any, cell::Cell, cmp, io, sync::Arc, task::Context, task::Poll}; use std::{any, cell::Cell, cmp, io, sync::Arc, task::Context, task::Poll};
use ntex_bytes::PoolRef;
use ntex_io::{ use ntex_io::{
Filter, FilterFactory, FilterLayer, Io, Layer, ReadBuf, ReadStatus, WriteBuf, Filter, FilterFactory, FilterLayer, Io, Layer, ReadBuf, ReadStatus, WriteBuf,
WriteStatus, WriteStatus,
@ -71,7 +70,7 @@ impl FilterLayer for TlsFilter {
} }
#[inline] #[inline]
fn shutdown(&self, buf: &mut WriteBuf<'_>) -> io::Result<Poll<()>> { fn shutdown(&self, buf: &WriteBuf<'_>) -> io::Result<Poll<()>> {
match self.inner { match self.inner {
InnerTlsFilter::Server(ref f) => f.shutdown(buf), InnerTlsFilter::Server(ref f) => f.shutdown(buf),
InnerTlsFilter::Client(ref f) => f.shutdown(buf), InnerTlsFilter::Client(ref f) => f.shutdown(buf),
@ -95,7 +94,7 @@ impl FilterLayer for TlsFilter {
} }
#[inline] #[inline]
fn process_read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<usize> { fn process_read_buf(&self, buf: &ReadBuf<'_>) -> io::Result<usize> {
match self.inner { match self.inner {
InnerTlsFilter::Server(ref f) => f.process_read_buf(buf), InnerTlsFilter::Server(ref f) => f.process_read_buf(buf),
InnerTlsFilter::Client(ref f) => f.process_read_buf(buf), InnerTlsFilter::Client(ref f) => f.process_read_buf(buf),
@ -103,7 +102,7 @@ impl FilterLayer for TlsFilter {
} }
#[inline] #[inline]
fn process_write_buf(&self, buf: &mut WriteBuf<'_>) -> io::Result<()> { fn process_write_buf(&self, buf: &WriteBuf<'_>) -> io::Result<()> {
match self.inner { match self.inner {
InnerTlsFilter::Server(ref f) => f.process_write_buf(buf), InnerTlsFilter::Server(ref f) => f.process_write_buf(buf),
InnerTlsFilter::Client(ref f) => f.process_write_buf(buf), InnerTlsFilter::Client(ref f) => f.process_write_buf(buf),
@ -219,30 +218,31 @@ impl<F: Filter> FilterFactory<F> for TlsConnectorConfigured {
} }
pub(crate) struct IoInner { pub(crate) struct IoInner {
pool: PoolRef,
handshake: Cell<bool>, handshake: Cell<bool>,
} }
pub(crate) struct Wrapper<'a, 'b>(&'a IoInner, &'a mut WriteBuf<'b>); pub(crate) struct Wrapper<'a, 'b>(&'a IoInner, &'a WriteBuf<'b>);
impl<'a, 'b> io::Read for Wrapper<'a, 'b> { impl<'a, 'b> io::Read for Wrapper<'a, 'b> {
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> { fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
self.1.with_read_buf(|buf| { self.1.with_read_buf(|buf| {
let read_buf = buf.get_src(); buf.with_src(|buf| {
let len = cmp::min(read_buf.len(), dst.len()); if let Some(buf) = buf {
if len > 0 { let len = cmp::min(buf.len(), dst.len());
dst[..len].copy_from_slice(&read_buf.split_to(len)); if len > 0 {
Ok(len) dst[..len].copy_from_slice(&buf.split_to(len));
} else { return Ok(len);
}
}
Err(io::Error::new(io::ErrorKind::WouldBlock, "")) Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
} })
}) })
} }
} }
impl<'a, 'b> io::Write for Wrapper<'a, 'b> { impl<'a, 'b> io::Write for Wrapper<'a, 'b> {
fn write(&mut self, src: &[u8]) -> io::Result<usize> { fn write(&mut self, src: &[u8]) -> io::Result<usize> {
self.1.with_dst_buf(|buf| buf.extend_from_slice(src)); self.1.with_dst(|buf| buf.extend_from_slice(src));
Ok(src.len()) Ok(src.len())
} }

View file

@ -63,60 +63,60 @@ impl FilterLayer for TlsServerFilter {
} }
} }
fn process_read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<usize> { fn process_read_buf(&self, buf: &ReadBuf<'_>) -> io::Result<usize> {
let mut session = self.session.borrow_mut(); let mut session = self.session.borrow_mut();
let mut new_bytes = usize::from(self.inner.handshake.get());
// get processed buffer // get processed buffer
let (src, dst) = buf.get_pair(); buf.with_src(|src| {
let mut new_bytes = usize::from(self.inner.handshake.get()); if let Some(src) = src {
loop { buf.with_dst(|dst| {
// make sure we've got room loop {
self.inner.pool.resize_read_buf(dst); 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 mut cursor = io::Cursor::new(&src); let new_b = state.plaintext_bytes_to_read();
let n = session.read_tls(&mut cursor)?; if new_b > 0 {
src.split_to(n); dst.reserve(new_b);
let state = session let chunk: &mut [u8] =
.process_new_packets() unsafe { std::mem::transmute(&mut *dst.chunk_mut()) };
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; let v = session.reader().read(chunk)?;
unsafe { dst.advance_mut(v) };
let new_b = state.plaintext_bytes_to_read(); new_bytes += v;
if new_b > 0 { } else {
dst.reserve(new_b); break;
let chunk: &mut [u8] = }
unsafe { std::mem::transmute(&mut *dst.chunk_mut()) }; }
let v = session.reader().read(chunk)?; Ok::<_, io::Error>(())
unsafe { dst.advance_mut(v) }; })?;
new_bytes += v;
} else {
break;
} }
} Ok(new_bytes)
})
Ok(new_bytes)
} }
fn process_write_buf(&self, buf: &mut WriteBuf<'_>) -> io::Result<()> { fn process_write_buf(&self, buf: &WriteBuf<'_>) -> io::Result<()> {
if let Some(mut src) = buf.take_src() { buf.with_src(|src| {
let mut session = self.session.borrow_mut(); if let Some(src) = src {
let mut io = Wrapper(&self.inner, buf); let mut session = self.session.borrow_mut();
let mut io = Wrapper(&self.inner, buf);
loop { loop {
if !src.is_empty() { if !src.is_empty() {
let n = session.writer().write(&src)?; src.split_to(session.writer().write(src)?);
src.split_to(n); }
} if session.wants_write() {
session.complete_io(&mut io)?;
if session.wants_write() { } else {
session.complete_io(&mut io)?; break;
} else { }
break;
} }
} }
Ok(())
buf.set_src(Some(src)); })
}
Ok(())
} }
} }
@ -132,7 +132,6 @@ impl TlsServerFilter {
let filter = TlsFilter::new_server(TlsServerFilter { let filter = TlsFilter::new_server(TlsServerFilter {
session: RefCell::new(session), session: RefCell::new(session),
inner: IoInner { inner: IoInner {
pool: io.memory_pool(),
handshake: Cell::new(true), handshake: Cell::new(true),
}, },
}); });

View file

@ -1,6 +1,6 @@
[package] [package]
name = "ntex" name = "ntex"
version = "0.6.2" version = "0.6.3"
authors = ["ntex contributors <team@ntex.rs>"] authors = ["ntex contributors <team@ntex.rs>"]
description = "Framework for composable network services" description = "Framework for composable network services"
readme = "README.md" readme = "README.md"
@ -58,8 +58,8 @@ ntex-util = "0.2.0"
ntex-bytes = "0.1.19" ntex-bytes = "0.1.19"
ntex-h2 = "0.2.1" ntex-h2 = "0.2.1"
ntex-rt = "0.4.7" ntex-rt = "0.4.7"
ntex-io = "0.2.3" ntex-io = "0.2.7"
ntex-tls = "0.2.3" ntex-tls = "0.2.4"
ntex-tokio = { version = "0.2.1", optional = true } ntex-tokio = { version = "0.2.1", optional = true }
ntex-glommio = { version = "0.2.1", optional = true } ntex-glommio = { version = "0.2.1", optional = true }
ntex-async-std = { version = "0.2.1", optional = true } ntex-async-std = { version = "0.2.1", optional = true }

View file

@ -684,8 +684,7 @@ where
// read request payload // read request payload
let mut updated = false; let mut updated = false;
loop { loop {
let res = io.poll_recv(&payload.0, cx); match io.poll_recv(&payload.0, cx) {
match res {
Poll::Ready(Ok(PayloadItem::Chunk(chunk))) => { Poll::Ready(Ok(PayloadItem::Chunk(chunk))) => {
updated = true; updated = true;
payload.1.feed_data(chunk); payload.1.feed_data(chunk);
@ -945,6 +944,7 @@ mod tests {
#[crate::rt_test] #[crate::rt_test]
async fn test_pipeline_with_payload() { async fn test_pipeline_with_payload() {
env_logger::init();
let (client, server) = Io::create(); let (client, server) = Io::create();
client.remote_buffer_cap(4096); client.remote_buffer_cap(4096);
let mut decoder = ClientCodec::default(); let mut decoder = ClientCodec::default();

View file

@ -58,7 +58,7 @@ impl WsTransport {
impl FilterLayer for WsTransport { impl FilterLayer for WsTransport {
#[inline] #[inline]
fn shutdown(&self, buf: &mut WriteBuf<'_>) -> io::Result<Poll<()>> { fn shutdown(&self, buf: &WriteBuf<'_>) -> io::Result<Poll<()>> {
let flags = self.flags.get(); let flags = self.flags.get();
if !flags.contains(Flags::CLOSED) { if !flags.contains(Flags::CLOSED) {
self.insert_flags(Flags::CLOSED); self.insert_flags(Flags::CLOSED);
@ -67,7 +67,7 @@ impl FilterLayer for WsTransport {
} else { } else {
CloseCode::Normal CloseCode::Normal
}; };
let _ = buf.with_dst_buf(|buf| { let _ = buf.with_dst(|buf| {
self.codec.encode_vec( self.codec.encode_vec(
Message::Close(Some(CloseReason { Message::Close(Some(CloseReason {
code, code,
@ -80,7 +80,7 @@ impl FilterLayer for WsTransport {
Ok(Poll::Ready(())) Ok(Poll::Ready(()))
} }
fn process_read_buf(&self, buf: &mut ReadBuf<'_>) -> io::Result<usize> { fn process_read_buf(&self, buf: &ReadBuf<'_>) -> io::Result<usize> {
if let Some(mut src) = buf.take_src() { if let Some(mut src) = buf.take_src() {
let mut dst = buf.take_dst(); let mut dst = buf.take_dst();
let dst_len = dst.len(); let dst_len = dst.len();
@ -133,7 +133,7 @@ impl FilterLayer for WsTransport {
} }
Frame::Ping(msg) => { Frame::Ping(msg) => {
let _ = buf.with_write_buf(|b| { let _ = buf.with_write_buf(|b| {
b.with_dst_buf(|b| self.codec.encode_vec(Message::Pong(msg), b)) b.with_dst(|b| self.codec.encode_vec(Message::Pong(msg), b))
}); });
} }
Frame::Pong(_) => (), Frame::Pong(_) => (),
@ -153,9 +153,9 @@ impl FilterLayer for WsTransport {
} }
} }
fn process_write_buf(&self, buf: &mut WriteBuf<'_>) -> io::Result<()> { fn process_write_buf(&self, buf: &WriteBuf<'_>) -> io::Result<()> {
if let Some(src) = buf.take_src() { if let Some(src) = buf.take_src() {
buf.with_dst_buf(|dst| { buf.with_dst(|dst| {
// make sure we've got room // make sure we've got room
let (hw, lw) = self.pool.write_params().unpack(); let (hw, lw) = self.pool.write_params().unpack();
let remaining = dst.remaining_mut(); let remaining = dst.remaining_mut();