1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use crate::{Error, Message};
pub struct Frame {
inner_op_code: u8,
masking_key: Option<u32>,
pub(crate) message: Option<Message>
}
impl Frame {
pub const FIN_RSV: u8 = 0x80;
pub const OP_CODE_CONTINUATION: u8 = 0x00;
pub const OP_CODE_TEXT: u8 = 0x01;
pub const OP_CODE_BINARY: u8 = 0x02;
pub const OP_CODE_CLOSE: u8 = 0x08;
pub const OP_CODE_PING: u8 = 0x09;
pub const OP_CODE_PONG: u8 = 0x0A;
pub fn op_code(&self) -> u8 {
self.inner_op_code
}
pub fn parse<A: AsRef<[u8]>>(content: A) -> Result<Frame, Error> {
let candidate = content.as_ref();
if candidate.len() < 2 {
return Err(Error::Incomplete)
}
if ((candidate[0] ^ !Frame::FIN_RSV) >> 4) == 0x08 {
return Err(Error::Parse(format!("Malformed message")))
}
let min_length = candidate[1] & (!0x80);
let (length, mut offset) = if min_length == 126 {
panic!("Too long!");
} else if min_length == 127 {
panic!("Way too long!");
} else {
(min_length as usize, 2usize)
};
let masking_key = if 0x80 == (candidate[1] & 0x80) {
offset += 4;
Some([candidate[offset - 4], candidate[offset - 3], candidate[offset - 2], candidate[offset - 1]])
} else {
None
};
let inner_op_code = (candidate[0] << 4) >> 4;
let mut payload = candidate.get(offset..offset+length).ok_or_else(|| Error::Incomplete)?.to_vec();
if let Some(masking_key) = &masking_key {
payload = payload.into_iter().enumerate().map(|(idx, v)| {
let j = idx % 4;
v ^ masking_key[j]
}).collect();
}
let message = match inner_op_code {
Frame::OP_CODE_TEXT => Some(Message::Text(String::from_utf8(payload).map_err(|e| Error::Parse(format!("{}", e)))?)),
Frame::OP_CODE_CLOSE => None,
Frame::OP_CODE_PING => None,
Frame::OP_CODE_PONG => None,
_ => panic!("Not supported")
};
Ok(Frame {
inner_op_code,
masking_key: masking_key.map(u32::from_be_bytes),
message
})
}
pub fn text<A: Into<String>>(text: A) -> Frame {
let payload = text.into();
let message = Some(Message::Text(payload));
Frame {
inner_op_code: Frame::OP_CODE_TEXT,
masking_key: None,
message
}
}
pub fn bytes(self) -> Vec<u8> {
let mut content = vec![Frame::FIN_RSV ^ self.inner_op_code];
let mut payload = self.message.map(|m| m.to_bytes());
let payload_length = payload.iter().map(|m| m.len()).next().unwrap_or(0);
if payload_length < 126 {
content.push(payload_length as u8 | if self.masking_key.is_some() {0x80} else {0x00});
} else {
panic!("Oh noes!");
}
if let Some(masking_key) = &self.masking_key {
let masking_bytes = masking_key.to_be_bytes();
payload = payload.map(|b| b.into_iter().enumerate().map(|(idx, v)| {
let j = idx % 4;
v ^ masking_bytes[j]
}).collect());
content.extend(masking_bytes);
}
if let Some(payload) = payload {
content.extend(payload);
}
content
}
pub fn into_message(self) -> Option<Message> {
self.message
}
}