Validate WebSocket continuation frame sequencing

This commit is contained in:
robert committed 2026-09-21 15:32:10 +03:00
1 parent bbee8ae61f
commit 60c75a22b8
4 files changed
+31 -6

No files matched your search

+6
View File
@@ -27032,6 +27032,12 @@ static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data) {
op = msg.flags & 15;
// MG_VERBOSE ("fin %d op %d len %d [%.*s]", final, op,
// (int) m.data.len, (int) m.data.len, m.data.buf));
if ((op == WEBSOCKET_OP_CONTINUE && ofs == 0) ||
((op == WEBSOCKET_OP_TEXT || op == WEBSOCKET_OP_BINARY) &&
ofs != 0)) {
mg_error(c, "invalid WS fragment sequence");
return;
}
switch (op) {
case WEBSOCKET_OP_CONTINUE:
mg_call(c, MG_EV_WS_CTL, &m);
+4 -5
View File
@@ -2838,9 +2838,9 @@ int mg_http_status(const struct mg_http_message *hm);
// Streams a POST/PUT body to a callback as it arrives, without buffering it.
// Call it from your connection handler on every event.
//
// Callback cb(hm, data, &user_data) is called:
// - at start: hm is set, data is NULL. Open the file, set *user_data.
// - per chunk: hm is NULL, data is set. Chunks are multiples of 512 bytes,
// Callback upload_fn(hm, data, user_data) is called:
// - at start: hm is set, data is NULL. Open the file, set user_data.
// - per chunk: hm is NULL, data is set. Chunks are 512 bytes aligned
// except the last one.
// - at end: both NULL. Close the file.
// After the last chunk, "200 ok" is sent and the connection is drained.
@@ -2852,8 +2852,7 @@ int mg_http_status(const struct mg_http_message *hm);
// mg_http_start_upload(), mg_http_start_ota()
// Notes:
// Requires Content-Length, chunked bodies are not streamed. user_data is
// c->fn_data. While streaming, c->pfn is NULL, so guard your own
// MG_EV_HTTP_MSG handling with c->pfn != NULL.
// &c->fn_data. While streaming, c->pfn is NULL
void mg_http_stream_body(struct mg_connection *c, int ev, void *ev_data,
struct mg_str uri_pattern,
void (*upload_fn)(struct mg_http_message *,
+6
View File
@@ -182,6 +182,12 @@ static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data) {
op = msg.flags & 15;
// MG_VERBOSE ("fin %d op %d len %d [%.*s]", final, op,
// (int) m.data.len, (int) m.data.len, m.data.buf));
if ((op == WEBSOCKET_OP_CONTINUE && ofs == 0) ||
((op == WEBSOCKET_OP_TEXT || op == WEBSOCKET_OP_BINARY) &&
ofs != 0)) {
mg_error(c, "invalid WS fragment sequence");
return;
}
switch (op) {
case WEBSOCKET_OP_CONTINUE:
mg_call(c, MG_EV_WS_CTL, &m);
+15 -1
View File
@@ -967,7 +967,7 @@ static void wcb(struct mg_connection *c, int ev, void *ev_data) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
struct mg_str *wsproto = mg_http_get_header(hm, "Sec-WebSocket-Protocol");
ASSERT(wsproto != NULL);
mg_ws_send(c, "hello", 0, 0);
mg_ws_send(c, "", 0, WEBSOCKET_OP_TEXT);
mg_ws_printf(c, WEBSOCKET_OP_BINARY, "%.3s", "boo!!!!");
mg_ws_printf(c, WEBSOCKET_OP_BINARY, "%s", "foobar");
mg_ws_send(c, "", 0, WEBSOCKET_OP_PING);
@@ -983,6 +983,15 @@ static void wcb(struct mg_connection *c, int ev, void *ev_data) {
}
}
static void wbad(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_WS_OPEN) {
mg_ws_send(c, "ABC", 3, WEBSOCKET_OP_CONTINUE);
} else if (ev == MG_EV_CLOSE) {
*(int *) c->fn_data = 1;
}
(void) ev_data;
}
static void ew2(struct mg_connection *c, int ev, void *ev_data) {
size_t size = 65 * 1024 + 737;
if (ev == MG_EV_WS_OPEN) {
@@ -1028,6 +1037,11 @@ static void test_ws(void) {
for (i = 0; i < 1000 && done == 0; i++) mg_mgr_poll(&mgr, 1);
ASSERT(done == 1);
done = 0;
mg_ws_connect(&mgr, url, wbad, &done, NULL);
for (i = 0; i < 30 && done == 0; i++) mg_mgr_poll(&mgr, 1);
ASSERT(done == 1);
mg_mgr_free(&mgr);
ASSERT(mgr.conns == NULL);
}