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}