15 constexpr uint8_t FIN_BIT = 0x80;
16 constexpr uint8_t RSV1_BIT = 0x40;
17 constexpr uint8_t RSV2_BIT = 0x20;
18 constexpr uint8_t RSV3_BIT = 0x10;
19 constexpr uint8_t OPCODE_MASK = 0x0F;
20 constexpr uint8_t MASK_BIT = 0x80;
21 constexpr uint8_t PAYLOAD_LEN_MASK = 0x7F;
23 constexpr uint8_t PAYLOAD_LEN_16BIT = 126;
24 constexpr uint8_t PAYLOAD_LEN_64BIT = 127;
27 constexpr size_t MIN_HEADER_SIZE = 2;
28 constexpr size_t MASKING_KEY_SIZE = 4;
33 auto to_network_u16(uint16_t value) -> std::array<uint8_t, 2>
35 return {
static_cast<uint8_t
>((value >> 8) & 0xFF),
36 static_cast<uint8_t
>(value & 0xFF)};
42 auto to_network_u64(uint64_t value) -> std::array<uint8_t, 8>
44 return {
static_cast<uint8_t
>((value >> 56) & 0xFF),
45 static_cast<uint8_t
>((value >> 48) & 0xFF),
46 static_cast<uint8_t
>((value >> 40) & 0xFF),
47 static_cast<uint8_t
>((value >> 32) & 0xFF),
48 static_cast<uint8_t
>((value >> 24) & 0xFF),
49 static_cast<uint8_t
>((value >> 16) & 0xFF),
50 static_cast<uint8_t
>((value >> 8) & 0xFF),
51 static_cast<uint8_t
>(value & 0xFF)};
57 auto from_network_u16(
const uint8_t* data) -> uint16_t
59 return static_cast<uint16_t
>((
data[0] << 8) |
data[1]);
65 auto from_network_u64(
const uint8_t* data) -> uint64_t
67 return (
static_cast<uint64_t
>(data[0]) << 56) |
68 (
static_cast<uint64_t
>(
data[1]) << 48) |
69 (
static_cast<uint64_t
>(data[2]) << 40) |
70 (
static_cast<uint64_t
>(
data[3]) << 32) |
71 (
static_cast<uint64_t
>(data[4]) << 24) |
72 (
static_cast<uint64_t
>(
data[5]) << 16) |
73 (
static_cast<uint64_t
>(data[6]) << 8) | (
static_cast<uint64_t
>(
data[7]));
80 size_t header_size = MIN_HEADER_SIZE;
82 if (payload_len >= 65536)
86 else if (payload_len >= 126)
93 header_size += MASKING_KEY_SIZE;
100 bool fin,
bool mask) -> std::vector<uint8_t>
102 const uint64_t payload_len = payload.size();
103 const size_t header_size = calculate_header_size(payload_len, mask);
105 std::vector<uint8_t>
frame;
106 frame.reserve(header_size + payload_len);
109 uint8_t byte0 =
static_cast<uint8_t
>(opcode);
114 frame.push_back(byte0);
123 if (payload_len < 126)
125 byte1 |=
static_cast<uint8_t
>(payload_len);
126 frame.push_back(byte1);
128 else if (payload_len < 65536)
130 byte1 |= PAYLOAD_LEN_16BIT;
131 frame.push_back(byte1);
134 auto len_bytes = to_network_u16(
static_cast<uint16_t
>(payload_len));
135 frame.insert(
frame.end(), len_bytes.begin(), len_bytes.end());
139 byte1 |= PAYLOAD_LEN_64BIT;
140 frame.push_back(byte1);
143 auto len_bytes = to_network_u64(payload_len);
144 frame.insert(
frame.end(), len_bytes.begin(), len_bytes.end());
148 std::array<uint8_t, 4> masking_key{};
151 masking_key = generate_mask();
152 frame.insert(
frame.end(), masking_key.begin(), masking_key.end());
155 apply_mask(payload, masking_key);
159 frame.insert(
frame.end(), payload.begin(), payload.end());
165 -> std::optional<ws_frame_header>
167 if (data.size() < MIN_HEADER_SIZE)
175 const uint8_t byte0 = data[0];
176 header.fin = (byte0 & FIN_BIT) != 0;
177 header.rsv1 = (byte0 & RSV1_BIT) != 0;
178 header.rsv2 = (byte0 & RSV2_BIT) != 0;
179 header.rsv3 = (byte0 & RSV3_BIT) != 0;
180 header.opcode =
static_cast<ws_opcode>(byte0 & OPCODE_MASK);
183 const uint8_t byte1 = data[1];
184 header.mask = (byte1 & MASK_BIT) != 0;
185 uint8_t payload_len = byte1 & PAYLOAD_LEN_MASK;
187 size_t offset = MIN_HEADER_SIZE;
190 if (payload_len == PAYLOAD_LEN_16BIT)
192 if (data.size() < offset + 2)
196 header.payload_len = from_network_u16(&data[offset]);
199 else if (payload_len == PAYLOAD_LEN_64BIT)
201 if (data.size() < offset + 8)
205 header.payload_len = from_network_u64(&data[offset]);
210 header.payload_len = payload_len;
216 if (data.size() < offset + MASKING_KEY_SIZE)
220 std::copy_n(data.begin() + offset, MASKING_KEY_SIZE, header.masking_key.begin());
227 const std::vector<uint8_t>& data)
228 -> std::vector<uint8_t>
230 const size_t header_size = calculate_header_size(header.payload_len, header.mask);
232 if (data.size() < header_size + header.payload_len)
237 std::vector<uint8_t> payload(data.begin() + header_size,
238 data.begin() + header_size + header.payload_len);
243 apply_mask(payload, header.masking_key);
250 const std::array<uint8_t, 4>& mask) ->
void
252 for (
size_t i = 0; i < data.size(); ++i)
254 data[i] ^= mask[i % 4];
260 static thread_local std::random_device rd;
261 static thread_local std::mt19937 gen(rd());
262 static thread_local std::uniform_int_distribution<uint32_t> dis;
264 const uint32_t random_value = dis(gen);
265 return {
static_cast<uint8_t
>((random_value >> 24) & 0xFF),
266 static_cast<uint8_t
>((random_value >> 16) & 0xFF),
267 static_cast<uint8_t
>((random_value >> 8) & 0xFF),
268 static_cast<uint8_t
>(random_value & 0xFF)};
static auto generate_mask() -> std::array< uint8_t, 4 >
Generates a random 4-byte masking key.
static auto encode_frame(ws_opcode opcode, std::vector< uint8_t > &&payload, bool fin=true, bool mask=false) -> std::vector< uint8_t >
Encodes data into a WebSocket frame.
static auto decode_payload(const ws_frame_header &header, const std::vector< uint8_t > &data) -> std::vector< uint8_t >
Decodes the payload from a WebSocket frame.
static auto calculate_header_size(uint64_t payload_len, bool mask) -> size_t
Calculates the size of the frame header.
static auto apply_mask(std::vector< uint8_t > &data, const std::array< uint8_t, 4 > &mask) -> void
Applies or removes XOR masking on data.
static auto decode_header(const std::vector< uint8_t > &data) -> std::optional< ws_frame_header >
Decodes a WebSocket frame header from raw data.
ws_opcode
WebSocket frame operation codes as defined in RFC 6455.
std::variant< padding_frame, ping_frame, ack_frame, reset_stream_frame, stop_sending_frame, crypto_frame, new_token_frame, stream_frame, max_data_frame, max_stream_data_frame, max_streams_frame, data_blocked_frame, stream_data_blocked_frame, streams_blocked_frame, new_connection_id_frame, retire_connection_id_frame, path_challenge_frame, path_response_frame, connection_close_frame, handshake_done_frame > frame
Variant type holding any QUIC frame.