]> git.kaiwu.me - nginx.git/commitdiff
Proxy: extracted control frame and skip functions for HTTP/2.
authorZhidao HONG <z.hong@f5.com>
Sun, 30 Nov 2025 16:27:26 +0000 (16:27 +0000)
committerRoman Arutyunyan <arutyunyan.roman@gmail.com>
Mon, 8 Dec 2025 03:49:16 +0000 (07:49 +0400)
src/http/modules/ngx_http_proxy_v2_module.c

index fc93ca71ca9ed84f3c4a5ed4f65efcf2abe89cc2..007a497a80a0365ee93d42de7b2d7a532875916b 100644 (file)
@@ -117,6 +117,10 @@ static ngx_int_t ngx_http_proxy_v2_process_header(ngx_http_request_t *r);
 static ngx_int_t ngx_http_proxy_v2_filter_init(void *data);
 static ngx_int_t ngx_http_proxy_v2_non_buffered_filter(void *data,
     ssize_t bytes);
+static ngx_int_t ngx_http_proxy_v2_process_control_frame(ngx_http_request_t *r,
+    ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b);
+static ngx_int_t ngx_http_proxy_v2_skip_frame(ngx_http_proxy_v2_ctx_t *ctx,
+    ngx_buf_t *b);
 static ngx_int_t ngx_http_proxy_v2_process_frames(ngx_http_request_t *r,
     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b);
 
@@ -1391,118 +1395,31 @@ ngx_http_proxy_v2_process_header(ngx_http_request_t *r)
             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
         }
 
-        if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {
-
-            rc = ngx_http_proxy_v2_parse_goaway(r, ctx, b);
+        rc = ngx_http_proxy_v2_process_control_frame(r, ctx, b);
 
-            if (rc == NGX_AGAIN) {
-                return NGX_AGAIN;
-            }
-
-            if (rc == NGX_ERROR) {
-                return NGX_HTTP_UPSTREAM_INVALID_HEADER;
-            }
-
-            /*
-             * If stream_id is lower than one we use, our
-             * request won't be processed and needs to be retried.
-             * If stream_id is greater or equal to the one we use,
-             * we can continue normally (except we can't use this
-             * connection for additional requests).  If there is
-             * a real error, the connection will be closed.
-             */
-
-            if (ctx->stream_id < ctx->id) {
-
-                /* TODO: we can retry non-idempotent requests */
-
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                              "upstream sent goaway with error %ui",
-                              ctx->error);
-
-                return NGX_HTTP_UPSTREAM_INVALID_HEADER;
-            }
-
-            ctx->goaway = 1;
-
-            continue;
-        }
-
-        if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) {
-
-            rc = ngx_http_proxy_v2_parse_window_update(r, ctx, b);
-
-            if (rc == NGX_AGAIN) {
-                return NGX_AGAIN;
-            }
-
-            if (rc == NGX_ERROR) {
-                return NGX_HTTP_UPSTREAM_INVALID_HEADER;
-            }
-
-            if (ctx->in) {
-                ngx_post_event(u->peer.connection->write, &ngx_posted_events);
-            }
-
-            continue;
+        if (rc == NGX_AGAIN) {
+            return NGX_AGAIN;
         }
 
-        if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) {
-
-            rc = ngx_http_proxy_v2_parse_settings(r, ctx, b);
-
-            if (rc == NGX_AGAIN) {
-                return NGX_AGAIN;
-            }
-
-            if (rc == NGX_ERROR) {
-                return NGX_HTTP_UPSTREAM_INVALID_HEADER;
-            }
-
-            if (ctx->in) {
-                ngx_post_event(u->peer.connection->write, &ngx_posted_events);
-            }
-
-            continue;
+        if (rc == NGX_ERROR) {
+            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
         }
 
-        if (ctx->type == NGX_HTTP_V2_PING_FRAME) {
-
-            rc = ngx_http_proxy_v2_parse_ping(r, ctx, b);
-
-            if (rc == NGX_AGAIN) {
-                return NGX_AGAIN;
-            }
-
-            if (rc == NGX_ERROR) {
-                return NGX_HTTP_UPSTREAM_INVALID_HEADER;
-            }
-
-            ngx_post_event(u->peer.connection->write, &ngx_posted_events);
+        if (rc == NGX_OK) {
             continue;
         }
 
-        if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
-            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                          "upstream sent unexpected push promise frame");
-            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
-        }
-
         if (ctx->type != NGX_HTTP_V2_HEADERS_FRAME
             && ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME)
         {
             /* priority, unknown frames */
 
-            if (b->last - b->pos < (ssize_t) ctx->rest) {
-                ctx->rest -= b->last - b->pos;
-                b->pos = b->last;
+            rc = ngx_http_proxy_v2_skip_frame(ctx, b);
+
+            if (rc == NGX_AGAIN) {
                 return NGX_AGAIN;
             }
 
-            b->pos += ctx->rest;
-            ctx->rest = 0;
-            ctx->state = ngx_http_proxy_v2_st_start;
-
             continue;
         }
 
@@ -1807,6 +1724,134 @@ ngx_http_proxy_v2_non_buffered_filter(void *data, ssize_t bytes)
 }
 
 
+static ngx_int_t
+ngx_http_proxy_v2_process_control_frame(ngx_http_request_t *r,
+    ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
+{
+    ngx_int_t             rc;
+    ngx_http_upstream_t  *u;
+
+    u = r->upstream;
+
+    if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {
+
+        rc = ngx_http_proxy_v2_parse_goaway(r, ctx, b);
+
+        if (rc == NGX_AGAIN) {
+            return NGX_AGAIN;
+        }
+
+        if (rc == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        /*
+         * If stream_id is lower than one we use, our
+         * request won't be processed and needs to be retried.
+         * If stream_id is greater or equal to the one we use,
+         * we can continue normally (except we can't use this
+         * connection for additional requests).  If there is
+         * a real error, the connection will be closed.
+         */
+
+        if (ctx->stream_id < ctx->id) {
+
+            /* TODO: we can retry non-idempotent requests */
+
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "upstream sent goaway with error %ui",
+                          ctx->error);
+
+            return NGX_ERROR;
+        }
+
+        ctx->goaway = 1;
+
+        return NGX_OK;
+    }
+
+    if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) {
+
+        rc = ngx_http_proxy_v2_parse_window_update(r, ctx, b);
+
+        if (rc == NGX_AGAIN) {
+            return NGX_AGAIN;
+        }
+
+        if (rc == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        if (ctx->in) {
+            ngx_post_event(u->peer.connection->write, &ngx_posted_events);
+        }
+
+        return NGX_OK;
+    }
+
+    if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) {
+
+        rc = ngx_http_proxy_v2_parse_settings(r, ctx, b);
+
+        if (rc == NGX_AGAIN) {
+            return NGX_AGAIN;
+        }
+
+        if (rc == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        if (ctx->in) {
+            ngx_post_event(u->peer.connection->write, &ngx_posted_events);
+        }
+
+        return NGX_OK;
+    }
+
+    if (ctx->type == NGX_HTTP_V2_PING_FRAME) {
+
+        rc = ngx_http_proxy_v2_parse_ping(r, ctx, b);
+
+        if (rc == NGX_AGAIN) {
+            return NGX_AGAIN;
+        }
+
+        if (rc == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        ngx_post_event(u->peer.connection->write, &ngx_posted_events);
+
+        return NGX_OK;
+    }
+
+    if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "upstream sent unexpected push promise frame");
+        return NGX_ERROR;
+    }
+
+    return NGX_DECLINED;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_v2_skip_frame(ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
+{
+    if (b->last - b->pos < (ssize_t) ctx->rest) {
+        ctx->rest -= b->last - b->pos;
+        b->pos = b->last;
+        return NGX_AGAIN;
+    }
+
+    b->pos += ctx->rest;
+    ctx->rest = 0;
+    ctx->state = ngx_http_proxy_v2_st_start;
+
+    return NGX_OK;
+}
+
+
 static ngx_int_t
 ngx_http_proxy_v2_process_frames(ngx_http_request_t *r,
     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
@@ -1990,103 +2035,20 @@ ngx_http_proxy_v2_process_frames(ngx_http_request_t *r,
             continue;
         }
 
-        if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {
-
-            rc = ngx_http_proxy_v2_parse_goaway(r, ctx, b);
-
-            if (rc == NGX_AGAIN) {
-                return NGX_AGAIN;
-            }
-
-            if (rc == NGX_ERROR) {
-                return NGX_ERROR;
-            }
-
-            /*
-             * If stream_id is lower than one we use, our
-             * request won't be processed and needs to be retried.
-             * If stream_id is greater or equal to the one we use,
-             * we can continue normally (except we can't use this
-             * connection for additional requests).  If there is
-             * a real error, the connection will be closed.
-             */
-
-            if (ctx->stream_id < ctx->id) {
-
-                /* TODO: we can retry non-idempotent requests */
-
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                              "upstream sent goaway with error %ui",
-                              ctx->error);
-
-                return NGX_ERROR;
-            }
-
-            ctx->goaway = 1;
-
-            continue;
-        }
-
-        if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) {
-
-            rc = ngx_http_proxy_v2_parse_window_update(r, ctx, b);
-
-            if (rc == NGX_AGAIN) {
-                return NGX_AGAIN;
-            }
-
-            if (rc == NGX_ERROR) {
-                return NGX_ERROR;
-            }
-
-            if (ctx->in) {
-                ngx_post_event(u->peer.connection->write, &ngx_posted_events);
-            }
+        rc = ngx_http_proxy_v2_process_control_frame(r, ctx, b);
 
-            continue;
+        if (rc == NGX_AGAIN) {
+            return NGX_AGAIN;
         }
 
-        if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) {
-
-            rc = ngx_http_proxy_v2_parse_settings(r, ctx, b);
-
-            if (rc == NGX_AGAIN) {
-                return NGX_AGAIN;
-            }
-
-            if (rc == NGX_ERROR) {
-                return NGX_ERROR;
-            }
-
-            if (ctx->in) {
-                ngx_post_event(u->peer.connection->write, &ngx_posted_events);
-            }
-
-            continue;
+        if (rc == NGX_ERROR) {
+            return NGX_ERROR;
         }
 
-        if (ctx->type == NGX_HTTP_V2_PING_FRAME) {
-
-            rc = ngx_http_proxy_v2_parse_ping(r, ctx, b);
-
-            if (rc == NGX_AGAIN) {
-                return NGX_AGAIN;
-            }
-
-            if (rc == NGX_ERROR) {
-                return NGX_ERROR;
-            }
-
-            ngx_post_event(u->peer.connection->write, &ngx_posted_events);
+        if (rc == NGX_OK) {
             continue;
         }
 
-        if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
-            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                          "upstream sent unexpected push promise frame");
-            return NGX_ERROR;
-        }
-
         if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME
             || ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME)
         {
@@ -2171,16 +2133,12 @@ ngx_http_proxy_v2_process_frames(ngx_http_request_t *r,
 
             /* priority, unknown frames */
 
-            if (b->last - b->pos < (ssize_t) ctx->rest) {
-                ctx->rest -= b->last - b->pos;
-                b->pos = b->last;
+            rc = ngx_http_proxy_v2_skip_frame(ctx, b);
+
+            if (rc == NGX_AGAIN) {
                 return NGX_AGAIN;
             }
 
-            b->pos += ctx->rest;
-            ctx->rest = 0;
-            ctx->state = ngx_http_proxy_v2_st_start;
-
             continue;
         }