Merge branch 'nginx' (nginx-1.15.6).

Change-Id: I2ea3953dd11ca3c2d27a2d89ba0768fa911ec25d
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index 58e35ca..04a512b 100644
--- a/.hgtags
+++ b/.hgtags
@@ -431,3 +431,4 @@
 28b3e17ca7eba1e6a0891afde0e4bc5bcc99c861 release-1.15.3
 49d49835653857daa418e68d6cbfed4958c78fca release-1.15.4
 f062e43d74fc2578bb100a9e82a953efa1eb9e4e release-1.15.5
+2351853ce6867b6166823bdf94333c0a76633c0a release-1.15.6
diff --git a/BUILD b/BUILD
index 232fe29..a08d335 100644
--- a/BUILD
+++ b/BUILD
@@ -1535,5 +1535,5 @@
     preinst = "@nginx_pkgoss//:debian_preinst",
     prerm = "@nginx_pkgoss//:debian_prerm",
     section = "httpd",
-    version = "1.15.5",
+    version = "1.15.6",
 )
diff --git a/build.bzl b/build.bzl
index b416982..8a6560b 100644
--- a/build.bzl
+++ b/build.bzl
@@ -663,7 +663,7 @@
         name = "nginx_pkgoss",
         build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) +
                              _PKGOSS_BUILD_FILE_TAIL,
-        commit = "d97bd6151f3a140021f9638c5d2ccc72e0c6911e",  # nginx-1.15.5
+        commit = "8cd9073e08734f32b52157e2495ad8804dbf8d51",  # nginx-1.15.6
         remote = "https://nginx.googlesource.com/nginx-pkgoss",
     )
 
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index dfff0a7..43a21e5 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,70 @@
 <change_log title="nginx">
 
 
+<changes ver="1.15.6" date="2018-11-06">
+
+<change type="security">
+<para lang="ru">
+при использовании HTTP/2 клиент мог вызвать
+чрезмерное потреблению памяти (CVE-2018-16843)
+и ресурсов процессора (CVE-2018-16844).
+</para>
+<para lang="en">
+when using HTTP/2 a client might cause
+excessive memory consumption (CVE-2018-16843)
+and CPU usage (CVE-2018-16844).
+</para>
+</change>
+
+<change type="security">
+<para lang="ru">
+при обработке специально созданного mp4-файла модулем ngx_http_mp4_module
+содержимое памяти рабочего процесса могло быть отправлено клиенту
+(CVE-2018-16845).
+</para>
+<para lang="en">
+processing of a specially crafted mp4 file with the ngx_http_mp4_module
+might result in worker process memory disclosure
+(CVE-2018-16845).
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директивы proxy_socket_keepalive, fastcgi_socket_keepalive,
+grpc_socket_keepalive, memcached_socket_keepalive,
+scgi_socket_keepalive и uwsgi_socket_keepalive.
+</para>
+<para lang="en">
+the "proxy_socket_keepalive", "fastcgi_socket_keepalive",
+"grpc_socket_keepalive", "memcached_socket_keepalive",
+"scgi_socket_keepalive", and "uwsgi_socket_keepalive" directives.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+если nginx был собран с OpenSSL 1.1.0, а использовался с OpenSSL 1.1.1,
+протокол TLS 1.3 всегда был разрешён.
+</para>
+<para lang="en">
+if nginx was built with OpenSSL 1.1.0 and used with OpenSSL 1.1.1,
+the TLS 1.3 protocol was always enabled.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при работе с gRPC-бэкендами могло расходоваться большое количество памяти.
+</para>
+<para lang="en">
+working with gRPC backends might result in excessive memory consumption.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="1.15.5" date="2018-10-02">
 
 <change type="bugfix">
diff --git a/src/core/nginx.h b/src/core/nginx.h
index c109ae1..2ddd19d 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
 #define NGINX_NAME         "nginx"
 #endif
 
-#define nginx_version      1015005
-#define NGINX_VERSION      "1.15.5"
+#define nginx_version      1015006
+#define NGINX_VERSION      "1.15.6"
 #define NGINX_VER          NGINX_NAME "/" NGINX_VERSION
 
 #ifdef NGX_BUILD
diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h
index 6783e71..0c03b56 100644
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -504,7 +504,7 @@
 
 
 #define ngx_event_get_conf(conf_ctx, module)                                  \
-             (*(ngx_get_conf(conf_ctx, ngx_events_module))) [module.ctx_index];
+             (*(ngx_get_conf(conf_ctx, ngx_events_module))) [module.ctx_index]
 
 
 
diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c
index 714fc47..1ffa798 100644
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -20,7 +20,7 @@
 ngx_int_t
 ngx_event_connect_peer(ngx_peer_connection_t *pc)
 {
-    int                rc, type;
+    int                rc, type, value;
 #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX)
     in_port_t          port;
 #endif
@@ -73,6 +73,18 @@
         }
     }
 
+    if (pc->so_keepalive) {
+        value = 1;
+
+        if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
+                       (const void *) &value, sizeof(int))
+            == -1)
+        {
+            ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
+                          "setsockopt(SO_KEEPALIVE) failed, ignored");
+        }
+    }
+
     if (ngx_nonblocking(s) == -1) {
         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
                       ngx_nonblocking_n " failed");
diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h
index 72d21d7..7253ebb 100644
--- a/src/event/ngx_event_connect.h
+++ b/src/event/ngx_event_connect.h
@@ -62,6 +62,7 @@
 
     unsigned                         cached:1;
     unsigned                         transparent:1;
+    unsigned                         so_keepalive:1;
 
                                      /* ngx_connection_log_error_e */
     unsigned                         log_error:2;
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index b903e87..88571a9 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -345,6 +345,11 @@
     }
 #endif
 
+#ifdef SSL_CTX_set_min_proto_version
+    SSL_CTX_set_min_proto_version(ssl->ctx, 0);
+    SSL_CTX_set_max_proto_version(ssl->ctx, TLS1_2_VERSION);
+#endif
+
 #ifdef TLS1_3_VERSION
     SSL_CTX_set_min_proto_version(ssl->ctx, 0);
     SSL_CTX_set_max_proto_version(ssl->ctx, TLS1_3_VERSION);
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index f73ff21..2be0672 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -286,6 +286,13 @@
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.local),
       NULL },
 
+    { ngx_string("fastcgi_socket_keepalive"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.socket_keepalive),
+      NULL },
+
     { ngx_string("fastcgi_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -2721,6 +2728,7 @@
     conf->upstream.force_ranges = NGX_CONF_UNSET;
 
     conf->upstream.local = NGX_CONF_UNSET_PTR;
+    conf->upstream.socket_keepalive = NGX_CONF_UNSET;
 
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
@@ -2824,6 +2832,9 @@
     ngx_conf_merge_ptr_value(conf->upstream.local,
                               prev->upstream.local, NULL);
 
+    ngx_conf_merge_value(conf->upstream.socket_keepalive,
+                              prev->upstream.socket_keepalive, 0);
+
     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
                               prev->upstream.connect_timeout, 60000);
 
diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c
index 17b0a26..18478b9 100644
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -78,6 +78,9 @@
 
     ngx_uint_t                 id;
 
+    ngx_uint_t                 pings;
+    ngx_uint_t                 settings;
+
     ssize_t                    send_window;
     size_t                     recv_window;
 
@@ -248,6 +251,13 @@
       offsetof(ngx_http_grpc_loc_conf_t, upstream.local),
       NULL },
 
+    { ngx_string("grpc_socket_keepalive"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_grpc_loc_conf_t, upstream.socket_keepalive),
+      NULL },
+
     { ngx_string("grpc_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -3577,6 +3587,12 @@
                           ctx->rest);
             return NGX_ERROR;
         }
+
+        if (ctx->free == NULL && ctx->settings++ > 1000) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "upstream sent too many settings frames");
+            return NGX_ERROR;
+        }
     }
 
     for (p = b->pos; p < last; p++) {
@@ -3729,6 +3745,12 @@
                           "upstream sent ping frame with ack flag");
             return NGX_ERROR;
         }
+
+        if (ctx->free == NULL && ctx->pings++ > 1000) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "upstream sent too many ping frames");
+            return NGX_ERROR;
+        }
     }
 
     for (p = b->pos; p < last; p++) {
@@ -4150,6 +4172,7 @@
      */
 
     conf->upstream.local = NGX_CONF_UNSET_PTR;
+    conf->upstream.socket_keepalive = NGX_CONF_UNSET;
     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
@@ -4205,6 +4228,9 @@
     ngx_conf_merge_ptr_value(conf->upstream.local,
                               prev->upstream.local, NULL);
 
+    ngx_conf_merge_value(conf->upstream.socket_keepalive,
+                              prev->upstream.socket_keepalive, 0);
+
     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
                               prev->upstream.next_upstream_tries, 0);
 
diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c
index 2624471..775bd7e 100644
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -67,6 +67,13 @@
       offsetof(ngx_http_memcached_loc_conf_t, upstream.local),
       NULL },
 
+    { ngx_string("memcached_socket_keepalive"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_memcached_loc_conf_t, upstream.socket_keepalive),
+      NULL },
+
     { ngx_string("memcached_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -595,6 +602,7 @@
      */
 
     conf->upstream.local = NGX_CONF_UNSET_PTR;
+    conf->upstream.socket_keepalive = NGX_CONF_UNSET;
     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
@@ -634,6 +642,9 @@
     ngx_conf_merge_ptr_value(conf->upstream.local,
                               prev->upstream.local, NULL);
 
+    ngx_conf_merge_value(conf->upstream.socket_keepalive,
+                              prev->upstream.socket_keepalive, 0);
+
     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
                               prev->upstream.next_upstream_tries, 0);
 
diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c
index 08a68d0..2a6fafa 100644
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -942,6 +942,13 @@
                 atom_size = ngx_mp4_get_64value(atom_header + 8);
                 atom_header_size = sizeof(ngx_mp4_atom_header64_t);
 
+                if (atom_size < sizeof(ngx_mp4_atom_header64_t)) {
+                    ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+                                  "\"%s\" mp4 atom is too small:%uL",
+                                  mp4->file.name.data, atom_size);
+                    return NGX_ERROR;
+                }
+
             } else {
                 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
                               "\"%s\" mp4 atom is too small:%uL",
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index a817b5c..09c6b53 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -324,6 +324,13 @@
       offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
       NULL },
 
+    { ngx_string("proxy_socket_keepalive"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.socket_keepalive),
+      NULL },
+
     { ngx_string("proxy_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -2840,6 +2847,7 @@
     conf->upstream.force_ranges = NGX_CONF_UNSET;
 
     conf->upstream.local = NGX_CONF_UNSET_PTR;
+    conf->upstream.socket_keepalive = NGX_CONF_UNSET;
 
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
@@ -2961,6 +2969,9 @@
     ngx_conf_merge_ptr_value(conf->upstream.local,
                               prev->upstream.local, NULL);
 
+    ngx_conf_merge_value(conf->upstream.socket_keepalive,
+                              prev->upstream.socket_keepalive, 0);
+
     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
                               prev->upstream.connect_timeout, 60000);
 
diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c
index ab7769a..7216f78 100644
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -143,6 +143,13 @@
       offsetof(ngx_http_scgi_loc_conf_t, upstream.local),
       NULL },
 
+    { ngx_string("scgi_socket_keepalive"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.socket_keepalive),
+      NULL },
+
     { ngx_string("scgi_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -1200,6 +1207,7 @@
     conf->upstream.force_ranges = NGX_CONF_UNSET;
 
     conf->upstream.local = NGX_CONF_UNSET_PTR;
+    conf->upstream.socket_keepalive = NGX_CONF_UNSET;
 
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
@@ -1298,6 +1306,9 @@
     ngx_conf_merge_ptr_value(conf->upstream.local,
                               prev->upstream.local, NULL);
 
+    ngx_conf_merge_value(conf->upstream.socket_keepalive,
+                              prev->upstream.socket_keepalive, 0);
+
     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
                               prev->upstream.connect_timeout, 60000);
 
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index d0adbdb..8b09110 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -204,6 +204,13 @@
       offsetof(ngx_http_uwsgi_loc_conf_t, upstream.local),
       NULL },
 
+    { ngx_string("uwsgi_socket_keepalive"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.socket_keepalive),
+      NULL },
+
     { ngx_string("uwsgi_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -1413,6 +1420,7 @@
     conf->upstream.force_ranges = NGX_CONF_UNSET;
 
     conf->upstream.local = NGX_CONF_UNSET_PTR;
+    conf->upstream.socket_keepalive = NGX_CONF_UNSET;
 
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
@@ -1519,6 +1527,9 @@
     ngx_conf_merge_ptr_value(conf->upstream.local,
                               prev->upstream.local, NULL);
 
+    ngx_conf_merge_value(conf->upstream.socket_keepalive,
+                              prev->upstream.socket_keepalive, 0);
+
     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
                               prev->upstream.connect_timeout, 60000);
 
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index 330833d..ecdf11e 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -2418,23 +2418,32 @@
 
             p = (u_char *) ngx_strchr(name.data, ':');
 
-            if (p) {
-                name.len = p - name.data;
-
-                p++;
-
-                s.len = value[i].data + value[i].len - p;
-                s.data = p;
-
-                size = ngx_parse_size(&s);
-                if (size > 8191) {
-                    continue;
-                }
+            if (p == NULL) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid keys zone size \"%V\"", &value[i]);
+                return NGX_CONF_ERROR;
             }
 
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "invalid keys zone size \"%V\"", &value[i]);
-            return NGX_CONF_ERROR;
+            name.len = p - name.data;
+
+            s.data = p + 1;
+            s.len = value[i].data + value[i].len - s.data;
+
+            size = ngx_parse_size(&s);
+
+            if (size == NGX_ERROR) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid keys zone size \"%V\"", &value[i]);
+                return NGX_CONF_ERROR;
+            }
+
+            if (size < (ssize_t) (2 * ngx_pagesize)) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "keys zone \"%V\" is too small", &value[i]);
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
         }
 
         if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 4fc41de..1127b71 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -632,6 +632,10 @@
         return;
     }
 
+    if (u->conf->socket_keepalive) {
+        u->peer.so_keepalive = 1;
+    }
+
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     u->output.alignment = clcf->directio_alignment;
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index 921a4f2..26a0cc5 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -189,6 +189,7 @@
     ngx_array_t                     *pass_headers;
 
     ngx_http_upstream_local_t       *local;
+    ngx_flag_t                       socket_keepalive;
 
 #if (NGX_HTTP_CACHE)
     ngx_shm_zone_t                  *cache_zone;
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index 04b3385..c070aa6 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -663,6 +663,7 @@
 
     h2c->pool = NULL;
     h2c->free_frames = NULL;
+    h2c->frames = 0;
     h2c->free_fake_connections = NULL;
 
 #if (NGX_HTTP_SSL)
@@ -2938,7 +2939,7 @@
 
         frame->blocked = 0;
 
-    } else {
+    } else if (h2c->frames < 10000) {
         pool = h2c->pool ? h2c->pool : h2c->connection->pool;
 
         frame = ngx_pcalloc(pool, sizeof(ngx_http_v2_out_frame_t));
@@ -2962,6 +2963,15 @@
         frame->last = frame->first;
 
         frame->handler = ngx_http_v2_frame_handler;
+
+        h2c->frames++;
+
+    } else {
+        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
+                      "http2 flood detected");
+
+        h2c->connection->error = 1;
+        return NULL;
     }
 
 #if (NGX_DEBUG)
@@ -4550,12 +4560,19 @@
 
 #endif
 
-    c->destroyed = 0;
-    ngx_reusable_connection(c, 0);
-
     h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
                                          ngx_http_v2_module);
 
+    if (h2c->idle++ > 10 * h2scf->max_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);
+        return;
+    }
+
+    c->destroyed = 0;
+    ngx_reusable_connection(c, 0);
+
     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.h b/src/http/v2/ngx_http_v2.h
index ebd0e77..bec2216 100644
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -120,6 +120,8 @@
     ngx_http_connection_t           *http_connection;
 
     ngx_uint_t                       processing;
+    ngx_uint_t                       frames;
+    ngx_uint_t                       idle;
 
     ngx_uint_t                       pushing;
     ngx_uint_t                       concurrent_pushes;
diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c
index d0497f5..c8465a7 100644
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -31,6 +31,7 @@
     ngx_flag_t                       next_upstream;
     ngx_flag_t                       proxy_protocol;
     ngx_stream_upstream_local_t     *local;
+    ngx_flag_t                       socket_keepalive;
 
 #if (NGX_STREAM_SSL)
     ngx_flag_t                       ssl_enable;
@@ -136,6 +137,13 @@
       0,
       NULL },
 
+    { ngx_string("proxy_socket_keepalive"),
+      NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_STREAM_SRV_CONF_OFFSET,
+      offsetof(ngx_stream_proxy_srv_conf_t, socket_keepalive),
+      NULL },
+
     { ngx_string("proxy_connect_timeout"),
       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -388,6 +396,10 @@
         return;
     }
 
+    if (pscf->socket_keepalive) {
+        u->peer.so_keepalive = 1;
+    }
+
     u->peer.type = c->type;
     u->start_sec = ngx_time();
 
@@ -1898,6 +1910,7 @@
     conf->next_upstream = NGX_CONF_UNSET;
     conf->proxy_protocol = NGX_CONF_UNSET;
     conf->local = NGX_CONF_UNSET_PTR;
+    conf->socket_keepalive = NGX_CONF_UNSET;
 
 #if (NGX_STREAM_SSL)
     conf->ssl_enable = NGX_CONF_UNSET;
@@ -1948,6 +1961,9 @@
 
     ngx_conf_merge_ptr_value(conf->local, prev->local, NULL);
 
+    ngx_conf_merge_value(conf->socket_keepalive,
+                              prev->socket_keepalive, 0);
+
 #if (NGX_STREAM_SSL)
 
     ngx_conf_merge_value(conf->ssl_enable, prev->ssl_enable, 0);