27void memmask(
char*
dst,
char const*
src,
size_t size, uint32_t
mask)
30 char*
m = (
char*)&
mask;
41 char*
m = (
char*)&
mask;
53 char* startPayload =
nullptr;
54 int maskSize =
mask ? 4 : 0;
57 headerSize =
sizeof(WebSocketFrameTiny);
61 outputs.push_back(uv_buf_init(chunk, 0));
63 auto&
buf = outputs.back();
66 buf.len += headerSize +
size + maskSize;
67 WebSocketFrameTiny* header = (WebSocketFrameTiny*)
buffer;
68 memset(
buffer, 0, headerSize);
70 }
else if (
size < 1 << 16) {
71 headerSize =
sizeof(WebSocketFrameShort);
75 outputs.push_back(uv_buf_init(chunk, 0));
77 auto&
buf = outputs.back();
80 buf.len += headerSize +
size + maskSize;
81 WebSocketFrameShort* header = (WebSocketFrameShort*)
buffer;
82 memset(
buffer, 0, headerSize);
84 header->len16 = htons(
size);
88 headerSize =
sizeof(WebSocketFrameHuge);
89 buffer = (
char*)malloc(headerSize + maskSize +
size);
90 WebSocketFrameHuge* header = (WebSocketFrameHuge*)
buffer;
91 memset(
buffer, 0, headerSize);
94 outputs.push_back(uv_buf_init(
buffer,
size + maskSize + headerSize));
96 size_t fullHeaderSize = maskSize + headerSize;
97 startPayload =
buffer + fullHeaderSize;
98 WebSocketFrameTiny* header = (WebSocketFrameTiny*)
buffer;
100 header->opcode = (
unsigned char)opcode;
103 *((uint32_t*)(startPayload - 4)) =
mask;
105 header->mask =
mask ? 1 : 0;
123 delete[] pendingFull;
146 WebSocketFrameTiny* header = (WebSocketFrameTiny*)cur;
147 size_t payloadSize = 0;
148 size_t headerSize = 0;
150 ((cur + 2 + 2 -
start >=
size) && header->len >= 126) ||
151 ((cur + 2 + 8 -
start >=
size) && header->len == 127)) {
159 if (header->len < 126) {
160 payloadSize = header->len;
161 headerSize = 2 + (header->mask ? 4 : 0);
162 }
else if (header->len == 126) {
163 WebSocketFrameShort* headerSmall = (WebSocketFrameShort*)cur;
164 payloadSize = ntohs(headerSmall->len16);
165 headerSize = 2 + 2 + (header->mask ? 4 : 0);
166 }
else if (header->len == 127) {
167 WebSocketFrameHuge* headerSmall = (WebSocketFrameHuge*)cur;
168 payloadSize =
ntohll(headerSmall->len64);
169 headerSize = 2 + 8 + (header->mask ? 4 : 0);
171 size_t availableSize =
size - (cur -
start);
172 if (availableSize < payloadSize + headerSize) {
173 handler.
remainingSize = payloadSize + headerSize - availableSize;
180 int32_t
mask = *(int32_t*)(cur + headerSize - 4);
181 memunmask(cur + headerSize, payloadSize,
mask);
183 handler.
frame(cur + headerSize, payloadSize);
184 cur += headerSize + payloadSize;
190 std::vector<std::pair<std::string, std::string>> headers)
193 "GET {} HTTP/1.1\r\n"
194 "Upgrade: websocket\r\n"
195 "Connection: Upgrade\r\n"
196 "Sec-WebSocket-Key: {}\r\n"
197 "Sec-WebSocket-Protocol: {}\r\n"
198 "Sec-WebSocket-Version: {}\r\n"
200 std::string encodedHeaders;
201 for (
auto [k,
v] : headers) {
202 encodedHeaders += std::string(fmt::format(
"{}: {}\r\n", k,
v));
209 std::string reply = std::string(nonce) +
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
211 SHA1(sha, reply.data(), reply.size());
214 return fmt::format(
"{}", base);
220 "HTTP/1.1 101 Switching Protocols\r\n"
221 "Upgrade: websocket\r\n"
222 "Connection: Upgrade\r\n"
223 "Access-Control-Allow-Origin: \"*\"\r\n"
224 "Sec-WebSocket-Accept: {}\r\n\r\n";
237 std::string_view lastToken(cur, 0);
238 std::string_view lastKey;
239 std::string_view lastValue;
240 std::string lastError;
241 if (parser->
states.empty()) {
244 char const* delimiters =
nullptr;
245 char const* skippable =
nullptr;
246 char const* separator =
nullptr;
247 char const* spaces =
"\t \v";
248 char const* colon =
":";
249 char const* newline =
"\r\n";
254 parser->
states.pop_back();
299 parser->
method(lastToken);
310 parser->
target(lastToken);
347 lastValue = lastToken;
351 if (strncmp(
"\r\n", next, 2) == 0) {
352 parser->
header(lastKey, lastValue);
357 parser->
header(lastKey, lastValue);
368 parser->
body(cur, bodySize);
369 next = cur + bodySize;
377 parser->
remaining += std::string_view(cur, next - cur);
379 if (strchr(skippable, *next)) {
388 if (memcmp(separator, cur, strlen(separator)) != 0) {
392 next += strlen(separator);
398 parser->
remaining += std::string_view(cur, next - cur);
400 if (strchr(delimiters, *next) ==
nullptr) {
404 lastToken = std::string_view(cur, next - cur);
411 if (next + strlen(separator) -
start ==
size) {
412 parser->
remaining += std::string_view(cur, next - cur);
414 if (memcmp(separator, next, strlen(separator)) != 0) {
418 lastToken = std::string_view(cur, next - cur);
419 next += strlen(separator);
429 }
else if (parser->
states.empty()) {
436 parser->
error = lastError;
451 s =
"ws://127.0.0.1:8080";
453 const std::regex urlMatcher(
"^ws://([0-9-_.]+)[:]([0-9]+)$");
455 if (!std::regex_match(s, parts, urlMatcher)) {
457 "Unable to parse driver client url: %s.\n"
458 "Format should be ws://[<driver ip>:<port>] e.g. ws://127.0.0.1:8080 or just ws://");
460 std::string ip = std::string{parts[1]};
461 auto portS = std::string(parts[2]);
462 unsigned short port = std::stoul(portS);
GLenum GLenum GLsizei len
GLenum GLuint GLenum GLsizei const GLchar * buf
int base64_encode(char *dest, int size, unsigned char *src, int slen)
Defining PrimaryVertex explicitly as messageable.
@ IN_SEPARATOR
capture until a specific "separator"
@ IN_CAPTURE_SEPARATOR
capture until any or the "delimiters" characters
@ IN_CAPTURE_DELIMITERS
skip any "delimiters" char.
void encode_websocket_frames(std::vector< uv_buf_t > &outputs, char const *src, size_t size, WebSocketOpCode opcode, uint32_t mask)
std::pair< std::string, unsigned short > parse_websocket_url(char const *url)
std::string encode_websocket_handshake_reply(char const *nonce)
void parse_http_request(char *start, size_t size, HTTPParser *parser)
std::string encode_websocket_handshake_request(const char *endpoint, const char *protocol, int version, char const *nonce, std::vector< std::pair< std::string, std::string > > headers)
void decode_websocket(char *start, size_t size, WebSocketHandler &handler)
RuntimeErrorRef runtime_error_f(const char *,...)
static std::string calculateAccept(const char *nonce)
Helper to calculate the reply to a nonce.
virtual void replyVersion(std::string_view const &s)
virtual void header(std::string_view const &k, std::string_view const &v)
virtual void method(std::string_view const &s)
virtual void replyCode(std::string_view const &s)
virtual void endHeaders()
virtual void body(char *data, size_t s)
virtual void target(std::string_view const &s)
std::vector< HTTPState > states
virtual void replyMessage(std::string_view const &s)
virtual void version(std::string_view const &s)
static constexpr size_t MaxChunkSize
An handler for a websocket message stream.
size_t pendingHeaderSize
Bytes from an incomplete header.
virtual void endChunk()
Invoked whenever we have no more input to process.
virtual void frame(char const *frame, size_t s)
char * pendingBuffer
A buffer large enough to contain the next frame to be processed.
size_t remainingSize
Bytes which are still to be received for the previous, half delivered frame.
size_t pendingSize
Bytes which are already there from the previous, half delivered frame.
virtual void beginChunk()
Invoked before processing the next round of input.