1use base64;
2use sha1;
3use std::convert::{From, Into};
4use std::fmt;
5
6use self::OpCode::*;
7#[derive(Debug, Eq, PartialEq, Clone, Copy)]
9pub enum OpCode {
10 Continue,
12 Text,
14 Binary,
16 Close,
18 Ping,
20 Pong,
22 Bad,
24}
25
26impl fmt::Display for OpCode {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 match *self {
29 Continue => write!(f, "CONTINUE"),
30 Text => write!(f, "TEXT"),
31 Binary => write!(f, "BINARY"),
32 Close => write!(f, "CLOSE"),
33 Ping => write!(f, "PING"),
34 Pong => write!(f, "PONG"),
35 Bad => write!(f, "BAD"),
36 }
37 }
38}
39
40impl Into<u8> for OpCode {
41 fn into(self) -> u8 {
42 match self {
43 Continue => 0,
44 Text => 1,
45 Binary => 2,
46 Close => 8,
47 Ping => 9,
48 Pong => 10,
49 Bad => {
50 log::error!("Attempted to convert invalid opcode to u8. This is a bug.");
51 8 }
53 }
54 }
55}
56
57impl From<u8> for OpCode {
58 fn from(byte: u8) -> OpCode {
59 match byte {
60 0 => Continue,
61 1 => Text,
62 2 => Binary,
63 8 => Close,
64 9 => Ping,
65 10 => Pong,
66 _ => Bad,
67 }
68 }
69}
70
71use self::CloseCode::*;
72#[derive(Debug, Eq, PartialEq, Clone, Copy)]
75pub enum CloseCode {
76 Normal,
79 Away,
82 Protocol,
85 Unsupported,
90 Abnormal,
96 Invalid,
101 Policy,
107 Size,
111 Extension,
119 Error,
123 Restart,
127 Again,
131 #[doc(hidden)]
132 Tls,
133 #[doc(hidden)]
134 Other(u16),
135}
136
137impl Into<u16> for CloseCode {
138 fn into(self) -> u16 {
139 match self {
140 Normal => 1000,
141 Away => 1001,
142 Protocol => 1002,
143 Unsupported => 1003,
144 Abnormal => 1006,
145 Invalid => 1007,
146 Policy => 1008,
147 Size => 1009,
148 Extension => 1010,
149 Error => 1011,
150 Restart => 1012,
151 Again => 1013,
152 Tls => 1015,
153 Other(code) => code,
154 }
155 }
156}
157
158impl From<u16> for CloseCode {
159 fn from(code: u16) -> CloseCode {
160 match code {
161 1000 => Normal,
162 1001 => Away,
163 1002 => Protocol,
164 1003 => Unsupported,
165 1006 => Abnormal,
166 1007 => Invalid,
167 1008 => Policy,
168 1009 => Size,
169 1010 => Extension,
170 1011 => Error,
171 1012 => Restart,
172 1013 => Again,
173 1015 => Tls,
174 _ => Other(code),
175 }
176 }
177}
178
179#[derive(Debug, Eq, PartialEq, Clone)]
180pub struct CloseReason {
182 pub code: CloseCode,
184 pub description: Option<String>,
186}
187
188impl From<CloseCode> for CloseReason {
189 fn from(code: CloseCode) -> Self {
190 CloseReason {
191 code,
192 description: None,
193 }
194 }
195}
196
197impl<T: Into<String>> From<(CloseCode, T)> for CloseReason {
198 fn from(info: (CloseCode, T)) -> Self {
199 CloseReason {
200 code: info.0,
201 description: Some(info.1.into()),
202 }
203 }
204}
205
206static WS_GUID: &str = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
207
208pub fn hash_key(key: &[u8]) -> String {
210 use sha1::Digest;
211 let mut hasher = sha1::Sha1::new();
212
213 hasher.input(key);
214 hasher.input(WS_GUID.as_bytes());
215
216 base64::encode(hasher.result().as_ref())
217}
218
219#[cfg(test)]
220mod test {
221 #![allow(unused_imports, unused_variables, dead_code)]
222 use super::*;
223
224 macro_rules! opcode_into {
225 ($from:expr => $opcode:pat) => {
226 match OpCode::from($from) {
227 e @ $opcode => (),
228 e => unreachable!("{:?}", e),
229 }
230 };
231 }
232
233 macro_rules! opcode_from {
234 ($from:expr => $opcode:pat) => {
235 let res: u8 = $from.into();
236 match res {
237 e @ $opcode => (),
238 e => unreachable!("{:?}", e),
239 }
240 };
241 }
242
243 #[test]
244 fn test_to_opcode() {
245 opcode_into!(0 => OpCode::Continue);
246 opcode_into!(1 => OpCode::Text);
247 opcode_into!(2 => OpCode::Binary);
248 opcode_into!(8 => OpCode::Close);
249 opcode_into!(9 => OpCode::Ping);
250 opcode_into!(10 => OpCode::Pong);
251 opcode_into!(99 => OpCode::Bad);
252 }
253
254 #[test]
255 fn test_from_opcode() {
256 opcode_from!(OpCode::Continue => 0);
257 opcode_from!(OpCode::Text => 1);
258 opcode_from!(OpCode::Binary => 2);
259 opcode_from!(OpCode::Close => 8);
260 opcode_from!(OpCode::Ping => 9);
261 opcode_from!(OpCode::Pong => 10);
262 }
263
264 #[test]
265 #[should_panic]
266 fn test_from_opcode_debug() {
267 opcode_from!(OpCode::Bad => 99);
268 }
269
270 #[test]
271 fn test_from_opcode_display() {
272 assert_eq!(format!("{}", OpCode::Continue), "CONTINUE");
273 assert_eq!(format!("{}", OpCode::Text), "TEXT");
274 assert_eq!(format!("{}", OpCode::Binary), "BINARY");
275 assert_eq!(format!("{}", OpCode::Close), "CLOSE");
276 assert_eq!(format!("{}", OpCode::Ping), "PING");
277 assert_eq!(format!("{}", OpCode::Pong), "PONG");
278 assert_eq!(format!("{}", OpCode::Bad), "BAD");
279 }
280
281 #[test]
282 fn test_hash_key() {
283 let hash = hash_key(b"hello actix-web");
284 assert_eq!(&hash, "cR1dlyUUJKp0s/Bel25u5TgvC3E=");
285 }
286
287 #[test]
288 fn closecode_from_u16() {
289 assert_eq!(CloseCode::from(1000u16), CloseCode::Normal);
290 assert_eq!(CloseCode::from(1001u16), CloseCode::Away);
291 assert_eq!(CloseCode::from(1002u16), CloseCode::Protocol);
292 assert_eq!(CloseCode::from(1003u16), CloseCode::Unsupported);
293 assert_eq!(CloseCode::from(1006u16), CloseCode::Abnormal);
294 assert_eq!(CloseCode::from(1007u16), CloseCode::Invalid);
295 assert_eq!(CloseCode::from(1008u16), CloseCode::Policy);
296 assert_eq!(CloseCode::from(1009u16), CloseCode::Size);
297 assert_eq!(CloseCode::from(1010u16), CloseCode::Extension);
298 assert_eq!(CloseCode::from(1011u16), CloseCode::Error);
299 assert_eq!(CloseCode::from(1012u16), CloseCode::Restart);
300 assert_eq!(CloseCode::from(1013u16), CloseCode::Again);
301 assert_eq!(CloseCode::from(1015u16), CloseCode::Tls);
302 assert_eq!(CloseCode::from(2000u16), CloseCode::Other(2000));
303 }
304
305 #[test]
306 fn closecode_into_u16() {
307 assert_eq!(1000u16, Into::<u16>::into(CloseCode::Normal));
308 assert_eq!(1001u16, Into::<u16>::into(CloseCode::Away));
309 assert_eq!(1002u16, Into::<u16>::into(CloseCode::Protocol));
310 assert_eq!(1003u16, Into::<u16>::into(CloseCode::Unsupported));
311 assert_eq!(1006u16, Into::<u16>::into(CloseCode::Abnormal));
312 assert_eq!(1007u16, Into::<u16>::into(CloseCode::Invalid));
313 assert_eq!(1008u16, Into::<u16>::into(CloseCode::Policy));
314 assert_eq!(1009u16, Into::<u16>::into(CloseCode::Size));
315 assert_eq!(1010u16, Into::<u16>::into(CloseCode::Extension));
316 assert_eq!(1011u16, Into::<u16>::into(CloseCode::Error));
317 assert_eq!(1012u16, Into::<u16>::into(CloseCode::Restart));
318 assert_eq!(1013u16, Into::<u16>::into(CloseCode::Again));
319 assert_eq!(1015u16, Into::<u16>::into(CloseCode::Tls));
320 assert_eq!(2000u16, Into::<u16>::into(CloseCode::Other(2000)));
321 }
322}