[libsoup/carlosgc/http2-protocol-errors: 1/2] http2: Handle all http2 errors on stream close




commit a31e1744191b88d0da4dcdc4d95cc78f37c2609a
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Wed Aug 31 14:33:41 2022 +0200

    http2: Handle all http2 errors on stream close
    
    Set the data error and save thee http2 error to ensure we don't retry
    the message in case of unhandled http2 error.

 libsoup/http2/soup-client-message-io-http2.c | 30 ++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)
---
diff --git a/libsoup/http2/soup-client-message-io-http2.c b/libsoup/http2/soup-client-message-io-http2.c
index 6a5b2265..6f7dd747 100644
--- a/libsoup/http2/soup-client-message-io-http2.c
+++ b/libsoup/http2/soup-client-message-io-http2.c
@@ -106,6 +106,7 @@ typedef struct {
         gpointer completion_data;
         SoupHTTP2IOState state;
         GError *error;
+        uint32_t http2_error;
         gboolean paused;
         guint32 stream_id;
         gboolean can_be_restarted;
@@ -170,6 +171,20 @@ set_error_for_data (SoupHTTP2MessageData *data,
                 g_error_free (error);
 }
 
+static void
+set_http2_error_for_data (SoupHTTP2MessageData *data,
+                          uint32_t              error_code)
+{
+        h2_debug (data->io, data, "[SESSION] Error: %s", nghttp2_http2_strerror (error_code));
+
+        if (data->error)
+                return;
+
+        data->http2_error = error_code;
+        data->error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
+                                   "HTTP/2 Error: %s", nghttp2_http2_strerror (error_code));
+}
+
 static void
 set_io_error (SoupClientMessageIOHTTP2 *io,
               GError                   *error)
@@ -223,6 +238,7 @@ soup_http2_message_data_can_be_restarted (SoupHTTP2MessageData *data,
                 !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 &&
+                data->http2_error == NGHTTP2_NO_ERROR &&
                 SOUP_METHOD_IS_IDEMPOTENT (soup_message_get_method (data->msg));
 }
 
@@ -600,8 +616,7 @@ handle_goaway (SoupClientMessageIOHTTP2 *io,
                 if ((error_code == 0 && (int32_t)data->stream_id > last_stream_id) ||
                      data->state < STATE_READ_DONE) {
                         /* TODO: We can restart unfinished messages */
-                        set_error_for_data (data, g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
-                                            "HTTP/2 Error: %s", nghttp2_http2_strerror (error_code)));
+                        set_http2_error_for_data (data, error_code);
                 }
         }
 }
@@ -715,10 +730,8 @@ on_frame_recv_callback (nghttp2_session     *session,
                 }
                 break;
         case NGHTTP2_RST_STREAM:
-                if (frame->rst_stream.error_code != NGHTTP2_NO_ERROR) {
-                        set_error_for_data (data, g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED,
-                                                                       nghttp2_http2_strerror 
(frame->rst_stream.error_code)));
-                }
+                if (frame->rst_stream.error_code != NGHTTP2_NO_ERROR)
+                        set_http2_error_for_data (data, frame->rst_stream.error_code);
                 break;
         case NGHTTP2_WINDOW_UPDATE:
                 h2_debug (io, data, "[RECV] WINDOW_UPDATE: increment=%d, total=%d", 
frame->window_update.window_size_increment,
@@ -938,6 +951,8 @@ on_stream_close_callback (nghttp2_session *session,
         data->io->in_callback++;
 
         switch (error_code) {
+        case NGHTTP2_NO_ERROR:
+                break;
         case NGHTTP2_REFUSED_STREAM:
                 if (data->state < STATE_READ_DATA_START)
                         data->can_be_restarted = TRUE;
@@ -946,6 +961,9 @@ on_stream_close_callback (nghttp2_session *session,
                 soup_message_set_force_http_version (data->item->msg, SOUP_HTTP_1_1);
                 data->can_be_restarted = TRUE;
                 break;
+        default:
+                set_http2_error_for_data (data, error_code);
+                break;
         }
 
         data->io->in_callback--;


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