summaryrefslogtreecommitdiffhomepage
path: root/src/http/modules
diff options
context:
space:
mode:
authorZhidao HONG <z.hong@f5.com>2025-11-30 16:27:26 +0000
committerRoman Arutyunyan <arutyunyan.roman@gmail.com>2025-12-08 07:49:16 +0400
commitfdd8e97558b3e4002affd11fedc88cdf4ad4796c (patch)
treed261285414180968babb3612ad428a0681aa5ca9 /src/http/modules
parent2a0342a17ddfe32ee984177dc313c8de14cb1de2 (diff)
downloadnginx-fdd8e97558b3e4002affd11fedc88cdf4ad4796c.tar.gz
nginx-fdd8e97558b3e4002affd11fedc88cdf4ad4796c.tar.bz2
Proxy: extracted control frame and skip functions for HTTP/2.
Diffstat (limited to 'src/http/modules')
-rw-r--r--src/http/modules/ngx_http_proxy_v2_module.c342
1 files changed, 150 insertions, 192 deletions
diff --git a/src/http/modules/ngx_http_proxy_v2_module.c b/src/http/modules/ngx_http_proxy_v2_module.c
index fc93ca71c..007a497a8 100644
--- a/src/http/modules/ngx_http_proxy_v2_module.c
+++ b/src/http/modules/ngx_http_proxy_v2_module.c
@@ -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;
}
@@ -1808,6 +1725,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;
}