diff options
author | Stefan Eissing <icing@apache.org> | 2024-05-27 13:04:52 +0200 |
---|---|---|
committer | Stefan Eissing <icing@apache.org> | 2024-05-27 13:04:52 +0200 |
commit | c69a51bff8157e403121f8436d85dde21ad28bd2 (patch) | |
tree | 81a298b558ae7f2a9b8bfe811ae0a7088ca22b54 /modules/http2 | |
parent | steal a number (diff) | |
download | apache2-c69a51bff8157e403121f8436d85dde21ad28bd2.tar.xz apache2-c69a51bff8157e403121f8436d85dde21ad28bd2.zip |
*) mod_http2: sync with module's github.
- on newer HTTPD versions, return connection monitoring
to the event MPM when block on client updates.
2.4.x versions still treat connections in the event
MPM as KeepAlive and purge them on load in the middle
of response processing.
- spelling fixes
- support for yield calls in c2 "network" filter
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1918003 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/http2')
-rw-r--r-- | modules/http2/h2_c1.c | 6 | ||||
-rw-r--r-- | modules/http2/h2_c2.c | 7 | ||||
-rw-r--r-- | modules/http2/h2_mplx.c | 24 | ||||
-rw-r--r-- | modules/http2/h2_mplx.h | 5 | ||||
-rw-r--r-- | modules/http2/h2_session.c | 48 | ||||
-rw-r--r-- | modules/http2/h2_session.h | 5 | ||||
-rw-r--r-- | modules/http2/h2_version.h | 4 |
7 files changed, 86 insertions, 13 deletions
diff --git a/modules/http2/h2_c1.c b/modules/http2/h2_c1.c index afb26fc073..739b1d14d5 100644 --- a/modules/http2/h2_c1.c +++ b/modules/http2/h2_c1.c @@ -116,7 +116,7 @@ cleanup: apr_status_t h2_c1_run(conn_rec *c) { apr_status_t status; - int mpm_state = 0; + int mpm_state = 0, keepalive = 0; h2_conn_ctx_t *conn_ctx = h2_conn_ctx_get(c); ap_assert(conn_ctx); @@ -127,7 +127,7 @@ apr_status_t h2_c1_run(conn_rec *c) c->cs->state = CONN_STATE_HANDLER; } - status = h2_session_process(conn_ctx->session, async_mpm); + status = h2_session_process(conn_ctx->session, async_mpm, &keepalive); if (APR_STATUS_IS_EOF(status)) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c, @@ -153,7 +153,7 @@ apr_status_t h2_c1_run(conn_rec *c) case H2_SESSION_ST_BUSY: case H2_SESSION_ST_WAIT: c->cs->state = CONN_STATE_WRITE_COMPLETION; - if (c->cs && !conn_ctx->session->remote.emitted_count) { + if (!keepalive) { /* let the MPM know that we are not done and want * the Timeout behaviour instead of a KeepAliveTimeout * See PR 63534. diff --git a/modules/http2/h2_c2.c b/modules/http2/h2_c2.c index a955200944..51e921310f 100644 --- a/modules/http2/h2_c2.c +++ b/modules/http2/h2_c2.c @@ -370,6 +370,13 @@ static apr_status_t h2_c2_filter_out(ap_filter_t* f, apr_bucket_brigade* bb) h2_conn_ctx_t *conn_ctx = h2_conn_ctx_get(f->c); apr_status_t rv; + if (bb == NULL) { +#if !AP_MODULE_MAGIC_AT_LEAST(20180720, 1) + f->c->data_in_output_filters = 0; +#endif + return APR_SUCCESS; + } + ap_assert(conn_ctx); #if AP_HAS_RESPONSE_BUCKETS if (!conn_ctx->has_final_response) { diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c index 9f9ce8087e..71a743177f 100644 --- a/modules/http2/h2_mplx.c +++ b/modules/http2/h2_mplx.c @@ -398,6 +398,7 @@ apr_status_t h2_mplx_c1_streams_do(h2_mplx *m, h2_mplx_stream_cb *cb, void *ctx) typedef struct { int stream_count; int stream_want_send; + int stream_send_win_exhausted; } stream_iter_aws_t; static int m_stream_want_send_data(void *ctx, void *stream) @@ -420,6 +421,29 @@ int h2_mplx_c1_all_streams_want_send_data(h2_mplx *m) return x.stream_count && (x.stream_count == x.stream_want_send); } +static int m_stream_send_win_exh(void *ctx, void *s) +{ + h2_stream *stream = s; + int win; + stream_iter_aws_t *x = ctx; + ++x->stream_count; + win = nghttp2_session_get_stream_remote_window_size(stream->session->ngh2, stream->id); + if (win == 0) + ++x->stream_send_win_exhausted; + return 1; +} + +int h2_mplx_c1_all_streams_send_win_exhausted(h2_mplx *m) +{ + stream_iter_aws_t x; + x.stream_count = 0; + x.stream_send_win_exhausted = 0; + H2_MPLX_ENTER(m); + h2_ihash_iter(m->streams, m_stream_send_win_exh, &x); + H2_MPLX_LEAVE(m); + return x.stream_count && (x.stream_count == x.stream_send_win_exhausted); +} + 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 860f916039..12e36f766f 100644 --- a/modules/http2/h2_mplx.h +++ b/modules/http2/h2_mplx.h @@ -197,6 +197,11 @@ apr_status_t h2_mplx_c1_streams_do(h2_mplx *m, h2_mplx_stream_cb *cb, void *ctx) int h2_mplx_c1_all_streams_want_send_data(h2_mplx *m); /** + * Return != 0 iff all open streams have send window exhausted + */ +int h2_mplx_c1_all_streams_send_win_exhausted(h2_mplx *m); + +/** * A stream has been RST_STREAM by the client. Abort * any processing going on and remove from processing * queue. diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c index 5724fdadb0..25001730a7 100644 --- a/modules/http2/h2_session.c +++ b/modules/http2/h2_session.c @@ -323,8 +323,8 @@ static int on_header_cb(nghttp2_session *ngh2, const nghttp2_frame *frame, (!stream->rtmp || stream->rtmp->http_status == H2_HTTP_STATUS_UNSET || /* We accept a certain amount of failures in order to reply - * with an informative HTTP error response like 413. But if the - * client is too wrong, we fail the request a RESET of the stream */ + * with an informative HTTP error response like 413. But of the + * client is too wrong, we RESET the stream */ stream->request_headers_failed > 100)) { return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } @@ -1762,12 +1762,22 @@ static void unblock_c1_out(h2_session *session) { } } -apr_status_t h2_session_process(h2_session *session, int async) +static int h2_send_flow_blocked(h2_session *session) +{ + /* We are completely send blocked if either the connection window + * is 0 or all stream flow windows are 0. */ + return ((nghttp2_session_get_remote_window_size(session->ngh2) <= 0) || + h2_mplx_c1_all_streams_send_win_exhausted(session->mplx)); +} + +apr_status_t h2_session_process(h2_session *session, int async, + int *pkeepalive) { apr_status_t status = APR_SUCCESS; conn_rec *c = session->c1; int rv, mpm_state, trace = APLOGctrace3(c); + *pkeepalive = 0; if (trace) { ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c, H2_SSSN_MSG(session, "process start, async=%d"), async); @@ -1922,6 +1932,14 @@ apr_status_t h2_session_process(h2_session *session, int async) break; case H2_SESSION_ST_WAIT: + /* In this state, we might have returned processing to the MPM + * before. On a connection socket event, we are invoked again and + * need to process any input before proceeding. */ + h2_c1_read(session); + if (session->state != H2_SESSION_ST_WAIT) { + break; + } + status = h2_c1_io_assure_flushed(&session->io); if (APR_SUCCESS != status) { h2_session_dispatch_event(session, H2_SESSION_EV_CONN_ERROR, status, NULL); @@ -1934,8 +1952,20 @@ apr_status_t h2_session_process(h2_session *session, int async) break; } } - /* No IO happening and input is exhausted. Make sure we have - * flushed any possibly pending output and then wait with +#if AP_MODULE_MAGIC_AT_LEAST(20211221, 19) + else if (async && h2_send_flow_blocked(session)) { + /* On a recent HTTPD, we can return to mpm c1 monitoring, + * as it does not treat all connections as having KeepAlive + * timing and being purgeable on load. + * By returning to the MPM, we do not block a worker + * and async wait for the client send window updates. */ + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c, + H2_SSSN_LOG(APLOGNO(10502), session, + "BLOCKED, return to mpm c1 monitoring")); + goto leaving; + } +#endif + /* No IO happening and input is exhausted. Wait with * the c1 connection timeout for sth to happen in our c1/c2 sockets/pipes */ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, c, H2_SSSN_MSG(session, "polling timeout=%d, open_streams=%d"), @@ -1976,9 +2006,13 @@ apr_status_t h2_session_process(h2_session *session, int async) } leaving: + /* entering KeepAlive timing when we have no more open streams AND + * we have processed at least one stream. */ + *pkeepalive = (session->open_streams == 0 && session->remote.emitted_count); if (trace) { - ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c, - H2_SSSN_MSG(session, "process returns")); + ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c, + H2_SSSN_MSG(session, "process returns, keepalive=%d"), + *pkeepalive); } h2_mplx_c1_going_keepalive(session->mplx); diff --git a/modules/http2/h2_session.h b/modules/http2/h2_session.h index 3328509de8..2c8f334cce 100644 --- a/modules/http2/h2_session.h +++ b/modules/http2/h2_session.h @@ -144,8 +144,11 @@ void h2_session_event(h2_session *session, h2_session_event_t ev, * error occurred. * * @param session the sessionm to process + * @param async if mpm is async + * @param pkeepalive on return, != 0 if connection to be put into keepalive + * behaviour and timouts */ -apr_status_t h2_session_process(h2_session *session, int async); +apr_status_t h2_session_process(h2_session *session, int async, int *pkeepalive); /** * Last chance to do anything before the connection is closed. diff --git a/modules/http2/h2_version.h b/modules/http2/h2_version.h index 80cec13415..bf222078e7 100644 --- a/modules/http2/h2_version.h +++ b/modules/http2/h2_version.h @@ -27,7 +27,7 @@ * @macro * Version number of the http2 module as c string */ -#define MOD_HTTP2_VERSION "2.0.26" +#define MOD_HTTP2_VERSION "2.0.27" /** * @macro @@ -35,7 +35,7 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define MOD_HTTP2_VERSION_NUM 0x02001a +#define MOD_HTTP2_VERSION_NUM 0x02001b #endif /* mod_h2_h2_version_h */ |