RESTinio
ws_parser.hpp
Go to the documentation of this file.
1/*
2 restinio
3*/
4
9#pragma once
10
13
15
16#include <cstdint>
17#include <vector>
18#include <list>
19#include <stdexcept>
20
21namespace restinio
22{
23
24namespace websocket
25{
26
27namespace basic
28{
29
31using byte_t = unsigned char;
32
34using raw_data_t = std::string;
35
36namespace impl
37{
38
41constexpr size_t websocket_first_two_bytes_size = 2;
45constexpr size_t websocket_short_ext_len_code = 126;
46constexpr size_t websocket_long_ext_len_code = 127;
47constexpr size_t websocket_masking_key_size = 4;
48
49constexpr byte_t bit_flag_7 = 0x80;
50constexpr byte_t bit_flag_6 = 0x40;
51constexpr byte_t bit_flag_5 = 0x20;
52constexpr byte_t bit_flag_4 = 0x10;
53constexpr byte_t opcode_mask = 0x0F;
54constexpr byte_t payload_len_mask = 0x7F;
56
57//
58// message_details_t
59//
60
63{
64 public:
65 message_details_t() = default;
66
68 final_frame_flag_t final_flag,
69 opcode_t opcode,
70 size_t payload_len ) noexcept
71 : m_final_flag{ final_frame == final_flag }
72 , m_opcode{ opcode }
73 {
75 }
76
78 final_frame_flag_t final_flag,
79 opcode_t opcode,
80 size_t payload_len,
81 std::uint32_t masking_key )
82 : m_final_flag{ final_frame == final_flag }
83 , m_opcode{ opcode }
84 , m_mask_flag( true )
85 , m_masking_key( masking_key )
86 {
88 }
89
91 std::uint64_t
93 {
94 // 126 and 127 are codes of ext payload. 125 and lower are real payload len.
96 }
97
99 void
100 set_masking_key( std::uint32_t value )
101 {
102 m_masking_key = value;
103 m_mask_flag = true;
104 }
105
107 bool m_final_flag = true;
108
111 bool m_rsv1_flag = false;
112 bool m_rsv2_flag = false;
113 bool m_rsv3_flag = false;
115
117 opcode_t m_opcode = opcode_t::continuation_frame;
118
120 bool m_mask_flag = false;
121
123
126 std::uint8_t m_payload_len = 0;
127
129 std::uint64_t m_ext_payload_len = 0;
130
132 std::uint32_t m_masking_key = 0;
133
134 private:
135
137
141 void
143 {
145 {
146 // if payload greater than 2bytes-number.
147 m_payload_len = payload_len > 0xFFFF ?
150
152 }
153 else
154 {
155 m_payload_len = static_cast< std::uint8_t >( payload_len );
156 }
157 }
158};
159
160//
161// expected_data_t
162//
163
166{
167 expected_data_t() = default;
168
169 expected_data_t( size_t expected_size )
170 : m_expected_size{ expected_size }
171 {
173 }
174
177
180
182 bool
184 {
185 return m_loaded_data.size() == m_expected_size;
186 }
187
189
193 bool
195 {
196 if( m_loaded_data.size() == m_expected_size )
197 throw exception_t("Cannot add one more bytes to expected data.");
198
199 m_loaded_data.push_back(static_cast<raw_data_t::value_type>(byte));
200
201 return all_bytes_loaded();
202 }
203
205 void
206 reset( size_t expected_size )
207 {
208 m_expected_size = expected_size;
209 m_loaded_data.clear();
210 m_loaded_data.reserve( expected_size );
211 }
212};
213
214//
215// read_number_from_big_endian_bytes
216//
217
219template <typename T>
220inline void
222{
223 number = T{};
224 for( const auto byte: data )
225 {
226 number <<= 8;
227 number |= static_cast<std::uint8_t>( byte );
228 }
229}
230
231//
232// write_number_to_big_endian_bytes
233//
234
236template <int Bytes>
237inline void
238write_number_to_big_endian_bytes( std::uint64_t& number, raw_data_t & data )
239{
240 for( auto i = 0 ; i < Bytes ; ++i )
241 {
242 auto shift_value = (Bytes - i - 1) * 8;
243 data.push_back( static_cast<raw_data_t::value_type>(
244 (number >> shift_value) & 0xFF) );
245 }
246}
247
248//
249// ws_parser_t
250//
251
253
260{
261 public:
262
264 size_t
265 parser_execute( const char * data, size_t size )
266 {
267 size_t parsed_bytes = 0;
268
269 while( parsed_bytes < size &&
271 {
272 byte_t byte = static_cast< byte_t >( data[parsed_bytes] );
273
274 process_byte( byte );
275
276 parsed_bytes++;
277 }
278
279 return parsed_bytes;
280 }
281
283 bool
285 {
287 }
288
290
293 void
295 {
299 }
300
302 const message_details_t &
304 {
305 return m_current_msg;
306 }
307
308 private:
309
311
315
318
320 enum class state_t
321 {
322 waiting_for_first_2_bytes,
323 waiting_for_ext_len,
324 waiting_for_mask_key,
326 };
327
330
332 void
334 {
336 {
337 switch( m_current_state )
338 {
339
341
343 break;
344
346
348 break;
349
351
353 break;
354
356
357 break;
358 }
359 }
360 }
361
363
366 void
368 {
371
372 size_t payload_len = m_current_msg.m_payload_len;
373
375 {
376 size_t expected_data_size = payload_len == websocket_short_ext_len_code?
379
380 m_expected_data.reset( expected_data_size );
381
383 }
384 else if( m_current_msg.m_mask_flag )
385 {
386 size_t expected_data_size = websocket_masking_key_size;
387 m_expected_data.reset( expected_data_size );
388
390 }
391 else
392 {
393 size_t expected_data_size = payload_len;
394 m_expected_data.reset( expected_data_size );
395
397 }
398 }
399
401
404 void
406 {
410
412 {
413 size_t expected_data_size = websocket_masking_key_size;
414 m_expected_data.reset( expected_data_size );
415
417 }
418 else
419 {
421 }
422 }
423
424 void
426
430 {
434
436 }
437
439 void
441 const raw_data_t & data )
442 {
443 m_current_msg.m_final_flag = (data[0] & bit_flag_7) != 0;
444 m_current_msg.m_rsv1_flag = (data[0] & bit_flag_6) != 0;
445 m_current_msg.m_rsv2_flag = (data[0] & bit_flag_5) != 0;
446 m_current_msg.m_rsv3_flag = (data[0] & bit_flag_4) != 0;
447
448 m_current_msg.m_opcode = static_cast< opcode_t >( data[0] & opcode_mask );
449
450 m_current_msg.m_mask_flag = (data[1] & bit_flag_7) != 0;
452 }
453
455 void
457 std::uint8_t payload_len,
458 const raw_data_t & data )
459 {
460 if( payload_len == websocket_short_ext_len_code )
461 {
464 }
465 else if( payload_len == websocket_long_ext_len_code )
466 {
469 }
470 }
471
473 void
475 bool mask_flag,
476 const raw_data_t & data )
477 {
478 if( mask_flag )
479 {
482 }
483 }
484};
485
487inline void
488mask_unmask_payload( std::uint32_t masking_key, raw_data_t & payload )
489{
490 using namespace ::restinio::utils::impl::bitops;
491
492 const std::size_t MASK_SIZE = 4;
493 const uint8_t mask[ MASK_SIZE ] = {
494 n_bits_from< std::uint8_t, 24 >(masking_key),
495 n_bits_from< std::uint8_t, 16 >(masking_key),
496 n_bits_from< std::uint8_t, 8 >(masking_key),
497 n_bits_from< std::uint8_t, 0 >(masking_key),
498 };
499
500 const auto payload_size = payload.size();
501 for( std::size_t i = 0; i < payload_size; )
502 {
503 for( std::size_t j = 0; j < MASK_SIZE && i < payload_size; ++j, ++i )
504 {
505 payload[ i ] ^= mask[ j ];
506 }
507 }
508}
509
511
514inline raw_data_t
516{
517 raw_data_t result;
518
519 byte_t byte = 0x00;
520
521 if( message.m_final_flag ) byte |= bit_flag_7;
522 if( message.m_rsv1_flag ) byte |= bit_flag_6;
523 if( message.m_rsv2_flag ) byte |= bit_flag_5;
524 if( message.m_rsv3_flag ) byte |= bit_flag_4;
525
526 byte |= static_cast< std::uint8_t> (message.m_opcode) & opcode_mask;
527
528 result.push_back( static_cast<raw_data_t::value_type>(byte) );
529
530 byte = 0x00;
531
532 if( message.m_mask_flag )
533 byte |= bit_flag_7;
534
535 auto length = message.m_payload_len;
536
537 if( length < websocket_short_ext_len_code )
538 {
539 byte |= length;
540 result.push_back( static_cast<raw_data_t::value_type>(byte) );
541 }
542 else if ( length == websocket_short_ext_len_code )
543 {
545
546 result.push_back( static_cast<raw_data_t::value_type>(byte) );
547
548 auto ext_len = message.m_ext_payload_len;
549
550 write_number_to_big_endian_bytes< websocket_short_ext_payload_length>(
551 ext_len, result );
552 }
553 else if ( length == websocket_long_ext_len_code )
554 {
556
557 result.push_back( static_cast<raw_data_t::value_type>(byte) );
558
559 auto ext_len = message.m_ext_payload_len;
560
561 write_number_to_big_endian_bytes< websocket_long_ext_payload_length >(
562 ext_len, result );
563 }
564
565 if( message.m_mask_flag )
566 {
567 using namespace ::restinio::utils::impl::bitops;
568
569 using ch_type = raw_data_t::value_type;
570
571 const auto key = message.m_masking_key;
572 result.push_back( n_bits_from< ch_type, 24 >(key) );
573 result.push_back( n_bits_from< ch_type, 16 >(key) );
574 result.push_back( n_bits_from< ch_type, 8 >(key) );
575 result.push_back( n_bits_from< ch_type, 0 >(key) );
576 }
577
578 return result;
579}
580
582
585inline raw_data_t
587 final_frame_flag_t final_flag,
588 opcode_t opcode,
589 size_t payload_len )
590{
592 message_details_t{ final_flag, opcode, payload_len } );
593}
594
596
599inline raw_data_t
601 final_frame_flag_t final_flag,
602 opcode_t opcode,
603 size_t payload_len,
604 std::uint32_t masking_key )
605{
607 message_details_t{ final_flag, opcode, payload_len, masking_key } );
608}
609
610} /* namespace impl */
611
612} /* namespace basic */
613
614} /* namespace websocket */
615
616} /* namespace restinio */
Exception class for all exceptions thrown by RESTinio.
Definition: exception.hpp:26
Websocket message class with more detailed protocol information.
Definition: ws_parser.hpp:63
std::uint64_t payload_len() const
Get payload len.
Definition: ws_parser.hpp:92
message_details_t(final_frame_flag_t final_flag, opcode_t opcode, size_t payload_len, std::uint32_t masking_key)
Definition: ws_parser.hpp:77
std::uint64_t m_ext_payload_len
Ext payload len.
Definition: ws_parser.hpp:129
message_details_t(final_frame_flag_t final_flag, opcode_t opcode, size_t payload_len) noexcept
Definition: ws_parser.hpp:67
void init_payload_len(size_t payload_len)
Initialize payload len.
Definition: ws_parser.hpp:142
void set_masking_key(std::uint32_t value)
Set masking key.
Definition: ws_parser.hpp:100
void process_extended_length()
Process extended length.
Definition: ws_parser.hpp:405
message_details_t m_current_msg
Current websocket message details.
Definition: ws_parser.hpp:317
const message_details_t & current_message() const
Get current mesasge details.
Definition: ws_parser.hpp:303
void process_byte(byte_t byte)
Process one byte of incoming buffer.
Definition: ws_parser.hpp:333
void parse_first_2_bytes(const raw_data_t &data)
Parse first two bytes of message from buffer.
Definition: ws_parser.hpp:440
void parse_ext_payload_len(std::uint8_t payload_len, const raw_data_t &data)
Parse extended length from buffer.
Definition: ws_parser.hpp:456
void parse_masking_key(bool mask_flag, const raw_data_t &data)
Parse masking key from buffer.
Definition: ws_parser.hpp:474
size_t parser_execute(const char *data, size_t size)
Parse piece of data from buffer.
Definition: ws_parser.hpp:265
void process_masking_key()
Process extended length.
Definition: ws_parser.hpp:429
bool header_parsed() const
Check header of current websocket message is parsed.
Definition: ws_parser.hpp:284
expected_data_t m_expected_data
Buffer for parts of websocket message with known size.
Definition: ws_parser.hpp:314
void process_first_2_bytes()
Process first two bytes of message.
Definition: ws_parser.hpp:367
constexpr T mask(unsigned bits_to_extract)
Definition: bitops.hpp:24
unsigned int byte(digest_t::value_type v)
Definition: sha1.hpp:365
void read_number_from_big_endian_bytes(T &number, const raw_data_t &data)
Read number from buffer with network bytes order.
Definition: ws_parser.hpp:221
void mask_unmask_payload(std::uint32_t masking_key, raw_data_t &payload)
Do msak/unmask operation with buffer.
Definition: ws_parser.hpp:488
constexpr size_t websocket_max_payload_size_without_ext
Definition: ws_parser.hpp:42
constexpr size_t websocket_long_ext_payload_length
Definition: ws_parser.hpp:44
raw_data_t write_message_details(const message_details_t &message)
Serialize websocket message details into bytes buffer.
Definition: ws_parser.hpp:515
constexpr size_t websocket_short_ext_len_code
Definition: ws_parser.hpp:45
constexpr byte_t payload_len_mask
Definition: ws_parser.hpp:54
constexpr size_t websocket_short_ext_payload_length
Definition: ws_parser.hpp:43
constexpr size_t websocket_long_ext_len_code
Definition: ws_parser.hpp:46
constexpr size_t websocket_masking_key_size
Definition: ws_parser.hpp:47
constexpr size_t websocket_first_two_bytes_size
Websocket parser constants.
Definition: ws_parser.hpp:41
void write_number_to_big_endian_bytes(std::uint64_t &number, raw_data_t &data)
Save number to buffer with network bytes order.
Definition: ws_parser.hpp:238
std::string raw_data_t
Bytes buffer.
Definition: ws_parser.hpp:34
unsigned char byte_t
Alias for byte.
Definition: ws_parser.hpp:31
constexpr final_frame_flag_t final_frame
Definition: message.hpp:135
final_frame_flag_t
WS frame (message) "final"/"not final" flag.
Definition: message.hpp:133
bool add_byte_and_check_size(byte_t byte)
Try to add one more byte to loaded data and check loaded data size.
Definition: ws_parser.hpp:194
void reset(size_t expected_size)
Reset internal state on next expected data size.
Definition: ws_parser.hpp:206
bool all_bytes_loaded() const
Check all bytes are loaded.
Definition: ws_parser.hpp:183
size_t m_expected_size
Expected data size in bytes.
Definition: ws_parser.hpp:176
raw_data_t m_loaded_data
Buffer for accumulating data.
Definition: ws_parser.hpp:179