[libsoup/carlosgc/websockets-close-after-close] WebSockets: ignore any messages after close has been sent and received



commit d9c729aa5a7991182fa7bdb8d94442f8f0cf055b
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Fri Jul 19 14:56:05 2019 +0200

    WebSockets: ignore any messages after close has been sent and received
    
    We currently ignore data frames when close has been received, but we
    should also ignore any frame after close has been sent and received.
    Currently, if we receive two close frames we end up with the code and
    reason of the second frame, while the RFC says: "The WebSocket
    Connection Close Code is defined as the status code contained in the
    first Close control frame received by the application implementing
    this protocol."

 libsoup/soup-websocket-connection.c |  3 +++
 tests/websocket-test.c              | 48 +++++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+)
---
diff --git a/libsoup/soup-websocket-connection.c b/libsoup/soup-websocket-connection.c
index 94ef52a4..4c755b7c 100644
--- a/libsoup/soup-websocket-connection.c
+++ b/libsoup/soup-websocket-connection.c
@@ -772,6 +772,9 @@ process_contents (SoupWebsocketConnection *self,
        SoupWebsocketConnectionPrivate *pv = self->pv;
        GBytes *message;
 
+       if (pv->close_sent && pv->close_received)
+               return;
+
        if (control) {
                /* Control frames must never be fragmented */
                if (!fin) {
diff --git a/tests/websocket-test.c b/tests/websocket-test.c
index 8de3a1dd..dc2a90bd 100644
--- a/tests/websocket-test.c
+++ b/tests/websocket-test.c
@@ -823,6 +823,49 @@ test_message_after_closing (Test *test,
        g_bytes_unref (message);
 }
 
+static gpointer
+close_after_close_server_thread (gpointer user_data)
+{
+       Test *test = user_data;
+       gsize written;
+       const char frames[] =
+               "\x88\x09\x03\xe8""reason1"
+               "\x88\x09\x03\xe8""reason2";
+       GError *error = NULL;
+
+       g_mutex_lock (&test->mutex);
+       g_mutex_unlock (&test->mutex);
+
+       g_output_stream_write_all (g_io_stream_get_output_stream (test->raw_server),
+                                  frames, sizeof (frames) -1, &written, NULL, &error);
+       g_assert_no_error (error);
+       g_assert_cmpuint (written, ==, sizeof (frames) - 1);
+       g_io_stream_close (test->raw_server, NULL, &error);
+       g_assert_no_error (error);
+
+       return NULL;
+}
+
+static void
+test_close_after_close (Test *test,
+                       gconstpointer data)
+{
+       GThread *thread;
+
+       g_mutex_lock (&test->mutex);
+
+       thread = g_thread_new ("close-after-close-thread", close_after_close_server_thread, test);
+
+       soup_websocket_connection_close (test->client, SOUP_WEBSOCKET_CLOSE_NORMAL, "reason1");
+       g_mutex_unlock (&test->mutex);
+
+       g_thread_join (thread);
+
+       WAIT_UNTIL (soup_websocket_connection_get_state (test->client) == SOUP_WEBSOCKET_STATE_CLOSED);
+       g_assert_cmpuint (soup_websocket_connection_get_close_code (test->client), ==, 
SOUP_WEBSOCKET_CLOSE_NORMAL);
+       g_assert_cmpstr (soup_websocket_connection_get_close_data (test->client), ==, "reason1");
+}
+
 static gpointer
 timeout_server_thread (gpointer user_data)
 {
@@ -1217,6 +1260,11 @@ main (int argc,
                    test_message_after_closing,
                    teardown_soup_connection);
 
+       g_test_add ("/websocket/direct/close-after-close", Test, NULL,
+                   setup_half_direct_connection,
+                   test_close_after_close,
+                   teardown_direct_connection);
+
 
        g_test_add ("/websocket/direct/protocol-negotiate", Test, NULL, NULL,
                    test_protocol_negotiate_direct,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]