Skip to main content

tokio_websockets/proto/
stream.rs

1//! Frame aggregating abstraction over the low-level [`super::codec`]
2//! implementation that provides [`futures_sink::Sink`] and
3//! [`futures_core::Stream`] implementations that take [`Message`] as a
4//! parameter.
5use std::{
6    collections::VecDeque,
7    io::{self, IoSlice},
8    mem::{replace, take},
9    pin::Pin,
10    task::{Context, Poll, Waker, ready},
11};
12
13use bytes::{Buf, BytesMut};
14use futures_core::Stream;
15use futures_sink::Sink;
16use tokio::io::{AsyncRead, AsyncWrite};
17use tokio_util::{codec::FramedRead, io::poll_write_buf};
18
19#[cfg(any(feature = "client", feature = "server"))]
20use super::types::Role;
21use super::{
22    Config, Limits,
23    codec::WebSocketProtocol,
24    types::{Frame, Message, OpCode, Payload, StreamState},
25};
26use crate::{CloseCode, Error};
27
28/// Helper struct for storing a frame header, the header size and payload.
29#[derive(Debug)]
30struct EncodedFrame {
31    /// Encoded frame header and mask.
32    header: [u8; 14],
33    /// Potentially masked message payload, ready for writing to the I/O.
34    payload: Payload,
35}
36
37impl EncodedFrame {
38    /// Whether or not this frame is masked.
39    #[inline]
40    fn is_masked(&self) -> bool {
41        self.header[1] >> 7 != 0
42    }
43
44    /// Returns the length of the combined header and mask in bytes.
45    #[inline]
46    fn header_len(&self) -> usize {
47        let mask_bytes = if self.is_masked() { 4 } else { 0 };
48        match self.header[1] & 127 {
49            127 => 10 + mask_bytes,
50            126 => 4 + mask_bytes,
51            _ => 2 + mask_bytes,
52        }
53    }
54
55    /// Total length of the frame.
56    fn len(&self) -> usize {
57        self.header_len() + self.payload.len()
58    }
59}
60
61/// Queued up frames that are being sent.
62#[derive(Debug)]
63struct FrameQueue {
64    /// Queue of outgoing frames to send. Some parts of the first item may have
65    /// been sent already.
66    queue: VecDeque<EncodedFrame>,
67    /// Amount of partial bytes written of the first frame in the queue.
68    bytes_written: usize,
69    /// Total amount of bytes remaining to be sent in the frame queue.
70    pending_bytes: usize,
71}
72
73impl FrameQueue {
74    /// Creates a new, empty [`FrameQueue`].
75    #[cfg(any(feature = "client", feature = "server"))]
76    fn new() -> Self {
77        Self {
78            queue: VecDeque::with_capacity(1),
79            bytes_written: 0,
80            pending_bytes: 0,
81        }
82    }
83
84    /// Queue a frame to be sent.
85    fn push(&mut self, item: EncodedFrame) {
86        self.pending_bytes += item.len();
87        self.queue.push_back(item);
88    }
89}
90
91impl Buf for FrameQueue {
92    fn remaining(&self) -> usize {
93        self.pending_bytes
94    }
95
96    fn chunk(&self) -> &[u8] {
97        if let Some(frame) = self.queue.front() {
98            if self.bytes_written >= frame.header_len() {
99                unsafe {
100                    frame
101                        .payload
102                        .get_unchecked(self.bytes_written - frame.header_len()..)
103                }
104            } else {
105                &frame.header[self.bytes_written..frame.header_len()]
106            }
107        } else {
108            &[]
109        }
110    }
111
112    fn advance(&mut self, mut cnt: usize) {
113        self.pending_bytes -= cnt;
114        cnt += self.bytes_written;
115
116        while cnt > 0 {
117            let item = self
118                .queue
119                .front()
120                .expect("advance called with too long count");
121            let item_len = item.len();
122
123            if cnt >= item_len {
124                self.queue.pop_front();
125                self.bytes_written = 0;
126                cnt -= item_len;
127            } else {
128                self.bytes_written = cnt;
129                return;
130            }
131        }
132    }
133
134    fn chunks_vectored<'a>(&'a self, dst: &mut [io::IoSlice<'a>]) -> usize {
135        let mut n = 0;
136        for (idx, frame) in self.queue.iter().enumerate() {
137            if n >= dst.len() {
138                break;
139            }
140
141            if idx == 0 {
142                if frame.header_len() > self.bytes_written {
143                    dst[n] = IoSlice::new(&frame.header[self.bytes_written..frame.header_len()]);
144                    n += 1;
145                }
146
147                if !frame.payload.is_empty() && n < dst.len() {
148                    dst[n] = IoSlice::new(unsafe {
149                        frame
150                            .payload
151                            .get_unchecked(self.bytes_written.saturating_sub(frame.header_len())..)
152                    });
153                    n += 1;
154                }
155            } else {
156                dst[n] = IoSlice::new(&frame.header[..frame.header_len()]);
157                n += 1;
158                if !frame.payload.is_empty() && n < dst.len() {
159                    dst[n] = IoSlice::new(&frame.payload);
160                    n += 1;
161                }
162            }
163        }
164
165        n
166    }
167}
168
169/// A WebSocket stream that full messages can be read from and written to.
170///
171/// The stream implements [`futures_sink::Sink`] and [`futures_core::Stream`].
172///
173/// You must use a [`ClientBuilder`] or [`ServerBuilder`] to
174/// obtain a WebSocket stream.
175///
176/// For usage examples, see the top level crate documentation, which showcases a
177/// simple echo server and client.
178///
179/// [`ClientBuilder`]: crate::ClientBuilder
180/// [`ServerBuilder`]: crate::ServerBuilder
181#[allow(clippy::module_name_repetitions)]
182#[derive(Debug)]
183pub struct WebSocketStream<T> {
184    /// The underlying stream using the [`WebSocketProtocol`] to read and write
185    /// full frames.
186    inner: FramedRead<T, WebSocketProtocol>,
187
188    /// Configuration for the stream.
189    config: Config,
190
191    /// The [`StreamState`] of the current stream.
192    state: StreamState,
193
194    /// Payload of the full message that is being assembled.
195    partial_payload: BytesMut,
196    /// Opcode of the full message that is being assembled.
197    partial_opcode: OpCode,
198
199    /// Buffer that outgoing frame headers are formatted into.
200    header_buf: [u8; 14],
201
202    /// Queue of outgoing frames to send.
203    frame_queue: FrameQueue,
204
205    /// Waker used for currently actively polling
206    /// [`WebSocketStream::poll_flush`] until completion.
207    flushing_waker: Option<Waker>,
208}
209
210impl<T> WebSocketStream<T>
211where
212    T: AsyncRead + AsyncWrite + Unpin,
213{
214    /// Create a new [`WebSocketStream`] from a raw stream.
215    #[cfg(any(feature = "client", feature = "server"))]
216    pub(crate) fn from_raw_stream(stream: T, role: Role, config: Config, limits: Limits) -> Self {
217        Self {
218            inner: FramedRead::new(stream, WebSocketProtocol::new(role, limits)),
219            config,
220            state: StreamState::Active,
221            partial_payload: BytesMut::new(),
222            partial_opcode: OpCode::Continuation,
223            header_buf: [0; 14],
224            frame_queue: FrameQueue::new(),
225            flushing_waker: None,
226        }
227    }
228
229    /// Create a new [`WebSocketStream`] from an existing [`FramedRead`]. This
230    /// allows for reusing the internal buffer of the [`FramedRead`] object.
231    #[cfg(any(feature = "client", feature = "server"))]
232    pub(crate) fn from_framed<U>(
233        framed: FramedRead<T, U>,
234        role: Role,
235        config: Config,
236        limits: Limits,
237    ) -> Self {
238        Self {
239            inner: framed.map_decoder(|_| WebSocketProtocol::new(role, limits)),
240            config,
241            state: StreamState::Active,
242            partial_payload: BytesMut::new(),
243            partial_opcode: OpCode::Continuation,
244            header_buf: [0; 14],
245            frame_queue: FrameQueue::new(),
246            flushing_waker: None,
247        }
248    }
249
250    /// Returns a reference to the underlying I/O stream wrapped by this stream.
251    ///
252    /// Care should be taken not to tamper with the stream of data to avoid
253    /// corrupting the stream of frames.
254    pub fn get_ref(&self) -> &T {
255        self.inner.get_ref()
256    }
257
258    /// Returns a mutable reference to the underlying I/O stream wrapped by this
259    /// stream.
260    ///
261    /// Care should be taken not to tamper with the stream of data to avoid
262    /// corrupting the stream of frames.
263    pub fn get_mut(&mut self) -> &mut T {
264        self.inner.get_mut()
265    }
266
267    /// Returns a reference to the inner websocket limits.
268    pub fn limits(&self) -> &Limits {
269        &self.inner.decoder().limits
270    }
271
272    /// Returns a mutable reference to the inner websocket limits.
273    pub fn limits_mut(&mut self) -> &mut Limits {
274        &mut self.inner.decoder_mut().limits
275    }
276
277    /// Consumes the `WebSocketStream`, returning its underlying I/O stream.
278    pub fn into_inner(self) -> T {
279        self.inner.into_inner()
280    }
281
282    /// Attempt to pull out the next frame from the [`Framed`] this stream and
283    /// from that update the stream's internal state.
284    ///
285    /// # Errors
286    ///
287    /// This method returns an [`Error`] if reading from the stream fails or a
288    /// protocol violation is encountered.
289    fn poll_next_frame(
290        mut self: Pin<&mut Self>,
291        cx: &mut Context<'_>,
292    ) -> Poll<Option<Result<Frame, Error>>> {
293        // In the case of Active or ClosedByUs, we want to receive more messages from
294        // the remote. In the case of ClosedByPeer, we have to flush to make sure our
295        // close acknowledge goes through.
296        if self.state == StreamState::CloseAcknowledged {
297            return Poll::Ready(None);
298        } else if self.state == StreamState::ClosedByPeer {
299            ready!(self.as_mut().poll_flush(cx))?;
300            self.state = StreamState::CloseAcknowledged;
301            return Poll::Ready(None);
302        }
303
304        // If there are pending items, try to flush the sink.
305        // Futures only store a single waker. If we use poll_flush(cx) here, the stored
306        // waker (i.e. usually that of the write task) is replaced with our waker (i.e.
307        // that of the read task) and our write task may never get woken up again. We
308        // circumvent this by not calling poll_flush at all if poll_flush is polled by
309        // another task at the moment.
310        if self.frame_queue.has_remaining() {
311            let waker = self.flushing_waker.clone();
312            _ = self.as_mut().poll_flush(&mut Context::from_waker(
313                waker.as_ref().unwrap_or(cx.waker()),
314            ))?;
315        }
316
317        let frame = match ready!(Pin::new(&mut self.inner).poll_next(cx)) {
318            Some(Ok(frame)) => frame,
319            Some(Err(e)) => {
320                if matches!(e, Error::Io(_)) || self.state == StreamState::ClosedByUs {
321                    self.state = StreamState::CloseAcknowledged;
322                } else {
323                    self.state = StreamState::ClosedByPeer;
324
325                    match &e {
326                        Error::Protocol(e) => self.queue_frame(Frame::from(e)),
327                        Error::PayloadTooLong { max_len, .. } => self.queue_frame(
328                            Message::close(
329                                Some(CloseCode::MESSAGE_TOO_BIG),
330                                &format!("max length: {max_len}"),
331                            )
332                            .into(),
333                        ),
334                        _ => {}
335                    }
336                }
337                return Poll::Ready(Some(Err(e)));
338            }
339            None => return Poll::Ready(None),
340        };
341
342        match frame.opcode {
343            OpCode::Close => match self.state {
344                StreamState::Active => {
345                    self.state = StreamState::ClosedByPeer;
346
347                    let mut frame = frame.clone();
348                    frame.payload.truncate(2);
349
350                    self.queue_frame(frame);
351                }
352                StreamState::ClosedByPeer | StreamState::CloseAcknowledged => {
353                    debug_assert!(false, "unexpected StreamState");
354                }
355                StreamState::ClosedByUs => {
356                    self.state = StreamState::CloseAcknowledged;
357                }
358            },
359            OpCode::Ping if self.state == StreamState::Active => {
360                let mut frame = frame.clone();
361                frame.opcode = OpCode::Pong;
362
363                self.queue_frame(frame);
364            }
365            _ => {}
366        }
367
368        Poll::Ready(Some(Ok(frame)))
369    }
370
371    /// Masks and queues a frame for sending when [`poll_flush`] gets called.
372    fn queue_frame(
373        &mut self,
374        #[cfg_attr(not(feature = "client"), allow(unused_mut))] mut frame: Frame,
375    ) {
376        if frame.opcode == OpCode::Close && self.state != StreamState::ClosedByPeer {
377            self.state = StreamState::ClosedByUs;
378        }
379
380        #[cfg_attr(not(feature = "client"), allow(unused_variables))]
381        let mask = frame.encode(&mut self.header_buf);
382
383        #[cfg(feature = "client")]
384        {
385            if self.inner.decoder().role == Role::Client {
386                let mut payload = BytesMut::from(frame.payload);
387                crate::rand::get_mask(mask);
388                // mask::frame will mutate the mask in-place, but we want to send the original
389                // mask. This is essentially a u32, so copying it is cheap and easier than
390                // special-casing this in the masking implementation.
391                // &mut *mask won't work, the compiler will optimize the deref/copy away
392                let mut mask_copy = *mask;
393                crate::mask::frame(&mut mask_copy, &mut payload);
394                frame.payload = Payload::from(payload);
395                self.header_buf[1] |= 1 << 7;
396            }
397        }
398
399        let item = EncodedFrame {
400            header: self.header_buf,
401            payload: frame.payload,
402        };
403        self.frame_queue.push(item);
404    }
405
406    /// Sets the waker that is currently flushing to a new one and does nothing
407    /// if the waker is the same.
408    fn set_flushing_waker(&mut self, waker: &Waker) {
409        if !self
410            .flushing_waker
411            .as_ref()
412            .is_some_and(|w| w.will_wake(waker))
413        {
414            self.flushing_waker = Some(waker.clone());
415        }
416    }
417}
418
419impl<T> Stream for WebSocketStream<T>
420where
421    T: AsyncRead + AsyncWrite + Unpin,
422{
423    type Item = Result<Message, Error>;
424
425    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
426        let max_len = self.inner.decoder().limits.max_payload_len;
427
428        loop {
429            let (opcode, payload, fin) = match ready!(self.as_mut().poll_next_frame(cx)?) {
430                Some(frame) => (frame.opcode, frame.payload, frame.is_final),
431                None => return Poll::Ready(None),
432            };
433            let len = self.partial_payload.len() + payload.len();
434
435            if opcode != OpCode::Continuation {
436                if fin {
437                    return Poll::Ready(Some(Ok(Message { opcode, payload })));
438                }
439                self.partial_opcode = opcode;
440                self.partial_payload = BytesMut::from(payload);
441            } else if len > max_len {
442                return Poll::Ready(Some(Err(Error::PayloadTooLong { len, max_len })));
443            } else {
444                self.partial_payload.extend_from_slice(&payload);
445            }
446
447            if fin {
448                break;
449            }
450        }
451
452        let opcode = replace(&mut self.partial_opcode, OpCode::Continuation);
453        let mut payload = Payload::from(take(&mut self.partial_payload));
454        payload.set_utf8_validated(opcode == OpCode::Text);
455
456        Poll::Ready(Some(Ok(Message { opcode, payload })))
457    }
458}
459
460// The tokio-util implementation of a sink uses a buffer which start_send
461// appends to and poll_flush tries to write from. This makes sense, but comes
462// with a hefty performance penalty when sending large payloads, since this adds
463// a memmove from the payload to the buffer. We completely avoid that overhead
464// by storing messages in a deque.
465impl<T> Sink<Message> for WebSocketStream<T>
466where
467    T: AsyncRead + AsyncWrite + Unpin,
468{
469    type Error = Error;
470
471    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
472        // tokio-util calls poll_flush when more than 8096 bytes are pending, otherwise
473        // it returns Ready. We will just replicate that behavior
474        if self.frame_queue.remaining() >= self.config.flush_threshold {
475            self.as_mut().poll_flush(cx)
476        } else {
477            Poll::Ready(Ok(()))
478        }
479    }
480
481    fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
482        if self.state != StreamState::Active {
483            return Err(Error::AlreadyClosed);
484        }
485
486        if item.opcode.is_control() || item.payload.len() <= self.config.frame_size {
487            let frame: Frame = item.into();
488            self.queue_frame(frame);
489        } else {
490            // Chunk the message into frames
491            for frame in item.into_frames(self.config.frame_size) {
492                self.queue_frame(frame);
493            }
494        }
495
496        Ok(())
497    }
498
499    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
500        // Borrow checker hacks... It needs this to understand that we can separately
501        // borrow the fields of the struct mutably
502        let this = self.get_mut();
503        let frame_queue = &mut this.frame_queue;
504        let io = this.inner.get_mut();
505        let flushing_waker = &mut this.flushing_waker;
506
507        while frame_queue.has_remaining() {
508            let n = match poll_write_buf(Pin::new(io), cx, frame_queue) {
509                Poll::Ready(Ok(n)) => n,
510                Poll::Ready(Err(e)) => {
511                    *flushing_waker = None;
512                    this.state = StreamState::CloseAcknowledged;
513                    return Poll::Ready(Err(Error::Io(e)));
514                }
515                Poll::Pending => {
516                    this.set_flushing_waker(cx.waker());
517                    return Poll::Pending;
518                }
519            };
520
521            if n == 0 {
522                *flushing_waker = None;
523                this.state = StreamState::CloseAcknowledged;
524                return Poll::Ready(Err(Error::Io(io::ErrorKind::WriteZero.into())));
525            }
526        }
527
528        match Pin::new(io).poll_flush(cx) {
529            Poll::Ready(Ok(())) => {
530                *flushing_waker = None;
531                Poll::Ready(Ok(()))
532            }
533            Poll::Ready(Err(e)) => {
534                *flushing_waker = None;
535                this.state = StreamState::CloseAcknowledged;
536                Poll::Ready(Err(Error::Io(e)))
537            }
538            Poll::Pending => {
539                this.set_flushing_waker(cx.waker());
540                Poll::Pending
541            }
542        }
543    }
544
545    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
546        if self.state == StreamState::Active {
547            self.queue_frame(Frame::DEFAULT_CLOSE);
548        }
549        while ready!(self.as_mut().poll_next(cx)).is_some() {}
550
551        ready!(self.as_mut().poll_flush(cx))?;
552        Pin::new(self.inner.get_mut())
553            .poll_shutdown(cx)
554            .map_err(Error::Io)
555    }
556}