1use std::{any, fmt, hash, io, ptr};
2
3use ntex_bytes::{BytePage, BytePages, BytesMut};
4use ntex_codec::{Decoder, Encoder};
5use ntex_service::cfg::SharedCfg;
6use ntex_util::time::Seconds;
7
8use crate::ops::{Id, Iops, TimerHandle};
9use crate::{Decoded, Filter, FilterBuf, Flags, IoConfig, IoContext, IoRef, types};
10
11impl IoRef {
12 #[inline]
13 pub fn id(&self) -> Id {
15 self.0.id()
16 }
17
18 #[inline]
19 pub fn tag(&self) -> &'static str {
21 self.0.tag()
22 }
23
24 #[doc(hidden)]
25 pub fn flags(&self) -> Flags {
27 self.0.flags.clone()
28 }
29
30 #[inline]
31 pub(crate) fn filter(&self) -> &dyn Filter {
33 self.0.filter()
34 }
35
36 #[inline]
37 pub fn cfg(&self) -> &IoConfig {
39 &self.0.cfg
40 }
41
42 #[inline]
43 pub fn shared(&self) -> SharedCfg {
45 self.0.cfg.shared()
46 }
47
48 #[inline]
49 pub fn is_closed(&self) -> bool {
51 self.0.flags.is_closed()
52 }
53
54 #[inline]
55 pub fn is_wr_backpressure(&self) -> bool {
57 self.0.flags.is_wr_backpressure()
58 }
59
60 pub fn close(&self) {
64 self.0.start_shutdown();
65 }
66
67 pub fn terminate(&self) {
72 log::trace!("{}: Terminate io stream object", self.tag());
73 self.0.terminate_connection(None);
74 }
75
76 #[doc(hidden)]
77 #[deprecated(since = "3.10.0", note = "use IoRef::terminate() instead")]
78 pub fn force_close(&self) {
83 self.terminate();
84 }
85
86 #[doc(hidden)]
87 #[deprecated(since = "3.11.0", note = "use IoRef::close() instead")]
88 pub fn wants_shutdown(&self) {
90 self.0.start_shutdown();
91 }
92
93 pub fn query<T: 'static>(&self) -> types::QueryItem<T> {
95 types::QueryItem::new(self.filter().query(any::TypeId::of::<T>()))
96 }
97
98 #[inline]
99 pub fn encode<U>(&self, item: U::Item, codec: &U) -> Result<(), <U as Encoder>::Error>
101 where
102 U: Encoder,
103 {
104 self.with_write_buf(|buf| codec.encodev(item, buf))
105 .unwrap_or_else(|_| Ok(()))
106 }
107
108 #[inline]
109 pub fn encode_slice(&self, src: &[u8]) -> io::Result<()> {
111 self.with_write_buf(|buf| buf.extend_from_slice(src))
112 }
113
114 #[inline]
115 pub fn encode_bytes<B>(&self, src: B) -> io::Result<()>
117 where
118 BytePage: From<B>,
119 {
120 self.with_write_buf(|buf| buf.append(src))
121 }
122
123 pub fn decode<U>(
125 &self,
126 codec: &U,
127 ) -> Result<Option<<U as Decoder>::Item>, <U as Decoder>::Error>
128 where
129 U: Decoder,
130 {
131 self.0.buffer.with_read_dst(self, |buf| {
132 let res = codec.decode(buf);
133 self.0.flags.unset_read_ready();
134 self.update_read_destination(buf);
135 res
136 })
137 }
138
139 pub fn decode_item<U>(
141 &self,
142 codec: &U,
143 ) -> Result<Decoded<<U as Decoder>::Item>, <U as Decoder>::Error>
144 where
145 U: Decoder,
146 {
147 self.0.buffer.with_read_dst(self, |buf| {
148 let len = buf.len();
149 let res = codec.decode(buf).map(|item| Decoded {
150 item,
151 remains: buf.len(),
152 consumed: len - buf.len(),
153 });
154 self.0.flags.unset_read_ready();
155 self.update_read_destination(buf);
156 res
157 })
158 }
159
160 pub fn send_buf(&self) -> io::Result<()> {
165 self.consolidate_write_state(true);
167
168 if self.0.flags.is_stopping_any()
169 && let Some(err) = self.0.error.take()
170 {
171 Err(err)
172 } else {
173 Ok(())
174 }
175 }
176
177 pub(crate) fn ops_send_buf(&self) {
178 let st = &self.0;
179 #[cfg(feature = "trace")]
180 log::trace!(
181 "{}: ops-send == buf:{} flags:{:?}",
182 st.tag(),
183 st.buffer.write_buf_size(),
184 st.flags
185 );
186
187 if st.flags.is_wr_send_scheduled() {
188 st.flags.unset_wr_send_scheduled();
189
190 if st.flags.is_write_paused() {
191 if self.call_write() == WakeWriteTask::Yes {
195 st.wake_write_task();
196 st.flags.unset_write_paused();
197 }
198 } else {
199 st.wake_write_task();
200 }
201 }
202 }
203
204 pub fn with_buf<F, R>(&self, f: F) -> io::Result<R>
206 where
207 F: FnOnce(&mut FilterBuf<'_>) -> R,
208 {
209 self.with_callbacks(|cb| cb.before_processing(self));
210 let result = self.0.buffer.with_filter(self, |ctx| ctx.with_buffer(f));
211 self.with_callbacks(|cb| cb.after_processing(self));
212
213 self.consolidate_write_state(false);
214 Ok(result)
215 }
216
217 pub fn with_read_buf<F, R>(&self, f: F) -> R
219 where
220 F: FnOnce(&mut BytesMut) -> R,
221 {
222 self.0.buffer.with_read_dst(self, |buf| {
223 let res = f(buf);
224 self.update_read_destination(buf);
225 res
226 })
227 }
228
229 pub fn with_write_buf<F, R>(&self, f: F) -> io::Result<R>
231 where
232 F: FnOnce(&mut BytePages) -> R,
233 {
234 let st = &self.0;
235
236 if st.flags.is_stopping_any() {
237 if st.flags.is_closed() {
238 Err(st.error_or_disconnected())
239 } else {
240 Err(io::Error::other("I/O stream is closing"))
241 }
242 } else {
243 let result = st.buffer.with_write_src(f);
244 self.consolidate_write_state(false);
245 Ok(result)
246 }
247 }
248
249 #[inline]
250 pub fn with_read_src_buf<F, R>(&self, f: F) -> R
252 where
253 F: FnOnce(&mut BytesMut) -> R,
254 {
255 self.0.buffer.with_read_src(self, f)
256 }
257
258 #[inline]
259 pub fn with_write_dst_buf<F, R>(&self, f: F) -> R
261 where
262 F: FnOnce(&mut BytePages) -> R,
263 {
264 self.0.buffer.with_write_dst(f)
265 }
266
267 pub(crate) fn consolidate_write_state(&self, force: bool) {
268 let st = &self.0;
269
270 let size = st.buffer.write_buf_size();
272
273 #[cfg(feature = "trace")]
274 log::trace!("{}: write-upd == buf:{size} flags:{:?}", st.tag(), st.flags);
275
276 if size > 0 && st.flags.is_write_paused() {
277 if st.flags.is_direct_wr_enabled()
288 && (force || size >= st.cfg.write_buf_threshold())
289 {
290 if self.call_write() == WakeWriteTask::Yes {
292 #[cfg(feature = "trace")]
293 log::trace!(
294 "{}: write-upd == schedule(more):{} flags:{:?}",
295 st.tag(),
296 st.buffer.write_buf_size(),
297 st.flags
298 );
299 if !st.flags.is_wr_send_scheduled() {
300 st.flags.set_wr_send_scheduled();
302 Iops::schedule_write(st.id());
303 }
304 } else {
305 st.flags.unset_wr_send_scheduled();
306 }
307 } else if !st.flags.is_wr_send_scheduled() {
308 #[cfg(feature = "trace")]
309 log::trace!("{}: write-upd == schedule(too small)", st.tag());
310 st.flags.set_wr_send_scheduled();
311 Iops::schedule_write(st.id());
312 }
313 }
314 if !st.flags.is_wr_backpressure() && st.is_wr_backpressure_needed(size) {
316 st.flags.set_wr_backpressure();
317 st.wake_dispatch_task();
318 }
319 }
320
321 fn update_read_destination(&self, buf: &mut BytesMut) {
322 let st = &self.0;
323
324 #[cfg(feature = "trace")]
325 log::trace!(
326 "{}: read-upd == buf:{} flags:{:?}",
327 st.tag(),
328 buf.len(),
329 st.flags
330 );
331
332 if st.flags.is_rd_backpressure() {
333 if st.is_rd_backpressure_needed(buf.len()) {
335 return;
336 }
337 st.flags.unset_all_read_flags();
338 } else {
339 st.flags.unset_read_ready();
340 }
341
342 if st.flags.is_read_paused() {
343 st.wake_read_task();
344 st.flags.unset_read_paused();
345 }
346 }
347
348 pub fn resize_read_buf(&self, buf: &mut BytesMut) {
350 self.0.cfg.read_buf().resize(buf);
351 }
352
353 #[doc(hidden)]
354 #[deprecated(since = "3.10.3", note = "Use .notify_disapatcher()")]
355 pub fn wake(&self) {
357 self.notify_dispatcher();
358 }
359
360 pub fn notify_dispatcher(&self) {
362 log::trace!("{}: Timer, notify dispatcher", self.tag());
363 self.0.wake_dispatch_task();
364 }
365
366 pub fn notify_timeout(&self) {
368 self.0.notify_timeout();
369 }
370
371 pub fn timer_handle(&self) -> TimerHandle {
373 self.0.timeout.get()
374 }
375
376 pub fn start_timer(&self, timeout: Seconds) -> TimerHandle {
378 let cur_hnd = self.0.timeout.get();
379
380 if timeout.is_zero() {
381 if cur_hnd.is_set() {
382 self.0.timeout.set(TimerHandle::ZERO);
383 cur_hnd.unregister(self);
384 }
385 TimerHandle::ZERO
386 } else if cur_hnd.is_set() {
387 let hnd = cur_hnd.update(timeout, self);
388 if hnd != cur_hnd {
389 log::trace!("{}: Update timer {:?}", self.tag(), timeout);
390 self.0.timeout.set(hnd);
391 }
392 hnd
393 } else {
394 log::trace!("{}: Start timer {:?}", self.tag(), timeout);
395 let hnd = TimerHandle::register(timeout, self);
396 self.0.timeout.set(hnd);
397 hnd
398 }
399 }
400
401 pub fn stop_timer(&self) {
403 let hnd = self.0.timeout.get();
404 if hnd.is_set() {
405 log::trace!("{}: Stop timer", self.tag());
406 self.0.timeout.set(TimerHandle::ZERO);
407 hnd.unregister(self);
408 }
409 }
410
411 pub fn on_disconnect(&self) -> crate::OnDisconnect {
413 crate::OnDisconnect::new(self.0.clone())
414 }
415
416 #[doc(hidden)]
417 pub fn register_filter_callbacks<F: crate::IoCallbacks + 'static>(&self, f: F) {
419 self.0.extensions.register_filter_callbacks(f);
420 }
421
422 fn call_write(&self) -> WakeWriteTask {
425 if let Some(hnd) = self.0.handle.take() {
426 self.0.flags.unset_write_paused();
427 #[cfg(feature = "trace")]
428 log::trace!(
429 "{}: call-write ({}), flags:{:?}",
430 self.tag(),
431 self.0.buffer.write_buf_size(),
432 self.0.flags
433 );
434 let ctx = unsafe { &*(ptr::from_ref(self).cast::<IoContext>()) };
435 hnd.write(ctx);
436 self.0.handle.set(Some(hnd));
437 }
438 if self.0.flags.is_write_paused() {
439 WakeWriteTask::No
440 } else {
441 WakeWriteTask::Yes
442 }
443 }
444
445 pub(crate) fn call_notify(&self) {
446 if let Some(hnd) = self.0.handle.take() {
447 let ctx = unsafe { &*(ptr::from_ref(self).cast::<IoContext>()) };
448 hnd.notify(ctx);
449 self.0.handle.set(Some(hnd));
450 }
451 }
452
453 pub(crate) fn with_callbacks<F>(&self, f: F)
454 where
455 F: FnOnce(&dyn crate::IoCallbacks),
456 {
457 self.0.extensions.with_callbacks(f);
458 }
459}
460
461#[derive(Copy, Clone, PartialEq, Eq, Debug)]
462enum WakeWriteTask {
463 Yes,
464 No,
465}
466
467impl Eq for IoRef {}
468
469impl PartialEq for IoRef {
470 #[inline]
471 fn eq(&self, other: &Self) -> bool {
472 self.0.eq(&other.0)
473 }
474}
475
476impl hash::Hash for IoRef {
477 #[inline]
478 fn hash<H: hash::Hasher>(&self, state: &mut H) {
479 self.0.hash(state);
480 }
481}
482
483impl fmt::Debug for IoRef {
484 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
485 f.debug_struct("IoRef")
486 .field("state", self.0.as_ref())
487 .finish()
488 }
489}
490
491#[cfg(test)]
492mod tests {
493 use std::cell::{Cell, RefCell};
494 use std::{future::Future, future::poll_fn, pin::Pin, rc::Rc, task::Poll};
495
496 use ntex_bytes::Bytes;
497 use ntex_codec::BytesCodec;
498 use ntex_util::{future::lazy, time::Millis, time::sleep};
499
500 use super::*;
501 use crate::{FilterCtx, Io, testing::IoTest};
502
503 const BIN: &[u8] = b"GET /test HTTP/1\r\n\r\n";
504 const TEXT: &str = "GET /test HTTP/1\r\n\r\n";
505
506 #[ntex::test]
507 async fn utils() {
508 let (client, server) = IoTest::create();
509 client.remote_buffer_cap(1024);
510 client.write(TEXT);
511
512 let state = Io::from(server);
513 assert_eq!(state.get_ref(), state.get_ref());
514
515 let msg = state.recv(&BytesCodec).await.unwrap().unwrap();
516 assert_eq!(msg, Bytes::from_static(BIN));
517 assert_eq!(state.get_ref(), state.as_ref().clone());
518 assert!(format!("{state:?}").find("Io {").is_some());
519 assert!(format!("{:?}", state.get_ref()).find("IoRef {").is_some());
520
521 let res = poll_fn(|cx| Poll::Ready(state.poll_recv(&BytesCodec, cx))).await;
522 assert!(res.is_pending());
523 client.write(TEXT);
524 sleep(Millis(50)).await;
525 let res = poll_fn(|cx| Poll::Ready(state.poll_recv(&BytesCodec, cx))).await;
526 if let Poll::Ready(msg) = res {
527 assert_eq!(msg.unwrap(), Bytes::from_static(BIN));
528 }
529
530 client.read_error(io::Error::other("err"));
531 let msg = state.recv(&BytesCodec).await;
532 assert!(msg.is_err());
533 assert!(state.flags().is_terminated());
534
535 let (client, server) = IoTest::create();
536 client.remote_buffer_cap(1024);
537 let state = Io::from(server);
538
539 client.read_error(io::Error::other("err"));
540 let res = poll_fn(|cx| Poll::Ready(state.poll_recv(&BytesCodec, cx))).await;
541 if let Poll::Ready(msg) = res {
542 assert!(msg.is_err());
543 assert!(state.flags().is_terminated());
544 }
545
546 let (client, server) = IoTest::create();
547 client.remote_buffer_cap(1024);
548 let state = Io::from(server);
549 assert_eq!(0, state.with_write_dst_buf(|b| b.len()));
550 state.encode_slice(b"test").unwrap();
551 assert_eq!(4, state.with_write_dst_buf(|b| b.len()));
552 let buf = client.read().await.unwrap();
553 assert_eq!(buf, Bytes::from_static(b"test"));
554
555 client.write(b"test");
556 state.read_ready().await.unwrap();
557 let buf = state.decode(&BytesCodec).unwrap().unwrap();
558 assert_eq!(buf, Bytes::from_static(b"test"));
559
560 client.write_error(io::Error::other("err"));
561 state
562 .send(Bytes::from_static(b"test"), &BytesCodec)
563 .await
564 .unwrap();
565 assert!(state.flags().is_terminated());
566
567 let res = state.send(Bytes::from_static(b"test"), &BytesCodec).await;
568 assert!(res.is_err());
569
570 let (client, server) = IoTest::create();
571 client.remote_buffer_cap(1024);
572 let state = Io::from(server);
573 state.terminate();
574 assert!(state.flags().is_stopping());
575 assert!(state.flags().is_terminated());
576 }
577
578 #[ntex::test]
579 #[allow(clippy::unit_cmp)]
580 async fn on_disconnect() {
581 let (client, server) = IoTest::create();
582 let state = Io::from(server);
583 let mut waiter = state.on_disconnect();
584 assert_eq!(
585 lazy(|cx| Pin::new(&mut waiter).poll(cx)).await,
586 Poll::Pending
587 );
588 let mut waiter2 = waiter.clone();
589 assert_eq!(
590 lazy(|cx| Pin::new(&mut waiter2).poll(cx)).await,
591 Poll::Pending
592 );
593 client.close().await;
594 assert_eq!(waiter.await, ());
595 assert_eq!(waiter2.await, ());
596
597 let mut waiter = state.on_disconnect();
598 assert_eq!(
599 lazy(|cx| Pin::new(&mut waiter).poll(cx)).await,
600 Poll::Ready(())
601 );
602
603 let (client, server) = IoTest::create();
604 let state = Io::from(server);
605 let mut waiter = state.on_disconnect();
606 assert_eq!(
607 lazy(|cx| Pin::new(&mut waiter).poll(cx)).await,
608 Poll::Pending
609 );
610 client.read_error(io::Error::other("err"));
611 assert_eq!(waiter.await, ());
612 }
613
614 #[ntex::test]
615 async fn write_to_closed_io() {
616 let (client, server) = IoTest::create();
617 let state = Io::from(server);
618 client.close().await;
619
620 assert!(state.is_closed());
621 assert!(state.encode_slice(TEXT.as_bytes()).is_err());
622 assert!(state.encode_bytes(Bytes::from_static(BIN)).is_err());
623 assert!(
624 state
625 .with_write_buf(|buf| buf.extend_from_slice(BIN))
626 .is_err()
627 );
628 }
629
630 #[derive(Debug)]
631 struct Counter<F> {
632 layer: F,
633 idx: usize,
634 in_bytes: Rc<Cell<usize>>,
635 out_bytes: Rc<Cell<usize>>,
636 read_order: Rc<RefCell<Vec<usize>>>,
637 write_order: Rc<RefCell<Vec<usize>>>,
638 }
639
640 impl<F: Filter> Filter for Counter<F> {
641 fn process_read_buf(&self, ctx: &mut FilterCtx<'_>) -> io::Result<()> {
642 self.read_order.borrow_mut().push(self.idx);
643 let result = self.layer.process_read_buf(ctx);
644 self.in_bytes
645 .set(self.in_bytes.get() + ctx.new_read_bytes());
646 result
647 }
648
649 fn process_write_buf(&self, ctx: &mut FilterCtx<'_>) -> io::Result<()> {
650 self.write_order.borrow_mut().push(self.idx);
651 ctx.with_buffer(|buf| {
652 buf.with_write_buffers(|src, _| {
653 self.out_bytes.set(self.out_bytes.get() + src.len());
654 });
655 });
656 self.layer.process_write_buf(ctx)
657 }
658
659 crate::forward_ready!(layer);
660 crate::forward_query!(layer);
661 crate::forward_shutdown!(layer);
662 }
663
664 #[ntex::test]
665 async fn filter() {
666 let in_bytes = Rc::new(Cell::new(0));
667 let out_bytes = Rc::new(Cell::new(0));
668 let read_order = Rc::new(RefCell::new(Vec::new()));
669 let write_order = Rc::new(RefCell::new(Vec::new()));
670
671 let (client, server) = IoTest::create();
672 let io = Io::from(server)
673 .map_filter(|layer| Counter {
674 layer,
675 idx: 1,
676 in_bytes: in_bytes.clone(),
677 out_bytes: out_bytes.clone(),
678 read_order: read_order.clone(),
679 write_order: write_order.clone(),
680 })
681 .seal();
682
683 client.remote_buffer_cap(1024);
684 client.write(TEXT);
685 let msg = io.recv(&BytesCodec).await.unwrap().unwrap();
686 assert_eq!(msg, Bytes::from_static(BIN));
687
688 io.send(Bytes::from_static(b"test"), &BytesCodec)
689 .await
690 .unwrap();
691 let buf = client.read().await.unwrap();
692 assert_eq!(buf, Bytes::from_static(b"test"));
693
694 client.write(TEXT);
695 let msg = io.recv(&BytesCodec).await.unwrap().unwrap();
696 assert_eq!(msg, Bytes::from_static(BIN));
697
698 assert_eq!(in_bytes.get(), BIN.len() * 2);
699 assert_eq!(out_bytes.get(), 8);
700 }
701
702 #[ntex::test]
703 async fn boxed_filter() {
704 let in_bytes = Rc::new(Cell::new(0));
705 let out_bytes = Rc::new(Cell::new(0));
706 let read_order = Rc::new(RefCell::new(Vec::new()));
707 let write_order = Rc::new(RefCell::new(Vec::new()));
708
709 let (client, server) = IoTest::create();
710 let state = Io::from(server)
711 .map_filter(|layer| Counter {
712 layer,
713 idx: 2,
714 in_bytes: in_bytes.clone(),
715 out_bytes: out_bytes.clone(),
716 read_order: read_order.clone(),
717 write_order: write_order.clone(),
718 })
719 .map_filter(|layer| Counter {
720 layer,
721 idx: 1,
722 in_bytes: in_bytes.clone(),
723 out_bytes: out_bytes.clone(),
724 read_order: read_order.clone(),
725 write_order: write_order.clone(),
726 });
727 let state = state.seal();
728
729 client.remote_buffer_cap(1024);
730 client.write(TEXT);
731 let msg = state.recv(&BytesCodec).await.unwrap().unwrap();
732 assert_eq!(msg, Bytes::from_static(BIN));
733
734 state
735 .send(Bytes::from_static(b"test"), &BytesCodec)
736 .await
737 .unwrap();
738 let buf = client.read().await.unwrap();
739 assert_eq!(buf, Bytes::from_static(b"test"));
740
741 assert_eq!(in_bytes.get(), BIN.len() * 2);
742 assert_eq!(out_bytes.get(), 16);
743 assert_eq!(state.0.buffer.with_write_dst(|b| b.len()), 0);
744
745 assert_eq!(Rc::strong_count(&in_bytes), 3);
747 drop(state);
748 assert_eq!(Rc::strong_count(&in_bytes), 1);
749 assert_eq!(*read_order.borrow(), &[1, 2][..]);
750 assert_eq!(*write_order.borrow(), &[1, 2, 1, 2, 1, 2][..]);
751 }
752}