1use std::cell::{Cell, UnsafeCell};
2use std::task::{Context, Poll};
3use std::{fmt, future::poll_fn, hash, io, marker, mem, ops, ptr, rc::Rc};
4
5use ntex_bytes::{BytePageSize, BytesMut};
6use ntex_codec::{Decoder, Encoder};
7use ntex_service::cfg::{Cfg, SharedCfg};
8use ntex_util::{future::Either, task::LocalWaker, time::Sleep};
9
10use crate::buf::Stack;
11use crate::cfg::IoConfig;
12use crate::ctx::IoContext;
13use crate::filter::{Base, Filter, Layer};
14use crate::filterptr::FilterPtr;
15use crate::flags::Flags;
16use crate::ops::{Id, IoManager, TimerHandle};
17use crate::seal::{IoBoxed, Sealed};
18use crate::utils::{Extensions, WriteDeadline, write_timed_out};
19use crate::waiters::{TAG_WRITE, WriteGuard};
20use crate::{Decoded, FilterLayer, Handle, IoStatusUpdate, IoStream, RecvError};
21
22const RD_SHRINK_BATCHES: u8 = 4;
25
26pub struct Io<F = Base>(UnsafeCell<IoRef>, marker::PhantomData<F>);
51
52#[derive(Clone)]
66pub struct IoRef(pub(super) Rc<IoState>);
67
68pub(crate) struct IoState {
69 filter: FilterPtr,
70 pub(super) id: Cell<Id>,
71 pub(super) cfg: Cfg<IoConfig>,
72 pub(super) flags: Flags,
73 pub(super) error: Cell<Option<io::Error>>,
74 pub(super) read_task: LocalWaker,
75 pub(super) write_task: LocalWaker,
76 dispatch_task: LocalWaker,
77 pub(super) buffer: Stack,
78 pub(super) handle: Cell<Option<Box<dyn Handle>>>,
79 pub(super) timeout: Cell<TimerHandle>,
80 pub(super) shutdown_timeout: Cell<Option<Sleep>>,
81 pub(super) wr_inflight: Cell<u32>,
87 rd_size: Cell<BytePageSize>,
92 rd_batch: Cell<u32>,
94 rd_small: Cell<u8>,
96 pub(super) extensions: Extensions,
97}
98
99impl IoState {
100 pub(super) fn id(&self) -> Id {
101 self.id.get()
102 }
103
104 pub(super) fn tag(&self) -> &'static str {
105 self.cfg.tag()
106 }
107
108 pub(super) fn is_io_dropped(&self) -> bool {
110 !self.filter.is_set()
111 }
112
113 pub(super) fn filter(&self) -> &dyn Filter {
114 self.filter.get()
115 }
116
117 pub(super) fn notify_timeout(&self) {
118 if self.flags.check_dispatcher_timeout_unset() {
119 self.wake_dispatch_task();
120 log::trace!("{}: Timer, notify dispatcher", self.cfg.tag());
121 }
122 }
123
124 pub(super) fn notify_disconnect(&self) {
126 self.extensions.wake_all();
127 }
128
129 pub(super) fn error(&self) -> Option<io::Error> {
131 if let Some(err) = self.error.take() {
132 let cloned = if let Some(code) = err.raw_os_error() {
133 io::Error::from_raw_os_error(code)
134 } else {
135 io::Error::new(err.kind(), format!("{err}"))
136 };
137 self.error.set(Some(cloned));
138 Some(err)
139 } else {
140 None
141 }
142 }
143
144 pub(super) fn error_or_disconnected(&self) -> io::Error {
146 self.error()
147 .unwrap_or_else(|| io::Error::new(io::ErrorKind::NotConnected, "Disconnected"))
148 }
149
150 pub(super) fn filters_stopped(&self) {
151 self.wake_read_task();
154 self.wake_write_task();
155 self.wake_dispatch_task();
156 self.wake_write_waiters();
157 self.flags.enter_transport_shutdown();
158 }
159
160 fn set_error(&self, err: Option<io::Error>) {
161 if let Some(err) = err {
162 if let Some(current) = self.error.take() {
163 self.error.set(Some(current));
164 } else {
165 self.error.set(Some(err));
166 }
167 }
168 }
169
170 pub(super) fn set_shutdown_error(&self, err: io::Error) {
171 self.set_error(Some(err));
172 }
173
174 pub(super) fn force_close_connection(&self) {
182 self.begin_terminate(None, true);
183 }
184
185 pub(super) fn terminate_connection(&self, err: Option<io::Error>) {
186 self.begin_terminate(err, false);
187 }
188
189 fn begin_terminate(&self, err: Option<io::Error>, force: bool) {
192 self.set_error(err);
193 if self.flags.begin_terminate(force) {
194 log::trace!("{}: Terminate io", self.cfg.tag());
195 self.wr_inflight.set(0);
197 self.wake_read_task();
198 self.wake_write_task();
199 self.wake_dispatch_task();
200 self.wake_write_waiters();
201 self.handle.take();
202 }
203 }
204
205 pub(super) fn stop_connection(&self, err: Option<io::Error>) {
206 if !self.flags.is_closed() {
207 log::trace!("{}: Stop io with error {:?}", self.cfg.tag(), err);
208 self.set_error(err);
209 self.flags.set_stopped();
210 self.wr_inflight.set(0);
212 self.wake_read_task();
213 self.wake_write_task();
214 self.wake_dispatch_task();
215 self.wake_write_waiters();
216 self.notify_disconnect();
217 self.handle.take();
218 }
219 }
220
221 pub(super) fn start_shutdown(&self) {
223 if self.flags.is_active() {
224 log::trace!("{}: Initiate io shutdown {:?}", self.cfg.tag(), self.flags);
225 self.flags.enter_filters_stopping();
226 self.wake_read_task();
227 self.wake_write_task();
228 }
229 }
230
231 pub(super) fn get_read_buf(&self) -> BytesMut {
234 BytesMut::with_page_size(self.rd_size.get())
235 }
236
237 #[cfg(test)]
239 pub(super) fn read_size(&self) -> BytePageSize {
240 self.rd_size.get()
241 }
242
243 fn reset_read_size(&self) {
245 self.rd_size.set(self.cfg.read_size_min());
246 self.rd_batch.set(0);
247 self.rd_small.set(0);
248 }
249
250 pub(super) fn track_read(&self, nbytes: usize, full: bool) {
259 let batch = self.rd_batch.get().saturating_add(as_u32(nbytes));
260 let size = self.rd_size.get();
261 if full {
262 self.rd_batch.set(batch);
263 if batch as usize > size.capacity() {
264 self.grow_read_size(batch as usize);
265 }
266 return;
267 }
268
269 self.rd_batch.set(0);
270 let batch = batch as usize;
271 if batch == 0 {
272 } else if batch > size.capacity() {
274 self.grow_read_size(batch);
275 } else if size != self.cfg.read_size_min() && batch < size.prev().capacity() / 2 {
276 let small = self.rd_small.get() + 1;
277 if small < RD_SHRINK_BATCHES {
278 self.rd_small.set(small);
279 } else {
280 let min = self.cfg.read_size_min();
281 let prev = size.prev();
282 self.rd_size.set(if prev.capacity() < min.capacity() {
283 min
284 } else {
285 prev
286 });
287 self.rd_small.set(0);
288 }
289 } else {
290 self.rd_small.set(0);
291 }
292 }
293
294 fn grow_read_size(&self, batch: usize) {
295 let max = self.cfg.read_size_max();
296 let size = BytePageSize::for_capacity(batch);
297 let size = if size == BytePageSize::Unset || size.capacity() > max.capacity() {
298 max
299 } else {
300 size
301 };
302 if size.capacity() > self.rd_size.get().capacity() {
303 self.rd_size.set(size);
304 }
305 self.rd_small.set(0);
306 }
307
308 pub(super) fn is_rd_backpressure_needed(&self, size: usize) -> bool {
309 size >= self.cfg.read_backpressure()
310 }
311
312 pub(super) fn is_wr_backpressure_needed(&self, size: usize) -> bool {
313 size >= self.cfg.write_backpressure()
314 }
315
316 pub(super) fn should_disable_rd_backpressure(&self, size: usize) -> bool {
317 size <= self.cfg.read_half()
318 }
319
320 pub(super) fn should_disable_wr_backpressure(&self, size: usize) -> bool {
321 size <= self.cfg.write_half()
322 }
323
324 pub(super) fn write_outstanding(&self) -> usize {
331 self.buffer.write_buf_size() + self.wr_inflight.get() as usize
332 }
333
334 pub(super) fn transport_outstanding(&self) -> usize {
340 self.buffer.write_dst_size() + self.wr_inflight.get() as usize
341 }
342
343 pub(super) fn track_wr_inflight(&self, before: usize, after: usize) {
345 let inflight = self.wr_inflight.get();
346 if after < before {
347 self.wr_inflight
348 .set(inflight.saturating_add(as_u32(before - after)));
349 } else {
350 self.wr_inflight
352 .set(inflight.saturating_sub(as_u32(after - before)));
353 }
354 }
355
356 pub(super) fn wr_inflight_written(&self, written: usize) {
358 self.wr_inflight
359 .set(self.wr_inflight.get().saturating_sub(as_u32(written)));
360 }
361
362 pub(super) fn wake_read_task(&self) {
363 self.read_task.wake();
364 }
365
366 pub(super) fn wake_write_task(&self) {
367 #[cfg(feature = "trace")]
368 log::trace!("{}: Wake write task, flags:{:?}", self.tag(), self.flags);
369 self.write_task.wake();
370 }
371
372 pub(super) fn wake_dispatch_task(&self) {
373 self.dispatch_task.wake();
374 }
375
376 pub(super) fn wake_write_waiters(&self) {
377 self.extensions.wake(TAG_WRITE);
378 }
379
380 pub(super) fn check_write_ready(&self) -> Option<io::Result<()>> {
382 if self.flags.is_peer_gone() {
383 Some(Err(self.error_or_disconnected()))
384 } else if !self.flags.is_wr_backpressure()
385 || self.should_disable_wr_backpressure(self.write_outstanding())
386 {
387 Some(Ok(()))
388 } else {
389 None
390 }
391 }
392
393 pub(super) async fn write_ready(&self) -> io::Result<()> {
394 if let Some(res) = self.check_write_ready() {
395 return res;
396 }
397
398 let waiter = WriteGuard::new(&self.extensions);
399 let mut deadline = WriteDeadline::new(self.cfg.write_timeout());
400 poll_fn(|cx| {
401 if let Some(res) = self.check_write_ready() {
402 Poll::Ready(res)
403 } else if deadline.poll_expired(cx) {
404 Poll::Ready(Err(write_timed_out()))
405 } else {
406 waiter.register(cx);
408 Poll::Pending
409 }
410 })
411 .await
412 }
413
414 pub(super) async fn with_write_timeout<T, F>(&self, mut f: F) -> io::Result<T>
416 where
417 F: FnMut(&mut Context<'_>) -> Poll<io::Result<T>>,
418 {
419 let mut deadline = WriteDeadline::new(self.cfg.write_timeout());
420 poll_fn(|cx| match f(cx) {
421 Poll::Ready(res) => Poll::Ready(res),
422 Poll::Pending if deadline.poll_expired(cx) => Poll::Ready(Err(write_timed_out())),
423 Poll::Pending => Poll::Pending,
424 })
425 .await
426 }
427}
428
429impl Eq for IoState {}
430
431impl PartialEq for IoState {
432 #[inline]
433 fn eq(&self, other: &Self) -> bool {
434 ptr::eq(self, other)
435 }
436}
437
438impl hash::Hash for IoState {
439 #[inline]
440 fn hash<H: hash::Hasher>(&self, state: &mut H) {
441 (ptr::from_ref(self) as usize).hash(state);
442 }
443}
444
445impl fmt::Debug for IoState {
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 let err = self.error.take();
448 let res = f
449 .debug_struct("IoState")
450 .field("id", &self.id)
451 .field("flags", &self.flags)
452 .field("filter", &self.filter.is_set())
453 .field("timeout", &self.timeout)
454 .field("error", &err)
455 .field("buffer", &self.buffer)
456 .field("cfg", &self.cfg)
457 .finish();
458 self.error.set(err);
459 res
460 }
461}
462
463impl Io {
464 pub fn new<I: IoStream, T: Into<SharedCfg>>(io: I, cfg: T) -> Self {
466 let cfg = cfg.into().get::<IoConfig>();
467 let size = cfg.write_size();
468 let flags = Flags::new(cfg.write_buf_threshold() > 0);
469
470 let inner = Rc::new(IoState {
471 cfg,
472 flags,
473 id: Cell::new(Id::default()),
474 filter: FilterPtr::null(),
475 error: Cell::new(None),
476 dispatch_task: LocalWaker::new(),
477 read_task: LocalWaker::new(),
478 write_task: LocalWaker::new(),
479 buffer: Stack::new(size),
480 handle: Cell::new(None),
481 timeout: Cell::new(TimerHandle::default()),
482 shutdown_timeout: Cell::new(None),
483 wr_inflight: Cell::new(0),
484 rd_size: Cell::new(BytePageSize::Size4),
485 rd_batch: Cell::new(0),
486 rd_small: Cell::new(0),
487 extensions: Extensions::default(),
488 });
489 inner.reset_read_size();
490 inner.filter.set(Base::new(IoRef(inner.clone())));
491
492 let ioref = IoRef(inner);
493 ioref.0.id.set(IoManager::register(&ioref));
494
495 let hnd = io.start(IoContext::new(ioref.clone()));
497 ioref.0.handle.set(Some(hnd));
498
499 Io(UnsafeCell::new(ioref), marker::PhantomData)
500 }
501}
502
503impl<I: IoStream> From<I> for Io {
504 #[inline]
505 fn from(io: I) -> Io {
506 Io::new(io, SharedCfg::default())
507 }
508}
509
510impl IoRef {
511 fn create_empty() -> IoRef {
512 IoRef(Rc::new(IoState {
513 id: Cell::new(Id::default()),
514 cfg: SharedCfg::default().get::<IoConfig>(),
515 filter: FilterPtr::null(),
516 flags: Flags::new_stopped(),
517 error: Cell::new(None),
518 dispatch_task: LocalWaker::new(),
519 read_task: LocalWaker::new(),
520 write_task: LocalWaker::new(),
521 buffer: Stack::new(BytePageSize::Size16),
522 handle: Cell::new(None),
523 timeout: Cell::new(TimerHandle::default()),
524 shutdown_timeout: Cell::new(None),
525 wr_inflight: Cell::new(0),
526 rd_size: Cell::new(BytePageSize::Size4),
527 rd_batch: Cell::new(0),
528 rd_small: Cell::new(0),
529 extensions: Extensions::default(),
530 }))
531 }
532}
533
534impl<F> Io<F> {
535 #[inline]
536 pub fn get_ref(&self) -> IoRef {
538 self.io_ref().clone()
539 }
540
541 #[inline]
542 #[must_use]
543 pub unsafe fn take(&self) -> Self {
555 Self(UnsafeCell::new(self.take_io_ref()), marker::PhantomData)
556 }
557
558 fn take_io_ref(&self) -> IoRef {
559 unsafe { mem::replace(&mut *self.0.get(), IoRef::create_empty()) }
560 }
561
562 #[track_caller]
564 fn check_not_borrowed(&self) {
565 if self.st().buffer.is_borrowed() {
566 let tag = self.tag();
567 mem::forget(self.take_io_ref());
570 panic!("{tag}: filter chain is changed while it is in use");
571 }
572 }
573
574 fn st(&self) -> &IoState {
575 unsafe { &(*self.0.get()).0 }
576 }
577
578 fn io_ref(&self) -> &IoRef {
579 unsafe { &*self.0.get() }
580 }
581
582 #[inline]
583 pub unsafe fn set_config<T: Into<SharedCfg>>(&self, cfg: T) {
596 let cfg = cfg.into().get::<IoConfig>();
597 let page_size = cfg.write_size();
598 if self.cfg().write_size() != page_size {
599 self.st().buffer.set_page_size(page_size);
600 }
601 self.st()
602 .flags
603 .set_direct_wr_enabled(cfg.write_buf_threshold() > 0);
604 unsafe {
605 self.st().cfg.replace(cfg);
606 }
607 self.st().reset_read_size();
608 }
609}
610
611impl<F: FilterLayer, T: Filter> Io<Layer<F, T>> {
612 #[inline]
613 pub fn filter(&self) -> &F {
615 &self.st().filter.filter::<Layer<F, T>>().0
616 }
617}
618
619impl<F: Filter> Io<F> {
620 #[inline]
621 pub fn seal(self) -> Io<Sealed> {
628 self.check_not_borrowed();
629 let state = self.take_io_ref();
630 state.0.filter.seal::<F>();
631
632 Io(UnsafeCell::new(state), marker::PhantomData)
633 }
634
635 #[inline]
636 pub fn boxed(self) -> IoBoxed {
638 self.seal().into()
639 }
640
641 #[inline]
642 pub fn add_filter<U>(self, nf: U) -> Io<Layer<U, F>>
649 where
650 U: FilterLayer,
651 {
652 self.check_not_borrowed();
653 self.with_callbacks(|cb| cb.before_processing(&self));
654
655 if let Err(e) = self.st().buffer.process_write_buf_no_cb(&self) {
658 self.st().terminate_connection(Some(e));
659 }
660
661 let state = self.take_io_ref();
662
663 state.0.buffer.add_layer(state.0.cfg.write_size());
665
666 state.0.filter.add_filter::<F, U>(nf);
668
669 let io = Io(UnsafeCell::new(state), marker::PhantomData);
670
671 if let Err(e) = io.st().buffer.process_read_buf_no_cb(&io) {
673 io.st().terminate_connection(Some(e));
674 }
675 io.with_callbacks(|cb| cb.after_processing(&io));
676
677 io
678 }
679
680 #[allow(clippy::items_after_statements)]
681 pub fn map_filter<U, R>(self, f: U) -> Io<R>
688 where
689 U: FnOnce(F) -> R,
690 R: Filter,
691 {
692 self.check_not_borrowed();
693 self.with_callbacks(|cb| cb.before_processing(&self));
694
695 if let Err(e) = self.st().buffer.process_write_buf(&self) {
698 self.st().terminate_connection(Some(e));
699 }
700
701 struct Guard<'a>(&'a IoRef);
705
706 impl Drop for Guard<'_> {
707 fn drop(&mut self) {
708 let st = &self.0.0;
709 st.force_close_connection();
710 st.buffer.release();
711 drop(st.extensions.take_callbacks());
712 }
713 }
714
715 let guard = Guard(self.io_ref());
716 self.st().filter.map_filter::<F, U, R>(f);
717 mem::forget(guard);
718
719 let state = self.take_io_ref();
720 let io = Io(UnsafeCell::new(state), marker::PhantomData);
721 io.with_callbacks(|cb| cb.after_processing(&io));
722 io
723 }
724}
725
726impl<F> Io<F> {
727 pub async fn recv<U>(&self, codec: &U) -> Result<Option<U::Item>, Either<U::Error, io::Error>>
748 where
749 U: Decoder,
750 {
751 loop {
752 return match poll_fn(|cx| self.poll_recv(codec, cx)).await {
753 Ok(item) => Ok(Some(item)),
754 Err(RecvError::Timeout) => Err(Either::Right(io::Error::new(
755 io::ErrorKind::TimedOut,
756 "Timeout",
757 ))),
758 Err(RecvError::WriteBackpressure) => {
759 let timed_out = poll_fn(|cx| {
760 if self.st().flags.check_dispatcher_timeout() {
761 Poll::Ready(Ok(true))
762 } else {
763 self.poll_flush(cx, false).map_ok(|()| false)
764 }
765 })
766 .await
767 .map_err(Either::Right)?;
768
769 if timed_out {
770 Err(Either::Right(io::Error::new(
771 io::ErrorKind::TimedOut,
772 "Timeout",
773 )))
774 } else {
775 continue;
776 }
777 }
778 Err(RecvError::Decoder(err)) => Err(Either::Left(err)),
779 Err(RecvError::PeerGone(Some(err))) => Err(Either::Right(err)),
780 Err(RecvError::PeerGone(None)) => {
781 let st = self.st();
782 if st.flags.is_read_eof() && st.buffer.read_dst_size() != 0 {
783 Err(Either::Right(io::Error::new(
784 io::ErrorKind::UnexpectedEof,
785 "bytes remaining on stream",
786 )))
787 } else {
788 Ok(None)
789 }
790 }
791 };
792 }
793 }
794
795 pub async fn read_exact(&self, dst: &mut [u8]) -> io::Result<()> {
806 loop {
807 let completed = self.with_read_dst(|buf| {
808 if buf.len() >= dst.len() {
809 let _ = io::Read::read(buf, dst).expect("Cannot fail");
810 true
811 } else {
812 false
813 }
814 });
815 if completed {
816 return Ok(());
817 }
818 if self.read_more().await?.is_none() {
820 return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "Disconnected"));
821 }
822 }
823 }
824
825 #[inline]
826 pub async fn read_more(&self) -> io::Result<Option<()>> {
838 poll_fn(|cx| self.poll_read_more(cx)).await
839 }
840
841 #[inline]
842 pub async fn read_notify(&self) -> io::Result<Option<()>> {
853 poll_fn(|cx| self.poll_read_notify(cx)).await
854 }
855
856 #[inline]
857 pub async fn send<U>(&self, item: U::Item, codec: &U) -> Result<(), Either<U::Error, io::Error>>
864 where
865 U: Encoder,
866 {
867 self.encode(item, codec).map_err(Either::Left)?;
868
869 self.st()
870 .with_write_timeout(|cx| self.poll_flush(cx, true))
871 .await
872 .map_err(Either::Right)?;
873
874 Ok(())
875 }
876
877 #[inline]
878 pub async fn flush(&self, full: bool) -> io::Result<()> {
888 self.st()
889 .with_write_timeout(|cx| self.poll_flush(cx, full))
890 .await
891 }
892
893 #[inline]
894 pub async fn shutdown(&self) -> io::Result<()> {
910 poll_fn(|cx| self.poll_shutdown(cx)).await
911 }
912
913 #[inline]
914 pub fn poll_read_more(&self, cx: &mut Context<'_>) -> Poll<io::Result<Option<()>>> {
944 let st = self.st();
945
946 if st.flags.is_peer_gone() {
947 if let Some(err) = st.error() {
948 Poll::Ready(Err(err))
949 } else {
950 Poll::Ready(Ok(None))
951 }
952 } else {
953 let ready = st.flags.is_read_ready();
954
955 if st.flags.is_read_eof() && !ready {
956 return Poll::Ready(Ok(None));
957 }
958
959 if st.flags.is_read_paused_or_backpressure() || st.flags.is_read_wr_backpressure() {
962 st.flags.unset_read_ready_and_backpressure();
963 st.flags.unset_read_paused();
964 st.flags.unset_read_wr_backpressure();
965 st.wake_read_task();
966 if ready {
967 Poll::Ready(Ok(Some(())))
968 } else {
969 st.dispatch_task.register(cx.waker());
970 Poll::Pending
971 }
972 } else if ready {
973 Poll::Ready(Ok(Some(())))
974 } else {
975 st.dispatch_task.register(cx.waker());
976 Poll::Pending
977 }
978 }
979 }
980
981 #[inline]
982 pub fn poll_read_notify(&self, cx: &mut Context<'_>) -> Poll<io::Result<Option<()>>> {
996 let st = self.st();
997 if st.flags.is_stopping_or_terminating() {
998 if let Some(err) = st.error() {
999 Poll::Ready(Err(err))
1000 } else {
1001 Poll::Ready(Ok(None))
1002 }
1003 } else if st.flags.is_read_eof() {
1004 let notified = st.flags.take_read_notified();
1005 if notified && st.flags.is_read_ready() {
1006 Poll::Ready(Ok(Some(())))
1007 } else {
1008 Poll::Ready(Ok(None))
1009 }
1010 } else if st.flags.take_read_notified() {
1011 Poll::Ready(Ok(Some(())))
1012 } else {
1013 st.flags.set_read_notify();
1014 let _ = self.poll_read_more(cx);
1019 st.dispatch_task.register(cx.waker());
1020 Poll::Pending
1021 }
1022 }
1023
1024 #[inline]
1025 pub fn poll_recv<U>(
1033 &self,
1034 codec: &U,
1035 cx: &mut Context<'_>,
1036 ) -> Poll<Result<U::Item, RecvError<U>>>
1037 where
1038 U: Decoder,
1039 {
1040 let decoded = self.poll_recv_decode(codec, cx)?;
1041
1042 if let Some(item) = decoded.item {
1043 Poll::Ready(Ok(item))
1044 } else {
1045 Poll::Pending
1046 }
1047 }
1048
1049 #[inline]
1050 pub fn poll_recv_decode<U>(
1071 &self,
1072 codec: &U,
1073 cx: &mut Context<'_>,
1074 ) -> Result<Decoded<U::Item>, RecvError<U>>
1075 where
1076 U: Decoder,
1077 {
1078 let st = self.st();
1079 st.flags.unset_read_ready();
1080
1081 let closed = st.flags.is_stopping() || st.flags.is_terminating();
1082 if !closed {
1083 if st.flags.check_dispatcher_timeout() {
1084 return Err(RecvError::Timeout);
1085 } else if st.flags.is_wr_backpressure() {
1086 return Err(RecvError::WriteBackpressure);
1087 }
1088 }
1089
1090 let decoded = self
1091 .decode_item(codec)
1092 .map_err(|err| RecvError::Decoder(err))?;
1093
1094 if decoded.item.is_some() {
1095 Ok(decoded)
1096 } else if st.flags.is_stopping() || st.flags.is_terminating() {
1097 Err(RecvError::PeerGone(st.error()))
1098 } else {
1099 match self.poll_read_more(cx) {
1100 Poll::Pending | Poll::Ready(Ok(Some(()))) => {
1101 #[cfg(feature = "trace")]
1102 if decoded.remains != 0 {
1103 log::trace!("{}: Not enough data to decode next frame", self.tag());
1104 }
1105 Ok(decoded)
1106 }
1107 Poll::Ready(Err(e)) => Err(RecvError::PeerGone(Some(e))),
1108 Poll::Ready(Ok(None)) => Err(RecvError::PeerGone(None)),
1109 }
1110 }
1111 }
1112
1113 #[inline]
1114 pub fn poll_flush(&self, cx: &mut Context<'_>, full: bool) -> Poll<io::Result<()>> {
1127 let st = self.st();
1128
1129 st.buffer.process_write_buf_force(self)?;
1131 self.consolidate_write_state(false)?;
1132
1133 let len = st.write_outstanding();
1134 if len > 0 {
1135 if st.flags.is_peer_gone() {
1136 return Poll::Ready(Err(st.error_or_disconnected()));
1137 } else if full {
1138 st.flags.set_wants_write_flush();
1139 st.dispatch_task.register(cx.waker());
1140 return Poll::Pending;
1141 } else if st.flags.is_wr_backpressure() {
1142 if !st.should_disable_wr_backpressure(len) {
1143 st.dispatch_task.register(cx.waker());
1144 return Poll::Pending;
1145 }
1146 } else if st.is_wr_backpressure_needed(len) {
1147 st.flags.set_wr_backpressure();
1148 st.dispatch_task.register(cx.waker());
1149 return Poll::Pending;
1150 }
1151 }
1152 if st.flags.is_peer_gone() && !st.flags.is_write_flush() {
1153 Poll::Ready(Err(st.error_or_disconnected()))
1154 } else {
1155 st.flags.unset_wr_backpressure_and_flush();
1156 Poll::Ready(Ok(()))
1157 }
1158 }
1159
1160 #[inline]
1161 pub fn poll_shutdown(&self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1166 let st = self.st();
1167
1168 if st.flags.is_closed() {
1169 if let Some(err) = st.error() {
1170 Poll::Ready(Err(err))
1171 } else {
1172 Poll::Ready(Ok(()))
1173 }
1174 } else {
1175 if !st.flags.is_terminating() && !st.flags.is_stopping_filters() {
1176 st.start_shutdown();
1177 }
1178 if st.flags.is_read_paused() {
1194 st.flags.unset_read_paused();
1195 st.wake_read_task();
1196 }
1197 st.dispatch_task.register(cx.waker());
1198 Poll::Pending
1199 }
1200 }
1201
1202 #[inline]
1203 pub fn poll_read_pause(&self, cx: &mut Context<'_>) -> Poll<IoStatusUpdate> {
1217 let st = self.st();
1218 if !st.flags.is_read_paused() {
1219 st.wake_read_task();
1220 st.flags.set_read_paused();
1221 }
1222 self.poll_status_update(cx)
1223 }
1224
1225 #[inline]
1226 pub fn poll_status_update(&self, cx: &mut Context<'_>) -> Poll<IoStatusUpdate> {
1236 let st = self.st();
1237 st.dispatch_task.register(cx.waker());
1238 if st.flags.is_peer_gone() {
1239 Poll::Ready(IoStatusUpdate::PeerGone(st.error()))
1240 } else if st.flags.check_dispatcher_timeout() {
1241 Poll::Ready(IoStatusUpdate::Timeout)
1242 } else if st.flags.is_wr_backpressure() {
1243 if st.should_disable_wr_backpressure(st.write_outstanding()) {
1245 st.flags.unset_wr_backpressure();
1246 Poll::Pending
1247 } else {
1248 Poll::Ready(IoStatusUpdate::WriteBackpressure)
1249 }
1250 } else {
1251 Poll::Pending
1252 }
1253 }
1254
1255 #[inline]
1256 pub fn register_dispatch(&self, cx: &mut Context<'_>) {
1258 self.st().dispatch_task.register(cx.waker());
1259 }
1260}
1261
1262impl<F> AsRef<IoRef> for Io<F> {
1263 #[inline]
1264 fn as_ref(&self) -> &IoRef {
1265 self.io_ref()
1266 }
1267}
1268
1269impl<F> Eq for Io<F> {}
1270
1271impl<F> PartialEq for Io<F> {
1272 #[inline]
1273 fn eq(&self, other: &Self) -> bool {
1274 self.io_ref().eq(other.io_ref())
1275 }
1276}
1277
1278impl<F> hash::Hash for Io<F> {
1279 #[inline]
1280 fn hash<H: hash::Hasher>(&self, state: &mut H) {
1281 self.io_ref().hash(state);
1282 }
1283}
1284
1285impl<F> fmt::Debug for Io<F> {
1286 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1287 f.debug_struct("Io").field("state", self.st()).finish()
1288 }
1289}
1290
1291impl<F> ops::Deref for Io<F> {
1292 type Target = IoRef;
1293
1294 #[inline]
1295 fn deref(&self) -> &Self::Target {
1296 self.io_ref()
1297 }
1298}
1299
1300impl<F> Drop for Io<F> {
1301 fn drop(&mut self) {
1302 let st = self.st();
1303 self.stop_timer();
1304
1305 let in_use = st.filter.is_set() && st.buffer.is_borrowed();
1307
1308 if st.filter.is_set() {
1309 if in_use {
1310 st.force_close_connection();
1312 st.filter.leak();
1313 } else {
1314 if !st.flags.is_closed() {
1317 log::trace!("{}: Io is dropped, terminate connection", st.tag());
1318 }
1319
1320 if st.write_outstanding() == 0 {
1321 st.terminate_connection(None);
1325 } else {
1326 st.force_close_connection();
1331 }
1332 st.filter.drop_filter::<F>();
1333 }
1334
1335 st.buffer.release();
1339
1340 drop(st.extensions.take_callbacks());
1344 }
1345
1346 IoManager::unregister(self.io_ref());
1347
1348 assert!(
1350 !in_use || std::thread::panicking(),
1351 "{}: Io is dropped while its filter is in use",
1352 st.tag()
1353 );
1354 }
1355}
1356
1357fn as_u32(v: usize) -> u32 {
1359 u32::try_from(v).unwrap_or(u32::MAX)
1360}
1361
1362#[cfg(test)]
1363mod tests {
1364 use std::{cell::Cell, rc::Rc};
1365
1366 use ntex_bytes::{BufMut, BytePages, Bytes, BytesMut};
1367 use ntex_codec::BytesCodec;
1368 use ntex_util::{future::lazy, time::Millis, time::sleep, time::timeout};
1369
1370 use super::*;
1371 use crate::waiters::{TAG_DISCONNECT, WaiterEntry};
1372 use crate::{
1373 FilterBuf, IoContext, IoTaskStatus, Readiness, Waiter, ops::Iops, testing::IoTest,
1374 };
1375 use std::pin::Pin;
1376
1377 const BIN: &[u8] = b"GET /test HTTP/1\r\n\r\n";
1378 const TEXT: &str = "GET /test HTTP/1\r\n\r\n";
1379 const BIN2: &[u8] = b"12345678901234561234567890123456";
1380
1381 #[ntex::test]
1382 async fn test_basics() {
1383 let (client, server) = IoTest::create();
1384 client.remote_buffer_cap(1024);
1385
1386 let server = Io::from(server);
1387 assert!(server.eq(&server));
1388 assert!(server.io_ref().eq(server.io_ref()));
1389 }
1390
1391 #[ntex::test]
1392 async fn test_recv() {
1393 let (client, server) = IoTest::create();
1394 client.remote_buffer_cap(1024);
1395
1396 let server = Io::new(server, SharedCfg::new("SRV"));
1397
1398 server.st().notify_timeout();
1399 let err = server.recv(&BytesCodec).await.err().unwrap();
1400 assert!(format!("{err:?}").contains("Timeout"));
1401
1402 client.write(TEXT);
1403 server.st().flags.set_wr_backpressure();
1404 let item = server.recv(&BytesCodec).await.ok().unwrap().unwrap();
1405 assert_eq!(item, TEXT);
1406 }
1407
1408 fn read_size_io(min: BytePageSize, max: BytePageSize) -> Io {
1409 Io::new(
1410 IoTest::create().1,
1411 SharedCfg::new("SRV").add(IoConfig::default().set_read_size(min, max)),
1412 )
1413 }
1414
1415 #[ntex::test]
1418 async fn read_size_grows_with_batch() {
1419 let io = Io::new(IoTest::create().1, SharedCfg::new("SRV"));
1420 let st = io.st();
1421 assert_eq!(st.read_size(), BytePageSize::Size4);
1422 assert_eq!(st.get_read_buf().capacity(), BytePageSize::Size4.capacity());
1423
1424 st.track_read(BytePageSize::Size4.capacity() - 1, false);
1426 assert_eq!(st.read_size(), BytePageSize::Size4);
1427
1428 st.track_read(3000, true);
1431 assert_eq!(st.read_size(), BytePageSize::Size4);
1432 st.track_read(3000, true);
1433 assert_eq!(st.read_size(), BytePageSize::Size8);
1434 st.track_read(10_000, false);
1435 assert_eq!(st.read_size(), BytePageSize::Size16);
1436 assert_eq!(
1437 st.get_read_buf().capacity(),
1438 BytePageSize::Size16.capacity()
1439 );
1440
1441 st.track_read(0, false);
1443 assert_eq!(st.read_size(), BytePageSize::Size16);
1444
1445 for _ in 0..10 {
1447 st.track_read(60_000, true);
1448 }
1449 assert_eq!(st.read_size(), BytePageSize::Size64);
1450 st.track_read(1, false);
1451 assert_eq!(st.read_size(), BytePageSize::Size64);
1452 }
1453
1454 #[ntex::test]
1457 async fn read_size_shrinks_after_small_batches() {
1458 let io = read_size_io(BytePageSize::Size8, BytePageSize::Size64);
1459 let st = io.st();
1460 assert_eq!(st.read_size(), BytePageSize::Size8);
1461 st.track_read(40_000, false);
1462 assert_eq!(st.read_size(), BytePageSize::Size48);
1463
1464 for _ in 0..RD_SHRINK_BATCHES - 1 {
1466 st.track_read(100, false);
1467 }
1468 assert_eq!(st.read_size(), BytePageSize::Size48);
1469 st.track_read(20_000, false);
1471 for _ in 0..RD_SHRINK_BATCHES - 1 {
1472 st.track_read(100, false);
1473 }
1474 assert_eq!(st.read_size(), BytePageSize::Size48);
1475 st.track_read(100, false);
1476 assert_eq!(st.read_size(), BytePageSize::Size32);
1477
1478 for _ in 0..RD_SHRINK_BATCHES * 10 {
1480 st.track_read(100, false);
1481 }
1482 assert_eq!(st.read_size(), BytePageSize::Size8);
1483 }
1484
1485 #[ntex::test]
1487 async fn read_size_fixed() {
1488 let io = read_size_io(BytePageSize::Size16, BytePageSize::Size16);
1489 let st = io.st();
1490 assert_eq!(st.read_size(), BytePageSize::Size16);
1491 for _ in 0..10 {
1492 st.track_read(60_000, true);
1493 }
1494 assert_eq!(st.read_size(), BytePageSize::Size16);
1495 for _ in 0..RD_SHRINK_BATCHES * 10 {
1496 st.track_read(1, false);
1497 }
1498 assert_eq!(st.read_size(), BytePageSize::Size16);
1499 }
1500
1501 #[ntex::test]
1504 async fn read_size_reset_by_set_config() {
1505 let io = Io::new(IoTest::create().1, SharedCfg::new("SRV"));
1506 io.st().track_read(60_000, false);
1507 assert_eq!(io.st().read_size(), BytePageSize::Size64);
1508
1509 unsafe {
1510 io.set_config(
1511 SharedCfg::new("SRV2").add(
1512 IoConfig::default().set_read_size(BytePageSize::Size8, BytePageSize::Size16),
1513 ),
1514 );
1515 }
1516 assert_eq!(io.st().read_size(), BytePageSize::Size8);
1517 io.st().track_read(60_000, false);
1518 assert_eq!(io.st().read_size(), BytePageSize::Size16);
1519 }
1520
1521 #[ntex::test]
1524 async fn read_size_follows_transport_reads() {
1525 let (client, server) = IoTest::create();
1526 let io = Io::new(server, SharedCfg::new("SRV"));
1527 assert_eq!(io.st().read_size(), BytePageSize::Size4);
1528
1529 let data = vec![7u8; 100 * 1024];
1530 client.write(&data);
1531 let mut received = 0;
1532 while received < data.len() {
1533 let item = io.recv(&BytesCodec).await.unwrap().unwrap();
1534 received += item.len();
1535 }
1536 assert_eq!(received, data.len());
1537 assert!(io.st().read_size().capacity() > BytePageSize::Size4.capacity());
1538 assert_eq!(
1539 io.cfg().read_backpressure(),
1540 BytePageSize::Size32.capacity()
1541 );
1542
1543 for _ in 0..RD_SHRINK_BATCHES * 10 {
1545 client.write(b"x");
1546 assert_eq!(io.recv(&BytesCodec).await.unwrap().unwrap(), &b"x"[..]);
1547 }
1548 assert_eq!(io.st().read_size(), BytePageSize::Size4);
1549 }
1550 #[ntex::test]
1553 async fn test_drop_releases_callbacks() {
1554 struct Cb(#[allow(dead_code)] IoRef);
1555 impl crate::IoCallbacks for Cb {
1556 fn before_processing(&self, _: &IoRef) {}
1557 fn after_processing(&self, _: &IoRef) {}
1558 }
1559
1560 let (client, server) = IoTest::create();
1561 let server = Io::new(server, SharedCfg::new("SRV"));
1562 server.register_filter_callbacks(Cb(server.get_ref()));
1563 let state = Rc::downgrade(&server.io_ref().0);
1564
1565 drop(server);
1566 client.close().await;
1567 sleep(Millis(50)).await;
1568 assert!(state.upgrade().is_none());
1569 }
1570
1571 #[ntex::test]
1574 async fn test_callbacks_not_registered_after_drop_or_close() {
1575 struct Cb(#[allow(dead_code)] IoRef, Rc<Cell<usize>>);
1576 impl crate::IoCallbacks for Cb {
1577 fn before_processing(&self, _: &IoRef) {
1578 self.1.set(self.1.get() + 1);
1579 }
1580 fn after_processing(&self, _: &IoRef) {}
1581 }
1582
1583 let (client, server) = IoTest::create();
1585 let server = Io::new(server, SharedCfg::new("SRV"));
1586 let io = server.get_ref();
1587 let state = Rc::downgrade(&io.0);
1588 drop(server);
1589 io.register_filter_callbacks(Cb(io.clone(), Rc::default()));
1590 drop(io);
1591 client.close().await;
1592 sleep(Millis(50)).await;
1593 assert!(state.upgrade().is_none());
1594
1595 let (client, server) = IoTest::create();
1597 let server = Io::new(server, SharedCfg::new("SRV"));
1598 client.close().await;
1599 server.close();
1600 let _ = server.shutdown().await;
1601 assert!(server.is_closed());
1602 let calls = Rc::new(Cell::new(0));
1603 server.register_filter_callbacks(Cb(server.get_ref(), calls.clone()));
1604 server.with_callbacks(|cb| cb.before_processing(&server));
1605 assert_eq!(calls.get(), 0);
1606 }
1607
1608 #[ntex::test]
1609 async fn test_stop_timer_clears_timeout_notification() {
1610 let (_client, server) = IoTest::create();
1611 let server = Io::new(server, SharedCfg::new("SRV"));
1612
1613 server.start_timer(ntex_util::time::Seconds(10));
1614 server.notify_timeout();
1615 server.stop_timer();
1616
1617 assert!(lazy(|cx| server.poll_status_update(cx)).await.is_pending());
1618 }
1619
1620 #[ntex::test]
1621 async fn test_read() {
1622 let (client, server) = IoTest::create();
1623 client.remote_buffer_cap(1024);
1624
1625 let server = Io::new(server, SharedCfg::new("SRV"));
1626
1627 client.write(b"1234");
1628 let mut buf: [u8; 4] = [0, 0, 0, 0];
1629 server.read_exact(&mut buf).await.unwrap();
1630 assert_eq!(&buf, b"1234");
1631
1632 let fut = ntex_rt::spawn(async move {
1634 let mut buf: [u8; 4] = [0, 0, 0, 0];
1635 let err = server.read_exact(&mut buf).await.unwrap_err();
1636 (server, err)
1637 });
1638 client.close().await;
1639 let (server, err) = fut.await.unwrap();
1640 assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof);
1641
1642 let err = server.read_exact(&mut [0]).await.unwrap_err();
1643 assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof);
1644 }
1645
1646 #[ntex::test]
1647 async fn test_read_partial_eof() {
1648 let (client, server) = IoTest::create();
1649 client.remote_buffer_cap(1024);
1650
1651 let server = Io::new(server, SharedCfg::new("SRV"));
1652
1653 client.write(b"12");
1654 client.close().await;
1655
1656 let err = server.read_exact(&mut [0; 4]).await.unwrap_err();
1657 assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof);
1658
1659 let mut buf = [0; 2];
1660 server.read_exact(&mut buf).await.unwrap();
1661 assert_eq!(&buf, b"12");
1662
1663 let err = server.read_exact(&mut [0]).await.unwrap_err();
1664 assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof);
1665 }
1666
1667 #[ntex::test]
1668 async fn test_send() {
1669 let (client, server) = IoTest::create();
1670 client.remote_buffer_cap(1024);
1671
1672 let server = Io::from(server);
1673 assert!(server.eq(&server));
1674
1675 server
1676 .send(Bytes::from_static(BIN), &BytesCodec)
1677 .await
1678 .ok()
1679 .unwrap();
1680 let item = client.read_any();
1681 assert_eq!(item, TEXT);
1682 }
1683
1684 #[ntex::test]
1685 async fn read() {
1686 let io = Io::new(
1687 IoTest::create().0,
1688 SharedCfg::new("SRV").add(
1689 IoConfig::default()
1690 .set_read_size(BytePageSize::Size4, BytePageSize::Size4)
1691 .set_read_backpressure(BytePageSize::Size4.capacity()),
1692 ),
1693 );
1694 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_pending());
1695 assert!(io.st().dispatch_task.is_set());
1696
1697 let high = BytePageSize::Size4.capacity();
1698 let half = high / 2;
1699 let data: Vec<u8> = (0..=u8::MAX).cycle().take(high + 2).collect();
1700 let ctx = IoContext::new(io.get_ref());
1701
1702 assert_eq!(
1704 lazy(|cx| ctx.poll_read_ready(cx)).await,
1705 Poll::Ready(Readiness::Ready)
1706 );
1707 assert!(io.st().read_task.is_set());
1708 assert!(!io.st().flags.is_read_ready());
1709 assert!(!io.st().flags.is_rd_backpressure());
1710 assert!(!io.is_rd_backpressure());
1711 assert!(!io.is_wr_backpressure());
1712
1713 ctx.release_read_buf(
1715 BytesMut::copy_from_slice(&data),
1716 Poll::Ready(Ok(data.len())),
1717 );
1718
1719 assert!(!io.st().dispatch_task.is_set());
1721 assert!(io.st().flags.is_read_paused());
1723 assert!(io.st().flags.is_read_ready());
1725 assert!(io.st().flags.is_rd_backpressure());
1727 assert!(io.is_rd_backpressure());
1728 assert!(!io.is_wr_backpressure());
1729 assert_eq!(lazy(|cx| ctx.poll_read_ready(cx)).await, Poll::Pending);
1731
1732 assert_eq!(io.with_read_dst(|buf| buf.split_to(1)), &data[..1]);
1734 assert!(io.st().flags.is_read_ready());
1736 assert!(io.st().flags.is_rd_backpressure());
1738
1739 assert!(io.st().read_task.is_set());
1741
1742 assert_eq!(io.with_read_dst(|buf| buf.split_to(1)), &data[1..2]);
1744 assert!(io.st().flags.is_rd_backpressure());
1746
1747 assert_eq!(io.with_read_dst(|buf| buf.split_to(1)), &data[2..3]);
1749 assert!(io.st().flags.is_rd_backpressure());
1750 assert!(io.st().flags.is_read_paused());
1751
1752 let n = high - 1 - half;
1754 assert_eq!(io.with_read_dst(|buf| buf.split_to(n)), &data[3..3 + n]);
1755 assert!(!io.st().flags.is_read_paused());
1757 assert!(!io.st().flags.is_read_ready());
1759 assert!(!io.st().flags.is_rd_backpressure());
1761 assert!(!io.st().read_task.is_set());
1763 assert_eq!(
1764 lazy(|cx| ctx.poll_read_ready(cx)).await,
1765 Poll::Ready(Readiness::Ready)
1766 );
1767
1768 lazy(|cx| io.register_dispatch(cx)).await;
1770
1771 ctx.release_read_buf(
1773 BytesMut::copy_from_slice(vec![b'a'; half]),
1774 Poll::Ready(Ok(half)),
1775 );
1776
1777 assert!(!io.st().dispatch_task.is_set());
1779 assert!(io.st().flags.is_read_paused());
1781 assert!(io.st().flags.is_read_ready());
1783 assert!(io.st().flags.is_rd_backpressure());
1785 assert_eq!(lazy(|cx| ctx.poll_read_ready(cx)).await, Poll::Pending);
1787
1788 assert_eq!(io.with_read_dst(|buf| buf.split_to(half)), &data[3 + n..]);
1790 assert!(!io.st().flags.is_rd_backpressure());
1792
1793 lazy(|cx| io.register_dispatch(cx)).await;
1795
1796 ctx.release_read_buf(
1798 BytesMut::copy_from_slice(vec![b'b'; half - 1]),
1799 Poll::Ready(Ok(half - 1)),
1800 );
1801
1802 assert!(!io.st().flags.is_read_paused());
1804 assert!(io.st().flags.is_read_ready());
1806 assert!(!io.st().flags.is_rd_backpressure());
1808 assert_eq!(
1810 lazy(|cx| ctx.poll_read_ready(cx)).await,
1811 Poll::Ready(Readiness::Ready)
1812 );
1813
1814 let item = io.with_read_dst(BytesMut::take);
1816 assert_eq!(item.len(), high - 1);
1817 assert_eq!(&item[..half], &vec![b'a'; half][..]);
1818 assert_eq!(&item[half..], &vec![b'b'; half - 1][..]);
1819 assert!(!io.st().flags.is_read_paused());
1821 assert!(!io.st().flags.is_read_ready());
1823 assert!(io.st().read_task.is_set());
1825
1826 io.terminate();
1828 assert!(!io.st().read_task.is_set());
1830 assert_eq!(
1832 lazy(|cx| ctx.poll_read_ready(cx)).await,
1833 Poll::Ready(Readiness::Terminate)
1834 );
1835 }
1836
1837 #[ntex::test]
1838 async fn only_force_close_reports_terminate() {
1839 let io = Io::new(IoTest::create().0, SharedCfg::new("SRV"));
1841 let ctx = IoContext::new(io.get_ref());
1842 ctx.stop(Some(io::Error::other("transport failed")));
1843 assert!(io.st().flags.is_terminating());
1844 assert!(!io.st().flags.is_force_closing());
1845 assert_eq!(
1846 lazy(|cx| ctx.poll_read_ready(cx)).await,
1847 Poll::Ready(Readiness::Close)
1848 );
1849 assert_eq!(
1850 lazy(|cx| ctx.poll_write_ready(cx)).await,
1851 Poll::Ready(Readiness::Close)
1852 );
1853
1854 let io = Io::new(IoTest::create().0, SharedCfg::new("SRV"));
1856 let ctx = IoContext::new(io.get_ref());
1857 io.close();
1858 io.st().filters_stopped();
1859 assert!(io.st().flags.is_stopping());
1860 ctx.stop(Some(io::Error::other("transport failed")));
1861 assert_eq!(
1862 lazy(|cx| ctx.poll_write_ready(cx)).await,
1863 Poll::Ready(Readiness::Close)
1864 );
1865
1866 let io = Io::new(IoTest::create().0, SharedCfg::new("SRV"));
1868 let ctx = IoContext::new(io.get_ref());
1869 io.terminate();
1870 assert!(io.st().flags.is_force_closing());
1871 assert_eq!(
1872 lazy(|cx| ctx.poll_read_ready(cx)).await,
1873 Poll::Ready(Readiness::Terminate)
1874 );
1875 assert_eq!(
1876 lazy(|cx| ctx.poll_write_ready(cx)).await,
1877 Poll::Ready(Readiness::Terminate)
1878 );
1879 }
1880
1881 #[ntex::test]
1882 async fn drop_closes_gracefully_once_output_is_flushed() {
1883 let io = Io::new(IoTest::create().0, SharedCfg::new("SRV"));
1886 let ioref = io.get_ref();
1887 let ctx = IoContext::new(io.get_ref());
1888 assert_eq!(io.st().write_outstanding(), 0);
1889 drop(io);
1890 assert!(!ioref.0.flags.is_force_closing());
1891 assert_eq!(
1892 lazy(|cx| ctx.poll_read_ready(cx)).await,
1893 Poll::Ready(Readiness::Close)
1894 );
1895 assert_eq!(
1896 lazy(|cx| ctx.poll_write_ready(cx)).await,
1897 Poll::Ready(Readiness::Close)
1898 );
1899 }
1900
1901 #[ntex::test]
1902 async fn drop_aborts_when_output_would_be_lost() {
1903 let io = Io::new(IoTest::create().0, SharedCfg::new("SRV"));
1907 let ioref = io.get_ref();
1908 let ctx = IoContext::new(io.get_ref());
1909 io.encode_slice(b"not delivered").unwrap();
1910 assert_ne!(io.st().write_outstanding(), 0);
1911 drop(io);
1912 assert!(ioref.0.flags.is_force_closing());
1913 assert_eq!(
1914 lazy(|cx| ctx.poll_read_ready(cx)).await,
1915 Poll::Ready(Readiness::Terminate)
1916 );
1917 assert_eq!(
1918 lazy(|cx| ctx.poll_write_ready(cx)).await,
1919 Poll::Ready(Readiness::Terminate)
1920 );
1921 }
1922
1923 #[ntex::test]
1924 async fn drop_releases_buffers() {
1925 let io = Io::new(IoTest::create().0, SharedCfg::new("SRV"));
1928 let ioref = io.get_ref();
1929 let ctx = IoContext::new(io.get_ref());
1930 ctx.release_read_buf(BytesMut::copy_from_slice(b"unread"), Poll::Ready(Ok(6)));
1931 io.encode_slice(b"not delivered").unwrap();
1932 assert_eq!(ioref.0.buffer.read_dst_size(), 6);
1933 assert_ne!(ioref.0.buffer.write_buf_size(), 0);
1934
1935 drop(io);
1936 assert_eq!(ioref.0.buffer.read_dst_size(), 0);
1937 assert!(ioref.0.buffer.get_read_buf().is_none());
1938 assert_eq!(ioref.0.buffer.write_buf_size(), 0);
1939
1940 ctx.release_read_buf(BytesMut::copy_from_slice(b"late"), Poll::Ready(Ok(4)));
1942 assert!(ioref.0.buffer.get_read_buf().is_none());
1943 ctx.with_read_buf(|buf| {
1944 buf.extend_from_slice(b"late");
1945 Poll::Ready(Ok(4))
1946 });
1947 assert!(ioref.0.buffer.get_read_buf().is_none());
1948 assert_eq!(ioref.0.buffer.read_dst_size(), 0);
1949 }
1950
1951 #[ntex::test]
1952 async fn force_close_survives_filter_replacement() {
1953 let io = Io::new(IoTest::create().0, SharedCfg::new("SRV"));
1956 let ctx = IoContext::new(io.get_ref());
1957 io.terminate();
1958 drop(io);
1959 assert_eq!(
1960 lazy(|cx| ctx.poll_read_ready(cx)).await,
1961 Poll::Ready(Readiness::Terminate)
1962 );
1963 assert_eq!(
1964 lazy(|cx| ctx.poll_write_ready(cx)).await,
1965 Poll::Ready(Readiness::Terminate)
1966 );
1967 }
1968
1969 #[ntex::test]
1970 async fn read_notify() {
1971 let io = Io::new(
1972 IoTest::create().0,
1973 SharedCfg::new("SRV").add(
1974 IoConfig::default()
1975 .set_read_size(BytePageSize::Size4, BytePageSize::Size4)
1976 .set_read_backpressure(BytePageSize::Size4.capacity()),
1977 ),
1978 );
1979 assert!(!io.st().flags.is_read_notify());
1980 assert!(lazy(|cx| io.poll_read_notify(cx)).await.is_pending());
1981 assert!(io.st().dispatch_task.is_set());
1982 assert!(io.st().flags.is_read_notify());
1983
1984 let ctx = IoContext::new(io.get_ref());
1985
1986 ctx.release_read_buf(BytesMut::copy_from_slice(b"1"), Poll::Ready(Ok(1)));
1988
1989 assert!(!io.st().dispatch_task.is_set());
1990 assert!(io.st().flags.is_read_ready());
1992 assert!(io.st().flags.is_read_notify());
1993 assert!(io.st().flags.is_read_notified());
1995 let res = lazy(|cx| io.poll_read_notify(cx)).await;
1996 assert!(matches!(res, Poll::Ready(Ok(Some(())))));
1997
1998 assert!(!io.st().dispatch_task.is_set());
2000 assert!(io.st().flags.is_read_ready());
2002
2003 assert!(lazy(|cx| io.poll_read_notify(cx)).await.is_pending());
2005 assert!(io.st().dispatch_task.is_set());
2006 assert!(io.st().flags.is_read_notify());
2007 assert!(io.st().flags.is_read_ready());
2008 assert_eq!(
2010 lazy(|cx| ctx.poll_read_ready(cx)).await,
2011 Poll::Ready(Readiness::Ready)
2012 );
2013
2014 let len = BytePageSize::Size4.capacity() - 1;
2016 ctx.release_read_buf(
2017 BytesMut::copy_from_slice(vec![b'2'; len]),
2018 Poll::Ready(Ok(len)),
2019 );
2020 assert!(io.st().flags.is_rd_backpressure());
2022
2023 assert!(io.st().flags.is_read_ready());
2025 assert!(io.st().flags.is_read_notify());
2026 assert!(io.st().flags.is_read_notified());
2028 let res = lazy(|cx| io.poll_read_notify(cx)).await;
2029 assert!(matches!(res, Poll::Ready(Ok(Some(())))));
2030 assert_eq!(lazy(|cx| ctx.poll_read_ready(cx)).await, Poll::Pending);
2032 assert!(io.st().read_task.is_set());
2034
2035 assert!(lazy(|cx| io.poll_read_notify(cx)).await.is_pending());
2037 assert!(!io.st().flags.is_rd_backpressure());
2039 assert!(!io.st().flags.is_read_ready());
2040 assert!(!io.st().flags.is_read_paused());
2041 assert!(!io.st().read_task.is_set());
2043 assert_eq!(
2045 lazy(|cx| ctx.poll_read_ready(cx)).await,
2046 Poll::Ready(Readiness::Ready)
2047 );
2048
2049 ctx.release_read_buf(BytesMut::copy_from_slice(b"1"), Poll::Ready(Ok(1)));
2051 assert!(!io.st().dispatch_task.is_set());
2052 assert!(io.st().flags.is_read_ready());
2054 assert!(io.st().flags.is_read_notify());
2055 assert!(io.st().flags.is_read_paused());
2056 assert!(io.st().flags.is_rd_backpressure());
2057 assert!(io.st().flags.is_read_notified());
2059 assert!(matches!(
2060 lazy(|cx| io.poll_read_notify(cx)).await,
2061 Poll::Ready(Ok(Some(())))
2062 ));
2063
2064 io.terminate();
2066 let res = lazy(|cx| io.poll_read_notify(cx)).await;
2067 assert!(matches!(res, Poll::Ready(Ok(None))), "{res:?}");
2068 }
2069
2070 #[ntex::test]
2071 async fn read_more() {
2072 let (client, server) = IoTest::create();
2073 client.remote_buffer_cap(1024);
2074
2075 let io = Io::from(server);
2076 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_pending());
2077
2078 client.write(TEXT);
2079 assert_eq!(io.read_more().await.unwrap(), Some(()));
2080 assert!(matches!(
2081 lazy(|cx| io.poll_read_more(cx)).await,
2082 Poll::Ready(Ok(Some(())))
2083 ));
2084
2085 let item = io.with_read_dst(BytesMut::take);
2086 assert_eq!(item, Bytes::from_static(BIN));
2087
2088 client.write(TEXT);
2089 sleep(Millis(50)).await;
2090 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_ready());
2091 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_ready());
2092 }
2093
2094 #[ntex::test]
2095 async fn read_backpressure() {
2096 let (client, server) = IoTest::create();
2097
2098 let io = Io::new(
2099 server,
2100 SharedCfg::new("SRV").add(
2101 IoConfig::default()
2102 .set_read_size(BytePageSize::Size4, BytePageSize::Size4)
2103 .set_read_backpressure(BytePageSize::Size4.capacity()),
2104 ),
2105 );
2106 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_pending());
2107
2108 client.write(vec![b'x'; BytePageSize::Size4.capacity()]);
2109 sleep(Millis(50)).await;
2110 assert!(io.flags().is_read_ready());
2111 assert!(io.flags().is_rd_backpressure());
2112 let _item = io.recv(&BytesCodec).await.ok().unwrap().unwrap();
2113 assert!(!io.flags().is_read_ready());
2114 assert!(!io.flags().is_rd_backpressure());
2115
2116 client.write(vec![b'x'; BytePageSize::Size4.capacity()]);
2117 sleep(Millis(50)).await;
2118 assert!(io.flags().is_read_ready());
2119 assert!(io.flags().is_rd_backpressure());
2120 assert_eq!(io.read_more().await.unwrap(), Some(()));
2121 }
2122
2123 #[ntex::test]
2124 async fn read_src_releases_read_backpressure() {
2125 let (client, server) = IoTest::create();
2126
2127 let io = Io::new(
2128 server,
2129 SharedCfg::new("SRV").add(
2130 IoConfig::default()
2131 .set_read_size(BytePageSize::Size4, BytePageSize::Size4)
2132 .set_read_backpressure(BytePageSize::Size4.capacity()),
2133 ),
2134 );
2135 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_pending());
2136
2137 client.write(vec![b'x'; BytePageSize::Size4.capacity()]);
2138 sleep(Millis(50)).await;
2139 assert!(io.flags().is_rd_backpressure());
2140
2141 let len = io.get_ref().with_read_src(|buf| {
2144 let len = buf.len();
2145 buf.clear();
2146 len
2147 });
2148 assert!(len > 0);
2149 assert!(!io.flags().is_rd_backpressure());
2150 assert!(!io.flags().is_read_paused());
2151
2152 client.write(BIN2);
2154 sleep(Millis(50)).await;
2155 assert!(io.flags().is_read_ready());
2156 }
2157
2158 #[ntex::test]
2159 async fn with_buf_releases_read_backpressure() {
2160 let (client, server) = IoTest::create();
2161
2162 let io = Io::new(
2163 server,
2164 SharedCfg::new("SRV").add(
2165 IoConfig::default()
2166 .set_read_size(BytePageSize::Size4, BytePageSize::Size4)
2167 .set_read_backpressure(BytePageSize::Size4.capacity()),
2168 ),
2169 );
2170 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_pending());
2171
2172 client.write(vec![b'x'; BytePageSize::Size4.capacity()]);
2173 sleep(Millis(50)).await;
2174 assert!(io.flags().is_rd_backpressure());
2175
2176 let len = io
2177 .get_ref()
2178 .with_buf(|buf| {
2179 buf.with_read_buffers(|_, dst| {
2180 let len = dst.len();
2181 dst.clear();
2182 len
2183 })
2184 })
2185 .unwrap();
2186 assert!(len > 0);
2187 assert!(!io.flags().is_rd_backpressure());
2188 assert!(!io.flags().is_read_paused());
2189
2190 client.write(BIN2);
2192 sleep(Millis(50)).await;
2193 assert!(io.flags().is_read_ready());
2194 }
2195
2196 #[ntex::test]
2197 async fn write() {
2198 let io = Io::new(
2199 IoTest::create().0,
2200 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(8)),
2201 );
2202 assert!(lazy(|cx| io.poll_status_update(cx)).await.is_pending());
2203 assert!(io.st().dispatch_task.is_set());
2204 assert!(io.st().flags.is_direct_wr_enabled());
2205
2206 let ctx = IoContext::new(io.get_ref());
2207
2208 assert_eq!(lazy(|cx| ctx.poll_write_ready(cx)).await, Poll::Pending);
2210 assert!(io.st().write_task.is_set());
2211 assert!(io.st().flags.is_write_paused());
2212 assert!(!io.st().flags.is_wr_backpressure());
2213
2214 io.with_write_src(|buf| buf.put_slice(b"1234")).unwrap();
2216 assert_eq!(lazy(|cx| ctx.poll_write_ready(cx)).await, Poll::Pending);
2217 assert!(io.st().flags.is_write_paused());
2219 assert!(io.st().flags.is_wr_send_scheduled());
2221 assert!(!io.st().flags.is_wr_backpressure());
2223 assert!(io.st().dispatch_task.is_set());
2225
2226 io.with_write_src(|buf| buf.put_slice(b"5678")).unwrap();
2228 assert!(io.st().flags.is_wr_backpressure());
2230 assert!(!io.st().dispatch_task.is_set());
2232 assert!(io.st().write_task.is_set());
2234 assert!(matches!(
2236 lazy(|cx| io.poll_status_update(cx)).await,
2237 Poll::Ready(IoStatusUpdate::WriteBackpressure)
2238 ));
2239 assert!(lazy(|cx| io.poll_flush(cx, false)).await.is_pending());
2241 assert!(!io.st().flags.is_write_flush());
2243
2244 Iops::run();
2246 assert!(!io.st().flags.is_wr_send_scheduled());
2248 assert!(!io.st().flags.is_write_paused());
2250 assert!(!io.st().write_task.is_set());
2252 assert_eq!(
2254 lazy(|cx| ctx.poll_write_ready(cx)).await,
2255 Poll::Ready(Readiness::Ready)
2256 );
2257
2258 assert_eq!(ctx.with_write_dst(|buf| buf.split_to(4).freeze()), b"1234");
2260 assert_eq!(ctx.update_write_status(Ok(4)), IoTaskStatus::Io);
2262 assert_eq!(
2264 lazy(|cx| ctx.poll_write_ready(cx)).await,
2265 Poll::Ready(Readiness::Ready)
2266 );
2267 assert!(!io.st().flags.is_write_paused());
2269 assert!(io.st().flags.is_wr_backpressure());
2271 assert!(lazy(|cx| io.poll_status_update(cx)).await.is_pending());
2274 assert!(!io.st().flags.is_wr_backpressure());
2276 assert!(lazy(|cx| io.poll_status_update(cx)).await.is_pending());
2277 assert!(matches!(
2279 lazy(|cx| io.poll_flush(cx, false)).await,
2280 Poll::Ready(Ok(()))
2281 ));
2282
2283 io.with_write_src(|buf| buf.put_slice(b"1234")).unwrap();
2285 assert!(lazy(|cx| io.poll_flush(cx, true)).await.is_pending());
2286 assert!(io.st().flags.is_write_flush());
2288 assert!(io.st().flags.is_wr_backpressure());
2290
2291 Iops::run();
2293 assert_eq!(ctx.with_write_dst(BytePages::freeze), b"56781234");
2294 assert!(!io.st().flags.is_wr_send_scheduled());
2296 assert_eq!(ctx.update_write_status(Ok(8)), IoTaskStatus::Pause);
2298 assert!(io.st().flags.is_write_paused());
2300 assert!(io.st().flags.is_write_flush());
2302 assert!(io.st().flags.is_wr_backpressure());
2304 assert!(!io.st().dispatch_task.is_set());
2306
2307 assert!(matches!(
2309 lazy(|cx| io.poll_flush(cx, false)).await,
2310 Poll::Ready(Ok(()))
2311 ));
2312 assert!(!io.st().flags.is_write_flush());
2314 assert!(!io.st().flags.is_wr_backpressure());
2316
2317 io.terminate();
2319 assert!(!io.st().write_task.is_set());
2321 assert_eq!(
2323 lazy(|cx| ctx.poll_write_ready(cx)).await,
2324 Poll::Ready(Readiness::Terminate)
2325 );
2326 let Poll::Ready(Err(err)) = lazy(|cx| io.poll_flush(cx, false)).await else {
2328 panic!()
2329 };
2330 assert_eq!(err.kind(), io::ErrorKind::NotConnected);
2331 assert!(matches!(
2333 lazy(|cx| io.poll_status_update(cx)).await,
2334 Poll::Ready(IoStatusUpdate::PeerGone(None))
2335 ));
2336 }
2337
2338 #[ntex::test]
2339 async fn local_shutdown_reports_peer_gone_without_error() {
2340 let (client, server) = IoTest::create();
2341 client.remote_buffer_cap(1024);
2342 let io = Io::from(server);
2343
2344 io.shutdown().await.unwrap();
2346
2347 assert!(!io.is_active());
2348 assert!(matches!(
2349 lazy(|cx| io.poll_status_update(cx)).await,
2350 Poll::Ready(IoStatusUpdate::PeerGone(None))
2351 ));
2352 }
2353
2354 #[ntex::test]
2355 async fn set_config_updates_eager_write_support() {
2356 let io = Io::new(
2357 IoTest::create().0,
2358 SharedCfg::new("SRV").add(IoConfig::new().set_write_buf_threshold(0)),
2359 );
2360 assert!(!io.st().flags.is_direct_wr_enabled());
2361
2362 unsafe {
2364 io.set_config(SharedCfg::new("SRV").add(IoConfig::new().set_write_buf_threshold(1024)));
2365 }
2366 assert!(io.st().flags.is_direct_wr_enabled());
2367 assert_eq!(io.cfg().write_buf_threshold(), 1024);
2368
2369 unsafe {
2372 io.set_config(SharedCfg::new("SRV").add(IoConfig::new().set_write_buf_threshold(0)));
2373 }
2374 assert!(!io.st().flags.is_direct_wr_enabled());
2375 assert_eq!(io.cfg().write_buf_threshold(), 0);
2376 }
2377
2378 #[ntex::test]
2379 async fn eager_write_uses_updated_buffer_size() {
2380 #[derive(Debug)]
2381 struct DirectWrite;
2382
2383 impl IoStream for DirectWrite {
2384 fn start(self, _: IoContext) -> Box<dyn Handle> {
2385 Box::new(self)
2386 }
2387 }
2388
2389 impl Handle for DirectWrite {
2390 fn write(&self, ctx: &IoContext) {
2391 let n = ctx.with_write_dst(|buf| {
2392 let n = buf.len();
2393 buf.clear();
2394 n
2395 });
2396 let _ = ctx.update_write_status(Ok(n));
2397 }
2398 }
2399
2400 let io = Io::new(
2401 DirectWrite,
2402 SharedCfg::new("SRV").add(
2403 IoConfig::new()
2404 .set_write_buf_threshold(1)
2405 .set_write_backpressure(8),
2406 ),
2407 );
2408
2409 io.encode_slice(BIN2).unwrap();
2410
2411 assert_eq!(io.st().buffer.write_buf_size(), 0);
2412 assert!(io.flags().is_write_paused());
2413 assert!(!io.flags().is_wr_backpressure());
2414 assert!(!io.st().flags.is_wr_send_scheduled());
2415 }
2416
2417 #[ntex::test]
2418 async fn eager_write_reports_transport_error() {
2419 #[derive(Debug)]
2420 struct FailedWrite;
2421
2422 impl IoStream for FailedWrite {
2423 fn start(self, _: IoContext) -> Box<dyn Handle> {
2424 Box::new(self)
2425 }
2426 }
2427
2428 impl Handle for FailedWrite {
2429 fn write(&self, ctx: &IoContext) {
2430 ctx.update_write_status(Err(io::Error::new(
2431 io::ErrorKind::ConnectionReset,
2432 "connection reset",
2433 )));
2434 }
2435 }
2436
2437 let io = Io::new(
2438 FailedWrite,
2439 SharedCfg::new("SRV").add(IoConfig::new().set_write_buf_threshold(1)),
2440 );
2441
2442 let err = io.encode_slice(BIN2).unwrap_err();
2443 assert_eq!(err.kind(), io::ErrorKind::ConnectionReset);
2444 assert_eq!(err.to_string(), "connection reset");
2445 assert!(io.st().flags.is_terminating());
2446 }
2447
2448 #[ntex::test]
2449 async fn terminate_during_eager_write_releases_transport() {
2450 #[derive(Debug)]
2451 struct FailedWrite(Rc<Cell<bool>>);
2452
2453 impl Drop for FailedWrite {
2454 fn drop(&mut self) {
2455 self.0.set(true);
2456 }
2457 }
2458
2459 impl IoStream for FailedWrite {
2460 fn start(self, _: IoContext) -> Box<dyn Handle> {
2461 Box::new(self)
2462 }
2463 }
2464
2465 impl Handle for FailedWrite {
2466 fn write(&self, ctx: &IoContext) {
2467 ctx.update_write_status(Err(io::Error::new(
2468 io::ErrorKind::ConnectionReset,
2469 "connection reset",
2470 )));
2471 }
2472 }
2473
2474 let dropped = Rc::new(Cell::new(false));
2475 let io = Io::new(
2476 FailedWrite(dropped.clone()),
2477 SharedCfg::new("SRV").add(IoConfig::new().set_write_buf_threshold(1)),
2478 );
2479
2480 io.encode_slice(BIN2).unwrap_err();
2481 assert!(io.st().flags.is_terminating());
2482
2483 assert!(dropped.get());
2486 assert!(io.st().handle.take().is_none());
2487 }
2488
2489 #[ntex::test]
2490 async fn write_backpressure() {
2491 let (client, server) = IoTest::create();
2492 client.remote_buffer_cap(0);
2493
2494 let io = Io::new(
2495 server,
2496 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(16)),
2497 );
2498 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_pending());
2499 assert!(io.flags().is_write_paused());
2500 assert!(!io.flags().is_wr_backpressure());
2501 assert!(!io.is_wr_backpressure());
2502
2503 io.encode_slice(BIN2).unwrap();
2504 assert!(Iops::is_registered(&io));
2505 assert!(io.flags().is_wr_backpressure());
2506
2507 client.remote_buffer_cap(1024);
2508 let item = client.read().await.unwrap();
2509 assert_eq!(item, BIN2);
2510 assert!(io.flags().is_wr_backpressure());
2511 assert!(lazy(|cx| io.poll_status_update(cx)).await.is_pending());
2514 assert!(!io.flags().is_wr_backpressure());
2515 assert!(matches!(
2516 lazy(|cx| io.poll_flush(cx, false)).await,
2517 Poll::Ready(Ok(()))
2518 ));
2519 assert!(!io.flags().is_wr_backpressure());
2520 }
2521
2522 #[ntex::test]
2523 async fn partial_flush_keeps_write_backpressure_until_half_watermark() {
2524 let io = Io::new(
2525 IoTest::create().0,
2526 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(8)),
2527 );
2528 let ctx = IoContext::new(io.get_ref());
2529
2530 io.encode_slice(b"12345678").unwrap();
2531 assert!(io.flags().is_wr_backpressure());
2532
2533 assert_eq!(ctx.with_write_dst(|buf| buf.split_to(1).len()), 1);
2534 assert_eq!(ctx.update_write_status(Ok(1)), IoTaskStatus::Io);
2535 assert!(lazy(|cx| io.poll_flush(cx, false)).await.is_pending());
2536 assert!(io.flags().is_wr_backpressure());
2537
2538 assert_eq!(ctx.with_write_dst(|buf| buf.split_to(3).len()), 3);
2539 assert_eq!(ctx.update_write_status(Ok(3)), IoTaskStatus::Io);
2540 assert!(matches!(
2541 lazy(|cx| io.poll_flush(cx, false)).await,
2542 Poll::Ready(Ok(()))
2543 ));
2544 assert!(!io.flags().is_wr_backpressure());
2545 }
2546
2547 #[ntex::test]
2548 async fn write_ready_waits_for_release_threshold() {
2549 let io = Io::new(
2550 IoTest::create().0,
2551 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(8)),
2552 );
2553 let ctx = IoContext::new(io.get_ref());
2554
2555 assert!(io.write_ready().await.is_ok());
2557
2558 io.encode_slice(b"12345678").unwrap();
2559 assert!(io.flags().is_wr_backpressure());
2560
2561 let done = Rc::new(Cell::new(0));
2563 for _ in 0..2 {
2564 let (io, done) = (io.get_ref(), done.clone());
2565 ntex_util::spawn(async move {
2566 io.write_ready().await.unwrap();
2567 done.set(done.get() + 1);
2568 });
2569 }
2570 sleep(Millis(10)).await;
2571 assert_eq!(done.get(), 0);
2572
2573 assert_eq!(ctx.with_write_dst(|buf| buf.split_to(1).len()), 1);
2575 assert_eq!(ctx.update_write_status(Ok(1)), IoTaskStatus::Io);
2576 sleep(Millis(10)).await;
2577 assert_eq!(done.get(), 0);
2578
2579 assert_eq!(ctx.with_write_dst(|buf| buf.split_to(3).len()), 3);
2581 assert_eq!(ctx.update_write_status(Ok(3)), IoTaskStatus::Io);
2582 sleep(Millis(10)).await;
2583 assert_eq!(done.get(), 2);
2584 assert!(io.flags().is_wr_backpressure());
2585 assert!(io.write_ready().await.is_ok());
2586 }
2587
2588 #[ntex::test]
2589 async fn write_ready_released_during_full_flush() {
2590 let io = Io::new(
2591 IoTest::create().0,
2592 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(8)),
2593 );
2594 let ctx = IoContext::new(io.get_ref());
2595
2596 io.encode_slice(b"12345678").unwrap();
2597 assert!(lazy(|cx| io.poll_flush(cx, true)).await.is_pending());
2598 assert!(io.flags().is_write_flush());
2599
2600 let done = Rc::new(Cell::new(false));
2601 let (io2, done2) = (io.get_ref(), done.clone());
2602 ntex_util::spawn(async move {
2603 io2.write_ready().await.unwrap();
2604 done2.set(true);
2605 });
2606 sleep(Millis(10)).await;
2607 assert!(!done.get());
2608
2609 assert_eq!(ctx.with_write_dst(|buf| buf.split_to(4).len()), 4);
2610 assert_eq!(ctx.update_write_status(Ok(4)), IoTaskStatus::Io);
2611 sleep(Millis(10)).await;
2612 assert!(done.get());
2613 }
2614
2615 #[ntex::test]
2616 async fn write_ready_fails_on_disconnect() {
2617 let (client, server) = IoTest::create();
2618 client.remote_buffer_cap(0);
2619 let io = Io::new(
2620 server,
2621 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(8)),
2622 );
2623 io.encode_slice(b"12345678").unwrap();
2624 assert!(io.flags().is_wr_backpressure());
2625
2626 let res = Rc::new(Cell::new(None));
2627 let (io2, res2) = (io.get_ref(), res.clone());
2628 ntex_util::spawn(async move {
2629 res2.set(Some(io2.write_ready().await.is_err()));
2630 });
2631 sleep(Millis(10)).await;
2632 assert_eq!(res.get(), None);
2633
2634 io.terminate();
2635 sleep(Millis(10)).await;
2636 assert_eq!(res.get(), Some(true));
2637 assert!(io.write_ready().await.is_err());
2638 }
2639
2640 #[ntex::test]
2641 async fn waiter() {
2642 let (client, server) = IoTest::create();
2643 let io = Io::from(server);
2644 let (mut s1, mut s2, mut s3) = (Waiter::new(&io, 7), Waiter::new(&io, 7), io.waiter(8));
2645 assert!(lazy(|cx| Pin::new(&mut s1).poll(cx)).await.is_pending());
2646 assert!(lazy(|cx| Pin::new(&mut s2).poll(cx)).await.is_pending());
2647 assert!(lazy(|cx| Pin::new(&mut s3).poll(cx)).await.is_pending());
2648 assert!(lazy(|cx| Pin::new(&mut s1).poll(cx)).await.is_pending());
2649 assert_eq!(io.get_ref().0.extensions.wakers_len(), 3);
2650
2651 io.wake(7);
2652 assert!(lazy(|cx| Pin::new(&mut s1).poll(cx)).await.is_ready());
2653 assert!(lazy(|cx| Pin::new(&mut s2).poll(cx)).await.is_ready());
2654 assert!(lazy(|cx| Pin::new(&mut s3).poll(cx)).await.is_pending());
2655 assert_eq!(io.get_ref().0.extensions.wakers_len(), 1);
2656
2657 drop(s3);
2658 assert_eq!(io.get_ref().0.extensions.wakers_len(), 0);
2659
2660 assert!(lazy(|cx| Pin::new(&mut s1).poll(cx)).await.is_pending());
2662 let mut s1 = s1.into_static();
2663 assert_eq!(io.get_ref().0.extensions.wakers_len(), 1);
2664
2665 let s4 = s1.clone();
2667 assert_eq!(io.get_ref().0.extensions.wakers_len(), 1);
2668 drop(s4);
2669 assert_eq!(io.get_ref().0.extensions.wakers_len(), 1);
2670
2671 let res = Rc::new(Cell::new(false));
2673 let res2 = res.clone();
2674 ntex_util::spawn(async move {
2675 (&mut s1).await;
2676 res2.set(true);
2677 });
2678 sleep(Millis(10)).await;
2679 assert_eq!(io.get_ref().0.extensions.wakers_len(), 1);
2680 client.close().await;
2681 timeout(Millis(1000), io.shutdown())
2682 .await
2683 .expect("stream shutdown did not complete")
2684 .unwrap();
2685 sleep(Millis(10)).await;
2686 assert!(res.get(), "waiter was not woken on disconnect");
2687 (&mut s2).await;
2688 drop(s2);
2689 assert_eq!(io.get_ref().0.extensions.wakers_len(), 0);
2690 }
2691
2692 #[ntex::test]
2693 async fn waiter_poll_ready() {
2694 let (_client, server) = IoTest::create();
2695 let io = Io::from(server);
2696 let waiter = io.waiter(3);
2697 let ext = &io.get_ref().0.extensions;
2698
2699 io.wake(3);
2701 assert!(lazy(|cx| waiter.poll_ready(cx)).await.is_pending());
2702 assert!(lazy(|cx| waiter.poll_ready(cx)).await.is_pending());
2703 assert_eq!(ext.wakers_len(), 1);
2704
2705 io.wake(3);
2707 assert!(lazy(|cx| waiter.poll_ready(cx)).await.is_ready());
2708 assert_eq!(ext.wakers_len(), 0);
2709 assert!(lazy(|cx| waiter.poll_ready(cx)).await.is_pending());
2710 assert_eq!(ext.wakers_len(), 1);
2711
2712 io.wake(3);
2713 waiter.await;
2714 assert_eq!(ext.wakers_len(), 0);
2715 }
2716
2717 #[ntex::test]
2718 async fn wake_reserved_tag_is_ignored() {
2719 let (_client, server) = IoTest::create();
2720 let io = Io::from(server);
2721 let mut waiter = io.on_disconnect();
2722 assert!(lazy(|cx| Pin::new(&mut waiter).poll(cx)).await.is_pending());
2723 io.wake(TAG_DISCONNECT);
2724 io.wake(TAG_WRITE);
2725 assert!(lazy(|cx| Pin::new(&mut waiter).poll(cx)).await.is_pending());
2726 assert_eq!(io.get_ref().0.extensions.wakers_len(), 1);
2727 }
2728
2729 #[cfg(debug_assertions)]
2730 #[ntex::test]
2731 #[should_panic(expected = "reserved")]
2732 async fn waiter_reserved_tag() {
2733 let (_client, server) = IoTest::create();
2734 let io = Io::from(server);
2735 let _waiter = Waiter::new(&io, TAG_DISCONNECT);
2736 }
2737
2738 #[cfg(debug_assertions)]
2739 #[ntex::test]
2740 #[should_panic(expected = "reserved")]
2741 async fn waiter_reserved_tag_ioref() {
2742 let (_client, server) = IoTest::create();
2743 let io = Io::from(server);
2744 let _waiter = io.waiter(TAG_WRITE);
2745 }
2746
2747 #[ntex::test]
2748 async fn dropped_waiters_are_removed() {
2749 let (client, server) = IoTest::create();
2750 client.remote_buffer_cap(0);
2751 let io = Io::new(
2752 server,
2753 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(8)),
2754 );
2755 let ext = &io.get_ref().0.extensions;
2756
2757 for _ in 0..4 {
2758 let waiter = io.on_disconnect();
2759 assert!(lazy(|cx| waiter.poll_ready(cx)).await.is_pending());
2760 assert!(lazy(|cx| waiter.poll_ready(cx)).await.is_pending());
2761 assert_eq!(ext.wakers_len(), 1);
2762 }
2763 assert_eq!(ext.wakers_len(), 0);
2764
2765 io.encode_slice(b"12345678").unwrap();
2766 assert!(io.flags().is_wr_backpressure());
2767 for _ in 0..4 {
2768 let mut fut = std::pin::pin!(io.write_ready());
2769 assert!(lazy(|cx| fut.as_mut().poll(cx)).await.is_pending());
2770 assert!(lazy(|cx| fut.as_mut().poll(cx)).await.is_pending());
2771 assert_eq!(ext.wakers_len(), 1);
2772 }
2773 assert_eq!(ext.wakers_len(), 0);
2774
2775 let waiter = io.on_disconnect();
2777 assert!(lazy(|cx| waiter.poll_ready(cx)).await.is_pending());
2778 let mut fut = std::pin::pin!(io.write_ready());
2779 assert!(lazy(|cx| fut.as_mut().poll(cx)).await.is_pending());
2780 assert_eq!(ext.wakers_len(), 2);
2781 io.terminate();
2782 assert_eq!(ext.wakers_len(), 1);
2783 assert!(lazy(|cx| fut.as_mut().poll(cx)).await.is_ready());
2784
2785 sleep(Millis(50)).await;
2787 assert_eq!(ext.wakers_len(), 0);
2788 assert!(lazy(|cx| waiter.poll_ready(cx)).await.is_ready());
2789 }
2790
2791 #[test]
2792 fn woken_waiter_slot_is_reused() {
2793 let ext = Extensions::default();
2794 let waker = std::task::Waker::noop();
2795 let (a, b) = (WaiterEntry::new(TAG_WRITE), WaiterEntry::new(TAG_WRITE));
2796
2797 ext.register_waker(&a, waker);
2798 ext.wake(TAG_WRITE);
2799
2800 ext.register_waker(&b, waker);
2802 ext.register_waker(&a, waker);
2803 assert_eq!(ext.wakers_len(), 2);
2804 ext.remove_waker(&a);
2805 assert_eq!(ext.wakers_len(), 1);
2806
2807 ext.wake(TAG_WRITE);
2809 ext.register_waker(&b, waker);
2810 ext.register_waker(&a, waker);
2811 ext.wake(TAG_WRITE);
2812 ext.register_waker(&b, waker);
2813 ext.remove_waker(&a);
2814 assert_eq!(ext.wakers_len(), 1);
2815 ext.remove_waker(&b);
2816 assert_eq!(ext.wakers_len(), 0);
2817 }
2818
2819 #[ntex::test]
2820 async fn full_flush_waits_for_inflight_write() {
2821 let io = Io::new(
2825 IoTest::create().0,
2826 SharedCfg::new("SRV").add(IoConfig::default()),
2827 );
2828 let ctx = IoContext::new(io.get_ref());
2829
2830 io.encode_slice(b"12345678").unwrap();
2831
2832 let page = ctx.with_write_dst(BytePages::take).unwrap();
2833 assert_eq!(page.len(), 8);
2834 assert_eq!(io.st().buffer.write_buf_size(), 0);
2836 assert_eq!(io.st().write_outstanding(), 8);
2837
2838 assert!(lazy(|cx| io.poll_flush(cx, true)).await.is_pending());
2839
2840 assert_eq!(ctx.update_write_status(Ok(page.len())), IoTaskStatus::Pause);
2842 assert_eq!(io.st().write_outstanding(), 0);
2843 assert!(matches!(
2844 lazy(|cx| io.poll_flush(cx, true)).await,
2845 Poll::Ready(Ok(()))
2846 ));
2847 }
2848
2849 #[ntex::test]
2850 async fn write_backpressure_counts_inflight_output() {
2851 let io = Io::new(
2854 IoTest::create().0,
2855 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(8)),
2856 );
2857 let ctx = IoContext::new(io.get_ref());
2858
2859 io.encode_slice(b"12345678").unwrap();
2860 assert!(io.flags().is_wr_backpressure());
2861
2862 let page = ctx.with_write_dst(BytePages::take).unwrap();
2863 assert_eq!(io.st().buffer.write_buf_size(), 0);
2864
2865 assert!(lazy(|cx| io.poll_flush(cx, false)).await.is_pending());
2867 assert!(io.flags().is_wr_backpressure());
2868
2869 assert_eq!(ctx.update_write_status(Ok(page.len())), IoTaskStatus::Pause);
2870 assert!(matches!(
2871 lazy(|cx| io.poll_flush(cx, false)).await,
2872 Poll::Ready(Ok(()))
2873 ));
2874 assert!(!io.flags().is_wr_backpressure());
2875 }
2876
2877 #[ntex::test]
2878 async fn transport_shutdown_waits_for_inflight_write() {
2879 let io = Io::new(
2883 IoTest::create().0,
2884 SharedCfg::new("SRV").add(IoConfig::default()),
2885 );
2886 let ctx = IoContext::new(io.get_ref());
2887
2888 io.encode_slice(b"12345678").unwrap();
2889 let page = ctx.with_write_dst(BytePages::take).unwrap();
2890
2891 io.st().flags.enter_filters_stopping();
2893 io.st().filters_stopped();
2894 assert!(io.st().flags.is_stopping());
2895
2896 assert_eq!(lazy(|cx| ctx.poll_write_ready(cx)).await, Poll::Pending);
2898
2899 assert_eq!(ctx.update_write_status(Ok(page.len())), IoTaskStatus::Pause);
2900 assert_eq!(
2901 lazy(|cx| ctx.poll_write_ready(cx)).await,
2902 Poll::Ready(Readiness::Close)
2903 );
2904 }
2905
2906 #[ntex::test]
2907 async fn shutdown_flushes_write_buf_with_read_backpressure() {
2908 let (client, server) = IoTest::create();
2911 client.remote_buffer_cap(0);
2913
2914 let io = Io::new(
2915 server,
2916 SharedCfg::new("SRV").add(
2917 IoConfig::default()
2918 .set_read_size(BytePageSize::Size4, BytePageSize::Size4)
2919 .set_read_backpressure(BytePageSize::Size4.capacity())
2920 .set_shutdown_timeout(ntex_util::time::Seconds(2)),
2921 ),
2922 );
2923
2924 io.encode_slice(b"response-tail").unwrap();
2926 sleep(Millis(50)).await;
2927 assert_eq!(io.st().buffer.write_buf_size(), 13);
2928
2929 client.write(vec![b'x'; BytePageSize::Size4.capacity()]);
2932 sleep(Millis(50)).await;
2933 assert!(io.flags().is_read_paused());
2934 assert!(io.flags().is_rd_backpressure());
2935 assert_eq!(io.st().buffer.write_buf_size(), 13);
2936
2937 io.close();
2939 sleep(Millis(50)).await;
2940
2941 client.remote_buffer_cap(1024);
2943
2944 let data = ntex_util::time::timeout(Millis(2000), client.read())
2949 .await
2950 .expect("write buffer was dropped during shutdown")
2951 .unwrap();
2952 assert_eq!(&data[..], b"response-tail");
2953
2954 ntex_util::time::timeout(Millis(4000), io.on_disconnect())
2957 .await
2958 .expect("io stream did not disconnect after flush");
2959 }
2960
2961 #[ntex::test]
2962 async fn peer_eof_allows_response_before_shutdown() {
2963 let (client, server) = IoTest::create();
2964 client.remote_buffer_cap(1024);
2965 let io = Io::from(server);
2966
2967 client.write("request");
2968 client.close().await;
2969
2970 assert_eq!(
2971 timeout(Millis(1000), io.recv(&BytesCodec))
2972 .await
2973 .expect("request was not decoded")
2974 .unwrap(),
2975 Some(Bytes::from_static(b"request"))
2976 );
2977 assert!(
2978 timeout(Millis(1000), io.recv(&BytesCodec))
2979 .await
2980 .expect("EOF was not reported")
2981 .unwrap()
2982 .is_none()
2983 );
2984 assert!(!io.st().flags.is_closed());
2985
2986 io.encode(Bytes::from_static(b"response"), &BytesCodec)
2987 .unwrap();
2988 timeout(Millis(1000), io.shutdown())
2989 .await
2990 .expect("shutdown did not complete")
2991 .unwrap();
2992
2993 assert_eq!(
2994 timeout(Millis(1000), client.read())
2995 .await
2996 .expect("response was not flushed")
2997 .unwrap(),
2998 b"response"[..]
2999 );
3000 }
3001
3002 #[ntex::test]
3003 async fn shutdown_waits_for_transport_stop() {
3004 #[derive(Debug)]
3005 struct DormantTransport;
3006
3007 impl IoStream for DormantTransport {
3008 fn start(self, _: IoContext) -> Box<dyn Handle> {
3009 Box::new(self)
3010 }
3011 }
3012
3013 impl Handle for DormantTransport {}
3014
3015 let io = Io::from(DormantTransport);
3016 let ctx = IoContext::new(io.get_ref());
3017 let waiter = io.on_disconnect();
3018 io.st().flags.enter_transport_shutdown();
3019
3020 assert!(lazy(|cx| io.poll_shutdown(cx)).await.is_pending());
3021 assert!(lazy(|cx| waiter.poll_ready(cx)).await.is_pending());
3022
3023 ctx.stopped(None);
3024 assert!(matches!(
3025 lazy(|cx| io.poll_shutdown(cx)).await,
3026 Poll::Ready(Ok(()))
3027 ));
3028 assert!(lazy(|cx| waiter.poll_ready(cx)).await.is_ready());
3029 }
3030
3031 #[ntex::test]
3036 async fn a_stopped_connection_keeps_its_buffered_input() {
3037 let (client, server) = IoTest::create();
3038 client.remote_buffer_cap(1024);
3039 client.write(TEXT);
3040
3041 let io = Io::from(server);
3042 io.read_more().await.unwrap().unwrap();
3043 assert_eq!(io.with_read_dst(|buf| buf.len()), BIN.len());
3044
3045 IoContext::new(io.get_ref()).stopped(None);
3046 assert!(io.is_closed() && !io.is_active());
3047 assert!(io.st().flags.is_stopping() && !io.st().flags.is_shutting_down_filters());
3049 assert_eq!(
3050 io.with_read_dst(|buf| buf.len()),
3051 BIN.len(),
3052 "input received before the transport went away was discarded"
3053 );
3054 }
3055
3056 #[ntex::test]
3057 async fn transport_shutdown_drain_wakes_write_task() {
3058 #[derive(Debug)]
3059 struct DormantTransport;
3060
3061 impl IoStream for DormantTransport {
3062 fn start(self, _: IoContext) -> Box<dyn Handle> {
3063 Box::new(self)
3064 }
3065 }
3066
3067 impl Handle for DormantTransport {}
3068
3069 let io = Io::from(DormantTransport);
3070 let ctx = IoContext::new(io.get_ref());
3071
3072 io.encode_slice(b"tail").unwrap();
3074 io.st().flags.enter_filters_stopping();
3075 io.st().flags.enter_transport_shutdown();
3076 assert_eq!(io.st().buffer.write_buf_size(), 4);
3077
3078 assert!(matches!(
3080 lazy(|cx| ctx.poll_write_ready(cx)).await,
3081 Poll::Ready(Readiness::Ready)
3082 ));
3083 assert!(io.st().write_task.is_set());
3084
3085 let res = ctx.with_write_dst(|buf| {
3087 let mut written = 0;
3088 while let Some(page) = buf.take() {
3089 written += page.len();
3090 }
3091 Ok(written)
3092 });
3093 assert_eq!(ctx.update_write_status(res), IoTaskStatus::Pause);
3094 assert_eq!(io.st().write_outstanding(), 0);
3095
3096 assert!(!io.st().write_task.is_set());
3099 assert!(matches!(
3100 lazy(|cx| ctx.poll_write_ready(cx)).await,
3101 Poll::Ready(Readiness::Close)
3102 ));
3103 }
3104
3105 #[ntex::test]
3106 async fn termination_waits_for_transport_stop() {
3107 #[derive(Debug)]
3108 struct DormantTransport;
3109
3110 impl IoStream for DormantTransport {
3111 fn start(self, _: IoContext) -> Box<dyn Handle> {
3112 Box::new(self)
3113 }
3114 }
3115
3116 impl Handle for DormantTransport {}
3117
3118 let io = Io::from(DormantTransport);
3119 let ctx = IoContext::new(io.get_ref());
3120 let waiter = io.on_disconnect();
3121 ctx.stop(Some(io::Error::new(
3122 io::ErrorKind::ConnectionReset,
3123 "connection reset",
3124 )));
3125
3126 assert!(io.st().flags.is_terminating());
3127 assert!(!io.st().flags.is_closed());
3128 assert!(lazy(|cx| io.poll_shutdown(cx)).await.is_pending());
3129 assert!(lazy(|cx| waiter.poll_ready(cx)).await.is_pending());
3130
3131 ctx.stopped(None);
3132 let Poll::Ready(Err(err)) = lazy(|cx| io.poll_shutdown(cx)).await else {
3133 panic!("shutdown did not report termination error");
3134 };
3135 assert_eq!(err.kind(), io::ErrorKind::ConnectionReset);
3136 assert!(lazy(|cx| waiter.poll_ready(cx)).await.is_ready());
3137 }
3138
3139 #[ntex::test]
3140 async fn send_buf_retains_termination_error() {
3141 #[derive(Debug)]
3142 struct DormantTransport;
3143
3144 impl IoStream for DormantTransport {
3145 fn start(self, _: IoContext) -> Box<dyn Handle> {
3146 Box::new(self)
3147 }
3148 }
3149
3150 impl Handle for DormantTransport {}
3151
3152 let io = Io::from(DormantTransport);
3153 let ctx = IoContext::new(io.get_ref());
3154 ctx.stop(Some(io::Error::new(
3155 io::ErrorKind::ConnectionReset,
3156 "connection reset",
3157 )));
3158
3159 let err = io.get_ref().send_buf().unwrap_err();
3160 assert_eq!(err.kind(), io::ErrorKind::ConnectionReset);
3161 assert_eq!(err.to_string(), "connection reset");
3162
3163 ctx.stopped(None);
3164 let err = io.shutdown().await.unwrap_err();
3165 assert_eq!(err.kind(), io::ErrorKind::ConnectionReset);
3166 assert_eq!(err.to_string(), "connection reset");
3167 }
3168
3169 #[ntex::test]
3170 async fn read_readiness_reports_termination_error() {
3171 #[derive(Debug)]
3172 struct DormantTransport;
3173
3174 impl IoStream for DormantTransport {
3175 fn start(self, _: IoContext) -> Box<dyn Handle> {
3176 Box::new(self)
3177 }
3178 }
3179
3180 impl Handle for DormantTransport {}
3181
3182 let io = Io::from(DormantTransport);
3183 let ctx = IoContext::new(io.get_ref());
3184 ctx.stop(Some(io::Error::new(
3185 io::ErrorKind::ConnectionReset,
3186 "connection reset",
3187 )));
3188
3189 let Poll::Ready(Err(err)) = lazy(|cx| io.poll_read_more(cx)).await else {
3190 panic!("read request did not report termination error");
3191 };
3192 assert_eq!(err.kind(), io::ErrorKind::ConnectionReset);
3193 assert_eq!(err.to_string(), "connection reset");
3194
3195 let Poll::Ready(Err(err)) = lazy(|cx| io.poll_read_notify(cx)).await else {
3196 panic!("read notification did not report termination error");
3197 };
3198 assert_eq!(err.kind(), io::ErrorKind::ConnectionReset);
3199 assert_eq!(err.to_string(), "connection reset");
3200
3201 let err = io.read_exact(&mut [0]).await.unwrap_err();
3202 assert_eq!(err.kind(), io::ErrorKind::ConnectionReset);
3203 assert_eq!(err.to_string(), "connection reset");
3204 }
3205
3206 #[ntex::test]
3212 async fn filter_shutdown_is_blocked_by_read_backpressure() {
3213 #[derive(Debug)]
3214 struct PendingShutdown;
3215
3216 impl FilterLayer for PendingShutdown {
3217 fn process_read_buf(&self, _: &FilterBuf<'_>) -> io::Result<()> {
3218 Ok(())
3219 }
3220
3221 fn process_write_buf(&self, _: &FilterBuf<'_>) -> io::Result<()> {
3222 Ok(())
3223 }
3224
3225 fn shutdown(&self, _: &FilterBuf<'_>) -> io::Result<Poll<()>> {
3226 Ok(Poll::Pending)
3227 }
3228 }
3229
3230 let (_client, server) = IoTest::create();
3231 let io = Io::new(server, SharedCfg::new("SRV")).add_filter(PendingShutdown);
3232
3233 io.st().flags.set_read_ready_and_backpressure();
3236 io.st().flags.unset_read_ready();
3237 assert!(lazy(|cx| io.poll_shutdown(cx)).await.is_pending());
3239
3240 let ctx = IoContext::new(io.get_ref());
3241 assert_eq!(lazy(|cx| ctx.poll_read_ready(cx)).await, Poll::Pending);
3242 assert!(io.st().flags.is_stopping());
3243 }
3244
3245 #[ntex::test]
3246 async fn intermediate_filter_output_reaches_transport() {
3247 #[derive(Debug)]
3250 struct Emit;
3251
3252 impl FilterLayer for Emit {
3253 fn process_read_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3254 buf.with_read_buffers(|src, dst| {
3255 if let Some(src) = src {
3256 dst.extend_from_slice(src);
3257 src.clear();
3258 }
3259 });
3260 buf.with_write_buffers(|_, dst| dst.extend_from_slice(b"pong"));
3261 Ok(())
3262 }
3263
3264 fn process_write_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3265 buf.with_write_buffers(BytePages::move_to);
3266 Ok(())
3267 }
3268
3269 fn shutdown(&self, _: &FilterBuf<'_>) -> io::Result<Poll<()>> {
3270 Ok(Poll::Ready(()))
3271 }
3272 }
3273
3274 #[derive(Debug)]
3275 struct Passthrough;
3276
3277 impl FilterLayer for Passthrough {
3278 fn process_read_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3279 buf.with_read_buffers(|src, dst| {
3280 if let Some(src) = src {
3281 dst.extend_from_slice(src);
3282 src.clear();
3283 }
3284 });
3285 Ok(())
3286 }
3287
3288 fn process_write_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3289 buf.with_write_buffers(BytePages::move_to);
3290 Ok(())
3291 }
3292
3293 fn shutdown(&self, _: &FilterBuf<'_>) -> io::Result<Poll<()>> {
3294 Ok(Poll::Ready(()))
3295 }
3296 }
3297
3298 let (client, server) = IoTest::create();
3299 client.remote_buffer_cap(1024);
3300
3301 let io = Io::from(server).add_filter(Passthrough).add_filter(Emit);
3305
3306 client.write("ping");
3307 let _ = io.recv(&BytesCodec).await.unwrap();
3308 sleep(Millis(50)).await;
3309 assert!(client.read_any().starts_with(b"pong"));
3310 }
3311
3312 #[ntex::test]
3313 async fn read_pauses_while_read_output_is_not_drained() {
3314 #[derive(Debug)]
3317 struct Reply;
3318
3319 impl FilterLayer for Reply {
3320 fn process_read_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3321 let data = buf.with_read_buffers(|src, _| src.as_mut().map(BytesMut::take));
3322 if let Some(data) = data {
3323 buf.with_write_buffers(|_, dst| dst.extend_from_slice(&data));
3324 }
3325 Ok(())
3326 }
3327
3328 fn process_write_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3329 buf.with_write_buffers(BytePages::move_to);
3330 Ok(())
3331 }
3332
3333 fn shutdown(&self, _: &FilterBuf<'_>) -> io::Result<Poll<()>> {
3334 Ok(Poll::Ready(()))
3335 }
3336 }
3337
3338 #[derive(Debug)]
3340 struct Manual;
3341
3342 impl IoStream for Manual {
3343 fn start(self, _: IoContext) -> Box<dyn Handle> {
3344 Box::new(self)
3345 }
3346 }
3347
3348 impl Handle for Manual {}
3349
3350 let io = Io::new(
3351 Manual,
3352 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(8)),
3353 )
3354 .add_filter(Reply);
3355 let ctx = IoContext::new(io.get_ref());
3356 let read = |data: &'static [u8]| {
3357 ctx.with_read_buf(|buf| {
3358 buf.extend_from_slice(data);
3359 Poll::Ready(Ok(data.len()))
3360 })
3361 };
3362
3363 assert_eq!(read(b"ping"), IoTaskStatus::Io);
3365 assert!(!io.st().flags.is_read_wr_backpressure());
3366
3367 assert_eq!(read(b"ping"), IoTaskStatus::Pause);
3369 assert!(io.st().flags.is_read_wr_backpressure());
3370 assert_eq!(lazy(|cx| ctx.poll_read_ready(cx)).await, Poll::Pending);
3371 assert!(io.st().read_task.is_set());
3372
3373 let _ = ctx.with_write_dst(|buf| buf.split_to(8));
3375 assert_eq!(io.st().write_outstanding(), 8);
3376 let _ = ctx.update_write_status(Ok(0));
3377 assert!(io.st().flags.is_read_wr_backpressure());
3378
3379 let _ = ctx.update_write_status(Ok(3));
3381 assert!(io.st().flags.is_read_wr_backpressure());
3382 assert!(io.st().read_task.is_set());
3383
3384 let _ = ctx.update_write_status(Ok(1));
3386 assert!(!io.st().flags.is_read_wr_backpressure());
3387 assert!(!io.st().read_task.is_set());
3388 assert_eq!(
3389 lazy(|cx| ctx.poll_read_ready(cx)).await,
3390 Poll::Ready(Readiness::Ready)
3391 );
3392
3393 io.encode_slice(b"12345678").unwrap();
3395 assert!(io.st().write_outstanding() >= 8);
3396 assert_eq!(
3397 lazy(|cx| ctx.poll_read_ready(cx)).await,
3398 Poll::Ready(Readiness::Ready)
3399 );
3400 assert!(!io.st().flags.is_read_wr_backpressure());
3401 }
3402
3403 #[ntex::test]
3404 async fn read_output_pause_ignores_held_back_output() {
3405 #[derive(Debug, Default)]
3408 struct Reneg(Cell<bool>);
3409
3410 impl FilterLayer for Reneg {
3411 fn process_read_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3412 let data = buf.with_read_buffers(|src, _| src.as_mut().map(BytesMut::take));
3413 match data.as_deref() {
3414 Some(b"hello") => {
3415 buf.with_write_buffers(|_, dst| dst.extend_from_slice(b"handshake"));
3416 }
3417 Some(b"done") => {
3418 self.0.set(true);
3419 buf.with_write_buffers(BytePages::move_to);
3420 }
3421 _ => (),
3422 }
3423 Ok(())
3424 }
3425
3426 fn process_write_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3427 if self.0.get() {
3428 buf.with_write_buffers(BytePages::move_to);
3429 }
3430 Ok(())
3431 }
3432
3433 fn shutdown(&self, _: &FilterBuf<'_>) -> io::Result<Poll<()>> {
3434 Ok(Poll::Ready(()))
3435 }
3436 }
3437
3438 #[derive(Debug)]
3439 struct Manual;
3440
3441 impl IoStream for Manual {
3442 fn start(self, _: IoContext) -> Box<dyn Handle> {
3443 Box::new(self)
3444 }
3445 }
3446
3447 impl Handle for Manual {}
3448
3449 let io = Io::new(
3450 Manual,
3451 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(8)),
3452 )
3453 .add_filter(Reneg::default());
3454 let ctx = IoContext::new(io.get_ref());
3455 let read = |data: &'static [u8]| {
3456 ctx.with_read_buf(|buf| {
3457 buf.extend_from_slice(data);
3458 Poll::Ready(Ok(data.len()))
3459 })
3460 };
3461
3462 io.encode_slice(b"12345678").unwrap();
3464 assert_eq!(io.st().write_outstanding(), 8);
3465
3466 assert_eq!(read(b"hello"), IoTaskStatus::Pause);
3468 assert!(io.st().flags.is_read_wr_backpressure());
3469
3470 let _ = ctx.with_write_dst(|buf| buf.split_to(9));
3472 let _ = ctx.update_write_status(Ok(9));
3473 assert_eq!(io.st().write_outstanding(), 8);
3474 assert!(!io.st().flags.is_read_wr_backpressure());
3475 assert_eq!(
3476 lazy(|cx| ctx.poll_read_ready(cx)).await,
3477 Poll::Ready(Readiness::Ready)
3478 );
3479
3480 let _ = read(b"done");
3482 assert_eq!(ctx.with_write_dst(|buf| buf.len()), 8);
3483 }
3484
3485 #[ntex::test]
3486 async fn read_more_lifts_read_output_pause() {
3487 #[derive(Debug)]
3488 struct Reply;
3489
3490 impl FilterLayer for Reply {
3491 fn process_read_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3492 let data = buf.with_read_buffers(|src, _| src.as_mut().map(BytesMut::take));
3493 if let Some(data) = data {
3494 buf.with_write_buffers(|_, dst| dst.extend_from_slice(&data));
3495 }
3496 Ok(())
3497 }
3498
3499 fn process_write_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3500 buf.with_write_buffers(BytePages::move_to);
3501 Ok(())
3502 }
3503
3504 fn shutdown(&self, _: &FilterBuf<'_>) -> io::Result<Poll<()>> {
3505 Ok(Poll::Ready(()))
3506 }
3507 }
3508
3509 #[derive(Debug)]
3510 struct Manual;
3511
3512 impl IoStream for Manual {
3513 fn start(self, _: IoContext) -> Box<dyn Handle> {
3514 Box::new(self)
3515 }
3516 }
3517
3518 impl Handle for Manual {}
3519
3520 let io = Io::new(
3521 Manual,
3522 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(8)),
3523 )
3524 .add_filter(Reply);
3525 let ctx = IoContext::new(io.get_ref());
3526 let read = |data: &'static [u8]| {
3527 ctx.with_read_buf(|buf| {
3528 buf.extend_from_slice(data);
3529 Poll::Ready(Ok(data.len()))
3530 })
3531 };
3532
3533 assert_eq!(read(b"pingping"), IoTaskStatus::Pause);
3535 assert_eq!(lazy(|cx| ctx.poll_read_ready(cx)).await, Poll::Pending);
3536 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_pending());
3537 assert!(!io.st().flags.is_read_wr_backpressure());
3538 assert!(!io.st().read_task.is_set());
3539 assert_eq!(
3540 lazy(|cx| ctx.poll_read_ready(cx)).await,
3541 Poll::Ready(Readiness::Ready)
3542 );
3543
3544 assert_eq!(read(b"ping"), IoTaskStatus::Pause);
3546 assert_eq!(lazy(|cx| ctx.poll_read_ready(cx)).await, Poll::Pending);
3547 assert!(lazy(|cx| io.poll_read_notify(cx)).await.is_pending());
3548 assert!(!io.st().flags.is_read_wr_backpressure());
3549 assert!(!io.st().read_task.is_set());
3550 assert_eq!(
3551 lazy(|cx| ctx.poll_read_ready(cx)).await,
3552 Poll::Ready(Readiness::Ready)
3553 );
3554 }
3555
3556 #[ntex::test]
3557 async fn read_pause_on_read_output_does_not_block_filter_shutdown() {
3558 #[derive(Debug)]
3559 struct Reply;
3560
3561 impl FilterLayer for Reply {
3562 fn process_read_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3563 let data = buf.with_read_buffers(|src, _| src.as_mut().map(BytesMut::take));
3564 if let Some(data) = data {
3565 buf.with_write_buffers(|_, dst| dst.extend_from_slice(&data));
3566 }
3567 Ok(())
3568 }
3569
3570 fn process_write_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3571 buf.with_write_buffers(BytePages::move_to);
3572 Ok(())
3573 }
3574
3575 fn shutdown(&self, _: &FilterBuf<'_>) -> io::Result<Poll<()>> {
3576 Ok(Poll::Pending)
3578 }
3579 }
3580
3581 #[derive(Debug)]
3582 struct Manual;
3583
3584 impl IoStream for Manual {
3585 fn start(self, _: IoContext) -> Box<dyn Handle> {
3586 Box::new(self)
3587 }
3588 }
3589
3590 impl Handle for Manual {}
3591
3592 let io = Io::new(
3593 Manual,
3594 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(8)),
3595 )
3596 .add_filter(Reply);
3597 let ctx = IoContext::new(io.get_ref());
3598 let read = |data: &'static [u8]| {
3599 ctx.with_read_buf(|buf| {
3600 buf.extend_from_slice(data);
3601 Poll::Ready(Ok(data.len()))
3602 })
3603 };
3604
3605 assert_eq!(read(b"pingping"), IoTaskStatus::Pause);
3606 assert!(io.st().flags.is_read_wr_backpressure());
3607
3608 assert!(lazy(|cx| io.poll_shutdown(cx)).await.is_pending());
3610 assert!(io.st().flags.is_stopping_filters());
3611 assert_eq!(
3612 lazy(|cx| ctx.poll_read_ready(cx)).await,
3613 Poll::Ready(Readiness::Ready)
3614 );
3615 assert_eq!(read(b"ping"), IoTaskStatus::Io);
3616 }
3617
3618 #[ntex::test]
3619 async fn peer_eof_completes_filter_shutdown() {
3620 #[derive(Debug)]
3621 struct PendingShutdown;
3622
3623 impl FilterLayer for PendingShutdown {
3624 fn process_read_buf(&self, _: &FilterBuf<'_>) -> io::Result<()> {
3625 Ok(())
3626 }
3627
3628 fn process_write_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3629 buf.with_write_buffers(BytePages::move_to);
3630 Ok(())
3631 }
3632
3633 fn shutdown(&self, buf: &FilterBuf<'_>) -> io::Result<Poll<()>> {
3634 buf.with_write_buffers(BytePages::move_to);
3636 Ok(Poll::Pending)
3637 }
3638 }
3639
3640 let (client, server) = IoTest::create();
3641 client.remote_buffer_cap(1024);
3642 let io = Io::new(
3643 server,
3644 SharedCfg::new("SRV")
3645 .add(IoConfig::default().set_shutdown_timeout(ntex_util::time::Seconds(30))),
3646 )
3647 .add_filter(PendingShutdown);
3648
3649 io.encode_slice(b"bye").unwrap();
3650
3651 let peer = client.clone();
3653 drop(client);
3654 assert!(io.read_more().await.unwrap().is_none());
3655 assert!(io.st().flags.is_read_eof());
3656
3657 timeout(Millis(1000), io.shutdown())
3659 .await
3660 .expect("transport shutdown did not complete")
3661 .unwrap();
3662 assert!(io.st().flags.is_closed());
3663
3664 assert_eq!(peer.read_any(), Bytes::from_static(b"bye"));
3666 }
3667
3668 #[derive(Debug)]
3670 struct StuckShutdown(Cell<bool>);
3671
3672 impl FilterLayer for StuckShutdown {
3673 fn process_read_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3674 buf.with_read_buffers(|src, dst| {
3675 if let Some(src) = src {
3676 dst.extend_from_slice(src);
3677 src.clear();
3678 }
3679 });
3680 Ok(())
3681 }
3682
3683 fn process_write_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3684 buf.with_write_buffers(BytePages::move_to);
3685 Ok(())
3686 }
3687
3688 fn shutdown(&self, _: &FilterBuf<'_>) -> io::Result<Poll<()>> {
3689 self.0.set(true);
3690 Ok(Poll::Pending)
3691 }
3692 }
3693
3694 #[ntex::test]
3695 async fn transport_shutdown_pauses_read_task() {
3696 let (client, server) = IoTest::create();
3697 client.remote_buffer_cap(1024);
3698 let io = Io::new(server, SharedCfg::new("SRV"));
3699
3700 client.write("before");
3701 sleep(Millis(25)).await;
3702 assert_eq!(
3703 io.recv(&BytesCodec).await.unwrap().unwrap(),
3704 b"before".as_ref()
3705 );
3706
3707 client.remote_buffer_cap(0);
3709 io.get_ref().with_write_dst(|b| b.extend_from_slice(b"out"));
3710
3711 io.st().flags.enter_filters_stopping();
3713 io.st().flags.enter_transport_shutdown();
3714 io.st().wake_read_task();
3715
3716 client.write("after");
3719 sleep(Millis(50)).await;
3720 assert!(!io.st().flags.is_closed());
3721 assert_eq!(client.remote_buffer(|buf| buf.len()), 5);
3722 }
3723
3724 #[derive(Default)]
3726 struct WakeCounter(std::sync::atomic::AtomicUsize);
3727
3728 impl std::task::Wake for WakeCounter {
3729 fn wake(self: std::sync::Arc<Self>) {
3730 self.wake_by_ref();
3731 }
3732
3733 fn wake_by_ref(self: &std::sync::Arc<Self>) {
3734 self.0.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
3735 }
3736 }
3737
3738 impl WakeCounter {
3739 fn count(&self) -> usize {
3740 self.0.load(std::sync::atomic::Ordering::Relaxed)
3741 }
3742 }
3743
3744 #[ntex::test]
3745 async fn repeated_shutdown_polls_do_not_wake_tasks() {
3746 use std::{sync::Arc, task::Waker};
3747
3748 let (_client, server) = IoTest::create();
3749 let io = Io::new(server, SharedCfg::new("SRV")).add_filter(StuckShutdown(Cell::new(false)));
3750
3751 let waker = Waker::noop();
3752 let mut cx = Context::from_waker(waker);
3753 assert!(io.poll_shutdown(&mut cx).is_pending());
3754 assert!(io.st().flags.is_stopping_filters());
3755
3756 let rd = Arc::new(WakeCounter::default());
3760 let wr = Arc::new(WakeCounter::default());
3761 io.st().read_task.register(&Waker::from(rd.clone()));
3762 io.st().write_task.register(&Waker::from(wr.clone()));
3763 for _ in 0..3 {
3764 assert!(io.poll_shutdown(&mut cx).is_pending());
3765 }
3766 assert_eq!(rd.count(), 0);
3767 assert_eq!(wr.count(), 0);
3768
3769 io.st().flags.set_read_paused();
3771 assert!(io.poll_shutdown(&mut cx).is_pending());
3772 assert!(!io.st().flags.is_read_paused());
3773 assert_eq!(rd.count(), 1);
3774 }
3775
3776 #[ntex::test]
3777 async fn filter_shutdown_applies_read_backpressure() {
3778 let (client, server) = IoTest::create();
3779 client.remote_buffer_cap(1024 * 1024);
3780 let io = Io::new(
3781 server,
3782 SharedCfg::new("SRV").add(
3783 IoConfig::default()
3784 .set_read_size(BytePageSize::Size4, BytePageSize::Size4)
3785 .set_read_backpressure(BytePageSize::Size4.capacity())
3786 .set_shutdown_timeout(ntex_util::time::Seconds(30)),
3787 ),
3788 )
3789 .add_filter(StuckShutdown(Cell::new(false)));
3790
3791 let ioref = io.get_ref();
3792 let high = BytePageSize::Size4.capacity();
3793 ntex::rt::spawn(async move {
3794 let _ = io.shutdown().await;
3795 });
3796 sleep(Millis(50)).await;
3797
3798 for _ in 0..40 {
3801 client.write("A".repeat(1024));
3802 sleep(Millis(5)).await;
3803 }
3804 sleep(Millis(100)).await;
3805
3806 let buffered = ioref.with_read_dst(|buf| buf.len());
3808 assert!(
3809 buffered <= high * 2,
3810 "read buffer grew to {buffered} with a high watermark of {high}"
3811 );
3812 assert!(
3813 client.remote_buffer(|buf| !buf.is_empty()),
3814 "peer send buffer was drained despite read backpressure"
3815 );
3816 }
3817
3818 #[ntex::test]
3819 async fn filter_shutdown_blocked_by_unconsumed_input() {
3820 let (client, server) = IoTest::create();
3825 client.remote_buffer_cap(1024 * 1024);
3826 let io = Io::new(
3827 server,
3828 SharedCfg::new("SRV").add(
3829 IoConfig::default()
3830 .set_read_size(BytePageSize::Size4, BytePageSize::Size4)
3831 .set_read_backpressure(BytePageSize::Size4.capacity())
3832 .set_shutdown_timeout(ntex_util::time::Seconds(30)),
3833 ),
3834 )
3835 .add_filter(StuckShutdown(Cell::new(false)));
3836
3837 client.write("A".repeat(4096));
3838 sleep(Millis(50)).await;
3839 assert!(
3840 io.get_ref().is_rd_backpressure(),
3841 "read backpressure was not active before the shutdown"
3842 );
3843
3844 let err = timeout(Millis(3000), io.shutdown())
3847 .await
3848 .expect("shutdown did not complete")
3849 .unwrap_err();
3850 assert_eq!(err.kind(), io::ErrorKind::Other);
3851 }
3852
3853 #[derive(Debug)]
3854 struct Passthrough;
3855
3856 impl FilterLayer for Passthrough {
3857 fn process_read_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3858 buf.with_read_buffers(|src, dst| {
3859 if let Some(src) = src {
3860 dst.extend_from_slice(src);
3861 src.clear();
3862 }
3863 });
3864 Ok(())
3865 }
3866
3867 fn process_write_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3868 buf.with_write_buffers(BytePages::move_to);
3869 Ok(())
3870 }
3871 }
3872
3873 #[derive(Debug, Default)]
3875 struct AckShutdown {
3876 sent: Cell<bool>,
3877 acked: Cell<bool>,
3878 }
3879
3880 impl FilterLayer for AckShutdown {
3881 fn process_read_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3882 buf.with_read_buffers(|src, dst| {
3883 if let Some(src) = src {
3884 if self.sent.get() && &src[..] == b"ack" {
3885 self.acked.set(true);
3886 } else {
3887 dst.extend_from_slice(src);
3888 }
3889 src.clear();
3890 }
3891 });
3892 Ok(())
3893 }
3894
3895 fn process_write_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3896 buf.with_write_buffers(BytePages::move_to);
3897 Ok(())
3898 }
3899
3900 fn shutdown(&self, buf: &FilterBuf<'_>) -> io::Result<Poll<()>> {
3901 if !self.sent.replace(true) {
3902 buf.with_write_buffers(|_, dst| dst.extend_from_slice(b"bye"));
3903 }
3904 Ok(if self.acked.get() {
3905 Poll::Ready(())
3906 } else {
3907 Poll::Pending
3908 })
3909 }
3910 }
3911
3912 async fn filter_shutdown_waits_for_peer<F: Filter>(client: IoTest, io: Io<F>) {
3913 client.remote_buffer_cap(1024);
3914 let io = io.add_filter(AckShutdown::default());
3915 let done = Rc::new(Cell::new(false));
3916 let done2 = done.clone();
3917 ntex::rt::spawn(async move {
3918 io.shutdown().await.unwrap();
3919 done2.set(true);
3920 });
3921 sleep(Millis(50)).await;
3922
3923 assert_eq!(client.read_any(), Bytes::from_static(b"bye"));
3925 assert!(!done.get());
3926
3927 client.write("ack");
3929 sleep(Millis(50)).await;
3930 assert!(done.get());
3931 }
3932
3933 #[ntex::test]
3934 async fn filter_shutdown_completes_on_peer_input() {
3935 let (client, server) = IoTest::create();
3936 let io = Io::new(server, SharedCfg::new("SRV"));
3937 filter_shutdown_waits_for_peer(client, io).await;
3938 }
3939
3940 #[ntex::test]
3941 async fn filter_shutdown_output_passes_inner_filters() {
3942 let (client, server) = IoTest::create();
3943 let io = Io::new(server, SharedCfg::new("SRV")).add_filter(Passthrough);
3944 filter_shutdown_waits_for_peer(client, io).await;
3945 }
3946
3947 #[ntex::test]
3948 async fn filter_failure_output_passes_inner_filters() {
3949 #[derive(Debug)]
3951 struct FailOnInput;
3952
3953 impl FilterLayer for FailOnInput {
3954 fn process_read_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3955 if buf.with_read_src(|src| src.take().is_some()) {
3956 buf.with_write_buffers(|_, dst| dst.extend_from_slice(b"err"));
3957 buf.io().close();
3958 Err(io::Error::new(io::ErrorKind::InvalidData, "failed"))
3959 } else {
3960 Ok(())
3961 }
3962 }
3963
3964 fn process_write_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
3965 buf.with_write_buffers(BytePages::move_to);
3966 Ok(())
3967 }
3968 }
3969
3970 let (client, server) = IoTest::create();
3971 client.remote_buffer_cap(1024);
3972 let io = Io::new(server, SharedCfg::new("SRV"))
3973 .add_filter(Passthrough)
3974 .add_filter(FailOnInput);
3975
3976 client.write("input");
3977 let err = io.recv(&BytesCodec).await.unwrap_err();
3978 assert_eq!(err.into_inner().kind(), io::ErrorKind::InvalidData);
3979 sleep(Millis(50)).await;
3980
3981 assert_eq!(client.read_any(), Bytes::from_static(b"err"));
3982 assert!(io.is_closed());
3983 }
3984
3985 #[ntex::test]
3986 async fn filter_shutdown_timeout_is_reported() {
3987 #[derive(Debug)]
3988 struct PendingShutdown;
3989
3990 impl FilterLayer for PendingShutdown {
3991 fn process_read_buf(&self, _: &FilterBuf<'_>) -> io::Result<()> {
3992 Ok(())
3993 }
3994
3995 fn process_write_buf(&self, _: &FilterBuf<'_>) -> io::Result<()> {
3996 Ok(())
3997 }
3998
3999 fn shutdown(&self, _: &FilterBuf<'_>) -> io::Result<Poll<()>> {
4000 Ok(Poll::Pending)
4001 }
4002 }
4003
4004 let (_client, server) = IoTest::create();
4005 let io = Io::new(
4006 server,
4007 SharedCfg::new("SRV")
4008 .add(IoConfig::default().set_shutdown_timeout(ntex_util::time::Seconds(1))),
4009 )
4010 .add_filter(PendingShutdown);
4011
4012 let err = timeout(Millis(3000), io.shutdown())
4013 .await
4014 .expect("transport shutdown did not complete")
4015 .unwrap_err();
4016 assert_eq!(err.kind(), io::ErrorKind::TimedOut);
4017 assert!(io.st().flags.is_closed());
4018 assert!(!io.st().flags.is_terminating());
4019 }
4020
4021 #[ntex::test]
4022 async fn blocked_filter_shutdown_flushes_buffered_output() {
4023 #[derive(Debug)]
4024 struct ClosingShutdown(Cell<bool>);
4025
4026 impl FilterLayer for ClosingShutdown {
4027 fn process_read_buf(&self, _: &FilterBuf<'_>) -> io::Result<()> {
4028 Ok(())
4029 }
4030
4031 fn process_write_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
4032 buf.with_write_buffers(BytePages::move_to);
4033 Ok(())
4034 }
4035
4036 fn shutdown(&self, buf: &FilterBuf<'_>) -> io::Result<Poll<()>> {
4037 if !self.0.replace(true) {
4039 buf.with_write_buffers(|_, dst| dst.extend_from_slice(b"bye"));
4040 }
4041 Ok(Poll::Pending)
4042 }
4043 }
4044
4045 let (client, server) = IoTest::create();
4046 client.remote_buffer_cap(0);
4048
4049 let io = Io::new(
4050 server,
4051 SharedCfg::new("SRV").add(
4052 IoConfig::default()
4053 .set_read_size(BytePageSize::Size4, BytePageSize::Size4)
4054 .set_read_backpressure(BytePageSize::Size4.capacity())
4055 .set_shutdown_timeout(ntex_util::time::Seconds(10)),
4056 ),
4057 )
4058 .add_filter(ClosingShutdown(Cell::new(false)));
4059
4060 io.st().flags.set_read_ready_and_backpressure();
4061 io.close();
4062 sleep(Millis(50)).await;
4063
4064 assert!(io.st().flags.is_stopping());
4067
4068 client.remote_buffer_cap(1024);
4070 assert_eq!(
4071 timeout(Millis(1000), client.read())
4072 .await
4073 .expect("closing record was not written")
4074 .unwrap(),
4075 Bytes::from_static(b"bye")
4076 );
4077
4078 let err = timeout(Millis(1000), io.shutdown())
4079 .await
4080 .expect("transport shutdown did not complete")
4081 .unwrap_err();
4082 assert_eq!(err.kind(), io::ErrorKind::Other);
4083 }
4084
4085 #[ntex::test]
4086 async fn one_deadline_bounds_both_shutdown_phases() {
4087 #[derive(Debug)]
4088 struct ClosingShutdown(Cell<bool>);
4089
4090 impl FilterLayer for ClosingShutdown {
4091 fn process_read_buf(&self, _: &FilterBuf<'_>) -> io::Result<()> {
4092 Ok(())
4093 }
4094
4095 fn process_write_buf(&self, buf: &FilterBuf<'_>) -> io::Result<()> {
4096 buf.with_write_buffers(BytePages::move_to);
4097 Ok(())
4098 }
4099
4100 fn shutdown(&self, buf: &FilterBuf<'_>) -> io::Result<Poll<()>> {
4101 if !self.0.replace(true) {
4102 buf.with_write_buffers(|_, dst| dst.extend_from_slice(b"bye"));
4103 }
4104 Ok(Poll::Pending)
4105 }
4106 }
4107
4108 let (client, server) = IoTest::create();
4109 client.remote_buffer_cap(0);
4112
4113 let io = Io::new(
4114 server,
4115 SharedCfg::new("SRV").add(
4116 IoConfig::default()
4117 .set_read_size(BytePageSize::Size4, BytePageSize::Size4)
4118 .set_read_backpressure(BytePageSize::Size4.capacity())
4119 .set_shutdown_timeout(ntex_util::time::Seconds(1)),
4120 ),
4121 )
4122 .add_filter(ClosingShutdown(Cell::new(false)));
4123
4124 let start = std::time::Instant::now();
4125 io.close();
4126
4127 timeout(Millis(5000), io.shutdown())
4128 .await
4129 .expect("transport shutdown did not complete")
4130 .unwrap_err();
4131 assert!(io.st().flags.is_closed());
4132
4133 let elapsed = start.elapsed();
4136 assert!(
4137 elapsed < std::time::Duration::from_millis(1600),
4138 "shutdown took {elapsed:?}, the deadline did not span both phases"
4139 );
4140 }
4141
4142 #[ntex::test]
4143 async fn blocked_filter_shutdown_is_reported() {
4144 #[derive(Debug)]
4145 struct PendingShutdown;
4146
4147 impl FilterLayer for PendingShutdown {
4148 fn process_read_buf(&self, _: &FilterBuf<'_>) -> io::Result<()> {
4149 Ok(())
4150 }
4151
4152 fn process_write_buf(&self, _: &FilterBuf<'_>) -> io::Result<()> {
4153 Ok(())
4154 }
4155
4156 fn shutdown(&self, _: &FilterBuf<'_>) -> io::Result<Poll<()>> {
4157 Ok(Poll::Pending)
4158 }
4159 }
4160
4161 let (_client, server) = IoTest::create();
4162 let io = Io::new(
4163 server,
4164 SharedCfg::new("SRV").add(
4165 IoConfig::default()
4166 .set_read_size(BytePageSize::Size4, BytePageSize::Size4)
4167 .set_read_backpressure(BytePageSize::Size4.capacity())
4168 .set_shutdown_timeout(ntex_util::time::Seconds(10)),
4169 ),
4170 )
4171 .add_filter(PendingShutdown);
4172
4173 io.st().flags.set_read_ready_and_backpressure();
4174 io.close();
4175 sleep(Millis(50)).await;
4176
4177 let err = timeout(Millis(1000), io.shutdown())
4178 .await
4179 .expect("transport shutdown did not complete")
4180 .unwrap_err();
4181 assert_eq!(err.kind(), io::ErrorKind::Other);
4182 assert!(io.st().flags.is_closed());
4183 assert!(!io.st().flags.is_terminating());
4184 }
4185
4186 #[ntex::test]
4187 async fn shutdown() {
4188 #[derive(Debug)]
4190 struct F;
4191
4192 impl FilterLayer for F {
4193 fn process_read_buf(&self, _: &FilterBuf<'_>) -> io::Result<()> {
4194 Ok(())
4195 }
4196 fn process_write_buf(&self, _: &FilterBuf<'_>) -> io::Result<()> {
4197 Ok(())
4198 }
4199 }
4200
4201 let io = Io::new(
4202 IoTest::create().0,
4203 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(8)),
4204 );
4205 let st = io.st();
4206 assert!(lazy(|cx| io.poll_status_update(cx)).await.is_pending());
4207 assert!(st.dispatch_task.is_set());
4208 assert!(!st.flags.is_peer_gone());
4209 assert!(!st.flags.is_stopping_filters());
4210
4211 let ctx = IoContext::new(io.get_ref());
4212
4213 io.close();
4215 assert!(!st.flags.is_peer_gone());
4216 assert!(st.flags.is_stopping_filters());
4217 let err = io.with_write_src(|_| 1).unwrap_err();
4219 assert_eq!(err.kind(), io::ErrorKind::Other);
4220
4221 let io = io.add_filter(F);
4222 let layer = Layer::new(F, Base::new(io.get_ref()));
4223
4224 let st = io.st();
4225 st.buffer.with_write_src(|p| p.put_slice(b"123"));
4226 assert_eq!(st.buffer.write_buf_size(), 3);
4227 let res = st.buffer.with_filter(io.as_ref(), |f| layer.shutdown(f));
4228 assert!(matches!(res, Ok(Poll::Ready(()))));
4229 assert_eq!(st.buffer.write_buf_size(), 0);
4230
4231 ctx.stop(None);
4233 assert!(st.flags.is_peer_gone());
4234 assert!(st.flags.is_terminating());
4235 assert!(!st.flags.is_closed());
4236 assert!(st.flags.is_stopping_filters());
4237
4238 let err = io.with_write_src(|_| 1).unwrap_err();
4239 assert_eq!(err.kind(), io::ErrorKind::NotConnected);
4240
4241 ctx.stopped(None);
4242 assert!(st.flags.is_closed());
4243 }
4244
4245 struct FixedSize(usize);
4246
4247 impl Decoder for FixedSize {
4248 type Item = Bytes;
4249 type Error = io::Error;
4250
4251 fn decode(&self, src: &mut BytesMut) -> Result<Option<Bytes>, io::Error> {
4252 if src.len() < self.0 {
4253 Ok(None)
4254 } else {
4255 Ok(Some(src.split_to(self.0)))
4256 }
4257 }
4258 }
4259
4260 #[ntex::test]
4261 async fn recv_reports_timeout_during_write_backpressure() {
4262 let (client, server) = IoTest::create();
4263 client.remote_buffer_cap(0);
4264 let io = Io::new(
4265 server,
4266 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(16)),
4267 );
4268 io.encode_slice(BIN2).unwrap();
4269 assert!(io.flags().is_wr_backpressure());
4270
4271 let ioref = io.get_ref();
4272 let (res, ()) =
4273 ntex_util::future::join(timeout(Millis(1000), io.recv(&BytesCodec)), async move {
4274 sleep(Millis(25)).await;
4275 ioref.0.notify_timeout();
4276 })
4277 .await;
4278
4279 let Err(Either::Right(err)) = res.expect("recv ignored the timeout") else {
4280 panic!("expected a timeout error")
4281 };
4282 assert_eq!(err.kind(), io::ErrorKind::TimedOut);
4283 assert!(io.flags().is_wr_backpressure());
4284 }
4285
4286 #[ntex::test]
4287 async fn write_timeout_bounds_output_waits() {
4288 let (client, server) = IoTest::create();
4289 client.remote_buffer_cap(0);
4290 let io = Io::new(
4291 server,
4292 SharedCfg::new("SRV").add(
4293 IoConfig::default()
4294 .set_write_backpressure(16)
4295 .set_write_timeout(ntex_util::time::Seconds(1)),
4296 ),
4297 );
4298 io.encode_slice(BIN2).unwrap();
4299 assert!(io.flags().is_wr_backpressure());
4300
4301 let ioref = io.get_ref();
4302 let ((send, flush), ready) = timeout(
4303 Millis(3000),
4304 ntex_util::future::join(
4305 ntex_util::future::join(
4306 io.send(Bytes::from_static(b"item"), &BytesCodec),
4307 io.flush(false),
4308 ),
4309 ioref.write_ready(),
4310 ),
4311 )
4312 .await
4313 .expect("output waits are not bounded by the write timeout");
4314
4315 let Err(Either::Right(err)) = send else {
4316 panic!("expected a transport error")
4317 };
4318 assert_eq!(err.kind(), io::ErrorKind::TimedOut);
4319 assert_eq!(flush.unwrap_err().kind(), io::ErrorKind::TimedOut);
4320 assert_eq!(ready.unwrap_err().kind(), io::ErrorKind::TimedOut);
4321
4322 assert!(!io.is_closed());
4324 client.remote_buffer_cap(1024);
4325 io.flush(true).await.unwrap();
4326 }
4327
4328 #[ntex::test]
4329 async fn recv_reports_truncated_stream() {
4330 let (client, server) = IoTest::create();
4331 client.remote_buffer_cap(1024);
4332 let io = Io::new(server, SharedCfg::new("SRV"));
4333
4334 client.write("123");
4336 sleep(Millis(25)).await;
4337 client.close().await;
4338
4339 let err = io.recv(&FixedSize(8)).await.err().unwrap();
4340 let Either::Right(err) = err else {
4341 panic!("expected a transport error")
4342 };
4343 assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof);
4344
4345 assert_eq!(io.with_read_dst(|b| b.len()), 3);
4347 }
4348
4349 #[ntex::test]
4350 async fn recv_reports_clean_eof() {
4351 let (client, server) = IoTest::create();
4352 client.remote_buffer_cap(1024);
4353 let io = Io::new(server, SharedCfg::new("SRV"));
4354
4355 client.write("12345678");
4357 sleep(Millis(25)).await;
4358 client.close().await;
4359
4360 assert_eq!(io.recv(&FixedSize(8)).await.unwrap().unwrap(), "12345678");
4361 assert!(io.recv(&FixedSize(8)).await.unwrap().is_none());
4362 }
4363
4364 struct FixedSizeEof(usize, std::cell::Cell<usize>);
4366
4367 impl Decoder for FixedSizeEof {
4368 type Item = Bytes;
4369 type Error = io::Error;
4370
4371 fn decode(&self, src: &mut BytesMut) -> Result<Option<Bytes>, io::Error> {
4372 FixedSize(self.0).decode(src)
4373 }
4374
4375 fn decode_eof(&self, src: &mut BytesMut) -> Result<Option<Bytes>, io::Error> {
4376 self.1.set(self.1.get() + 1);
4377 if src.is_empty() {
4378 Ok(None)
4379 } else {
4380 let len = src.len().min(self.0);
4381 Ok(Some(src.split_to(len)))
4382 }
4383 }
4384 }
4385
4386 #[ntex::test]
4387 async fn recv_uses_decode_eof_after_eof() {
4388 let (client, server) = IoTest::create();
4389 client.remote_buffer_cap(1024);
4390 let io = Io::new(server, SharedCfg::new("SRV"));
4391 let codec = FixedSizeEof(8, std::cell::Cell::new(0));
4392
4393 client.write("12345678");
4394 sleep(Millis(25)).await;
4395 assert_eq!(io.recv(&codec).await.unwrap().unwrap(), "12345678");
4396 assert_eq!(codec.1.get(), 0);
4398
4399 client.write("123");
4401 sleep(Millis(25)).await;
4402 client.close().await;
4403
4404 assert_eq!(io.recv(&codec).await.unwrap().unwrap(), "123");
4405 assert!(io.recv(&codec).await.unwrap().is_none());
4406 assert!(codec.1.get() >= 2);
4407 assert_eq!(io.with_read_dst(|b| b.len()), 0);
4408 }
4409
4410 #[ntex::test]
4411 async fn recv_local_shutdown_is_not_truncation() {
4412 let (client, server) = IoTest::create();
4413 client.remote_buffer_cap(1024);
4414 let io = Io::new(server, SharedCfg::new("SRV"));
4415
4416 client.write("123");
4419 sleep(Millis(25)).await;
4420 io.close();
4421 sleep(Millis(25)).await;
4422
4423 assert!(io.recv(&FixedSize(8)).await.unwrap().is_none());
4424 assert_eq!(io.with_read_dst(|b| b.len()), 3);
4425 }
4426
4427 #[ntex::test]
4428 async fn read_pause_stops_transport_reads() {
4429 let (client, server) = IoTest::create();
4430 client.remote_buffer_cap(1024);
4431 let io = Io::new(server, SharedCfg::new("SRV"));
4432
4433 assert!(lazy(|cx| io.poll_read_pause(cx)).await.is_pending());
4434 assert!(io.flags().is_read_paused());
4435 assert!(lazy(|cx| io.poll_read_pause(cx)).await.is_pending());
4436
4437 client.write("data");
4439 sleep(Millis(25)).await;
4440 assert_eq!(io.st().buffer.read_dst_size(), 0);
4441
4442 io.st().notify_timeout();
4444 assert!(matches!(
4445 lazy(|cx| io.poll_read_pause(cx)).await,
4446 Poll::Ready(IoStatusUpdate::Timeout)
4447 ));
4448
4449 assert_eq!(io.read_notify().await.unwrap(), Some(()));
4451 assert!(!io.flags().is_read_paused());
4452 assert_eq!(io.with_read_dst(BytesMut::take), b"data");
4453 }
4454
4455 #[ntex::test]
4457 async fn read_dst_size_keeps_read_state() {
4458 let (client, server) = IoTest::create();
4459 client.remote_buffer_cap(1024);
4460 let io = Io::new(server, SharedCfg::new("SRV"));
4461
4462 assert!(lazy(|cx| io.poll_read_pause(cx)).await.is_pending());
4464 assert_eq!(io.read_dst_size(), 0);
4465 assert!(io.flags().is_read_paused());
4466
4467 client.write("data");
4469 assert_eq!(io.read_notify().await.unwrap(), Some(()));
4470 io.st().flags.set_read_ready();
4471 assert_eq!(io.read_dst_size(), 4);
4472 assert!(io.flags().is_read_ready());
4473 assert_eq!(io.with_read_dst(BytesMut::take), b"data");
4474 assert!(!io.flags().is_read_ready());
4475 }
4476
4477 struct Failing;
4478
4479 impl Decoder for Failing {
4480 type Item = Bytes;
4481 type Error = &'static str;
4482
4483 fn decode(&self, _: &mut BytesMut) -> Result<Option<Bytes>, &'static str> {
4484 Err("invalid frame")
4485 }
4486 }
4487
4488 #[ntex::test]
4489 async fn recv_reports_decoder_error() {
4490 let (client, server) = IoTest::create();
4491 client.remote_buffer_cap(1024);
4492 let io = Io::new(server, SharedCfg::new("SRV"));
4493
4494 client.write("data");
4495 let Err(Either::Left(err)) = io.recv(&Failing).await else {
4496 panic!("expected a decoder error")
4497 };
4498 assert_eq!(err, "invalid frame");
4499 }
4500
4501 #[ntex::test]
4504 async fn poll_recv_decode_reports_timeout_before_decoding() {
4505 let (client, server) = IoTest::create();
4506 client.remote_buffer_cap(1024);
4507 let io = Io::new(server, SharedCfg::new("SRV"));
4508
4509 client.write("data");
4510 sleep(Millis(25)).await;
4511 io.st().notify_timeout();
4512
4513 let res = lazy(|cx| io.poll_recv_decode(&BytesCodec, cx)).await;
4514 assert!(matches!(res, Err(RecvError::Timeout)));
4515 assert_eq!(io.st().buffer.read_dst_size(), 4);
4516
4517 let decoded = lazy(|cx| io.poll_recv_decode(&BytesCodec, cx))
4518 .await
4519 .unwrap();
4520 assert_eq!(decoded.item.unwrap(), "data");
4521 assert_eq!((decoded.consumed, decoded.remains), (4, 0));
4522 }
4523
4524 #[ntex::test]
4527 async fn poll_recv_decode_reports_write_backpressure_before_decoding() {
4528 let (client, server) = IoTest::create();
4529 client.remote_buffer_cap(1024);
4530 let io = Io::new(server, SharedCfg::new("SRV"));
4531
4532 client.write("data");
4533 sleep(Millis(25)).await;
4534 io.st().flags.set_wr_backpressure();
4535
4536 let res = lazy(|cx| io.poll_recv_decode(&BytesCodec, cx)).await;
4537 assert!(matches!(res, Err(RecvError::WriteBackpressure)));
4538 assert_eq!(io.st().buffer.read_dst_size(), 4);
4539
4540 io.flush(false).await.unwrap();
4541 let decoded = lazy(|cx| io.poll_recv_decode(&BytesCodec, cx))
4542 .await
4543 .unwrap();
4544 assert_eq!(decoded.item.unwrap(), "data");
4545 }
4546
4547 #[ntex::test]
4550 async fn poll_recv_decode_closing_decodes_buffered_input() {
4551 let (client, server) = IoTest::create();
4552 client.remote_buffer_cap(1024);
4553 let io = Io::new(server, SharedCfg::new("SRV"));
4554
4555 client.write("data");
4556 sleep(Millis(25)).await;
4557 io.close();
4558 sleep(Millis(25)).await;
4559 io.st().notify_timeout();
4560 io.st().flags.set_wr_backpressure();
4561
4562 let decoded = lazy(|cx| io.poll_recv_decode(&BytesCodec, cx))
4563 .await
4564 .unwrap();
4565 assert_eq!(decoded.item.unwrap(), "data");
4566
4567 let res = lazy(|cx| io.poll_recv_decode(&BytesCodec, cx)).await;
4568 assert!(matches!(res, Err(RecvError::PeerGone(None))));
4569 }
4570
4571 #[ntex::test]
4572 async fn poll_flush_enables_write_backpressure() {
4573 let (client, server) = IoTest::create();
4574 client.remote_buffer_cap(0);
4575 let io = Io::new(
4576 server,
4577 SharedCfg::new("SRV").add(IoConfig::default().set_write_backpressure(16)),
4578 );
4579
4580 io.with_write_dst(|buf| buf.extend_from_slice(BIN2));
4582 assert!(!io.flags().is_wr_backpressure());
4583
4584 assert!(lazy(|cx| io.poll_flush(cx, false)).await.is_pending());
4585 assert!(io.flags().is_wr_backpressure());
4586
4587 client.remote_buffer_cap(1024);
4588 assert_eq!(client.read().await.unwrap(), BIN2);
4589 io.flush(false).await.unwrap();
4590 assert!(!io.flags().is_wr_backpressure());
4591 }
4592
4593 struct Gate<F>(F, Rc<Cell<bool>>, Rc<Cell<bool>>);
4596
4597 impl<F: Filter> Filter for Gate<F> {
4598 fn query(&self, id: std::any::TypeId) -> Option<Box<dyn std::any::Any>> {
4599 self.0.query(id)
4600 }
4601
4602 fn process_read_buf(&self, ctx: &mut crate::FilterCtx<'_>) -> io::Result<()> {
4603 self.0.process_read_buf(ctx)
4604 }
4605
4606 fn process_write_buf(&self, ctx: &mut crate::FilterCtx<'_>) -> io::Result<()> {
4607 self.0.process_write_buf(ctx)
4608 }
4609
4610 fn shutdown(&self, ctx: &mut crate::FilterCtx<'_>) -> io::Result<Poll<()>> {
4611 self.0.shutdown(ctx)
4612 }
4613
4614 fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Readiness> {
4615 match self.0.poll_read_ready(cx) {
4616 Poll::Ready(Readiness::Ready) if self.1.get() => Poll::Pending,
4617 res => res,
4618 }
4619 }
4620
4621 fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<Readiness> {
4622 match self.0.poll_write_ready(cx) {
4623 Poll::Ready(Readiness::Ready) if self.2.get() => Poll::Pending,
4624 res => res,
4625 }
4626 }
4627 }
4628
4629 #[derive(Debug)]
4630 struct GateTransport;
4631
4632 impl IoStream for GateTransport {
4633 fn start(self, _: IoContext) -> Box<dyn Handle> {
4634 Box::new(self)
4635 }
4636 }
4637
4638 impl Handle for GateTransport {}
4639
4640 #[ntex::test]
4641 async fn filter_pause_pauses_reading() {
4642 let blocked = Rc::new(Cell::new(false));
4643 let b = blocked.clone();
4644 let io = Io::new(GateTransport, SharedCfg::default())
4645 .map_filter(move |f| Gate(f, b, Rc::default()));
4646 let ctx = IoContext::new(io.get_ref());
4647
4648 assert_eq!(
4649 lazy(|cx| ctx.poll_read_ready(cx)).await,
4650 Poll::Ready(Readiness::Ready)
4651 );
4652 assert!(!io.is_read_filter_paused());
4653
4654 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_pending());
4656 blocked.set(true);
4657 assert!(lazy(|cx| ctx.poll_read_ready(cx)).await.is_pending());
4658 assert!(io.is_read_filter_paused());
4659 assert!(!io.st().dispatch_task.is_set(), "dispatcher is notified");
4660
4661 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_pending());
4663 assert!(lazy(|cx| ctx.poll_read_ready(cx)).await.is_pending());
4664 assert!(io.st().dispatch_task.is_set());
4665
4666 let mut buf = ctx.take_read_buf();
4668 buf.extend_from_slice(b"12");
4669 assert_eq!(
4670 ctx.release_read_buf(buf, Poll::Ready(Ok(2))),
4671 IoTaskStatus::Pause
4672 );
4673 assert_eq!(io.with_read_dst(BytesMut::take), b"12");
4674 assert_eq!(
4675 ctx.with_read_buf(|_| Poll::<io::Result<usize>>::Pending),
4676 IoTaskStatus::Pause
4677 );
4678
4679 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_pending());
4681 blocked.set(false);
4682 assert_eq!(
4683 lazy(|cx| ctx.poll_read_ready(cx)).await,
4684 Poll::Ready(Readiness::Ready)
4685 );
4686 assert!(!io.is_read_filter_paused());
4687 assert!(!io.st().dispatch_task.is_set(), "dispatcher is notified");
4688 assert_eq!(
4689 ctx.with_read_buf(|_| Poll::<io::Result<usize>>::Pending),
4690 IoTaskStatus::Io
4691 );
4692 }
4693
4694 #[ntex::test]
4695 async fn io_state_pause_is_not_filter_pause() {
4696 let blocked = Rc::new(Cell::new(true));
4697 let b = blocked.clone();
4698 let io = Io::new(GateTransport, SharedCfg::default())
4699 .map_filter(move |f| Gate(f, b, Rc::default()));
4700 let ctx = IoContext::new(io.get_ref());
4701
4702 io.st().flags.set_read_paused();
4704 assert!(lazy(|cx| ctx.poll_read_ready(cx)).await.is_pending());
4705 assert!(!io.is_read_filter_paused());
4706
4707 io.st().flags.unset_read_paused();
4709 assert!(lazy(|cx| ctx.poll_read_ready(cx)).await.is_pending());
4710 assert!(io.is_read_filter_paused());
4711
4712 io.st().flags.set_read_paused();
4714 assert!(lazy(|cx| ctx.poll_read_ready(cx)).await.is_pending());
4715 assert!(io.is_read_filter_paused());
4716
4717 blocked.set(false);
4719 io.st().flags.unset_read_paused();
4720 assert_eq!(
4721 lazy(|cx| ctx.poll_read_ready(cx)).await,
4722 Poll::Ready(Readiness::Ready)
4723 );
4724 assert!(!io.is_read_filter_paused());
4725 }
4726
4727 #[ntex::test]
4728 async fn filter_pause_pauses_writing() {
4729 let blocked = Rc::new(Cell::new(true));
4730 let b = blocked.clone();
4731 let io = Io::new(GateTransport, SharedCfg::default())
4732 .map_filter(move |f| Gate(f, Rc::default(), b));
4733 let ctx = IoContext::new(io.get_ref());
4734
4735 assert!(lazy(|cx| ctx.poll_write_ready(cx)).await.is_pending());
4737 assert!(!io.is_write_filter_paused());
4738
4739 io.encode_slice(b"1234").unwrap();
4741 sleep(Millis(10)).await;
4742 assert!(!io.st().flags.is_write_paused());
4743 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_pending());
4744 assert!(lazy(|cx| ctx.poll_write_ready(cx)).await.is_pending());
4745 assert!(io.is_write_filter_paused());
4746 assert!(!io.st().dispatch_task.is_set(), "dispatcher is notified");
4747
4748 ctx.with_write_dst(|dst| {
4750 let mut page = dst.take().unwrap();
4751 page.advance_to(2);
4752 dst.prepend(page);
4753 });
4754 assert_eq!(ctx.update_write_status(Ok(2)), IoTaskStatus::Pause);
4755 assert!(!io.st().flags.is_write_paused());
4756 assert_eq!(io.st().buffer.write_buf_size(), 2);
4757
4758 assert!(lazy(|cx| io.poll_read_more(cx)).await.is_pending());
4760 blocked.set(false);
4761 assert_eq!(
4762 lazy(|cx| ctx.poll_write_ready(cx)).await,
4763 Poll::Ready(Readiness::Ready)
4764 );
4765 assert!(!io.is_write_filter_paused());
4766 assert!(!io.st().dispatch_task.is_set(), "dispatcher is notified");
4767 assert_eq!(ctx.update_write_status(Ok(0)), IoTaskStatus::Io);
4768 }
4769}