]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon/http: improve handling of stream errors
authorTomas Krizek <tomas.krizek@nic.cz>
Thu, 1 Apr 2021 15:04:10 +0000 (17:04 +0200)
committerLukáš Ježek <lukas.jezek@nic.cz>
Fri, 16 Apr 2021 09:08:56 +0000 (11:08 +0200)
The on_frame_recv() callback ins't guaranteed to be called by nghttp2.
This can happen e.g. in a case when nghttp2 issues a PROTOCOL_ERROR
RST_STREAM frame. Previously, it would leave the connection in a
stream-processing state, making it completely useless.

While this guarantees a cleanup will be called eventually, some streams
may still get ignored due to the order of various callbacks and data
processing procedures. Still, it's better than the previous
implementation.

daemon/http.c

index f72465f65e1313e187cd763815077d0a416fa8ee..5782941e672049eb547c1eaacea3f67bc7ba4fa1 100644 (file)
@@ -243,6 +243,15 @@ static void refuse_stream(nghttp2_session *h2, int32_t stream_id)
                h2, NGHTTP2_FLAG_NONE, stream_id, NGHTTP2_REFUSED_STREAM);
 }
 
+/* Return the http ctx into a pristine state in which no stream is being processed. */
+static void http_cleanup_stream(struct http_ctx *ctx)
+{
+       ctx->incomplete_stream = -1;
+       ctx->current_method = HTTP_METHOD_NONE;
+       free(ctx->uri_path);
+       ctx->uri_path = NULL;
+}
+
 /*
  * Save stream id from first header's frame.
  *
@@ -388,10 +397,7 @@ static int on_frame_recv_callback(nghttp2_session *h2, const nghttp2_frame *fram
                                refuse_stream(h2, stream_id);
                        }
                }
-               ctx->incomplete_stream = -1;
-               ctx->current_method = HTTP_METHOD_NONE;
-               free(ctx->uri_path);
-               ctx->uri_path = NULL;
+               http_cleanup_stream(ctx);
 
                len = ctx->buf_pos - sizeof(uint16_t);
                if (len <= 0 || len > KNOT_WIRE_MAX_PKTSIZE) {
@@ -431,6 +437,12 @@ static int on_stream_close_callback(nghttp2_session *h2, int32_t stream_id,
                                    uint32_t error_code, void *user_data)
 {
        struct http_data *data;
+       struct http_ctx *ctx = (struct http_ctx *)user_data;
+
+       /* Ensure connection state is cleaned up in case the stream gets
+        * unexpectedly closed, e.g. by PROTOCOL_ERROR issued from nghttp2. */
+       if (ctx->incomplete_stream == stream_id)
+               http_cleanup_stream(ctx);
 
        data = nghttp2_session_get_stream_user_data(h2, stream_id);
        if (data)