From 09b41d5eab2d4743d696989d38914556bd315627 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 11 Jan 2021 22:06:27 +0300 Subject: Version bump. --- src/core/nginx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/nginx.h b/src/core/nginx.h index e915be3e7..b926ba6fe 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1019006 -#define NGINX_VERSION "1.19.6" +#define nginx_version 1019007 +#define NGINX_VERSION "1.19.7" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD -- cgit From 7b6b8b62dd9a66e91da0a28b06941ddb5e312590 Mon Sep 17 00:00:00 2001 From: Gena Makhomed Date: Tue, 29 Dec 2020 13:13:57 +0200 Subject: Contrib: vim syntax, update core and 3rd party module directives. --- contrib/vim/syntax/nginx.vim | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 830470878..2d5ed060e 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -268,6 +268,7 @@ syn keyword ngxDirective contained grpc_socket_keepalive syn keyword ngxDirective contained grpc_ssl_certificate syn keyword ngxDirective contained grpc_ssl_certificate_key syn keyword ngxDirective contained grpc_ssl_ciphers +syn keyword ngxDirective contained grpc_ssl_conf_command syn keyword ngxDirective contained grpc_ssl_crl syn keyword ngxDirective contained grpc_ssl_name syn keyword ngxDirective contained grpc_ssl_password_file @@ -447,6 +448,7 @@ syn keyword ngxDirective contained proxy_cache_use_stale syn keyword ngxDirective contained proxy_cache_valid syn keyword ngxDirective contained proxy_connect_timeout syn keyword ngxDirective contained proxy_cookie_domain +syn keyword ngxDirective contained proxy_cookie_flags syn keyword ngxDirective contained proxy_cookie_path syn keyword ngxDirective contained proxy_download_rate syn keyword ngxDirective contained proxy_force_ranges @@ -480,11 +482,13 @@ syn keyword ngxDirective contained proxy_send_timeout syn keyword ngxDirective contained proxy_session_drop syn keyword ngxDirective contained proxy_set_body syn keyword ngxDirective contained proxy_set_header +syn keyword ngxDirective contained proxy_smtp_auth syn keyword ngxDirective contained proxy_socket_keepalive syn keyword ngxDirective contained proxy_ssl syn keyword ngxDirective contained proxy_ssl_certificate syn keyword ngxDirective contained proxy_ssl_certificate_key syn keyword ngxDirective contained proxy_ssl_ciphers +syn keyword ngxDirective contained proxy_ssl_conf_command syn keyword ngxDirective contained proxy_ssl_crl syn keyword ngxDirective contained proxy_ssl_name syn keyword ngxDirective contained proxy_ssl_password_file @@ -592,6 +596,7 @@ syn keyword ngxDirective contained ssl_certificate syn keyword ngxDirective contained ssl_certificate_key syn keyword ngxDirective contained ssl_ciphers syn keyword ngxDirective contained ssl_client_certificate +syn keyword ngxDirective contained ssl_conf_command syn keyword ngxDirective contained ssl_crl syn keyword ngxDirective contained ssl_dhparam syn keyword ngxDirective contained ssl_early_data @@ -605,6 +610,7 @@ syn keyword ngxDirective contained ssl_password_file syn keyword ngxDirective contained ssl_prefer_server_ciphers syn keyword ngxDirective contained ssl_preread syn keyword ngxDirective contained ssl_protocols +syn keyword ngxDirective contained ssl_reject_handshake syn keyword ngxDirective contained ssl_session_cache syn keyword ngxDirective contained ssl_session_ticket_key syn keyword ngxDirective contained ssl_session_tickets @@ -643,6 +649,7 @@ syn keyword ngxDirective contained user syn keyword ngxDirective contained userid syn keyword ngxDirective contained userid_domain syn keyword ngxDirective contained userid_expires +syn keyword ngxDirective contained userid_flags syn keyword ngxDirective contained userid_mark syn keyword ngxDirective contained userid_name syn keyword ngxDirective contained userid_p3p @@ -693,6 +700,7 @@ syn keyword ngxDirective contained uwsgi_socket_keepalive syn keyword ngxDirective contained uwsgi_ssl_certificate syn keyword ngxDirective contained uwsgi_ssl_certificate_key syn keyword ngxDirective contained uwsgi_ssl_ciphers +syn keyword ngxDirective contained uwsgi_ssl_conf_command syn keyword ngxDirective contained uwsgi_ssl_crl syn keyword ngxDirective contained uwsgi_ssl_name syn keyword ngxDirective contained uwsgi_ssl_password_file @@ -738,6 +746,7 @@ syn keyword ngxDirective contained zone_sync_ssl syn keyword ngxDirective contained zone_sync_ssl_certificate syn keyword ngxDirective contained zone_sync_ssl_certificate_key syn keyword ngxDirective contained zone_sync_ssl_ciphers +syn keyword ngxDirective contained zone_sync_ssl_conf_command syn keyword ngxDirective contained zone_sync_ssl_crl syn keyword ngxDirective contained zone_sync_ssl_name syn keyword ngxDirective contained zone_sync_ssl_password_file @@ -1329,6 +1338,8 @@ syn keyword ngxDirectiveThirdParty contained body_filter_by_lua_file syn keyword ngxDirectiveThirdParty contained content_by_lua syn keyword ngxDirectiveThirdParty contained content_by_lua_block syn keyword ngxDirectiveThirdParty contained content_by_lua_file +syn keyword ngxDirectiveThirdParty contained exit_worker_by_lua_block +syn keyword ngxDirectiveThirdParty contained exit_worker_by_lua_file syn keyword ngxDirectiveThirdParty contained header_filter_by_lua syn keyword ngxDirectiveThirdParty contained header_filter_by_lua_block syn keyword ngxDirectiveThirdParty contained header_filter_by_lua_file @@ -1370,6 +1381,7 @@ syn keyword ngxDirectiveThirdParty contained lua_ssl_crl syn keyword ngxDirectiveThirdParty contained lua_ssl_protocols syn keyword ngxDirectiveThirdParty contained lua_ssl_trusted_certificate syn keyword ngxDirectiveThirdParty contained lua_ssl_verify_depth +syn keyword ngxDirectiveThirdParty contained lua_thread_cache_max_entries syn keyword ngxDirectiveThirdParty contained lua_transform_underscores_in_response_headers syn keyword ngxDirectiveThirdParty contained lua_use_default_type syn keyword ngxDirectiveThirdParty contained rewrite_by_lua @@ -2285,6 +2297,7 @@ syn keyword ngxDirectiveThirdParty contained testcookie_refresh_encrypt_cookie_i syn keyword ngxDirectiveThirdParty contained testcookie_refresh_encrypt_cookie_key syn keyword ngxDirectiveThirdParty contained testcookie_refresh_status syn keyword ngxDirectiveThirdParty contained testcookie_refresh_template +syn keyword ngxDirectiveThirdParty contained testcookie_samesite syn keyword ngxDirectiveThirdParty contained testcookie_secret syn keyword ngxDirectiveThirdParty contained testcookie_secure_flag syn keyword ngxDirectiveThirdParty contained testcookie_session @@ -2355,15 +2368,31 @@ syn keyword ngxDirectiveThirdParty contained websockify_send_timeout " IP2Location Nginx " https://github.com/ip2location/ip2location-nginx -syn keyword ngxDirectiveThirdParty contained ip2location -syn keyword ngxDirectiveThirdParty contained ip2location_access_type syn keyword ngxDirectiveThirdParty contained ip2location_proxy syn keyword ngxDirectiveThirdParty contained ip2location_proxy_recursive +syn keyword ngxDirectiveThirdParty contained ip2location_areacode +syn keyword ngxDirectiveThirdParty contained ip2location_city +syn keyword ngxDirectiveThirdParty contained ip2location_country_long +syn keyword ngxDirectiveThirdParty contained ip2location_country_short +syn keyword ngxDirectiveThirdParty contained ip2location_domain +syn keyword ngxDirectiveThirdParty contained ip2location_elevation +syn keyword ngxDirectiveThirdParty contained ip2location_iddcode +syn keyword ngxDirectiveThirdParty contained ip2location_isp +syn keyword ngxDirectiveThirdParty contained ip2location_latitude +syn keyword ngxDirectiveThirdParty contained ip2location_longitude +syn keyword ngxDirectiveThirdParty contained ip2location_mcc +syn keyword ngxDirectiveThirdParty contained ip2location_mnc +syn keyword ngxDirectiveThirdParty contained ip2location_mobilebrand +syn keyword ngxDirectiveThirdParty contained ip2location_netspeed +syn keyword ngxDirectiveThirdParty contained ip2location_region +syn keyword ngxDirectiveThirdParty contained ip2location_timezone +syn keyword ngxDirectiveThirdParty contained ip2location_usagetype +syn keyword ngxDirectiveThirdParty contained ip2location_weatherstationcode +syn keyword ngxDirectiveThirdParty contained ip2location_weatherstationname +syn keyword ngxDirectiveThirdParty contained ip2location_zipcode " IP2Proxy module for Nginx " https://github.com/ip2location/ip2proxy-nginx -syn keyword ngxDirectiveThirdParty contained ip2proxy -syn keyword ngxDirectiveThirdParty contained ip2proxy_access_type syn keyword ngxDirectiveThirdParty contained ip2proxy_as syn keyword ngxDirectiveThirdParty contained ip2proxy_asn syn keyword ngxDirectiveThirdParty contained ip2proxy_city @@ -2371,12 +2400,14 @@ syn keyword ngxDirectiveThirdParty contained ip2proxy_country_long syn keyword ngxDirectiveThirdParty contained ip2proxy_country_short syn keyword ngxDirectiveThirdParty contained ip2proxy_database syn keyword ngxDirectiveThirdParty contained ip2proxy_domain -syn keyword ngxDirectiveThirdParty contained ip2proxy_is_proxy syn keyword ngxDirectiveThirdParty contained ip2proxy_isp +syn keyword ngxDirectiveThirdParty contained ip2proxy_is_proxy syn keyword ngxDirectiveThirdParty contained ip2proxy_last_seen +syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy +syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_recursive syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_type syn keyword ngxDirectiveThirdParty contained ip2proxy_region -syn keyword ngxDirectiveThirdParty contained ip2proxy_reverse_proxy +syn keyword ngxDirectiveThirdParty contained ip2proxy_threat syn keyword ngxDirectiveThirdParty contained ip2proxy_usage_type -- cgit From e1ca9851220bb6d5f8e6b967635078f35a423c7c Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 12 Jan 2021 16:59:31 +0300 Subject: Upstream: fixed zero size buf alerts on extra data (ticket #2117). After 7675:9afa45068b8f and 7678:bffcc5af1d72 (1.19.1), during non-buffered simple proxying, responses with extra data might result in zero size buffers being generated and "zero size buf" alerts in writer. This bug is similar to the one with FastCGI proxying fixed in 7689:da8d758aabeb. In non-buffered mode, normally the filter function is not called if u->length is already 0, since u->length is checked after each call of the filter function. There is a case when this can happen though: if the response length is 0, and there are pre-read response body data left after reading response headers. As such, a check for u->length is needed at the start of non-buffered filter functions, similar to the one for p->length present in buffered filter functions. Appropriate checks added to the existing non-buffered copy filters in the upstream (used by scgi and uwsgi proxying) and proxy modules. --- src/http/modules/ngx_http_proxy_module.c | 7 +++++++ src/http/ngx_http_upstream.c | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 3d8768af6..77a1e0d7f 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -2334,6 +2334,13 @@ ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes) u = r->upstream; + if (u->length == 0) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); + return NGX_OK; + } + for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) { ll = &cl->next; } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index dda4046be..9cbb5a3b0 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -3721,6 +3721,13 @@ ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes) u = r->upstream; + if (u->length == 0) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent more data than specified in " + "\"Content-Length\" header"); + return NGX_OK; + } + for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) { ll = &cl->next; } -- cgit From d2c0b9a6c7b0757d5d55db36b1ae656bba056a8c Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 19 Jan 2021 20:21:12 +0300 Subject: Removed incorrect optimization of HEAD requests. The stub status module and ngx_http_send_response() (used by the empty gif module and the "return" directive) incorrectly assumed that responding to HEAD requests always results in r->header_only being set. This is not true, and results in incorrect behaviour, for example, in the following configuration: location / { image_filter size; return 200 test; } Fix is to remove this incorrect micro-optimization from both stub status module and ngx_http_send_response(). Reported by Chris Newton. --- src/http/modules/ngx_http_stub_status_module.c | 10 ---------- src/http/ngx_http_core_module.c | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c index 9bdf88129..db68b768a 100644 --- a/src/http/modules/ngx_http_stub_status_module.c +++ b/src/http/modules/ngx_http_stub_status_module.c @@ -103,16 +103,6 @@ ngx_http_stub_status_handler(ngx_http_request_t *r) ngx_str_set(&r->headers_out.content_type, "text/plain"); r->headers_out.content_type_lowcase = NULL; - if (r->method == NGX_HTTP_HEAD) { - r->headers_out.status = NGX_HTTP_OK; - - rc = ngx_http_send_header(r); - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - } - size = sizeof("Active connections: \n") + NGX_ATOMIC_T_LEN + sizeof("server accepts handled requests\n") - 1 + 6 + 3 * NGX_ATOMIC_T_LEN diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 3671558d8..aa40c9985 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1782,7 +1782,7 @@ ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, } } - if (r->method == NGX_HTTP_HEAD || (r != r->main && val.len == 0)) { + if (r != r->main && val.len == 0) { return ngx_http_send_header(r); } -- cgit From 2ec8fac2d6b8e5023c9894d10bc50d78e63f242c Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 19 Jan 2021 20:32:00 +0300 Subject: Core: removed post_accept_timeout. Keeping post_accept_timeout in ngx_listening_t is no longer needed since we've switched to 1 second timeout for deferred accept in 5541:fdb67cfc957d. Further, using it in HTTP code can result in client_header_timeout being used from an incorrect server block, notably if address-specific virtual servers are used along with a wildcard listening socket, or if we've switched to a different server block based on SNI in SSL handshake. --- src/core/ngx_connection.h | 2 -- src/http/ngx_http.c | 1 - src/http/ngx_http_request.c | 34 +++++++++++++++++++++------------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index ad6556d0c..9d8ac46d2 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -45,8 +45,6 @@ struct ngx_listening_s { size_t pool_size; /* should be here because of the AcceptEx() preread */ size_t post_accept_buffer_size; - /* should be here because of the deferred accept */ - ngx_msec_t post_accept_timeout; ngx_listening_t *previous; ngx_connection_t *connection; diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index a35e9bb8a..e1d3d0034 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1714,7 +1714,6 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) cscf = addr->default_server; ls->pool_size = cscf->connection_pool_size; - ls->post_accept_timeout = cscf->client_header_timeout; clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index d453b8a49..68d81e932 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -206,16 +206,17 @@ ngx_http_header_t ngx_http_headers_in[] = { void ngx_http_init_connection(ngx_connection_t *c) { - ngx_uint_t i; - ngx_event_t *rev; - struct sockaddr_in *sin; - ngx_http_port_t *port; - ngx_http_in_addr_t *addr; - ngx_http_log_ctx_t *ctx; - ngx_http_connection_t *hc; + ngx_uint_t i; + ngx_event_t *rev; + struct sockaddr_in *sin; + ngx_http_port_t *port; + ngx_http_in_addr_t *addr; + ngx_http_log_ctx_t *ctx; + ngx_http_connection_t *hc; + ngx_http_core_srv_conf_t *cscf; #if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; - ngx_http_in6_addr_t *addr6; + struct sockaddr_in6 *sin6; + ngx_http_in6_addr_t *addr6; #endif hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); @@ -361,7 +362,9 @@ ngx_http_init_connection(ngx_connection_t *c) return; } - ngx_add_timer(rev, c->listening->post_accept_timeout); + cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); + + ngx_add_timer(rev, cscf->client_header_timeout); ngx_reusable_connection(c, 1); if (ngx_handle_read_event(rev, 0) != NGX_OK) { @@ -431,7 +434,7 @@ ngx_http_wait_request_handler(ngx_event_t *rev) if (n == NGX_AGAIN) { if (!rev->timer_set) { - ngx_add_timer(rev, c->listening->post_accept_timeout); + ngx_add_timer(rev, cscf->client_header_timeout); ngx_reusable_connection(c, 1); } @@ -649,6 +652,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev) ngx_http_connection_t *hc; ngx_http_ssl_srv_conf_t *sscf; ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; c = rev->data; hc = c->data; @@ -680,7 +684,9 @@ ngx_http_ssl_handshake(ngx_event_t *rev) rev->ready = 0; if (!rev->timer_set) { - ngx_add_timer(rev, c->listening->post_accept_timeout); + cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, + ngx_http_core_module); + ngx_add_timer(rev, cscf->client_header_timeout); ngx_reusable_connection(c, 1); } @@ -755,7 +761,9 @@ ngx_http_ssl_handshake(ngx_event_t *rev) if (rc == NGX_AGAIN) { if (!rev->timer_set) { - ngx_add_timer(rev, c->listening->post_accept_timeout); + cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, + ngx_http_core_module); + ngx_add_timer(rev, cscf->client_header_timeout); } c->ssl->handler = ngx_http_ssl_handshake_handler; -- cgit From 2f008a76f82440d0c10a27b83a0d11ac58249b21 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 19 Jan 2021 20:35:17 +0300 Subject: Year 2021. --- docs/text/LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/text/LICENSE b/docs/text/LICENSE index c63e0ba4e..fd0c72d49 100644 --- a/docs/text/LICENSE +++ b/docs/text/LICENSE @@ -1,6 +1,6 @@ /* - * Copyright (C) 2002-2019 Igor Sysoev - * Copyright (C) 2011-2019 Nginx, Inc. + * Copyright (C) 2002-2021 Igor Sysoev + * Copyright (C) 2011-2021 Nginx, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without -- cgit From 56f53316837271a8cbb1d99f638e28d268a00d45 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Tue, 26 Jan 2021 12:39:28 +0300 Subject: Clean up trailers in ngx_http_clean_header() as well. The function has not been updated with introduction of trailers support in 7034:1b068a4e82d8 (1.13.2). --- src/http/ngx_http_special_response.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c index 76e670588..72f56fd9a 100644 --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -575,6 +575,10 @@ ngx_http_clean_header(ngx_http_request_t *r) r->headers_out.headers.part.next = NULL; r->headers_out.headers.last = &r->headers_out.headers.part; + r->headers_out.trailers.part.nelts = 0; + r->headers_out.trailers.part.next = NULL; + r->headers_out.trailers.last = &r->headers_out.trailers.part; + r->headers_out.content_length_n = -1; r->headers_out.last_modified_time = -1; } -- cgit From 327e21c43293ecfdbd116bd572ee08b7d8066b24 Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Mon, 1 Feb 2021 16:42:50 +0300 Subject: HTTP/2: lingering close changed to handle NGX_AGAIN. This part somehow slipped away from c5840ca2063d. While it is not expected to be needed in case of lingering close, it is good to keep it for correctness (see 2b5528023f6b). --- src/http/v2/ngx_http_v2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 77b60d42e..7c1ba597f 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -807,6 +807,10 @@ ngx_http_v2_lingering_close_handler(ngx_event_t *rev) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lingering read: %z", n); + if (n == NGX_AGAIN) { + break; + } + if (n == NGX_ERROR || n == 0) { ngx_http_close_connection(c); return; -- cgit From fb2a2152d756f23ce191ab109116585f90acf087 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 11 Feb 2021 21:52:09 +0300 Subject: Reuse of connections in lingering close. This is particularly important in HTTP/2, where keepalive connections are closed with lingering. Before the patch, reusing a keepalive HTTP/2 connection resulted in the connection waiting for lingering close to remain in the reusable connections queue, preventing ngx_drain_connections() from closing additional connections. The patch fixes it by marking the connection reusable again, and so moving it in the reusable connections queue. Further, it makes actually possible to reuse such connections if needed. --- src/http/ngx_http_request.c | 5 ++++- src/http/v2/ngx_http_v2.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 68d81e932..d129f8079 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -3437,6 +3437,9 @@ ngx_http_set_lingering_close(ngx_connection_t *c) return; } + c->close = 0; + ngx_reusable_connection(c, 1); + ngx_add_timer(rev, clcf->lingering_timeout); if (rev->ready) { @@ -3461,7 +3464,7 @@ ngx_http_lingering_close_handler(ngx_event_t *rev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http lingering close handler"); - if (rev->timedout) { + if (rev->timedout || c->close) { ngx_http_close_request(r, 0); return; } diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 7c1ba597f..2af3ef7e5 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -767,6 +767,9 @@ ngx_http_v2_lingering_close(ngx_connection_t *c) return; } + c->close = 0; + ngx_reusable_connection(c, 1); + ngx_add_timer(rev, clcf->lingering_timeout); if (rev->ready) { @@ -791,7 +794,7 @@ ngx_http_v2_lingering_close_handler(ngx_event_t *rev) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 lingering close handler"); - if (rev->timedout) { + if (rev->timedout || c->close) { ngx_http_close_connection(c); return; } -- cgit From 9a3ec202322b174acb5973d8f55cf570f1177149 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 11 Feb 2021 21:52:11 +0300 Subject: Additional connections reuse. If ngx_drain_connections() fails to immediately reuse any connections and there are no free connections, it now additionally tries to reuse a connection again. This helps to provide at least one free connection in case of HTTP/2 with lingering close, where merely trying to reuse a connection once does not free it, but makes it reusable again, waiting for lingering close. --- src/core/ngx_connection.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index c082d0dac..8339e2bb7 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -1310,6 +1310,7 @@ ngx_drain_connections(ngx_cycle_t *cycle) cycle->connection_n); } + c = NULL; n = ngx_max(ngx_min(32, cycle->reusable_connections_n / 8), 1); for (i = 0; i < n; i++) { @@ -1326,6 +1327,21 @@ ngx_drain_connections(ngx_cycle_t *cycle) c->close = 1; c->read->handler(c->read); } + + if (cycle->free_connection_n == 0 && c && c->reusable) { + + /* + * if no connections were freed, try to reuse the last + * connection again: this should free it as long as + * previous reuse moved it to lingering close + */ + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0, + "reusing connection again"); + + c->close = 1; + c->read->handler(c->read); + } } -- cgit From 76672e6500c1a51905c9366f7c833ea58f351bc4 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 11 Feb 2021 21:52:12 +0300 Subject: HTTP/2: reuse of connections with incomplete frames. Prodded by Taewoo Kim. --- src/http/v2/ngx_http_v2.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 2af3ef7e5..df78576df 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -362,6 +362,11 @@ ngx_http_v2_read_handler(ngx_event_t *rev) return; } + if (!h2c->processing && !h2c->pushing) { + ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); + return; + } + if (!h2c->goaway) { h2c->goaway = 1; @@ -668,6 +673,8 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) return; } + ngx_reusable_connection(c, 1); + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, ngx_http_v2_module); if (h2c->state.incomplete) { @@ -689,7 +696,6 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) #endif c->destroyed = 1; - ngx_reusable_connection(c, 1); c->write->handler = ngx_http_empty_handler; c->read->handler = ngx_http_v2_idle_handler; -- cgit From 797a2dc7cf970d2ee7523ec1f276156c5ea16b01 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 11 Feb 2021 21:52:17 +0300 Subject: HTTP/2: fixed reusing connections with active requests. New connections are marked reusable by ngx_http_init_connection() if there are no data available for reading. As a result, if SSL is not used, ngx_http_v2_init() might be called when the connection is marked reusable. If a HEADERS frame is immediately available for reading, this resulted in connection being preserved in reusable state with an active request, and possibly closed later as if during worker shutdown (that is, after all active requests were finalized). Fix is to explicitly mark connections non-reusable in ngx_http_v2_init() instead of (incorrectly) assuming they are already non-reusable. Found by Sergey Kandaurov. --- src/http/v2/ngx_http_v2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index df78576df..5482ea63e 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -326,6 +326,7 @@ ngx_http_v2_init(ngx_event_t *rev) c->write->handler = ngx_http_v2_write_handler; c->idle = 1; + ngx_reusable_connection(c, 0); ngx_http_v2_read_handler(rev); } -- cgit From e82939206dc80a392ecc685013dc98691d9d2f06 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 11 Feb 2021 21:52:19 +0300 Subject: HTTP/2: removed SPDY directives handling. The spdy_* directives are not available since introduction of HTTP/2 module in nginx 1.9.5 more than five years ago. --- src/http/ngx_http_core_module.c | 8 ----- src/http/v2/ngx_http_v2_module.c | 69 ---------------------------------------- 2 files changed, 77 deletions(-) diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index aa40c9985..67476e7d7 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -4078,14 +4078,6 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } - if (ngx_strcmp(value[n].data, "spdy") == 0) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "invalid parameter \"spdy\": " - "ngx_http_spdy_module was superseded " - "by ngx_http_v2_module"); - continue; - } - if (ngx_strncmp(value[n].data, "so_keepalive=", 13) == 0) { if (ngx_strcmp(&value[n].data[13], "on") == 0) { diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c index c54dc103a..3be6bfac8 100644 --- a/src/http/v2/ngx_http_v2_module.c +++ b/src/http/v2/ngx_http_v2_module.c @@ -36,8 +36,6 @@ static char *ngx_http_v2_preread_size(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data); -static char *ngx_http_v2_spdy_deprecated(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); static ngx_conf_post_t ngx_http_v2_recv_buffer_size_post = @@ -152,62 +150,6 @@ static ngx_command_t ngx_http_v2_commands[] = { 0, NULL }, - { ngx_string("spdy_recv_buffer_size"), - NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_MAIN_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_pool_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_max_concurrent_streams"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_streams_index_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_recv_timeout"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_keepalive_timeout"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_headers_comp"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_SRV_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("spdy_chunk_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_http_v2_spdy_deprecated, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - ngx_null_command }; @@ -597,14 +539,3 @@ ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; } - - -static char * -ngx_http_v2_spdy_deprecated(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "invalid directive \"%V\": ngx_http_spdy_module " - "was superseded by ngx_http_v2_module", &cmd->name); - - return NGX_CONF_OK; -} -- cgit From d18e066d650bff39f1705d3038804873584007af Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 11 Feb 2021 21:52:20 +0300 Subject: HTTP/2: removed http2_recv_timeout. Instead, the client_header_timeout is now used for HTTP/2 reading. Further, the timeout is changed to be set once till no further data left to read, similarly to how client_header_timeout is used in other places. --- src/http/v2/ngx_http_v2.c | 23 +++++++++++++++++------ src/http/v2/ngx_http_v2_module.c | 32 +++++++++++++++++++++++++------- src/http/v2/ngx_http_v2_module.h | 1 - 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 5482ea63e..1962d6dc1 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -635,9 +635,10 @@ error: static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) { - ngx_int_t rc; - ngx_connection_t *c; - ngx_http_v2_srv_conf_t *h2scf; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_v2_srv_conf_t *h2scf; + ngx_http_core_srv_conf_t *cscf; if (h2c->last_out || h2c->processing || h2c->pushing) { return; @@ -676,10 +677,13 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) ngx_reusable_connection(c, 1); - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); if (h2c->state.incomplete) { - ngx_add_timer(c->read, h2scf->recv_timeout); + if (!c->read->timer_set) { + cscf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); + ngx_add_timer(c->read, cscf->client_header_timeout); + } + return; } @@ -705,6 +709,9 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) ngx_del_timer(c->write); } + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + ngx_add_timer(c->read, h2scf->idle_timeout); } @@ -4696,6 +4703,10 @@ ngx_http_v2_idle_handler(ngx_event_t *rev) c->destroyed = 0; ngx_reusable_connection(c, 0); + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); if (h2c->pool == NULL) { ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR); diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c index 3be6bfac8..fc50edddd 100644 --- a/src/http/v2/ngx_http_v2_module.c +++ b/src/http/v2/ngx_http_v2_module.c @@ -36,6 +36,13 @@ static char *ngx_http_v2_preread_size(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_v2_obsolete(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_conf_deprecated_t ngx_http_v2_recv_timeout_deprecated = { + ngx_conf_deprecated, "http2_recv_timeout", "client_header_timeout" +}; static ngx_conf_post_t ngx_http_v2_recv_buffer_size_post = @@ -117,10 +124,10 @@ static ngx_command_t ngx_http_v2_commands[] = { { ngx_string("http2_recv_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v2_srv_conf_t, recv_timeout), - NULL }, + ngx_http_v2_obsolete, + 0, + 0, + &ngx_http_v2_recv_timeout_deprecated }, { ngx_string("http2_idle_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, @@ -304,7 +311,6 @@ ngx_http_v2_create_srv_conf(ngx_conf_t *cf) h2scf->streams_index_mask = NGX_CONF_UNSET_UINT; - h2scf->recv_timeout = NGX_CONF_UNSET_MSEC; h2scf->idle_timeout = NGX_CONF_UNSET_MSEC; return h2scf; @@ -335,8 +341,6 @@ ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->streams_index_mask, prev->streams_index_mask, 32 - 1); - ngx_conf_merge_msec_value(conf->recv_timeout, - prev->recv_timeout, 30000); ngx_conf_merge_msec_value(conf->idle_timeout, prev->idle_timeout, 180000); @@ -539,3 +543,17 @@ ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; } + + +static char * +ngx_http_v2_obsolete(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_conf_deprecated_t *d = cmd->post; + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "the \"%s\" directive is obsolete, " + "use the \"%s\" directive instead", + d->old_name, d->new_name); + + return NGX_CONF_OK; +} diff --git a/src/http/v2/ngx_http_v2_module.h b/src/http/v2/ngx_http_v2_module.h index cdd2921a5..bc20c6806 100644 --- a/src/http/v2/ngx_http_v2_module.h +++ b/src/http/v2/ngx_http_v2_module.h @@ -29,7 +29,6 @@ typedef struct { size_t max_header_size; size_t preread_size; ngx_uint_t streams_index_mask; - ngx_msec_t recv_timeout; ngx_msec_t idle_timeout; } ngx_http_v2_srv_conf_t; -- cgit From 49ab3312448495f0ee8e00143a29624dde46ef5c Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 11 Feb 2021 21:52:23 +0300 Subject: HTTP/2: removed http2_idle_timeout and http2_max_requests. Instead, keepalive_timeout and keepalive_requests are now used. This is expected to simplify HTTP/2 code and usage. This also matches directives used by upstream module for all protocols. In case of default settings, this effectively changes maximum number of requests per connection from 1000 to 100. This looks acceptable, especially given that HTTP/2 code now properly supports lingering close. Further, this changes default keepalive timeout in HTTP/2 from 300 seconds to 75 seconds. This also looks acceptable, and larger than PING interval used by Firefox (network.http.spdy.ping-threshold defaults to 58s), the only browser to use PINGs. --- src/http/v2/ngx_http_v2.c | 37 +++++++++++++++++++++++-------------- src/http/v2/ngx_http_v2_module.c | 31 ++++++++++++++++--------------- src/http/v2/ngx_http_v2_module.h | 2 -- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 1962d6dc1..071fadb59 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -637,7 +637,7 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) { ngx_int_t rc; ngx_connection_t *c; - ngx_http_v2_srv_conf_t *h2scf; + ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; if (h2c->last_out || h2c->processing || h2c->pushing) { @@ -709,10 +709,10 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) ngx_del_timer(c->write); } - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); + clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); - ngx_add_timer(c->read, h2scf->idle_timeout); + ngx_add_timer(c->read, clcf->keepalive_timeout); } @@ -1200,12 +1200,14 @@ static u_char * ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - size_t size; - ngx_uint_t padded, priority, depend, dependency, excl, weight; - ngx_uint_t status; - ngx_http_v2_node_t *node; - ngx_http_v2_stream_t *stream; - ngx_http_v2_srv_conf_t *h2scf; + size_t size; + ngx_uint_t padded, priority, depend, dependency, excl, + weight; + ngx_uint_t status; + ngx_http_v2_node_t *node; + ngx_http_v2_stream_t *stream; + ngx_http_v2_srv_conf_t *h2scf; + ngx_http_core_loc_conf_t *clcf; padded = h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG; priority = h2c->state.flags & NGX_HTTP_V2_PRIORITY_FLAG; @@ -1364,7 +1366,10 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_http_v2_set_dependency(h2c, node, depend, excl); } - if (h2c->connection->requests >= h2scf->max_requests) { + clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); + + if (h2c->connection->requests >= clcf->keepalive_requests) { h2c->goaway = 1; if (ngx_http_v2_send_goaway(h2c, NGX_HTTP_V2_NO_ERROR) == NGX_ERROR) { @@ -4659,6 +4664,7 @@ ngx_http_v2_idle_handler(ngx_event_t *rev) ngx_connection_t *c; ngx_http_v2_srv_conf_t *h2scf; ngx_http_v2_connection_t *h2c; + ngx_http_core_loc_conf_t *clcf; c = rev->data; h2c = c->data; @@ -4690,10 +4696,10 @@ ngx_http_v2_idle_handler(ngx_event_t *rev) #endif - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); + clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); - if (h2c->idle++ > 10 * h2scf->max_requests) { + if (h2c->idle++ > 10 * clcf->keepalive_requests) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, "http2 flood detected"); ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); @@ -4707,6 +4713,9 @@ ngx_http_v2_idle_handler(ngx_event_t *rev) ngx_del_timer(c->read); } + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); if (h2c->pool == NULL) { ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR); diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c index fc50edddd..4ecf81a52 100644 --- a/src/http/v2/ngx_http_v2_module.c +++ b/src/http/v2/ngx_http_v2_module.c @@ -44,6 +44,14 @@ static ngx_conf_deprecated_t ngx_http_v2_recv_timeout_deprecated = { ngx_conf_deprecated, "http2_recv_timeout", "client_header_timeout" }; +static ngx_conf_deprecated_t ngx_http_v2_idle_timeout_deprecated = { + ngx_conf_deprecated, "http2_idle_timeout", "keepalive_timeout" +}; + +static ngx_conf_deprecated_t ngx_http_v2_max_requests_deprecated = { + ngx_conf_deprecated, "http2_max_requests", "keepalive_requests" +}; + static ngx_conf_post_t ngx_http_v2_recv_buffer_size_post = { ngx_http_v2_recv_buffer_size }; @@ -89,10 +97,10 @@ static ngx_command_t ngx_http_v2_commands[] = { { ngx_string("http2_max_requests"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v2_srv_conf_t, max_requests), - NULL }, + ngx_http_v2_obsolete, + 0, + 0, + &ngx_http_v2_max_requests_deprecated }, { ngx_string("http2_max_field_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, @@ -131,10 +139,10 @@ static ngx_command_t ngx_http_v2_commands[] = { { ngx_string("http2_idle_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v2_srv_conf_t, idle_timeout), - NULL }, + ngx_http_v2_obsolete, + 0, + 0, + &ngx_http_v2_idle_timeout_deprecated }, { ngx_string("http2_chunk_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, @@ -302,7 +310,6 @@ ngx_http_v2_create_srv_conf(ngx_conf_t *cf) h2scf->concurrent_streams = NGX_CONF_UNSET_UINT; h2scf->concurrent_pushes = NGX_CONF_UNSET_UINT; - h2scf->max_requests = NGX_CONF_UNSET_UINT; h2scf->max_field_size = NGX_CONF_UNSET_SIZE; h2scf->max_header_size = NGX_CONF_UNSET_SIZE; @@ -311,8 +318,6 @@ ngx_http_v2_create_srv_conf(ngx_conf_t *cf) h2scf->streams_index_mask = NGX_CONF_UNSET_UINT; - h2scf->idle_timeout = NGX_CONF_UNSET_MSEC; - return h2scf; } @@ -329,7 +334,6 @@ ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) prev->concurrent_streams, 128); ngx_conf_merge_uint_value(conf->concurrent_pushes, prev->concurrent_pushes, 10); - ngx_conf_merge_uint_value(conf->max_requests, prev->max_requests, 1000); ngx_conf_merge_size_value(conf->max_field_size, prev->max_field_size, 4096); @@ -341,9 +345,6 @@ ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->streams_index_mask, prev->streams_index_mask, 32 - 1); - ngx_conf_merge_msec_value(conf->idle_timeout, - prev->idle_timeout, 180000); - return NGX_CONF_OK; } diff --git a/src/http/v2/ngx_http_v2_module.h b/src/http/v2/ngx_http_v2_module.h index bc20c6806..7b90f39e9 100644 --- a/src/http/v2/ngx_http_v2_module.h +++ b/src/http/v2/ngx_http_v2_module.h @@ -24,12 +24,10 @@ typedef struct { size_t pool_size; ngx_uint_t concurrent_streams; ngx_uint_t concurrent_pushes; - ngx_uint_t max_requests; size_t max_field_size; size_t max_header_size; size_t preread_size; ngx_uint_t streams_index_mask; - ngx_msec_t idle_timeout; } ngx_http_v2_srv_conf_t; -- cgit From 94567a8f849c02c70ee7f51307fa0372c94c925b Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 11 Feb 2021 21:52:24 +0300 Subject: HTTP/2: keepalive_timeout now armed once between requests. Previously, PINGs and other frames extended possible keepalive time, making it possible to keep an open HTTP/2 connection for a long time. Now the connection is always closed as long as keepalive_timeout expires, similarly to how it happens in HTTP/1.x. Note that as a part of this change, incomplete frames are no longer trigger a separate timeout, so http2_recv_timeout (replaced by client_header_timeout in previous patches) is essentially cancelled. The client_header_timeout is, however, used for SSL handshake and while reading HEADERS frames. --- src/http/v2/ngx_http_v2.c | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 071fadb59..e57c65cbb 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -325,6 +325,10 @@ ngx_http_v2_init(ngx_event_t *rev) rev->handler = ngx_http_v2_read_handler; c->write->handler = ngx_http_v2_write_handler; + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + c->idle = 1; ngx_reusable_connection(c, 0); @@ -455,14 +459,6 @@ ngx_http_v2_read_handler(ngx_event_t *rev) h2c->blocked = 0; - if (h2c->processing || h2c->pushing) { - if (rev->timer_set) { - ngx_del_timer(rev); - } - - return; - } - ngx_http_v2_handle_connection(h2c); } @@ -638,7 +634,6 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) ngx_int_t rc; ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf; - ngx_http_core_srv_conf_t *cscf; if (h2c->last_out || h2c->processing || h2c->pushing) { return; @@ -675,15 +670,16 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) return; } + clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); + + if (!c->read->timer_set) { + ngx_add_timer(c->read, clcf->keepalive_timeout); + } + ngx_reusable_connection(c, 1); if (h2c->state.incomplete) { - if (!c->read->timer_set) { - cscf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_core_module); - ngx_add_timer(c->read, cscf->client_header_timeout); - } - return; } @@ -708,11 +704,6 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c) if (c->write->timer_set) { ngx_del_timer(c->write); } - - clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx, - ngx_http_core_module); - - ngx_add_timer(c->read, clcf->keepalive_timeout); } @@ -3298,6 +3289,10 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t push) h2c->priority_limit += h2scf->concurrent_streams; + if (h2c->connection->read->timer_set) { + ngx_del_timer(h2c->connection->read); + } + return stream; } @@ -4709,10 +4704,6 @@ ngx_http_v2_idle_handler(ngx_event_t *rev) c->destroyed = 0; ngx_reusable_connection(c, 0); - if (c->read->timer_set) { - ngx_del_timer(c->read); - } - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, ngx_http_v2_module); -- cgit From 51fea093e4374dbd857dc437ff9588060ef56471 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 11 Feb 2021 21:52:26 +0300 Subject: HTTP/2: removed http2_max_field_size and http2_max_header_size. Instead, size of one large_client_header_buffers buffer and all large client header buffers are used. --- src/http/v2/ngx_http_v2.c | 27 ++++++++++++++++----------- src/http/v2/ngx_http_v2_module.c | 32 ++++++++++++++++---------------- src/http/v2/ngx_http_v2_module.h | 2 -- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index e57c65cbb..a59528494 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -1198,6 +1198,7 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_http_v2_node_t *node; ngx_http_v2_stream_t *stream; ngx_http_v2_srv_conf_t *h2scf; + ngx_http_core_srv_conf_t *cscf; ngx_http_core_loc_conf_t *clcf; padded = h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG; @@ -1299,11 +1300,15 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); } + cscf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); + + h2c->state.header_limit = cscf->large_client_header_buffers.size + * cscf->large_client_header_buffers.num; + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, ngx_http_v2_module); - h2c->state.header_limit = h2scf->max_header_size; - if (h2c->processing >= h2scf->concurrent_streams) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, "concurrent streams exceeded %ui", h2c->processing); @@ -1485,10 +1490,10 @@ static u_char * ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - size_t alloc; - ngx_int_t len; - ngx_uint_t huff; - ngx_http_v2_srv_conf_t *h2scf; + size_t alloc; + ngx_int_t len; + ngx_uint_t huff; + ngx_http_core_srv_conf_t *cscf; if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) && h2c->state.length < NGX_HTTP_V2_INT_OCTETS) @@ -1535,12 +1540,12 @@ ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos, "http2 %s string, len:%i", huff ? "encoded" : "raw", len); - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); + cscf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_core_module); - if ((size_t) len > h2scf->max_field_size) { + if ((size_t) len > cscf->large_client_header_buffers.size) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, - "client exceeded http2_max_field_size limit"); + "client sent too large header field"); return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); } @@ -1755,7 +1760,7 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, if (len > h2c->state.header_limit) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, - "client exceeded http2_max_header_size limit"); + "client sent too large header"); return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM); } diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c index 4ecf81a52..005088611 100644 --- a/src/http/v2/ngx_http_v2_module.c +++ b/src/http/v2/ngx_http_v2_module.c @@ -52,6 +52,14 @@ static ngx_conf_deprecated_t ngx_http_v2_max_requests_deprecated = { ngx_conf_deprecated, "http2_max_requests", "keepalive_requests" }; +static ngx_conf_deprecated_t ngx_http_v2_max_field_size_deprecated = { + ngx_conf_deprecated, "http2_max_field_size", "large_client_header_buffers" +}; + +static ngx_conf_deprecated_t ngx_http_v2_max_header_size_deprecated = { + ngx_conf_deprecated, "http2_max_header_size", "large_client_header_buffers" +}; + static ngx_conf_post_t ngx_http_v2_recv_buffer_size_post = { ngx_http_v2_recv_buffer_size }; @@ -104,17 +112,17 @@ static ngx_command_t ngx_http_v2_commands[] = { { ngx_string("http2_max_field_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v2_srv_conf_t, max_field_size), - NULL }, + ngx_http_v2_obsolete, + 0, + 0, + &ngx_http_v2_max_field_size_deprecated }, { ngx_string("http2_max_header_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v2_srv_conf_t, max_header_size), - NULL }, + ngx_http_v2_obsolete, + 0, + 0, + &ngx_http_v2_max_header_size_deprecated }, { ngx_string("http2_body_preread_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, @@ -311,9 +319,6 @@ ngx_http_v2_create_srv_conf(ngx_conf_t *cf) h2scf->concurrent_streams = NGX_CONF_UNSET_UINT; h2scf->concurrent_pushes = NGX_CONF_UNSET_UINT; - h2scf->max_field_size = NGX_CONF_UNSET_SIZE; - h2scf->max_header_size = NGX_CONF_UNSET_SIZE; - h2scf->preread_size = NGX_CONF_UNSET_SIZE; h2scf->streams_index_mask = NGX_CONF_UNSET_UINT; @@ -335,11 +340,6 @@ ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->concurrent_pushes, prev->concurrent_pushes, 10); - ngx_conf_merge_size_value(conf->max_field_size, prev->max_field_size, - 4096); - ngx_conf_merge_size_value(conf->max_header_size, prev->max_header_size, - 16384); - ngx_conf_merge_size_value(conf->preread_size, prev->preread_size, 65536); ngx_conf_merge_uint_value(conf->streams_index_mask, diff --git a/src/http/v2/ngx_http_v2_module.h b/src/http/v2/ngx_http_v2_module.h index 7b90f39e9..ca4a0bfc5 100644 --- a/src/http/v2/ngx_http_v2_module.h +++ b/src/http/v2/ngx_http_v2_module.h @@ -24,8 +24,6 @@ typedef struct { size_t pool_size; ngx_uint_t concurrent_streams; ngx_uint_t concurrent_pushes; - size_t max_field_size; - size_t max_header_size; size_t preread_size; ngx_uint_t streams_index_mask; } ngx_http_v2_srv_conf_t; -- cgit From e539d472e7a3016cff9c3fee2be2ef05369dedb3 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 16 Feb 2021 18:57:18 +0300 Subject: nginx-1.19.7-RELEASE --- docs/xml/nginx/changes.xml | 86 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml index 3d5666711..6d407f0bb 100644 --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,92 @@ + + + + +обработка соединений в HTTP/2 была изменена +и теперь более соответствует HTTP/1.x; +директивы http2_recv_timeout, http2_idle_timeout +и http2_max_requests упразднены, +вместо них следует использовать директивы +keepalive_timeout и keepalive_requests. + + +connections handling in HTTP/2 has been changed +to better match HTTP/1.x; +the "http2_recv_timeout", "http2_idle_timeout", +and "http2_max_requests" directives have been removed, +the "keepalive_timeout" and "keepalive_requests" directives +should be used instead. + + + + + +директивы http2_max_field_size и http2_max_header_size упразднены, +вместо них следует использовать директиву large_client_header_buffers. + + +the "http2_max_field_size" and "http2_max_header_size" directives +have been removed, +the "large_client_header_buffers" directive should be used instead. + + + + + +теперь при исчерпании свободных соединений +nginx закрывает не только keepalive-соединения, +но и соединения в lingering close. + + +now, if free worker connections are exhausted, +nginx starts closing not only keepalive connections, +but also connections in lingering close. + + + + + +в логах могли появляться сообщения "zero size buf in output", +если бэкенд возвращал некорректный ответ +при небуферизированном проксировании; +ошибка появилась в 1.19.1. + + +"zero size buf in output" alerts might appear in logs +if an upstream server returned an incorrect response +during unbuffered proxying; +the bug had appeared in 1.19.1. + + + + + +при использовании директивы return +вместе с image_filter или xslt_stylesheet +HEAD-запросы обрабатывались некорректно. + + +HEAD requests were handled incorrectly +if the "return" directive was used +with the "image_filter" or "xslt_stylesheet" directives. + + + + + +в директиве add_trailer. + + +in the "add_trailer" directive. + + + + + + -- cgit From 949c97007b9c6010e958c36653e33c3f5bf34540 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 16 Feb 2021 18:57:18 +0300 Subject: release-1.19.7 tag --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 4dffd1a73..139bd2f16 100644 --- a/.hgtags +++ b/.hgtags @@ -456,3 +456,4 @@ a7b46539f507e6c64efa0efda69ad60b6f4ffbce release-1.19.2 dc0cc425fa63a80315f6efb68697cadb6626cdf2 release-1.19.4 8e5b068f761cd512d10c9671fbde0b568c1fd08b release-1.19.5 f618488eb769e0ed74ef0d93cd118d2ad79ef94d release-1.19.6 +3fa6e2095a7a51acc630517e1c27a7b7ac41f7b3 release-1.19.7 -- cgit