# HG changeset patch # User Ruslan Ermilov # Date 1458038179 -10800 # Node ID cf3e75cfa95140bcadde8c0699549820d197275b # Parent 3b9c6b91d988a7435f9ef81263e4fad9536a45ab Added variables support to server_tokens. It can now be set to "off" conditionally, e.g. using the map directive. An empty value will disable the emission of the Server: header and the signature in error messages generated by nginx. Any other value is treated as "on", meaning that full nginx version is emitted in the Server: header and error messages generated by nginx. diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -59,6 +59,8 @@ static char *ngx_http_core_set_aio(ngx_c void *conf); static char *ngx_http_core_directio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_core_server_tokens(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_try_files(ngx_conf_t *cf, ngx_command_t *cmd, @@ -585,10 +587,10 @@ static ngx_command_t ngx_http_core_comm NULL }, { ngx_string("server_tokens"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_core_server_tokens, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_core_loc_conf_t, server_tokens), + 0, NULL }, { ngx_string("if_modified_since"), @@ -3635,9 +3637,9 @@ ngx_http_core_create_loc_conf(ngx_conf_t clcf->log_not_found = NGX_CONF_UNSET; clcf->log_subrequest = NGX_CONF_UNSET; clcf->recursive_error_pages = NGX_CONF_UNSET; - clcf->server_tokens = NGX_CONF_UNSET; clcf->chunked_transfer_encoding = NGX_CONF_UNSET; clcf->etag = NGX_CONF_UNSET; + clcf->server_tokens = NGX_CONF_UNSET_UINT; clcf->types_hash_max_size = NGX_CONF_UNSET_UINT; clcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT; @@ -3900,11 +3902,15 @@ ngx_http_core_merge_loc_conf(ngx_conf_t ngx_conf_merge_value(conf->log_subrequest, prev->log_subrequest, 0); ngx_conf_merge_value(conf->recursive_error_pages, prev->recursive_error_pages, 0); - ngx_conf_merge_value(conf->server_tokens, prev->server_tokens, 1); ngx_conf_merge_value(conf->chunked_transfer_encoding, prev->chunked_transfer_encoding, 1); ngx_conf_merge_value(conf->etag, prev->etag, 1); + if (conf->server_tokens == NGX_CONF_UNSET_UINT) { + ngx_conf_merge_uint_value(conf->server_tokens, prev->server_tokens, 1); + conf->server_tokens_value = prev->server_tokens_value; + } + ngx_conf_merge_ptr_value(conf->open_file_cache, prev->open_file_cache, NULL); @@ -4787,6 +4793,46 @@ ngx_http_core_directio(ngx_conf_t *cf, n static char * +ngx_http_core_server_tokens(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_core_loc_conf_t *clcf = conf; + + ngx_str_t *value; + ngx_http_compile_complex_value_t ccv; + + if (clcf->server_tokens != NGX_CONF_UNSET_UINT) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "on") == 0) { + clcf->server_tokens = 1; + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[1].data, "off") == 0) { + clcf->server_tokens = 0; + return NGX_CONF_OK; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &clcf->server_tokens_value; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + clcf->server_tokens = 2; + + return NGX_CONF_OK; +} + + +static char * ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_loc_conf_t *clcf = conf; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -414,10 +414,12 @@ struct ngx_http_core_loc_conf_s { ngx_flag_t log_not_found; /* log_not_found */ ngx_flag_t log_subrequest; /* log_subrequest */ ngx_flag_t recursive_error_pages; /* recursive_error_pages */ - ngx_flag_t server_tokens; /* server_tokens */ ngx_flag_t chunked_transfer_encoding; /* chunked_transfer_encoding */ ngx_flag_t etag; /* etag */ + ngx_uint_t server_tokens; /* server_tokens */ + ngx_http_complex_value_t server_tokens_value; + #if (NGX_HTTP_GZIP) ngx_flag_t gzip_vary; /* gzip_vary */ diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -46,8 +46,8 @@ ngx_module_t ngx_http_header_filter_mod }; -static char ngx_http_server_string[] = "Server: nginx" CRLF; -static char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF; +static u_char ngx_http_server_string[] = "Server: nginx" CRLF; +static u_char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF; static ngx_str_t ngx_http_status_lines[] = { @@ -152,7 +152,7 @@ ngx_http_header_filter(ngx_http_request_ { u_char *p; size_t len; - ngx_str_t host, *status_line; + ngx_str_t host, *status_line, tokens; ngx_buf_t *b; ngx_uint_t status, i, port; ngx_chain_t out; @@ -278,8 +278,30 @@ ngx_http_header_filter(ngx_http_request_ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->headers_out.server == NULL) { - len += clcf->server_tokens ? sizeof(ngx_http_server_full_string) - 1: - sizeof(ngx_http_server_string) - 1; + if (clcf->server_tokens == 0) { + ngx_str_set(&tokens, ngx_http_server_string); + + } else if (clcf->server_tokens == 1) { + ngx_str_set(&tokens, ngx_http_server_full_string); + + } else { + if (ngx_http_complex_value(r, &clcf->server_tokens_value, &tokens) + != NGX_OK) + { + return NGX_ERROR; + } + + if (tokens.len == 3 + && ngx_strncmp(tokens.data, "off", 3) == 0) + { + ngx_str_set(&tokens, ngx_http_server_string); + + } else if (tokens.len) { + ngx_str_set(&tokens, ngx_http_server_full_string); + } + } + + len += tokens.len; } if (r->headers_out.date == NULL) { @@ -455,17 +477,8 @@ ngx_http_header_filter(ngx_http_request_ } *b->last++ = CR; *b->last++ = LF; - if (r->headers_out.server == NULL) { - if (clcf->server_tokens) { - p = (u_char *) ngx_http_server_full_string; - len = sizeof(ngx_http_server_full_string) - 1; - - } else { - p = (u_char *) ngx_http_server_string; - len = sizeof(ngx_http_server_string) - 1; - } - - b->last = ngx_cpymem(b->last, p, len); + if (r->headers_out.server == NULL && tokens.len) { + b->last = ngx_cpymem(b->last, tokens.data, tokens.len); } if (r->headers_out.date == NULL) { diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -32,6 +32,12 @@ static u_char ngx_http_error_tail[] = ; +static u_char ngx_http_error_no_tail[] = +"" CRLF +"" CRLF +; + + static u_char ngx_http_msie_padding[] = "" CRLF "" CRLF @@ -609,26 +615,45 @@ static ngx_int_t ngx_http_send_special_response(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf, ngx_uint_t err) { - u_char *tail; - size_t len; ngx_int_t rc; + ngx_str_t tail, tokens; ngx_buf_t *b; ngx_uint_t msie_padding; ngx_chain_t out[3]; - if (clcf->server_tokens) { - len = sizeof(ngx_http_error_full_tail) - 1; - tail = ngx_http_error_full_tail; - - } else { - len = sizeof(ngx_http_error_tail) - 1; - tail = ngx_http_error_tail; - } - msie_padding = 0; if (ngx_http_error_pages[err].len) { - r->headers_out.content_length_n = ngx_http_error_pages[err].len + len; + + if (clcf->server_tokens == 0) { + ngx_str_set(&tail, ngx_http_error_tail); + + } else if (clcf->server_tokens == 1) { + ngx_str_set(&tail, ngx_http_error_full_tail); + + } else { + if (ngx_http_complex_value(r, &clcf->server_tokens_value, &tokens) + != NGX_OK) + { + return NGX_ERROR; + } + + if (tokens.len == 3 + && ngx_strncmp(tokens.data, "off", 3) == 0) + { + ngx_str_set(&tail, ngx_http_error_tail); + + } else if (tokens.len) { + ngx_str_set(&tail, ngx_http_error_full_tail); + + } else { + ngx_str_set(&tail, ngx_http_error_no_tail); + } + } + + r->headers_out.content_length_n = ngx_http_error_pages[err].len + + tail.len; + if (clcf->msie_padding && (r->headers_in.msie || r->headers_in.chrome) && r->http_version >= NGX_HTTP_VERSION_10 @@ -645,6 +670,10 @@ ngx_http_send_special_response(ngx_http_ } else { r->headers_out.content_length_n = 0; + +#if (NGX_SUPPRESS_WARN) + ngx_str_null(&tail); +#endif } if (r->headers_out.content_length) { @@ -684,9 +713,8 @@ ngx_http_send_special_response(ngx_http_ } b->memory = 1; - - b->pos = tail; - b->last = tail + len; + b->pos = tail.data; + b->last = tail.data + tail.len; out[1].buf = b; out[1].next = NULL; diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -128,8 +128,8 @@ ngx_http_v2_header_filter(ngx_http_reque { u_char status, *pos, *start, *p, *tmp; size_t len, tmp_len; - ngx_str_t host, location; - ngx_uint_t i, port; + ngx_str_t host, location, tokens; + ngx_uint_t i, port, server_tokens; ngx_list_part_t *part; ngx_table_elt_t *header; ngx_connection_t *fc; @@ -229,8 +229,38 @@ ngx_http_v2_header_filter(ngx_http_reque clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + server_tokens = clcf->server_tokens; + if (r->headers_out.server == NULL) { - len += 1 + (clcf->server_tokens ? nginx_ver_len : sizeof(nginx)); + + if (server_tokens == 0) { + len += 1 + sizeof(nginx); + ngx_str_set(&tokens, "nginx"); + + } else if (server_tokens == 1) { + len += 1 + nginx_ver_len; + ngx_str_set(&tokens, NGINX_VER); + + } else { + if (ngx_http_complex_value(r, &clcf->server_tokens_value, &tokens) + != NGX_OK) + { + return NGX_ERROR; + } + + if (tokens.len == 3 + && ngx_strncmp(tokens.data, "off", 3) == 0) + { + server_tokens = 0; + len += 1 + sizeof(nginx); + ngx_str_set(&tokens, "nginx"); + + } else if (tokens.len) { + server_tokens = 1; + len += 1 + nginx_ver_len; + ngx_str_set(&tokens, NGINX_VER); + } + } } if (r->headers_out.date == NULL) { @@ -434,14 +464,17 @@ ngx_http_v2_header_filter(ngx_http_reque pos = ngx_sprintf(pos, "%03ui", r->headers_out.status); } - if (r->headers_out.server == NULL) { + if (r->headers_out.server == NULL && tokens.len) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, - "http2 output header: \"server: %s\"", - clcf->server_tokens ? NGINX_VER : "nginx"); + "http2 output header: \"server: %V\"", + &tokens); *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_SERVER_INDEX); - if (clcf->server_tokens) { + if (server_tokens == 0) { + pos = ngx_cpymem(pos, nginx, sizeof(nginx)); + + } else { if (nginx_ver[0] == '\0') { p = ngx_http_v2_write_value(nginx_ver, (u_char *) NGINX_VER, sizeof(NGINX_VER) - 1, tmp); @@ -449,9 +482,6 @@ ngx_http_v2_header_filter(ngx_http_reque } pos = ngx_cpymem(pos, nginx_ver, nginx_ver_len); - - } else { - pos = ngx_cpymem(pos, nginx, sizeof(nginx)); } }