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