diff options
| author | Stefan Boberg <[email protected]> | 2026-02-27 14:05:46 +0100 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2026-02-27 14:05:46 +0100 |
| commit | ee12fa3e2f34cb0a5b0ccb2b7b444ec5fa158f8e (patch) | |
| tree | 829bf13c20eaf2198272fa9f73a1428feabb58e6 /src/zenhttp/servers/wsframecodec.cpp | |
| parent | MeasureLatency now bails out quickly if it experiences a connection error (diff) | |
| download | zen-ee12fa3e2f34cb0a5b0ccb2b7b444ec5fa158f8e.tar.xz zen-ee12fa3e2f34cb0a5b0ccb2b7b444ec5fa158f8e.zip | |
added Websocket client HttpWsClient
implemented in terms of asio
Diffstat (limited to 'src/zenhttp/servers/wsframecodec.cpp')
| -rw-r--r-- | src/zenhttp/servers/wsframecodec.cpp | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/src/zenhttp/servers/wsframecodec.cpp b/src/zenhttp/servers/wsframecodec.cpp index 80045c576..a4c5e0f16 100644 --- a/src/zenhttp/servers/wsframecodec.cpp +++ b/src/zenhttp/servers/wsframecodec.cpp @@ -6,6 +6,7 @@ #include <zencore/sha1.h> #include <cstring> +#include <random> namespace zen { @@ -137,6 +138,69 @@ WsFrameCodec::BuildCloseFrame(uint16_t Code, std::string_view Reason) ////////////////////////////////////////////////////////////////////////// // +// Frame building (client-to-server, with masking) +// + +std::vector<uint8_t> +WsFrameCodec::BuildMaskedFrame(WebSocketOpcode Opcode, std::span<const uint8_t> Payload) +{ + std::vector<uint8_t> Frame; + + const size_t PayloadLen = Payload.size(); + + // FIN + opcode + Frame.push_back(0x80 | static_cast<uint8_t>(Opcode)); + + // Payload length with mask bit set + if (PayloadLen < 126) + { + Frame.push_back(0x80 | static_cast<uint8_t>(PayloadLen)); + } + else if (PayloadLen <= 0xFFFF) + { + Frame.push_back(0x80 | 126); + Frame.push_back(static_cast<uint8_t>((PayloadLen >> 8) & 0xFF)); + Frame.push_back(static_cast<uint8_t>(PayloadLen & 0xFF)); + } + else + { + Frame.push_back(0x80 | 127); + for (int i = 7; i >= 0; --i) + { + Frame.push_back(static_cast<uint8_t>((PayloadLen >> (i * 8)) & 0xFF)); + } + } + + // Generate random 4-byte mask key + static thread_local std::mt19937 s_Rng(std::random_device{}()); + uint32_t MaskValue = s_Rng(); + uint8_t MaskKey[4]; + std::memcpy(MaskKey, &MaskValue, 4); + + Frame.insert(Frame.end(), MaskKey, MaskKey + 4); + + // Masked payload + for (size_t i = 0; i < PayloadLen; ++i) + { + Frame.push_back(Payload[i] ^ MaskKey[i & 3]); + } + + return Frame; +} + +std::vector<uint8_t> +WsFrameCodec::BuildMaskedCloseFrame(uint16_t Code, std::string_view Reason) +{ + std::vector<uint8_t> Payload; + Payload.push_back(static_cast<uint8_t>((Code >> 8) & 0xFF)); + Payload.push_back(static_cast<uint8_t>(Code & 0xFF)); + Payload.insert(Payload.end(), Reason.begin(), Reason.end()); + + return BuildMaskedFrame(WebSocketOpcode::kClose, Payload); +} + +////////////////////////////////////////////////////////////////////////// +// // Sec-WebSocket-Accept key computation (RFC 6455 section 4.2.2) // |