[libsoup] http2-io: fix a crash when a goaway frame is received while processing pending messages



commit 9a91641a1291d003cd97617079d04e08a6c59ea9
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Tue Jun 22 17:56:39 2021 +0200

    http2-io: fix a crash when a goaway frame is received while processing pending messages
    
    We need to make sure the connection is not disconnected while we are in
    io_read_ready.

 libsoup/http1/soup-client-message-io-http1.c |  4 ++--
 libsoup/http1/soup-client-message-io-http1.h |  2 +-
 libsoup/http2/soup-client-message-io-http2.c | 23 ++++++++++++++++++++---
 libsoup/http2/soup-client-message-io-http2.h |  3 +--
 libsoup/soup-connection.c                    |  8 ++++----
 5 files changed, 28 insertions(+), 12 deletions(-)
---
diff --git a/libsoup/http1/soup-client-message-io-http1.c b/libsoup/http1/soup-client-message-io-http1.c
index 46029612..129ddb4f 100644
--- a/libsoup/http1/soup-client-message-io-http1.c
+++ b/libsoup/http1/soup-client-message-io-http1.c
@@ -1161,12 +1161,12 @@ static const SoupClientMessageIOFuncs io_funcs = {
 };
 
 SoupClientMessageIO *
-soup_client_message_io_http1_new (GIOStream *stream)
+soup_client_message_io_http1_new (SoupConnection *conn)
 {
         SoupClientMessageIOHTTP1 *io;
 
         io = g_slice_new0 (SoupClientMessageIOHTTP1);
-        io->iostream = g_object_ref (stream);
+        io->iostream = g_object_ref (soup_connection_get_iostream (conn));
         io->istream = g_io_stream_get_input_stream (io->iostream);
         io->ostream = g_io_stream_get_output_stream (io->iostream);
         io->is_reusable = TRUE;
diff --git a/libsoup/http1/soup-client-message-io-http1.h b/libsoup/http1/soup-client-message-io-http1.h
index e749360d..0634df29 100644
--- a/libsoup/http1/soup-client-message-io-http1.h
+++ b/libsoup/http1/soup-client-message-io-http1.h
@@ -7,4 +7,4 @@
 
 #include "soup-client-message-io.h"
 
-SoupClientMessageIO *soup_client_message_io_http1_new (GIOStream *stream);
+SoupClientMessageIO *soup_client_message_io_http1_new (SoupConnection *conn);
diff --git a/libsoup/http2/soup-client-message-io-http2.c b/libsoup/http2/soup-client-message-io-http2.c
index b1ae61e0..334fb8be 100644
--- a/libsoup/http2/soup-client-message-io-http2.c
+++ b/libsoup/http2/soup-client-message-io-http2.c
@@ -61,6 +61,7 @@ typedef enum {
 typedef struct {
         SoupClientMessageIO iface;
 
+        SoupConnection *conn;
         GIOStream *stream;
         GInputStream *istream;
         GOutputStream *ostream;
@@ -443,6 +444,12 @@ io_read_ready (GObject                  *stream,
                 return G_SOURCE_REMOVE;
         }
 
+        /* Mark the connection as in use to make sure it's not disconnected while
+         * processing pending messages, for example if a goaway is received.
+         */
+        if (io->conn)
+                soup_connection_set_in_use (io->conn, TRUE);
+
         while (nghttp2_session_want_read (io->session) && progress) {
                 progress = io_read (io, FALSE, NULL, &error);
                 if (progress) {
@@ -454,6 +461,8 @@ io_read_ready (GObject                  *stream,
 
         if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
                 g_error_free (error);
+                if (io->conn)
+                        soup_connection_set_in_use (io->conn, FALSE);
                 return G_SOURCE_CONTINUE;
         }
 
@@ -463,6 +472,8 @@ io_read_ready (GObject                  *stream,
         io->is_shutdown = TRUE;
 
         g_clear_pointer (&io->read_source, g_source_unref);
+        if (io->conn)
+                soup_connection_set_in_use (io->conn, FALSE);
         return G_SOURCE_REMOVE;
 }
 
@@ -1560,6 +1571,9 @@ soup_client_message_io_http2_destroy (SoupClientMessageIO *iface)
                 g_source_destroy (io->write_source);
                 g_source_unref (io->write_source);
         }
+
+        if (io->conn)
+                g_object_remove_weak_pointer (G_OBJECT (io->conn), (gpointer*)&io->conn);
         g_clear_object (&io->stream);
         g_clear_object (&io->close_task);
         g_clear_pointer (&io->session, nghttp2_session_del);
@@ -1642,15 +1656,18 @@ soup_client_message_io_http2_init (SoupClientMessageIOHTTP2 *io)
 #define MAX_HEADER_TABLE_SIZE 65536 /* Match size used by Chromium/Firefox */
 
 SoupClientMessageIO *
-soup_client_message_io_http2_new (GIOStream *stream, guint64 connection_id)
+soup_client_message_io_http2_new (SoupConnection *conn)
 {
         SoupClientMessageIOHTTP2 *io = g_new0 (SoupClientMessageIOHTTP2, 1);
         soup_client_message_io_http2_init (io);
 
-        io->stream = g_object_ref (stream);
+        io->conn = conn;
+        g_object_add_weak_pointer (G_OBJECT (io->conn), (gpointer*)&io->conn);
+
+        io->stream = g_object_ref (soup_connection_get_iostream (conn));
         io->istream = g_io_stream_get_input_stream (io->stream);
         io->ostream = g_io_stream_get_output_stream (io->stream);
-        io->connection_id = connection_id;
+        io->connection_id = soup_connection_get_id (conn);
 
         io->read_source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (io->istream), 
NULL);
         g_source_set_name (io->read_source, "Soup HTTP/2 read source");
diff --git a/libsoup/http2/soup-client-message-io-http2.h b/libsoup/http2/soup-client-message-io-http2.h
index 213c38f3..50aece85 100644
--- a/libsoup/http2/soup-client-message-io-http2.h
+++ b/libsoup/http2/soup-client-message-io-http2.h
@@ -9,7 +9,6 @@
 
 G_BEGIN_DECLS
 
-SoupClientMessageIO *soup_client_message_io_http2_new (GIOStream *stream,
-                                                       guint64    connection_id);
+SoupClientMessageIO *soup_client_message_io_http2_new (SoupConnection *conn);
 
 G_END_DECLS
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index 24b084f4..3d06a870 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -455,10 +455,10 @@ soup_connection_create_io_data (SoupConnection *conn)
         switch (priv->http_version) {
         case SOUP_HTTP_1_0:
         case SOUP_HTTP_1_1:
-                priv->io_data = soup_client_message_io_http1_new (priv->iostream);
+                priv->io_data = soup_client_message_io_http1_new (conn);
                 break;
         case SOUP_HTTP_2_0:
-                priv->io_data = soup_client_message_io_http2_new (priv->iostream, priv->id);
+                priv->io_data = soup_client_message_io_http2_new (conn);
                 break;
         }
 }
@@ -820,7 +820,7 @@ tunnel_handshake_ready_cb (GTlsConnection *tls_connection,
                 soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
 
                 g_assert (!priv->io_data);
-                priv->io_data = soup_client_message_io_http1_new (priv->iostream);
+                priv->io_data = soup_client_message_io_http1_new (conn);
 
                 g_task_return_boolean (task, TRUE);
         } else {
@@ -911,7 +911,7 @@ soup_connection_tunnel_handshake (SoupConnection *conn,
         soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
 
         g_assert (!priv->io_data);
-        priv->io_data = soup_client_message_io_http1_new (priv->iostream);
+        priv->io_data = soup_client_message_io_http1_new (conn);
 
         return TRUE;
 }


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