diff options
author | Carlos Garcia Campos <cgarcia@igalia.com> | 2019-07-04 10:13:57 +0200 |
---|---|---|
committer | Claudio Saavedra <csaavedra@igalia.com> | 2020-12-11 16:40:19 +0200 |
commit | 4e7b45a512d3374212ac8238de01928a568d1427 (patch) | |
tree | 0d46b56eb67bb81a06fd57a600aba97169ca573a | |
parent | 912b4e4271f362c45509c2e880ed50552d89895e (diff) | |
download | libsoup-4e7b45a512d3374212ac8238de01928a568d1427.tar.gz |
WebSockets: server must close the connection when receiving an unmasked frame
RFC 6455:
The server MUST close the connection upon receiving a
frame that is not masked.
-rw-r--r-- | libsoup/soup-websocket-connection.c | 9 | ||||
-rw-r--r-- | tests/websocket-test.c | 49 |
2 files changed, 55 insertions, 3 deletions
diff --git a/libsoup/soup-websocket-connection.c b/libsoup/soup-websocket-connection.c index a41f05cd..03647413 100644 --- a/libsoup/soup-websocket-connection.c +++ b/libsoup/soup-websocket-connection.c @@ -921,6 +921,15 @@ process_frame (SoupWebsocketConnection *self) return FALSE; } + if (self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER && !masked) { + /* The server MUST close the connection upon receiving a frame + * that is not masked. + */ + g_debug ("The client should always mask frames"); + protocol_error_and_close (self); + return FALSE; + } + /* We do not support extensions, reserved bits must be 0 */ if (header[0] & 0x70) { protocol_error_and_close (self); diff --git a/tests/websocket-test.c b/tests/websocket-test.c index 59cbba39..890f358c 100644 --- a/tests/websocket-test.c +++ b/tests/websocket-test.c @@ -507,11 +507,11 @@ test_send_bad_data (Test *test, io = soup_websocket_connection_get_io_stream (test->client); /* Bad UTF-8 frame */ - frame = "\x81\x04\xEE\xEE\xEE\xEE"; + frame = "\x81\x84\x00\x00\x00\x00\xEE\xEE\xEE\xEE"; if (!g_output_stream_write_all (g_io_stream_get_output_stream (io), - frame, 6, &written, NULL, NULL)) + frame, 10, &written, NULL, NULL)) g_assert_not_reached (); - g_assert_cmpuint (written, ==, 6); + g_assert_cmpuint (written, ==, 10); WAIT_UNTIL (error != NULL); g_assert_error (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_CLOSE_BAD_DATA); @@ -1028,6 +1028,40 @@ test_client_receive_masked_frame (Test *test, } static void +test_server_receive_unmasked_frame (Test *test, + gconstpointer data) +{ + GError *error = NULL; + GIOStream *io; + gsize written; + const char *frame; + gboolean close_event = FALSE; + + g_signal_handlers_disconnect_by_func (test->server, on_error_not_reached, NULL); + g_signal_connect (test->server, "error", G_CALLBACK (on_error_copy), &error); + g_signal_connect (test->client, "closed", G_CALLBACK (on_close_set_flag), &close_event); + + io = soup_websocket_connection_get_io_stream (test->client); + + /* Unmasked frame */ + frame = "\x81\x0bHello World"; + if (!g_output_stream_write_all (g_io_stream_get_output_stream (io), + frame, 13, &written, NULL, NULL)) + g_assert_not_reached (); + g_assert_cmpuint (written, ==, 13); + + WAIT_UNTIL (error != NULL); + g_assert_error (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_CLOSE_PROTOCOL_ERROR); + g_clear_error (&error); + + WAIT_UNTIL (soup_websocket_connection_get_state (test->client) == SOUP_WEBSOCKET_STATE_CLOSED); + g_assert (close_event); + + g_assert_cmpuint (soup_websocket_connection_get_close_code (test->client), ==, SOUP_WEBSOCKET_CLOSE_PROTOCOL_ERROR); + +} + +static void test_client_context_got_server_connection (SoupServer *server, SoupWebsocketConnection *connection, const char *path, @@ -1214,6 +1248,15 @@ main (int argc, test_client_receive_masked_frame, teardown_direct_connection); + g_test_add ("/websocket/direct/server-receive-unmasked-frame", Test, NULL, + setup_direct_connection, + test_server_receive_unmasked_frame, + teardown_direct_connection); + g_test_add ("/websocket/soup/server-receive-unmasked-frame", Test, NULL, + setup_soup_connection, + test_server_receive_unmasked_frame, + teardown_soup_connection); + if (g_test_slow ()) { g_test_add ("/websocket/direct/close-after-timeout", Test, NULL, setup_half_direct_connection, |