]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Merge of 1912385 from trunk:
authorStefan Eissing <icing@apache.org>
Mon, 16 Oct 2023 06:18:54 +0000 (06:18 +0000)
committerStefan Eissing <icing@apache.org>
Mon, 16 Oct 2023 06:18:54 +0000 (06:18 +0000)
  *) mod_http2: fixed a bug in handling of stream timeouts.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1912991 13f79535-47bb-0310-9956-ffa450edef68

changes-entries/h2_stream_timeout.txt [new file with mode: 0644]
modules/http2/h2_mplx.c
modules/http2/h2_mplx.h
modules/http2/h2_session.c
modules/http2/h2_stream.c
modules/http2/h2_stream.h

diff --git a/changes-entries/h2_stream_timeout.txt b/changes-entries/h2_stream_timeout.txt
new file mode 100644 (file)
index 0000000..401028e
--- /dev/null
@@ -0,0 +1,2 @@
+ * mod_http2: fixed a bug in handling of stream timeouts.
+   [Stefan Eissing]
index 460a38a00a95f011f4baf69fc916dc9ce2155c96..4637a5f66efd50156af5a6a2fa0d716f03e529fe 100644 (file)
@@ -394,6 +394,31 @@ apr_status_t h2_mplx_c1_streams_do(h2_mplx *m, h2_mplx_stream_cb *cb, void *ctx)
     return APR_SUCCESS;
 }
 
+typedef struct {
+    int stream_count;
+    int stream_want_send;
+} stream_iter_aws_t;
+
+static int m_stream_want_send_data(void *ctx, void *stream)
+{
+    stream_iter_aws_t *x = ctx;
+    ++x->stream_count;
+    if (h2_stream_wants_send_data(stream))
+      ++x->stream_want_send;
+    return 1;
+}
+
+int h2_mplx_c1_all_streams_want_send_data(h2_mplx *m)
+{
+    stream_iter_aws_t x;
+    x.stream_count = 0;
+    x.stream_want_send = 0;
+    H2_MPLX_ENTER(m);
+    h2_ihash_iter(m->streams, m_stream_want_send_data, &x);
+    H2_MPLX_LEAVE(m);
+    return x.stream_count && (x.stream_count == x.stream_want_send);
+}
+
 static int m_report_stream_iter(void *ctx, void *val) {
     h2_mplx *m = ctx;
     h2_stream *stream = val;
index 781ddf2f4d5edc44dc74b3e2413e48cb5bc41888..a2e73d9d7c3855c9f978a8c7c84757c16a087594 100644 (file)
@@ -191,6 +191,11 @@ typedef int h2_mplx_stream_cb(struct h2_stream *s, void *userdata);
  */
 apr_status_t h2_mplx_c1_streams_do(h2_mplx *m, h2_mplx_stream_cb *cb, void *ctx);
 
+/**
+ * Return != 0 iff all open streams want to send data
+ */
+int h2_mplx_c1_all_streams_want_send_data(h2_mplx *m);
+
 /**
  * A stream has been RST_STREAM by the client. Abort
  * any processing going on and remove from processing
index c104cac18412311731163360ec96a7f48513837e..066c73ad98bc6f704f11452e90958b4eacdeae58 100644 (file)
@@ -1921,7 +1921,15 @@ apr_status_t h2_session_process(h2_session *session, int async)
             status = h2_mplx_c1_poll(session->mplx, session->s->timeout,
                                      on_stream_input, on_stream_output, session);
             if (APR_STATUS_IS_TIMEUP(status)) {
-                if (session->open_streams == 0) {
+                /* If we timeout without streams open, no new request from client
+                 * arrived.
+                 * If we timeout without nghttp2 wanting to write something, but
+                 * all open streams have something to send, it means we are
+                 * blocked on HTTP/2 flow control and the client did not send
+                 * WINDOW_UPDATEs to us. */
+                if (session->open_streams == 0 ||
+                    (!h2_session_want_send(session) &&
+                     h2_mplx_c1_all_streams_want_send_data(session->mplx))) {
                     h2_session_dispatch_event(session, H2_SESSION_EV_CONN_TIMEOUT, status, NULL);
                     break;
                 }
index 257f0c7a9e3b4703194053f42141438720e34820..c419e2d85914288dfec46f455edae6425c8d7223 100644 (file)
@@ -1264,6 +1264,14 @@ int h2_stream_is_ready(h2_stream *stream)
     return 0;
 }
 
+int h2_stream_wants_send_data(h2_stream *stream)
+{
+    H2_STRM_ASSERT_MAGIC(stream, H2_STRM_MAGIC_OK);
+    return h2_stream_is_ready(stream) &&
+           ((stream->out_buffer && !APR_BRIGADE_EMPTY(stream->out_buffer)) ||
+            (stream->output && !h2_beam_empty(stream->output)));
+}
+
 int h2_stream_is_at(const h2_stream *stream, h2_stream_state_t state)
 {
     H2_STRM_ASSERT_MAGIC(stream, H2_STRM_MAGIC_OK);
index 638dbdac0d158aa841adfb7c3e3d4e6d00f6e605..d68d426038ad69bbdfe9d640d9f4449bae81479e 100644 (file)
@@ -332,6 +332,8 @@ const char *h2_stream_state_str(const h2_stream *stream);
  */
 int h2_stream_is_ready(h2_stream *stream);
 
+int h2_stream_wants_send_data(h2_stream *stream);
+
 #define H2_STRM_MSG(s, msg)     \
     "h2_stream(%d-%lu-%d,%s): "msg, s->session->child_num, \
     (unsigned long)s->session->id, s->id, h2_stream_state_str(s)