1#![deny(clippy::pedantic)]
12#![allow(clippy::cast_possible_truncation)]
13use std::task::{Context, Poll, ready};
14use std::time::Instant;
15use std::{cell::Cell, fmt, future::Future, future::poll_fn, io, mem, pin::Pin, rc::Rc};
16
17use ntex_codec::{Decoder, Encoder};
18use ntex_io::{Decoded, IoBoxed, IoStatusUpdate, RecvError};
19use ntex_service::pipeline::{Pipeline, PipelineCall};
20use ntex_util::{spawn, time::Seconds, time::Sleep, time::sleep};
21
22mod timer;
23
24use self::timer::{Timer, Timers};
25
26type Response<U> = <U as Encoder>::Item;
27
28pub enum DispatchItem<U: Encoder + Decoder> {
30 Item(<U as Decoder>::Item),
32 Control(Control),
34 Stop(Reason<U>),
36}
37
38#[derive(Copy, Clone, Debug, PartialEq, Eq)]
39pub enum Control {
41 WBackPressureEnabled,
43 WBackPressureDisabled,
45}
46
47pub enum Reason<U: Encoder + Decoder> {
49 Service,
51 Io(Option<io::Error>),
58 Encoder(<U as Encoder>::Error),
60 Decoder(<U as Decoder>::Error),
62 KeepAlive,
64 ReadTimeout,
66 WriteTimeout,
69}
70
71fn truncated(io: &IoBoxed) -> Option<io::Error> {
73 if io.is_read_eof() && io.read_dst_size() != 0 {
74 Some(io::Error::new(
75 io::ErrorKind::UnexpectedEof,
76 "bytes remaining on stream",
77 ))
78 } else {
79 None
80 }
81}
82
83pub struct Dispatcher<U, Err>
100where
101 U: Encoder + Decoder + 'static,
102 Err: 'static,
103{
104 inner: DispatcherInner<U, Err>,
105}
106
107impl<U: Encoder + Decoder, Err> Unpin for Dispatcher<U, Err> {}
109
110impl<U: Encoder + Decoder, Err> fmt::Debug for Dispatcher<U, Err> {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 f.debug_struct("Dispatcher").finish_non_exhaustive()
113 }
114}
115
116type Call<U, Err> = PipelineCall<DispatchItem<U>, Option<Response<U>>, Err>;
117type Service<U, Err> = Pipeline<DispatchItem<U>, Option<Response<U>>, Err>;
118
119struct DispatcherInner<U, Err>
120where
121 U: Encoder + Decoder + 'static,
122{
123 st: DispatcherState<U, Err>,
124 error: Option<Err>,
125 shared: Rc<DispatcherShared<U, Err>>,
126 response: Option<Call<U, Err>>,
127 timers: Timers,
128 max_inflight: u32,
129}
130
131pub(crate) struct DispatcherShared<U, Err>
132where
133 U: Encoder + Decoder,
134{
135 io: IoBoxed,
136 codec: U,
137 service: Service<U, Err>,
138 keepalive: bool,
139 error: Cell<Option<DispatcherError<Err, <U as Encoder>::Error>>>,
140 inflight: Cell<u32>,
141}
142
143#[derive(Debug)]
144enum DispatcherState<U: Encoder + Decoder, Err> {
145 Processing,
146 Backpressure,
147 Stop(StopCall<U, Err>),
148 Shutdown,
149 ShutdownIo,
150}
151
152#[derive(Debug)]
153struct StopCall<U: Encoder + Decoder, Err> {
154 fut: Call<U, Err>,
155 timeout: Option<Sleep>,
157}
158
159#[derive(Debug)]
160enum DispatcherError<S, U> {
161 Encoder(U),
162 Service(S),
163}
164
165enum PollService {
166 Backpressure,
168 Continue,
169 Ready,
170}
171
172impl<U, Err> Dispatcher<U, Err>
173where
174 U: Decoder + Encoder + 'static,
175 Err: 'static,
176{
177 pub fn new<Io>(io: Io, codec: U, service: Service<U, Err>) -> Dispatcher<U, Err>
182 where
183 IoBoxed: From<Io>,
184 {
185 let io = IoBoxed::from(io);
186 let shared = Rc::new(DispatcherShared {
187 keepalive: !io.cfg().keepalive_timeout().is_zero(),
188 io,
189 codec,
190 service,
191 error: Cell::new(None),
192 inflight: Cell::new(0),
193 });
194
195 Dispatcher {
196 inner: DispatcherInner {
197 timers: Timers::new(&shared.io),
198 shared,
199 response: None,
200 error: None,
201 st: DispatcherState::Processing,
202 max_inflight: u32::MAX,
203 },
204 }
205 }
206
207 #[must_use]
208 pub fn max_inflight(mut self, max: u32) -> Self {
218 assert!(max > 0, "max_inflight must be greater than zero");
219 self.inner.max_inflight = max;
220 self
221 }
222}
223
224impl<U, Err> DispatcherShared<U, Err>
225where
226 U: Encoder + Decoder + 'static,
227 Err: 'static,
228{
229 fn call(&self, item: DispatchItem<U>) -> Call<U, Err> {
230 self.inflight.set(self.inflight.get() + 1);
231 self.service.call_static(item)
232 }
233
234 fn handle_result(&self, item: Result<Option<Response<U>>, Err>, wake: bool) {
235 match item {
236 Ok(Some(val)) => {
237 if let Err(err) = self.io.encode(val, &self.codec) {
238 self.error.set(Some(DispatcherError::Encoder(err)));
239 }
240 }
241 Err(err) => self.error.set(Some(DispatcherError::Service(err))),
242 Ok(None) => (),
243 }
244 self.inflight.set(self.inflight.get() - 1);
245 if wake {
246 self.io.notify_dispatcher();
247 }
248 }
249}
250
251impl<U, Err> Future for Dispatcher<U, Err>
252where
253 U: Decoder + Encoder + 'static,
254 Err: 'static,
255{
256 type Output = Result<(), Err>;
257
258 #[allow(clippy::too_many_lines)]
259 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
260 let inner = &mut self.get_mut().inner;
261
262 if let Some(fut) = inner.response.as_mut()
264 && let Poll::Ready(item) = Pin::new(fut).poll(cx)
265 {
266 inner.shared.handle_result(item, false);
267 inner.response = None;
268 }
269
270 loop {
271 match inner.st {
272 DispatcherState::Processing => {
273 let item = match ready!(inner.poll_service(cx)) {
274 PollService::Ready => {
275 match inner.shared.io.poll_recv_decode(&inner.shared.codec, cx) {
277 Ok(decoded) => {
278 inner.update_timer(&decoded);
279 if let Some(el) = decoded.item {
280 DispatchItem::Item(el)
281 } else {
282 return Poll::Pending;
283 }
284 }
285 Err(RecvError::Timeout) if inner.timers.active != Timer::Write => {
286 match inner.shared.io.decode_item(&inner.shared.codec) {
289 Ok(decoded) => {
290 let timer = inner.timers.active;
291 inner.update_timer(&decoded);
292 if let Some(el) = decoded.item {
293 DispatchItem::Item(el)
294 } else {
295 if inner.timers.active == timer
298 && let Err(ctl) = inner.handle_timeout()
299 {
300 inner.st = inner.stop(ctl);
301 }
302 continue;
303 }
304 }
305 Err(err) => {
306 log::trace!(
307 "{}: Decoder error, stopping dispatcher: {:?}",
308 inner.shared.io.tag(),
309 err
310 );
311 inner.st = inner.stop(Reason::Decoder(err));
312 continue;
313 }
314 }
315 }
316 Err(RecvError::Timeout) => {
317 if let Err(ctl) = inner.handle_timeout() {
318 inner.st = inner.stop(ctl);
319 }
320 continue;
321 }
322 Err(RecvError::WriteBackpressure) => {
323 inner.start_write_timer();
325 inner.st = DispatcherState::Backpressure;
326 DispatchItem::Control(Control::WBackPressureEnabled)
327 }
328 Err(RecvError::Decoder(err)) => {
329 log::trace!(
330 "{}: Decoder error, stopping dispatcher: {:?}",
331 inner.shared.io.tag(),
332 err
333 );
334 inner.st = inner.stop(Reason::Decoder(err));
335 continue;
336 }
337 Err(RecvError::PeerGone(err)) => {
338 let err = err.or_else(|| truncated(&inner.shared.io));
339 log::trace!(
340 "{}: Peer is gone, stopping dispatcher: {:?}",
341 inner.shared.io.tag(),
342 err
343 );
344 inner.st = inner.stop(Reason::Io(err));
345 continue;
346 }
347 }
348 }
349 PollService::Backpressure => {
350 DispatchItem::Control(Control::WBackPressureEnabled)
351 }
352 PollService::Continue => continue,
353 };
354
355 inner.call_service(cx, item);
356 }
357 DispatcherState::Backpressure => {
359 match ready!(inner.poll_service(cx)) {
360 PollService::Ready | PollService::Backpressure => {}
361 PollService::Continue => continue,
362 }
363
364 if let Poll::Ready(IoStatusUpdate::Timeout) =
366 inner.shared.io.poll_status_update(cx)
367 && let Err(reason) = inner.handle_timeout()
368 {
369 inner.st = inner.stop(reason);
370 continue;
371 }
372 inner.start_write_timer();
374
375 let item = if let Err(err) = ready!(inner.shared.io.poll_flush(cx, false)) {
376 inner.st = inner.stop(Reason::Io(Some(err)));
377 continue;
378 } else {
379 inner.stop_timer();
381 inner.st = DispatcherState::Processing;
382 DispatchItem::Control(Control::WBackPressureDisabled)
383 };
384 inner.call_service(cx, item);
385 }
386 DispatcherState::Stop(ref mut stop) => {
388 let ready = inner.shared.service.poll_ready(cx);
390
391 if let Poll::Ready(result) = Pin::new(&mut stop.fut).poll(cx) {
392 inner.shared.handle_result(result, false);
393 if let Some(DispatcherError::Service(err)) = inner.shared.error.take()
396 && inner.error.is_none()
397 {
398 inner.error = Some(err);
399 }
400 inner.shared.io.stop_timer();
401 inner.st = DispatcherState::Shutdown;
402 continue;
403 }
404 if ready.is_ready() {
405 return Poll::Pending;
406 }
407
408 let timeout = stop
411 .timeout
412 .get_or_insert_with(|| sleep(inner.shared.io.cfg().shutdown_timeout()));
413 ready!(timeout.poll_elapsed(cx));
414 log::trace!(
415 "{}: Service is not ready for stop, shutdown io",
416 inner.shared.io.tag()
417 );
418
419 let DispatcherState::Stop(stop) =
420 mem::replace(&mut inner.st, DispatcherState::ShutdownIo)
421 else {
422 unreachable!()
423 };
424 inner.shared.io.stop_timer();
425
426 let shared = inner.shared.clone();
428 let mut fut = Some(stop.fut);
429 spawn(poll_fn(move |cx| {
430 let _ = shared.service.poll_ready(cx);
431 if let Some(f) = fut.as_mut() {
432 let result = ready!(Pin::new(f).poll(cx));
433 fut = None;
434 shared.handle_result(result, false);
435 }
436 if shared.inflight.get() != 0 {
437 shared.io.register_dispatch(cx);
438 return Poll::Pending;
439 }
440 shared.service.poll_shutdown(cx)
441 }));
442 }
443 DispatcherState::Shutdown => {
445 let _ = inner.shared.service.poll_ready(cx);
447
448 if inner.shared.inflight.get() != 0 {
449 inner.shared.io.register_dispatch(cx);
450 return Poll::Pending;
451 }
452
453 ready!(inner.shared.service.poll_shutdown(cx));
454 log::trace!(
455 "{}: Service shutdown is completed, stop",
456 inner.shared.io.tag()
457 );
458 inner.st = DispatcherState::ShutdownIo;
459 }
460 DispatcherState::ShutdownIo => {
462 let _ = ready!(inner.shared.io.poll_shutdown(cx));
463
464 return Poll::Ready(if let Some(err) = inner.error.take() {
465 Err(err)
466 } else {
467 Ok(())
468 });
469 }
470 }
471 }
472 }
473}
474
475impl<U, Err> DispatcherInner<U, Err>
476where
477 U: Decoder + Encoder + 'static,
478 Err: 'static,
479{
480 fn stop(&self, reason: Reason<U>) -> DispatcherState<U, Err> {
481 DispatcherState::Stop(StopCall {
482 fut: self.shared.call(DispatchItem::Stop(reason)),
483 timeout: None,
484 })
485 }
486
487 fn call_service(&mut self, cx: &mut Context<'_>, item: DispatchItem<U>) {
488 let mut fut = self.shared.call(item);
489
490 if let Poll::Ready(result) = Pin::new(&mut fut).poll(cx) {
492 self.shared.handle_result(result, false);
493 } else if self.response.is_none() {
494 self.response = Some(fut);
495 } else {
496 let shared = self.shared.clone();
497 spawn(async move {
498 let result = fut.await;
499 shared.handle_result(result, true);
500 });
501 }
502 }
503
504 fn check_error(&mut self) -> PollService {
505 if let Some(err) = self.shared.error.take() {
507 log::trace!(
508 "{}: Error occurred, stopping dispatcher",
509 self.shared.io.tag()
510 );
511 match err {
512 DispatcherError::Encoder(err) => {
513 self.st = self.stop(Reason::Encoder(err));
514 }
515 DispatcherError::Service(err) => {
516 self.error = Some(err);
517 self.st = self.stop(Reason::Service);
518 }
519 }
520 PollService::Continue
521 } else {
522 PollService::Ready
523 }
524 }
525
526 fn poll_service(&mut self, cx: &mut Context<'_>) -> Poll<PollService> {
527 let ready = if self.shared.inflight.get() >= self.max_inflight {
529 Poll::Pending
530 } else {
531 self.shared.service.poll_ready(cx)
532 };
533 match ready {
534 Poll::Ready(Ok(())) => Poll::Ready(self.check_error()),
535 Poll::Pending => {
537 log::trace!(
538 "{}: Service is not ready, register dispatcher",
539 self.shared.io.tag()
540 );
541
542 if self.timers.active != Timer::Write {
544 self.stop_timer();
545 }
546 self.timers.reset_read(self.shared.io.cfg());
547
548 match ready!(self.shared.io.poll_read_pause(cx)) {
549 IoStatusUpdate::Timeout => {
550 if let Err(reason) = self.handle_timeout() {
551 log::trace!(
552 "{}: Timeout during pause, stopping dispatcher: {:?}",
553 self.shared.io.tag(),
554 reason
555 );
556 self.st = self.stop(reason);
557 }
558 Poll::Ready(PollService::Continue)
559 }
560 IoStatusUpdate::PeerGone(_) if self.shared.io.read_dst_size() != 0 => {
563 log::trace!(
564 "{}: Peer is gone during pause, wait for service",
565 self.shared.io.tag()
566 );
567 Poll::Pending
568 }
569 IoStatusUpdate::PeerGone(err) => {
570 log::trace!(
571 "{}: Peer is gone during pause, stopping dispatcher: {:?}",
572 self.shared.io.tag(),
573 err
574 );
575 self.st = self.stop(Reason::Io(err));
576 Poll::Ready(PollService::Continue)
577 }
578 IoStatusUpdate::WriteBackpressure => {
579 if !matches!(self.st, DispatcherState::Backpressure) {
580 self.start_write_timer();
581 }
582 self.st = DispatcherState::Backpressure;
583 Poll::Ready(PollService::Backpressure)
584 }
585 }
586 }
587 Poll::Ready(Err(err)) => {
589 log::trace!(
590 "{}: Service readiness check failed, stopping",
591 self.shared.io.tag()
592 );
593 self.st = self.stop(Reason::Service);
594 self.error = Some(err);
595 Poll::Ready(PollService::Continue)
596 }
597 }
598 }
599
600 fn start_write_timer(&mut self) {
607 let timeout = self.shared.io.cfg().write_timeout();
608 if timeout.is_zero() || self.shared.io.is_write_filter_paused() {
609 self.stop_timer();
610 } else if self.timers.active != Timer::Write {
611 self.timers.active = Timer::Write;
612 self.shared.io.start_timer(timeout);
613 }
614 }
615
616 fn update_timer(&mut self, decoded: &Decoded<<U as Decoder>::Item>) {
617 let item = decoded.item.is_some();
618 self.timers.update_read(
619 self.shared.io.cfg(),
620 item,
621 decoded.remains as u32,
622 decoded.consumed as u32,
623 );
624
625 if !item && self.shared.io.is_read_filter_paused() {
627 if self.timers.active != Timer::Write {
628 self.stop_timer();
629 }
630 self.timers.reset_read(self.shared.io.cfg());
631 return;
632 }
633
634 let handling = item || self.shared.inflight.get() != 0;
636 let timer = self
637 .timers
638 .select(self.shared.io.cfg(), self.shared.keepalive, handling);
639 self.set_timer(timer);
640 }
641
642 fn stop_timer(&mut self) {
644 if self.timers.active != Timer::Stopped {
645 self.timers.active = Timer::Stopped;
646 self.shared.io.stop_timer();
647 }
648 }
649
650 fn set_timer(&mut self, timer: Timer) {
656 if self.timers.active == timer {
657 return;
658 }
659 let io = &self.shared.io;
660 self.timers.active = match (self.timers.active, timer) {
661 (Timer::KeepAlive | Timer::Suspended, Timer::Stopped) => Timer::Suspended,
662 (_, Timer::KeepAlive) => {
663 log::trace!(
664 "{}: Start keep-alive timer {:?}",
665 io.tag(),
666 io.cfg().keepalive_timeout()
667 );
668 let hnd = io.start_timer(io.cfg().keepalive_timeout());
669 self.timers.keepalive = Some(hnd.instant());
670 Timer::KeepAlive
671 }
672 (_, Timer::FrameRead) if let Some(params) = io.cfg().frame_read_rate() => {
673 io.start_timer(params.timeout);
674 Timer::FrameRead
675 }
676 _ => {
677 io.stop_timer();
678 Timer::Stopped
679 }
680 };
681 }
682
683 fn handle_timeout(&mut self) -> Result<(), Reason<U>> {
684 match self.timers.active {
685 Timer::FrameRead => {
686 let (Some(params), Some(p)) = (
687 self.shared.io.cfg().frame_read_rate(),
688 self.timers.read.progress(),
689 ) else {
690 self.timers.active = Timer::Stopped;
691 return Ok(());
692 };
693
694 if p.consumed > params.rate {
696 let total = p.consumed;
697 p.consumed = 0;
698
699 if !params.max_timeout.is_zero() {
700 p.max_timeout = Seconds(p.max_timeout.0.saturating_sub(params.timeout.0));
701 }
702
703 if params.max_timeout.is_zero() || !p.max_timeout.is_zero() {
704 log::trace!(
705 "{}: Frame read rate {:?}, extend timer",
706 self.shared.io.tag(),
707 total
708 );
709 self.shared.io.start_timer(params.timeout);
710 return Ok(());
711 }
712 log::trace!(
713 "{}: Max payload timeout has been reached",
714 self.shared.io.tag()
715 );
716 }
717 Err(Reason::ReadTimeout)
718 }
719 Timer::Write if !self.shared.io.is_wr_backpressure() => {
721 self.timers.active = Timer::Stopped;
722 Ok(())
723 }
724 Timer::Write if self.shared.io.is_write_filter_paused() => {
726 self.stop_timer();
727 Ok(())
728 }
729 Timer::Write => {
730 log::trace!(
731 "{}: Write backpressure timeout, stopping dispatcher",
732 self.shared.io.tag()
733 );
734 Err(Reason::WriteTimeout)
735 }
736 Timer::KeepAlive => {
737 log::trace!(
738 "{}: Keep-alive error, stopping dispatcher",
739 self.shared.io.tag()
740 );
741 Err(Reason::KeepAlive)
742 }
743 Timer::Suspended
746 if self
747 .timers
748 .keepalive
749 .is_none_or(|expiry| Instant::now() >= expiry) =>
750 {
751 self.timers.active = Timer::Stopped;
752 Ok(())
753 }
754 Timer::Stopped | Timer::Suspended if self.shared.inflight.get() == 0 => {
756 log::trace!(
757 "{}: Idle timeout, stopping dispatcher",
758 self.shared.io.tag()
759 );
760 Err(Reason::KeepAlive)
761 }
762 Timer::Stopped | Timer::Suspended => Ok(()),
763 }
764 }
765}
766
767impl<U> fmt::Debug for DispatchItem<U>
768where
769 U: Encoder + Decoder,
770 <U as Decoder>::Item: fmt::Debug,
771{
772 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
773 match self {
774 DispatchItem::Item(item) => f.debug_tuple("DispatchItem::Item").field(item).finish(),
775 DispatchItem::Control(e) => f.debug_tuple("DispatchItem::Control").field(e).finish(),
776 DispatchItem::Stop(e) => f.debug_tuple("DispatchItem::Stop").field(e).finish(),
777 }
778 }
779}
780
781impl<U> fmt::Debug for Reason<U>
782where
783 U: Encoder + Decoder,
784 <U as Encoder>::Error: fmt::Debug,
785 <U as Decoder>::Error: fmt::Debug,
786{
787 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
788 match self {
789 Reason::Service => f.write_str("Reason::Service"),
790 Reason::Io(err) => f.debug_tuple("Reason::Io").field(err).finish(),
791 Reason::Encoder(err) => f.debug_tuple("Reason::Encoder").field(err).finish(),
792 Reason::Decoder(err) => f.debug_tuple("Reason::Decoder").field(err).finish(),
793 Reason::KeepAlive => f.write_str("Reason::KeepAlive"),
794 Reason::ReadTimeout => f.write_str("Reason::ReadTimeout"),
795 Reason::WriteTimeout => f.write_str("Reason::WriteTimeout"),
796 }
797 }
798}
799
800#[cfg(test)]
801#[allow(clippy::unused_async_trait_impl)]
802mod tests {
803 use std::sync::{Arc, Mutex, atomic::AtomicBool, atomic::Ordering::Relaxed};
804 use std::{cell::RefCell, io};
805
806 use ntex_bytes::{BytePageSize, BytePages, Bytes, BytesMut};
807 use ntex_codec::BytesCodec;
808 use ntex_io::{Io, IoConfig, IoRef, testing::IoTest};
809 use ntex_service::{Ctx, Pipeline, Service, cfg::SharedCfg};
810 use ntex_util::time::{Millis, sleep, timeout};
811 use ntex_util::{channel::condition::Condition, channel::oneshot, future::lazy};
812 use rand::Rng;
813
814 use super::*;
815
816 async fn wait_until(max: Millis, f: impl Fn() -> bool) {
818 for _ in 0..max.0 / 50 {
819 if f() {
820 break;
821 }
822 sleep(Millis(50)).await;
823 }
824 }
825
826 async fn wait_closed(client: &IoTest, max: Millis) {
828 wait_until(max, || client.is_closed()).await;
829 }
830
831 pub(crate) struct State(IoRef);
832
833 impl State {
834 fn io(&self) -> &IoRef {
835 &self.0
836 }
837
838 fn close(&self) {
839 self.0.close();
840 }
841 }
842
843 #[derive(Copy, Clone)]
844 struct BCodec(usize);
845
846 impl Encoder for BCodec {
847 type Item = Bytes;
848 type Error = io::Error;
849
850 fn encode(&self, item: Bytes, dst: &mut BytePages) -> Result<(), Self::Error> {
851 dst.append(item);
852 Ok(())
853 }
854 }
855
856 impl Decoder for BCodec {
857 type Item = Bytes;
858 type Error = io::Error;
859
860 fn decode(&self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
861 if src.len() < self.0 {
862 Ok(None)
863 } else {
864 Ok(Some(src.split_to(self.0)))
865 }
866 }
867 }
868
869 impl<U, Err> Dispatcher<U, Err>
870 where
871 U: Decoder + Encoder + 'static,
872 {
873 pub(crate) fn debug<S>(io: Io, codec: U, service: S) -> (Self, State)
875 where
876 S: Service<(), DispatchItem<U>, Res = Option<Response<U>>, Error = Err> + 'static,
877 {
878 let st = State(io.get_ref());
879 (Dispatcher::new(io, codec, Pipeline::new((), service)), st)
880 }
881 }
882
883 #[ntex::test]
884 async fn basics() {
885 let (client, server) = IoTest::create();
886 client.remote_buffer_cap(1024);
887 client.write("GET /test HTTP/1\r\n\r\n");
888
889 let (disp, _) = Dispatcher::debug(
890 Io::from(server),
891 BytesCodec,
892 ntex_service::fn_service(|msg: DispatchItem<BytesCodec>| async move {
893 sleep(Millis(50)).await;
894 if let DispatchItem::Item(msg) = msg {
895 Ok::<_, ()>(Some(msg))
896 } else {
897 Ok(None)
898 }
899 }),
900 );
901 spawn(async move {
902 let _ = disp.await;
903 });
904
905 sleep(Millis(25)).await;
906 let buf = client.read().await.unwrap();
907 assert_eq!(buf, Bytes::from_static(b"GET /test HTTP/1\r\n\r\n"));
908
909 client.write("GET /test HTTP/1\r\n\r\n");
910 let buf = client.read().await.unwrap();
911 assert_eq!(buf, Bytes::from_static(b"GET /test HTTP/1\r\n\r\n"));
912
913 client.close().await;
914 sleep(Millis(75)).await;
915 assert!(client.is_server_dropped());
916 }
917
918 #[ntex::test]
919 async fn sink() {
920 let (client, server) = IoTest::create();
921 client.remote_buffer_cap(1024);
922 client.write("GET /test HTTP/1\r\n\r\n");
923
924 let (disp, st) = Dispatcher::debug(
925 Io::from(server),
926 BytesCodec,
927 ntex_service::fn_service(|msg: DispatchItem<BytesCodec>| async move {
928 if let DispatchItem::Item(msg) = msg {
929 Ok::<_, ()>(Some(msg))
930 } else if let DispatchItem::Stop(_) = msg {
931 Ok(None)
932 } else {
933 panic!()
934 }
935 }),
936 );
937 spawn(async move {
938 let _ = disp.await;
939 });
940
941 let buf = client.read().await.unwrap();
942 assert_eq!(buf, Bytes::from_static(b"GET /test HTTP/1\r\n\r\n"));
943
944 assert!(
945 st.io()
946 .encode(Bytes::from_static(b"test"), &BytesCodec)
947 .is_ok()
948 );
949 let buf = client.read().await.unwrap();
950 assert_eq!(buf, Bytes::from_static(b"test"));
951
952 st.close();
953 wait_until(Millis(2000), || client.is_server_dropped()).await;
954 assert!(client.is_server_dropped());
955 }
956
957 #[ntex::test]
958 async fn err_in_service() {
959 let (client, server) = IoTest::create();
960 client.remote_buffer_cap(0);
961 client.write("GET /test HTTP/1\r\n\r\n");
962
963 let (disp, state) = Dispatcher::debug(
964 Io::new(server, SharedCfg::new("SRV")),
965 BytesCodec,
966 ntex_service::fn_service(|_: DispatchItem<BytesCodec>| async move {
967 Err::<Option<Bytes>, _>(())
968 }),
969 );
970 state
971 .io()
972 .encode(Bytes::from_static(b"GET /test HTTP/1\r\n\r\n"), &BytesCodec)
973 .unwrap();
974 spawn(async move {
975 let _ = disp.await;
976 });
977
978 client.remote_buffer_cap(1024);
980 let buf = client.read().await.unwrap();
981 assert_eq!(buf, Bytes::from_static(b"GET /test HTTP/1\r\n\r\n"));
982
983 wait_closed(&client, Millis(1000)).await;
985 assert!(client.is_closed());
986
987 client.close().await;
989
990 assert!(client.is_server_dropped());
992 }
993
994 #[ntex::test]
995 #[allow(clippy::items_after_statements)]
996 async fn err_in_service_ready() {
997 let (client, server) = IoTest::create();
998 client.remote_buffer_cap(0);
999 client.write("GET /test HTTP/1\r\n\r\n");
1000
1001 let counter = Rc::new(Cell::new(0));
1002
1003 struct Srv(Rc<Cell<usize>>);
1004
1005 impl Service<(), DispatchItem<BytesCodec>> for Srv {
1006 type Res = Option<Response<BytesCodec>>;
1007 type Error = &'static str;
1008
1009 async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Self::Error> {
1010 self.0.set(self.0.get() + 1);
1011 Err("test")
1012 }
1013
1014 async fn call(
1015 &self,
1016 _: DispatchItem<BytesCodec>,
1017 _: Ctx<'_, Self>,
1018 ) -> Result<Self::Res, Self::Error> {
1019 Ok(None)
1020 }
1021 }
1022
1023 let (disp, state) = Dispatcher::debug(Io::from(server), BytesCodec, Srv(counter.clone()));
1024 spawn(async move {
1025 let res = disp.await;
1026 assert_eq!(res, Err("test"));
1027 });
1028
1029 state
1030 .io()
1031 .encode(Bytes::from_static(b"GET /test HTTP/1\r\n\r\n"), &BytesCodec)
1032 .unwrap();
1033
1034 client.remote_buffer_cap(1024);
1036 let buf = client.read().await.unwrap();
1037 assert_eq!(buf, Bytes::from_static(b"GET /test HTTP/1\r\n\r\n"));
1038
1039 wait_closed(&client, Millis(1000)).await;
1041 assert!(client.is_closed());
1042
1043 client.close().await;
1045 assert!(client.is_server_dropped());
1046
1047 assert_eq!(counter.get(), 4);
1050 }
1051
1052 #[ntex::test]
1053 async fn write_backpressure() {
1054 let (client, server) = IoTest::create();
1055 client.remote_buffer_cap(0);
1057 client.write("GET /test HTTP/1\r\n\r\n");
1058
1059 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
1060 let data2 = data.clone();
1061
1062 let io = Io::new(
1063 server,
1064 SharedCfg::new("TEST").add(
1065 IoConfig::new()
1066 .set_read_size(BytePageSize::Size8, BytePageSize::Size8)
1067 .set_read_backpressure(BytePageSize::Size8.capacity())
1068 .set_write_backpressure(16 * 1024),
1069 ),
1070 );
1071
1072 let (disp, state) = Dispatcher::debug(
1073 io,
1074 BytesCodec,
1075 ntex_service::fn_service(move |msg: DispatchItem<BytesCodec>| {
1076 let data = data2.clone();
1077 async move {
1078 match msg {
1079 DispatchItem::Item(_) => {
1080 data.lock().unwrap().borrow_mut().push(0);
1081 let bytes = rand::rng()
1082 .sample_iter(&rand::distr::Alphanumeric)
1083 .take(65_536)
1084 .map(char::from)
1085 .collect::<String>();
1086 return Ok::<_, ()>(Some(Bytes::from(bytes)));
1087 }
1088 DispatchItem::Control(Control::WBackPressureEnabled) => {
1089 data.lock().unwrap().borrow_mut().push(1);
1090 }
1091 DispatchItem::Control(Control::WBackPressureDisabled) => {
1092 data.lock().unwrap().borrow_mut().push(2);
1093 }
1094 _ => (),
1095 }
1096 Ok(None)
1097 }
1098 }),
1099 );
1100
1101 spawn(async move {
1102 let _ = disp.await;
1103 });
1104
1105 let buf = client.read_any();
1106 assert_eq!(buf, Bytes::from_static(b""));
1107 client.write("GET /test HTTP/1\r\n\r\n");
1108 sleep(Millis(25)).await;
1109
1110 assert_eq!(client.remote_buffer(|buf| buf.len()), 0);
1112
1113 assert_eq!(state.io().with_write_src(|buf| buf.len()).unwrap(), 65536);
1115
1116 client.remote_buffer_cap(10240);
1117 sleep(Millis(50)).await;
1118 assert_eq!(state.io().with_write_src(|buf| buf.len()).unwrap(), 55296);
1119
1120 client.remote_buffer_cap(48056);
1121 sleep(Millis(50)).await;
1122 assert_eq!(state.io().with_write_src(|buf| buf.len()).unwrap(), 7240);
1123
1124 assert_eq!(&data.lock().unwrap().borrow()[..], &[0, 1, 2]);
1126 }
1127
1128 #[ntex::test]
1129 async fn disconnect_during_read_backpressure() {
1130 let (client, server) = IoTest::create();
1131 client.remote_buffer_cap(0);
1132
1133 let (disp, state) = Dispatcher::debug(
1134 Io::new(
1135 server,
1136 SharedCfg::new("TEST").add(
1137 IoConfig::new()
1138 .set_keepalive_timeout(Seconds::ZERO)
1139 .set_read_size(BytePageSize::Size4, BytePageSize::Size4)
1140 .set_read_backpressure(BytePageSize::Size4.capacity()),
1141 ),
1142 ),
1143 BytesCodec,
1144 ntex_util::services::inflight::InFlightService::new(
1145 1,
1146 ntex_service::fn_service(move |msg: DispatchItem<BytesCodec>| async move {
1147 if let DispatchItem::Item(_) = msg {
1148 sleep(Millis(500)).await;
1149 Ok::<_, ()>(None)
1150 } else {
1151 Ok(None)
1152 }
1153 }),
1154 ),
1155 );
1156
1157 let (tx, rx) = ntex::channel::oneshot::channel();
1158 ntex::rt::spawn(async move {
1159 let _ = disp.await;
1160 let _ = tx.send(());
1161 });
1162
1163 let bytes = rand::rng()
1164 .sample_iter(&rand::distr::Alphanumeric)
1165 .take(BytePageSize::Size4.capacity())
1166 .map(char::from)
1167 .collect::<String>();
1168 client.write(bytes.clone());
1169 sleep(Millis(25)).await;
1170 client.write(bytes);
1171 sleep(Millis(25)).await;
1172
1173 state.close();
1175 let _ = rx.recv().await;
1176 }
1177
1178 #[ntex::test]
1179 async fn application_close_waits_for_pending_service_call() {
1180 let started = Arc::new(AtomicBool::new(false));
1181 let started2 = started.clone();
1182 let release = Condition::<()>::new();
1183 let release2 = release.clone();
1184 let (client, server) = IoTest::create();
1185 client.remote_buffer_cap(1024);
1186
1187 let (mut disp, state) = Dispatcher::debug(
1188 Io::from(server),
1189 BytesCodec,
1190 ntex_service::fn_service(move |msg: DispatchItem<BytesCodec>| {
1191 let started = started2.clone();
1192 let waiter = release2.wait();
1193 async move {
1194 if matches!(msg, DispatchItem::Item(_)) {
1195 started.store(true, Relaxed);
1196 let _ = waiter.ready().await;
1197 }
1198 Ok::<_, ()>(None)
1199 }
1200 }),
1201 );
1202
1203 client.write("request");
1204 for _ in 0..100 {
1205 assert!(lazy(|cx| Pin::new(&mut disp).poll(cx)).await.is_pending());
1206 if started.load(Relaxed) {
1207 break;
1208 }
1209 sleep(Millis(10)).await;
1210 }
1211 assert!(started.load(Relaxed));
1212
1213 state.close();
1215 assert!(
1216 timeout(Millis(50), poll_fn(|cx| Pin::new(&mut disp).poll(cx)))
1217 .await
1218 .is_err()
1219 );
1220 release.notify(());
1221 timeout(Millis(1000), poll_fn(|cx| Pin::new(&mut disp).poll(cx)))
1222 .await
1223 .expect("dispatcher did not drain pending service call")
1224 .unwrap();
1225 }
1226
1227 #[ntex::test]
1228 async fn max_inflight_calls() {
1229 let calls = Rc::new(Cell::new(0));
1230 let calls2 = calls.clone();
1231 let release = Condition::<()>::new();
1232 let release2 = release.clone();
1233 let (client, server) = IoTest::create();
1234 client.remote_buffer_cap(1024);
1235
1236 let (disp, _) = Dispatcher::debug(
1237 Io::from(server),
1238 BytesCodec,
1239 ntex_service::fn_service(move |msg: DispatchItem<BytesCodec>| {
1240 let waiter = release2.wait();
1241 if matches!(msg, DispatchItem::Item(_)) {
1242 calls2.set(calls2.get() + 1);
1243 }
1244 async move {
1245 let _ = waiter.ready().await;
1246 Ok::<_, ()>(None)
1247 }
1248 }),
1249 );
1250 ntex::rt::spawn(disp.max_inflight(2));
1251
1252 for msg in ["a", "b", "c"] {
1253 client.write(msg);
1254 sleep(Millis(25)).await;
1255 }
1256 assert_eq!(calls.get(), 2);
1257
1258 release.notify(());
1259 sleep(Millis(25)).await;
1260 assert_eq!(calls.get(), 3);
1261 }
1262
1263 #[ntex::test]
1264 async fn keepalive() {
1265 let (client, server) = IoTest::create();
1266 client.remote_buffer_cap(1024);
1267 client.write("GET /test HTTP/1\r\n\r\n");
1268
1269 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
1270 let data2 = data.clone();
1271
1272 let cfg = SharedCfg::new("DBG").add(
1273 IoConfig::new()
1274 .set_shutdown_timeout(Seconds(1))
1275 .set_keepalive_timeout(Seconds(1)),
1276 );
1277
1278 let (disp, state) = Dispatcher::debug(
1279 Io::new(server, cfg),
1280 BytesCodec,
1281 ntex_service::fn_service(move |msg: DispatchItem<BytesCodec>| {
1282 let data = data2.clone();
1283 async move {
1284 match msg {
1285 DispatchItem::Item(bytes) => {
1286 data.lock().unwrap().borrow_mut().push(0);
1287 return Ok::<_, ()>(Some(bytes));
1288 }
1289 DispatchItem::Stop(Reason::KeepAlive) => {
1290 data.lock().unwrap().borrow_mut().push(1);
1291 }
1292 _ => (),
1293 }
1294 Ok(None)
1295 }
1296 }),
1297 );
1298 spawn(async move {
1299 let _ = disp.await;
1300 });
1301
1302 let buf = client.read().await.unwrap();
1303 assert_eq!(buf, Bytes::from_static(b"GET /test HTTP/1\r\n\r\n"));
1304 wait_until(Millis(3000), || {
1305 !state.0.is_active() && client.is_closed() && data.lock().unwrap().borrow().len() == 2
1306 })
1307 .await;
1308
1309 assert!(!state.0.is_active());
1311 assert!(client.is_closed());
1312 assert_eq!(&data.lock().unwrap().borrow()[..], &[0, 1]);
1313 }
1314
1315 #[ntex::test]
1316 async fn keepalive2() {
1317 let (client, server) = IoTest::create();
1318 client.remote_buffer_cap(1024);
1319
1320 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
1321 let data2 = data.clone();
1322
1323 let cfg = SharedCfg::new("DBG").add(
1324 IoConfig::new()
1325 .set_keepalive_timeout(Seconds(1))
1326 .set_frame_read_rate(Seconds(1), Seconds(2), 2),
1327 );
1328
1329 let (disp, state) = Dispatcher::debug(
1330 Io::new(server, cfg),
1331 BCodec(8),
1332 ntex_service::fn_service(move |msg: DispatchItem<BCodec>| {
1333 let data = data2.clone();
1334 async move {
1335 match msg {
1336 DispatchItem::Item(bytes) => {
1337 data.lock().unwrap().borrow_mut().push(0);
1338 return Ok::<_, ()>(Some(bytes));
1339 }
1340 DispatchItem::Stop(Reason::KeepAlive) => {
1341 data.lock().unwrap().borrow_mut().push(1);
1342 }
1343 _ => (),
1344 }
1345 Ok(None)
1346 }
1347 }),
1348 );
1349 spawn(async move {
1350 let _ = disp.await;
1351 });
1352
1353 client.write("12345678");
1354 let buf = client.read().await.unwrap();
1355 assert_eq!(buf, Bytes::from_static(b"12345678"));
1356 wait_until(Millis(3000), || {
1357 !state.0.is_active() && client.is_closed() && data.lock().unwrap().borrow().len() == 2
1358 })
1359 .await;
1360
1361 assert!(!state.0.is_active());
1363 assert!(client.is_closed());
1364 assert_eq!(&data.lock().unwrap().borrow()[..], &[0, 1]);
1365 }
1366
1367 #[ntex::test]
1369 async fn keepalive3() {
1370 let (client, server) = IoTest::create();
1371 client.remote_buffer_cap(1024);
1372
1373 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
1374 let data2 = data.clone();
1375
1376 let cfg = SharedCfg::new("DBG").add(
1377 IoConfig::new()
1378 .set_keepalive_timeout(Seconds(1))
1379 .set_frame_read_rate(Seconds(1), Seconds(2), 2),
1380 );
1381
1382 let (disp, _) = Dispatcher::debug(
1383 Io::new(server, cfg),
1384 BCodec(1),
1385 ntex_service::fn_service(move |msg: DispatchItem<BCodec>| {
1386 let data = data2.clone();
1387 async move {
1388 match msg {
1389 DispatchItem::Item(bytes) => {
1390 data.lock().unwrap().borrow_mut().push(0);
1391 return Ok::<_, ()>(Some(bytes));
1392 }
1393 DispatchItem::Stop(Reason::KeepAlive) => {
1394 data.lock().unwrap().borrow_mut().push(1);
1395 }
1396 _ => (),
1397 }
1398 Ok(None)
1399 }
1400 }),
1401 );
1402 spawn(async move {
1403 let _ = disp.await;
1404 });
1405
1406 client.write("1");
1407 let buf = client.read().await.unwrap();
1408 assert_eq!(buf, Bytes::from_static(b"1"));
1409 sleep(Millis(500)).await;
1410
1411 client.write("2");
1412 let buf = client.read().await.unwrap();
1413 assert_eq!(buf, Bytes::from_static(b"2"));
1414
1415 sleep(Millis(500)).await;
1416 client.write("3");
1417 let buf = client.read().await.unwrap();
1418 assert_eq!(buf, Bytes::from_static(b"3"));
1419
1420 sleep(Millis(500)).await;
1421 assert!(!client.is_closed());
1422 assert_eq!(&data.lock().unwrap().borrow()[..], &[0, 0, 0]);
1423 }
1424
1425 #[ntex::test]
1426 async fn read_timeout() {
1427 let (client, server) = IoTest::create();
1428 client.remote_buffer_cap(1024);
1429
1430 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
1431 let data2 = data.clone();
1432
1433 let io = Io::new(
1434 server,
1435 SharedCfg::new("TEST").add(
1436 IoConfig::new()
1437 .set_keepalive_timeout(Seconds::ZERO)
1438 .set_frame_read_rate(Seconds(1), Seconds(2), 2),
1439 ),
1440 );
1441
1442 let (disp, state) = Dispatcher::debug(
1443 io,
1444 BCodec(8),
1445 ntex_service::fn_service(move |msg: DispatchItem<BCodec>| {
1446 let data = data2.clone();
1447 async move {
1448 match msg {
1449 DispatchItem::Item(bytes) => {
1450 data.lock().unwrap().borrow_mut().push(0);
1451 return Ok::<_, ()>(Some(bytes));
1452 }
1453 DispatchItem::Stop(Reason::ReadTimeout) => {
1454 data.lock().unwrap().borrow_mut().push(1);
1455 }
1456 _ => (),
1457 }
1458 Ok(None)
1459 }
1460 }),
1461 );
1462 spawn(async move {
1463 let _ = disp.await;
1464 });
1465
1466 client.write("12345678");
1467 let buf = client.read().await.unwrap();
1468 assert_eq!(buf, Bytes::from_static(b"12345678"));
1469
1470 client.write("1");
1473 sleep(Millis(500)).await;
1474 assert!(state.0.is_active());
1475 client.write("23");
1476 sleep(Millis(1000)).await;
1477 assert!(state.0.is_active());
1478 client.write("4");
1479 wait_until(Millis(3000), || {
1480 !state.0.is_active() && client.is_closed() && data.lock().unwrap().borrow().len() == 2
1481 })
1482 .await;
1483
1484 assert!(!state.0.is_active());
1486 assert!(client.is_closed());
1487 assert_eq!(&data.lock().unwrap().borrow()[..], &[0, 1]);
1488 }
1489
1490 #[ntex::test]
1491 async fn idle_timeout() {
1492 let (client, server) = IoTest::create();
1493 client.remote_buffer_cap(1024);
1494
1495 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
1496 let data2 = data.clone();
1497
1498 let io = Io::new(
1499 server,
1500 SharedCfg::new("DBG").add(IoConfig::new().set_keepalive_timeout(Seconds::ZERO)),
1501 );
1502 let ioref = io.get_ref();
1503
1504 let (disp, state) = Dispatcher::debug(
1505 io,
1506 BCodec(1),
1507 ntex_service::fn_service(move |msg: DispatchItem<BCodec>| {
1508 let ioref = ioref.clone();
1509 ntex::rt::spawn(async move {
1510 sleep(Millis(500)).await;
1511 ioref.notify_timeout();
1512 });
1513 let data = data2.clone();
1514 async move {
1515 match msg {
1516 DispatchItem::Item(bytes) => {
1517 data.lock().unwrap().borrow_mut().push(0);
1518 return Ok::<_, ()>(Some(bytes));
1519 }
1520 DispatchItem::Stop(Reason::ReadTimeout) => {
1521 data.lock().unwrap().borrow_mut().push(1);
1522 }
1523 _ => (),
1524 }
1525 Ok(None)
1526 }
1527 }),
1528 );
1529 spawn(async move {
1530 let _ = disp.await;
1531 });
1532
1533 client.write("1");
1534 let buf = client.read().await.unwrap();
1535 assert_eq!(buf, Bytes::from_static(b"1"));
1536
1537 wait_until(Millis(2000), || !state.0.is_active() && client.is_closed()).await;
1538 assert!(!state.0.is_active());
1539 assert!(client.is_closed());
1540 }
1541
1542 #[ntex::test]
1543 async fn unhandled_data() {
1544 let handled = Arc::new(AtomicBool::new(false));
1545 let handled2 = handled.clone();
1546
1547 let (client, server) = IoTest::create();
1548 client.remote_buffer_cap(1024);
1549 client.write("GET /test HTTP/1\r\n\r\n");
1550
1551 let (disp, _) = Dispatcher::debug(
1552 Io::from(server),
1553 BytesCodec,
1554 ntex_service::fn_service(move |msg: DispatchItem<BytesCodec>| {
1555 handled2.store(true, Relaxed);
1556 async move {
1557 sleep(Millis(50)).await;
1558 if let DispatchItem::Item(msg) = msg {
1559 Ok::<_, ()>(Some(msg))
1560 } else if let DispatchItem::Stop(_) = msg {
1561 Ok::<_, ()>(None)
1562 } else {
1563 panic!()
1564 }
1565 }
1566 }),
1567 );
1568 client.close().await;
1569 spawn(async move {
1570 let _ = disp.await;
1571 });
1572 sleep(Millis(50)).await;
1573
1574 assert!(handled.load(Relaxed));
1575 }
1576
1577 async fn stop_reason_at_eof(input: &'static str) -> Option<io::ErrorKind> {
1578 let reason = Rc::new(RefCell::new(None));
1579 let reason2 = reason.clone();
1580
1581 let (client, server) = IoTest::create();
1582 client.remote_buffer_cap(1024);
1583 client.write(input);
1584
1585 let (disp, _) = Dispatcher::debug(
1586 Io::from(server),
1587 BCodec(8),
1588 ntex_service::fn_service(move |msg: DispatchItem<BCodec>| {
1589 if let DispatchItem::Stop(Reason::Io(err)) = msg {
1590 *reason2.borrow_mut() = Some(err.map(|e| e.kind()));
1591 }
1592 async move { Ok::<_, ()>(None) }
1593 }),
1594 );
1595 spawn(async move {
1596 let _ = disp.await;
1597 });
1598 sleep(Millis(25)).await;
1599 client.close().await;
1600 sleep(Millis(50)).await;
1601
1602 reason.borrow_mut().take().expect("dispatcher did not stop")
1603 }
1604
1605 #[ntex::test]
1608 async fn peer_gone_during_pause_dispatches_buffered_frames() {
1609 struct Srv(Condition, Rc<RefCell<Vec<String>>>);
1610
1611 impl Service<(), DispatchItem<BCodec>> for Srv {
1612 type Res = Option<Bytes>;
1613 type Error = ();
1614
1615 async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Self::Error> {
1616 if self.1.borrow().len() == 1 {
1617 self.0.wait().await;
1618 }
1619 Ok(())
1620 }
1621
1622 async fn call(
1623 &self,
1624 msg: DispatchItem<BCodec>,
1625 _: Ctx<'_, Self>,
1626 ) -> Result<Option<Bytes>, Self::Error> {
1627 match msg {
1628 DispatchItem::Item(msg) => {
1629 self.1
1630 .borrow_mut()
1631 .push(String::from_utf8_lossy(&msg).into_owned());
1632 return Ok(Some(msg));
1633 }
1634 DispatchItem::Stop(Reason::Io(err)) => self
1635 .1
1636 .borrow_mut()
1637 .push(format!("stop: {:?}", err.map(|e| e.kind()))),
1638 _ => (),
1639 }
1640 Ok(None)
1641 }
1642 }
1643
1644 let gate = Condition::new();
1645 let items = Rc::new(RefCell::new(Vec::new()));
1646 let (client, server) = IoTest::create();
1647 client.remote_buffer_cap(1024);
1648 client.write_error(io::Error::new(io::ErrorKind::ConnectionReset, "reset"));
1650 client.write("1234567887654321");
1651
1652 let (disp, _) = Dispatcher::debug(
1653 Io::from(server),
1654 BCodec(8),
1655 Srv(gate.clone(), items.clone()),
1656 );
1657 spawn(async move {
1658 let _ = disp.await;
1659 });
1660 sleep(Millis(25)).await;
1661
1662 gate.notify(());
1663 sleep(Millis(50)).await;
1664
1665 assert_eq!(
1666 *items.borrow(),
1667 ["12345678", "87654321", "stop: Some(ConnectionReset)"]
1668 );
1669 }
1670
1671 #[ntex::test]
1672 async fn stop_call_error_is_returned() {
1673 let (client, server) = IoTest::create();
1674 client.remote_buffer_cap(1024);
1675
1676 let (disp, _) = Dispatcher::debug(
1677 Io::from(server),
1678 BCodec(8),
1679 ntex_service::fn_service(async move |msg: DispatchItem<BCodec>| match msg {
1680 DispatchItem::Stop(_) => Err("stop"),
1681 _ => Ok(None),
1682 }),
1683 );
1684 client.close().await;
1685 assert_eq!(disp.await, Err("stop"));
1686 }
1687
1688 #[ntex::test]
1689 async fn earlier_service_error_is_kept() {
1690 let (client, server) = IoTest::create();
1691 client.remote_buffer_cap(1024);
1692 client.write("12345678");
1693
1694 let (disp, _) = Dispatcher::debug(
1695 Io::from(server),
1696 BCodec(8),
1697 ntex_service::fn_service(async move |msg: DispatchItem<BCodec>| match msg {
1698 DispatchItem::Item(_) => Err("item"),
1699 DispatchItem::Stop(_) => Err("stop"),
1700 DispatchItem::Control(_) => Ok(None),
1701 }),
1702 );
1703 assert_eq!(disp.await, Err("item"));
1704 }
1705
1706 #[ntex::test]
1707 async fn peer_eof_reports_truncated_frame() {
1708 assert_eq!(
1709 stop_reason_at_eof("123").await,
1710 Some(io::ErrorKind::UnexpectedEof)
1711 );
1712 }
1713
1714 #[ntex::test]
1715 async fn peer_eof_after_whole_frame_is_clean() {
1716 assert_eq!(stop_reason_at_eof("12345678").await, None);
1717 }
1718
1719 #[ntex::test]
1721 async fn service_is_not_ready_and_backpressure() {
1722 struct Srv(
1723 Cell<Option<oneshot::Receiver<()>>>,
1724 Rc<Cell<usize>>,
1725 Cell<bool>,
1726 );
1727
1728 impl Service<(), DispatchItem<BytesCodec>> for Srv {
1729 type Res = Option<Bytes>;
1730 type Error = ();
1731
1732 async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Self::Error> {
1733 if self.2.get()
1734 && let Some(rx) = self.0.take()
1735 {
1736 let _ = rx.await;
1737 }
1738 Ok(())
1739 }
1740
1741 async fn call(
1742 &self,
1743 msg: DispatchItem<BytesCodec>,
1744 _: Ctx<'_, Self>,
1745 ) -> Result<Option<Bytes>, Self::Error> {
1746 if let DispatchItem::Item(msg) = msg {
1747 self.2.set(true);
1748 return Ok::<_, ()>(Some(msg));
1749 } else if let DispatchItem::Control(Control::WBackPressureEnabled) = msg {
1750 self.1.set(self.1.get() + 1);
1751 }
1752 Ok::<_, ()>(None)
1753 }
1754 }
1755
1756 let (ctx, rx) = oneshot::channel();
1757 let cnt = Rc::new(Cell::new(0));
1758 let (client, server) = IoTest::create();
1759 client.remote_buffer_cap(0);
1760
1761 let (disp, _) = Dispatcher::debug(
1762 Io::new(
1763 server,
1764 SharedCfg::new("DBG").add(IoConfig::new().set_write_backpressure(2)),
1765 ),
1766 BytesCodec,
1767 Srv(Cell::new(Some(rx)), cnt.clone(), Cell::new(false)),
1768 );
1769 let (tx, rx) = ntex::channel::oneshot::channel();
1770 ntex_util::spawn(async move {
1771 let _ = disp.await;
1772 let _ = tx.send(());
1773 });
1774
1775 client.write("123456789");
1776 client.remote_buffer_cap(9);
1777 sleep(Millis(125)).await;
1778 let _ = ctx.send(());
1779 client.write("123456789");
1780 sleep(Millis(125)).await;
1781 client.remote_buffer_cap(16);
1782 let res = client.read().await;
1783 assert_eq!(res.unwrap(), Bytes::from_static(b"123456789"));
1784 client.close().await;
1785 let _ = rx.await;
1786 assert_eq!(cnt.get(), 2);
1787 }
1788
1789 #[ntex::test]
1792 async fn read_timer_stopped_after_frame() {
1793 let (client, server) = IoTest::create();
1794 client.remote_buffer_cap(1024);
1795
1796 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
1797 let data2 = data.clone();
1798
1799 let io = Io::new(
1800 server,
1801 SharedCfg::new("TEST").add(
1802 IoConfig::new()
1803 .set_keepalive_timeout(Seconds::ZERO)
1804 .set_frame_read_rate(Seconds(1), Seconds(5), 2),
1805 ),
1806 );
1807 let disp = Dispatcher::new(
1808 io,
1809 BCodec(8),
1810 Pipeline::new(
1811 (),
1812 ntex_service::fn_service(move |msg: DispatchItem<BCodec>| {
1813 let data = data2.clone();
1814 async move {
1815 match msg {
1816 DispatchItem::Item(bytes) => {
1817 data.lock().unwrap().borrow_mut().push(0);
1818 return Ok::<_, ()>(Some(bytes));
1819 }
1820 DispatchItem::Stop(_) => data.lock().unwrap().borrow_mut().push(1),
1821 DispatchItem::Control(_) => (),
1822 }
1823 Ok(None)
1824 }
1825 }),
1826 ),
1827 );
1828 spawn(async move {
1829 let _ = disp.await;
1830 });
1831
1832 client.write("1234");
1833 sleep(Millis(200)).await;
1834 client.write("5678");
1835 let buf = client.read().await.unwrap();
1836 assert_eq!(buf, Bytes::from_static(b"12345678"));
1837
1838 sleep(Millis(2500)).await;
1839 assert!(!client.is_closed());
1840 assert_eq!(&data.lock().unwrap().borrow()[..], &[0]);
1841 }
1842
1843 struct DropCodec;
1845
1846 impl Encoder for DropCodec {
1847 type Item = Bytes;
1848 type Error = io::Error;
1849
1850 fn encode(&self, item: Bytes, dst: &mut BytePages) -> Result<(), Self::Error> {
1851 dst.append(item);
1852 Ok(())
1853 }
1854 }
1855
1856 impl Decoder for DropCodec {
1857 type Item = Bytes;
1858 type Error = io::Error;
1859
1860 fn decode(&self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
1861 if let Some(n) = src.iter().position(|b| *b == b'#') {
1862 let _ = src.split_to(n + 1);
1863 }
1864 if src.len() < 8 {
1865 Ok(None)
1866 } else {
1867 Ok(Some(src.split_to(8)))
1868 }
1869 }
1870 }
1871
1872 #[ntex::test]
1875 async fn read_rate_counts_consumed_bytes() {
1876 let (client, server) = IoTest::create();
1877 client.remote_buffer_cap(1024);
1878
1879 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
1880 let data2 = data.clone();
1881
1882 let io = Io::new(
1883 server,
1884 SharedCfg::new("TEST").add(
1885 IoConfig::new()
1886 .set_keepalive_timeout(Seconds::ZERO)
1887 .set_frame_read_rate(Seconds(1), Seconds(10), 2),
1888 ),
1889 );
1890 let disp = Dispatcher::new(
1891 io,
1892 DropCodec,
1893 Pipeline::new(
1894 (),
1895 ntex_service::fn_service(move |msg: DispatchItem<DropCodec>| {
1896 let data = data2.clone();
1897 async move {
1898 if let DispatchItem::Stop(Reason::ReadTimeout) = msg {
1899 data.lock().unwrap().borrow_mut().push(1);
1900 }
1901 Ok::<_, ()>(None)
1902 }
1903 }),
1904 ),
1905 );
1906 spawn(async move {
1907 let _ = disp.await;
1908 });
1909
1910 client.write("123");
1911 for _ in 0..4 {
1913 sleep(Millis(350)).await;
1914 client.write("abc#");
1915 }
1916 sleep(Millis(1000)).await;
1919 assert!(!client.is_closed());
1920 assert!(data.lock().unwrap().borrow().is_empty());
1921
1922 wait_closed(&client, Millis(4500)).await;
1924 assert!(client.is_closed());
1925 assert_eq!(&data.lock().unwrap().borrow()[..], &[1]);
1926 }
1927
1928 fn first_frame_dispatcher(
1929 server: IoTest,
1930 data: Arc<Mutex<RefCell<Vec<usize>>>>,
1931 ) -> Dispatcher<BCodec, ()> {
1932 let io = Io::new(
1933 server,
1934 SharedCfg::new("TEST").add(
1935 IoConfig::new()
1936 .set_keepalive_timeout(Seconds(30))
1937 .set_frame_read_rate(Seconds(1), Seconds(2), 2),
1938 ),
1939 );
1940 Dispatcher::new(
1941 io,
1942 BCodec(8),
1943 Pipeline::new(
1944 (),
1945 ntex_service::fn_service(move |msg: DispatchItem<BCodec>| {
1946 let data = data.clone();
1947 async move {
1948 match msg {
1949 DispatchItem::Item(bytes) => {
1950 data.lock().unwrap().borrow_mut().push(0);
1951 return Ok::<_, ()>(Some(bytes));
1952 }
1953 DispatchItem::Stop(Reason::ReadTimeout) => {
1954 data.lock().unwrap().borrow_mut().push(1);
1955 }
1956 DispatchItem::Stop(Reason::KeepAlive) => {
1957 data.lock().unwrap().borrow_mut().push(2);
1958 }
1959 _ => (),
1960 }
1961 Ok(None)
1962 }
1963 }),
1964 ),
1965 )
1966 }
1967
1968 #[ntex::test]
1971 async fn first_frame_read_rate_silent_peer() {
1972 let (client, server) = IoTest::create();
1973 client.remote_buffer_cap(1024);
1974
1975 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
1976 let disp = first_frame_dispatcher(server, data.clone());
1977 spawn(async move {
1978 let _ = disp.await;
1979 });
1980
1981 wait_until(Millis(5000), || {
1982 client.is_closed() && data.lock().unwrap().borrow().len() == 1
1983 })
1984 .await;
1985 assert!(client.is_closed());
1986 assert_eq!(&data.lock().unwrap().borrow()[..], &[1]);
1987 }
1988
1989 #[ntex::test]
1992 async fn first_frame_read_rate_then_keepalive() {
1993 let (client, server) = IoTest::create();
1994 client.remote_buffer_cap(1024);
1995
1996 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
1997 let disp = first_frame_dispatcher(server, data.clone());
1998 spawn(async move {
1999 let _ = disp.await;
2000 });
2001
2002 sleep(Millis(200)).await;
2003 client.write("12345678");
2004 let buf = client.read().await.unwrap();
2005 assert_eq!(buf, Bytes::from_static(b"12345678"));
2006
2007 sleep(Millis(2500)).await;
2010 assert!(!client.is_closed());
2011 assert_eq!(&data.lock().unwrap().borrow()[..], &[0]);
2012 }
2013
2014 struct GateSrv(Rc<RefCell<Option<oneshot::Receiver<()>>>>, Rc<Cell<bool>>);
2016
2017 impl Service<(), DispatchItem<BCodec>> for GateSrv {
2018 type Res = Option<Bytes>;
2019 type Error = ();
2020
2021 async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Self::Error> {
2022 let rx = self.0.borrow_mut().take();
2023 if let Some(rx) = rx {
2024 let _ = rx.await;
2025 }
2026 Ok(())
2027 }
2028
2029 async fn call(
2030 &self,
2031 msg: DispatchItem<BCodec>,
2032 _: Ctx<'_, Self>,
2033 ) -> Result<Option<Bytes>, Self::Error> {
2034 if let DispatchItem::Stop(Reason::ReadTimeout) = msg {
2035 self.1.set(true);
2036 }
2037 Ok(None)
2038 }
2039 }
2040
2041 #[ntex::test]
2044 async fn read_rate_budget_reset_on_service_pause() {
2045 let (client, server) = IoTest::create();
2046 client.remote_buffer_cap(1024);
2047
2048 let gate = Rc::new(RefCell::new(None));
2049 let timed_out = Rc::new(Cell::new(false));
2050 let io = Io::new(
2051 server,
2052 SharedCfg::new("TEST").add(
2053 IoConfig::new()
2054 .set_keepalive_timeout(Seconds::ZERO)
2055 .set_frame_read_rate(Seconds(1), Seconds(2), 2),
2056 ),
2057 );
2058 let disp = Dispatcher::new(
2059 io,
2060 BCodec(1024),
2061 Pipeline::new((), GateSrv(gate.clone(), timed_out.clone())),
2062 );
2063 spawn(async move {
2064 let _ = disp.await;
2065 });
2066
2067 client.write("abc");
2071 for _ in 0..2 {
2072 for _ in 0..2 {
2073 sleep(Millis(700)).await;
2074 client.write("abc");
2075 }
2076 let (tx, rx) = oneshot::channel();
2077 *gate.borrow_mut() = Some(rx);
2078 client.write("abc");
2079 sleep(Millis(100)).await;
2080 let _ = tx.send(());
2081 }
2082 assert!(!client.is_closed());
2083 assert!(!timed_out.get());
2084 }
2085
2086 #[ntex::test]
2089 async fn read_rate_restarts_after_service_pause() {
2090 let (client, server) = IoTest::create();
2091 client.remote_buffer_cap(1024);
2092
2093 let gate = Rc::new(RefCell::new(None));
2094 let timed_out = Rc::new(Cell::new(false));
2095 let io = Io::new(
2096 server,
2097 SharedCfg::new("TEST").add(
2098 IoConfig::new()
2099 .set_keepalive_timeout(Seconds::ZERO)
2100 .set_frame_read_rate(Seconds(1), Seconds::ZERO, 2),
2101 ),
2102 );
2103 let disp = Dispatcher::new(
2104 io,
2105 BCodec(1024),
2106 Pipeline::new((), GateSrv(gate.clone(), timed_out.clone())),
2107 );
2108 spawn(async move {
2109 let _ = disp.await;
2110 });
2111
2112 client.write("abc");
2113 sleep(Millis(100)).await;
2114 let (tx, rx) = oneshot::channel();
2115 *gate.borrow_mut() = Some(rx);
2116 client.write("abc");
2117 sleep(Millis(1500)).await;
2118 let _ = tx.send(());
2119
2120 sleep(Millis(1500)).await;
2123 assert!(!client.is_closed());
2124 wait_closed(&client, Millis(3500)).await;
2125 assert!(client.is_closed());
2126 assert!(timed_out.get());
2127 }
2128
2129 #[ntex::test]
2132 async fn read_rate_starts_for_consumed_partial_frame() {
2133 let (client, server) = IoTest::create();
2134 client.remote_buffer_cap(1024);
2135
2136 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
2137 let data2 = data.clone();
2138
2139 let io = Io::new(
2140 server,
2141 SharedCfg::new("TEST").add(
2142 IoConfig::new()
2143 .set_keepalive_timeout(Seconds(30))
2144 .set_frame_read_rate(Seconds(1), Seconds(2), 2),
2145 ),
2146 );
2147 let disp = Dispatcher::new(
2148 io,
2149 DropCodec,
2150 Pipeline::new(
2151 (),
2152 ntex_service::fn_service(move |msg: DispatchItem<DropCodec>| {
2153 let data = data2.clone();
2154 async move {
2155 match msg {
2156 DispatchItem::Item(_) => data.lock().unwrap().borrow_mut().push(0),
2157 DispatchItem::Stop(Reason::ReadTimeout) => {
2158 data.lock().unwrap().borrow_mut().push(1);
2159 }
2160 _ => (),
2161 }
2162 Ok::<_, ()>(None)
2163 }
2164 }),
2165 ),
2166 );
2167 spawn(async move {
2168 let _ = disp.await;
2169 });
2170
2171 client.write("12345678");
2172 sleep(Millis(100)).await;
2173 client.write("1#");
2175 wait_until(Millis(5000), || {
2176 client.is_closed() && data.lock().unwrap().borrow().len() == 2
2177 })
2178 .await;
2179 assert!(client.is_closed());
2180 assert_eq!(&data.lock().unwrap().borrow()[..], &[0, 1]);
2181 }
2182
2183 struct BusySrv(Rc<Cell<bool>>, IoRef);
2185
2186 impl Service<(), DispatchItem<BCodec>> for BusySrv {
2187 type Res = Option<Bytes>;
2188 type Error = ();
2189
2190 async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Self::Error> {
2191 while self.0.get() {
2192 sleep(Millis(50)).await;
2193 }
2194 Ok(())
2195 }
2196
2197 async fn call(
2198 &self,
2199 msg: DispatchItem<BCodec>,
2200 _: Ctx<'_, Self>,
2201 ) -> Result<Option<Bytes>, Self::Error> {
2202 if let DispatchItem::Item(bytes) = msg {
2203 self.0.set(true);
2204 let ioref = self.1.clone();
2205 spawn(async move {
2206 sleep(Millis(300)).await;
2207 ioref.notify_timeout();
2208 });
2209 sleep(Millis(800)).await;
2210 self.0.set(false);
2211 return Ok(Some(bytes));
2212 }
2213 Ok(None)
2214 }
2215 }
2216
2217 #[ntex::test]
2220 async fn notify_timeout_ignored_during_pause_while_handling() {
2221 let (client, server) = IoTest::create();
2222 client.remote_buffer_cap(1024);
2223
2224 let io = Io::new(
2225 server,
2226 SharedCfg::new("TEST").add(IoConfig::new().set_keepalive_timeout(Seconds(5))),
2227 );
2228 let srv = BusySrv(Rc::new(Cell::new(false)), io.get_ref());
2229 let disp = Dispatcher::new(io, BCodec(1), Pipeline::new((), srv));
2230 spawn(async move {
2231 let _ = disp.await;
2232 });
2233
2234 client.write("1");
2235 sleep(Millis(600)).await;
2237 assert!(!client.is_closed());
2238 let buf = client.read().await.unwrap();
2239 assert_eq!(buf, Bytes::from_static(b"1"));
2240 sleep(Millis(300)).await;
2242 assert!(!client.is_closed());
2243 }
2244
2245 #[ntex::test]
2248 async fn notify_timeout_during_idle_pause() {
2249 let (client, server) = IoTest::create();
2250 client.remote_buffer_cap(1024);
2251
2252 let gate = Rc::new(RefCell::new(None));
2253 let io = Io::new(
2254 server,
2255 SharedCfg::new("TEST").add(IoConfig::new().set_keepalive_timeout(Seconds::ZERO)),
2256 );
2257 let ioref = io.get_ref();
2258 let (tx, rx) = oneshot::channel();
2259 *gate.borrow_mut() = Some(rx);
2260 let disp = Dispatcher::new(
2261 io,
2262 BCodec(1),
2263 Pipeline::new((), GateSrv(gate, Rc::new(Cell::new(false)))),
2264 );
2265 spawn(async move {
2266 let _ = disp.await;
2267 });
2268
2269 sleep(Millis(300)).await;
2270 ioref.notify_timeout();
2271 sleep(Millis(300)).await;
2272 let _ = tx.send(());
2274 wait_closed(&client, Millis(1000)).await;
2275 assert!(client.is_closed());
2276 }
2277
2278 fn keepalive_dispatcher(
2279 server: IoTest,
2280 delay: Millis,
2281 data: Arc<Mutex<RefCell<Vec<usize>>>>,
2282 ) -> Dispatcher<BCodec, ()> {
2283 keepalive_io_dispatcher(keepalive_io(server), delay, data)
2284 }
2285
2286 fn keepalive_io(server: IoTest) -> Io {
2287 Io::new(
2288 server,
2289 SharedCfg::new("TEST").add(IoConfig::new().set_keepalive_timeout(Seconds(1))),
2290 )
2291 }
2292
2293 fn keepalive_io_dispatcher(
2294 io: Io,
2295 delay: Millis,
2296 data: Arc<Mutex<RefCell<Vec<usize>>>>,
2297 ) -> Dispatcher<BCodec, ()> {
2298 Dispatcher::new(
2299 io,
2300 BCodec(8),
2301 Pipeline::new(
2302 (),
2303 ntex_service::fn_service(move |msg: DispatchItem<BCodec>| {
2304 let data = data.clone();
2305 async move {
2306 match msg {
2307 DispatchItem::Item(bytes) => {
2308 sleep(delay).await;
2309 data.lock().unwrap().borrow_mut().push(0);
2310 return Ok::<_, ()>(Some(bytes));
2311 }
2312 DispatchItem::Stop(Reason::KeepAlive) => {
2313 data.lock().unwrap().borrow_mut().push(1);
2314 }
2315 _ => (),
2316 }
2317 Ok(None)
2318 }
2319 }),
2320 ),
2321 )
2322 }
2323
2324 #[ntex::test]
2327 async fn keepalive_inactive_during_frame_handling() {
2328 let (client, server) = IoTest::create();
2329 client.remote_buffer_cap(1024);
2330
2331 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
2332 let disp = keepalive_dispatcher(server, Millis(2200), data.clone());
2334 spawn(async move {
2335 let _ = disp.await;
2336 });
2337
2338 client.write("12345678");
2339 sleep(Millis(2400)).await;
2340 assert!(!client.is_closed());
2341 assert_eq!(&data.lock().unwrap().borrow()[..], &[0]);
2342
2343 wait_closed(&client, Millis(3000)).await;
2344 assert!(client.is_closed());
2345 assert_eq!(&data.lock().unwrap().borrow()[..], &[0, 1]);
2346 }
2347
2348 #[ntex::test]
2350 async fn keepalive_inactive_during_frame_read() {
2351 let (client, server) = IoTest::create();
2352 client.remote_buffer_cap(1024);
2353
2354 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
2355 let disp = keepalive_dispatcher(server, Millis(0), data.clone());
2356 spawn(async move {
2357 let _ = disp.await;
2358 });
2359
2360 sleep(Millis(200)).await;
2363 client.write("1234");
2364 sleep(Millis(2200)).await;
2365 assert!(!client.is_closed());
2366
2367 client.write("5678");
2368 let buf = client.read().await.unwrap();
2369 assert_eq!(buf, Bytes::from_static(b"12345678"));
2370
2371 wait_closed(&client, Millis(3000)).await;
2372 assert!(client.is_closed());
2373 assert_eq!(&data.lock().unwrap().borrow()[..], &[0, 1]);
2374 }
2375
2376 #[ntex::test]
2379 async fn keepalive_timer_kept_during_frame_handling() {
2380 let (client, server) = IoTest::create();
2381 client.remote_buffer_cap(1024);
2382
2383 let io = Io::new(
2384 server,
2385 SharedCfg::new("TEST").add(IoConfig::new().set_keepalive_timeout(Seconds(5))),
2386 );
2387 let ioref = io.get_ref();
2388 let handles = Rc::new(RefCell::new(Vec::new()));
2389 let handles2 = handles.clone();
2390 let disp = Dispatcher::new(
2391 io,
2392 BCodec(1),
2393 Pipeline::new(
2394 (),
2395 ntex_service::fn_service(move |msg: DispatchItem<BCodec>| {
2396 let handles = handles2.clone();
2397 let ioref = ioref.clone();
2398 async move {
2399 if let DispatchItem::Item(bytes) = msg {
2400 handles.borrow_mut().push(ioref.timer_handle());
2401 return Ok::<_, ()>(Some(bytes));
2402 }
2403 Ok(None)
2404 }
2405 }),
2406 ),
2407 );
2408 spawn(async move {
2409 let _ = disp.await;
2410 });
2411
2412 for frame in ["1", "2"] {
2413 sleep(Millis(50)).await;
2414 client.write(frame);
2415 let buf = client.read().await.unwrap();
2416 assert_eq!(buf, Bytes::from(frame));
2417 }
2418 assert_eq!(handles.borrow().len(), 2);
2419 assert!(handles.borrow().iter().all(ntex_io::TimerHandle::is_set));
2420 assert!(!client.is_closed());
2421 }
2422
2423 #[ntex::test]
2426 async fn notify_timeout_during_frame_read() {
2427 let (client, server) = IoTest::create();
2428 client.remote_buffer_cap(1024);
2429
2430 let io = Io::new(
2431 server,
2432 SharedCfg::new("TEST").add(IoConfig::new().set_keepalive_timeout(Seconds(5))),
2433 );
2434 let ioref = io.get_ref();
2435 let data = Rc::new(RefCell::new(Vec::new()));
2436 let data2 = data.clone();
2437 let disp = Dispatcher::new(
2438 io,
2439 BCodec(8),
2440 Pipeline::new(
2441 (),
2442 ntex_service::fn_service(move |msg: DispatchItem<BCodec>| {
2443 if let DispatchItem::Stop(Reason::KeepAlive) = msg {
2444 data2.borrow_mut().push(1);
2445 }
2446 async move { Ok::<_, ()>(None) }
2447 }),
2448 ),
2449 );
2450 spawn(async move {
2451 let _ = disp.await;
2452 });
2453
2454 sleep(Millis(100)).await;
2455 client.write("1234");
2456 sleep(Millis(100)).await;
2457 assert!(!client.is_closed());
2458
2459 ioref.notify_timeout();
2460 wait_closed(&client, Millis(1000)).await;
2461 assert!(client.is_closed());
2462 assert_eq!(&data.borrow()[..], &[1]);
2463 }
2464
2465 struct WriteSrv {
2467 size: usize,
2468 gate: Gate,
2469 events: Events,
2470 }
2471
2472 impl Service<(), DispatchItem<BCodec>> for WriteSrv {
2473 type Res = Option<Bytes>;
2474 type Error = ();
2475
2476 async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Self::Error> {
2477 let rx = self.gate.borrow_mut().take();
2478 if let Some(rx) = rx {
2479 let _ = rx.await;
2480 }
2481 Ok(())
2482 }
2483
2484 async fn call(
2485 &self,
2486 msg: DispatchItem<BCodec>,
2487 _: Ctx<'_, Self>,
2488 ) -> Result<Option<Bytes>, Self::Error> {
2489 let ev = match msg {
2490 DispatchItem::Item(_) => {
2491 self.events.borrow_mut().push("item");
2492 return Ok(Some(Bytes::from(vec![b'x'; self.size])));
2493 }
2494 DispatchItem::Control(Control::WBackPressureEnabled) => "bp-on",
2495 DispatchItem::Control(Control::WBackPressureDisabled) => "bp-off",
2496 DispatchItem::Stop(Reason::WriteTimeout) => "write-timeout",
2497 DispatchItem::Stop(Reason::KeepAlive) => "keepalive",
2498 DispatchItem::Stop(Reason::ReadTimeout) => "read-timeout",
2499 DispatchItem::Stop(_) => "stop",
2500 };
2501 self.events.borrow_mut().push(ev);
2502 Ok(None)
2503 }
2504 }
2505
2506 type Gate = Rc<RefCell<Option<oneshot::Receiver<()>>>>;
2507 type Events = Rc<RefCell<Vec<&'static str>>>;
2508
2509 fn write_dispatcher(
2510 server: IoTest,
2511 cfg: IoConfig,
2512 size: usize,
2513 ) -> (Dispatcher<BCodec, ()>, Gate, Events) {
2514 let gate = Rc::new(RefCell::new(None));
2515 let events = Rc::new(RefCell::new(Vec::new()));
2516 let io = Io::new(
2517 server,
2518 SharedCfg::new("TEST").add(cfg.set_write_backpressure(1024)),
2519 );
2520 let disp = Dispatcher::new(
2521 io,
2522 BCodec(8),
2523 Pipeline::new(
2524 (),
2525 WriteSrv {
2526 size,
2527 gate: gate.clone(),
2528 events: events.clone(),
2529 },
2530 ),
2531 );
2532 (disp, gate, events)
2533 }
2534
2535 #[ntex::test]
2538 async fn write_timeout_peer_not_reading() {
2539 let (client, server) = IoTest::create();
2540 client.remote_buffer_cap(0);
2541
2542 let (disp, _, events) = write_dispatcher(
2543 server,
2544 IoConfig::new()
2545 .set_keepalive_timeout(Seconds(1))
2546 .set_write_timeout(Seconds(2)),
2547 8192,
2548 );
2549 spawn(async move {
2550 let _ = disp.await;
2551 });
2552
2553 client.write("12345678");
2554 sleep(Millis(1500)).await;
2555 assert!(!client.is_closed());
2556 wait_closed(&client, Millis(4000)).await;
2557 assert!(client.is_closed());
2558 assert_eq!(&events.borrow()[..], &["item", "bp-on", "write-timeout"]);
2559 }
2560
2561 #[ntex::test]
2564 async fn write_timeout_slow_reader() {
2565 let (client, server) = IoTest::create();
2566 client.remote_buffer_cap(0);
2567
2568 let (disp, _, events) =
2569 write_dispatcher(server, IoConfig::new().set_write_timeout(Seconds(2)), 65536);
2570 spawn(async move {
2571 let _ = disp.await;
2572 });
2573
2574 client.write("12345678");
2575 for _ in 0..24 {
2576 sleep(Millis(250)).await;
2577 client.remote_buffer_cap(64);
2578 let _ = client.read_any();
2579 if client.is_closed() {
2580 break;
2581 }
2582 }
2583 assert!(client.is_closed());
2584 wait_until(Millis(1000), || events.borrow().len() == 3).await;
2585 assert_eq!(&events.borrow()[..], &["item", "bp-on", "write-timeout"]);
2586 }
2587
2588 #[ntex::test]
2592 async fn write_timeout_during_service_pause() {
2593 let (client, server) = IoTest::create();
2594 client.remote_buffer_cap(0);
2595
2596 let (disp, gate, events) =
2597 write_dispatcher(server, IoConfig::new().set_write_timeout(Seconds(1)), 8192);
2598 spawn(async move {
2599 let _ = disp.await;
2600 });
2601
2602 client.write("12345678");
2603 sleep(Millis(100)).await;
2604 assert_eq!(&events.borrow()[..], &["item", "bp-on"]);
2605
2606 let (tx, rx) = oneshot::channel::<()>();
2608 *gate.borrow_mut() = Some(rx);
2609
2610 wait_closed(&client, Millis(5000)).await;
2612 assert!(client.is_closed());
2613 assert_eq!(&events.borrow()[..], &["item", "bp-on"]);
2614
2615 drop(tx);
2617 wait_until(Millis(1000), || events.borrow().len() == 3).await;
2618 assert_eq!(&events.borrow()[..], &["item", "bp-on", "write-timeout"]);
2619 }
2620
2621 #[ntex::test]
2624 async fn write_timeout_released_during_service_pause() {
2625 let (client, server) = IoTest::create();
2626 client.remote_buffer_cap(0);
2627
2628 let (disp, gate, events) =
2629 write_dispatcher(server, IoConfig::new().set_write_timeout(Seconds(1)), 8192);
2630 spawn(async move {
2631 let _ = disp.await;
2632 });
2633
2634 client.write("12345678");
2635 sleep(Millis(100)).await;
2636 assert_eq!(&events.borrow()[..], &["item", "bp-on"]);
2637
2638 let (tx, rx) = oneshot::channel::<()>();
2640 *gate.borrow_mut() = Some(rx);
2641 client.remote_buffer_cap(65536);
2642 sleep(Millis(100)).await;
2643 assert_eq!(client.read_any().len(), 8192);
2644 sleep(Millis(2300)).await;
2646
2647 drop(tx);
2648 sleep(Millis(100)).await;
2649 assert!(!client.is_closed());
2650 assert_eq!(&events.borrow()[..], &["item", "bp-on", "bp-off"]);
2651 }
2652
2653 #[ntex::test]
2655 async fn keepalive_after_write_backpressure() {
2656 let (client, server) = IoTest::create();
2657 client.remote_buffer_cap(0);
2658
2659 let (disp, _, events) = write_dispatcher(
2660 server,
2661 IoConfig::new()
2662 .set_keepalive_timeout(Seconds(1))
2663 .set_write_timeout(Seconds(1)),
2664 8192,
2665 );
2666 spawn(async move {
2667 let _ = disp.await;
2668 });
2669
2670 client.write("12345678");
2671 wait_until(Millis(2000), || events.borrow().len() == 2).await;
2672 client.remote_buffer_cap(65536);
2673 sleep(Millis(100)).await;
2674 assert_eq!(client.read_any().len(), 8192);
2675 assert_eq!(&events.borrow()[..], &["item", "bp-on", "bp-off"]);
2676
2677 wait_closed(&client, Millis(4000)).await;
2678 assert!(client.is_closed());
2679 assert_eq!(
2680 &events.borrow()[..],
2681 &["item", "bp-on", "bp-off", "keepalive"]
2682 );
2683 }
2684
2685 #[ntex::test]
2688 async fn write_timeout_ends_at_backpressure_release() {
2689 let (client, server) = IoTest::create();
2690 client.remote_buffer_cap(0);
2691
2692 let (disp, _, events) =
2693 write_dispatcher(server, IoConfig::new().set_write_timeout(Seconds(1)), 8192);
2694 spawn(async move {
2695 let _ = disp.await;
2696 });
2697
2698 client.write("12345678");
2699 sleep(Millis(250)).await;
2700 client.remote_buffer_cap(7900);
2702 sleep(Millis(100)).await;
2703 assert_eq!(client.read_any().len(), 7900);
2704 assert_eq!(&events.borrow()[..], &["item", "bp-on", "bp-off"]);
2705
2706 sleep(Millis(2500)).await;
2708 assert!(!client.is_closed());
2709 assert_eq!(&events.borrow()[..], &["item", "bp-on", "bp-off"]);
2710 }
2711
2712 #[ntex::test]
2714 async fn write_timeout_restarts_per_backpressure_period() {
2715 let (client, server) = IoTest::create();
2716 client.remote_buffer_cap(0);
2717
2718 let (disp, _, events) =
2719 write_dispatcher(server, IoConfig::new().set_write_timeout(Seconds(2)), 8192);
2720 spawn(async move {
2721 let _ = disp.await;
2722 });
2723
2724 client.write("12345678");
2725 for _ in 0..2 {
2726 sleep(Millis(1200)).await;
2728 client.remote_buffer_cap(65536);
2729 sleep(Millis(100)).await;
2730 assert_eq!(client.read_any().len(), 8192);
2731 client.remote_buffer_cap(0);
2732 client.write("12345678");
2733 }
2734 sleep(Millis(100)).await;
2735 assert!(!client.is_closed());
2736 assert_eq!(
2737 &events.borrow()[..],
2738 &[
2739 "item", "bp-on", "bp-off", "item", "bp-on", "bp-off", "item", "bp-on"
2740 ]
2741 );
2742 }
2743
2744 struct SlowWriteSrv(Events);
2746
2747 impl Service<(), DispatchItem<BCodec>> for SlowWriteSrv {
2748 type Res = Option<Bytes>;
2749 type Error = ();
2750
2751 async fn call(
2752 &self,
2753 msg: DispatchItem<BCodec>,
2754 _: Ctx<'_, Self>,
2755 ) -> Result<Option<Bytes>, Self::Error> {
2756 let ev = match msg {
2757 DispatchItem::Item(_) => {
2758 sleep(Millis(300)).await;
2759 self.0.borrow_mut().push("item");
2760 return Ok(Some(Bytes::from(vec![b'x'; 8192])));
2761 }
2762 DispatchItem::Control(Control::WBackPressureEnabled) => "bp-on",
2763 DispatchItem::Control(Control::WBackPressureDisabled) => "bp-off",
2764 DispatchItem::Stop(Reason::ReadTimeout) => "read-timeout",
2765 DispatchItem::Stop(_) => "stop",
2766 };
2767 self.0.borrow_mut().push(ev);
2768 Ok(None)
2769 }
2770 }
2771
2772 #[ntex::test]
2775 async fn read_rate_stopped_during_write_backpressure() {
2776 let (client, server) = IoTest::create();
2777 client.remote_buffer_cap(0);
2778
2779 let events: Events = Rc::new(RefCell::new(Vec::new()));
2780 let io = Io::new(
2781 server,
2782 SharedCfg::new("TEST").add(
2783 IoConfig::new()
2784 .set_write_backpressure(1024)
2785 .set_frame_read_rate(Seconds(1), Seconds::ZERO, 0),
2786 ),
2787 );
2788 let disp = Dispatcher::new(
2789 io,
2790 BCodec(8),
2791 Pipeline::new((), SlowWriteSrv(events.clone())),
2792 );
2793 spawn(async move {
2794 let _ = disp.await;
2795 });
2796
2797 client.write("12345678");
2800 sleep(Millis(100)).await;
2801 client.write("1");
2802 sleep(Millis(400)).await;
2803 assert_eq!(&events.borrow()[..], &["item", "bp-on"]);
2804
2805 for _ in 0..5 {
2808 sleep(Millis(500)).await;
2809 client.write("1");
2810 }
2811 assert_eq!(&events.borrow()[..], &["item", "bp-on"]);
2812 }
2813
2814 struct ErrCodec;
2816
2817 impl Encoder for ErrCodec {
2818 type Item = Bytes;
2819 type Error = io::Error;
2820
2821 fn encode(&self, _: Bytes, _: &mut BytePages) -> Result<(), Self::Error> {
2822 Err(io::Error::other("encode"))
2823 }
2824 }
2825
2826 impl Decoder for ErrCodec {
2827 type Item = Bytes;
2828 type Error = io::Error;
2829
2830 fn decode(&self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
2831 if src.contains(&b'!') {
2832 Err(io::Error::other("decode"))
2833 } else if src.is_empty() {
2834 Ok(None)
2835 } else {
2836 Ok(Some(src.split_to(src.len())))
2837 }
2838 }
2839 }
2840
2841 async fn err_codec_stop(input: &'static str) -> String {
2844 let (client, server) = IoTest::create();
2845 client.remote_buffer_cap(1024);
2846 client.write(input);
2847
2848 let reason = Rc::new(RefCell::new(String::new()));
2849 let reason2 = reason.clone();
2850 let (disp, _) = Dispatcher::debug(
2851 Io::from(server),
2852 ErrCodec,
2853 ntex_service::fn_service(move |msg: DispatchItem<ErrCodec>| {
2854 let reason = reason2.clone();
2855 async move {
2856 match msg {
2857 DispatchItem::Item(item) => return Ok::<_, ()>(Some(item)),
2858 DispatchItem::Stop(r) => *reason.borrow_mut() = format!("{r:?}"),
2859 DispatchItem::Control(_) => (),
2860 }
2861 Ok(None)
2862 }
2863 }),
2864 );
2865 assert!(format!("{disp:?}").contains("Dispatcher"));
2866 assert_eq!(timeout(Millis(1000), disp).await, Ok(Ok(())));
2867 reason.take()
2868 }
2869
2870 #[ntex::test]
2871 async fn encoder_error_stops_dispatcher() {
2872 let reason = err_codec_stop("data").await;
2873 assert!(reason.starts_with("Reason::Encoder("), "{reason}");
2874 assert!(reason.contains("encode"), "{reason}");
2875 }
2876
2877 #[ntex::test]
2878 async fn decoder_error_stops_dispatcher() {
2879 let reason = err_codec_stop("!").await;
2880 assert!(reason.starts_with("Reason::Decoder("), "{reason}");
2881 assert!(reason.contains("decode"), "{reason}");
2882 }
2883
2884 #[test]
2885 fn debug_formats() {
2886 let item = DispatchItem::<BCodec>::Item(Bytes::from_static(b"x"));
2887 assert_eq!(format!("{item:?}"), "DispatchItem::Item(b\"x\")");
2888 let item = DispatchItem::<BCodec>::Control(Control::WBackPressureEnabled);
2889 assert_eq!(
2890 format!("{item:?}"),
2891 "DispatchItem::Control(WBackPressureEnabled)"
2892 );
2893 let item = DispatchItem::<BCodec>::Stop(Reason::KeepAlive);
2894 assert_eq!(format!("{item:?}"), "DispatchItem::Stop(Reason::KeepAlive)");
2895
2896 for (reason, expected) in [
2897 (Reason::<BCodec>::Service, "Reason::Service"),
2898 (Reason::Io(None), "Reason::Io(None)"),
2899 (Reason::KeepAlive, "Reason::KeepAlive"),
2900 (Reason::ReadTimeout, "Reason::ReadTimeout"),
2901 (Reason::WriteTimeout, "Reason::WriteTimeout"),
2902 ] {
2903 assert_eq!(format!("{reason:?}"), expected);
2904 }
2905 let reason = Reason::<BCodec>::Encoder(io::Error::other("e"));
2906 assert!(format!("{reason:?}").starts_with("Reason::Encoder("));
2907 let reason = Reason::<BCodec>::Decoder(io::Error::other("d"));
2908 assert!(format!("{reason:?}").starts_with("Reason::Decoder("));
2909 }
2910
2911 #[ntex::test]
2914 async fn write_error_during_backpressure() {
2915 let (client, server) = IoTest::create();
2916 client.remote_buffer_cap(0);
2917
2918 let events = Rc::new(RefCell::new(Vec::new()));
2919 let events2 = events.clone();
2920 let io = Io::new(
2921 server,
2922 SharedCfg::new("TEST").add(IoConfig::new().set_write_backpressure(1024)),
2923 );
2924 let (disp, _) = Dispatcher::debug(
2925 io,
2926 BCodec(1),
2927 ntex_service::fn_service(move |msg: DispatchItem<BCodec>| {
2928 let events = events2.clone();
2929 async move {
2930 let ev = match msg {
2931 DispatchItem::Item(_) => {
2932 events.borrow_mut().push("item".to_string());
2933 return Ok::<_, ()>(Some(Bytes::from(vec![b'x'; 4096])));
2934 }
2935 DispatchItem::Control(c) => format!("{c:?}"),
2936 DispatchItem::Stop(Reason::Io(Some(err))) => format!("io: {err}"),
2937 DispatchItem::Stop(r) => format!("{r:?}"),
2938 };
2939 events.borrow_mut().push(ev);
2940 Ok(None)
2941 }
2942 }),
2943 );
2944 let hnd = spawn(disp);
2945
2946 client.write("1");
2947 sleep(Millis(100)).await;
2948 assert_eq!(&events.borrow()[..], &["item", "WBackPressureEnabled"]);
2949
2950 client.write_error(io::Error::other("write failed"));
2951 client.remote_buffer_cap(1024);
2952 assert!(matches!(timeout(Millis(1000), hnd).await, Ok(Ok(Ok(())))));
2953 assert_eq!(
2954 &events.borrow()[..],
2955 &["item", "WBackPressureEnabled", "io: write failed"]
2956 );
2957 }
2958
2959 #[ntex::test]
2962 async fn read_rate_max_timeout_reached() {
2963 let (client, server) = IoTest::create();
2964 client.remote_buffer_cap(1024);
2965
2966 let data = Arc::new(Mutex::new(RefCell::new(Vec::new())));
2967 let data2 = data.clone();
2968 let io = Io::new(
2969 server,
2970 SharedCfg::new("TEST").add(
2971 IoConfig::new()
2972 .set_keepalive_timeout(Seconds::ZERO)
2973 .set_frame_read_rate(Seconds(1), Seconds(2), 2),
2974 ),
2975 );
2976 let (disp, _) = Dispatcher::debug(
2977 io,
2978 BCodec(1024),
2979 ntex_service::fn_service(move |msg: DispatchItem<BCodec>| {
2980 let data = data2.clone();
2981 async move {
2982 if let DispatchItem::Stop(Reason::ReadTimeout) = msg {
2983 data.lock().unwrap().borrow_mut().push(1);
2984 }
2985 Ok::<_, ()>(None)
2986 }
2987 }),
2988 );
2989 spawn(async move {
2990 let _ = disp.await;
2991 });
2992
2993 let start = std::time::Instant::now();
2994 for _ in 0..12 {
2995 client.write("abc");
2996 sleep(Millis(300)).await;
2997 if client.is_closed() {
2998 break;
2999 }
3000 }
3001 wait_closed(&client, Millis(1000)).await;
3002 assert!(client.is_closed());
3003 assert!(start.elapsed() < std::time::Duration::from_millis(3500));
3004 assert_eq!(&data.lock().unwrap().borrow()[..], &[1]);
3005 }
3006
3007 #[derive(Default)]
3008 struct GateDir {
3009 blocked: Cell<bool>,
3010 waker: RefCell<Option<std::task::Waker>>,
3011 }
3012
3013 impl GateDir {
3014 fn poll(
3015 &self,
3016 res: Poll<ntex_io::Readiness>,
3017 cx: &Context<'_>,
3018 ) -> Poll<ntex_io::Readiness> {
3019 match res {
3020 Poll::Ready(ntex_io::Readiness::Ready) if self.blocked.get() => {
3021 *self.waker.borrow_mut() = Some(cx.waker().clone());
3022 Poll::Pending
3023 }
3024 res => res,
3025 }
3026 }
3027
3028 fn set(&self, blocked: bool) {
3029 self.blocked.set(blocked);
3030 if !blocked && let Some(waker) = self.waker.borrow_mut().take() {
3031 waker.wake();
3032 }
3033 }
3034 }
3035
3036 #[derive(Clone, Default)]
3038 struct GateCtl(Rc<(GateDir, GateDir)>);
3039
3040 impl GateCtl {
3041 fn block(&self) {
3042 self.0.0.set(true);
3043 }
3044
3045 fn unblock(&self) {
3046 self.0.0.set(false);
3047 }
3048
3049 fn block_write(&self) {
3050 self.0.1.set(true);
3051 }
3052
3053 fn unblock_write(&self) {
3054 self.0.1.set(false);
3055 }
3056 }
3057
3058 struct GateFilter<F>(F, GateCtl);
3059
3060 impl<F: ntex_io::Filter> ntex_io::Filter for GateFilter<F> {
3061 fn query(&self, id: std::any::TypeId) -> Option<Box<dyn std::any::Any>> {
3062 self.0.query(id)
3063 }
3064
3065 fn process_read_buf(&self, ctx: &mut ntex_io::FilterCtx<'_>) -> io::Result<()> {
3066 self.0.process_read_buf(ctx)
3067 }
3068
3069 fn process_write_buf(&self, ctx: &mut ntex_io::FilterCtx<'_>) -> io::Result<()> {
3070 self.0.process_write_buf(ctx)
3071 }
3072
3073 fn shutdown(&self, ctx: &mut ntex_io::FilterCtx<'_>) -> io::Result<Poll<()>> {
3074 self.0.shutdown(ctx)
3075 }
3076
3077 fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<ntex_io::Readiness> {
3078 self.1.0.0.poll(self.0.poll_read_ready(cx), cx)
3079 }
3080
3081 fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<ntex_io::Readiness> {
3082 self.1.0.1.poll(self.0.poll_write_ready(cx), cx)
3083 }
3084 }
3085
3086 fn gated_dispatcher(
3089 server: IoTest,
3090 cfg: IoConfig,
3091 data: Rc<RefCell<Vec<u8>>>,
3092 ) -> (GateCtl, IoRef) {
3093 let gate = GateCtl::default();
3094 let g = gate.clone();
3095 let io =
3096 Io::new(server, SharedCfg::new("TEST").add(cfg)).map_filter(move |f| GateFilter(f, g));
3097 let ioref = io.get_ref();
3098
3099 let disp = Dispatcher::new(
3100 io,
3101 BCodec(8),
3102 Pipeline::new(
3103 (),
3104 ntex_service::fn_service(move |msg: DispatchItem<BCodec>| {
3105 let data = data.clone();
3106 async move {
3107 match msg {
3108 DispatchItem::Item(bytes) => {
3109 data.borrow_mut().push(0);
3110 return Ok::<_, ()>(Some(bytes));
3111 }
3112 DispatchItem::Stop(Reason::ReadTimeout | Reason::KeepAlive) => {
3113 data.borrow_mut().push(1);
3114 }
3115 _ => (),
3116 }
3117 Ok(None)
3118 }
3119 }),
3120 ),
3121 );
3122 spawn(async move {
3123 let _ = disp.await;
3124 });
3125 (gate, ioref)
3126 }
3127
3128 #[ntex::test]
3129 async fn filter_pause_suspends_read_timeout() {
3130 let (client, server) = IoTest::create();
3131 client.remote_buffer_cap(1024);
3132 let data = Rc::new(RefCell::new(Vec::new()));
3133 let (gate, io) = gated_dispatcher(
3134 server,
3135 IoConfig::new()
3136 .set_keepalive_timeout(Seconds::ZERO)
3137 .set_frame_read_rate(Seconds(1), Seconds(2), 2),
3138 data.clone(),
3139 );
3140
3141 client.write("1234");
3143 sleep(Millis(100)).await;
3144
3145 gate.block();
3147 client.write("5678");
3148 sleep(Millis(100)).await;
3149 assert!(io.is_read_filter_paused());
3150
3151 sleep(Millis(3000)).await;
3153 assert!(io.is_active());
3154 assert!(data.borrow().is_empty());
3155
3156 gate.unblock();
3157 let buf = client.read().await.unwrap();
3158 assert_eq!(buf, Bytes::from_static(b"12345678"));
3159 assert!(!io.is_read_filter_paused());
3160 assert_eq!(&data.borrow()[..], &[0]);
3161 }
3162
3163 #[ntex::test]
3164 async fn filter_pause_suspends_keepalive() {
3165 let (client, server) = IoTest::create();
3166 client.remote_buffer_cap(1024);
3167 let data = Rc::new(RefCell::new(Vec::new()));
3168 let (gate, io) = gated_dispatcher(
3169 server,
3170 IoConfig::new()
3171 .set_shutdown_timeout(Seconds(1))
3172 .set_keepalive_timeout(Seconds(1)),
3173 data.clone(),
3174 );
3175
3176 sleep(Millis(100)).await;
3178 gate.block();
3179 client.write("12345678");
3180 sleep(Millis(100)).await;
3181 assert!(io.is_read_filter_paused());
3182
3183 sleep(Millis(2000)).await;
3185 assert!(io.is_active());
3186 assert!(data.borrow().is_empty());
3187
3188 gate.unblock();
3189 let buf = client.read().await.unwrap();
3190 assert_eq!(buf, Bytes::from_static(b"12345678"));
3191
3192 wait_until(Millis(3000), || {
3194 !io.is_active() && client.is_closed() && data.borrow().len() == 2
3195 })
3196 .await;
3197 assert!(!io.is_active());
3198 assert!(client.is_closed());
3199 assert_eq!(&data.borrow()[..], &[0, 1]);
3200 }
3201
3202 fn gated_write_dispatcher(
3204 server: IoTest,
3205 cfg: IoConfig,
3206 size: usize,
3207 ) -> (GateCtl, IoRef, Events) {
3208 let gate = GateCtl::default();
3209 let g = gate.clone();
3210 let events = Rc::new(RefCell::new(Vec::new()));
3211 let io = Io::new(
3212 server,
3213 SharedCfg::new("TEST").add(cfg.set_write_backpressure(1024)),
3214 )
3215 .map_filter(move |f| GateFilter(f, g));
3216 let ioref = io.get_ref();
3217 let disp = Dispatcher::new(
3218 io,
3219 BCodec(8),
3220 Pipeline::new(
3221 (),
3222 WriteSrv {
3223 size,
3224 gate: Rc::new(RefCell::new(None)),
3225 events: events.clone(),
3226 },
3227 ),
3228 );
3229 spawn(async move {
3230 let _ = disp.await;
3231 });
3232 (gate, ioref, events)
3233 }
3234
3235 #[ntex::test]
3236 async fn filter_pause_suspends_write_timeout() {
3237 let (client, server) = IoTest::create();
3238 client.remote_buffer_cap(65536);
3239 let (gate, io, events) =
3240 gated_write_dispatcher(server, IoConfig::new().set_write_timeout(Seconds(1)), 8192);
3241
3242 gate.block_write();
3244 client.write("12345678");
3245 sleep(Millis(100)).await;
3246 assert!(io.is_write_filter_paused());
3247 assert_eq!(&events.borrow()[..], &["item", "bp-on"]);
3248
3249 sleep(Millis(2500)).await;
3251 assert!(io.is_active());
3252 assert_eq!(&events.borrow()[..], &["item", "bp-on"]);
3253
3254 gate.unblock_write();
3255 let mut received = 0;
3256 while received < 8192 {
3257 received += client.read().await.unwrap().len();
3258 }
3259 assert!(!io.is_write_filter_paused());
3260 wait_until(Millis(1000), || events.borrow().len() == 3).await;
3261 assert_eq!(&events.borrow()[..], &["item", "bp-on", "bp-off"]);
3262 }
3263
3264 #[ntex::test]
3265 async fn write_timeout_restarts_after_filter_pause() {
3266 let (client, server) = IoTest::create();
3267 client.remote_buffer_cap(0);
3268 let (gate, io, events) =
3269 gated_write_dispatcher(server, IoConfig::new().set_write_timeout(Seconds(1)), 8192);
3270
3271 gate.block_write();
3272 client.write("12345678");
3273 sleep(Millis(1500)).await;
3274 assert!(io.is_write_filter_paused());
3275 assert!(io.is_active());
3276
3277 gate.unblock_write();
3279 sleep(Millis(500)).await;
3280 assert!(!io.is_write_filter_paused());
3281 assert!(io.is_active());
3282 wait_closed(&client, Millis(2000)).await;
3283 assert!(client.is_closed());
3284 assert_eq!(&events.borrow()[..], &["item", "bp-on", "write-timeout"]);
3285 }
3286}