Saw a websocket message go across the wire with this.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4694 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2023-12-24 22:06:11 +00:00
parent 606e82d718
commit adf8c14536

View File

@ -43,6 +43,7 @@ typedef struct _tf_http_connection_t
tf_http_callback_t* callback; tf_http_callback_t* callback;
void* user_data; void* user_data;
bool is_websocket;
void* body; void* body;
size_t body_length; size_t body_length;
size_t content_length; size_t content_length;
@ -170,35 +171,113 @@ static void _http_reset_connection(tf_http_connection_t* connection)
static void _http_add_body_bytes(tf_http_connection_t* connection, const void* data, size_t size) static void _http_add_body_bytes(tf_http_connection_t* connection, const void* data, size_t size)
{ {
size_t fit = tf_min(connection->content_length - connection->body_length, size); if (connection->is_websocket)
if (fit > 0)
{ {
memcpy((char*)connection->body + connection->body_length, data, fit); connection->body = tf_realloc(connection->body, connection->body_length + size);
connection->body_length += fit; memcpy((char*)connection->body + connection->body_length, data, size);
} connection->body_length += size;
if (connection->body_length == connection->content_length) uint8_t* p = connection->body;
{ while (connection->body_length >= 2)
tf_http_request_t* request = tf_malloc(sizeof(tf_http_request_t));
*request = (tf_http_request_t)
{ {
.connection = connection, uint8_t bits0 = p[0];
.phase = k_http_callback_phase_headers_received, uint8_t bits1 = p[1];
.method = connection->method, if ((bits1 & (1 << 7)) == 0)
.path = connection->path, {
.flags = connection->flags, /* Unmasked message. */
.query = connection->query, _http_connection_destroy(connection);
.body = connection->body, return;
.content_length = connection->content_length, }
.headers = connection->headers, uint8_t opcode = bits0 & 0xf;
.headers_count = connection->headers_length, bool fin = (bits0 & (1 << 7)) != 0;
.user_data = connection->user_data, size_t length = bits1 & 0x7f;
}; int mask_start = 2;
tf_http_request_ref(request); if (length == 126)
connection->callback(request); {
tf_http_request_release(request); length = 0;
_http_reset_connection(connection); for (int i = 0; i < 2; i++)
{
length <<= 8;
length |= p[2 + i];
}
mask_start = 4;
}
else if (length == 127)
{
length = 0;
for (int i = 0; i < 8; i++)
{
length <<= 8;
length |= p[2 + i];
}
mask_start = 10;
}
if (connection->body_length >= length + 2 + 4)
{
uint32_t mask =
p[mask_start + 0] |
p[mask_start + 1] << 8 |
p[mask_start + 2] << 16 |
p[mask_start + 3] << 24;
size_t i = 0;
for (i = mask_start + 4; i < length; i += 4)
{
*(uint32_t*)(p + i) ^= mask;
}
for (; i < length; i++)
{
p[i] ^= ((mask >> (8 * (i % 4))) & 0xff);
}
if (fin)
{
tf_printf("MESSAGE %d [%.*s]\n", opcode, (int)length, p + mask_start + 4);
}
size_t total_length + mask_Start + 4 + length;
memmove(connection->body, (char*)connection->body + total_length, connection->body_length - total_length);
connection->body_length -= total_length;
}
}
}
else
{
size_t fit = tf_min(connection->content_length - connection->body_length, size);
if (fit > 0)
{
memcpy((char*)connection->body + connection->body_length, data, fit);
connection->body_length += fit;
}
if (connection->body_length == connection->content_length)
{
if (connection->flags & k_tf_http_handler_flag_websocket)
{
connection->is_websocket = true;
}
tf_http_request_t* request = tf_malloc(sizeof(tf_http_request_t));
*request = (tf_http_request_t)
{
.connection = connection,
.phase = k_http_callback_phase_headers_received,
.method = connection->method,
.path = connection->path,
.flags = connection->flags,
.query = connection->query,
.body = connection->body,
.content_length = connection->content_length,
.headers = connection->headers,
.headers_count = connection->headers_length,
.user_data = connection->user_data,
};
tf_http_request_ref(request);
connection->callback(request);
tf_http_request_release(request);
if (!connection->is_websocket)
{
_http_reset_connection(connection);
}
}
} }
} }