From a6c188ce4fb42a12eef068bdcc8e9f7b270c5da8 Mon Sep 17 00:00:00 2001 From: Sebastien Helleu Date: Sat, 5 Oct 2013 16:49:39 +0200 Subject: [PATCH] relay: fix decoding of websocket frames when there are multiple frames in a single message received (only the first one was decoded) --- ChangeLog | 4 +- src/plugins/relay/relay-websocket.c | 88 +++++++++++++++-------------- 2 files changed, 48 insertions(+), 44 deletions(-) diff --git a/ChangeLog b/ChangeLog index 98ed5de62..09cbebba9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,7 @@ WeeChat ChangeLog ================= Sébastien Helleu -v0.4.2-rc2, 2013-09-30 +v0.4.2-rc2, 2013-10-05 This document lists all changes for each version. @@ -119,6 +119,8 @@ Version 0.4.2 (under dev!) buffer per nick * logger: add option "flush" for command /logger * lua: fix interpreter used in API functions (bug #39470) +* relay: fix decoding of websocket frames when there are multiple frames in a + single message received (only the first one was decoded) * relay: add command "ping" in weechat protocol (task #12689) * relay: fix binding to an IP address (bug #39119) * rmodifier: add option "missing" for command /rmodifier diff --git a/src/plugins/relay/relay-websocket.c b/src/plugins/relay/relay-websocket.c index 44b74445f..5ef44e2fa 100644 --- a/src/plugins/relay/relay-websocket.c +++ b/src/plugins/relay/relay-websocket.c @@ -262,61 +262,63 @@ relay_websocket_send_http (struct t_relay_client *client, int relay_websocket_decode_frame (const unsigned char *buffer, - unsigned long long length, + unsigned long long buffer_length, unsigned char *decoded, unsigned long long *decoded_length) { - unsigned long long i, index, length_frame_size, length_frame; + unsigned long long i, index_buffer, length_frame_size, length_frame; *decoded_length = 0; + index_buffer = 0; - if (length < 2) - return 0; - - /* - * check if frame is masked: client MUST send a masked frame; if frame is - * not masked, we MUST reject it and close the connection (see RFC 6455) - */ - if (!(buffer[1] & 128)) - return 0; - - /* decode frame */ - index = 2; - length_frame_size = 1; - length_frame = buffer[1] & 127; - if ((length_frame == 126) || (length_frame == 127)) + /* loop to decode all frames in message */ + while (index_buffer + 2 <= buffer_length) { - length_frame_size = (length_frame == 126) ? 2 : 8; - if (length < 1 + length_frame_size) + /* + * check if frame is masked: client MUST send a masked frame; if frame is + * not masked, we MUST reject it and close the connection (see RFC 6455) + */ + if (!(buffer[index_buffer + 1] & 128)) return 0; - length_frame = 0; - for (i = 0; i < length_frame_size; i++) + + /* decode frame */ + length_frame_size = 1; + length_frame = buffer[index_buffer + 1] & 127; + index_buffer += 2; + if ((length_frame == 126) || (length_frame == 127)) { - length_frame += (unsigned long long)buffer[index + i] << ((length_frame_size - i - 1) * 8); + length_frame_size = (length_frame == 126) ? 2 : 8; + if (buffer_length < 1 + length_frame_size) + return 0; + length_frame = 0; + for (i = 0; i < length_frame_size; i++) + { + length_frame += (unsigned long long)buffer[index_buffer + i] << ((length_frame_size - i - 1) * 8); + } + index_buffer += length_frame_size; } - index += length_frame_size; + + if (buffer_length < 1 + length_frame_size + 4 + length_frame) + return 0; + + /* read masks (4 bytes) */ + int masks[4]; + for (i = 0; i < 4; i++) + { + masks[i] = (int)((unsigned char)buffer[index_buffer + i]); + } + index_buffer += 4; + + /* decode data using masks */ + for (i = 0; i < length_frame; i++) + { + decoded[*decoded_length + i] = (int)((unsigned char)buffer[index_buffer + i]) ^ masks[i % 4]; + } + decoded[*decoded_length + length_frame] = '\0'; + *decoded_length += length_frame; + index_buffer += length_frame; } - if (length < 1 + length_frame_size + 4 + length_frame) - return 0; - - /* read masks (4 bytes) */ - int masks[4]; - for (i = 0; i < 4; i++) - { - masks[i] = (int)((unsigned char)buffer[index + i]); - } - index += 4; - - /* decode data using masks */ - for (i = 0; i < length_frame; i++) - { - decoded[i] = (int)((unsigned char)buffer[index + i]) ^ masks[i % 4]; - } - decoded[length_frame] = '\0'; - - *decoded_length = length_frame; - return 1; }