From 582c533c1728459eef5f8ec1a64b81fb093b26a8 Mon Sep 17 00:00:00 2001 From: SteFan Eissing 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