http_ws/error.rs
1use core::fmt;
2
3use std::error;
4
5use super::proto::OpCode;
6
7/// WebSocket protocol errors.
8///
9/// # Close handshake errors
10///
11/// [`SendClosed`](Self::SendClosed), [`RecvClosed`](Self::RecvClosed), and
12/// [`UnexpectedEof`](Self::UnexpectedEof) are related to the WebSocket close handshake.
13/// Their meaning depends on the context in which they are observed:
14///
15/// ## `SendClosed`
16///
17/// Returned by [`ResponseSender::send`] when a Close frame has already been sent on this
18/// session. This can happen in two scenarios:
19///
20/// - **You called `close()` and then tried to send more messages.** After sending a Close
21/// frame, no further messages are permitted per RFC 6455.
22/// - **A concurrent sender (via [`ResponseWeakSender::upgrade`]) already initiated the
23/// close.** The caller observing this error should return gracefully — the shutdown is
24/// already in progress.
25///
26/// ## `RecvClosed`
27///
28/// Returned by [`RequestStream`] (as `WsError::Protocol(ProtocolError::RecvClosed)`) when
29/// the stream is polled after a Close frame has already been received and yielded. The
30/// caller should have stopped polling after observing `Message::Close`. Receiving this
31/// error means:
32///
33/// - The remote peer sent a Close frame, which was already yielded as
34/// `Ok(Message::Close(_))`.
35/// - The caller should respond with a Close frame via [`ResponseSender`] (if not already
36/// sent) and then drop both the stream and sender.
37///
38/// ## `UnexpectedEof`
39///
40/// Returned by [`RequestStream`] when the underlying transport closed without a Close
41/// frame. This is an abnormal closure — the remote peer disconnected without following the
42/// WebSocket protocol. The associated connection should not be reused.
43///
44/// # Typical close flows
45///
46/// **Remote-initiated close:**
47/// 1. [`RequestStream`] yields `Ok(Message::Close(reason))`.
48/// 2. Caller sends a Close frame back via [`ResponseSender::close`].
49/// 3. Caller drops both the stream and sender.
50///
51/// **Local-initiated close:**
52/// 1. Caller calls [`ResponseSender::close`].
53/// 2. Caller continues polling [`RequestStream`] for the peer's Close echo.
54/// 3. [`RequestStream`] yields `Ok(Message::Close(_))` — handshake complete.
55/// 4. Caller drops the stream. Any concurrent senders attempting to send will observe
56/// `SendClosed`.
57///
58/// **Timeout on close echo:**
59/// 1. Caller calls [`ResponseSender::close`].
60/// 2. Caller polls [`RequestStream`] with a timeout.
61/// 3. Timeout expires — caller sends an error via [`ResponseSender::send_error`] to signal
62/// the I/O layer to shut down the connection.
63#[derive(Debug)]
64pub enum ProtocolError {
65 UnmaskedFrame,
66 MaskedFrame,
67 InvalidOpcode(u8),
68 InvalidLength(usize),
69 BadOpCode,
70 Overflow,
71 ContinuationNotStarted,
72 ContinuationStarted,
73 ContinuationFragment(OpCode),
74 /// A Close frame has already been sent. No further messages can be sent.
75 SendClosed,
76 /// A Close frame has already been received. The caller should stop polling the stream.
77 RecvClosed,
78 /// The underlying transport closed without a Close frame. This is an abnormal closure.
79 UnexpectedEof,
80}
81
82impl fmt::Display for ProtocolError {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 match *self {
85 Self::UnmaskedFrame => f.write_str("Received an unmasked frame from client."),
86 Self::MaskedFrame => f.write_str("Received a masked frame from server."),
87 Self::InvalidOpcode(code) => write!(f, " Encountered invalid OpCode: {code}"),
88 Self::InvalidLength(len) => write!(f, "Invalid control frame length: {len}."),
89 Self::BadOpCode => f.write_str("Bad opcode."),
90 Self::Overflow => f.write_str("A payload reached size limit."),
91 Self::ContinuationNotStarted => f.write_str("Continuation is not started."),
92 Self::ContinuationStarted => f.write_str("Received new continuation but it is already started."),
93 Self::ContinuationFragment(ref code) => write!(f, "Unknown continuation fragment with OpCode: {code}."),
94 Self::SendClosed => f.write_str("Close message has already been sent."),
95 Self::RecvClosed => f.write_str("Close message has alredy been received"),
96 Self::UnexpectedEof => f.write_str("Connection is closed prematurely without Close message"),
97 }
98 }
99}
100
101impl error::Error for ProtocolError {}
102
103impl From<OpCode> for ProtocolError {
104 fn from(e: OpCode) -> Self {
105 Self::ContinuationFragment(e)
106 }
107}
108
109/// WebSocket handshake errors
110#[derive(Debug, Eq, PartialEq)]
111pub enum HandshakeError {
112 GetMethodRequired,
113 ConnectMethodRequired,
114 NoWebsocketUpgrade,
115 NoConnectionUpgrade,
116 NoVersionHeader,
117 UnsupportedVersion,
118 BadWebsocketKey,
119}
120
121impl fmt::Display for HandshakeError {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 match *self {
124 Self::GetMethodRequired => f.write_str("Only GET method is allowed for HTTP/1.1 websocket."),
125 Self::ConnectMethodRequired => f.write_str("Only CONNECT method is allowed HTTP/2 websocket."),
126 Self::NoWebsocketUpgrade => f.write_str("Upgrade header is not set to HTTP/1.1 websocket."),
127 Self::NoConnectionUpgrade => f.write_str("Connection header is not set to HTTP/1.1 websocket."),
128 Self::NoVersionHeader => f.write_str(" WebSocket version header is not set to HTTP/1.1 websocket."),
129 Self::UnsupportedVersion => f.write_str("Unsupported WebSocket version."),
130 Self::BadWebsocketKey => f.write_str("WebSocket key is not set or wrong to HTTP/1.1 websocket."),
131 }
132 }
133}
134
135impl error::Error for HandshakeError {}