Blame SOURCES/0001-WebSockets-ignore-any-messages-after-close-has-been-.patch

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