From 90a4fc793527b67678fd48b2692be09f30d8ffcf Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Tue, 15 Jul 2025 15:03:39 +0000 Subject: [PATCH] Proxy: refactored for HTTP/2 support. --- auto/modules | 2 +- src/http/modules/ngx_http_proxy_module.c | 166 ++++++++--------------- src/http/modules/ngx_http_proxy_module.h | 123 +++++++++++++++++ 3 files changed, 183 insertions(+), 108 deletions(-) create mode 100644 src/http/modules/ngx_http_proxy_module.h diff --git a/auto/modules b/auto/modules index 38b3aba78..8989212b8 100644 --- a/auto/modules +++ b/auto/modules @@ -729,7 +729,7 @@ if [ $HTTP = YES ]; then ngx_module_name=ngx_http_proxy_module ngx_module_incs= - ngx_module_deps= + ngx_module_deps=src/http/modules/ngx_http_proxy_module.h ngx_module_srcs=src/http/modules/ngx_http_proxy_module.c ngx_module_libs= ngx_module_link=$HTTP_PROXY diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 5e6b0c434..9f40c2193 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -8,6 +8,7 @@ #include #include #include +#include #define NGX_HTTP_PROXY_COOKIE_SECURE 0x0001 @@ -23,11 +24,6 @@ #define NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF 0x0400 -typedef struct { - ngx_array_t caches; /* ngx_http_file_cache_t * */ -} ngx_http_proxy_main_conf_t; - - typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t; typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r, @@ -61,96 +57,6 @@ typedef struct { } ngx_http_proxy_cookie_flags_t; -typedef struct { - ngx_str_t key_start; - ngx_str_t schema; - ngx_str_t host_header; - ngx_str_t port; - ngx_str_t uri; -} ngx_http_proxy_vars_t; - - -typedef struct { - ngx_array_t *flushes; - ngx_array_t *lengths; - ngx_array_t *values; - ngx_hash_t hash; -} ngx_http_proxy_headers_t; - - -typedef struct { - ngx_http_upstream_conf_t upstream; - - ngx_array_t *body_flushes; - ngx_array_t *body_lengths; - ngx_array_t *body_values; - ngx_str_t body_source; - - ngx_http_proxy_headers_t headers; -#if (NGX_HTTP_CACHE) - ngx_http_proxy_headers_t headers_cache; -#endif - ngx_array_t *headers_source; - - ngx_array_t *proxy_lengths; - ngx_array_t *proxy_values; - - ngx_array_t *redirects; - ngx_array_t *cookie_domains; - ngx_array_t *cookie_paths; - ngx_array_t *cookie_flags; - - ngx_http_complex_value_t *method; - ngx_str_t location; - ngx_str_t url; - -#if (NGX_HTTP_CACHE) - ngx_http_complex_value_t cache_key; -#endif - - ngx_http_proxy_vars_t vars; - - ngx_flag_t redirect; - - ngx_uint_t http_version; - - ngx_uint_t headers_hash_max_size; - ngx_uint_t headers_hash_bucket_size; - -#if (NGX_HTTP_SSL) - ngx_uint_t ssl; - ngx_uint_t ssl_protocols; - ngx_str_t ssl_ciphers; - ngx_uint_t ssl_verify_depth; - ngx_str_t ssl_trusted_certificate; - ngx_str_t ssl_crl; - ngx_array_t *ssl_conf_commands; -#endif -} ngx_http_proxy_loc_conf_t; - - -typedef struct { - ngx_http_status_t status; - ngx_http_chunked_t chunked; - ngx_http_proxy_vars_t vars; - off_t internal_body_length; - - ngx_chain_t *free; - ngx_chain_t *busy; - - ngx_buf_t *trailers; - - unsigned head:1; - unsigned internal_chunked:1; - unsigned header_sent:1; -} ngx_http_proxy_ctx_t; - - -static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r, - ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf); -#if (NGX_HTTP_CACHE) -static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r); -#endif static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r); static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r); static ngx_int_t ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in); @@ -178,15 +84,14 @@ static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r, static ngx_int_t ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t + ngx_http_proxy_internal_connection_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); -static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, - ngx_table_elt_t *h, size_t prefix); -static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, - ngx_table_elt_t *h); static ngx_int_t ngx_http_proxy_parse_cookie(ngx_str_t *value, ngx_array_t *attrs); static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, @@ -840,8 +745,8 @@ static char ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF; static ngx_keyval_t ngx_http_proxy_headers[] = { - { ngx_string("Host"), ngx_string("$proxy_host") }, - { ngx_string("Connection"), ngx_string("close") }, + { ngx_string("Host"), ngx_string("$proxy_internal_host") }, + { ngx_string("Connection"), ngx_string("$proxy_internal_connection") }, { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") }, { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") }, { ngx_string("TE"), ngx_string("") }, @@ -868,8 +773,8 @@ static ngx_str_t ngx_http_proxy_hide_headers[] = { #if (NGX_HTTP_CACHE) static ngx_keyval_t ngx_http_proxy_cache_headers[] = { - { ngx_string("Host"), ngx_string("$proxy_host") }, - { ngx_string("Connection"), ngx_string("close") }, + { ngx_string("Host"), ngx_string("$proxy_internal_host") }, + { ngx_string("Connection"), ngx_string("$proxy_internal_connection") }, { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") }, { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") }, { ngx_string("TE"), ngx_string("") }, @@ -904,6 +809,14 @@ static ngx_http_variable_t ngx_http_proxy_vars[] = { { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 }, #endif + { ngx_string("proxy_internal_host"), NULL, + ngx_http_proxy_host_variable, 1, + NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + + { ngx_string("proxy_internal_connection"), NULL, + ngx_http_proxy_internal_connection_variable, 0, + NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + { ngx_string("proxy_internal_body_length"), NULL, ngx_http_proxy_internal_body_length_variable, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, @@ -971,6 +884,8 @@ ngx_http_proxy_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } + ctx->legacy = 1; + ngx_http_set_ctx(r, ctx, ngx_http_proxy_module); plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); @@ -1050,7 +965,7 @@ ngx_http_proxy_handler(ngx_http_request_t *r) } -static ngx_int_t +ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf) { @@ -1154,7 +1069,7 @@ ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx, #if (NGX_HTTP_CACHE) -static ngx_int_t +ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r) { size_t len, loc_len; @@ -2768,6 +2683,11 @@ ngx_http_proxy_host_variable(ngx_http_request_t *r, return NGX_OK; } + if (data == 1 && !ctx->legacy) { + v->not_found = 1; + return NGX_OK; + } + v->len = ctx->vars.host_header.len; v->valid = 1; v->no_cacheable = 0; @@ -2848,6 +2768,29 @@ ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_proxy_internal_connection_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_proxy_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); + + if (ctx == NULL || !ctx->legacy) { + v->not_found = 1; + return NGX_OK; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + ngx_str_set(v, "close"); + + return NGX_OK; +} + + static ngx_int_t ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -2901,7 +2844,7 @@ ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r, } -static ngx_int_t +ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix) { @@ -2933,7 +2876,7 @@ ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, } -static ngx_int_t +ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h) { u_char *p; @@ -3578,6 +3521,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) * conf->headers.values = NULL; * conf->headers.hash = { NULL, 0 }; * conf->headers_cache.lengths = NULL; + * conf->host_set = 0; * conf->headers_cache.values = NULL; * conf->headers_cache.hash = { NULL, 0 }; * conf->body_lengths = NULL; @@ -4153,6 +4097,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_HTTP_CACHE) conf->headers_cache = prev->headers_cache; #endif + conf->host_set = prev->host_set; } rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers, @@ -4185,6 +4130,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #if (NGX_HTTP_CACHE) prev->headers_cache = conf->headers_cache; #endif + prev->host_set = conf->host_set; } return NGX_CONF_OK; @@ -4237,6 +4183,12 @@ ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, src = conf->headers_source->elts; for (i = 0; i < conf->headers_source->nelts; i++) { + if (src[i].key.len == 4 + && ngx_strncasecmp(src[i].key.data, (u_char *) "Host", 4) == 0) + { + conf->host_set = 1; + } + s = ngx_array_push(&headers_merged); if (s == NULL) { return NGX_ERROR; diff --git a/src/http/modules/ngx_http_proxy_module.h b/src/http/modules/ngx_http_proxy_module.h new file mode 100644 index 000000000..18f52d930 --- /dev/null +++ b/src/http/modules/ngx_http_proxy_module.h @@ -0,0 +1,123 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_HTTP_PROXY_H_INCLUDED_ +#define _NGX_HTTP_PROXY_H_INCLUDED_ + + +#include +#include +#include + + +typedef struct { + ngx_array_t caches; /* ngx_http_file_cache_t * */ +} ngx_http_proxy_main_conf_t; + + +typedef struct { + ngx_str_t key_start; + ngx_str_t schema; + ngx_str_t host_header; + ngx_str_t port; + ngx_str_t uri; +} ngx_http_proxy_vars_t; + + +typedef struct { + ngx_array_t *flushes; + ngx_array_t *lengths; + ngx_array_t *values; + ngx_hash_t hash; +} ngx_http_proxy_headers_t; + + +typedef struct { + ngx_http_upstream_conf_t upstream; + + ngx_array_t *body_flushes; + ngx_array_t *body_lengths; + ngx_array_t *body_values; + ngx_str_t body_source; + + ngx_http_proxy_headers_t headers; +#if (NGX_HTTP_CACHE) + ngx_http_proxy_headers_t headers_cache; +#endif + ngx_array_t *headers_source; + ngx_uint_t host_set; + + ngx_array_t *proxy_lengths; + ngx_array_t *proxy_values; + + ngx_array_t *redirects; + ngx_array_t *cookie_domains; + ngx_array_t *cookie_paths; + ngx_array_t *cookie_flags; + + ngx_http_complex_value_t *method; + ngx_str_t location; + ngx_str_t url; + +#if (NGX_HTTP_CACHE) + ngx_http_complex_value_t cache_key; +#endif + + ngx_http_proxy_vars_t vars; + + ngx_flag_t redirect; + + ngx_uint_t http_version; + + ngx_uint_t headers_hash_max_size; + ngx_uint_t headers_hash_bucket_size; + +#if (NGX_HTTP_SSL || NGX_COMPAT) + ngx_uint_t ssl; + ngx_uint_t ssl_protocols; + ngx_str_t ssl_ciphers; + ngx_uint_t ssl_verify_depth; + ngx_str_t ssl_trusted_certificate; + ngx_str_t ssl_crl; + ngx_array_t *ssl_conf_commands; +#endif +} ngx_http_proxy_loc_conf_t; + + +typedef struct { + ngx_http_status_t status; + ngx_http_chunked_t chunked; + ngx_http_proxy_vars_t vars; + off_t internal_body_length; + + ngx_chain_t *free; + ngx_chain_t *busy; + + ngx_buf_t *trailers; + + unsigned head:1; + unsigned internal_chunked:1; + unsigned header_sent:1; + unsigned legacy:1; +} ngx_http_proxy_ctx_t; + + +ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx, + ngx_http_proxy_loc_conf_t *plcf); +#if (NGX_HTTP_CACHE) +ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r); +#endif +ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, + ngx_table_elt_t *h, size_t prefix); +ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, + ngx_table_elt_t *h); + + +extern ngx_module_t ngx_http_proxy_module; + + +#endif /* _NGX_HTTP_PROXY_H_INCLUDED_ */