1use std::convert::TryInto;
91
92use bytes::{ BytesMut, Buf, BufMut };
93use tokio_util::codec::{ Decoder, Encoder };
94
95use crate::{
96 Message,
97 Opcode,
98 WebsocketError,
99 WebsocketResult,
100};
101
102#[derive(Debug, Default)]
103pub struct WebsocketCodec {
104 fin: bool,
105 opcode: Opcode,
106 payload: BytesMut,
107}
108
109impl WebsocketCodec {
110 #[inline(always)]
111 fn next_frame(&mut self, buf: &mut BytesMut) -> Option<()> {
112 if buf.len() < 6 {
113 return None
114 }
115
116 self.fin = (0x80 & buf[0]) >> 7 != 0;
117
118 self._set_opcode(0x0F & buf[0]);
119
120 if self.opcode == Opcode::Text {
121 let (payload_len, payload_idx, mask_key) = self._payload_meta(buf);
122
123 if buf[payload_idx..].len() < payload_len {
124 return None
125 }
126
127 self._unmask(buf, payload_len, payload_idx, mask_key);
128
129 self.payload.extend_from_slice(&buf[payload_idx..payload_idx + payload_len]);
130 buf.advance(payload_idx + payload_len);
131
132 return Some(())
133 }
134
135 if
136 self.opcode == Opcode::Ping
137 || self.opcode == Opcode::Pong
138 || self.opcode == Opcode::Close
139 {
140 buf.advance(buf.len());
141 return Some(())
142 }
143
144 unimplemented!()
145 }
146
147 #[inline(always)]
148 fn _unmask(&mut self, buf: &mut BytesMut, len: usize, idx: usize, key: [u8; 4]) {
149 if (0x80 & buf[1]) >> 7 != 0 {
150 for i in idx..(idx + len) {
151 buf[i] ^= key[(i - idx) % 4];
152 }
153 }
154 }
155
156 #[inline(always)]
157 fn _payload_meta(&self, buf: &BytesMut) -> (usize, usize, [u8; 4]) {
158 let len = (0x7F & buf[1]) as usize;
159
160 if len == 127 {
161 return (
162 usize::from_be_bytes(buf[2..10].try_into().unwrap()),
163 14,
164 buf[10..14].try_into().unwrap()
165 )
166 }
167
168 if len == 126 {
169 return (
170 u16::from_be_bytes(buf[2..4].try_into().unwrap()) as usize,
171 8,
172 buf[4..8].try_into().unwrap()
173 )
174 }
175
176 (len, 6, buf[2..6].try_into().unwrap())
177 }
178
179 #[inline(always)]
180 fn _set_opcode(&mut self, opcode: u8) {
181 if opcode == 1 { self.opcode = Opcode::Text; }
182 else if opcode == 0x9 { self.opcode = Opcode::Ping; }
183 else if opcode == 0xA { self.opcode = Opcode::Pong; }
184 else if opcode == 0x8 { self.opcode = Opcode::Close; }
185 else { self.opcode = Opcode::Unknown; }
186 }
187}
188
189impl Decoder for WebsocketCodec {
190 type Item = Message;
191 type Error = WebsocketError;
192
193 fn decode(&mut self, buf: &mut BytesMut) -> WebsocketResult<Option<Self::Item>> {
194 while self.next_frame(buf).is_some() {
195 if self.fin && (
196 self.opcode == Opcode::Text
197 || self.opcode == Opcode::Ping
198 || self.opcode == Opcode::Pong
199 || self.opcode == Opcode::Close
200 ) {
201 return Ok(Some(Message {
202 opcode: self.opcode,
203 payload: self.payload.to_bytes(),
204 }))
205 }
206 }
207
208 Ok(None)
209 }
210}
211
212impl Encoder<Message> for WebsocketCodec {
213 type Error = WebsocketError;
214
215 fn encode(&mut self, msg: Message, dst: &mut BytesMut) -> WebsocketResult<()> {
216 if msg.opcode == Opcode::Pong {
217 dst.extend_from_slice(&[138, 0]);
220 }
221
222 if msg.opcode == Opcode::Text {
223 dst.put_u8(0x81);
224
225 if msg.payload.len() <= 125 {
226 dst.put_u8(msg.payload.len() as u8);
227 } else if msg.payload.len() == 126 {
228 dst.put_u8(126);
229 dst.put_u16(msg.payload.len() as u16);
230 } else {
231 dst.put_u8(127);
232 dst.put_u64(msg.payload.len() as u64);
233 }
234
235 dst.put_slice(&msg.payload[..]);
236 }
237
238 Ok(())
239 }
240}
241
242#[cfg(test)]
243mod tests {
244 extern crate test;
245
246 use super::*;
247 use bytes::BytesMut;
248 use std::str;
249 use test::Bencher;
250
251 macro_rules! frame {
252 ($buf:expr, $payload:expr, $opcode:expr) => {
253 let mut buf: BytesMut = $buf.as_bytes()
254 .chunks(2)
255 .map(|s| u8::from_str_radix(unsafe { str::from_utf8_unchecked(s) }, 16).unwrap())
256 .collect();
257
258 let mut wsc = WebsocketCodec::default();
259
260 if let Some(_) = wsc.next_frame(&mut buf) {
261 let payload = unsafe { str::from_utf8_unchecked(&wsc.payload) };
262 assert!(payload == $payload);
263 assert!(wsc.opcode == $opcode);
264 } else {
265 assert!(false, "failed to extract frame from '{:x}'")
266 }
267 }
268 }
269
270 #[test]
271 fn text_frame_with_no_payload() {
272 frame!("8180e0350bbc", "", Opcode::Text);
273 }
274
275 #[test]
276 fn text_frame_with_payload_len_eq_1() {
277 frame!("8181f3dba99092", "a", Opcode::Text);
278 }
279
280 #[test]
281 fn text_frame_with_hello_world_payload() {
282 frame!("818bb013fc40d876902cdf338b2fc27f98", "hello world", Opcode::Text);
283 }
284
285 #[test]
286 fn text_frame_payload_125() {
287 frame!(
288 "81fd16f9d90b5795b52b6291b87f369eb562628dbc7965d9b0783697b67f369eb66772d99f6a7f8bf96265d9bf646395f52b7797bd2b7096ac673690aa2b7098b0792cd99164609cab2b6291ab64639eb12b6291bc2b7096be2b7797bd2b7090b57f7e80f96a7f8bf72b36adb16e659cf97d7f96b56e788df96f7395b06c7e8daa2b7e",
289 "All that glitters is not gold Fair is foul, and foul is fair: Hover through the fog and filthy air. These violent delights h",
290 Opcode::Text
291 );
292 }
293
294 #[bench]
295 fn bench_text_frame_payload_125(b: &mut Bencher) {
296 b.iter(|| text_frame_payload_125())
298 }
299
300 #[test]
301 fn text_frame_long_payload() {
302 frame!(
303 "81fe020d6742ba33262ed613132adb474725d65a1336df411462d340472cd5474725d55f0348fc520e309a5a1462dc5c122e9613062cde13012dcf5f472bc9130123d3415d62f25c1127c813132ac85c1225d213132adf13012ddd13062cde13012bd6470f3b9a520e309439332adf400262cc5a082edf5d1362de560b2bdd5b13319a5b0634df13112bd55f022cce13022cde40496c94392f27d65f472bc913022fca471e62db5d0362db5f0b62ce5b0262de56112bd6404723c856472adf41026cb0711e62ce5b0262ca410e21d15a09259a5c0162d74a4736d2460a20c91f4711d55e0236d25a09259a440e21d1560362ce5b0e319a44063b9a50082fdf404962f543022c96130b2dd958146e9a640f2ddf4502309a58092dd9581463b0670f279a5f0626c313032dce5b4732c85c1327c9474736d55c472fcf500f6e9a5e0236d25a0929c91d6d00c856112bce4a472bc913132adf13142dcf5f472ddc13102bce1d6d0bdc130a37c95a0462d8564736d2564724d55c0362d555472ed545026e9a430b23c313082c9439292dcd130e319a470f279a440e2cce561562d555472dcf414726d340042dd447022cce1d6d05d55c0362d45a002ace1f4725d55c0362d45a002ace124732db41132bd454472bc9131437d95b4731cd5602369a400830c85c106e9a670f23ce132e62c95b062ed6131423c313002dd557472cd3540f369a470e2ed6130e369a510262d75c1530d54449",
304 "All that glitters is not gold
305Fair is foul, and foul is fair: Hover through the fog and filthy air.
306These violent delights have violent ends...
307Hell is empty and all the devils are here.
308By the pricking of my thumbs, Something wicked this way comes. Open, locks, Whoever knocks!
309The lady doth protest too much, methinks.
310Brevity is the soul of wit.
311If music be the food of love, play on.
312Now is the winter of our discontent.
313Good night, good night! parting is such sweet sorrow, That I shall say good night till it be morrow.",
314 Opcode::Text
315 );
316 }
317
318 #[bench]
319 fn bench_text_frame_long_payload(b: &mut Bencher) {
320 b.iter(|| text_frame_long_payload())
322 }
323}