summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garcia Campos <cgarcia@igalia.com>2021-06-22 17:56:39 +0200
committerCarlos Garcia Campos <cgarcia@igalia.com>2021-06-22 17:59:48 +0200
commit9a91641a1291d003cd97617079d04e08a6c59ea9 (patch)
tree47ed226728667732b1028003d2af61d47bd20e44
parentfcc79a377ec1e8e38c0554233bb565e41e0e3e94 (diff)
downloadlibsoup-9a91641a1291d003cd97617079d04e08a6c59ea9.tar.gz
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.
-rw-r--r--libsoup/http1/soup-client-message-io-http1.c4
-rw-r--r--libsoup/http1/soup-client-message-io-http1.h2
-rw-r--r--libsoup/http2/soup-client-message-io-http2.c23
-rw-r--r--libsoup/http2/soup-client-message-io-http2.h3
-rw-r--r--libsoup/soup-connection.c8
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;
}