reqwest_websocket/
protocol.rs

1use bytes::Bytes;
2
3/// A `WebSocket` message, which can be a text string or binary data.
4#[derive(Clone, Debug)]
5pub enum Message {
6    /// A text `WebSocket` message.
7    // note: we can't use `tungstenite::Utf8String` here, since we don't have tungstenite on wasm.
8    Text(String),
9
10    /// A binary `WebSocket` message.
11    Binary(Bytes),
12
13    /// A ping message with the specified payload.
14    ///
15    /// The payload here must have a length less than 125 bytes.
16    ///
17    /// # WASM
18    ///
19    /// This variant is ignored for WASM targets.
20    #[cfg_attr(
21        target_arch = "wasm32",
22        deprecated(note = "This variant is ignored for WASM targets")
23    )]
24    Ping(Bytes),
25
26    /// A pong message with the specified payload.
27    ///
28    /// The payload here must have a length less than 125 bytes.
29    ///
30    /// # WASM
31    ///
32    /// This variant is ignored for WASM targets.
33    #[cfg_attr(
34        target_arch = "wasm32",
35        deprecated(note = "This variant is ignored for WASM targets")
36    )]
37    Pong(Bytes),
38
39    /// A close message.
40    ///
41    /// Sending this will not close the connection. Use [`WebSocket::close`] for this.
42    /// Though the remote peer will likely close the connection after receiving this.
43    ///
44    /// [`WebSocket::close`]: crate::WebSocket::close
45    Close { code: CloseCode, reason: String },
46}
47
48impl From<String> for Message {
49    #[inline]
50    fn from(value: String) -> Self {
51        Self::Text(value)
52    }
53}
54
55impl From<&str> for Message {
56    #[inline]
57    fn from(value: &str) -> Self {
58        Self::from(value.to_owned())
59    }
60}
61
62impl From<Bytes> for Message {
63    #[inline]
64    fn from(value: Bytes) -> Self {
65        Self::Binary(value)
66    }
67}
68
69impl From<Vec<u8>> for Message {
70    #[inline]
71    fn from(value: Vec<u8>) -> Self {
72        Self::from(Bytes::from(value))
73    }
74}
75
76impl From<&[u8]> for Message {
77    #[inline]
78    fn from(value: &[u8]) -> Self {
79        Self::from(Bytes::copy_from_slice(value))
80    }
81}
82
83/// Status code used to indicate why an endpoint is closing the `WebSocket`
84/// connection.[1]
85///
86/// [1]: https://datatracker.ietf.org/doc/html/rfc6455
87#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
88#[non_exhaustive]
89pub enum CloseCode {
90    /// Indicates a normal closure, meaning that the purpose for
91    /// which the connection was established has been fulfilled.
92    #[default]
93    Normal,
94
95    /// Indicates that an endpoint is "going away", such as a server
96    /// going down or a browser having navigated away from a page.
97    Away,
98
99    /// Indicates that an endpoint is terminating the connection due
100    /// to a protocol error.
101    Protocol,
102
103    /// Indicates that an endpoint is terminating the connection
104    /// because it has received a type of data it cannot accept (e.g., an
105    /// endpoint that understands only text data MAY send this if it
106    /// receives a binary message).
107    Unsupported,
108
109    /// Indicates that no status code was included in a closing frame. This
110    /// close code makes it possible to use a single method, `on_close` to
111    /// handle even cases where no close code was provided.
112    Status,
113
114    /// Indicates an abnormal closure. If the abnormal closure was due to an
115    /// error, this close code will not be used. Instead, the `on_error` method
116    /// of the handler will be called with the error. However, if the connection
117    /// is simply dropped, without an error, this close code will be sent to the
118    /// handler.
119    Abnormal,
120
121    /// Indicates that an endpoint is terminating the connection
122    /// because it has received data within a message that was not
123    /// consistent with the type of the message (e.g., non-UTF-8 \[RFC3629\]
124    /// data within a text message).
125    Invalid,
126
127    /// Indicates that an endpoint is terminating the connection
128    /// because it has received a message that violates its policy.  This
129    /// is a generic status code that can be returned when there is no
130    /// other more suitable status code (e.g., Unsupported or Size) or if there
131    /// is a need to hide specific details about the policy.
132    Policy,
133
134    /// Indicates that an endpoint is terminating the connection
135    /// because it has received a message that is too big for it to
136    /// process.
137    Size,
138
139    /// Indicates that an endpoint (client) is terminating the
140    /// connection because it has expected the server to negotiate one or
141    /// more extension, but the server didn't return them in the response
142    /// message of the `WebSocket` handshake.  The list of extensions that
143    /// are needed should be given as the reason for closing.
144    /// Note that this status code is not used by the server, because it
145    /// can fail the `WebSocket` handshake instead.
146    Extension,
147
148    /// Indicates that a server is terminating the connection because
149    /// it encountered an unexpected condition that prevented it from
150    /// fulfilling the request.
151    Error,
152
153    /// Indicates that the server is restarting. A client may choose to
154    /// reconnect, and if it does, it should use a randomized delay of 5-30
155    /// seconds between attempts.
156    Restart,
157
158    /// Indicates that the server is overloaded and the client should either
159    /// connect to a different IP (when multiple targets exist), or
160    /// reconnect to the same IP when a user has performed an action.
161    Again,
162
163    /// Indicates that the connection was closed due to a failure to perform a
164    /// TLS handshake (e.g., the server certificate can't be verified). This
165    /// is a reserved value and MUST NOT be set as a status code in a Close
166    /// control frame by an endpoint.
167    Tls,
168
169    /// Reserved status codes.
170    Reserved(u16),
171
172    /// Reserved for use by libraries, frameworks, and applications. These
173    /// status codes are registered directly with IANA. The interpretation of
174    /// these codes is undefined by the `WebSocket` protocol.
175    Iana(u16),
176
177    /// Reserved for private use. These can't be registered and can be used by
178    /// prior agreements between `WebSocket` applications. The interpretation of
179    /// these codes is undefined by the `WebSocket` protocol.
180    Library(u16),
181
182    /// Unused / invalid status codes.
183    Bad(u16),
184}
185
186impl CloseCode {
187    /// Check if this `CloseCode` is allowed.
188    #[must_use]
189    pub const fn is_allowed(self) -> bool {
190        !matches!(
191            self,
192            Self::Bad(_) | Self::Reserved(_) | Self::Status | Self::Abnormal | Self::Tls
193        )
194    }
195}
196
197impl std::fmt::Display for CloseCode {
198    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
199        let code: u16 = (*self).into();
200        write!(f, "{code}")
201    }
202}
203
204impl From<CloseCode> for u16 {
205    fn from(code: CloseCode) -> Self {
206        match code {
207            CloseCode::Normal => 1000,
208            CloseCode::Away => 1001,
209            CloseCode::Protocol => 1002,
210            CloseCode::Unsupported => 1003,
211            CloseCode::Status => 1005,
212            CloseCode::Abnormal => 1006,
213            CloseCode::Invalid => 1007,
214            CloseCode::Policy => 1008,
215            CloseCode::Size => 1009,
216            CloseCode::Extension => 1010,
217            CloseCode::Error => 1011,
218            CloseCode::Restart => 1012,
219            CloseCode::Again => 1013,
220            CloseCode::Tls => 1015,
221            CloseCode::Reserved(code)
222            | CloseCode::Iana(code)
223            | CloseCode::Library(code)
224            | CloseCode::Bad(code) => code,
225        }
226    }
227}
228
229impl From<u16> for CloseCode {
230    fn from(code: u16) -> Self {
231        match code {
232            1000 => Self::Normal,
233            1001 => Self::Away,
234            1002 => Self::Protocol,
235            1003 => Self::Unsupported,
236            1005 => Self::Status,
237            1006 => Self::Abnormal,
238            1007 => Self::Invalid,
239            1008 => Self::Policy,
240            1009 => Self::Size,
241            1010 => Self::Extension,
242            1011 => Self::Error,
243            1012 => Self::Restart,
244            1013 => Self::Again,
245            1015 => Self::Tls,
246            1016..=2999 => Self::Reserved(code),
247            3000..=3999 => Self::Iana(code),
248            4000..=4999 => Self::Library(code),
249            _ => Self::Bad(code),
250        }
251    }
252}