22void CheckSecWebSocketAccept(
const std::string& allServerHeaders,
const std::string& clientKeyBase64);
87 auto key = GenerateWebSocketKey(Rd);
89 "GET " + path +
" HTTP/1.1\r\n"
90 "Host: " + host +
"\r\n"
91 "User-Agent: coroio\r\n"
93 "Connection: Upgrade\r\n"
94 "Upgrade: websocket\r\n"
95 "Sec-WebSocket-Key: " + key +
"\r\n"
96 "Sec-WebSocket-Version: 13\r\n\r\n";
98 co_await Writer.Write(request.data(), request.size());
100 auto response =
co_await Reader.ReadUntil(
"\r\n\r\n");
102 CheckSecWebSocketAccept(response, key);
104 if (response.find(
"101 Switching Protocols") == std::string::npos) {
105 throw std::runtime_error(
"Failed to establish WebSocket connection");
118 co_await SendFrame(0x1, message);
130 auto [opcode, payload] =
co_await ReceiveFrame();
132 throw std::runtime_error(
133 "Unexpected opcode: " +
134 std::to_string(opcode) +
135 " , expected text frame, got: '" +
136 std::string(payload) +
"'");
145 std::random_device Rd;
147 std::vector<uint8_t> Frame;
149 TFuture<void> SendFrame(uint8_t opcode, std::string_view payload) {
151 Frame.push_back(0x80 | opcode);
153 uint8_t maskingKey[4];
154 for (
int i = 0; i < 4; ++i) {
155 maskingKey[i] =
static_cast<uint8_t
>(Rd());
158 if (payload.size() <= 125) {
159 Frame.push_back(0x80 |
static_cast<uint8_t
>(payload.size()));
160 }
else if (payload.size() <= 0xFFFF) {
161 Frame.push_back(0x80 | 126);
162 uint16_t length = htons(
static_cast<uint16_t
>(payload.size()));
163 Frame.insert(Frame.end(),
reinterpret_cast<uint8_t*
>(&length),
reinterpret_cast<uint8_t*
>(&length) + 2);
165 Frame.push_back(0x80 | 127);
166 uint64_t length = htonll(payload.size());
167 Frame.insert(Frame.end(),
reinterpret_cast<uint8_t*
>(&length),
reinterpret_cast<uint8_t*
>(&length) + 8);
170 Frame.insert(Frame.end(), std::begin(maskingKey), std::end(maskingKey));
172 for (
size_t i = 0; i < payload.size(); ++i) {
173 Frame.push_back(payload[i] ^ maskingKey[i % 4]);
176 co_await Writer.Write(Frame.data(), Frame.size());
180 TFuture<std::pair<uint8_t, std::string_view>> ReceiveFrame() {
182 co_await Reader.Read(header,
sizeof(header));
184 uint8_t opcode = header[0] & 0x0F;
185 bool masked = header[1] & 0x80;
186 uint64_t payloadLength = header[1] & 0x7F;
188 if (payloadLength == 126) {
189 uint16_t extendedLength;
190 co_await Reader.Read(&extendedLength,
sizeof(extendedLength));
191 payloadLength = ntohs(extendedLength);
192 }
else if (payloadLength == 127) {
193 uint64_t extendedLength;
194 co_await Reader.Read(&extendedLength,
sizeof(extendedLength));
195 payloadLength = ntohll(extendedLength);
198 uint8_t mask[4] = {0};
200 co_await Reader.Read(mask,
sizeof(mask));
203 Payload.resize(payloadLength);
204 co_await Reader.Read(Payload.data(), Payload.size());
207 for (
size_t i = 0; i < Payload.size(); ++i) {
208 Payload[i] ^= mask[i % 4];
212 co_return {opcode, Payload};
A utility for reading data from a socket-like object, either a fixed number of bytes or until a speci...
Definition sockutils.hpp:55