Skip to main content

ng_tungstenite/protocol/
mod.rs

1//! Generic WebSocket message stream.
2
3pub mod frame;
4
5mod message;
6
7pub use self::{frame::CloseFrame, message::Message};
8
9use log::*;
10use std::{
11    collections::VecDeque,
12    io::{ErrorKind as IoErrorKind, Read, Write},
13    mem::replace,
14};
15
16use self::{
17    frame::{
18        coding::{CloseCode, Control as OpCtl, Data as OpData, OpCode},
19        Frame, FrameCodec,
20    },
21    message::{IncompleteMessage, IncompleteMessageType},
22};
23use crate::{
24    error::{Error, ProtocolError, Result},
25    util::NonBlockingResult,
26};
27
28/// Indicates a Client or Server role of the websocket
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum Role {
31    /// This socket is a server
32    Server,
33    /// This socket is a client
34    Client,
35}
36
37/// The configuration for WebSocket connection.
38#[derive(Debug, Clone, Copy)]
39pub struct WebSocketConfig {
40    /// The size of the send queue. You can use it to turn on/off the backpressure features. `None`
41    /// means here that the size of the queue is unlimited. The default value is the unlimited
42    /// queue.
43    pub max_send_queue: Option<usize>,
44    /// The maximum size of a message. `None` means no size limit. The default value is 64 MiB
45    /// which should be reasonably big for all normal use-cases but small enough to prevent
46    /// memory eating by a malicious user.
47    pub max_message_size: Option<usize>,
48    /// The maximum size of a single message frame. `None` means no size limit. The limit is for
49    /// frame payload NOT including the frame header. The default value is 16 MiB which should
50    /// be reasonably big for all normal use-cases but small enough to prevent memory eating
51    /// by a malicious user.
52    pub max_frame_size: Option<usize>,
53    /// When set to `true`, the server will accept and handle unmasked frames
54    /// from the client. According to the RFC 6455, the server must close the
55    /// connection to the client in such cases, however it seems like there are
56    /// some popular libraries that are sending unmasked frames, ignoring the RFC.
57    /// By default this option is set to `false`, i.e. according to RFC 6455.
58    pub accept_unmasked_frames: bool,
59}
60
61impl Default for WebSocketConfig {
62    fn default() -> Self {
63        WebSocketConfig {
64            max_send_queue: None,
65            max_message_size: Some(64 << 20),
66            max_frame_size: Some(16 << 20),
67            accept_unmasked_frames: false,
68        }
69    }
70}
71
72/// WebSocket input-output stream.
73///
74/// This is THE structure you want to create to be able to speak the WebSocket protocol.
75/// It may be created by calling `connect`, `accept` or `client` functions.
76#[derive(Debug)]
77pub struct WebSocket<Stream> {
78    /// The underlying socket.
79    socket: Stream,
80    /// The context for managing a WebSocket.
81    context: WebSocketContext,
82}
83
84impl<Stream> WebSocket<Stream> {
85    /// Convert a raw socket into a WebSocket without performing a handshake.
86    ///
87    /// Call this function if you're using Tungstenite as a part of a web framework
88    /// or together with an existing one. If you need an initial handshake, use
89    /// `connect()` or `accept()` functions of the crate to construct a websocket.
90    pub fn from_raw_socket(stream: Stream, role: Role, config: Option<WebSocketConfig>) -> Self {
91        WebSocket { socket: stream, context: WebSocketContext::new(role, config) }
92    }
93
94    /// Convert a raw socket into a WebSocket without performing a handshake.
95    ///
96    /// Call this function if you're using Tungstenite as a part of a web framework
97    /// or together with an existing one. If you need an initial handshake, use
98    /// `connect()` or `accept()` functions of the crate to construct a websocket.
99    pub fn from_partially_read(
100        stream: Stream,
101        part: Vec<u8>,
102        role: Role,
103        config: Option<WebSocketConfig>,
104    ) -> Self {
105        WebSocket {
106            socket: stream,
107            context: WebSocketContext::from_partially_read(part, role, config),
108        }
109    }
110
111    /// Returns a shared reference to the inner stream.
112    pub fn get_ref(&self) -> &Stream {
113        &self.socket
114    }
115    /// Returns a mutable reference to the inner stream.
116    pub fn get_mut(&mut self) -> &mut Stream {
117        &mut self.socket
118    }
119
120    /// Change the configuration.
121    pub fn set_config(&mut self, set_func: impl FnOnce(&mut WebSocketConfig)) {
122        self.context.set_config(set_func)
123    }
124
125    /// Read the configuration.
126    pub fn get_config(&self) -> &WebSocketConfig {
127        self.context.get_config()
128    }
129
130    /// Check if it is possible to read messages.
131    ///
132    /// Reading is impossible after receiving `Message::Close`. It is still possible after
133    /// sending close frame since the peer still may send some data before confirming close.
134    pub fn can_read(&self) -> bool {
135        self.context.can_read()
136    }
137
138    /// Check if it is possible to write messages.
139    ///
140    /// Writing gets impossible immediately after sending or receiving `Message::Close`.
141    pub fn can_write(&self) -> bool {
142        self.context.can_write()
143    }
144}
145
146impl<Stream: Read + Write> WebSocket<Stream> {
147    /// Read a message from stream, if possible.
148    ///
149    /// This will queue responses to ping and close messages to be sent. It will call
150    /// `write_pending` before trying to read in order to make sure that those responses
151    /// make progress even if you never call `write_pending`. That does mean that they
152    /// get sent out earliest on the next call to `read_message`, `write_message` or `write_pending`.
153    ///
154    /// ## Closing the connection
155    /// When the remote endpoint decides to close the connection this will return
156    /// the close message with an optional close frame.
157    ///
158    /// You should continue calling `read_message`, `write_message` or `write_pending` to drive
159    /// the reply to the close frame until [Error::ConnectionClosed] is returned. Once that happens
160    /// it is safe to drop the underlying connection.
161    pub fn read_message(&mut self) -> Result<Message> {
162        self.context.read_message(&mut self.socket)
163    }
164
165    /// Send a message to stream, if possible.
166    ///
167    /// WebSocket will buffer a configurable number of messages at a time, except to reply to Ping
168    /// requests. A Pong reply will jump the queue because the
169    /// [websocket RFC](https://tools.ietf.org/html/rfc6455#section-5.5.2) specifies it should be sent
170    /// as soon as is practical.
171    ///
172    /// Note that upon receiving a ping message, tungstenite cues a pong reply automatically.
173    /// When you call either `read_message`, `write_message` or `write_pending` next it will try to send
174    /// that pong out if the underlying connection can take more data. This means you should not
175    /// respond to ping frames manually.
176    ///
177    /// You can however send pong frames manually in order to indicate a unidirectional heartbeat
178    /// as described in [RFC 6455](https://tools.ietf.org/html/rfc6455#section-5.5.3). Note that
179    /// if `read_message` returns a ping, you should call `write_pending` until it doesn't return
180    /// WouldBlock before passing a pong to `write_message`, otherwise the response to the
181    /// ping will not be sent, but rather replaced by your custom pong message.
182    ///
183    /// ## Errors
184    /// - If the WebSocket's send queue is full, `SendQueueFull` will be returned
185    /// along with the passed message. Otherwise, the message is queued and Ok(()) is returned.
186    /// - If the connection is closed and should be dropped, this will return [Error::ConnectionClosed].
187    /// - If you try again after [Error::ConnectionClosed] was returned either from here or from `read_message`,
188    ///   [Error::AlreadyClosed] will be returned. This indicates a program error on your part.
189    /// - [Error::Io] is returned if the underlying connection returns an error
190    ///   (consider these fatal except for WouldBlock).
191    /// - [Error::Capacity] if your message size is bigger than the configured max message size.
192    pub fn write_message(&mut self, message: Message) -> Result<()> {
193        self.context.write_message(&mut self.socket, message)
194    }
195
196    /// Flush the pending send queue.
197    pub fn write_pending(&mut self) -> Result<()> {
198        self.context.write_pending(&mut self.socket)
199    }
200
201    /// Close the connection.
202    ///
203    /// This function guarantees that the close frame will be queued.
204    /// There is no need to call it again. Calling this function is
205    /// the same as calling `write_message(Message::Close(..))`.
206    ///
207    /// After queuing the close frame you should continue calling `read_message` or
208    /// `write_pending` to drive the close handshake to completion.
209    ///
210    /// The websocket RFC defines that the underlying connection should be closed
211    /// by the server. Tungstenite takes care of this asymmetry for you.
212    ///
213    /// When the close handshake is finished (we have both sent and received
214    /// a close message), `read_message` or `write_pending` will return
215    /// [Error::ConnectionClosed] if this endpoint is the server.
216    ///
217    /// If this endpoint is a client, [Error::ConnectionClosed] will only be
218    /// returned after the server has closed the underlying connection.
219    ///
220    /// It is thus safe to drop the underlying connection as soon as [Error::ConnectionClosed]
221    /// is returned from `read_message` or `write_pending`.
222    pub fn close(&mut self, code: Option<CloseFrame>) -> Result<()> {
223        self.context.close(&mut self.socket, code)
224    }
225}
226
227/// A context for managing WebSocket stream.
228#[derive(Debug)]
229pub struct WebSocketContext {
230    /// Server or client?
231    role: Role,
232    /// encoder/decoder of frame.
233    frame: FrameCodec,
234    /// The state of processing, either "active" or "closing".
235    state: WebSocketState,
236    /// Receive: an incomplete message being processed.
237    incomplete: Option<IncompleteMessage>,
238    /// Send: a data send queue.
239    send_queue: VecDeque<Frame>,
240    /// Send: an OOB pong message.
241    pong: Option<Frame>,
242    /// The configuration for the websocket session.
243    config: WebSocketConfig,
244}
245
246impl WebSocketContext {
247    /// Create a WebSocket context that manages a post-handshake stream.
248    pub fn new(role: Role, config: Option<WebSocketConfig>) -> Self {
249        WebSocketContext {
250            role,
251            frame: FrameCodec::new(),
252            state: WebSocketState::Active,
253            incomplete: None,
254            send_queue: VecDeque::new(),
255            pong: None,
256            config: config.unwrap_or_default(),
257        }
258    }
259
260    /// Create a WebSocket context that manages an post-handshake stream.
261    pub fn from_partially_read(part: Vec<u8>, role: Role, config: Option<WebSocketConfig>) -> Self {
262        WebSocketContext {
263            frame: FrameCodec::from_partially_read(part),
264            ..WebSocketContext::new(role, config)
265        }
266    }
267
268    /// Change the configuration.
269    pub fn set_config(&mut self, set_func: impl FnOnce(&mut WebSocketConfig)) {
270        set_func(&mut self.config)
271    }
272
273    /// Read the configuration.
274    pub fn get_config(&self) -> &WebSocketConfig {
275        &self.config
276    }
277
278    /// Check if it is possible to read messages.
279    ///
280    /// Reading is impossible after receiving `Message::Close`. It is still possible after
281    /// sending close frame since the peer still may send some data before confirming close.
282    pub fn can_read(&self) -> bool {
283        self.state.can_read()
284    }
285
286    /// Check if it is possible to write messages.
287    ///
288    /// Writing gets impossible immediately after sending or receiving `Message::Close`.
289    pub fn can_write(&self) -> bool {
290        self.state.is_active()
291    }
292
293    /// Read a message from the provided stream, if possible.
294    ///
295    /// This function sends pong and close responses automatically.
296    /// However, it never blocks on write.
297    pub fn read_message<Stream>(&mut self, stream: &mut Stream) -> Result<Message>
298    where
299        Stream: Read + Write,
300    {
301        // Do not read from already closed connections.
302        self.state.check_active()?;
303
304        loop {
305            // Since we may get ping or close, we need to reply to the messages even during read.
306            // Thus we call write_pending() but ignore its blocking.
307            self.write_pending(stream).no_block()?;
308            // If we get here, either write blocks or we have nothing to write.
309            // Thus if read blocks, just let it return WouldBlock.
310            if let Some(message) = self.read_message_frame(stream)? {
311                trace!("Received message {}", message);
312                return Ok(message);
313            }
314        }
315    }
316
317    /// Send a message to the provided stream, if possible.
318    ///
319    /// WebSocket will buffer a configurable number of messages at a time, except to reply to Ping
320    /// and Close requests. If the WebSocket's send queue is full, `SendQueueFull` will be returned
321    /// along with the passed message. Otherwise, the message is queued and Ok(()) is returned.
322    ///
323    /// Note that only the last pong frame is stored to be sent, and only the
324    /// most recent pong frame is sent if multiple pong frames are queued.
325    pub fn write_message<Stream>(&mut self, stream: &mut Stream, message: Message) -> Result<()>
326    where
327        Stream: Read + Write,
328    {
329        // When terminated, return AlreadyClosed.
330        self.state.check_active()?;
331
332        // Do not write after sending a close frame.
333        if !self.state.is_active() {
334            return Err(Error::Protocol(ProtocolError::SendAfterClosing));
335        }
336
337        if let Some(max_send_queue) = self.config.max_send_queue {
338            if self.send_queue.len() >= max_send_queue {
339                // Try to make some room for the new message.
340                // Do not return here if write would block, ignore WouldBlock silently
341                // since we must queue the message anyway.
342                self.write_pending(stream).no_block()?;
343            }
344
345            if self.send_queue.len() >= max_send_queue {
346                return Err(Error::SendQueueFull(message));
347            }
348        }
349
350        let frame = match message {
351            Message::Text(data) => Frame::message(data.into(), OpCode::Data(OpData::Text), true),
352            Message::Binary(data) => Frame::message(data, OpCode::Data(OpData::Binary), true),
353            Message::Ping(data) => Frame::ping(data),
354            Message::Pong(data) => {
355                self.pong = Some(Frame::pong(data));
356                return self.write_pending(stream);
357            }
358            Message::Close(code) => return self.close(stream, code),
359            Message::Frame(f) => f,
360        };
361
362        self.send_queue.push_back(frame);
363        self.write_pending(stream)
364    }
365
366    /// Flush the pending send queue.
367    pub fn write_pending<Stream>(&mut self, stream: &mut Stream) -> Result<()>
368    where
369        Stream: Read + Write,
370    {
371        // First, make sure we have no pending frame sending.
372        self.frame.write_pending(stream)?;
373
374        // Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in
375        // response, unless it already received a Close frame. It SHOULD
376        // respond with Pong frame as soon as is practical. (RFC 6455)
377        if let Some(pong) = self.pong.take() {
378            trace!("Sending pong reply");
379            self.send_one_frame(stream, pong)?;
380        }
381        // If we have any unsent frames, send them.
382        trace!("Frames still in queue: {}", self.send_queue.len());
383        while let Some(data) = self.send_queue.pop_front() {
384            self.send_one_frame(stream, data)?;
385        }
386
387        // If we get to this point, the send queue is empty and the underlying socket is still
388        // willing to take more data.
389
390        // If we're closing and there is nothing to send anymore, we should close the connection.
391        if self.role == Role::Server && !self.state.can_read() {
392            // The underlying TCP connection, in most normal cases, SHOULD be closed
393            // first by the server, so that it holds the TIME_WAIT state and not the
394            // client (as this would prevent it from re-opening the connection for 2
395            // maximum segment lifetimes (2MSL), while there is no corresponding
396            // server impact as a TIME_WAIT connection is immediately reopened upon
397            // a new SYN with a higher seq number). (RFC 6455)
398            self.state = WebSocketState::Terminated;
399            Err(Error::ConnectionClosed)
400        } else {
401            Ok(())
402        }
403    }
404
405    /// Close the connection.
406    ///
407    /// This function guarantees that the close frame will be queued.
408    /// There is no need to call it again. Calling this function is
409    /// the same as calling `write(Message::Close(..))`.
410    pub fn close<Stream>(&mut self, stream: &mut Stream, code: Option<CloseFrame>) -> Result<()>
411    where
412        Stream: Read + Write,
413    {
414        if let WebSocketState::Active = self.state {
415            self.state = WebSocketState::ClosedByUs;
416            let frame = Frame::close(code);
417            self.send_queue.push_back(frame);
418        } else {
419            // Already closed, nothing to do.
420        }
421        self.write_pending(stream)
422    }
423
424    /// Try to decode one message frame. May return None.
425    fn read_message_frame<Stream>(&mut self, stream: &mut Stream) -> Result<Option<Message>>
426    where
427        Stream: Read + Write,
428    {
429        if let Some(mut frame) = self
430            .frame
431            .read_frame(stream, self.config.max_frame_size)
432            .check_connection_reset(self.state)?
433        {
434            if !self.state.can_read() {
435                return Err(Error::Protocol(ProtocolError::ReceivedAfterClosing));
436            }
437            // MUST be 0 unless an extension is negotiated that defines meanings
438            // for non-zero values.  If a nonzero value is received and none of
439            // the negotiated extensions defines the meaning of such a nonzero
440            // value, the receiving endpoint MUST _Fail the WebSocket
441            // Connection_.
442            {
443                let hdr = frame.header();
444                if hdr.rsv1 || hdr.rsv2 || hdr.rsv3 {
445                    return Err(Error::Protocol(ProtocolError::NonZeroReservedBits));
446                }
447            }
448
449            match self.role {
450                Role::Server => {
451                    if frame.is_masked() {
452                        // A server MUST remove masking for data frames received from a client
453                        // as described in Section 5.3. (RFC 6455)
454                        frame.apply_mask()
455                    } else if !self.config.accept_unmasked_frames {
456                        // The server MUST close the connection upon receiving a
457                        // frame that is not masked. (RFC 6455)
458                        // The only exception here is if the user explicitly accepts given
459                        // stream by setting WebSocketConfig.accept_unmasked_frames to true
460                        return Err(Error::Protocol(ProtocolError::UnmaskedFrameFromClient));
461                    }
462                }
463                Role::Client => {
464                    if frame.is_masked() {
465                        // A client MUST close a connection if it detects a masked frame. (RFC 6455)
466                        return Err(Error::Protocol(ProtocolError::MaskedFrameFromServer));
467                    }
468                }
469            }
470
471            match frame.header().opcode {
472                OpCode::Control(ctl) => {
473                    match ctl {
474                        // All control frames MUST have a payload length of 125 bytes or less
475                        // and MUST NOT be fragmented. (RFC 6455)
476                        _ if !frame.header().is_final => {
477                            Err(Error::Protocol(ProtocolError::FragmentedControlFrame))
478                        }
479                        _ if frame.payload().len() > 125 => {
480                            Err(Error::Protocol(ProtocolError::ControlFrameTooBig))
481                        }
482                        OpCtl::Close => Ok(self.do_close(frame.into_close()?).map(Message::Close)),
483                        OpCtl::Reserved(i) => {
484                            Err(Error::Protocol(ProtocolError::UnknownControlFrameType(i)))
485                        }
486                        OpCtl::Ping => {
487                            let data = frame.into_data();
488                            // No ping processing after we sent a close frame.
489                            if self.state.is_active() {
490                                self.pong = Some(Frame::pong(data.clone()));
491                            }
492                            Ok(Some(Message::Ping(data)))
493                        }
494                        OpCtl::Pong => Ok(Some(Message::Pong(frame.into_data()))),
495                    }
496                }
497
498                OpCode::Data(data) => {
499                    let fin = frame.header().is_final;
500                    match data {
501                        OpData::Continue => {
502                            if let Some(ref mut msg) = self.incomplete {
503                                msg.extend(frame.into_data(), self.config.max_message_size)?;
504                            } else {
505                                return Err(Error::Protocol(
506                                    ProtocolError::UnexpectedContinueFrame,
507                                ));
508                            }
509                            if fin {
510                                Ok(Some(self.incomplete.take().unwrap().complete()?))
511                            } else {
512                                Ok(None)
513                            }
514                        }
515                        c if self.incomplete.is_some() => {
516                            Err(Error::Protocol(ProtocolError::ExpectedFragment(c)))
517                        }
518                        OpData::Text | OpData::Binary => {
519                            let msg = {
520                                let message_type = match data {
521                                    OpData::Text => IncompleteMessageType::Text,
522                                    OpData::Binary => IncompleteMessageType::Binary,
523                                    _ => panic!("Bug: message is not text nor binary"),
524                                };
525                                let mut m = IncompleteMessage::new(message_type);
526                                m.extend(frame.into_data(), self.config.max_message_size)?;
527                                m
528                            };
529                            if fin {
530                                Ok(Some(msg.complete()?))
531                            } else {
532                                self.incomplete = Some(msg);
533                                Ok(None)
534                            }
535                        }
536                        OpData::Reserved(i) => {
537                            Err(Error::Protocol(ProtocolError::UnknownDataFrameType(i)))
538                        }
539                    }
540                }
541            } // match opcode
542        } else {
543            // Connection closed by peer
544            match replace(&mut self.state, WebSocketState::Terminated) {
545                WebSocketState::ClosedByPeer | WebSocketState::CloseAcknowledged => {
546                    Err(Error::ConnectionClosed)
547                }
548                _ => Err(Error::Protocol(ProtocolError::ResetWithoutClosingHandshake)),
549            }
550        }
551    }
552
553    /// Received a close frame. Tells if we need to return a close frame to the user.
554    #[allow(clippy::option_option)]
555    fn do_close<'t>(&mut self, close: Option<CloseFrame<'t>>) -> Option<Option<CloseFrame<'t>>> {
556        debug!("Received close frame: {:?}", close);
557        match self.state {
558            WebSocketState::Active => {
559                self.state = WebSocketState::ClosedByPeer;
560
561                let close = close.map(|frame| {
562                    if !frame.code.is_allowed() {
563                        CloseFrame {
564                            code: CloseCode::Protocol,
565                            reason: "Protocol violation".into(),
566                        }
567                    } else {
568                        frame
569                    }
570                });
571
572                let reply = Frame::close(close.clone());
573                debug!("Replying to close with {:?}", reply);
574                self.send_queue.push_back(reply);
575
576                Some(close)
577            }
578            WebSocketState::ClosedByPeer | WebSocketState::CloseAcknowledged => {
579                // It is already closed, just ignore.
580                None
581            }
582            WebSocketState::ClosedByUs => {
583                // We received a reply.
584                self.state = WebSocketState::CloseAcknowledged;
585                Some(close)
586            }
587            WebSocketState::Terminated => unreachable!(),
588        }
589    }
590
591    /// Send a single pending frame.
592    fn send_one_frame<Stream>(&mut self, stream: &mut Stream, mut frame: Frame) -> Result<()>
593    where
594        Stream: Read + Write,
595    {
596        match self.role {
597            Role::Server => {}
598            Role::Client => {
599                // 5.  If the data is being sent by the client, the frame(s) MUST be
600                // masked as defined in Section 5.3. (RFC 6455)
601                frame.set_random_mask();
602            }
603        }
604
605        trace!("Sending frame: {:?}", frame);
606        self.frame.write_frame(stream, frame).check_connection_reset(self.state)
607    }
608}
609
610/// The current connection state.
611#[derive(Debug, PartialEq, Eq, Clone, Copy)]
612enum WebSocketState {
613    /// The connection is active.
614    Active,
615    /// We initiated a close handshake.
616    ClosedByUs,
617    /// The peer initiated a close handshake.
618    ClosedByPeer,
619    /// The peer replied to our close handshake.
620    CloseAcknowledged,
621    /// The connection does not exist anymore.
622    Terminated,
623}
624
625impl WebSocketState {
626    /// Tell if we're allowed to process normal messages.
627    fn is_active(self) -> bool {
628        matches!(self, WebSocketState::Active)
629    }
630
631    /// Tell if we should process incoming data. Note that if we send a close frame
632    /// but the remote hasn't confirmed, they might have sent data before they receive our
633    /// close frame, so we should still pass those to client code, hence ClosedByUs is valid.
634    fn can_read(self) -> bool {
635        matches!(self, WebSocketState::Active | WebSocketState::ClosedByUs)
636    }
637
638    /// Check if the state is active, return error if not.
639    fn check_active(self) -> Result<()> {
640        match self {
641            WebSocketState::Terminated => Err(Error::AlreadyClosed),
642            _ => Ok(()),
643        }
644    }
645}
646
647/// Translate "Connection reset by peer" into `ConnectionClosed` if appropriate.
648trait CheckConnectionReset {
649    fn check_connection_reset(self, state: WebSocketState) -> Self;
650}
651
652impl<T> CheckConnectionReset for Result<T> {
653    fn check_connection_reset(self, state: WebSocketState) -> Self {
654        match self {
655            Err(Error::Io(io_error)) => Err({
656                if !state.can_read() && io_error.kind() == IoErrorKind::ConnectionReset {
657                    Error::ConnectionClosed
658                } else {
659                    Error::Io(io_error)
660                }
661            }),
662            x => x,
663        }
664    }
665}
666
667#[cfg(test)]
668mod tests {
669    use super::{Message, Role, WebSocket, WebSocketConfig};
670    use crate::error::{CapacityError, Error};
671
672    use std::{io, io::Cursor};
673
674    struct WriteMoc<Stream>(Stream);
675
676    impl<Stream> io::Write for WriteMoc<Stream> {
677        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
678            Ok(buf.len())
679        }
680        fn flush(&mut self) -> io::Result<()> {
681            Ok(())
682        }
683    }
684
685    impl<Stream: io::Read> io::Read for WriteMoc<Stream> {
686        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
687            self.0.read(buf)
688        }
689    }
690
691    struct WouldBlockStreamMoc;
692
693    impl io::Write for WouldBlockStreamMoc {
694        fn write(&mut self, _: &[u8]) -> io::Result<usize> {
695            Err(io::Error::new(io::ErrorKind::WouldBlock, "would block"))
696        }
697        fn flush(&mut self) -> io::Result<()> {
698            Err(io::Error::new(io::ErrorKind::WouldBlock, "would block"))
699        }
700    }
701
702    impl io::Read for WouldBlockStreamMoc {
703        fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
704            Err(io::Error::new(io::ErrorKind::WouldBlock, "would block"))
705        }
706    }
707
708    #[test]
709    fn queue_logic() {
710        // Create a socket with the queue size of 1.
711        let mut socket = WebSocket::from_raw_socket(
712            WouldBlockStreamMoc,
713            Role::Client,
714            Some(WebSocketConfig { max_send_queue: Some(1), ..Default::default() }),
715        );
716
717        // Test message that we're going to send.
718        let message = Message::Binary(vec![0xFF; 1024]);
719
720        // Helper to check the error.
721        let assert_would_block = |error| {
722            if let Error::Io(io_error) = error {
723                assert_eq!(io_error.kind(), io::ErrorKind::WouldBlock);
724            } else {
725                panic!("Expected WouldBlock error");
726            }
727        };
728
729        // The first attempt of writing must not fail, since the queue is empty at start.
730        // But since the underlying mock object always returns `WouldBlock`, so is the result.
731        assert_would_block(dbg!(socket.write_message(message.clone()).unwrap_err()));
732
733        // Any subsequent attempts must return an error telling that the queue is full.
734        for _i in 0..100 {
735            assert!(matches!(
736                socket.write_message(message.clone()).unwrap_err(),
737                Error::SendQueueFull(..)
738            ));
739        }
740
741        // The size of the output buffer must not be bigger than the size of that message
742        // that we managed to write to the output buffer at first. Since we could not make
743        // any progress (because of the logic of the moc buffer), the size remains unchanged.
744        if socket.context.frame.output_buffer_len() > message.len() {
745            panic!("Too many frames in the queue");
746        }
747    }
748
749    #[test]
750    fn receive_messages() {
751        let incoming = Cursor::new(vec![
752            0x89, 0x02, 0x01, 0x02, 0x8a, 0x01, 0x03, 0x01, 0x07, 0x48, 0x65, 0x6c, 0x6c, 0x6f,
753            0x2c, 0x20, 0x80, 0x06, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x82, 0x03, 0x01, 0x02,
754            0x03,
755        ]);
756        let mut socket = WebSocket::from_raw_socket(WriteMoc(incoming), Role::Client, None);
757        assert_eq!(socket.read_message().unwrap(), Message::Ping(vec![1, 2]));
758        assert_eq!(socket.read_message().unwrap(), Message::Pong(vec![3]));
759        assert_eq!(socket.read_message().unwrap(), Message::Text("Hello, World!".into()));
760        assert_eq!(socket.read_message().unwrap(), Message::Binary(vec![0x01, 0x02, 0x03]));
761    }
762
763    #[test]
764    fn size_limiting_text_fragmented() {
765        let incoming = Cursor::new(vec![
766            0x01, 0x07, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x80, 0x06, 0x57, 0x6f, 0x72,
767            0x6c, 0x64, 0x21,
768        ]);
769        let limit = WebSocketConfig { max_message_size: Some(10), ..WebSocketConfig::default() };
770        let mut socket = WebSocket::from_raw_socket(WriteMoc(incoming), Role::Client, Some(limit));
771
772        assert!(matches!(
773            socket.read_message(),
774            Err(Error::Capacity(CapacityError::MessageTooLong { size: 13, max_size: 10 }))
775        ));
776    }
777
778    #[test]
779    fn size_limiting_binary() {
780        let incoming = Cursor::new(vec![0x82, 0x03, 0x01, 0x02, 0x03]);
781        let limit = WebSocketConfig { max_message_size: Some(2), ..WebSocketConfig::default() };
782        let mut socket = WebSocket::from_raw_socket(WriteMoc(incoming), Role::Client, Some(limit));
783
784        assert!(matches!(
785            socket.read_message(),
786            Err(Error::Capacity(CapacityError::MessageTooLong { size: 3, max_size: 2 }))
787        ));
788    }
789}