135 lines
4.9 KiB
Diff
135 lines
4.9 KiB
Diff
From 582c533c1728459eef5f8ec1a64b81fb093b26a8 Mon Sep 17 00:00:00 2001
|
|
From: SteFan Eissing <icing@apache.org>
|
|
Date: Mon, 16 Oct 2023 06:18:30 +0000
|
|
Subject: [PATCH] mod_http2: fixed a bug in handling of stream timeouts.
|
|
|
|
Conflict:NA
|
|
Reference:https://github.com/apache/httpd/commit/582c533c1728459eef5f8ec1a64b81fb093b26a8
|
|
|
|
---
|
|
changes-entries/h2_stream_timeout.txt | 2 ++
|
|
modules/http2/h2_mplx.c | 25 +++++++++++++++++++++++++
|
|
modules/http2/h2_mplx.h | 5 +++++
|
|
modules/http2/h2_session.c | 10 +++++++++-
|
|
modules/http2/h2_stream.c | 8 ++++++++
|
|
modules/http2/h2_stream.h | 2 ++
|
|
6 files changed, 51 insertions(+), 1 deletion(-)
|
|
create mode 100644 changes-entries/h2_stream_timeout.txt
|
|
|
|
diff --git a/changes-entries/h2_stream_timeout.txt b/changes-entries/h2_stream_timeout.txt
|
|
new file mode 100644
|
|
index 0000000..ab39b42
|
|
--- /dev/null
|
|
+++ b/changes-entries/h2_stream_timeout.txt
|
|
@@ -0,0 +1,2 @@
|
|
+* mod_http2: fixed a bug in handing of stream timeouts.
|
|
+ [Stefan Eissing]
|
|
diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c
|
|
index b4855af..e150cc3 100644
|
|
--- a/modules/http2/h2_mplx.c
|
|
+++ b/modules/http2/h2_mplx.c
|
|
@@ -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;
|
|
diff --git a/modules/http2/h2_mplx.h b/modules/http2/h2_mplx.h
|
|
index f565a09..730bb16 100644
|
|
--- a/modules/http2/h2_mplx.h
|
|
+++ b/modules/http2/h2_mplx.h
|
|
@@ -193,6 +193,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
|
|
diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c
|
|
index f740373..8aeff3c 100644
|
|
--- a/modules/http2/h2_session.c
|
|
+++ b/modules/http2/h2_session.c
|
|
@@ -1931,7 +1931,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, bug
|
|
+ * 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_stream == 0 ||
|
|
+ (!h2_session_want_send(session) &&
|
|
+ h2_mplx_c1_all_streams_want_send_data(session->m))) {
|
|
h2_session_dispatch_event(session, H2_SESSION_EV_CONN_TIMEOUT, status, NULL);
|
|
break;
|
|
}
|
|
diff --git a/modules/http2/h2_stream.c b/modules/http2/h2_stream.c
|
|
index 17e5d34..c81c3e4 100644
|
|
--- a/modules/http2/h2_stream.c
|
|
+++ b/modules/http2/h2_stream.c
|
|
@@ -1185,6 +1185,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)
|
|
{
|
|
return stream->state == state;
|
|
diff --git a/modules/http2/h2_stream.h b/modules/http2/h2_stream.h
|
|
index 695d56a..647ef2d 100644
|
|
--- a/modules/http2/h2_stream.h
|
|
+++ b/modules/http2/h2_stream.h
|
|
@@ -317,6 +317,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)
|
|
--
|
|
2.23.0
|
|
|