websocket_simple/protocol.rs
1use std::fmt;
2use std::convert::{Into, From};
3
4use self::OpCode::*;
5/// Operation codes as part of rfc6455.
6#[derive(Debug, Eq, PartialEq, Clone, Copy)]
7pub enum OpCode {
8 /// Indicates a continuation frame of a fragmented message.
9 Continue,
10 /// Indicates a text data frame.
11 Text,
12 /// Indicates a binary data frame.
13 Binary,
14 /// Indicates a close control frame.
15 Close,
16 /// Indicates a ping control frame.
17 Ping,
18 /// Indicates a pong control frame.
19 Pong,
20 /// Indicates an invalid opcode was received.
21 Bad,
22}
23
24impl OpCode {
25
26 /// Test whether the opcode indicates a control frame.
27 pub fn is_control(&self) -> bool {
28 match *self {
29 Text | Binary | Continue => false,
30 _ => true,
31 }
32 }
33
34}
35
36impl fmt::Display for OpCode {
37 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38 match *self {
39 Continue => write!(f, "CONTINUE"),
40 Text => write!(f, "TEXT"),
41 Binary => write!(f, "BINARY"),
42 Close => write!(f, "CLOSE"),
43 Ping => write!(f, "PING"),
44 Pong => write!(f, "PONG"),
45 Bad => write!(f, "BAD"),
46 }
47 }
48}
49
50impl Into<u8> for OpCode {
51
52 fn into(self) -> u8 {
53 match self {
54 Continue => 0,
55 Text => 1,
56 Binary => 2,
57 Close => 8,
58 Ping => 9,
59 Pong => 10,
60 Bad => {
61 debug_assert!(false, "Attempted to convert invalid opcode to u8. This is a bug.");
62 8 // if this somehow happens, a close frame will help us tear down quickly
63 }
64 }
65 }
66}
67
68impl From<u8> for OpCode {
69
70 fn from(byte: u8) -> OpCode {
71 match byte {
72 0 => Continue,
73 1 => Text,
74 2 => Binary,
75 8 => Close,
76 9 => Ping,
77 10 => Pong,
78 _ => Bad
79 }
80 }
81}
82
83use self::CloseCode::*;
84/// Status code used to indicate why an endpoint is closing the WebSocket connection.
85#[derive(Debug, Eq, PartialEq, Clone, Copy)]
86pub enum CloseCode {
87 /// Indicates a normal closure, meaning that the purpose for
88 /// which the connection was established has been fulfilled.
89 Normal,
90 /// Indicates that an endpoint is "going away", such as a server
91 /// going down or a browser having navigated away from a page.
92 Away,
93 /// Indicates that an endpoint is terminating the connection due
94 /// to a protocol error.
95 Protocol,
96 /// Indicates that an endpoint is terminating the connection
97 /// because it has received a type of data it cannot accept (e.g., an
98 /// endpoint that understands only text data MAY send this if it
99 /// receives a binary message).
100 Unsupported,
101 /// Indicates that no status code was included in a closing frame. This
102 /// close code makes it possible to use a single method, `on_close` to
103 /// handle even cases where no close code was provided.
104 Status,
105 /// Indicates an abnormal closure. If the abnormal closure was due to an
106 /// error, this close code will not be used. Instead, the `on_error` method
107 /// of the handler will be called with the error. However, if the connection
108 /// is simply dropped, without an error, this close code will be sent to the
109 /// handler.
110 Abnormal,
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 /// Indicates that an endpoint is terminating the connection
117 /// because it has received a message that violates its policy. This
118 /// is a generic status code that can be returned when there is no
119 /// other more suitable status code (e.g., Unsupported or Size) or if there
120 /// is a need to hide specific details about the policy.
121 Policy,
122 /// Indicates that an endpoint is terminating the connection
123 /// because it has received a message that is too big for it to
124 /// process.
125 Size,
126 /// Indicates that an endpoint (client) is terminating the
127 /// connection because it has expected the server to negotiate one or
128 /// more extension, but the server didn't return them in the response
129 /// message of the WebSocket handshake. The list of extensions that
130 /// are needed should be given as the reason for closing.
131 /// Note that this status code is not used by the server, because it
132 /// can fail the WebSocket handshake instead.
133 Extension,
134 /// Indicates that a server is terminating the connection because
135 /// it encountered an unexpected condition that prevented it from
136 /// fulfilling the request.
137 Error,
138 /// Indicates that the server is restarting. A client may choose to reconnect,
139 /// and if it does, it should use a randomized delay of 5-30 seconds between attempts.
140 Restart,
141 /// Indicates that the server is overloaded and the client should either connect
142 /// to a different IP (when multiple targets exist), or reconnect to the same IP
143 /// when a user has performed an action.
144 Again,
145 #[doc(hidden)]
146 Tls,
147 #[doc(hidden)]
148 Empty,
149 #[doc(hidden)]
150 Other(u16),
151}
152
153impl Into<u16> for CloseCode {
154
155 fn into(self) -> u16 {
156 match self {
157 Normal => 1000,
158 Away => 1001,
159 Protocol => 1002,
160 Unsupported => 1003,
161 Status => 1005,
162 Abnormal => 1006,
163 Invalid => 1007,
164 Policy => 1008,
165 Size => 1009,
166 Extension => 1010,
167 Error => 1011,
168 Restart => 1012,
169 Again => 1013,
170 Tls => 1015,
171 Empty => 0,
172 Other(code) => code,
173 }
174 }
175}
176
177impl From<u16> for CloseCode {
178
179 fn from(code: u16) -> CloseCode {
180 match code {
181 1000 => Normal,
182 1001 => Away,
183 1002 => Protocol,
184 1003 => Unsupported,
185 1005 => Status,
186 1006 => Abnormal,
187 1007 => Invalid,
188 1008 => Policy,
189 1009 => Size,
190 1010 => Extension,
191 1011 => Error,
192 1012 => Restart,
193 1013 => Again,
194 1015 => Tls,
195 0 => Empty,
196 _ => Other(code),
197 }
198 }
199}
200
201
202mod test {
203 #![allow(unused_imports, unused_variables, dead_code)]
204 use super::*;
205
206 #[test]
207 fn opcode_from_u8() {
208 let byte = 2u8;
209 assert_eq!(OpCode::from(byte), OpCode::Binary);
210 }
211
212 #[test]
213 fn opcode_into_u8() {
214 let text = OpCode::Text;
215 let byte: u8 = text.into();
216 assert_eq!(byte, 1u8);
217 }
218
219 #[test]
220 fn closecode_from_u16() {
221 let byte = 1008u16;
222 assert_eq!(CloseCode::from(byte), CloseCode::Policy);
223 }
224
225 #[test]
226 fn closecode_into_u16() {
227 let text = CloseCode::Away;
228 let byte: u16 = text.into();
229 assert_eq!(byte, 1001u16);
230 }
231}