]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
*) mod_http2: sync with module's github.
authorStefan Eissing <icing@apache.org>
Mon, 27 May 2024 11:04:52 +0000 (11:04 +0000)
committerStefan Eissing <icing@apache.org>
Mon, 27 May 2024 11:04:52 +0000 (11:04 +0000)
    - 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

modules/http2/h2_c1.c
modules/http2/h2_c2.c
modules/http2/h2_mplx.c
modules/http2/h2_mplx.h
modules/http2/h2_session.c
modules/http2/h2_session.h
modules/http2/h2_version.h

index afb26fc0737a48a977ca4456dac56e64ea300f84..739b1d14d5ad1a398f7260ea5eee7aea6ff053fa 100644 (file)
@@ -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. 
index a955200944214de8f4bbead817b9e15cb66c9bcc..51e921310f9d2870d30544fec0c5a4f41bf40708 100644 (file)
@@ -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) {
index 9f9ce8087e25f738a3e0ebbcd1b167c42346137e..71a743177f206d6f6fe7204fede6e03d2fa9cd15 100644 (file)
@@ -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;
index 860f916039785573247938950ffc3599a44507b6..12e36f766f4397baf1e802e71848712ee16fbe24 100644 (file)
@@ -196,6 +196,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
index 5724fdadb018ec68345169f5474193edc324bcf8..25001730a70e8e9dba11b1103b3ca328f5472f0d 100644 (file)
@@ -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);
 
index 3328509de8ac0ac390c38b707513d6252100734f..2c8f334cce0d779fad3252ba8d953e2c8c526d5c 100644 (file)
@@ -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.
index 80cec134156be8c03fd556e012fc9bf6668e2d21..bf222078e7eeaf31305c6d45aa4aa7d5ea4b8213 100644 (file)
@@ -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 */