11 #include <restinio/exception.hpp> 12 #include <restinio/websocket/message.hpp> 14 #include <restinio/utils/impl/bitops.hpp> 31 using byte_t =
unsigned char;
68 final_frame_flag_t final_flag,
70 size_t payload_len )
noexcept 78 final_frame_flag_t final_flag,
81 std::uint32_t masking_key )
95 return m_payload_len > websocket_max_payload_size_without_ext? m_ext_payload_len: m_payload_len;
102 m_masking_key = value;
147 m_payload_len = payload_len > 0xFFFF ?
148 websocket_long_ext_len_code:
149 websocket_short_ext_len_code;
151 m_ext_payload_len = payload_len;
155 m_payload_len =
static_cast< std::uint8_t >( payload_len );
172 m_loaded_data.reserve( m_expected_size );
185 return m_loaded_data.size() == m_expected_size;
196 if( m_loaded_data.size() == m_expected_size )
197 throw exception_t(
"Cannot add one more bytes to expected data.");
199 m_loaded_data.push_back(
static_cast<raw_data_t::value_type>(byte));
209 m_loaded_data.clear();
210 m_loaded_data.reserve( expected_size );
219 template <
typename T>
267 size_t parsed_bytes = 0;
269 while( parsed_bytes < size &&
272 byte_t byte =
static_cast< byte_t >( data[parsed_bytes] );
297 m_current_msg = message_details_t();
298 m_expected_data.reset( websocket_first_two_bytes_size );
305 return m_current_msg;
335 if( m_expected_data.add_byte_and_check_size(byte) )
370 m_expected_data.m_loaded_data );
372 size_t payload_len = m_current_msg.m_payload_len;
380 m_expected_data.reset( expected_data_size );
384 else if( m_current_msg.m_mask_flag )
387 m_expected_data.reset( expected_data_size );
393 size_t expected_data_size = payload_len;
394 m_expected_data.reset( expected_data_size );
407 parse_ext_payload_len(
408 m_current_msg.m_payload_len,
409 m_expected_data.m_loaded_data );
411 if( m_current_msg.m_mask_flag )
414 m_expected_data.reset( expected_data_size );
432 m_current_msg.m_mask_flag,
433 m_expected_data.m_loaded_data );
441 const raw_data_t & data )
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;
448 m_current_msg.m_opcode =
static_cast< opcode_t >( data[0] & opcode_mask );
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;
457 std::uint8_t payload_len,
458 const raw_data_t & data )
460 if( payload_len == websocket_short_ext_len_code )
462 read_number_from_big_endian_bytes(
463 m_current_msg.m_ext_payload_len, data );
465 else if( payload_len == websocket_long_ext_len_code )
467 read_number_from_big_endian_bytes(
468 m_current_msg.m_ext_payload_len, data );
476 const raw_data_t & data )
480 read_number_from_big_endian_bytes(
481 m_current_msg.m_masking_key, data );
490 using namespace ::restinio::utils::impl::bitops;
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),
500 const auto payload_size = payload.size();
501 for( std::size_t i = 0; i < payload_size; )
503 for( std::size_t j = 0; j < MASK_SIZE && i < payload_size; ++j, ++i )
505 payload[ i ] ^= mask[ j ];
526 byte |=
static_cast< std::uint8_t> (message.m_opcode) & opcode_mask;
528 result.push_back(
static_cast<raw_data_t::value_type>(byte) );
535 auto length = message.m_payload_len;
537 if( length < websocket_short_ext_len_code )
540 result.push_back(
static_cast<raw_data_t::value_type>(byte) );
542 else if ( length == websocket_short_ext_len_code )
546 result.push_back(
static_cast<raw_data_t::value_type>(byte) );
548 auto ext_len = message.m_ext_payload_len;
550 write_number_to_big_endian_bytes< websocket_short_ext_payload_length>(
553 else if ( length == websocket_long_ext_len_code )
557 result.push_back(
static_cast<raw_data_t::value_type>(byte) );
559 auto ext_len = message.m_ext_payload_len;
561 write_number_to_big_endian_bytes< websocket_long_ext_payload_length >(
567 using namespace ::restinio::utils::impl::bitops;
569 using ch_type = raw_data_t::value_type;
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) );
591 return write_message_details(
592 message_details_t{ final_flag, opcode, payload_len } );
606 return write_message_details(
607 message_details_t{ final_flag, opcode, payload_len, masking_key } );
raw_data_t m_loaded_data
Buffer for accumulating data.
void parse_masking_key(bool mask_flag, const raw_data_t &data)
Parse masking key from buffer.
constexpr size_t websocket_short_ext_len_code
constexpr byte_t bit_flag_6
size_t m_expected_size
Expected data size in bytes.
const message_details_t & current_message() const
Get current mesasge details.
bool m_mask_flag
Mask flag.
void process_masking_key()
Process extended length.
bool add_byte_and_check_size(byte_t byte)
Try to add one more byte to loaded data and check loaded data size.
raw_data_t write_message_details(const message_details_t &message)
Serialize websocket message details into bytes buffer.
constexpr size_t websocket_first_two_bytes_size
Websocket parser constants.
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.
state_t m_current_state
Current state.
message_details_t()=default
expected_data_t m_expected_data
Buffer for parts of websocket message with known size.
Websocket message class with more detailed protocol information.
void init_payload_len(size_t payload_len)
Initialize payload len.
message_details_t m_current_msg
Current websocket message details.
bool m_final_flag
Final flag.
void parse_ext_payload_len(std::uint8_t payload_len, const raw_data_t &data)
Parse extended length from buffer.
void mask_unmask_payload(std::uint32_t masking_key, raw_data_t &payload)
Do msak/unmask operation with buffer.
std::uint32_t m_masking_key
Masking key.
std::uint64_t m_ext_payload_len
Ext payload len.
message_details_t(final_frame_flag_t final_flag, opcode_t opcode, size_t payload_len, std::uint32_t masking_key)
constexpr byte_t opcode_mask
constexpr byte_t bit_flag_7
void reset(size_t expected_size)
Reset internal state on next expected data size.
message_details_t(final_frame_flag_t final_flag, opcode_t opcode, size_t payload_len) noexcept
constexpr size_t websocket_max_payload_size_without_ext
constexpr byte_t payload_len_mask
void process_extended_length()
Process extended length.
constexpr byte_t bit_flag_5
size_t parser_execute(const char *data, size_t size)
Parse piece of data from buffer.
void process_byte(byte_t byte)
Process one byte of incoming buffer.
constexpr byte_t bit_flag_4
constexpr size_t websocket_long_ext_payload_length
bool all_bytes_loaded() const
Check all bytes are loaded.
void read_number_from_big_endian_bytes(T &number, const raw_data_t &data)
Read number from buffer with network bytes order.
void parse_first_2_bytes(const raw_data_t &data)
Parse first two bytes of message from buffer.
void write_number_to_big_endian_bytes(std::uint64_t &number, raw_data_t &data)
Save number to buffer with network bytes order.
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.
constexpr size_t websocket_long_ext_len_code
bool header_parsed() const
Check header of current websocket message is parsed.
constexpr size_t websocket_short_ext_payload_length
std::uint64_t payload_len() const
Get payload len.
void process_first_2_bytes()
Process first two bytes of message.
expected_data_t(size_t expected_size)
std::uint8_t m_payload_len
Payload len.
void reset()
Reset internal state.
constexpr size_t websocket_masking_key_size
expected_data_t()=default
bool m_rsv1_flag
Reserved flags.
void set_masking_key(std::uint32_t value)
Set masking key.
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 ¶ms, string_view_t key)
Gets the value of a parameter specified by key wrapped in optional_t<Value_Type> if parameter exists ...