|
|
0a2b47 |
From d9c729aa5a7991182fa7bdb8d94442f8f0cf055b Mon Sep 17 00:00:00 2001
|
|
|
0a2b47 |
From: Carlos Garcia Campos <cgarcia@igalia.com>
|
|
|
0a2b47 |
Date: Fri, 19 Jul 2019 14:56:05 +0200
|
|
|
0a2b47 |
Subject: [PATCH] WebSockets: ignore any messages after close has been sent and
|
|
|
0a2b47 |
received
|
|
|
0a2b47 |
|
|
|
0a2b47 |
We currently ignore data frames when close has been received, but we
|
|
|
0a2b47 |
should also ignore any frame after close has been sent and received.
|
|
|
0a2b47 |
Currently, if we receive two close frames we end up with the code and
|
|
|
0a2b47 |
reason of the second frame, while the RFC says: "The WebSocket
|
|
|
0a2b47 |
Connection Close Code is defined as the status code contained in the
|
|
|
0a2b47 |
first Close control frame received by the application implementing
|
|
|
0a2b47 |
this protocol."
|
|
|
0a2b47 |
---
|
|
|
0a2b47 |
libsoup/soup-websocket-connection.c | 3 ++
|
|
|
0a2b47 |
tests/websocket-test.c | 48 +++++++++++++++++++++++++++++
|
|
|
0a2b47 |
2 files changed, 51 insertions(+)
|
|
|
0a2b47 |
|
|
|
0a2b47 |
diff --git libsoup/soup-websocket-connection.c libsoup/soup-websocket-connection.c
|
|
|
0a2b47 |
--- a/libsoup/soup-websocket-connection.c
|
|
|
0a2b47 |
+++ b/libsoup/soup-websocket-connection.c
|
|
|
0a2b47 |
@@ -690,6 +690,9 @@
|
|
|
0a2b47 |
SoupWebsocketConnectionPrivate *pv = self->pv;
|
|
|
0a2b47 |
GBytes *message;
|
|
|
0a2b47 |
|
|
|
0a2b47 |
+ if (pv->close_sent && pv->close_received)
|
|
|
0a2b47 |
+ return;
|
|
|
0a2b47 |
+
|
|
|
0a2b47 |
if (control) {
|
|
|
0a2b47 |
/* Control frames must never be fragmented */
|
|
|
0a2b47 |
if (!fin) {
|
|
|
0a2b47 |
--- a/tests/websocket-test.c
|
|
|
0a2b47 |
+++ b/tests/websocket-test.c
|
|
|
0a2b47 |
@@ -707,6 +707,49 @@
|
|
|
0a2b47 |
}
|
|
|
0a2b47 |
|
|
|
0a2b47 |
static gpointer
|
|
|
0a2b47 |
+close_after_close_server_thread (gpointer user_data)
|
|
|
0a2b47 |
+{
|
|
|
0a2b47 |
+ Test *test = user_data;
|
|
|
0a2b47 |
+ gsize written;
|
|
|
0a2b47 |
+ const char frames[] =
|
|
|
0a2b47 |
+ "\x88\x09\x03\xe8""reason1"
|
|
|
0a2b47 |
+ "\x88\x09\x03\xe8""reason2";
|
|
|
0a2b47 |
+ GError *error = NULL;
|
|
|
0a2b47 |
+
|
|
|
0a2b47 |
+ g_mutex_lock (&test->mutex);
|
|
|
0a2b47 |
+ g_mutex_unlock (&test->mutex);
|
|
|
0a2b47 |
+
|
|
|
0a2b47 |
+ g_output_stream_write_all (g_io_stream_get_output_stream (test->raw_server),
|
|
|
0a2b47 |
+ frames, sizeof (frames) -1, &written, NULL, &error);
|
|
|
0a2b47 |
+ g_assert_no_error (error);
|
|
|
0a2b47 |
+ g_assert_cmpuint (written, ==, sizeof (frames) - 1);
|
|
|
0a2b47 |
+ g_io_stream_close (test->raw_server, NULL, &error);
|
|
|
0a2b47 |
+ g_assert_no_error (error);
|
|
|
0a2b47 |
+
|
|
|
0a2b47 |
+ return NULL;
|
|
|
0a2b47 |
+}
|
|
|
0a2b47 |
+
|
|
|
0a2b47 |
+static void
|
|
|
0a2b47 |
+test_close_after_close (Test *test,
|
|
|
0a2b47 |
+ gconstpointer data)
|
|
|
0a2b47 |
+{
|
|
|
0a2b47 |
+ GThread *thread;
|
|
|
0a2b47 |
+
|
|
|
0a2b47 |
+ g_mutex_lock (&test->mutex);
|
|
|
0a2b47 |
+
|
|
|
0a2b47 |
+ thread = g_thread_new ("close-after-close-thread", close_after_close_server_thread, test);
|
|
|
0a2b47 |
+
|
|
|
0a2b47 |
+ soup_websocket_connection_close (test->client, SOUP_WEBSOCKET_CLOSE_NORMAL, "reason1");
|
|
|
0a2b47 |
+ g_mutex_unlock (&test->mutex);
|
|
|
0a2b47 |
+
|
|
|
0a2b47 |
+ g_thread_join (thread);
|
|
|
0a2b47 |
+
|
|
|
0a2b47 |
+ WAIT_UNTIL (soup_websocket_connection_get_state (test->client) == SOUP_WEBSOCKET_STATE_CLOSED);
|
|
|
0a2b47 |
+ g_assert_cmpuint (soup_websocket_connection_get_close_code (test->client), ==, SOUP_WEBSOCKET_CLOSE_NORMAL);
|
|
|
0a2b47 |
+ g_assert_cmpstr (soup_websocket_connection_get_close_data (test->client), ==, "reason1");
|
|
|
0a2b47 |
+}
|
|
|
0a2b47 |
+
|
|
|
0a2b47 |
+static gpointer
|
|
|
0a2b47 |
timeout_server_thread (gpointer user_data)
|
|
|
0a2b47 |
{
|
|
|
0a2b47 |
Test *test = user_data;
|
|
|
0a2b47 |
@@ -918,6 +961,11 @@
|
|
|
0a2b47 |
test_message_after_closing,
|
|
|
0a2b47 |
teardown_soup_connection);
|
|
|
0a2b47 |
|
|
|
0a2b47 |
+ g_test_add ("/websocket/direct/close-after-close", Test, NULL,
|
|
|
0a2b47 |
+ setup_half_direct_connection,
|
|
|
0a2b47 |
+ test_close_after_close,
|
|
|
0a2b47 |
+ teardown_direct_connection);
|
|
|
0a2b47 |
+
|
|
|
0a2b47 |
|
|
|
0a2b47 |
g_test_add ("/websocket/direct/protocol-negotiate", Test, NULL, NULL,
|
|
|
0a2b47 |
test_protocol_negotiate_direct,
|