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