Skip to content

Commit

Permalink
fix(ws_transport): Fix reading WS header bytes
Browse files Browse the repository at this point in the history
Correct split header bytes

When the underlying transport returns header,
length, or mask bytes early, again call the
underlying transport.

This solves the WS parser getting offset when
the server sends a burst of frames where the
last WS header is split across packet boundaries,
so fewer than the needed bytes may be available.

Merges #14706
  • Loading branch information
bryghtlabs-richard authored and david-cermak committed Nov 12, 2024
1 parent 190939e commit 7f54410
Showing 1 changed file with 32 additions and 4 deletions.
36 changes: 32 additions & 4 deletions components/tcp_transport/transport_ws.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,34 @@ static int esp_transport_read_internal(transport_ws_t *ws, char *buffer, int len
return to_read;
}

static int esp_transport_read_exact_size(transport_ws_t *ws, char *buffer, int requested_len, int timeout_ms)
{
int total_read = 0;
int len = requested_len;

while (len > 0) {
int bytes_read = esp_transport_read_internal(ws, buffer, len, timeout_ms);

if (bytes_read < 0) {
return bytes_read; // Return error from the underlying read
}

if (bytes_read == 0) {
// If we read 0 bytes, we return an error, since reading exact number of bytes resulted in a timeout operation
ESP_LOGW(TAG, "Requested to read %d, actually read %d bytes", requested_len, total_read);
return -1;
}

// Update buffer and remaining length
buffer += bytes_read;
len -= bytes_read;
total_read += bytes_read;

ESP_LOGV(TAG, "Read fragment of %d bytes", bytes_read);
}
return total_read;
}

static char *trimwhitespace(char *str)
{
char *end;
Expand Down Expand Up @@ -486,7 +514,7 @@ static int ws_read_header(esp_transport_handle_t t, char *buffer, int len, int t
// Receive and process header first (based on header size)
int header = 2;
int mask_len = 4;
if ((rlen = esp_transport_read_internal(ws, data_ptr, header, timeout_ms)) <= 0) {
if ((rlen = esp_transport_read_exact_size(ws, data_ptr, header, timeout_ms)) <= 0) {
ESP_LOGE(TAG, "Error read data");
return rlen;
}
Expand All @@ -500,15 +528,15 @@ static int ws_read_header(esp_transport_handle_t t, char *buffer, int len, int t
ESP_LOGD(TAG, "Opcode: %d, mask: %d, len: %d", ws->frame_state.opcode, mask, payload_len);
if (payload_len == 126) {
// headerLen += 2;
if ((rlen = esp_transport_read_internal(ws, data_ptr, header, timeout_ms)) <= 0) {
if ((rlen = esp_transport_read_exact_size(ws, data_ptr, header, timeout_ms)) <= 0) {
ESP_LOGE(TAG, "Error read data");
return rlen;
}
payload_len = (uint8_t)data_ptr[0] << 8 | (uint8_t)data_ptr[1];
} else if (payload_len == 127) {
// headerLen += 8;
header = 8;
if ((rlen = esp_transport_read_internal(ws, data_ptr, header, timeout_ms)) <= 0) {
if ((rlen = esp_transport_read_exact_size(ws, data_ptr, header, timeout_ms)) <= 0) {
ESP_LOGE(TAG, "Error read data");
return rlen;
}
Expand All @@ -523,7 +551,7 @@ static int ws_read_header(esp_transport_handle_t t, char *buffer, int len, int t

if (mask) {
// Read and store mask
if (payload_len != 0 && (rlen = esp_transport_read_internal(ws, buffer, mask_len, timeout_ms)) <= 0) {
if (payload_len != 0 && (rlen = esp_transport_read_exact_size(ws, buffer, mask_len, timeout_ms)) <= 0) {
ESP_LOGE(TAG, "Error read data");
return rlen;
}
Expand Down

0 comments on commit 7f54410

Please sign in to comment.