mirror of
https://github.com/weechat/weechat.git
synced 2026-06-12 14:14:48 +02:00
3687ce0f0f
A relay client could announce a huge websocket frame (or HTTP body via "Content-Length") and dribble its payload, making WeeChat accumulate it in a buffer that grew without limit, until all memory was exhausted. The websocket frame path is reachable before authentication with the "weechat" and "irc" protocols. The announced websocket frame length and HTTP "Content-Length" are now bounded by WEBSOCKET_FRAME_MAX_LENGTH and RELAY_HTTP_BODY_MAX_LENGTH: an oversized websocket frame closes the connection, and an oversized body is rejected.
572 lines
23 KiB
C++
572 lines
23 KiB
C++
/*
|
|
* SPDX-FileCopyrightText: 2024-2026 Sébastien Helleu <flashcode@flashtux.org>
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*
|
|
* This file is part of WeeChat, the extensible chat client.
|
|
*
|
|
* WeeChat is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* WeeChat is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with WeeChat. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/* Test websocket functions */
|
|
|
|
#include "CppUTest/TestHarness.h"
|
|
|
|
#include "tests.h"
|
|
|
|
extern "C"
|
|
{
|
|
#include <string.h>
|
|
#include <zlib.h>
|
|
#include "src/core/core-config-file.h"
|
|
#include "src/core/core-hashtable.h"
|
|
#include "src/plugins/relay/relay-config.h"
|
|
#include "src/plugins/relay/relay-http.h"
|
|
#include "src/plugins/relay/relay-websocket.h"
|
|
|
|
extern void relay_websocket_deflate_free_stream_deflate (struct t_relay_websocket_deflate *ws_deflate);
|
|
extern void relay_websocket_deflate_free_stream_inflate (struct t_relay_websocket_deflate *ws_deflate);
|
|
extern char *relay_websocket_deflate (const void *data, size_t size, z_stream *strm,
|
|
size_t *size_compressed);
|
|
extern char *relay_websocket_inflate (const void *data, size_t size, z_stream *strm,
|
|
size_t *size_decompressed);
|
|
}
|
|
|
|
TEST_GROUP(RelayWebsocket)
|
|
{
|
|
};
|
|
|
|
/*
|
|
* Test functions:
|
|
* relay_websocket_deflate_alloc
|
|
* relay_websocket_deflate_init_stream_deflate
|
|
* relay_websocket_deflate_free_stream_deflate
|
|
* relay_websocket_deflate_init_stream_inflate
|
|
* relay_websocket_deflate_free_stream_inflate
|
|
* relay_websocket_deflate_free
|
|
*/
|
|
|
|
TEST(RelayWebsocket, DeflateAllocFree)
|
|
{
|
|
struct t_relay_websocket_deflate *ws_deflate;
|
|
|
|
ws_deflate = relay_websocket_deflate_alloc ();
|
|
LONGS_EQUAL(0, ws_deflate->enabled);
|
|
LONGS_EQUAL(0, ws_deflate->server_context_takeover);
|
|
LONGS_EQUAL(0, ws_deflate->client_context_takeover);
|
|
LONGS_EQUAL(0, ws_deflate->window_bits_deflate);
|
|
LONGS_EQUAL(0, ws_deflate->window_bits_inflate);
|
|
LONGS_EQUAL(0, ws_deflate->server_max_window_bits_recv);
|
|
LONGS_EQUAL(0, ws_deflate->client_max_window_bits_recv);
|
|
POINTERS_EQUAL(NULL, ws_deflate->strm_deflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate->strm_inflate);
|
|
|
|
ws_deflate->window_bits_deflate = 15;
|
|
ws_deflate->window_bits_inflate = 15;
|
|
|
|
ws_deflate->strm_deflate = (z_stream *)calloc (1, sizeof (*ws_deflate->strm_deflate));
|
|
CHECK(ws_deflate->strm_deflate);
|
|
relay_websocket_deflate_init_stream_deflate (ws_deflate);
|
|
relay_websocket_deflate_free_stream_deflate (ws_deflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate->strm_deflate);
|
|
|
|
ws_deflate->strm_inflate = (z_stream *)calloc (1, sizeof (*ws_deflate->strm_inflate));
|
|
CHECK(ws_deflate->strm_inflate);
|
|
relay_websocket_deflate_init_stream_inflate (ws_deflate);
|
|
relay_websocket_deflate_free_stream_inflate (ws_deflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate->strm_inflate);
|
|
|
|
relay_websocket_deflate_free (ws_deflate);
|
|
|
|
/* test free of NULL websocket deflate */
|
|
relay_websocket_deflate_free (NULL);
|
|
}
|
|
|
|
/*
|
|
* Test functions:
|
|
* relay_websocket_is_valid_http_get
|
|
*/
|
|
|
|
TEST(RelayWebsocket, IsValidHttpGet)
|
|
{
|
|
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, NULL));
|
|
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, ""));
|
|
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "xxx"));
|
|
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "GET /api\r\n"));
|
|
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "GET /api test\r\n"));
|
|
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "GET /api HTTP/1.1\r\n"));
|
|
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_API, "GET /weechat\r\n"));
|
|
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_API, "GET /weechat test\r\n"));
|
|
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_API, "GET /weechat HTTP/1.1\r\n"));
|
|
|
|
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "GET /weechat test\r\n"));
|
|
LONGS_EQUAL(0, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_API, "GET /api test\r\n"));
|
|
|
|
LONGS_EQUAL(1, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "GET /weechat\r\n"));
|
|
LONGS_EQUAL(1, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_WEECHAT, "GET /weechat HTTP/1.1\r\n"));
|
|
LONGS_EQUAL(1, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_API, "GET /api\r\n"));
|
|
LONGS_EQUAL(1, relay_websocket_is_valid_http_get (RELAY_PROTOCOL_API, "GET /api HTTP/1.1\r\n"));
|
|
}
|
|
|
|
/*
|
|
* Test functions:
|
|
* relay_websocket_client_handshake_valid
|
|
* relay_websocket_build_handshake
|
|
*/
|
|
|
|
TEST(RelayWebsocket, ClientHandshakeValid)
|
|
{
|
|
struct t_relay_http_request *request;
|
|
char *str;
|
|
|
|
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (NULL));
|
|
|
|
request = relay_http_request_alloc ();
|
|
CHECK(request);
|
|
|
|
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (NULL));
|
|
|
|
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (request));
|
|
hashtable_set (request->headers, "upgrade", NULL);
|
|
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (request));
|
|
hashtable_set (request->headers, "upgrade", "test");
|
|
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (request));
|
|
hashtable_set (request->headers, "upgrade", "websocket");
|
|
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (request));
|
|
hashtable_set (request->headers, "sec-websocket-key", NULL);
|
|
LONGS_EQUAL(-1, relay_websocket_client_handshake_valid (request));
|
|
hashtable_set (request->headers, "sec-websocket-key", "CI1sXhf/u2o34BfWK7NeIg==");
|
|
LONGS_EQUAL(0, relay_websocket_client_handshake_valid (request));
|
|
|
|
STRCMP_EQUAL(NULL, relay_websocket_build_handshake (NULL));
|
|
|
|
WEE_TEST_STR(
|
|
"HTTP/1.1 101 Switching Protocols\r\n"
|
|
"Upgrade: websocket\r\n"
|
|
"Connection: Upgrade\r\n"
|
|
"Sec-WebSocket-Accept: fhLJYtv//ugX2vQXpifQgByRZ5Y=\r\n"
|
|
"\r\n",
|
|
relay_websocket_build_handshake (request));
|
|
|
|
config_file_option_set (relay_config_network_websocket_allowed_origins, "example.com", 1);
|
|
LONGS_EQUAL(-2, relay_websocket_client_handshake_valid (request));
|
|
hashtable_set (request->headers, "origin", NULL);
|
|
LONGS_EQUAL(-2, relay_websocket_client_handshake_valid (request));
|
|
hashtable_set (request->headers, "origin", "weechat.org");
|
|
LONGS_EQUAL(-2, relay_websocket_client_handshake_valid (request));
|
|
hashtable_set (request->headers, "origin", "example.com");
|
|
LONGS_EQUAL(0, relay_websocket_client_handshake_valid (request));
|
|
config_file_option_reset (relay_config_network_websocket_allowed_origins, 1);
|
|
|
|
relay_websocket_deflate_reinit (request->ws_deflate);
|
|
relay_websocket_parse_extensions ("permessage-deflate", request->ws_deflate, 1);
|
|
LONGS_EQUAL(1, request->ws_deflate->enabled);
|
|
LONGS_EQUAL(1, request->ws_deflate->server_context_takeover);
|
|
LONGS_EQUAL(1, request->ws_deflate->client_context_takeover);
|
|
LONGS_EQUAL(15, request->ws_deflate->window_bits_deflate);
|
|
LONGS_EQUAL(15, request->ws_deflate->window_bits_inflate);
|
|
LONGS_EQUAL(0, request->ws_deflate->server_max_window_bits_recv);
|
|
LONGS_EQUAL(0, request->ws_deflate->client_max_window_bits_recv);
|
|
WEE_TEST_STR(
|
|
"HTTP/1.1 101 Switching Protocols\r\n"
|
|
"Upgrade: websocket\r\n"
|
|
"Connection: Upgrade\r\n"
|
|
"Sec-WebSocket-Accept: fhLJYtv//ugX2vQXpifQgByRZ5Y=\r\n"
|
|
"Sec-WebSocket-Extensions: permessage-deflate\r\n"
|
|
"\r\n",
|
|
relay_websocket_build_handshake (request));
|
|
|
|
relay_websocket_deflate_reinit (request->ws_deflate);
|
|
relay_websocket_parse_extensions (
|
|
"permessage-deflate; client_max_window_bits",
|
|
request->ws_deflate,
|
|
1);
|
|
LONGS_EQUAL(1, request->ws_deflate->enabled);
|
|
LONGS_EQUAL(1, request->ws_deflate->server_context_takeover);
|
|
LONGS_EQUAL(1, request->ws_deflate->client_context_takeover);
|
|
LONGS_EQUAL(15, request->ws_deflate->window_bits_deflate);
|
|
LONGS_EQUAL(15, request->ws_deflate->window_bits_inflate);
|
|
LONGS_EQUAL(0, request->ws_deflate->server_max_window_bits_recv);
|
|
LONGS_EQUAL(1, request->ws_deflate->client_max_window_bits_recv);
|
|
WEE_TEST_STR(
|
|
"HTTP/1.1 101 Switching Protocols\r\n"
|
|
"Upgrade: websocket\r\n"
|
|
"Connection: Upgrade\r\n"
|
|
"Sec-WebSocket-Accept: fhLJYtv//ugX2vQXpifQgByRZ5Y=\r\n"
|
|
"Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits=15\r\n"
|
|
"\r\n",
|
|
relay_websocket_build_handshake (request));
|
|
|
|
relay_websocket_deflate_reinit (request->ws_deflate);
|
|
relay_websocket_parse_extensions (
|
|
"permessage-deflate; client_max_window_bits = 12; server_no_context_takeover",
|
|
request->ws_deflate,
|
|
1);
|
|
LONGS_EQUAL(1, request->ws_deflate->enabled);
|
|
LONGS_EQUAL(0, request->ws_deflate->server_context_takeover);
|
|
LONGS_EQUAL(1, request->ws_deflate->client_context_takeover);
|
|
LONGS_EQUAL(15, request->ws_deflate->window_bits_deflate);
|
|
LONGS_EQUAL(12, request->ws_deflate->window_bits_inflate);
|
|
LONGS_EQUAL(0, request->ws_deflate->server_max_window_bits_recv);
|
|
LONGS_EQUAL(1, request->ws_deflate->client_max_window_bits_recv);
|
|
WEE_TEST_STR(
|
|
"HTTP/1.1 101 Switching Protocols\r\n"
|
|
"Upgrade: websocket\r\n"
|
|
"Connection: Upgrade\r\n"
|
|
"Sec-WebSocket-Accept: fhLJYtv//ugX2vQXpifQgByRZ5Y=\r\n"
|
|
"Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_max_window_bits=12\r\n"
|
|
"\r\n",
|
|
relay_websocket_build_handshake (request));
|
|
|
|
relay_websocket_deflate_reinit (request->ws_deflate);
|
|
relay_websocket_parse_extensions (
|
|
"permessage-deflate; client_max_window_bits = 12; server_max_window_bits=8; client_no_context_takeover; server_no_context_takeover",
|
|
request->ws_deflate,
|
|
1);
|
|
LONGS_EQUAL(1, request->ws_deflate->enabled);
|
|
LONGS_EQUAL(0, request->ws_deflate->server_context_takeover);
|
|
LONGS_EQUAL(0, request->ws_deflate->client_context_takeover);
|
|
LONGS_EQUAL(8, request->ws_deflate->window_bits_deflate);
|
|
LONGS_EQUAL(12, request->ws_deflate->window_bits_inflate);
|
|
LONGS_EQUAL(1, request->ws_deflate->server_max_window_bits_recv);
|
|
LONGS_EQUAL(1, request->ws_deflate->client_max_window_bits_recv);
|
|
WEE_TEST_STR(
|
|
"HTTP/1.1 101 Switching Protocols\r\n"
|
|
"Upgrade: websocket\r\n"
|
|
"Connection: Upgrade\r\n"
|
|
"Sec-WebSocket-Accept: fhLJYtv//ugX2vQXpifQgByRZ5Y=\r\n"
|
|
"Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover; server_max_window_bits=8; client_max_window_bits=12\r\n"
|
|
"\r\n",
|
|
relay_websocket_build_handshake (request));
|
|
|
|
relay_websocket_deflate_reinit (request->ws_deflate);
|
|
hashtable_set (request->headers, "sec-websocket-protocol",
|
|
WEBSOCKET_SUB_PROTOCOL_API_WEECHAT
|
|
", base64url.bearer.authorization.weechat.cGxhaW46c2VjcmV0X3Bhc3N3b3Jk");
|
|
WEE_TEST_STR(
|
|
"HTTP/1.1 101 Switching Protocols\r\n"
|
|
"Upgrade: websocket\r\n"
|
|
"Connection: Upgrade\r\n"
|
|
"Sec-WebSocket-Accept: fhLJYtv//ugX2vQXpifQgByRZ5Y=\r\n"
|
|
"Sec-WebSocket-Protocol: " WEBSOCKET_SUB_PROTOCOL_API_WEECHAT "\r\n"
|
|
"\r\n",
|
|
relay_websocket_build_handshake (request));
|
|
|
|
relay_http_request_free (request);
|
|
}
|
|
|
|
/*
|
|
* Test functions:
|
|
* relay_websocket_parse_extensions
|
|
*/
|
|
|
|
TEST(RelayWebsocket, ParseExtensions)
|
|
{
|
|
struct t_relay_websocket_deflate ws_deflate;
|
|
|
|
relay_websocket_parse_extensions (NULL, NULL, 1);
|
|
relay_websocket_parse_extensions ("test", NULL, 1);
|
|
relay_websocket_parse_extensions (NULL, &ws_deflate, 1);
|
|
|
|
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
|
relay_websocket_parse_extensions ("test", &ws_deflate, 1);
|
|
LONGS_EQUAL(0, ws_deflate.enabled);
|
|
|
|
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
|
relay_websocket_parse_extensions ("permessage-deflate", &ws_deflate, 0);
|
|
LONGS_EQUAL(0, ws_deflate.enabled);
|
|
LONGS_EQUAL(0, ws_deflate.server_context_takeover);
|
|
LONGS_EQUAL(0, ws_deflate.client_context_takeover);
|
|
LONGS_EQUAL(0, ws_deflate.window_bits_deflate);
|
|
LONGS_EQUAL(0, ws_deflate.window_bits_inflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
|
|
|
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
|
relay_websocket_parse_extensions ("permessage-deflate", &ws_deflate, 1);
|
|
LONGS_EQUAL(1, ws_deflate.enabled);
|
|
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
|
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
|
LONGS_EQUAL(15, ws_deflate.window_bits_deflate);
|
|
LONGS_EQUAL(15, ws_deflate.window_bits_inflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
|
|
|
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
|
relay_websocket_parse_extensions ("permessage-deflate; client_max_window_bits",
|
|
&ws_deflate,
|
|
1);
|
|
LONGS_EQUAL(1, ws_deflate.enabled);
|
|
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
|
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
|
LONGS_EQUAL(15, ws_deflate.window_bits_deflate);
|
|
LONGS_EQUAL(15, ws_deflate.window_bits_inflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
|
|
|
/* client_max_window_bits < 8 (min value) */
|
|
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
|
relay_websocket_parse_extensions (
|
|
"permessage-deflate; client_max_window_bits=4",
|
|
&ws_deflate,
|
|
1);
|
|
LONGS_EQUAL(1, ws_deflate.enabled);
|
|
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
|
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
|
LONGS_EQUAL(15, ws_deflate.window_bits_deflate);
|
|
LONGS_EQUAL(8, ws_deflate.window_bits_inflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
|
|
|
/* client_max_window_bits > 15 (max value) */
|
|
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
|
relay_websocket_parse_extensions (
|
|
"permessage-deflate; client_max_window_bits=30",
|
|
&ws_deflate,
|
|
1);
|
|
LONGS_EQUAL(1, ws_deflate.enabled);
|
|
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
|
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
|
LONGS_EQUAL(15, ws_deflate.window_bits_deflate);
|
|
LONGS_EQUAL(15, ws_deflate.window_bits_inflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
|
|
|
/* invalid value for client_max_window_bits */
|
|
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
|
relay_websocket_parse_extensions (
|
|
"permessage-deflate; client_max_window_bits=test",
|
|
&ws_deflate,
|
|
1);
|
|
LONGS_EQUAL(1, ws_deflate.enabled);
|
|
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
|
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
|
LONGS_EQUAL(15, ws_deflate.window_bits_deflate);
|
|
LONGS_EQUAL(15, ws_deflate.window_bits_inflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
|
|
|
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
|
relay_websocket_parse_extensions (
|
|
"permessage-deflate; client_max_window_bits=9",
|
|
&ws_deflate,
|
|
1);
|
|
LONGS_EQUAL(1, ws_deflate.enabled);
|
|
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
|
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
|
LONGS_EQUAL(15, ws_deflate.window_bits_deflate);
|
|
LONGS_EQUAL(9, ws_deflate.window_bits_inflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
|
|
|
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
|
relay_websocket_parse_extensions (
|
|
"permessage-deflate; client_max_window_bits=9; server_max_window_bits=10",
|
|
&ws_deflate,
|
|
1);
|
|
LONGS_EQUAL(1, ws_deflate.enabled);
|
|
LONGS_EQUAL(1, ws_deflate.server_context_takeover);
|
|
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
|
LONGS_EQUAL(10, ws_deflate.window_bits_deflate);
|
|
LONGS_EQUAL(9, ws_deflate.window_bits_inflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
|
|
|
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
|
relay_websocket_parse_extensions (
|
|
"permessage-deflate; client_max_window_bits=9; server_max_window_bits=10; "
|
|
"server_no_context_takeover",
|
|
&ws_deflate,
|
|
1);
|
|
LONGS_EQUAL(1, ws_deflate.enabled);
|
|
LONGS_EQUAL(0, ws_deflate.server_context_takeover);
|
|
LONGS_EQUAL(1, ws_deflate.client_context_takeover);
|
|
LONGS_EQUAL(10, ws_deflate.window_bits_deflate);
|
|
LONGS_EQUAL(9, ws_deflate.window_bits_inflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
|
|
|
memset (&ws_deflate, 0, sizeof (ws_deflate));
|
|
relay_websocket_parse_extensions (
|
|
"permessage-deflate; client_max_window_bits=9; server_max_window_bits=10; "
|
|
"server_no_context_takeover; client_no_context_takeover",
|
|
&ws_deflate,
|
|
1);
|
|
LONGS_EQUAL(1, ws_deflate.enabled);
|
|
LONGS_EQUAL(0, ws_deflate.server_context_takeover);
|
|
LONGS_EQUAL(0, ws_deflate.client_context_takeover);
|
|
LONGS_EQUAL(10, ws_deflate.window_bits_deflate);
|
|
LONGS_EQUAL(9, ws_deflate.window_bits_inflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_deflate);
|
|
POINTERS_EQUAL(NULL, ws_deflate.strm_inflate);
|
|
}
|
|
|
|
/*
|
|
* Test functions:
|
|
* relay_websocket_deflate
|
|
* relay_websocket_inflate
|
|
*/
|
|
|
|
TEST(RelayWebsocket, Inflate)
|
|
{
|
|
struct t_relay_websocket_deflate *ws_deflate;
|
|
char payload[256], *payload_comp, *payload_decomp;
|
|
size_t size_comp, size_decomp;
|
|
int i;
|
|
|
|
ws_deflate = relay_websocket_deflate_alloc ();
|
|
CHECK(ws_deflate);
|
|
|
|
ws_deflate->window_bits_deflate = 15;
|
|
ws_deflate->window_bits_inflate = 15;
|
|
|
|
ws_deflate->strm_deflate = (z_stream *)calloc (1, sizeof (*ws_deflate->strm_deflate));
|
|
CHECK(ws_deflate->strm_deflate);
|
|
LONGS_EQUAL(1, relay_websocket_deflate_init_stream_deflate (ws_deflate));
|
|
|
|
ws_deflate->strm_inflate = (z_stream *)calloc (1, sizeof (*ws_deflate->strm_inflate));
|
|
CHECK(ws_deflate->strm_inflate);
|
|
LONGS_EQUAL(1, relay_websocket_deflate_init_stream_inflate (ws_deflate));
|
|
|
|
for (i = 0; i < (int)sizeof (payload); i++)
|
|
{
|
|
payload[i] = i % 64;
|
|
}
|
|
|
|
POINTERS_EQUAL(NULL, relay_websocket_deflate (NULL, 0, NULL, NULL));
|
|
POINTERS_EQUAL(NULL, relay_websocket_deflate (payload, 0, NULL, NULL));
|
|
POINTERS_EQUAL(NULL, relay_websocket_deflate (payload, sizeof (payload),
|
|
NULL, NULL));
|
|
POINTERS_EQUAL(NULL, relay_websocket_deflate (payload, sizeof (payload),
|
|
ws_deflate->strm_deflate, NULL));
|
|
|
|
payload_comp = (char *)relay_websocket_deflate (payload, sizeof (payload),
|
|
ws_deflate->strm_deflate, &size_comp);
|
|
CHECK(payload_comp);
|
|
CHECK((size_comp > 0) && (size_comp < (int)sizeof (payload)));
|
|
|
|
payload_decomp = (char *)relay_websocket_inflate (payload_comp, size_comp,
|
|
ws_deflate->strm_inflate, &size_decomp);
|
|
CHECK(payload_decomp);
|
|
LONGS_EQUAL(sizeof (payload), size_decomp);
|
|
MEMCMP_EQUAL(payload, payload_decomp, sizeof (payload));
|
|
|
|
free (payload_decomp);
|
|
free (payload_comp);
|
|
|
|
relay_websocket_deflate_free (ws_deflate);
|
|
|
|
/*
|
|
* protection against "deflate bomb": a small compressed frame that
|
|
* decompresses to more than WEBSOCKET_INFLATE_MAX_SIZE must be rejected
|
|
* (relay_websocket_inflate returns NULL)
|
|
*/
|
|
ws_deflate = relay_websocket_deflate_alloc ();
|
|
CHECK(ws_deflate);
|
|
ws_deflate->window_bits_deflate = 15;
|
|
ws_deflate->window_bits_inflate = 15;
|
|
ws_deflate->strm_deflate = (z_stream *)calloc (1, sizeof (*ws_deflate->strm_deflate));
|
|
CHECK(ws_deflate->strm_deflate);
|
|
LONGS_EQUAL(1, relay_websocket_deflate_init_stream_deflate (ws_deflate));
|
|
ws_deflate->strm_inflate = (z_stream *)calloc (1, sizeof (*ws_deflate->strm_inflate));
|
|
CHECK(ws_deflate->strm_inflate);
|
|
LONGS_EQUAL(1, relay_websocket_deflate_init_stream_inflate (ws_deflate));
|
|
|
|
/* highly compressible payload that decompresses past the maximum size */
|
|
size_t bomb_size = WEBSOCKET_INFLATE_MAX_SIZE + (1024 * 1024);
|
|
char *bomb = (char *)calloc (1, bomb_size);
|
|
CHECK(bomb);
|
|
|
|
payload_comp = (char *)relay_websocket_deflate (bomb, bomb_size,
|
|
ws_deflate->strm_deflate, &size_comp);
|
|
CHECK(payload_comp);
|
|
CHECK(size_comp < bomb_size);
|
|
|
|
payload_decomp = (char *)relay_websocket_inflate (payload_comp, size_comp,
|
|
ws_deflate->strm_inflate, &size_decomp);
|
|
POINTERS_EQUAL(NULL, payload_decomp);
|
|
|
|
free (payload_comp);
|
|
free (bomb);
|
|
|
|
relay_websocket_deflate_free (ws_deflate);
|
|
}
|
|
|
|
/*
|
|
* Test functions:
|
|
* relay_websocket_decode_frame
|
|
*/
|
|
|
|
TEST(RelayWebsocket, DecodeFrame)
|
|
{
|
|
struct t_relay_websocket_frame *frames;
|
|
char *partial_ws_frame;
|
|
int num_frames, partial_ws_frame_size;
|
|
/* small unmasked binary frame with payload "hello" */
|
|
unsigned char frame_ok[7] = { 0x82, 0x05, 'h', 'e', 'l', 'l', 'o' };
|
|
/* masked frame announcing a 1 GB payload (64-bit length field) */
|
|
unsigned char frame_too_big[10] = {
|
|
0x82, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
/* a valid small frame is decoded */
|
|
frames = NULL;
|
|
num_frames = 0;
|
|
partial_ws_frame = NULL;
|
|
partial_ws_frame_size = 0;
|
|
LONGS_EQUAL(1, relay_websocket_decode_frame (
|
|
frame_ok, sizeof (frame_ok), 0, NULL,
|
|
&frames, &num_frames, &partial_ws_frame,
|
|
&partial_ws_frame_size));
|
|
LONGS_EQUAL(1, num_frames);
|
|
CHECK(frames);
|
|
LONGS_EQUAL(5, frames[0].payload_size);
|
|
MEMCMP_EQUAL("hello", frames[0].payload, 5);
|
|
free (frames[0].payload);
|
|
free (frames);
|
|
free (partial_ws_frame);
|
|
|
|
/* a frame announcing an oversized payload is rejected (return 0) */
|
|
frames = NULL;
|
|
num_frames = 0;
|
|
partial_ws_frame = NULL;
|
|
partial_ws_frame_size = 0;
|
|
LONGS_EQUAL(0, relay_websocket_decode_frame (
|
|
frame_too_big, sizeof (frame_too_big), 1, NULL,
|
|
&frames, &num_frames, &partial_ws_frame,
|
|
&partial_ws_frame_size));
|
|
free (frames);
|
|
free (partial_ws_frame);
|
|
}
|
|
|
|
/*
|
|
* Test functions:
|
|
* relay_websocket_encode_frame
|
|
*/
|
|
|
|
TEST(RelayWebsocket, EncodeFrame)
|
|
{
|
|
/* TODO: write tests */
|
|
}
|
|
|
|
/*
|
|
* Test functions:
|
|
* relay_websocket_deflate_print_log
|
|
*/
|
|
|
|
TEST(RelayWebsocket, DeflatePrintLog)
|
|
{
|
|
/* TODO: write tests */
|
|
}
|