[libsoup/carlosgc/http2-io-errors: 7/8] server: make sure we don't call nghttp2 IO functions from callbacks




commit 794baa7ec23fcdbeb14c3129a187f1e4a55098b7
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Tue Aug 30 15:28:59 2022 +0200

    server: make sure we don't call nghttp2 IO functions from callbacks

 .../server/http2/soup-server-message-io-http2.c    | 40 ++++++++++++++++++++--
 1 file changed, 38 insertions(+), 2 deletions(-)
---
diff --git a/libsoup/server/http2/soup-server-message-io-http2.c 
b/libsoup/server/http2/soup-server-message-io-http2.c
index 81a5dd3c..e9e2fbfb 100644
--- a/libsoup/server/http2/soup-server-message-io-http2.c
+++ b/libsoup/server/http2/soup-server-message-io-http2.c
@@ -66,6 +66,8 @@ typedef struct {
         gpointer started_user_data;
 
         GHashTable *messages;
+
+        guint in_callback;
 } SoupServerMessageIOHTTP2;
 
 static void soup_server_message_io_http2_send_response (SoupServerMessageIOHTTP2 *io,
@@ -324,6 +326,7 @@ io_write (SoupServerMessageIOHTTP2 *io,
 
         if (io->write_buffer == NULL) {
                 io->written_bytes = 0;
+                g_assert (io->in_callback == 0);
                 io->write_buffer_size = nghttp2_session_mem_send (io->session, (const 
guint8**)&io->write_buffer);
                 if (io->write_buffer_size == 0) {
                         /* Done */
@@ -382,10 +385,10 @@ io_try_write (SoupServerMessageIOHTTP2 *io)
 
         g_object_ref (conn);
 
-        while (!error && soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io && 
nghttp2_session_want_write (io->session))
+        while (!error && soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io && 
!io->in_callback && nghttp2_session_want_write (io->session))
                 io_write (io, &error);
 
-        if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
+        if (io->in_callback || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
                 g_clear_error (&error);
                 io->write_source = g_pollable_output_stream_create_source (G_POLLABLE_OUTPUT_STREAM 
(io->ostream), NULL);
                 g_source_set_name (io->write_source, "Soup server HTTP/2 write source");
@@ -418,6 +421,7 @@ io_read (SoupServerMessageIOHTTP2 *io,
                 return FALSE;
         }
 
+        g_assert (io->in_callback == 0);
         ret = nghttp2_session_mem_recv (io->session, buffer, read);
         if (ret < 0) {
                 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "HTTP/2 IO error: %s", nghttp2_strerror 
(ret));
@@ -496,6 +500,8 @@ on_begin_headers_callback (nghttp2_session     *session,
         if (frame->hd.type != NGHTTP2_HEADERS || frame->headers.cat != NGHTTP2_HCAT_REQUEST)
                 return 0;
 
+        io->in_callback++;
+
         msg_io = soup_server_message_io_http2_get_or_create_msg_io (io, frame->hd.stream_id);
         h2_debug (io, msg_io, "[SESSION] Message IO created");
 
@@ -506,6 +512,8 @@ on_begin_headers_callback (nghttp2_session     *session,
 
         advance_state_from (msg_io, STATE_NONE, STATE_READ_HEADERS);
 
+        io->in_callback--;
+
         return 0;
 }
 
@@ -519,6 +527,7 @@ on_header_callback (nghttp2_session     *session,
                     uint8_t              flags,
                     void                *user_data)
 {
+        SoupServerMessageIOHTTP2 *io = (SoupServerMessageIOHTTP2 *)user_data;
         SoupMessageIOHTTP2 *msg_io;
         SoupServerMessage *msg;
 
@@ -532,6 +541,8 @@ on_header_callback (nghttp2_session     *session,
         if (!msg_io)
                 return 0;
 
+        io->in_callback++;
+
         msg = msg_io->msg;
         if (name[0] == ':') {
                 if (strcmp ((char *)name, ":method") == 0)
@@ -544,11 +555,14 @@ on_header_callback (nghttp2_session     *session,
                         msg_io->path = g_strndup ((char *)value, valuelen);
                 else
                         g_debug ("Unknown header: %s = %s", name, value);
+                io->in_callback--;
                 return 0;
         }
 
         soup_message_headers_append_untrusted_data (soup_server_message_get_request_headers (msg),
                                                     (const char*)name, (const char*)value);
+
+        io->in_callback--;
         return 0;
 }
 
@@ -560,6 +574,7 @@ on_data_chunk_recv_callback (nghttp2_session *session,
                              size_t           len,
                              void            *user_data)
 {
+        SoupServerMessageIOHTTP2 *io = (SoupServerMessageIOHTTP2 *)user_data;
         SoupMessageIOHTTP2 *msg_io;
         GBytes *bytes;
 
@@ -569,11 +584,15 @@ on_data_chunk_recv_callback (nghttp2_session *session,
 
         h2_debug (user_data, msg_io, "[DATA] Received chunk, len=%zu, flags=%u, paused=%d", len, flags, 
msg_io->paused);
 
+        io->in_callback++;
+
         bytes = g_bytes_new (data, len);
         soup_message_body_got_chunk (soup_server_message_get_request_body (msg_io->msg), bytes);
         soup_server_message_got_chunk (msg_io->msg, bytes);
         g_bytes_unref (bytes);
 
+        io->in_callback--;
+
         return 0;
 }
 
@@ -586,10 +605,13 @@ on_data_source_read_callback (nghttp2_session     *session,
                               nghttp2_data_source *source,
                               void                *user_data)
 {
+        SoupServerMessageIOHTTP2 *io = (SoupServerMessageIOHTTP2 *)user_data;
         SoupMessageIOHTTP2 *msg_io;
         gsize bytes_written = 0;
         SoupMessageBody *response_body = (SoupMessageBody *)source->ptr;
 
+        io->in_callback++;
+
         msg_io = nghttp2_session_get_stream_user_data (session, stream_id);
 
         h2_debug (user_data, msg_io, "[SEND_BODY] paused=%d", msg_io->paused);
@@ -625,6 +647,8 @@ on_data_source_read_callback (nghttp2_session     *session,
                 *data_flags |= NGHTTP2_DATA_FLAG_EOF;
         }
 
+        io->in_callback--;
+
         return bytes_written;
 }
 
@@ -689,6 +713,8 @@ on_frame_recv_callback (nghttp2_session     *session,
         if (!msg_io)
                 return 0;
 
+        io->in_callback++;
+
         switch (frame->hd.type) {
         case NGHTTP2_HEADERS: {
                 char *uri_string;
@@ -707,6 +733,7 @@ on_frame_recv_callback (nghttp2_session     *session,
         case NGHTTP2_DATA:
                 break;
         default:
+                io->in_callback--;
                 return 0;
         }
 
@@ -716,6 +743,7 @@ on_frame_recv_callback (nghttp2_session     *session,
                 soup_server_message_io_http2_send_response (io, msg_io);
         }
 
+        io->in_callback--;
         return 0;
 }
 
@@ -724,8 +752,11 @@ on_frame_send_callback (nghttp2_session     *session,
                         const nghttp2_frame *frame,
                         void                *user_data)
 {
+        SoupServerMessageIOHTTP2 *io = (SoupServerMessageIOHTTP2 *)user_data;
         SoupMessageIOHTTP2 *msg_io;
 
+        io->in_callback++;
+
         msg_io = nghttp2_session_get_stream_user_data (session, frame->hd.stream_id);
 
         h2_debug (user_data, msg_io, "[SEND] [%s]", soup_http2_frame_type_to_string (frame->hd.type));
@@ -747,6 +778,7 @@ on_frame_send_callback (nghttp2_session     *session,
                 break;
         }
 
+        io->in_callback--;
         return 0;
 }
 
@@ -756,6 +788,7 @@ on_stream_close_callback (nghttp2_session *session,
                           uint32_t         error_code,
                           void            *user_data)
 {
+        SoupServerMessageIOHTTP2 *io = (SoupServerMessageIOHTTP2 *)user_data;
         SoupMessageIOHTTP2 *msg_io;
 
         msg_io = nghttp2_session_get_stream_user_data (session, stream_id);
@@ -763,9 +796,12 @@ on_stream_close_callback (nghttp2_session *session,
         if (!msg_io)
                 return 0;
 
+        io->in_callback++;
+
         if (!msg_io->paused)
                 soup_server_message_finish (msg_io->msg);
 
+        io->in_callback--;
         return 0;
 }
 


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