mirror of
https://github.com/nginx/nginx.git
synced 2026-08-03 22:33:10 +00:00
HTTP/2: add proxy_set_authority and grpc_set_authority directives
Previously, setting proxy_set_header Host caused :authority to be omitted in HTTP/2 requests. This caused many upstream servers to reject requests that only contained a Host header without :authority. Now users can explicitly set the :authority pseudo-header field. Closes: https://github.com/nginx/nginx/issues/1462
This commit is contained in:
parent
1c7687c98d
commit
a86cc836d6
4 changed files with 163 additions and 83 deletions
|
|
@ -25,7 +25,6 @@ typedef struct {
|
|||
ngx_array_t *headers_source;
|
||||
|
||||
ngx_str_t host;
|
||||
ngx_uint_t host_set;
|
||||
ngx_http_complex_value_t *authority;
|
||||
|
||||
ngx_array_t *grpc_lengths;
|
||||
|
|
@ -204,6 +203,8 @@ static ngx_int_t ngx_http_grpc_init_headers(ngx_conf_t *cf,
|
|||
|
||||
static char *ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_http_grpc_set_header(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
#if (NGX_HTTP_SSL)
|
||||
static char *ngx_http_grpc_ssl_certificate_cache(ngx_conf_t *cf,
|
||||
|
|
@ -335,7 +336,7 @@ static ngx_command_t ngx_http_grpc_commands[] = {
|
|||
|
||||
{ ngx_string("grpc_set_header"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
|
||||
ngx_conf_set_keyval_slot,
|
||||
ngx_http_grpc_set_header,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
offsetof(ngx_http_grpc_loc_conf_t, headers_source),
|
||||
NULL },
|
||||
|
|
@ -798,15 +799,16 @@ ngx_http_grpc_create_request(ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
/* :authority header */
|
||||
host = &ctx->host;
|
||||
|
||||
if (glcf->authority != NULL) {
|
||||
if (ngx_http_complex_value(r, glcf->authority, &host_val) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
host = &host_val;
|
||||
|
||||
} else {
|
||||
host = &ctx->host;
|
||||
if (host_val.len) {
|
||||
host = &host_val;
|
||||
}
|
||||
}
|
||||
|
||||
if (host->len > NGX_HTTP_V2_MAX_FIELD) {
|
||||
|
|
@ -4443,7 +4445,6 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf)
|
|||
* conf->headers.values = NULL;
|
||||
* conf->headers.hash = { NULL, 0 };
|
||||
* conf->host = { 0, NULL };
|
||||
* conf->host_set = 0;
|
||||
* conf->ssl = 0;
|
||||
* conf->ssl_protocols = 0;
|
||||
* conf->ssl_ciphers = { 0, NULL };
|
||||
|
|
@ -4646,7 +4647,6 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|
|||
|
||||
if (conf->headers_source == prev->headers_source) {
|
||||
conf->headers = prev->headers;
|
||||
conf->host_set = prev->host_set;
|
||||
}
|
||||
|
||||
rc = ngx_http_grpc_init_headers(cf, conf, &conf->headers,
|
||||
|
|
@ -4664,8 +4664,6 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|
|||
&& conf->headers_source == prev->headers_source)
|
||||
{
|
||||
prev->headers = conf->headers;
|
||||
prev->host_set = conf->host_set;
|
||||
prev->authority = conf->authority;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
|
|
@ -4718,37 +4716,6 @@ ngx_http_grpc_init_headers(ngx_conf_t *cf, ngx_http_grpc_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;
|
||||
|
||||
if (conf->authority != NULL) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"\"grpc_set_header Host\" cannot be "
|
||||
"used with \"grpc_set_authority\"");
|
||||
return NGX_ERROR;
|
||||
|
||||
} else {
|
||||
ngx_http_compile_complex_value_t ccv;
|
||||
|
||||
conf->authority = ngx_palloc(cf->pool,
|
||||
sizeof(ngx_http_complex_value_t));
|
||||
if (conf->authority == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
|
||||
ccv.cf = cf;
|
||||
ccv.value = &src[i].value;
|
||||
ccv.complex_value = conf->authority;
|
||||
|
||||
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s = ngx_array_push(&headers_merged);
|
||||
if (s == NULL) {
|
||||
return NGX_ERROR;
|
||||
|
|
@ -4850,6 +4817,28 @@ ngx_http_grpc_init_headers(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *conf,
|
|||
*code = (uintptr_t) NULL;
|
||||
}
|
||||
|
||||
if (conf->authority == NULL) {
|
||||
ngx_str_t v;
|
||||
ngx_http_compile_complex_value_t ccv;
|
||||
|
||||
ngx_str_set(&v, "$proxy_internal_host");
|
||||
|
||||
conf->authority = ngx_palloc(cf->pool,
|
||||
sizeof(ngx_http_complex_value_t));
|
||||
if (conf->authority == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
|
||||
ccv.cf = cf;
|
||||
ccv.value = &v;
|
||||
ccv.complex_value = conf->authority;
|
||||
|
||||
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
|
|
@ -4971,6 +4960,48 @@ ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_grpc_set_header(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_grpc_loc_conf_t *glcf = conf;
|
||||
ngx_str_t *value = cf->args->elts;
|
||||
|
||||
if (value[1].len == 4
|
||||
&& ngx_strncasecmp(value[1].data, (u_char *) "Host", 4) == 0)
|
||||
{
|
||||
ngx_http_compile_complex_value_t ccv;
|
||||
|
||||
if (glcf->authority != NGX_CONF_UNSET_PTR
|
||||
&& glcf->authority != NULL)
|
||||
{
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"\"grpc_set_header Host\" cannot be "
|
||||
"used with \"grpc_set_authority\"");
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
glcf->authority = ngx_palloc(cf->pool,
|
||||
sizeof(ngx_http_complex_value_t));
|
||||
if (glcf->authority == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
|
||||
ccv.cf = cf;
|
||||
ccv.value = &value[2];
|
||||
ccv.complex_value = glcf->authority;
|
||||
|
||||
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
return ngx_conf_set_keyval_slot(cf, cmd, conf);
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_HTTP_SSL)
|
||||
|
||||
static char *
|
||||
|
|
|
|||
|
|
@ -113,6 +113,8 @@ static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
|
|||
void *conf);
|
||||
static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_http_proxy_set_header(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
|
|
@ -321,7 +323,7 @@ static ngx_command_t ngx_http_proxy_commands[] = {
|
|||
|
||||
{ ngx_string("proxy_set_header"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
|
||||
ngx_conf_set_keyval_slot,
|
||||
ngx_http_proxy_set_header,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
offsetof(ngx_http_proxy_loc_conf_t, headers_source),
|
||||
NULL },
|
||||
|
|
@ -752,7 +754,7 @@ 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_internal_host") },
|
||||
{ ngx_string("Host"), ngx_string("") },
|
||||
{ ngx_string("Connection"), ngx_string("") },
|
||||
{ ngx_string("Proxy-Connection"), ngx_string("") },
|
||||
{ ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
|
||||
|
|
@ -781,7 +783,7 @@ 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_internal_host") },
|
||||
{ ngx_string("Host"), ngx_string("") },
|
||||
{ ngx_string("Connection"), ngx_string("") },
|
||||
{ ngx_string("Proxy-Connection"), ngx_string("") },
|
||||
{ ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
|
||||
|
|
@ -1186,7 +1188,7 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
|
|||
key_len, val_len;
|
||||
uintptr_t escape;
|
||||
ngx_buf_t *b;
|
||||
ngx_str_t method;
|
||||
ngx_str_t method, host_val;
|
||||
ngx_uint_t i, unparsed_uri;
|
||||
ngx_chain_t *cl, *body;
|
||||
ngx_list_part_t *part;
|
||||
|
|
@ -1313,6 +1315,15 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
|
|||
len += key_len + sizeof(": ") - 1 + val_len + sizeof(CRLF) - 1;
|
||||
}
|
||||
|
||||
/* Host header */
|
||||
|
||||
if (ngx_http_complex_value(r, plcf->authority, &host_val) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (host_val.len) {
|
||||
len += sizeof("Host: ") - 1 + host_val.len + sizeof(CRLF) - 1;
|
||||
}
|
||||
|
||||
if (plcf->upstream.pass_request_headers) {
|
||||
part = &r->headers_in.headers.part;
|
||||
|
|
@ -1400,6 +1411,14 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
|
|||
sizeof(ngx_http_proxy_version) - 1);
|
||||
}
|
||||
|
||||
/* Host header */
|
||||
|
||||
if (host_val.len) {
|
||||
b->last = ngx_cpymem(b->last, "Host: ", sizeof("Host: ") - 1);
|
||||
b->last = ngx_copy(b->last, host_val.data, host_val.len);
|
||||
*b->last++ = CR; *b->last++ = LF;
|
||||
}
|
||||
|
||||
ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
|
||||
|
||||
e.ip = headers->values->elts;
|
||||
|
|
@ -3510,7 +3529,6 @@ 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;
|
||||
|
|
@ -4090,7 +4108,6 @@ 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,
|
||||
|
|
@ -4123,8 +4140,6 @@ 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;
|
||||
prev->authority = conf->authority;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
|
|
@ -4177,37 +4192,6 @@ 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;
|
||||
|
||||
if (conf->authority != NULL) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"\"proxy_set_header Host\" cannot be "
|
||||
"used with \"proxy_set_authority\"");
|
||||
return NGX_ERROR;
|
||||
|
||||
} else {
|
||||
ngx_http_compile_complex_value_t ccv;
|
||||
|
||||
conf->authority = ngx_palloc(cf->pool,
|
||||
sizeof(ngx_http_complex_value_t));
|
||||
if (conf->authority == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
|
||||
ccv.cf = cf;
|
||||
ccv.value = &src[i].value;
|
||||
ccv.complex_value = conf->authority;
|
||||
|
||||
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s = ngx_array_push(&headers_merged);
|
||||
if (s == NULL) {
|
||||
return NGX_ERROR;
|
||||
|
|
@ -4309,6 +4293,28 @@ ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
|
|||
*code = (uintptr_t) NULL;
|
||||
}
|
||||
|
||||
if (conf->authority == NULL) {
|
||||
ngx_str_t v;
|
||||
ngx_http_compile_complex_value_t ccv;
|
||||
|
||||
ngx_str_set(&v, "$proxy_internal_host");
|
||||
|
||||
conf->authority = ngx_palloc(cf->pool,
|
||||
sizeof(ngx_http_complex_value_t));
|
||||
if (conf->authority == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
|
||||
ccv.cf = cf;
|
||||
ccv.value = &v;
|
||||
ccv.complex_value = conf->authority;
|
||||
|
||||
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
|
|
@ -4595,6 +4601,48 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_proxy_set_header(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_proxy_loc_conf_t *plcf = conf;
|
||||
ngx_str_t *value = cf->args->elts;
|
||||
|
||||
if (value[1].len == 4
|
||||
&& ngx_strncasecmp(value[1].data, (u_char *) "Host", 4) == 0)
|
||||
{
|
||||
ngx_http_compile_complex_value_t ccv;
|
||||
|
||||
if (plcf->authority != NGX_CONF_UNSET_PTR
|
||||
&& plcf->authority != NULL)
|
||||
{
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"\"proxy_set_header Host\" cannot be "
|
||||
"used with \"proxy_set_authority\"");
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
plcf->authority = ngx_palloc(cf->pool,
|
||||
sizeof(ngx_http_complex_value_t));
|
||||
if (plcf->authority == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
|
||||
ccv.cf = cf;
|
||||
ccv.value = &value[2];
|
||||
ccv.complex_value = plcf->authority;
|
||||
|
||||
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
return ngx_conf_set_keyval_slot(cf, cmd, conf);
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ typedef struct {
|
|||
ngx_http_proxy_headers_t headers_cache;
|
||||
#endif
|
||||
ngx_array_t *headers_source;
|
||||
ngx_uint_t host_set;
|
||||
ngx_http_complex_value_t *authority;
|
||||
|
||||
ngx_array_t *proxy_lengths;
|
||||
|
|
|
|||
|
|
@ -439,14 +439,16 @@ ngx_http_proxy_v2_create_request(ngx_http_request_t *r)
|
|||
|
||||
/* :authority header */
|
||||
|
||||
host = &ctx->ctx.vars.host_header;
|
||||
|
||||
if (plcf->authority != NULL) {
|
||||
if (ngx_http_complex_value(r, plcf->authority, &host_val) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
host = &host_val;
|
||||
|
||||
} else {
|
||||
host = &ctx->ctx.vars.host_header;
|
||||
if (host_val.len) {
|
||||
host = &host_val;
|
||||
}
|
||||
}
|
||||
|
||||
if (host->len > NGX_HTTP_V2_MAX_FIELD) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue