RESTinio
ws_parser.hpp
Go to the documentation of this file.
1 /*
2  restinio
3 */
4 
5 /*!
6  Websocket.
7 */
8 
9 #pragma once
10 
11 #include <restinio/exception.hpp>
12 #include <restinio/websocket/message.hpp>
13 
14 #include <restinio/utils/impl/bitops.hpp>
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 
30 //! Alias for byte.
31 using byte_t = unsigned char;
32 
33 //! Bytes buffer.
35 
36 namespace impl
37 {
38 
39 //! Websocket parser constants.
40 //! \{
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;
55 //! \}
56 
57 //
58 // message_details_t
59 //
60 
61 //! Websocket message class with more detailed protocol information.
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
72  , m_opcode{ opcode }
73  {
74  init_payload_len( payload_len );
75  }
76 
78  final_frame_flag_t final_flag,
79  opcode_t opcode,
80  size_t payload_len,
81  std::uint32_t masking_key )
83  , m_opcode{ opcode }
84  , m_mask_flag( true )
86  {
87  init_payload_len( payload_len );
88  }
89 
90  //! Get payload len.
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.
95  return m_payload_len > websocket_max_payload_size_without_ext? m_ext_payload_len: m_payload_len;
96  }
97 
98  //! Set masking key.
99  void
100  set_masking_key( std::uint32_t value )
101  {
102  m_masking_key = value;
103  m_mask_flag = true;
104  }
105 
106  //! Final flag.
107  bool m_final_flag = true;
108 
109  //! Reserved flags.
110  //! \{
111  bool m_rsv1_flag = false;
112  bool m_rsv2_flag = false;
113  bool m_rsv3_flag = false;
114  //! \}
115 
116  //! Opcode.
118 
119  //! Mask flag.
120  bool m_mask_flag = false;
121 
122  //! Payload len.
123  /*!
124  It contains payload len or ext payload len code.
125  */
127 
128  //! Ext payload len.
130 
131  //! Masking key.
133 
134  private:
135 
136  //! Initialize payload len.
137  /*!
138  Set only payload length if value is lower than 126 or payload length
139  and ext payload length otherwise.
140  */
141  void
142  init_payload_len( size_t payload_len )
143  {
144  if( payload_len > websocket_max_payload_size_without_ext )
145  {
146  // if payload greater than 2bytes-number.
147  m_payload_len = payload_len > 0xFFFF ?
148  websocket_long_ext_len_code:
149  websocket_short_ext_len_code;
150 
151  m_ext_payload_len = payload_len;
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 
164 //! Data with expected size.
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 
175  //! Expected data size in bytes.
176  size_t m_expected_size{0};
177 
178  //! Buffer for accumulating data.
180 
181  //! Check all bytes are loaded.
182  bool
184  {
185  return m_loaded_data.size() == m_expected_size;
186  }
187 
188  //! Try to add one more byte to loaded data and check loaded data size.
189  /*!
190  \return true if loaded data size equals expected size.
191  \return false otherwise.
192  */
193  bool
194  add_byte_and_check_size( byte_t byte )
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 
204  //! Reset internal state on next expected data size.
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 
218 //! Read number from buffer with network bytes order.
219 template <typename T>
220 inline void
221 read_number_from_big_endian_bytes( T & number, const raw_data_t & data )
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 
235 //! Save number to buffer with network bytes order.
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 
252 //! Websocket parser.
253 /*!
254  This class can parse message from binary buffer.
255 
256  It is not necessary to have all buffer before parsing. Parser can process
257  pieces of data and save intermediate state.
258 */
260 {
261  public:
262 
263  //! Parse piece of data from buffer.
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 
282  //! Check header of current websocket message is parsed.
283  bool
285  {
287  }
288 
289  //! Reset internal state.
290  /*!
291  Need to call this function before processing next message.
292  */
293  void
295  {
297  m_current_msg = message_details_t();
298  m_expected_data.reset( websocket_first_two_bytes_size );
299  }
300 
301  //! Get current mesasge details.
302  const message_details_t &
304  {
305  return m_current_msg;
306  }
307 
308  private:
309 
310  //! Buffer for parts of websocket message with known size.
311  /*!
312  Default value is first 2 bytes for flags and opcode.
313  */
315 
316  //! Current websocket message details.
318 
319  //! Internal state.
320  enum class state_t
321  {
326  };
327 
328  //! Current state.
330 
331  //! Process one byte of incoming buffer.
332  void
333  process_byte( byte_t byte )
334  {
335  if( m_expected_data.add_byte_and_check_size(byte) )
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 
362  //! Process first two bytes of message.
363  /*!
364  Parse flags, opcode, payload length and set new state.
365  */
366  void
368  {
369  parse_first_2_bytes(
370  m_expected_data.m_loaded_data );
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 
400  //! Process extended length.
401  /*!
402  Parse extended length and set new state.
403  */
404  void
406  {
407  parse_ext_payload_len(
408  m_current_msg.m_payload_len,
409  m_expected_data.m_loaded_data );
410 
411  if( m_current_msg.m_mask_flag )
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
425  //! Process extended length.
426  /*!
427  Parse masking key and set new state.
428  */
430  {
431  parse_masking_key(
432  m_current_msg.m_mask_flag,
433  m_expected_data.m_loaded_data );
434 
436  }
437 
438  //! Parse first two bytes of message from buffer.
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;
451  m_current_msg.m_payload_len = data[1] & payload_len_mask;
452  }
453 
454  //! Parse extended length from buffer.
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  {
462  read_number_from_big_endian_bytes(
463  m_current_msg.m_ext_payload_len, data );
464  }
465  else if( payload_len == websocket_long_ext_len_code )
466  {
467  read_number_from_big_endian_bytes(
468  m_current_msg.m_ext_payload_len, data );
469  }
470  }
471 
472  //! Parse masking key from buffer.
473  void
475  bool mask_flag,
476  const raw_data_t & data )
477  {
478  if( mask_flag )
479  {
480  read_number_from_big_endian_bytes(
481  m_current_msg.m_masking_key, data );
482  }
483  }
484 };
485 
486 //! Do msak/unmask operation with buffer.
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 
510 //! Serialize websocket message details into bytes buffer.
511 /*!
512  \return buffer with written websocket message.
513 */
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 
581 //! Serialize websocket message details into bytes buffer.
582 /*!
583  \return buffer with written websocket message.
584 */
585 inline raw_data_t
590 {
591  return write_message_details(
592  message_details_t{ final_flag, opcode, payload_len } );
593 }
594 
595 //! Serialize websocket message details into bytes buffer.
596 /*!
597  \return buffer with written websocket message.
598 */
599 inline raw_data_t
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 */
raw_data_t m_loaded_data
Buffer for accumulating data.
Definition: ws_parser.hpp:179
void parse_masking_key(bool mask_flag, const raw_data_t &data)
Parse masking key from buffer.
Definition: ws_parser.hpp:474
constexpr size_t websocket_short_ext_len_code
Definition: ws_parser.hpp:45
size_t m_expected_size
Expected data size in bytes.
Definition: ws_parser.hpp:176
const message_details_t & current_message() const
Get current mesasge details.
Definition: ws_parser.hpp:303
void process_masking_key()
Process extended length.
Definition: ws_parser.hpp:429
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
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_first_two_bytes_size
Websocket parser constants.
Definition: ws_parser.hpp:41
raw_data_t write_message_details(final_frame_flag_t final_flag, opcode_t opcode, size_t payload_len, std::uint32_t masking_key)
Serialize websocket message details into bytes buffer.
Definition: ws_parser.hpp:600
expected_data_t m_expected_data
Buffer for parts of websocket message with known size.
Definition: ws_parser.hpp:314
Websocket message class with more detailed protocol information.
Definition: ws_parser.hpp:62
void init_payload_len(size_t payload_len)
Initialize payload len.
Definition: ws_parser.hpp:142
message_details_t m_current_msg
Current websocket message details.
Definition: ws_parser.hpp:317
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 mask_unmask_payload(std::uint32_t masking_key, raw_data_t &payload)
Do msak/unmask operation with buffer.
Definition: ws_parser.hpp:488
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, std::uint32_t masking_key)
Definition: ws_parser.hpp:77
void reset(size_t expected_size)
Reset internal state on next expected data size.
Definition: ws_parser.hpp:206
message_details_t(final_frame_flag_t final_flag, opcode_t opcode, size_t payload_len) noexcept
Definition: ws_parser.hpp:67
constexpr size_t websocket_max_payload_size_without_ext
Definition: ws_parser.hpp:42
constexpr byte_t payload_len_mask
Definition: ws_parser.hpp:54
void process_extended_length()
Process extended length.
Definition: ws_parser.hpp:405
size_t parser_execute(const char *data, size_t size)
Parse piece of data from buffer.
Definition: ws_parser.hpp:265
void process_byte(byte_t byte)
Process one byte of incoming buffer.
Definition: ws_parser.hpp:333
constexpr size_t websocket_long_ext_payload_length
Definition: ws_parser.hpp:44
bool all_bytes_loaded() const
Check all bytes are loaded.
Definition: ws_parser.hpp:183
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 parse_first_2_bytes(const raw_data_t &data)
Parse first two bytes of message from buffer.
Definition: ws_parser.hpp:440
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
raw_data_t write_message_details(final_frame_flag_t final_flag, opcode_t opcode, size_t payload_len)
Serialize websocket message details into bytes buffer.
Definition: ws_parser.hpp:586
constexpr size_t websocket_long_ext_len_code
Definition: ws_parser.hpp:46
bool header_parsed() const
Check header of current websocket message is parsed.
Definition: ws_parser.hpp:284
constexpr size_t websocket_short_ext_payload_length
Definition: ws_parser.hpp:43
std::uint64_t payload_len() const
Get payload len.
Definition: ws_parser.hpp:92
void process_first_2_bytes()
Process first two bytes of message.
Definition: ws_parser.hpp:367
void reset()
Reset internal state.
Definition: ws_parser.hpp:294
constexpr size_t websocket_masking_key_size
Definition: ws_parser.hpp:47
void set_masking_key(std::uint32_t value)
Set masking key.
Definition: ws_parser.hpp:100
std::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, optional_t< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in optional_t<Value_Type> if parameter exists ...
Definition: value_or.hpp:64