RESTinio
ws_parser.hpp
Go to the documentation of this file.
1 /*
2  restinio
3 */
4 
9 #pragma once
10 
11 #include <restinio/exception.hpp>
13 
15 
16 #include <cstdint>
17 #include <vector>
18 #include <list>
19 #include <stdexcept>
20 
21 namespace restinio
22 {
23 
24 namespace websocket
25 {
26 
27 namespace basic
28 {
29 
31 using byte_t = unsigned char;
32 
34 using raw_data_t = std::string;
35 
36 namespace impl
37 {
38 
41 constexpr size_t websocket_first_two_bytes_size = 2;
44 constexpr size_t websocket_long_ext_payload_length = 8;
45 constexpr size_t websocket_short_ext_len_code = 126;
46 constexpr size_t websocket_long_ext_len_code = 127;
47 constexpr size_t websocket_masking_key_size = 4;
48 
49 constexpr byte_t bit_flag_7 = 0x80;
50 constexpr byte_t bit_flag_6 = 0x40;
51 constexpr byte_t bit_flag_5 = 0x20;
52 constexpr byte_t bit_flag_4 = 0x10;
53 constexpr byte_t opcode_mask = 0x0F;
54 constexpr 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
92  payload_len() const
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  {
172  m_loaded_data.reserve( m_expected_size );
173  }
174 
176  size_t m_expected_size{0};
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 
219 template <typename T>
220 inline 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 
236 template <int Bytes>
237 inline void
238 write_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  {
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 
374  if( payload_len > websocket_max_payload_size_without_ext )
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 
487 inline void
488 mask_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 
514 inline 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 
585 inline raw_data_t
587  final_frame_flag_t final_flag,
588  opcode_t opcode,
589  size_t payload_len )
590 {
591  return write_message_details(
592  message_details_t{ final_flag, opcode, payload_len } );
593 }
594 
596 
599 inline 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 {
606  return write_message_details(
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 */
restinio::exception_t
Exception class for all exceptions thrown by RESTinio.
Definition: exception.hpp:26
restinio::websocket::basic::impl::message_details_t::message_details_t
message_details_t()=default
message.hpp
restinio::websocket::basic::raw_data_t
std::string raw_data_t
Bytes buffer.
Definition: ws_parser.hpp:34
restinio::websocket::basic::impl::payload_len_mask
constexpr byte_t payload_len_mask
Definition: ws_parser.hpp:54
restinio::websocket::basic::impl::ws_parser_t::parse_ext_payload_len
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
restinio::websocket::basic::impl::ws_parser_t
Websocket parser.
Definition: ws_parser.hpp:260
restinio::websocket::basic::impl::ws_parser_t::current_message
const message_details_t & current_message() const
Get current mesasge details.
Definition: ws_parser.hpp:303
restinio::websocket::basic::impl::ws_parser_t::state_t::waiting_for_mask_key
@ waiting_for_mask_key
restinio::websocket::basic::impl::ws_parser_t::state_t::header_parsed
@ header_parsed
restinio::websocket::basic::impl::expected_data_t::m_loaded_data
raw_data_t m_loaded_data
Buffer for accumulating data.
Definition: ws_parser.hpp:179
restinio::utils::impl::bitops
Definition: bitops.hpp:19
restinio::websocket::basic::impl::ws_parser_t::state_t
state_t
Internal state.
Definition: ws_parser.hpp:321
restinio::utils::impl::bitops::details::mask
constexpr T mask(unsigned bits_to_extract)
Definition: bitops.hpp:24
restinio::websocket::basic::impl::websocket_long_ext_payload_length
constexpr size_t websocket_long_ext_payload_length
Definition: ws_parser.hpp:44
restinio::websocket::basic::impl::message_details_t
Websocket message class with more detailed protocol information.
Definition: ws_parser.hpp:63
restinio::websocket::basic::impl::websocket_short_ext_len_code
constexpr size_t websocket_short_ext_len_code
Definition: ws_parser.hpp:45
bitops.hpp
restinio::websocket::basic::impl::bit_flag_4
constexpr byte_t bit_flag_4
Definition: ws_parser.hpp:52
restinio::websocket::basic::opcode_t
opcode_t
Definition: message.hpp:37
restinio::websocket::basic::impl::message_details_t::m_rsv2_flag
bool m_rsv2_flag
Definition: ws_parser.hpp:112
restinio::websocket::basic::impl::bit_flag_7
constexpr byte_t bit_flag_7
Definition: ws_parser.hpp:49
restinio::websocket::basic::impl::write_number_to_big_endian_bytes
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
restinio::websocket::basic::impl::ws_parser_t::parser_execute
size_t parser_execute(const char *data, size_t size)
Parse piece of data from buffer.
Definition: ws_parser.hpp:265
restinio::websocket::basic::impl::message_details_t::m_ext_payload_len
std::uint64_t m_ext_payload_len
Ext payload len.
Definition: ws_parser.hpp:129
restinio::websocket::basic::impl::ws_parser_t::process_extended_length
void process_extended_length()
Process extended length.
Definition: ws_parser.hpp:405
restinio::websocket::basic::impl::ws_parser_t::state_t::waiting_for_ext_len
@ waiting_for_ext_len
restinio::websocket::basic::impl::write_message_details
raw_data_t write_message_details(const message_details_t &message)
Serialize websocket message details into bytes buffer.
Definition: ws_parser.hpp:515
restinio::websocket::basic::impl::message_details_t::init_payload_len
void init_payload_len(size_t payload_len)
Initialize payload len.
Definition: ws_parser.hpp:142
restinio::websocket::basic::impl::expected_data_t::reset
void reset(size_t expected_size)
Reset internal state on next expected data size.
Definition: ws_parser.hpp:206
restinio::websocket::basic::impl::expected_data_t::all_bytes_loaded
bool all_bytes_loaded() const
Check all bytes are loaded.
Definition: ws_parser.hpp:183
restinio::websocket::basic::impl::read_number_from_big_endian_bytes
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
restinio::websocket::basic::final_frame
constexpr final_frame_flag_t final_frame
Definition: message.hpp:135
restinio::websocket::basic::impl::ws_parser_t::parse_first_2_bytes
void parse_first_2_bytes(const raw_data_t &data)
Parse first two bytes of message from buffer.
Definition: ws_parser.hpp:440
restinio::websocket::basic::impl::message_details_t::m_masking_key
std::uint32_t m_masking_key
Masking key.
Definition: ws_parser.hpp:132
restinio::websocket::basic::impl::mask_unmask_payload
void mask_unmask_payload(std::uint32_t masking_key, raw_data_t &payload)
Do msak/unmask operation with buffer.
Definition: ws_parser.hpp:488
restinio::websocket::basic::impl::bit_flag_6
constexpr byte_t bit_flag_6
Definition: ws_parser.hpp:50
restinio::websocket::basic::impl::websocket_short_ext_payload_length
constexpr size_t websocket_short_ext_payload_length
Definition: ws_parser.hpp:43
restinio::websocket::basic::impl::message_details_t::m_payload_len
std::uint8_t m_payload_len
Payload len.
Definition: ws_parser.hpp:126
restinio::websocket::basic::impl::expected_data_t::expected_data_t
expected_data_t()=default
restinio::websocket::basic::impl::websocket_long_ext_len_code
constexpr size_t websocket_long_ext_len_code
Definition: ws_parser.hpp:46
restinio::utils::sha1::details::byte
unsigned int byte(digest_t::value_type v)
Definition: sha1.hpp:365
restinio::websocket::basic::impl::ws_parser_t::process_byte
void process_byte(byte_t byte)
Process one byte of incoming buffer.
Definition: ws_parser.hpp:333
restinio
Definition: asio_include.hpp:21
restinio::websocket::basic::impl::websocket_max_payload_size_without_ext
constexpr size_t websocket_max_payload_size_without_ext
Definition: ws_parser.hpp:42
restinio::websocket::basic::impl::ws_parser_t::reset
void reset()
Reset internal state.
Definition: ws_parser.hpp:294
restinio::websocket::basic::impl::expected_data_t::expected_data_t
expected_data_t(size_t expected_size)
Definition: ws_parser.hpp:169
restinio::websocket::basic::impl::expected_data_t::m_expected_size
size_t m_expected_size
Expected data size in bytes.
Definition: ws_parser.hpp:176
restinio::websocket::basic::impl::ws_parser_t::process_masking_key
void process_masking_key()
Process extended length.
Definition: ws_parser.hpp:429
restinio::websocket::basic::impl::ws_parser_t::state_t::waiting_for_first_2_bytes
@ waiting_for_first_2_bytes
restinio::websocket::basic::impl::websocket_masking_key_size
constexpr size_t websocket_masking_key_size
Definition: ws_parser.hpp:47
exception.hpp
restinio::websocket::basic::impl::ws_parser_t::m_current_msg
message_details_t m_current_msg
Current websocket message details.
Definition: ws_parser.hpp:317
restinio::websocket::basic::impl::message_details_t::m_mask_flag
bool m_mask_flag
Mask flag.
Definition: ws_parser.hpp:120
restinio::websocket::basic::impl::websocket_first_two_bytes_size
constexpr size_t websocket_first_two_bytes_size
Websocket parser constants.
Definition: ws_parser.hpp:41
restinio::websocket::basic::impl::message_details_t::m_opcode
opcode_t m_opcode
Opcode.
Definition: ws_parser.hpp:117
restinio::websocket::basic::byte_t
unsigned char byte_t
Alias for byte.
Definition: ws_parser.hpp:31
restinio::websocket::basic::impl::message_details_t::message_details_t
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
restinio::websocket::basic::impl::message_details_t::payload_len
std::uint64_t payload_len() const
Get payload len.
Definition: ws_parser.hpp:92
restinio::websocket::basic::impl::ws_parser_t::m_current_state
state_t m_current_state
Current state.
Definition: ws_parser.hpp:329
restinio::websocket::basic::impl::ws_parser_t::process_first_2_bytes
void process_first_2_bytes()
Process first two bytes of message.
Definition: ws_parser.hpp:367
restinio::websocket::basic::impl::opcode_mask
constexpr byte_t opcode_mask
Definition: ws_parser.hpp:53
restinio::websocket::basic::final_frame_flag_t
final_frame_flag_t
WS frame (message) "final"/"not final" flag.
Definition: message.hpp:133
restinio::websocket::basic::impl::message_details_t::m_rsv1_flag
bool m_rsv1_flag
Reserved flags.
Definition: ws_parser.hpp:111
restinio::websocket::basic::impl::ws_parser_t::m_expected_data
expected_data_t m_expected_data
Buffer for parts of websocket message with known size.
Definition: ws_parser.hpp:314
restinio::websocket::basic::impl::message_details_t::m_rsv3_flag
bool m_rsv3_flag
Definition: ws_parser.hpp:113
restinio::websocket::basic::impl::expected_data_t
Data with expected size.
Definition: ws_parser.hpp:166
restinio::websocket::basic::impl::message_details_t::set_masking_key
void set_masking_key(std::uint32_t value)
Set masking key.
Definition: ws_parser.hpp:100
restinio::websocket::basic::impl::message_details_t::message_details_t
message_details_t(final_frame_flag_t final_flag, opcode_t opcode, size_t payload_len) noexcept
Definition: ws_parser.hpp:67
restinio::websocket::basic::impl::bit_flag_5
constexpr byte_t bit_flag_5
Definition: ws_parser.hpp:51
restinio::websocket::basic::impl::expected_data_t::add_byte_and_check_size
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
restinio::websocket::basic::impl::message_details_t::m_final_flag
bool m_final_flag
Final flag.
Definition: ws_parser.hpp:107
restinio::websocket::basic::impl::ws_parser_t::header_parsed
bool header_parsed() const
Check header of current websocket message is parsed.
Definition: ws_parser.hpp:284
restinio::websocket::basic::impl::ws_parser_t::parse_masking_key
void parse_masking_key(bool mask_flag, const raw_data_t &data)
Parse masking key from buffer.
Definition: ws_parser.hpp:474