Latest update - GitHub 7c2524a

This commit is contained in:
2025-12-17 11:54:42 +09:00
parent d42d1aa241
commit 694f182c33
40 changed files with 5617 additions and 423 deletions
+294 -123
View File
@@ -8,6 +8,7 @@
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <ngx_http_proxy_module.h>
#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,94 +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;
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);
@@ -163,6 +71,8 @@ static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
ssize_t bytes);
static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
ssize_t bytes);
static ngx_int_t ngx_http_proxy_process_trailer(ngx_http_request_t *r,
ngx_buf_t *buf);
static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
ngx_int_t rc);
@@ -174,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,
@@ -289,6 +198,9 @@ static ngx_conf_post_t ngx_http_proxy_ssl_conf_command_post =
static ngx_conf_enum_t ngx_http_proxy_http_version[] = {
{ ngx_string("1.0"), NGX_HTTP_VERSION_10 },
{ ngx_string("1.1"), NGX_HTTP_VERSION_11 },
#if (NGX_HTTP_V2)
{ ngx_string("2"), NGX_HTTP_VERSION_20 },
#endif
{ ngx_null_string, 0 }
};
@@ -459,6 +371,13 @@ static ngx_command_t ngx_http_proxy_commands[] = {
offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
NULL },
{ ngx_string("proxy_pass_trailers"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_trailers),
NULL },
{ ngx_string("proxy_buffer_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
@@ -829,8 +748,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("") },
@@ -857,8 +776,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("") },
@@ -893,6 +812,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 },
@@ -951,6 +878,14 @@ ngx_http_proxy_handler(ngx_http_request_t *r)
ngx_http_proxy_main_conf_t *pmcf;
#endif
plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
#if (NGX_HTTP_V2)
if (plcf->http_version == NGX_HTTP_VERSION_20) {
return ngx_http_proxy_v2_handler(r);
}
#endif
if (ngx_http_upstream_create(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
@@ -960,9 +895,9 @@ ngx_http_proxy_handler(ngx_http_request_t *r)
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
ctx->legacy = 1;
plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
u = r->upstream;
@@ -1039,7 +974,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)
{
@@ -1143,7 +1078,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;
@@ -1195,7 +1130,8 @@ ngx_http_proxy_create_key(ngx_http_request_t *r)
return NGX_OK;
}
loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
loc_len = (r->valid_location && ctx->vars.uri.len)
? ngx_min(plcf->location.len, r->uri.len) : 0;
if (r->quoted_uri || r->internal) {
escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
@@ -1307,8 +1243,8 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
uri_len = r->unparsed_uri.len;
} else {
loc_len = (r->valid_location && ctx->vars.uri.len) ?
plcf->location.len : 0;
loc_len = (r->valid_location && ctx->vars.uri.len)
? ngx_min(plcf->location.len, r->uri.len) : 0;
if (r->quoted_uri || r->internal) {
escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
@@ -2107,7 +2043,7 @@ ngx_http_proxy_input_filter_init(void *data)
/* chunked */
u->pipe->input_filter = ngx_http_proxy_chunked_filter;
u->pipe->length = 3; /* "0" LF LF */
u->pipe->length = 5; /* "0" CRLF CRLF */
u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
u->length = 1;
@@ -2213,11 +2149,12 @@ ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
static ngx_int_t
ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
{
ngx_int_t rc;
ngx_buf_t *b, **prev;
ngx_chain_t *cl;
ngx_http_request_t *r;
ngx_http_proxy_ctx_t *ctx;
ngx_int_t rc;
ngx_buf_t *b, **prev;
ngx_chain_t *cl;
ngx_http_request_t *r;
ngx_http_proxy_ctx_t *ctx;
ngx_http_proxy_loc_conf_t *plcf;
if (buf->pos == buf->last) {
return NGX_OK;
@@ -2248,11 +2185,39 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
}
b = NULL;
if (ctx->trailers) {
rc = ngx_http_proxy_process_trailer(r, buf);
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
if (rc == NGX_OK) {
/* a whole response has been parsed successfully */
p->length = 0;
r->upstream->keepalive = !r->upstream->headers_in.connection_close;
if (buf->pos != buf->last) {
ngx_log_error(NGX_LOG_WARN, p->log, 0,
"upstream sent data after trailers");
r->upstream->keepalive = 0;
}
}
goto free_buf;
}
plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
prev = &buf->shadow;
for ( ;; ) {
rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
rc = ngx_http_parse_chunked(r, buf, &ctx->chunked,
plcf->upstream.pass_trailers);
if (rc == NGX_OK) {
@@ -2307,6 +2272,19 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
if (rc == NGX_DONE) {
if (plcf->upstream.pass_trailers) {
rc = ngx_http_proxy_process_trailer(r, buf);
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
if (rc == NGX_AGAIN) {
p->length = 1;
break;
}
}
/* a whole response has been parsed successfully */
p->length = 0;
@@ -2338,6 +2316,8 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_ERROR;
}
free_buf:
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->log, 0,
"http proxy chunked state %ui, length %O",
ctx->chunked.state, p->length);
@@ -2433,11 +2413,14 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
{
ngx_http_request_t *r = data;
ngx_int_t rc;
ngx_buf_t *b, *buf;
ngx_chain_t *cl, **ll;
ngx_http_upstream_t *u;
ngx_http_proxy_ctx_t *ctx;
ngx_int_t rc;
ngx_buf_t *b, *buf;
ngx_chain_t *cl, **ll;
ngx_http_upstream_t *u;
ngx_http_proxy_ctx_t *ctx;
ngx_http_proxy_loc_conf_t *plcf;
plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
@@ -2451,13 +2434,38 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
buf->pos = buf->last;
buf->last += bytes;
if (ctx->trailers) {
rc = ngx_http_proxy_process_trailer(r, buf);
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
if (rc == NGX_OK) {
/* a whole response has been parsed successfully */
r->upstream->keepalive = !u->headers_in.connection_close;
u->length = 0;
if (buf->pos != buf->last) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent data after trailers");
u->keepalive = 0;
}
}
return NGX_OK;
}
for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
ll = &cl->next;
}
for ( ;; ) {
rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
rc = ngx_http_parse_chunked(r, buf, &ctx->chunked,
plcf->upstream.pass_trailers);
if (rc == NGX_OK) {
@@ -2499,6 +2507,19 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
if (rc == NGX_DONE) {
if (plcf->upstream.pass_trailers) {
rc = ngx_http_proxy_process_trailer(r, buf);
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
if (rc == NGX_AGAIN) {
u->length = 1;
break;
}
}
/* a whole response has been parsed successfully */
u->keepalive = !u->headers_in.connection_close;
@@ -2529,6 +2550,115 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
}
static ngx_int_t
ngx_http_proxy_process_trailer(ngx_http_request_t *r, ngx_buf_t *buf)
{
size_t len;
ngx_int_t rc;
ngx_buf_t *b;
ngx_table_elt_t *h;
ngx_http_proxy_ctx_t *ctx;
ngx_http_proxy_loc_conf_t *plcf;
plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
if (ctx->trailers == NULL) {
ctx->trailers = ngx_create_temp_buf(r->pool,
plcf->upstream.buffer_size);
if (ctx->trailers == NULL) {
return NGX_ERROR;
}
}
b = ctx->trailers;
len = ngx_min(buf->last - buf->pos, b->end - b->last);
b->last = ngx_cpymem(b->last, buf->pos, len);
for ( ;; ) {
rc = ngx_http_parse_header_line(r, b, 1);
if (rc == NGX_OK) {
/* a header line has been parsed successfully */
h = ngx_list_push(&r->upstream->headers_in.trailers);
if (h == NULL) {
return NGX_ERROR;
}
h->hash = r->header_hash;
h->key.len = r->header_name_end - r->header_name_start;
h->value.len = r->header_end - r->header_start;
h->key.data = ngx_pnalloc(r->pool,
h->key.len + 1 + h->value.len + 1 + h->key.len);
if (h->key.data == NULL) {
h->hash = 0;
return NGX_ERROR;
}
h->value.data = h->key.data + h->key.len + 1;
h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
h->key.data[h->key.len] = '\0';
ngx_memcpy(h->value.data, r->header_start, h->value.len);
h->value.data[h->value.len] = '\0';
if (h->key.len == r->lowcase_index) {
ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
} else {
ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http proxy trailer: \"%V: %V\"",
&h->key, &h->value);
continue;
}
if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
/* a whole header has been parsed successfully */
buf->pos += len - (b->last - b->pos);
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http proxy trailer done");
return NGX_OK;
}
if (rc == NGX_AGAIN) {
buf->pos += len;
if (b->last == b->end) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent too big trailers");
return NGX_ERROR;
}
return NGX_AGAIN;
}
/* rc == NGX_HTTP_PARSE_INVALID_HEADER */
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent invalid trailer: \"%*s\\x%02xd...\"",
r->header_end - r->header_name_start,
r->header_name_start, *r->header_end);
return NGX_ERROR;
}
}
static void
ngx_http_proxy_abort_request(ngx_http_request_t *r)
{
@@ -2562,6 +2692,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;
@@ -2642,6 +2777,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)
@@ -2695,7 +2853,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)
{
@@ -2727,7 +2885,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;
@@ -3372,6 +3530,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;
@@ -3411,6 +3570,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.pass_request_headers = NGX_CONF_UNSET;
conf->upstream.pass_request_body = NGX_CONF_UNSET;
conf->upstream.pass_trailers = NGX_CONF_UNSET;
#if (NGX_HTTP_CACHE)
conf->upstream.cache = NGX_CONF_UNSET;
@@ -3754,6 +3914,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->upstream.pass_request_body,
prev->upstream.pass_request_body, 1);
ngx_conf_merge_value(conf->upstream.pass_trailers,
prev->upstream.pass_trailers, 0);
ngx_conf_merge_value(conf->upstream.intercept_errors,
prev->upstream.intercept_errors, 0);
@@ -3943,6 +4106,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,
@@ -3975,6 +4139,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;
@@ -4027,6 +4192,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;