changeset 8704:13f7085b90d2 quic

Merged with the default branch.
author Sergey Kandaurov <pluknet@nginx.com>
date Wed, 17 Feb 2021 14:48:35 +0300
parents d710c457171c (current diff) f77ad78046dc (diff)
children ae2e68f206f9
files src/core/ngx_connection.c src/core/ngx_connection.h src/http/ngx_http.c src/http/ngx_http_core_module.c src/http/ngx_http_request.c src/http/ngx_http_upstream.c
diffstat 17 files changed, 307 insertions(+), 190 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags
+++ b/.hgtags
@@ -456,3 +456,4 @@ 3cbc2602325f0ac08917a4397d76f5155c34b7b1
 dc0cc425fa63a80315f6efb68697cadb6626cdf2 release-1.19.4
 8e5b068f761cd512d10c9671fbde0b568c1fd08b release-1.19.5
 f618488eb769e0ed74ef0d93cd118d2ad79ef94d release-1.19.6
+3fa6e2095a7a51acc630517e1c27a7b7ac41f7b3 release-1.19.7
--- a/contrib/vim/syntax/nginx.vim
+++ b/contrib/vim/syntax/nginx.vim
@@ -268,6 +268,7 @@ syn keyword ngxDirective contained grpc_
 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
 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
 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_c
 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_p
 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
 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_
 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 conta
 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 conta
 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 conta
 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 conta
 
 " 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 conta
 syn keyword ngxDirectiveThirdParty contained ip2proxy_country_short
 syn keyword ngxDirectiveThirdParty contained ip2proxy_database
 syn keyword ngxDirectiveThirdParty contained ip2proxy_domain
+syn keyword ngxDirectiveThirdParty contained ip2proxy_isp
 syn keyword ngxDirectiveThirdParty contained ip2proxy_is_proxy
-syn keyword ngxDirectiveThirdParty contained ip2proxy_isp
 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
 
 
--- 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
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,92 @@
 <change_log title="nginx">
 
 
+<changes ver="1.19.7" date="2021-02-16">
+
+<change type="change">
+<para lang="ru">
+обработка соединений в HTTP/2 была изменена
+и теперь более соответствует HTTP/1.x;
+директивы http2_recv_timeout, http2_idle_timeout
+и http2_max_requests упразднены,
+вместо них следует использовать директивы
+keepalive_timeout и keepalive_requests.
+</para>
+<para lang="en">
+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.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+директивы http2_max_field_size и http2_max_header_size упразднены,
+вместо них следует использовать директиву large_client_header_buffers.
+</para>
+<para lang="en">
+the "http2_max_field_size" and "http2_max_header_size" directives
+have been removed,
+the "large_client_header_buffers" directive should be used instead.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+теперь при исчерпании свободных соединений
+nginx закрывает не только keepalive-соединения,
+но и соединения в lingering close.
+</para>
+<para lang="en">
+now, if free worker connections are exhausted,
+nginx starts closing not only keepalive connections,
+but also connections in lingering close.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в логах могли появляться сообщения "zero size buf in output",
+если бэкенд возвращал некорректный ответ
+при небуферизированном проксировании;
+ошибка появилась в 1.19.1.
+</para>
+<para lang="en">
+"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.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при использовании директивы return
+вместе с image_filter или xslt_stylesheet
+HEAD-запросы обрабатывались некорректно.
+</para>
+<para lang="en">
+HEAD requests were handled incorrectly
+if the "return" directive was used
+with the "image_filter" or "xslt_stylesheet" directives.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в директиве add_trailer.
+</para>
+<para lang="en">
+in the "add_trailer" directive.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="1.19.6" date="2020-12-15">
 
 <change type="bugfix">
--- 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
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -1316,6 +1316,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++) {
@@ -1332,6 +1333,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);
+    }
 }
 
 
--- 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;
--- 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(
 
     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;
     }
--- 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_re
     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
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -1747,7 +1747,6 @@ ngx_http_add_listening(ngx_conf_t *cf, n
 
     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];
 
--- 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_
         }
     }
 
-    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);
     }
 
@@ -4106,14 +4106,6 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 #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) {
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -200,16 +200,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));
@@ -370,7 +371,9 @@ ngx_http_init_connection(ngx_connection_
         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) {
@@ -440,7 +443,7 @@ ngx_http_wait_request_handler(ngx_event_
     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);
         }
 
@@ -658,6 +661,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;
@@ -689,7 +693,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);
             }
 
@@ -764,7 +770,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;
@@ -3458,6 +3466,9 @@ ngx_http_set_lingering_close(ngx_connect
         return;
     }
 
+    c->close = 0;
+    ngx_reusable_connection(c, 1);
+
     ngx_add_timer(rev, clcf->lingering_timeout);
 
     if (rev->ready) {
@@ -3482,7 +3493,7 @@ ngx_http_lingering_close_handler(ngx_eve
     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;
     }
--- 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->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;
 }
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -3741,6 +3741,13 @@ ngx_http_upstream_non_buffered_filter(vo
 
     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;
     }
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -325,7 +325,12 @@ 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);
 
     ngx_http_v2_read_handler(rev);
 }
@@ -362,6 +367,11 @@ ngx_http_v2_read_handler(ngx_event_t *re
             return;
         }
 
+        if (!h2c->processing && !h2c->pushing) {
+            ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR);
+            return;
+        }
+
         if (!h2c->goaway) {
             h2c->goaway = 1;
 
@@ -449,14 +459,6 @@ ngx_http_v2_read_handler(ngx_event_t *re
 
     h2c->blocked = 0;
 
-    if (h2c->processing || h2c->pushing) {
-        if (rev->timer_set) {
-            ngx_del_timer(rev);
-        }
-
-        return;
-    }
-
     ngx_http_v2_handle_connection(h2c);
 }
 
@@ -629,9 +631,9 @@ 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_core_loc_conf_t  *clcf;
 
     if (h2c->last_out || h2c->processing || h2c->pushing) {
         return;
@@ -668,10 +670,16 @@ ngx_http_v2_handle_connection(ngx_http_v
         return;
     }
 
-    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 (!c->read->timer_set) {
+        ngx_add_timer(c->read, clcf->keepalive_timeout);
+    }
+
+    ngx_reusable_connection(c, 1);
+
     if (h2c->state.incomplete) {
-        ngx_add_timer(c->read, h2scf->recv_timeout);
         return;
     }
 
@@ -689,7 +697,6 @@ ngx_http_v2_handle_connection(ngx_http_v
 #endif
 
     c->destroyed = 1;
-    ngx_reusable_connection(c, 1);
 
     c->write->handler = ngx_http_empty_handler;
     c->read->handler = ngx_http_v2_idle_handler;
@@ -697,8 +704,6 @@ ngx_http_v2_handle_connection(ngx_http_v
     if (c->write->timer_set) {
         ngx_del_timer(c->write);
     }
-
-    ngx_add_timer(c->read, h2scf->idle_timeout);
 }
 
 
@@ -767,6 +772,9 @@ ngx_http_v2_lingering_close(ngx_connecti
         return;
     }
 
+    c->close = 0;
+    ngx_reusable_connection(c, 1);
+
     ngx_add_timer(rev, clcf->lingering_timeout);
 
     if (rev->ready) {
@@ -791,7 +799,7 @@ ngx_http_v2_lingering_close_handler(ngx_
     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;
     }
@@ -807,6 +815,10 @@ ngx_http_v2_lingering_close_handler(ngx_
 
         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;
@@ -1179,12 +1191,15 @@ 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_srv_conf_t  *cscf;
+    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;
@@ -1285,11 +1300,15 @@ ngx_http_v2_state_headers(ngx_http_v2_co
         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);
@@ -1343,7 +1362,10 @@ ngx_http_v2_state_headers(ngx_http_v2_co
         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) {
@@ -1468,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)
@@ -1518,12 +1540,12 @@ ngx_http_v2_state_field_len(ngx_http_v2_
                    "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);
-
-    if ((size_t) len > h2scf->max_field_size) {
+    cscf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
+                                        ngx_http_core_module);
+
+    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);
     }
@@ -1738,7 +1760,7 @@ ngx_http_v2_state_process_header(ngx_htt
 
     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);
     }
@@ -3272,6 +3294,10 @@ ngx_http_v2_create_stream(ngx_http_v2_co
 
     h2c->priority_limit += h2scf->concurrent_streams;
 
+    if (h2c->connection->read->timer_set) {
+        ngx_del_timer(h2c->connection->read);
+    }
+
     return stream;
 }
 
@@ -4638,6 +4664,7 @@ ngx_http_v2_idle_handler(ngx_event_t *re
     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;
@@ -4669,10 +4696,10 @@ ngx_http_v2_idle_handler(ngx_event_t *re
 
 #endif
 
-    h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
-                                         ngx_http_v2_module);
-
-    if (h2c->idle++ > 10 * h2scf->max_requests) {
+    clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx,
+                                        ngx_http_core_module);
+
+    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);
@@ -4682,6 +4709,9 @@ ngx_http_v2_idle_handler(ngx_event_t *re
     c->destroyed = 0;
     ngx_reusable_connection(c, 0);
 
+    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);
--- a/src/http/v2/ngx_http_v2_module.c
+++ b/src/http/v2/ngx_http_v2_module.c
@@ -36,10 +36,31 @@ static char *ngx_http_v2_preread_size(ng
 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,
+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_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_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 };
 static ngx_conf_post_t  ngx_http_v2_pool_size_post =
@@ -84,24 +105,24 @@ static ngx_command_t  ngx_http_v2_comman
 
     { 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,
-      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,
@@ -119,17 +140,17 @@ static ngx_command_t  ngx_http_v2_comman
 
     { 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,
-      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,
@@ -152,62 +173,6 @@ static ngx_command_t  ngx_http_v2_comman
       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
 };
 
@@ -353,18 +318,11 @@ ngx_http_v2_create_srv_conf(ngx_conf_t *
 
     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;
 
     h2scf->preread_size = NGX_CONF_UNSET_SIZE;
 
     h2scf->streams_index_mask = NGX_CONF_UNSET_UINT;
 
-    h2scf->recv_timeout = NGX_CONF_UNSET_MSEC;
-    h2scf->idle_timeout = NGX_CONF_UNSET_MSEC;
-
     return h2scf;
 }
 
@@ -381,23 +339,12 @@ ngx_http_v2_merge_srv_conf(ngx_conf_t *c
                               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);
-    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,
                               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);
-
     return NGX_CONF_OK;
 }
 
@@ -600,11 +547,14 @@ ngx_http_v2_chunk_size(ngx_conf_t *cf, v
 
 
 static char *
-ngx_http_v2_spdy_deprecated(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+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,
-                       "invalid directive \"%V\": ngx_http_spdy_module "
-                       "was superseded by ngx_http_v2_module", &cmd->name);
+                       "the \"%s\" directive is obsolete, "
+                       "use the \"%s\" directive instead",
+                       d->old_name, d->new_name);
 
     return NGX_CONF_OK;
 }
--- a/src/http/v2/ngx_http_v2_module.h
+++ b/src/http/v2/ngx_http_v2_module.h
@@ -24,13 +24,8 @@ 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                      recv_timeout;
-    ngx_msec_t                      idle_timeout;
 } ngx_http_v2_srv_conf_t;