diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 93ba6a998e..2107637216 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -252,6 +252,13 @@ static ngx_command_t ngx_http_core_commands[] = { offsetof(ngx_http_core_srv_conf_t, large_client_header_buffers), NULL }, + { ngx_string("max_headers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_core_srv_conf_t, max_headers), + NULL }, + { ngx_string("ignore_invalid_headers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -3466,6 +3473,7 @@ ngx_http_core_create_srv_conf(ngx_conf_t *cf) cscf->request_pool_size = NGX_CONF_UNSET_SIZE; cscf->client_header_timeout = NGX_CONF_UNSET_MSEC; cscf->client_header_buffer_size = NGX_CONF_UNSET_SIZE; + cscf->max_headers = NGX_CONF_UNSET_UINT; cscf->ignore_invalid_headers = NGX_CONF_UNSET; cscf->merge_slashes = NGX_CONF_UNSET; cscf->underscores_in_headers = NGX_CONF_UNSET; @@ -3507,6 +3515,8 @@ ngx_http_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + ngx_conf_merge_uint_value(conf->max_headers, prev->max_headers, 1000); + ngx_conf_merge_value(conf->ignore_invalid_headers, prev->ignore_invalid_headers, 1); diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 472672c86c..ec470b0dc1 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -196,6 +196,8 @@ typedef struct { ngx_msec_t client_header_timeout; + ngx_uint_t max_headers; + ngx_flag_t ignore_invalid_headers; ngx_flag_t merge_slashes; ngx_flag_t underscores_in_headers; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 5e0340b288..720f93ef85 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1433,6 +1433,15 @@ ngx_http_process_request_headers(ngx_event_t *rev) /* a header line has been parsed successfully */ + if (r->headers_in.count++ >= cscf->max_headers) { + r->lingering_close = 1; + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent too many header lines"); + ngx_http_finalize_request(r, + NGX_HTTP_REQUEST_HEADER_TOO_LARGE); + break; + } + h = ngx_list_push(&r->headers_in.headers); if (h == NULL) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 8c9eed2493..01ac4f9846 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -181,6 +181,7 @@ typedef struct { typedef struct { ngx_list_t headers; + ngx_uint_t count; ngx_table_elt_t *host; ngx_table_elt_t *connection; diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index ea3f27c078..a87c3b61f6 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -1841,6 +1841,15 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, } } else { + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + if (r->headers_in.count++ >= cscf->max_headers) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent too many header lines"); + ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE); + goto error; + } + h = ngx_list_push(&r->headers_in.headers); if (h == NULL) { return ngx_http_v2_connection_error(h2c,