ws_client: fix fragmented send setting proper opcodes

Previous implementation violated the RFC by having both the actual opcode and WS_FIN flag set for all fragments of a message.
Fixed by setting the opcode only for the first fragment and WS_FIN for the last one

Closes IDFGH-2938
Closes https://github.com/espressif/esp-idf/issues/4974
This commit is contained in:
David Cermak 2020-03-25 21:22:25 +01:00 committed by bot
parent 2ebd93e1d2
commit af839f371f
3 changed files with 10 additions and 5 deletions

View file

@ -471,7 +471,7 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
// if a PING message received -> send out the PONG, this will not work for PING messages with payload longer than buffer len // if a PING message received -> send out the PONG, this will not work for PING messages with payload longer than buffer len
if (client->last_opcode == WS_TRANSPORT_OPCODES_PING) { if (client->last_opcode == WS_TRANSPORT_OPCODES_PING) {
const char *data = (client->payload_len == 0) ? NULL : client->rx_buffer; const char *data = (client->payload_len == 0) ? NULL : client->rx_buffer;
esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PONG, data, client->payload_len, esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PONG | WS_TRANSPORT_OPCODES_FIN, data, client->payload_len,
client->config->network_timeout_ms); client->config->network_timeout_ms);
} }
@ -529,7 +529,7 @@ static void esp_websocket_client_task(void *pv)
if (_tick_get_ms() - client->ping_tick_ms > WEBSOCKET_PING_TIMEOUT_MS) { if (_tick_get_ms() - client->ping_tick_ms > WEBSOCKET_PING_TIMEOUT_MS) {
client->ping_tick_ms = _tick_get_ms(); client->ping_tick_ms = _tick_get_ms();
ESP_LOGD(TAG, "Sending PING..."); ESP_LOGD(TAG, "Sending PING...");
esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PING, NULL, 0, client->config->network_timeout_ms); esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PING | WS_TRANSPORT_OPCODES_FIN, NULL, 0, client->config->network_timeout_ms);
} }
if (read_select == 0) { if (read_select == 0) {
ESP_LOGV(TAG, "Read poll timeout: skipping esp_transport_read()..."); ESP_LOGV(TAG, "Read poll timeout: skipping esp_transport_read()...");
@ -649,22 +649,26 @@ static int esp_websocket_client_send_with_opcode(esp_websocket_client_handle_t c
ESP_LOGE(TAG, "Invalid transport"); ESP_LOGE(TAG, "Invalid transport");
goto unlock_and_return; goto unlock_and_return;
} }
uint32_t current_opcode = opcode;
while (widx < len) { while (widx < len) {
if (need_write > client->buffer_size) { if (need_write > client->buffer_size) {
need_write = client->buffer_size; need_write = client->buffer_size;
} else {
current_opcode |= WS_TRANSPORT_OPCODES_FIN;
} }
memcpy(client->tx_buffer, data + widx, need_write); memcpy(client->tx_buffer, data + widx, need_write);
// send with ws specific way and specific opcode // send with ws specific way and specific opcode
wlen = esp_transport_ws_send_raw(client->transport, opcode, (char *)client->tx_buffer, need_write, wlen = esp_transport_ws_send_raw(client->transport, current_opcode, (char *)client->tx_buffer, need_write,
(timeout==portMAX_DELAY)? -1 : timeout * portTICK_PERIOD_MS); (timeout==portMAX_DELAY)? -1 : timeout * portTICK_PERIOD_MS);
if (wlen <= 0) { if (wlen <= 0) {
ret = wlen; ret = wlen;
ESP_LOGE(TAG, "Network error: esp_transport_write() returned %d, errno=%d", ret, errno); ESP_LOGE(TAG, "Network error: esp_transport_write() returned %d, errno=%d", ret, errno);
goto unlock_and_return; goto unlock_and_return;
} }
current_opcode = 0;
widx += wlen; widx += wlen;
need_write = len - widx; need_write = len - widx;
} }
ret = widx; ret = widx;
unlock_and_return: unlock_and_return:

View file

@ -20,6 +20,7 @@ typedef enum ws_transport_opcodes {
WS_TRANSPORT_OPCODES_CLOSE = 0x08, WS_TRANSPORT_OPCODES_CLOSE = 0x08,
WS_TRANSPORT_OPCODES_PING = 0x09, WS_TRANSPORT_OPCODES_PING = 0x09,
WS_TRANSPORT_OPCODES_PONG = 0x0a, WS_TRANSPORT_OPCODES_PONG = 0x0a,
WS_TRANSPORT_OPCODES_FIN = 0x80,
} ws_transport_opcodes_t; } ws_transport_opcodes_t;
/** /**

View file

@ -268,7 +268,7 @@ int esp_transport_ws_send_raw(esp_transport_handle_t t, ws_transport_opcodes_t o
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
ESP_LOGD(TAG, "Sending raw ws message with opcode %d", op_code); ESP_LOGD(TAG, "Sending raw ws message with opcode %d", op_code);
return _ws_write(t, op_code | WS_FIN, WS_MASK, b, len, timeout_ms); return _ws_write(t, op_code, WS_MASK, b, len, timeout_ms);
} }
static int ws_write(esp_transport_handle_t t, const char *b, int len, int timeout_ms) static int ws_write(esp_transport_handle_t t, const char *b, int len, int timeout_ms)