[libsoup/carlosgc/http2-io-errors: 8/8] http2: retry messages that failed due to IO errors




commit fbc21347c8ab56c08ddb61f7146b485225df86f8
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Mon Aug 29 12:00:35 2022 +0200

    http2: retry messages that failed due to IO errors

 libsoup/http2/soup-client-message-io-http2.c | 26 ++++++++++++++++---
 tests/connection-test.c                      | 39 ++++++++++++++++++----------
 2 files changed, 48 insertions(+), 17 deletions(-)
---
diff --git a/libsoup/http2/soup-client-message-io-http2.c b/libsoup/http2/soup-client-message-io-http2.c
index 528c4e36..6a5b2265 100644
--- a/libsoup/http2/soup-client-message-io-http2.c
+++ b/libsoup/http2/soup-client-message-io-http2.c
@@ -211,6 +211,21 @@ advance_state_from (SoupHTTP2MessageData *data,
         data->state = to;
 }
 
+static gboolean
+soup_http2_message_data_can_be_restarted (SoupHTTP2MessageData *data,
+                                          GError               *error)
+{
+        if (data->can_be_restarted)
+                return TRUE;
+
+        return data->state < STATE_READ_DATA_START &&
+                !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT) &&
+                !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) &&
+                !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+                error->domain != G_TLS_ERROR &&
+                SOUP_METHOD_IS_IDEMPOTENT (soup_message_get_method (data->msg));
+}
+
 static void
 soup_http2_message_data_check_status (SoupHTTP2MessageData *data)
 {
@@ -237,7 +252,7 @@ soup_http2_message_data_check_status (SoupHTTP2MessageData *data)
         if (data->error) {
                 GError *error = g_steal_pointer (&data->error);
 
-                if (data->can_be_restarted)
+                if (soup_http2_message_data_can_be_restarted (data, error))
                         data->item->state = SOUP_MESSAGE_RESTARTING;
                 else
                         soup_message_set_metrics_timestamp (data->msg, SOUP_MESSAGE_METRICS_RESPONSE_END);
@@ -924,7 +939,7 @@ on_stream_close_callback (nghttp2_session *session,
 
         switch (error_code) {
         case NGHTTP2_REFUSED_STREAM:
-                if (data->state < STATE_READ_DATA)
+                if (data->state < STATE_READ_DATA_START)
                         data->can_be_restarted = TRUE;
                 break;
         case NGHTTP2_HTTP_1_1_REQUIRED:
@@ -1601,12 +1616,13 @@ soup_client_message_io_http2_run_until_read (SoupClientMessageIO  *iface,
 {
         SoupClientMessageIOHTTP2 *io = (SoupClientMessageIOHTTP2 *)iface;
         SoupHTTP2MessageData *data = get_data_for_message (io, msg);
+        GError *my_error = NULL;
 
-        if (io_run_until (io, msg, STATE_READ_DATA, cancellable, error))
+        if (io_run_until (io, msg, STATE_READ_DATA, cancellable, &my_error))
                 return TRUE;
 
         if (get_io_data (msg) == io) {
-                if (data->can_be_restarted)
+                if (soup_http2_message_data_can_be_restarted (data, my_error))
                         data->item->state = SOUP_MESSAGE_RESTARTING;
                 else
                         soup_message_set_metrics_timestamp (msg, SOUP_MESSAGE_METRICS_RESPONSE_END);
@@ -1614,6 +1630,8 @@ soup_client_message_io_http2_run_until_read (SoupClientMessageIO  *iface,
                 soup_client_message_io_http2_finished (iface, msg);
         }
 
+        g_propagate_error (error, my_error);
+
         return FALSE;
 }
 
diff --git a/tests/connection-test.c b/tests/connection-test.c
index 8a1ca7e5..18b75f31 100644
--- a/tests/connection-test.c
+++ b/tests/connection-test.c
@@ -13,6 +13,7 @@
 
 static SoupServer *server;
 static GUri *base_uri;
+static GUri *base_https_uri;
 static GMutex server_mutex;
 
 static void
@@ -63,7 +64,6 @@ timeout_request_finished (SoupServer        *server,
                           gpointer           user_data)
 {
        SoupServerConnection *conn;
-       GMainContext *context = g_main_context_get_thread_default ();
        GIOStream *iostream;
        GInputStream *istream;
        GSource *source;
@@ -79,8 +79,6 @@ timeout_request_finished (SoupServer        *server,
        g_source_unref (source);
 
        g_mutex_unlock (&server_mutex);
-       while (soup_server_connection_is_connected (conn))
-               g_main_context_iteration (context, TRUE);
 }
 
 static void
@@ -261,14 +259,17 @@ request_queued_socket_collector (SoupSession *session,
 }
 
 static void
-do_timeout_test_for_session (SoupSession *session)
+do_timeout_test_for_base_uri (GUri *base_uri)
 {
+        SoupSession *session;
        SoupMessage *msg;
        GSocket *sockets[4] = { NULL, NULL, NULL, NULL };
        GUri *timeout_uri;
        int i;
        GBytes *body;
 
+        session = soup_test_session_new (NULL);
+
        g_signal_connect (session, "request-queued",
                          G_CALLBACK (request_queued_socket_collector),
                          &sockets);
@@ -311,23 +312,24 @@ do_timeout_test_for_session (SoupSession *session)
 
        for (i = 0; sockets[i]; i++)
                g_object_unref (sockets[i]);
+
+        soup_test_session_abort_unref (session);
 }
 
 static void
 do_persistent_connection_timeout_test (void)
 {
-       SoupSession *session;
-
        g_test_bug ("631525");
 
-       debug_printf (1, "  Normal session, message API\n");
-       session = soup_test_session_new (NULL);
-       do_timeout_test_for_session (session);
-       soup_test_session_abort_unref (session);
+        debug_printf (1, "  HTTP/1\n");
+        do_timeout_test_for_base_uri (base_uri);
+
+        debug_printf (1, "  HTTP/2\n");
+        do_timeout_test_for_base_uri (base_https_uri);
 }
 
 static void
-do_persistent_connection_timeout_test_with_cancellation (void)
+do_persistent_connection_timeout_test_with_cancellation_for_base_uri (GUri *base_uri)
 {
        SoupSession *session;
        SoupMessage *msg;
@@ -410,6 +412,16 @@ do_persistent_connection_timeout_test_with_cancellation (void)
        soup_test_session_abort_unref (session);
 }
 
+static void
+do_persistent_connection_timeout_test_with_cancellation (void)
+{
+        debug_printf (1, "  HTTP/1\n");
+        do_persistent_connection_timeout_test_with_cancellation_for_base_uri (base_uri);
+
+        debug_printf (1, "  HTTP/2\n");
+        do_persistent_connection_timeout_test_with_cancellation_for_base_uri (base_https_uri);
+}
+
 static GMainLoop *max_conns_loop;
 static int msgs_done;
 static guint quit_loop_timeout;
@@ -1693,9 +1705,10 @@ main (int argc, char **argv)
        test_init (argc, argv, NULL);
        apache_init ();
 
-       server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
-       soup_server_add_handler (server, NULL, server_callback, "http", NULL);
+       server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD | SOUP_TEST_SERVER_HTTP2);
+       soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
        base_uri = soup_test_server_get_uri (server, "http", NULL);
+        base_https_uri = soup_test_server_get_uri (server, "https", NULL);
 
        g_test_add_func ("/connection/content-length-framing", do_content_length_framing_test);
        g_test_add_func ("/connection/persistent-connection-timeout", do_persistent_connection_timeout_test);


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