mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
Merge branch 'bugfix/transport_ws_ping_pong' into 'master'
fix(transport_ws): fix stream desync and chunked delivery of control frames Closes IDFGH-16946 See merge request espressif/esp-idf!46972
This commit is contained in:
@@ -556,6 +556,7 @@ static int esp_transport_read_exact_size(transport_ws_t *ws, char *buffer, int r
|
|||||||
|
|
||||||
|
|
||||||
/* Read and parse the WS header, determine length of payload */
|
/* Read and parse the WS header, determine length of payload */
|
||||||
|
|
||||||
static int ws_read_header(esp_transport_handle_t t, char *buffer, int len, int timeout_ms)
|
static int ws_read_header(esp_transport_handle_t t, char *buffer, int len, int timeout_ms)
|
||||||
{
|
{
|
||||||
transport_ws_t *ws = esp_transport_get_context_data(t);
|
transport_ws_t *ws = esp_transport_get_context_data(t);
|
||||||
@@ -635,6 +636,16 @@ static int ws_read_header(esp_transport_handle_t t, char *buffer, int len, int t
|
|||||||
if ((ws->frame_state.opcode & WS_OPCODE_CONTROL_FRAME) && payload_len > 125) {
|
if ((ws->frame_state.opcode & WS_OPCODE_CONTROL_FRAME) && payload_len > 125) {
|
||||||
ESP_LOGE(TAG, "Control frame with excessive payload detected (opcode=0x%02X, payload_len=%d) - protocol violation",
|
ESP_LOGE(TAG, "Control frame with excessive payload detected (opcode=0x%02X, payload_len=%d) - protocol violation",
|
||||||
ws->frame_state.opcode, payload_len);
|
ws->frame_state.opcode, payload_len);
|
||||||
|
// Consume the payload bytes from the TCP stream to keep it in sync before returning error
|
||||||
|
int remaining = payload_len;
|
||||||
|
while (remaining > 0 && len > 0) {
|
||||||
|
int to_read = remaining < len ? remaining : len;
|
||||||
|
int bytes_read = esp_transport_read_internal(ws, buffer, to_read, timeout_ms);
|
||||||
|
if (bytes_read <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
remaining -= bytes_read;
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (mask) {
|
if (mask) {
|
||||||
@@ -727,6 +738,24 @@ static int ws_read(esp_transport_handle_t t, char *buffer, int len, int timeout_
|
|||||||
return ws_handle_control_frame_internal(t, timeout_ms);
|
return ws_handle_control_frame_internal(t, timeout_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read the full control frame payload into the caller's buffer in one shot.
|
||||||
|
// This prevents the client from receiving the payload in chunks and
|
||||||
|
// incorrectly echoing only the last chunk as a PONG response.
|
||||||
|
if ((ws->frame_state.opcode & WS_OPCODE_CONTROL_FRAME) && ws->frame_state.payload_len > 0) {
|
||||||
|
int payload_len = ws->frame_state.payload_len;
|
||||||
|
if (payload_len > len) {
|
||||||
|
ESP_LOGE(TAG, "Control frame payload (%d) exceeds caller buffer (%d)", payload_len, len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int bytes_read = esp_transport_read_exact_size(ws, buffer, payload_len, timeout_ms);
|
||||||
|
if (bytes_read != payload_len) {
|
||||||
|
ESP_LOGE(TAG, "Control frame payload read failed (expected=%d, got=%d)", payload_len, bytes_read);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ws->frame_state.bytes_remaining = 0;
|
||||||
|
return payload_len;
|
||||||
|
}
|
||||||
|
|
||||||
if (rlen == 0) {
|
if (rlen == 0) {
|
||||||
ws->frame_state.bytes_remaining = 0;
|
ws->frame_state.bytes_remaining = 0;
|
||||||
return 0; // timeout
|
return 0; // timeout
|
||||||
|
|||||||
Reference in New Issue
Block a user