fix(ws): validate CLOSE frame semantics, echo payload, validate UTF-8 text

This commit is contained in:
Ashish Sharma
2026-09-04 16:24:38 +08:00
parent ba2b9256e2
commit d0e35277dd
8 changed files with 363 additions and 130 deletions
@@ -69,9 +69,21 @@ httpd_ws_recv_frame(req, &ws_pkt, MAX_PAYLOAD_LEN);
2) Allocate the size based on the received packet length
3) Call `httpd_ws_recv_frame()` with the allocated buffer
#### Fragmented messages
The WebSocket HTTP server does not support fragmented messages, as [RFC6455, section 5.4](https://tools.ietf.org/html/rfc6455#section-5.4) defines them.
On receive, the server passes each frame to the handler on its own. It does not join the fragments of one message. A handler that gets a message in three fragments sees three separate frames. Use the `final` and `fragmented` fields of `httpd_ws_frame_t` to detect a fragment, and join the payloads in the application.
The server also does not validate the fragment sequence. It accepts a CONTINUE frame that continues no message. It also accepts a new TEXT or BINARY frame while a fragmented message is still open. RFC 6455 requires a close with status code 1002 in both cases.
`CONFIG_HTTPD_WS_STRICTER_RFC6455` validates the UTF-8 of a complete, unfragmented TEXT frame only. It does not validate a TEXT message that arrives in fragments. Join the fragments and call `httpd_ws_validate_utf8()` on the result.
This example echoes each frame as a complete message, so it does not handle fragments either.
#### Handling outgoing data
Please note that the WebSocket HTTP server does not automatically fragment messages.
On transmit, the server does not automatically fragment messages.
Each outgoing frame has the FIN flag set by default.
In case an application wants to send fragmented data, it must be done manually by setting the
`fragmented` option and using the `final` flag as described in [RFC6455, section 5.4](https://tools.ietf.org/html/rfc6455#section-5.4).
@@ -215,9 +215,11 @@ static esp_err_t echo_handler(httpd_req_t *req)
}
}
ret = httpd_ws_send_frame(req, &ws_pkt);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "httpd_ws_send_frame failed with %d", ret);
if (ws_pkt.type == HTTPD_WS_TYPE_TEXT || ws_pkt.type == HTTPD_WS_TYPE_BINARY) {
ret = httpd_ws_send_frame(req, &ws_pkt);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "httpd_ws_send_frame failed with %d", ret);
}
}
free(buf);
return ret;