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