/src/tungstenite-rs/src/protocol/frame/coding.rs
Line | Count | Source |
1 | | //! Various codes defined in RFC 6455. |
2 | | |
3 | | use std::{ |
4 | | convert::{From, Into}, |
5 | | fmt, |
6 | | }; |
7 | | |
8 | | /// WebSocket message opcode as in RFC 6455. |
9 | | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
10 | | pub enum OpCode { |
11 | | /// Data (text or binary). |
12 | | Data(Data), |
13 | | /// Control message (close, ping, pong). |
14 | | Control(Control), |
15 | | } |
16 | | |
17 | | /// Data opcodes as in RFC 6455 |
18 | | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
19 | | pub enum Data { |
20 | | /// 0x0 denotes a continuation frame |
21 | | Continue, |
22 | | /// 0x1 denotes a text frame |
23 | | Text, |
24 | | /// 0x2 denotes a binary frame |
25 | | Binary, |
26 | | /// 0x3-7 are reserved for further non-control frames |
27 | | Reserved(u8), |
28 | | } |
29 | | |
30 | | /// Control opcodes as in RFC 6455 |
31 | | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
32 | | pub enum Control { |
33 | | /// 0x8 denotes a connection close |
34 | | Close, |
35 | | /// 0x9 denotes a ping |
36 | | Ping, |
37 | | /// 0xa denotes a pong |
38 | | Pong, |
39 | | /// 0xb-f are reserved for further control frames |
40 | | Reserved(u8), |
41 | | } |
42 | | |
43 | | impl fmt::Display for Data { |
44 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
45 | 0 | match *self { |
46 | 0 | Data::Continue => write!(f, "CONTINUE"), |
47 | 0 | Data::Text => write!(f, "TEXT"), |
48 | 0 | Data::Binary => write!(f, "BINARY"), |
49 | 0 | Data::Reserved(x) => write!(f, "RESERVED_DATA_{x}"), |
50 | | } |
51 | 0 | } |
52 | | } |
53 | | |
54 | | impl fmt::Display for Control { |
55 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
56 | 0 | match *self { |
57 | 0 | Control::Close => write!(f, "CLOSE"), |
58 | 0 | Control::Ping => write!(f, "PING"), |
59 | 0 | Control::Pong => write!(f, "PONG"), |
60 | 0 | Control::Reserved(x) => write!(f, "RESERVED_CONTROL_{x}"), |
61 | | } |
62 | 0 | } |
63 | | } |
64 | | |
65 | | impl fmt::Display for OpCode { |
66 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
67 | 0 | match *self { |
68 | 0 | OpCode::Data(d) => d.fmt(f), |
69 | 0 | OpCode::Control(c) => c.fmt(f), |
70 | | } |
71 | 0 | } |
72 | | } |
73 | | |
74 | | impl From<OpCode> for u8 { |
75 | 0 | fn from(code: OpCode) -> Self { |
76 | | use self::{ |
77 | | Control::{Close, Ping, Pong}, |
78 | | Data::{Binary, Continue, Text}, |
79 | | OpCode::*, |
80 | | }; |
81 | 0 | match code { |
82 | 0 | Data(Continue) => 0, |
83 | 0 | Data(Text) => 1, |
84 | 0 | Data(Binary) => 2, |
85 | 0 | Data(self::Data::Reserved(i)) => i, |
86 | | |
87 | 0 | Control(Close) => 8, |
88 | 0 | Control(Ping) => 9, |
89 | 0 | Control(Pong) => 10, |
90 | 0 | Control(self::Control::Reserved(i)) => i, |
91 | | } |
92 | 0 | } |
93 | | } |
94 | | |
95 | | impl From<u8> for OpCode { |
96 | 8.71M | fn from(byte: u8) -> OpCode { |
97 | | use self::{ |
98 | | Control::{Close, Ping, Pong}, |
99 | | Data::{Binary, Continue, Text}, |
100 | | OpCode::*, |
101 | | }; |
102 | 8.71M | match byte { |
103 | 8.70M | 0 => Data(Continue), |
104 | 1.73k | 1 => Data(Text), |
105 | 710 | 2 => Data(Binary), |
106 | 152 | i @ 3..=7 => Data(self::Data::Reserved(i)), |
107 | 403 | 8 => Control(Close), |
108 | 127 | 9 => Control(Ping), |
109 | 71 | 10 => Control(Pong), |
110 | 110 | i @ 11..=15 => Control(self::Control::Reserved(i)), |
111 | 0 | _ => panic!("Bug: OpCode out of range"), |
112 | | } |
113 | 8.71M | } |
114 | | } |
115 | | |
116 | | use self::CloseCode::*; |
117 | | /// Status code used to indicate why an endpoint is closing the WebSocket connection. |
118 | | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
119 | | pub enum CloseCode { |
120 | | /// Indicates a normal closure, meaning that the purpose for |
121 | | /// which the connection was established has been fulfilled. |
122 | | Normal, |
123 | | /// Indicates that an endpoint is "going away", such as a server |
124 | | /// going down or a browser having navigated away from a page. |
125 | | Away, |
126 | | /// Indicates that an endpoint is terminating the connection due |
127 | | /// to a protocol error. |
128 | | Protocol, |
129 | | /// Indicates that an endpoint is terminating the connection |
130 | | /// because it has received a type of data it cannot accept (e.g., an |
131 | | /// endpoint that understands only text data MAY send this if it |
132 | | /// receives a binary message). |
133 | | Unsupported, |
134 | | /// Indicates that no status code was included in a closing frame. This |
135 | | /// close code makes it possible to use a single method, `on_close` to |
136 | | /// handle even cases where no close code was provided. |
137 | | Status, |
138 | | /// Indicates an abnormal closure. If the abnormal closure was due to an |
139 | | /// error, this close code will not be used. Instead, the `on_error` method |
140 | | /// of the handler will be called with the error. However, if the connection |
141 | | /// is simply dropped, without an error, this close code will be sent to the |
142 | | /// handler. |
143 | | Abnormal, |
144 | | /// Indicates that an endpoint is terminating the connection |
145 | | /// because it has received data within a message that was not |
146 | | /// consistent with the type of the message (e.g., non-UTF-8 \[RFC3629\] |
147 | | /// data within a text message). |
148 | | Invalid, |
149 | | /// Indicates that an endpoint is terminating the connection |
150 | | /// because it has received a message that violates its policy. This |
151 | | /// is a generic status code that can be returned when there is no |
152 | | /// other more suitable status code (e.g., Unsupported or Size) or if there |
153 | | /// is a need to hide specific details about the policy. |
154 | | Policy, |
155 | | /// Indicates that an endpoint is terminating the connection |
156 | | /// because it has received a message that is too big for it to |
157 | | /// process. |
158 | | Size, |
159 | | /// Indicates that an endpoint (client) is terminating the |
160 | | /// connection because it has expected the server to negotiate one or |
161 | | /// more extension, but the server didn't return them in the response |
162 | | /// message of the WebSocket handshake. The list of extensions that |
163 | | /// are needed should be given as the reason for closing. |
164 | | /// Note that this status code is not used by the server, because it |
165 | | /// can fail the WebSocket handshake instead. |
166 | | Extension, |
167 | | /// Indicates that a server is terminating the connection because |
168 | | /// it encountered an unexpected condition that prevented it from |
169 | | /// fulfilling the request. |
170 | | Error, |
171 | | /// Indicates that the server is restarting. A client may choose to reconnect, |
172 | | /// and if it does, it should use a randomized delay of 5-30 seconds between attempts. |
173 | | Restart, |
174 | | /// Indicates that the server is overloaded and the client should either connect |
175 | | /// to a different IP (when multiple targets exist), or reconnect to the same IP |
176 | | /// when a user has performed an action. |
177 | | Again, |
178 | | #[doc(hidden)] |
179 | | Tls, |
180 | | #[doc(hidden)] |
181 | | Reserved(u16), |
182 | | #[doc(hidden)] |
183 | | Iana(u16), |
184 | | #[doc(hidden)] |
185 | | Library(u16), |
186 | | #[doc(hidden)] |
187 | | Bad(u16), |
188 | | } |
189 | | |
190 | | impl CloseCode { |
191 | | /// Check if this CloseCode is allowed. |
192 | 256 | pub fn is_allowed(self) -> bool { |
193 | 256 | !matches!(self, Bad(_) | Reserved(_) | Status | Abnormal | Tls) |
194 | 256 | } |
195 | | } |
196 | | |
197 | | impl fmt::Display for CloseCode { |
198 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
199 | 0 | let code: u16 = self.into(); |
200 | 0 | write!(f, "{code}") |
201 | 0 | } |
202 | | } |
203 | | |
204 | | impl From<CloseCode> for u16 { |
205 | 256 | fn from(code: CloseCode) -> u16 { |
206 | 256 | match code { |
207 | 2 | Normal => 1000, |
208 | 2 | Away => 1001, |
209 | 159 | Protocol => 1002, |
210 | 3 | Unsupported => 1003, |
211 | 0 | Status => 1005, |
212 | 0 | Abnormal => 1006, |
213 | 4 | Invalid => 1007, |
214 | 6 | Policy => 1008, |
215 | 4 | Size => 1009, |
216 | 3 | Extension => 1010, |
217 | 2 | Error => 1011, |
218 | 2 | Restart => 1012, |
219 | 2 | Again => 1013, |
220 | 0 | Tls => 1015, |
221 | 0 | Reserved(code) => code, |
222 | 38 | Iana(code) => code, |
223 | 29 | Library(code) => code, |
224 | 0 | Bad(code) => code, |
225 | | } |
226 | 256 | } |
227 | | } |
228 | | |
229 | | impl<'t> From<&'t CloseCode> for u16 { |
230 | 0 | fn from(code: &'t CloseCode) -> u16 { |
231 | 0 | (*code).into() |
232 | 0 | } |
233 | | } |
234 | | |
235 | | impl From<u16> for CloseCode { |
236 | 288 | fn from(code: u16) -> CloseCode { |
237 | 288 | match code { |
238 | 2 | 1000 => Normal, |
239 | 2 | 1001 => Away, |
240 | 2 | 1002 => Protocol, |
241 | 3 | 1003 => Unsupported, |
242 | 4 | 1005 => Status, |
243 | 2 | 1006 => Abnormal, |
244 | 5 | 1007 => Invalid, |
245 | 6 | 1008 => Policy, |
246 | 4 | 1009 => Size, |
247 | 3 | 1010 => Extension, |
248 | 2 | 1011 => Error, |
249 | 2 | 1012 => Restart, |
250 | 2 | 1013 => Again, |
251 | 3 | 1015 => Tls, |
252 | 240 | 1..=999 => Bad(code), |
253 | 200 | 1016..=2999 => Reserved(code), |
254 | 155 | 3000..=3999 => Iana(code), |
255 | 117 | 4000..=4999 => Library(code), |
256 | 95 | _ => Bad(code), |
257 | | } |
258 | 288 | } |
259 | | } |
260 | | |
261 | | #[cfg(test)] |
262 | | mod tests { |
263 | | use super::*; |
264 | | |
265 | | #[test] |
266 | | fn opcode_from_u8() { |
267 | | let byte = 2u8; |
268 | | assert_eq!(OpCode::from(byte), OpCode::Data(Data::Binary)); |
269 | | } |
270 | | |
271 | | #[test] |
272 | | fn opcode_into_u8() { |
273 | | let text = OpCode::Data(Data::Text); |
274 | | let byte: u8 = text.into(); |
275 | | assert_eq!(byte, 1u8); |
276 | | } |
277 | | |
278 | | #[test] |
279 | | fn closecode_from_u16() { |
280 | | let byte = 1008u16; |
281 | | assert_eq!(CloseCode::from(byte), CloseCode::Policy); |
282 | | } |
283 | | |
284 | | #[test] |
285 | | fn closecode_into_u16() { |
286 | | let text = CloseCode::Away; |
287 | | let byte: u16 = text.into(); |
288 | | assert_eq!(byte, 1001u16); |
289 | | assert_eq!(u16::from(text), 1001u16); |
290 | | } |
291 | | } |