aboutsummaryrefslogtreecommitdiff
path: root/src/zenhttp/servers/wsframecodec.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2026-02-27 14:05:46 +0100
committerStefan Boberg <[email protected]>2026-02-27 14:05:46 +0100
commitee12fa3e2f34cb0a5b0ccb2b7b444ec5fa158f8e (patch)
tree829bf13c20eaf2198272fa9f73a1428feabb58e6 /src/zenhttp/servers/wsframecodec.cpp
parentMeasureLatency now bails out quickly if it experiences a connection error (diff)
downloadzen-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.cpp64
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)
//