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

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,