Merge branch 'nginx' (nginx-1.11.6).

Change-Id: Icb9e5403e3501273bfdfc729ecb3dedf003fc284
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index 6bd0512..d4acb78 100644
--- a/.hgtags
+++ b/.hgtags
@@ -404,3 +404,4 @@
 b83a067949a3384a49fd3d943eb8d0997b31f87b release-1.11.3
 953512ca02c6f63b4fcbbc3e10d0d9835896bf99 release-1.11.4
 5253015a339aaca0a3111473d3e931b6d4752393 release-1.11.5
+5e371426b3bcba4312ce08606194b89b758927d1 release-1.11.6
diff --git a/BUILD b/BUILD
index 0f05f9b..953f138 100644
--- a/BUILD
+++ b/BUILD
@@ -1468,5 +1468,5 @@
     preinst = "@nginx_pkgoss//:debian_preinst",
     prerm = "@nginx_pkgoss//:debian_prerm",
     section = "httpd",
-    version = "1.11.5",
+    version = "1.11.6",
 )
diff --git a/auto/lib/libgd/conf b/auto/lib/libgd/conf
index 84031b6..2025396 100644
--- a/auto/lib/libgd/conf
+++ b/auto/lib/libgd/conf
@@ -74,6 +74,11 @@
 
     NGX_LIB_LIBGD=$ngx_feature_libs
 
+    ngx_feature="GD WebP support"
+    ngx_feature_name="NGX_HAVE_GD_WEBP"
+    ngx_feature_test="gdImagePtr img = gdImageCreateFromWebpPtr(1, NULL);"
+    . auto/feature
+
 else
 
 cat << END
diff --git a/build.bzl b/build.bzl
index ad949e4..cf90e8b 100644
--- a/build.bzl
+++ b/build.bzl
@@ -666,7 +666,7 @@
         name = "nginx_pkgoss",
         build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) +
                              _PKGOSS_BUILD_FILE_TAIL,
-        commit = "842c192fdab7037c0b099ed6c290daa00e9c0cd5",  # nginx-1.11.5
+        commit = "f0a74a54c8948c668fe477f7fafb0f3a175ee19a",  # nginx-1.11.6
         remote = "https://nginx.googlesource.com/nginx-pkgoss",
     )
 
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 97ed726..1376338 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,136 @@
 <change_log title="nginx">
 
 
+<changes ver="1.11.6" date="15.11.2016">
+
+<change type="change">
+<para lang="ru">
+формат переменных $ssl_client_s_dn и $ssl_client_i_dn
+изменён на соответствующий RFC 2253 (RFC 4514);
+значения в старом формате доступны через переменные
+$ssl_client_s_dn_legacy и $ssl_client_i_dn_legacy.
+</para>
+<para lang="en">
+format of the $ssl_client_s_dn and $ssl_client_i_dn variables
+has been changed to follow RFC 2253 (RFC 4514);
+values in the old format are available in
+the $ssl_client_s_dn_legacy and $ssl_client_i_dn_legacy variables.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+при сохранении временных файлов в каталоге кэша
+они теперь располагаются не в отдельном подкаталоге для временных файлов,
+а в том же подкаталоге, что и соответствующие файлы в кэше.
+</para>
+<para lang="en">
+when storing temporary files in a cache directory
+they will be stored in the same subdirectories as corresponding cache files
+instead of a separate subdirectory for temporary files.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+поддержка метода аутентификации EXTERNAL
+в почтовом прокси-сервере.<br/>
+Спасибо Robert Norris.
+</para>
+<para lang="en">
+EXTERNAL authentication mechanism support
+in mail proxy.<br/>
+Thanks to Robert Norris.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+поддержка WebP в модуле ngx_http_image_filter_module.
+</para>
+<para lang="en">
+WebP support in the ngx_http_image_filter_module.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директива proxy_method поддерживает переменные.<br/>
+Спасибо Дмитрию Лазуркину.
+</para>
+<para lang="en">
+variables support in the "proxy_method" directive.<br/>
+Thanks to Dmitry Lazurkin.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директива http2_max_requests в модуле ngx_http_v2_module.
+</para>
+<para lang="en">
+the "http2_max_requests" directive in the ngx_http_v2_module.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директивы proxy_cache_max_range_offset, fastcgi_cache_max_range_offset,
+scgi_cache_max_range_offset и uwsgi_cache_max_range_offset.
+</para>
+<para lang="en">
+the "proxy_cache_max_range_offset", "fastcgi_cache_max_range_offset",
+"scgi_cache_max_range_offset", and "uwsgi_cache_max_range_offset" directives.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+плавное завершение старых рабочих процессов могло занимать бесконечное время
+при использовании HTTP/2.
+</para>
+<para lang="en">
+graceful shutdown of old worker processes might require infinite time
+when using HTTP/2.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в модуле ngx_http_mp4_module.
+</para>
+<para lang="en">
+in the ngx_http_mp4_module.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при проксировании WebSocket-соединений и включённом кэшировании
+в логах могли появляться сообщения "ignore long locked inactive cache entry".
+</para>
+<para lang="en">
+"ignore long locked inactive cache entry" alerts might appear in logs
+when proxying WebSocket connections with caching enabled.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+если во время SSL handshake с бэкендом происходил таймаут,
+nginx ничего не писал в лог
+и возвращал ответ с кодом 502 вместо 504.
+</para>
+<para lang="en">
+nginx did not write anything to log
+and returned a response with code 502 instead of 504
+when a timeout occurred during an SSL handshake to a backend.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="1.11.5" date="11.10.2016">
 
 <change type="change">
@@ -790,7 +920,6 @@
 в логах могли появляться сообщения "task already active" и "second aio post".
 </para>
 <para lang="en">
-
 "task already active" and "second aio post" alerts might appear in logs
 when using the "sendfile" and "aio" directives with subrequests.
 </para>
@@ -18140,7 +18269,7 @@
 
 <change type="feature">
 <para lang="ru">
-POP3 прокси поддерживает AUTH LOIGN PLAIN и CRAM-MD5.
+POP3 прокси поддерживает AUTH LOGIN PLAIN и CRAM-MD5.
 </para>
 <para lang="en">
 the POP3 proxy supports the AUTH LOGIN PLAIN and CRAM-MD5.
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 955a39b..9f545d3 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
 #define NGINX_NAME         "nginx"
 #endif
 
-#define nginx_version      1011005
-#define NGINX_VERSION      "1.11.5"
+#define nginx_version      1011006
+#define NGINX_VERSION      "1.11.6"
 #define NGINX_VER          NGINX_NAME "/" NGINX_VERSION
 
 #ifdef NGX_BUILD
diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c
index 00b6644..d30a0a4 100644
--- a/src/core/ngx_buf.c
+++ b/src/core/ngx_buf.c
@@ -186,17 +186,19 @@
 {
     ngx_chain_t  *cl;
 
-    if (*busy == NULL) {
-        *busy = *out;
+    if (*out) {
+        if (*busy == NULL) {
+            *busy = *out;
 
-    } else {
-        for (cl = *busy; cl->next; cl = cl->next) { /* void */ }
+        } else {
+            for (cl = *busy; cl->next; cl = cl->next) { /* void */ }
 
-        cl->next = *out;
+            cl->next = *out;
+        }
+
+        *out = NULL;
     }
 
-    *out = NULL;
-
     while (*busy) {
         cl = *busy;
 
diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c
index ea1dceb..ce8c602 100644
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -10,6 +10,7 @@
 
 #define NGX_CONF_BUFFER  4096
 
+static ngx_int_t ngx_conf_add_dump(ngx_conf_t *cf, ngx_str_t *filename);
 static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last);
 static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf);
 static void ngx_conf_flush_files(ngx_cycle_t *cycle);
@@ -97,17 +98,70 @@
 }
 
 
+static ngx_int_t
+ngx_conf_add_dump(ngx_conf_t *cf, ngx_str_t *filename)
+{
+    off_t             size;
+    u_char           *p;
+    uint32_t          hash;
+    ngx_buf_t        *buf;
+    ngx_str_node_t   *sn;
+    ngx_conf_dump_t  *cd;
+
+    hash = ngx_crc32_long(filename->data, filename->len);
+
+    sn = ngx_str_rbtree_lookup(&cf->cycle->config_dump_rbtree, filename, hash);
+
+    if (sn) {
+        cf->conf_file->dump = NULL;
+        return NGX_OK;
+    }
+
+    p = ngx_pstrdup(cf->cycle->pool, filename);
+    if (p == NULL) {
+        return NGX_ERROR;
+    }
+
+    cd = ngx_array_push(&cf->cycle->config_dump);
+    if (cd == NULL) {
+        return NGX_ERROR;
+    }
+
+    size = ngx_file_size(&cf->conf_file->file.info);
+
+    buf = ngx_create_temp_buf(cf->cycle->pool, (size_t) size);
+    if (buf == NULL) {
+        return NGX_ERROR;
+    }
+
+    cd->name.data = p;
+    cd->name.len = filename->len;
+    cd->buffer = buf;
+
+    cf->conf_file->dump = buf;
+
+    sn = ngx_palloc(cf->temp_pool, sizeof(ngx_str_node_t));
+    if (sn == NULL) {
+        return NGX_ERROR;
+    }
+
+    sn->node.key = hash;
+    sn->str = cd->name;
+
+    ngx_rbtree_insert(&cf->cycle->config_dump_rbtree, &sn->node);
+
+    return NGX_OK;
+}
+
+
 char *
 ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
 {
     char             *rv;
-    u_char           *p;
-    off_t             size;
     ngx_fd_t          fd;
     ngx_int_t         rc;
-    ngx_buf_t         buf, *tbuf;
+    ngx_buf_t         buf;
     ngx_conf_file_t  *prev, conf_file;
-    ngx_conf_dump_t  *cd;
     enum {
         parse_file = 0,
         parse_block,
@@ -167,29 +221,10 @@
 #endif
            )
         {
-            p = ngx_pstrdup(cf->cycle->pool, filename);
-            if (p == NULL) {
+            if (ngx_conf_add_dump(cf, filename) != NGX_OK) {
                 goto failed;
             }
 
-            size = ngx_file_size(&cf->conf_file->file.info);
-
-            tbuf = ngx_create_temp_buf(cf->cycle->pool, (size_t) size);
-            if (tbuf == NULL) {
-                goto failed;
-            }
-
-            cd = ngx_array_push(&cf->cycle->config_dump);
-            if (cd == NULL) {
-                goto failed;
-            }
-
-            cd->name.len = filename->len;
-            cd->name.data = p;
-            cd->buffer = tbuf;
-
-            cf->conf_file->dump = tbuf;
-
         } else {
             cf->conf_file->dump = NULL;
         }
diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c
index 98599f3..a57991c 100644
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -132,6 +132,9 @@
         return NULL;
     }
 
+    ngx_rbtree_init(&cycle->config_dump_rbtree, &cycle->config_dump_sentinel,
+                    ngx_str_rbtree_insert_value);
+
     if (old_cycle->open_files.part.nelts) {
         n = old_cycle->open_files.part.nelts;
         for (part = old_cycle->open_files.part.next; part; part = part->next) {
diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h
index f17c1bc..dfc3630 100644
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -56,7 +56,11 @@
 
     ngx_array_t               listening;
     ngx_array_t               paths;
+
     ngx_array_t               config_dump;
+    ngx_rbtree_t              config_dump_rbtree;
+    ngx_rbtree_node_t         config_dump_sentinel;
+
     ngx_list_t                open_files;
     ngx_list_t                shared_memory;
 
diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c
index 8359c0f..b7dd4bc 100644
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -141,12 +141,27 @@
 ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,
     ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access)
 {
+    size_t                    levels;
+    u_char                   *p;
     uint32_t                  n;
     ngx_err_t                 err;
+    ngx_str_t                 name;
+    ngx_uint_t                prefix;
     ngx_pool_cleanup_t       *cln;
     ngx_pool_cleanup_file_t  *clnf;
 
-    file->name.len = path->name.len + 1 + path->len + 10;
+    if (file->name.len) {
+        name = file->name;
+        levels = 0;
+        prefix = 1;
+
+    } else {
+        name = path->name;
+        levels = path->len;
+        prefix = 0;
+    }
+
+    file->name.len = name.len + 1 + levels + 10;
 
     file->name.data = ngx_pnalloc(pool, file->name.len + 1);
     if (file->name.data == NULL) {
@@ -159,7 +174,13 @@
     }
 #endif
 
-    ngx_memcpy(file->name.data, path->name.data, path->name.len);
+    p = ngx_cpymem(file->name.data, name.data, name.len);
+
+    if (prefix) {
+        *p = '.';
+    }
+
+    p += 1 + levels;
 
     n = (uint32_t) ngx_next_temp_number(0);
 
@@ -169,10 +190,11 @@
     }
 
     for ( ;; ) {
-        (void) ngx_sprintf(file->name.data + path->name.len + 1 + path->len,
-                           "%010uD%Z", n);
+        (void) ngx_sprintf(p, "%010uD%Z", n);
 
-        ngx_create_hashed_filename(path, file->name.data, file->name.len);
+        if (!prefix) {
+            ngx_create_hashed_filename(path, file->name.data, file->name.len);
+        }
 
         ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
                        "hashed path: %s", file->name.data);
diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c
index 151e643..1944c7a 100644
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -390,7 +390,6 @@
 
         buckets[i] = (ngx_hash_elt_t *) elts;
         elts += test[i];
-
     }
 
     for (i = 0; i < size; i++) {
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 3648122..9a257b5 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -2140,7 +2140,9 @@
             break;
         }
 
-        if (p >= last) {
+        /* ERR_error_string_n() requires at least one byte */
+
+        if (p >= last - 1) {
             goto next;
         }
 
@@ -3439,6 +3441,109 @@
 ngx_int_t
 ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
 {
+    BIO        *bio;
+    X509       *cert;
+    X509_NAME  *name;
+
+    s->len = 0;
+
+    cert = SSL_get_peer_certificate(c->ssl->connection);
+    if (cert == NULL) {
+        return NGX_OK;
+    }
+
+    name = X509_get_subject_name(cert);
+    if (name == NULL) {
+        return NGX_ERROR;
+    }
+
+    bio = BIO_new(BIO_s_mem());
+    if (bio == NULL) {
+        X509_free(cert);
+        return NGX_ERROR;
+    }
+
+    if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253) < 0) {
+        goto failed;
+    }
+
+    s->len = BIO_pending(bio);
+    s->data = ngx_pnalloc(pool, s->len);
+    if (s->data == NULL) {
+        goto failed;
+    }
+
+    BIO_read(bio, s->data, s->len);
+
+    BIO_free(bio);
+    X509_free(cert);
+
+    return NGX_OK;
+
+failed:
+
+    BIO_free(bio);
+    X509_free(cert);
+
+    return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+    BIO        *bio;
+    X509       *cert;
+    X509_NAME  *name;
+
+    s->len = 0;
+
+    cert = SSL_get_peer_certificate(c->ssl->connection);
+    if (cert == NULL) {
+        return NGX_OK;
+    }
+
+    name = X509_get_issuer_name(cert);
+    if (name == NULL) {
+        return NGX_ERROR;
+    }
+
+    bio = BIO_new(BIO_s_mem());
+    if (bio == NULL) {
+        X509_free(cert);
+        return NGX_ERROR;
+    }
+
+    if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253) < 0) {
+        goto failed;
+    }
+
+    s->len = BIO_pending(bio);
+    s->data = ngx_pnalloc(pool, s->len);
+    if (s->data == NULL) {
+        goto failed;
+    }
+
+    BIO_read(bio, s->data, s->len);
+
+    BIO_free(bio);
+    X509_free(cert);
+
+    return NGX_OK;
+
+failed:
+
+    BIO_free(bio);
+    X509_free(cert);
+
+    return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_ssl_get_subject_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s)
+{
     char       *p;
     size_t      len;
     X509       *cert;
@@ -3479,7 +3584,8 @@
 
 
 ngx_int_t
-ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+ngx_ssl_get_issuer_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s)
 {
     char       *p;
     size_t      len;
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index 24b812f..d233c02 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -205,6 +205,10 @@
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
+ngx_int_t ngx_ssl_get_subject_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s);
+ngx_int_t ngx_ssl_get_issuer_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s);
 ngx_int_t ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_fingerprint(ngx_connection_t *c, ngx_pool_t *pool,
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index 4320779..ba3fa40 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -421,6 +421,13 @@
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_min_uses),
       NULL },
 
+    { ngx_string("fastcgi_cache_max_range_offset"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_off_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_max_range_offset),
+      NULL },
+
     { ngx_string("fastcgi_cache_use_stale"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_conf_set_bitmask_slot,
@@ -767,16 +774,14 @@
         return NGX_ERROR;
     }
 
-    if (url.addrs && url.addrs[0].sockaddr) {
+    if (url.addrs) {
         u->resolved->sockaddr = url.addrs[0].sockaddr;
         u->resolved->socklen = url.addrs[0].socklen;
+        u->resolved->name = url.addrs[0].name;
         u->resolved->naddrs = 1;
-        u->resolved->host = url.addrs[0].name;
-
-    } else {
-        u->resolved->host = url.host;
     }
 
+    u->resolved->host = url.host;
     u->resolved->port = url.port;
     u->resolved->no_port = url.no_port;
 
@@ -2757,6 +2762,7 @@
 #if (NGX_HTTP_CACHE)
     conf->upstream.cache = NGX_CONF_UNSET;
     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
+    conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
@@ -3002,6 +3008,10 @@
     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
                               prev->upstream.cache_min_uses, 1);
 
+    ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
+                              prev->upstream.cache_max_range_offset,
+                              NGX_MAX_OFF_T_VALUE);
+
     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
                               prev->upstream.cache_use_stale,
                               (NGX_CONF_BITMASK_SET
@@ -3128,6 +3138,20 @@
 
 #endif
 
+    /*
+     * special handling to preserve conf->params in the "http" section
+     * to inherit it to all servers
+     */
+
+    if (prev->params.hash.buckets == NULL
+        && conf->params_source == prev->params_source)
+    {
+        prev->params = conf->params;
+#if (NGX_HTTP_CACHE)
+        prev->params_cache = conf->params_cache;
+#endif
+    }
+
     return NGX_CONF_OK;
 }
 
diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c
index b608de1..dbec5d8 100644
--- a/src/http/modules/ngx_http_image_filter_module.c
+++ b/src/http/modules/ngx_http_image_filter_module.c
@@ -31,6 +31,7 @@
 #define NGX_HTTP_IMAGE_JPEG      1
 #define NGX_HTTP_IMAGE_GIF       2
 #define NGX_HTTP_IMAGE_PNG       3
+#define NGX_HTTP_IMAGE_WEBP      4
 
 
 #define NGX_HTTP_IMAGE_BUFFERED  0x08
@@ -42,6 +43,7 @@
     ngx_uint_t                   height;
     ngx_uint_t                   angle;
     ngx_uint_t                   jpeg_quality;
+    ngx_uint_t                   webp_quality;
     ngx_uint_t                   sharpen;
 
     ngx_flag_t                   transparency;
@@ -51,6 +53,7 @@
     ngx_http_complex_value_t    *hcv;
     ngx_http_complex_value_t    *acv;
     ngx_http_complex_value_t    *jqcv;
+    ngx_http_complex_value_t    *wqcv;
     ngx_http_complex_value_t    *shcv;
 
     size_t                       buffer_size;
@@ -109,6 +112,8 @@
     void *conf);
 static char *ngx_http_image_filter_jpeg_quality(ngx_conf_t *cf,
     ngx_command_t *cmd, void *conf);
+static char *ngx_http_image_filter_webp_quality(ngx_conf_t *cf,
+    ngx_command_t *cmd, void *conf);
 static char *ngx_http_image_filter_sharpen(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 static ngx_int_t ngx_http_image_filter_init(ngx_conf_t *cf);
@@ -130,6 +135,13 @@
       0,
       NULL },
 
+    { ngx_string("image_filter_webp_quality"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_image_filter_webp_quality,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
     { ngx_string("image_filter_sharpen"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_http_image_filter_sharpen,
@@ -200,7 +212,8 @@
 static ngx_str_t  ngx_http_image_types[] = {
     ngx_string("image/jpeg"),
     ngx_string("image/gif"),
-    ngx_string("image/png")
+    ngx_string("image/png"),
+    ngx_string("image/webp")
 };
 
 
@@ -441,6 +454,13 @@
         /* PNG */
 
         return NGX_HTTP_IMAGE_PNG;
+
+    } else if (p[0] == 'R' && p[1] == 'I' && p[2] == 'F' && p[3] == 'F'
+               && p[8] == 'W' && p[9] == 'E' && p[10] == 'B' && p[11] == 'P')
+    {
+        /* WebP */
+
+        return NGX_HTTP_IMAGE_WEBP;
     }
 
     return NGX_HTTP_IMAGE_NONE;
@@ -731,6 +751,56 @@
 
         break;
 
+    case NGX_HTTP_IMAGE_WEBP:
+
+        if (ctx->length < 30) {
+            return NGX_DECLINED;
+        }
+
+        if (p[12] != 'V' || p[13] != 'P' || p[14] != '8') {
+            return NGX_DECLINED;
+        }
+
+        switch (p[15]) {
+
+        case ' ':
+            if (p[20] & 1) {
+                /* not a key frame */
+                return NGX_DECLINED;
+            }
+
+            if (p[23] != 0x9d || p[24] != 0x01 || p[25] != 0x2a) {
+                /* invalid start code */
+                return NGX_DECLINED;
+            }
+
+            width = (p[26] | p[27] << 8) & 0x3fff;
+            height = (p[28] | p[29] << 8) & 0x3fff;
+
+            break;
+
+        case 'L':
+            if (p[20] != 0x2f) {
+                /* invalid signature */
+                return NGX_DECLINED;
+            }
+
+            width = ((p[21] | p[22] << 8) & 0x3fff) + 1;
+            height = ((p[22] >> 6 | p[23] << 2 | p[24] << 10) & 0x3fff) + 1;
+
+            break;
+
+        case 'X':
+            width = (p[24] | p[25] << 8 | p[26] << 16) + 1;
+            height = (p[27] | p[28] << 8 | p[29] << 16) + 1;
+            break;
+
+        default:
+            return NGX_DECLINED;
+        }
+
+        break;
+
     default:
 
         return NGX_DECLINED;
@@ -1043,6 +1113,15 @@
         failed = "gdImageCreateFromPngPtr() failed";
         break;
 
+    case NGX_HTTP_IMAGE_WEBP:
+#if (NGX_HAVE_GD_WEBP)
+        img = gdImageCreateFromWebpPtr(ctx->length, ctx->image);
+        failed = "gdImageCreateFromWebpPtr() failed";
+#else
+        failed = "nginx was built without GD WebP support";
+#endif
+        break;
+
     default:
         failed = "unknown image type";
         break;
@@ -1090,7 +1169,7 @@
 {
     char                          *failed;
     u_char                        *out;
-    ngx_int_t                      jq;
+    ngx_int_t                      q;
     ngx_http_image_filter_conf_t  *conf;
 
     out = NULL;
@@ -1100,12 +1179,12 @@
     case NGX_HTTP_IMAGE_JPEG:
         conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
 
-        jq = ngx_http_image_filter_get_value(r, conf->jqcv, conf->jpeg_quality);
-        if (jq <= 0) {
+        q = ngx_http_image_filter_get_value(r, conf->jqcv, conf->jpeg_quality);
+        if (q <= 0) {
             return NULL;
         }
 
-        out = gdImageJpegPtr(img, size, jq);
+        out = gdImageJpegPtr(img, size, q);
         failed = "gdImageJpegPtr() failed";
         break;
 
@@ -1119,6 +1198,22 @@
         failed = "gdImagePngPtr() failed";
         break;
 
+    case NGX_HTTP_IMAGE_WEBP:
+#if (NGX_HAVE_GD_WEBP)
+        conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
+
+        q = ngx_http_image_filter_get_value(r, conf->wqcv, conf->webp_quality);
+        if (q <= 0) {
+            return NULL;
+        }
+
+        out = gdImageWebpPtrEx(img, size, q);
+        failed = "gdImageWebpPtrEx() failed";
+#else
+        failed = "nginx was built without GD WebP support";
+#endif
+        break;
+
     default:
         failed = "unknown image type";
         break;
@@ -1196,11 +1291,13 @@
      *     conf->hcv = NULL;
      *     conf->acv = NULL;
      *     conf->jqcv = NULL;
+     *     conf->wqcv = NULL;
      *     conf->shcv = NULL;
      */
 
     conf->filter = NGX_CONF_UNSET_UINT;
     conf->jpeg_quality = NGX_CONF_UNSET_UINT;
+    conf->webp_quality = NGX_CONF_UNSET_UINT;
     conf->sharpen = NGX_CONF_UNSET_UINT;
     conf->transparency = NGX_CONF_UNSET;
     conf->interlace = NGX_CONF_UNSET;
@@ -1242,6 +1339,16 @@
         }
     }
 
+    if (conf->webp_quality == NGX_CONF_UNSET_UINT) {
+
+        /* 80 is libwebp default quality */
+        ngx_conf_merge_uint_value(conf->webp_quality, prev->webp_quality, 80);
+
+        if (conf->wqcv == NULL) {
+            conf->wqcv = prev->wqcv;
+        }
+    }
+
     if (conf->sharpen == NGX_CONF_UNSET_UINT) {
         ngx_conf_merge_uint_value(conf->sharpen, prev->sharpen, 0);
 
@@ -1462,6 +1569,53 @@
 
 
 static char *
+ngx_http_image_filter_webp_quality(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf)
+{
+    ngx_http_image_filter_conf_t *imcf = conf;
+
+    ngx_str_t                         *value;
+    ngx_int_t                          n;
+    ngx_http_complex_value_t           cv;
+    ngx_http_compile_complex_value_t   ccv;
+
+    value = cf->args->elts;
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = &value[1];
+    ccv.complex_value = &cv;
+
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (cv.lengths == NULL) {
+        n = ngx_http_image_filter_value(&value[1]);
+
+        if (n <= 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid value \"%V\"", &value[1]);
+            return NGX_CONF_ERROR;
+        }
+
+        imcf->webp_quality = (ngx_uint_t) n;
+
+    } else {
+        imcf->wqcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
+        if (imcf->wqcv == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *imcf->wqcv = cv;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
 ngx_http_image_filter_sharpen(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf)
 {
diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c
index 2a68bae..8f2920f 100644
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -216,6 +216,7 @@
 
 
 static ngx_int_t ngx_http_mp4_handler(ngx_http_request_t *r);
+static ngx_int_t ngx_http_mp4_atofp(u_char *line, size_t n, size_t point);
 
 static ngx_int_t ngx_http_mp4_process(ngx_http_mp4_file_t *mp4);
 static ngx_int_t ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4,
@@ -537,26 +538,15 @@
 
             /*
              * A Flash player may send start value with a lot of digits
-             * after dot so strtod() is used instead of atofp().  NaNs and
-             * infinities become negative numbers after (int) conversion.
+             * after dot so a custom function is used instead of ngx_atofp().
              */
 
-            ngx_set_errno(0);
-            start = (int) (strtod((char *) value.data, NULL) * 1000);
-
-            if (ngx_errno != 0) {
-                start = -1;
-            }
+            start = ngx_http_mp4_atofp(value.data, value.len, 3);
         }
 
         if (ngx_http_arg(r, (u_char *) "end", 3, &value) == NGX_OK) {
 
-            ngx_set_errno(0);
-            end = (int) (strtod((char *) value.data, NULL) * 1000);
-
-            if (ngx_errno != 0) {
-                end = -1;
-            }
+            end = ngx_http_mp4_atofp(value.data, value.len, 3);
 
             if (end > 0) {
                 if (start < 0) {
@@ -687,6 +677,62 @@
 
 
 static ngx_int_t
+ngx_http_mp4_atofp(u_char *line, size_t n, size_t point)
+{
+    ngx_int_t   value, cutoff, cutlim;
+    ngx_uint_t  dot;
+
+    /* same as ngx_atofp(), but allows additional digits */
+
+    if (n == 0) {
+        return NGX_ERROR;
+    }
+
+    cutoff = NGX_MAX_INT_T_VALUE / 10;
+    cutlim = NGX_MAX_INT_T_VALUE % 10;
+
+    dot = 0;
+
+    for (value = 0; n--; line++) {
+
+        if (*line == '.') {
+            if (dot) {
+                return NGX_ERROR;
+            }
+
+            dot = 1;
+            continue;
+        }
+
+        if (*line < '0' || *line > '9') {
+            return NGX_ERROR;
+        }
+
+        if (point == 0) {
+            continue;
+        }
+
+        if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
+            return NGX_ERROR;
+        }
+
+        value = value * 10 + (*line - '0');
+        point -= dot;
+    }
+
+    while (point--) {
+        if (value > cutoff) {
+            return NGX_ERROR;
+        }
+
+        value = value * 10;
+    }
+
+    return value;
+}
+
+
+static ngx_int_t
 ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)
 {
     off_t                  start_offset, end_offset, adjustment;
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 4059d4b..0abc09b 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -73,7 +73,7 @@
     ngx_array_t                   *cookie_domains;
     ngx_array_t                   *cookie_paths;
 
-    ngx_str_t                      method;
+    ngx_http_complex_value_t      *method;
     ngx_str_t                      location;
     ngx_str_t                      url;
 
@@ -381,7 +381,7 @@
 
     { ngx_string("proxy_method"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_str_slot,
+      ngx_http_set_complex_value_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_proxy_loc_conf_t, method),
       NULL },
@@ -493,6 +493,13 @@
       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses),
       NULL },
 
+    { ngx_string("proxy_cache_max_range_offset"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_off_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_max_range_offset),
+      NULL },
+
     { ngx_string("proxy_cache_use_stale"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_conf_set_bitmask_slot,
@@ -1009,16 +1016,14 @@
         return NGX_ERROR;
     }
 
-    if (url.addrs && url.addrs[0].sockaddr) {
+    if (url.addrs) {
         u->resolved->sockaddr = url.addrs[0].sockaddr;
         u->resolved->socklen = url.addrs[0].socklen;
+        u->resolved->name = url.addrs[0].name;
         u->resolved->naddrs = 1;
-        u->resolved->host = url.addrs[0].name;
-
-    } else {
-        u->resolved->host = url.host;
     }
 
+    u->resolved->host = url.host;
     u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
     u->resolved->no_port = url.no_port;
 
@@ -1160,8 +1165,10 @@
         /* HEAD was changed to GET to cache response */
         method = u->method;
 
-    } else if (plcf->method.len) {
-        method = plcf->method;
+    } else if (plcf->method) {
+        if (ngx_http_complex_value(r, plcf->method, &method) != NGX_OK) {
+            return NGX_ERROR;
+        }
 
     } else {
         method = r->method_name;
@@ -2798,7 +2805,7 @@
      *     conf->upstream.store_values = NULL;
      *     conf->upstream.ssl_name = NULL;
      *
-     *     conf->method = { 0, NULL };
+     *     conf->method = NULL;
      *     conf->headers_source = NULL;
      *     conf->headers.lengths = NULL;
      *     conf->headers.values = NULL;
@@ -2848,6 +2855,7 @@
 #if (NGX_HTTP_CACHE)
     conf->upstream.cache = NGX_CONF_UNSET;
     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
+    conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
@@ -3109,6 +3117,10 @@
     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
                               prev->upstream.cache_min_uses, 1);
 
+    ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
+                              prev->upstream.cache_max_range_offset,
+                              NGX_MAX_OFF_T_VALUE);
+
     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
                               prev->upstream.cache_use_stale,
                               (NGX_CONF_BITMASK_SET
@@ -3159,7 +3171,9 @@
 
 #endif
 
-    ngx_conf_merge_str_value(conf->method, prev->method, "");
+    if (conf->method == NULL) {
+        conf->method = prev->method;
+    }
 
     ngx_conf_merge_value(conf->upstream.pass_request_headers,
                               prev->upstream.pass_request_headers, 1);
@@ -3358,6 +3372,20 @@
 
 #endif
 
+    /*
+     * special handling to preserve conf->headers in the "http" section
+     * to inherit it to all servers
+     */
+
+    if (prev->headers.hash.buckets == NULL
+        && conf->headers_source == prev->headers_source)
+    {
+        prev->headers = conf->headers;
+#if (NGX_HTTP_CACHE)
+        prev->headers_cache = conf->headers_cache;
+#endif
+    }
+
     return NGX_CONF_OK;
 }
 
@@ -3393,14 +3421,6 @@
         return NGX_ERROR;
     }
 
-    if (conf->headers_source == NULL) {
-        conf->headers_source = ngx_array_create(cf->pool, 4,
-                                                sizeof(ngx_keyval_t));
-        if (conf->headers_source == NULL) {
-            return NGX_ERROR;
-        }
-    }
-
     headers->lengths = ngx_array_create(cf->pool, 64, 1);
     if (headers->lengths == NULL) {
         return NGX_ERROR;
@@ -3411,15 +3431,18 @@
         return NGX_ERROR;
     }
 
-    src = conf->headers_source->elts;
-    for (i = 0; i < conf->headers_source->nelts; i++) {
+    if (conf->headers_source) {
 
-        s = ngx_array_push(&headers_merged);
-        if (s == NULL) {
-            return NGX_ERROR;
+        src = conf->headers_source->elts;
+        for (i = 0; i < conf->headers_source->nelts; i++) {
+
+            s = ngx_array_push(&headers_merged);
+            if (s == NULL) {
+                return NGX_ERROR;
+            }
+
+            *s = src[i];
         }
-
-        *s = src[i];
     }
 
     h = default_headers;
diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c
index 095ef06..951a00d 100644
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -224,12 +224,6 @@
 
     ctx->offset = r->headers_out.content_offset;
 
-    if (ngx_array_init(&ctx->ranges, r->pool, 1, sizeof(ngx_http_range_t))
-        != NGX_OK)
-    {
-        return NGX_ERROR;
-    }
-
     ranges = r->single_range ? 1 : clcf->max_ranges;
 
     switch (ngx_http_range_parse(r, ctx, ranges)) {
@@ -291,6 +285,12 @@
         }
     }
 
+    if (ngx_array_init(&ctx->ranges, r->pool, 1, sizeof(ngx_http_range_t))
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
     p = r->headers_in.range->value.data + 6;
     size = 0;
     content_length = r->headers_out.content_length_n;
diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c
index cd6359b..4d13c62 100644
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -271,6 +271,13 @@
       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_min_uses),
       NULL },
 
+    { ngx_string("scgi_cache_max_range_offset"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_off_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_max_range_offset),
+      NULL },
+
     { ngx_string("scgi_cache_use_stale"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_conf_set_bitmask_slot,
@@ -563,16 +570,14 @@
         return NGX_ERROR;
     }
 
-    if (url.addrs && url.addrs[0].sockaddr) {
+    if (url.addrs) {
         u->resolved->sockaddr = url.addrs[0].sockaddr;
         u->resolved->socklen = url.addrs[0].socklen;
+        u->resolved->name = url.addrs[0].name;
         u->resolved->naddrs = 1;
-        u->resolved->host = url.addrs[0].name;
-
-    } else {
-        u->resolved->host = url.host;
     }
 
+    u->resolved->host = url.host;
     u->resolved->port = url.port;
     u->resolved->no_port = url.no_port;
 
@@ -1207,6 +1212,7 @@
 #if (NGX_HTTP_CACHE)
     conf->upstream.cache = NGX_CONF_UNSET;
     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
+    conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
@@ -1447,6 +1453,10 @@
     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
                               prev->upstream.cache_min_uses, 1);
 
+    ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
+                              prev->upstream.cache_max_range_offset,
+                              NGX_MAX_OFF_T_VALUE);
+
     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
                               prev->upstream.cache_use_stale,
                               (NGX_CONF_BITMASK_SET
@@ -1559,6 +1569,20 @@
 
 #endif
 
+    /*
+     * special handling to preserve conf->params in the "http" section
+     * to inherit it to all servers
+     */
+
+    if (prev->params.hash.buckets == NULL
+        && conf->params_source == prev->params_source)
+    {
+        prev->params = conf->params;
+#if (NGX_HTTP_CACHE)
+        prev->params_cache = conf->params_cache;
+#endif
+    }
+
     return NGX_CONF_OK;
 }
 
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index d685ae9..e75f5d8 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -298,6 +298,12 @@
     { ngx_string("ssl_client_i_dn"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_issuer_dn, NGX_HTTP_VAR_CHANGEABLE, 0 },
 
+    { ngx_string("ssl_client_s_dn_legacy"), NULL, ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_subject_dn_legacy, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
+    { ngx_string("ssl_client_i_dn_legacy"), NULL, ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_issuer_dn_legacy, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
     { ngx_string("ssl_client_serial"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_serial_number, NGX_HTTP_VAR_CHANGEABLE, 0 },
 
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index 0cf3c1d..d7eee43 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -331,6 +331,13 @@
       offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_min_uses),
       NULL },
 
+    { ngx_string("uwsgi_cache_max_range_offset"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_off_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_max_range_offset),
+      NULL },
+
     { ngx_string("uwsgi_cache_use_stale"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_conf_set_bitmask_slot,
@@ -765,16 +772,14 @@
         return NGX_ERROR;
     }
 
-    if (url.addrs && url.addrs[0].sockaddr) {
+    if (url.addrs) {
         u->resolved->sockaddr = url.addrs[0].sockaddr;
         u->resolved->socklen = url.addrs[0].socklen;
+        u->resolved->name = url.addrs[0].name;
         u->resolved->naddrs = 1;
-        u->resolved->host = url.addrs[0].name;
-
-    } else {
-        u->resolved->host = url.host;
     }
 
+    u->resolved->host = url.host;
     u->resolved->port = url.port;
     u->resolved->no_port = url.no_port;
 
@@ -1413,6 +1418,7 @@
 #if (NGX_HTTP_CACHE)
     conf->upstream.cache = NGX_CONF_UNSET;
     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
+    conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
@@ -1661,6 +1667,10 @@
     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
                               prev->upstream.cache_min_uses, 1);
 
+    ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
+                              prev->upstream.cache_max_range_offset,
+                              NGX_MAX_OFF_T_VALUE);
+
     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
                               prev->upstream.cache_use_stale,
                               (NGX_CONF_BITMASK_SET
@@ -1821,6 +1831,20 @@
 
 #endif
 
+    /*
+     * special handling to preserve conf->params in the "http" section
+     * to inherit it to all servers
+     */
+
+    if (prev->params.hash.buckets == NULL
+        && conf->params_source == prev->params_source)
+    {
+        prev->params = conf->params;
+#if (NGX_HTTP_CACHE)
+        prev->params_cache = conf->params_cache;
+#endif
+    }
+
     return NGX_CONF_OK;
 }
 
diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c
index 6a8894c..f9a9a84 100644
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -410,7 +410,7 @@
 
     args = &params[NGX_HTTP_PERL_SSI_ARG];
 
-    if (args) {
+    if (args[0]) {
 
         for (i = 0; args[i]; i++) { /* void */ }
 
diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h
index 70342d0..4075f3d 100644
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -151,7 +151,6 @@
     ngx_slab_pool_t                 *shpool;
 
     ngx_path_t                      *path;
-    ngx_path_t                      *temp_path;
 
     off_t                            max_size;
     size_t                           bsize;
@@ -171,6 +170,9 @@
     ngx_msec_t                       manager_threshold;
 
     ngx_shm_zone_t                  *shm_zone;
+
+    ngx_uint_t                       use_temp_path;
+                                     /* unsigned use_temp_path:1 */
 };
 
 
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 468d863..9f40173 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -4827,8 +4827,6 @@
                 case NGX_HTTPS_CERT_ERROR:
                 case NGX_HTTPS_NO_CERT:
                     err->overwrite = NGX_HTTP_BAD_REQUEST;
-                default:
-                    break;
             }
         }
 
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index 199a901..3c8ad7d 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -1920,17 +1920,18 @@
     ngx_http_file_cache_t  *cache = data;
 
     off_t       size;
-    time_t      next, wait;
-    ngx_msec_t  elapsed;
+    time_t      wait;
+    ngx_msec_t  elapsed, next;
     ngx_uint_t  count, watermark;
 
     cache->last = ngx_current_msec;
     cache->files = 0;
 
-    next = ngx_http_file_cache_expire(cache);
+    next = (ngx_msec_t) ngx_http_file_cache_expire(cache) * 1000;
 
     if (next == 0) {
-        return cache->manager_sleep;
+        next = cache->manager_sleep;
+        goto done;
     }
 
     for ( ;; ) {
@@ -1947,21 +1948,23 @@
                        size, count, (ngx_int_t) watermark);
 
         if (size < cache->max_size && count < watermark) {
-            return (ngx_msec_t) next * 1000;
+            break;
         }
 
         wait = ngx_http_file_cache_forced_expire(cache);
 
         if (wait > 0) {
-            return (ngx_msec_t) wait * 1000;
+            next = (ngx_msec_t) wait * 1000;
+            break;
         }
 
         if (ngx_quit || ngx_terminate) {
-            return (ngx_msec_t) next * 1000;
+            break;
         }
 
         if (++cache->files >= cache->manager_files) {
-            return cache->manager_sleep;
+            next = cache->manager_sleep;
+            break;
         }
 
         ngx_time_update();
@@ -1969,9 +1972,20 @@
         elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last));
 
         if (elapsed >= cache->manager_threshold) {
-            return cache->manager_sleep;
+            next = cache->manager_sleep;
+            break;
         }
     }
+
+done:
+
+    elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last));
+
+    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
+                   "http file cache manager: %ui e:%M n:%M",
+                   cache->files, elapsed, next);
+
+    return next;
 }
 
 
@@ -2098,6 +2112,17 @@
         return NGX_ERROR;
     }
 
+    /*
+     * Temporary files in cache have a suffix consisting of a dot
+     * followed by 10 digits.
+     */
+
+    if (name->len >= 2 * NGX_HTTP_CACHE_KEY_LEN + 1 + 10
+        && name->data[name->len - 10 - 1] == '.')
+    {
+        return NGX_OK;
+    }
+
     if (ctx->size < (off_t) sizeof(ngx_http_file_cache_header_t)) {
         ngx_log_error(NGX_LOG_CRIT, ctx->log, 0,
                       "cache file \"%s\" is too small", name->data);
@@ -2242,7 +2267,6 @@
     off_t                   max_size;
     u_char                 *last, *p;
     time_t                  inactive;
-    size_t                  len;
     ssize_t                 size;
     ngx_str_t               s, name, *value;
     ngx_int_t               loader_files, manager_files;
@@ -2515,37 +2539,6 @@
         return NGX_CONF_ERROR;
     }
 
-    if (!use_temp_path) {
-        cache->temp_path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
-        if (cache->temp_path == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        len = cache->path->name.len + sizeof("/temp") - 1;
-
-        p = ngx_pnalloc(cf->pool, len + 1);
-        if (p == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        cache->temp_path->name.len = len;
-        cache->temp_path->name.data = p;
-
-        p = ngx_cpymem(p, cache->path->name.data, cache->path->name.len);
-        ngx_memcpy(p, "/temp", sizeof("/temp"));
-
-        ngx_memcpy(&cache->temp_path->level, &cache->path->level,
-                   NGX_MAX_PATH_LEVEL * sizeof(size_t));
-
-        cache->temp_path->len = cache->path->len;
-        cache->temp_path->conf_file = cf->conf_file->file.name.data;
-        cache->temp_path->line = cf->conf_file->line;
-
-        if (ngx_add_path(cf, &cache->temp_path) != NGX_OK) {
-            return NGX_CONF_ERROR;
-        }
-    }
-
     cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post);
     if (cache->shm_zone == NULL) {
         return NGX_CONF_ERROR;
@@ -2561,6 +2554,8 @@
     cache->shm_zone->init = ngx_http_file_cache_init;
     cache->shm_zone->data = cache;
 
+    cache->use_temp_path = use_temp_path;
+
     cache->inactive = inactive;
     cache->max_size = max_size;
 
diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c
index 9794434..96d12ff 100644
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -489,7 +489,6 @@
             case NGX_HTTPS_NO_CERT:
             case NGX_HTTP_REQUEST_HEADER_TOO_LARGE:
                 r->err_status = NGX_HTTP_BAD_REQUEST;
-                break;
         }
 
     } else {
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index f21c78f..0b7c911 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -17,6 +17,8 @@
     ngx_http_upstream_t *u, ngx_http_file_cache_t **cache);
 static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r,
     ngx_http_upstream_t *u);
+static ngx_int_t ngx_http_upstream_cache_check_range(ngx_http_request_t *r,
+    ngx_http_upstream_t *u);
 static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_upstream_cache_last_modified(ngx_http_request_t *r,
@@ -655,6 +657,23 @@
 
         host = &u->resolved->host;
 
+        umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
+
+        uscfp = umcf->upstreams.elts;
+
+        for (i = 0; i < umcf->upstreams.nelts; i++) {
+
+            uscf = uscfp[i];
+
+            if (uscf->host.len == host->len
+                && ((uscf->port == 0 && u->resolved->no_port)
+                     || uscf->port == u->resolved->port)
+                && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0)
+            {
+                goto found;
+            }
+        }
+
         if (u->resolved->sockaddr) {
 
             if (u->resolved->port == 0
@@ -680,23 +699,6 @@
             return;
         }
 
-        umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
-
-        uscfp = umcf->upstreams.elts;
-
-        for (i = 0; i < umcf->upstreams.nelts; i++) {
-
-            uscf = uscfp[i];
-
-            if (uscf->host.len == host->len
-                && ((uscf->port == 0 && u->resolved->no_port)
-                     || uscf->port == u->resolved->port)
-                && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0)
-            {
-                goto found;
-            }
-        }
-
         if (u->resolved->port == 0) {
             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                           "no port in upstream \"%V\"", host);
@@ -923,6 +925,10 @@
         return rc;
     }
 
+    if (ngx_http_upstream_cache_check_range(r, u) == NGX_DECLINED) {
+        u->cacheable = 0;
+    }
+
     r->cached = 0;
 
     return NGX_DECLINED;
@@ -1024,6 +1030,55 @@
     return rc;
 }
 
+
+static ngx_int_t
+ngx_http_upstream_cache_check_range(ngx_http_request_t *r,
+    ngx_http_upstream_t *u)
+{
+    off_t             offset;
+    u_char           *p, *start;
+    ngx_table_elt_t  *h;
+
+    h = r->headers_in.range;
+
+    if (h == NULL
+        || !u->cacheable
+        || u->conf->cache_max_range_offset == NGX_MAX_OFF_T_VALUE)
+    {
+        return NGX_OK;
+    }
+
+    if (u->conf->cache_max_range_offset == 0) {
+        return NGX_DECLINED;
+    }
+
+    if (h->value.len < 7
+        || ngx_strncasecmp(h->value.data, (u_char *) "bytes=", 6) != 0)
+    {
+        return NGX_OK;
+    }
+
+    p = h->value.data + 6;
+
+    while (*p == ' ') { p++; }
+
+    if (*p == '-') {
+        return NGX_DECLINED;
+    }
+
+    start = p;
+
+    while (*p >= '0' && *p <= '9') { p++; }
+
+    offset = ngx_atoof(start, p - start);
+
+    if (offset >= u->conf->cache_max_range_offset) {
+        return NGX_DECLINED;
+    }
+
+    return NGX_OK;
+}
+
 #endif
 
 
@@ -1612,6 +1667,13 @@
         return;
     }
 
+    if (c->write->timedout) {
+        c = r->connection;
+        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
+        ngx_http_run_posted_requests(c);
+        return;
+    }
+
 failed:
 
     c = r->connection;
@@ -1697,7 +1759,8 @@
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "upstream SSL server name: \"%s\"", name.data);
 
-    if (SSL_set_tlsext_host_name(c->ssl->connection, (const char *) name.data)
+    if (SSL_set_tlsext_host_name(c->ssl->connection,
+                                 (char *) name.data)
         == 0)
     {
         ngx_ssl_error(NGX_LOG_ERR, r->connection->log, 0,
@@ -2705,6 +2768,15 @@
     u->header_sent = 1;
 
     if (u->upgrade) {
+
+#if (NGX_HTTP_CACHE)
+
+        if (r->cache) {
+            ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
+        }
+
+#endif
+
         ngx_http_upstream_upgrade(r, u);
         return;
     }
@@ -2735,6 +2807,14 @@
 
     if (!u->buffering) {
 
+#if (NGX_HTTP_CACHE)
+
+        if (r->cache) {
+            ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
+        }
+
+#endif
+
         if (u->input_filter == NULL) {
             u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
             u->input_filter = ngx_http_upstream_non_buffered_filter;
@@ -2925,8 +3005,9 @@
         p->temp_file->persistent = 1;
 
 #if (NGX_HTTP_CACHE)
-        if (r->cache && r->cache->file_cache->temp_path) {
-            p->temp_file->path = r->cache->file_cache->temp_path;
+        if (r->cache && !r->cache->file_cache->use_temp_path) {
+            p->temp_file->path = r->cache->file_cache->path;
+            p->temp_file->file.name = r->cache->file.name;
         }
 #endif
 
@@ -5765,14 +5846,9 @@
             continue;
         }
 
-        if (uscfp[i]->default_port && u->default_port
-            && uscfp[i]->default_port != u->default_port)
-        {
-            continue;
-        }
-
         if (flags & NGX_HTTP_UPSTREAM_CREATE) {
             uscfp[i]->flags = flags;
+            uscfp[i]->port = 0;
         }
 
         return uscfp[i];
@@ -5788,7 +5864,6 @@
     uscf->file_name = cf->conf_file->file.name.data;
     uscf->line = cf->conf_file->line;
     uscf->port = u->port;
-    uscf->default_port = u->default_port;
     uscf->no_port = u->no_port;
 
     if (u->naddrs == 1 && (u->port || u->family == AF_UNIX)) {
@@ -6029,12 +6104,7 @@
 
         conf->hide_headers_hash = prev->hide_headers_hash;
 
-        if (conf->hide_headers_hash.buckets
-#if (NGX_HTTP_CACHE)
-            && ((conf->cache == 0) == (prev->cache == 0))
-#endif
-           )
-        {
+        if (conf->hide_headers_hash.buckets) {
             return NGX_OK;
         }
 
@@ -6119,7 +6189,23 @@
     hash->pool = cf->pool;
     hash->temp_pool = NULL;
 
-    return ngx_hash_init(hash, hide_headers.elts, hide_headers.nelts);
+    if (ngx_hash_init(hash, hide_headers.elts, hide_headers.nelts) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    /*
+     * special handling to preserve conf->hide_headers_hash
+     * in the "http" section to inherit it to all servers
+     */
+
+    if (prev->hide_headers_hash.buckets == NULL
+        && conf->hide_headers == prev->hide_headers
+        && conf->pass_headers == prev->pass_headers)
+    {
+        prev->hide_headers_hash = conf->hide_headers_hash;
+    }
+
+    return NGX_OK;
 }
 
 
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index 5d8b432..1de5f23 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -130,7 +130,6 @@
     u_char                          *file_name;
     ngx_uint_t                       line;
     in_port_t                        port;
-    in_port_t                        default_port;
     ngx_uint_t                       no_port;  /* unsigned no_port:1 */
 
 #if (NGX_HTTP_UPSTREAM_ZONE || NGX_COMPAT)
@@ -201,6 +200,8 @@
     ngx_uint_t                       cache_use_stale;
     ngx_uint_t                       cache_methods;
 
+    off_t                            cache_max_range_offset;
+
     ngx_flag_t                       cache_lock;
     ngx_msec_t                       cache_lock_timeout;
     ngx_msec_t                       cache_lock_age;
@@ -302,6 +303,7 @@
 
     struct sockaddr                 *sockaddr;
     socklen_t                        socklen;
+    ngx_str_t                        name;
 
     ngx_resolver_ctx_t              *ctx;
 } ngx_http_upstream_resolved_t;
diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
index 6eb0bec..d4e5a6d 100644
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -337,7 +337,7 @@
     if (ur->sockaddr) {
         peer[0].sockaddr = ur->sockaddr;
         peer[0].socklen = ur->socklen;
-        peer[0].name = ur->host;
+        peer[0].name = ur->name.data ? ur->name : ur->host;
         peer[0].weight = 1;
         peer[0].effective_weight = 1;
         peer[0].current_weight = 0;
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index 235092b..8301630 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -136,6 +136,8 @@
     ngx_uint_t sid, size_t window);
 static ngx_int_t ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c,
     ngx_uint_t sid, ngx_uint_t status);
+static ngx_int_t ngx_http_v2_send_goaway(ngx_http_v2_connection_t *h2c,
+    ngx_uint_t status);
 
 static ngx_http_v2_out_frame_t *ngx_http_v2_get_frame(
     ngx_http_v2_connection_t *h2c, size_t length, ngx_uint_t type,
@@ -293,6 +295,8 @@
     rev->handler = ngx_http_v2_read_handler;
     c->write->handler = ngx_http_v2_write_handler;
 
+    c->idle = 1;
+
     ngx_http_v2_read_handler(rev);
 }
 
@@ -320,6 +324,30 @@
 
     h2c->blocked = 1;
 
+    if (c->close) {
+        c->close = 0;
+
+        if (!h2c->goaway) {
+            h2c->goaway = 1;
+
+            if (ngx_http_v2_send_goaway(h2c, NGX_HTTP_V2_NO_ERROR)
+                == NGX_ERROR)
+            {
+                ngx_http_v2_finalize_connection(h2c, 0);
+                return;
+            }
+
+            if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
+                ngx_http_v2_finalize_connection(h2c, 0);
+                return;
+            }
+        }
+
+        h2c->blocked = 0;
+
+        return;
+    }
+
     h2mcf = ngx_http_get_module_main_conf(h2c->http_connection->conf_ctx,
                                           ngx_http_v2_module);
 
@@ -633,6 +661,11 @@
         /* rc == NGX_OK */
     }
 
+    if (h2c->goaway) {
+        ngx_http_close_connection(c);
+        return;
+    }
+
     h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
                                          ngx_http_v2_module);
     if (h2c->state.incomplete) {
@@ -640,11 +673,6 @@
         return;
     }
 
-    if (ngx_terminate || ngx_exiting) {
-        ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR);
-        return;
-    }
-
     ngx_destroy_pool(h2c->pool);
 
     h2c->pool = NULL;
@@ -658,7 +686,6 @@
 #endif
 
     c->destroyed = 1;
-    c->idle = 1;
     ngx_reusable_connection(c, 1);
 
     c->write->handler = ngx_http_empty_handler;
@@ -1027,6 +1054,12 @@
         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
     }
 
+    if (h2c->goaway) {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
+                       "skipping http2 HEADERS frame");
+        return ngx_http_v2_state_skip(h2c, pos, end);
+    }
+
     if ((size_t) (end - pos) < size) {
         return ngx_http_v2_state_save(h2c, pos, end,
                                       ngx_http_v2_state_headers);
@@ -1149,6 +1182,15 @@
         ngx_http_v2_set_dependency(h2c, node, depend, excl);
     }
 
+    if (h2c->connection->requests >= h2scf->max_requests) {
+        h2c->goaway = 1;
+
+        if (ngx_http_v2_send_goaway(h2c, NGX_HTTP_V2_NO_ERROR) == NGX_ERROR) {
+            return ngx_http_v2_connection_error(h2c,
+                                                NGX_HTTP_V2_INTERNAL_ERROR);
+        }
+    }
+
     return ngx_http_v2_state_header_block(h2c, pos, end);
 
 rst_stream:
@@ -2550,7 +2592,7 @@
     ngx_http_v2_out_frame_t  *frame;
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
-                   "http2 send RST_STREAM frame sid:%ui, status:%uz",
+                   "http2 send RST_STREAM frame sid:%ui, status:%ui",
                    sid, status);
 
     frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_RST_STREAM_SIZE,
@@ -2576,8 +2618,9 @@
     ngx_buf_t                *buf;
     ngx_http_v2_out_frame_t  *frame;
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
-                   "http2 send GOAWAY frame, status:%uz", status);
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
+                   "http2 send GOAWAY frame: last sid %ui, error %ui",
+                   h2c->last_sid, status);
 
     frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_GOAWAY_SIZE,
                                   NGX_HTTP_V2_GOAWAY_FRAME,
@@ -4162,7 +4205,6 @@
 #endif
 
     c->destroyed = 0;
-    c->idle = 0;
     ngx_reusable_connection(c, 0);
 
     h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
@@ -4197,8 +4239,10 @@
 
     h2c->blocked = 1;
 
-    if (!c->error && ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) {
-        (void) ngx_http_v2_send_output_queue(h2c);
+    if (!c->error && !h2c->goaway) {
+        if (ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) {
+            (void) ngx_http_v2_send_output_queue(h2c);
+        }
     }
 
     c->error = 1;
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
index d712d38..63bbdad 100644
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -146,6 +146,7 @@
     unsigned                         closed_nodes:8;
     unsigned                         settings_ack:1;
     unsigned                         blocked:1;
+    unsigned                         goaway:1;
 };
 
 
diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c
index f63c7da..c4606e8 100644
--- a/src/http/v2/ngx_http_v2_filter_module.c
+++ b/src/http/v2/ngx_http_v2_filter_module.c
@@ -1223,6 +1223,10 @@
 ngx_http_v2_flow_control(ngx_http_v2_connection_t *h2c,
     ngx_http_v2_stream_t *stream)
 {
+    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
+                   "http2:%ui available windows: conn:%uz stream:%z",
+                   stream->node->id, h2c->send_window, stream->send_window);
+
     if (stream->send_window <= 0) {
         stream->exhausted = 1;
         return NGX_DECLINED;
diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c
index b7d99e0..032abcb 100644
--- a/src/http/v2/ngx_http_v2_module.c
+++ b/src/http/v2/ngx_http_v2_module.c
@@ -73,6 +73,13 @@
       offsetof(ngx_http_v2_srv_conf_t, concurrent_streams),
       NULL },
 
+    { 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_string("http2_max_field_size"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_size_slot,
@@ -322,6 +329,7 @@
     h2scf->pool_size = NGX_CONF_UNSET_SIZE;
 
     h2scf->concurrent_streams = 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;
@@ -347,6 +355,7 @@
 
     ngx_conf_merge_uint_value(conf->concurrent_streams,
                               prev->concurrent_streams, 128);
+    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);
diff --git a/src/http/v2/ngx_http_v2_module.h b/src/http/v2/ngx_http_v2_module.h
index 91f97c2..540f826 100644
--- a/src/http/v2/ngx_http_v2_module.h
+++ b/src/http/v2/ngx_http_v2_module.h
@@ -23,6 +23,7 @@
 typedef struct {
     size_t                          pool_size;
     ngx_uint_t                      concurrent_streams;
+    ngx_uint_t                      max_requests;
     size_t                          max_field_size;
     size_t                          max_header_size;
     size_t                          preread_size;
diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h
index c30af35..6002508 100644
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -132,7 +132,8 @@
     ngx_pop3_auth_login_username,
     ngx_pop3_auth_login_password,
     ngx_pop3_auth_plain,
-    ngx_pop3_auth_cram_md5
+    ngx_pop3_auth_cram_md5,
+    ngx_pop3_auth_external
 } ngx_pop3_state_e;
 
 
@@ -142,6 +143,7 @@
     ngx_imap_auth_login_password,
     ngx_imap_auth_plain,
     ngx_imap_auth_cram_md5,
+    ngx_imap_auth_external,
     ngx_imap_login,
     ngx_imap_user,
     ngx_imap_passwd
@@ -154,6 +156,7 @@
     ngx_smtp_auth_login_password,
     ngx_smtp_auth_plain,
     ngx_smtp_auth_cram_md5,
+    ngx_smtp_auth_external,
     ngx_smtp_helo,
     ngx_smtp_helo_xclient,
     ngx_smtp_helo_from,
@@ -285,14 +288,16 @@
 #define NGX_MAIL_AUTH_LOGIN_USERNAME    2
 #define NGX_MAIL_AUTH_APOP              3
 #define NGX_MAIL_AUTH_CRAM_MD5          4
-#define NGX_MAIL_AUTH_NONE              5
+#define NGX_MAIL_AUTH_EXTERNAL          5
+#define NGX_MAIL_AUTH_NONE              6
 
 
 #define NGX_MAIL_AUTH_PLAIN_ENABLED     0x0002
 #define NGX_MAIL_AUTH_LOGIN_ENABLED     0x0004
 #define NGX_MAIL_AUTH_APOP_ENABLED      0x0008
 #define NGX_MAIL_AUTH_CRAM_MD5_ENABLED  0x0010
-#define NGX_MAIL_AUTH_NONE_ENABLED      0x0020
+#define NGX_MAIL_AUTH_EXTERNAL_ENABLED  0x0020
+#define NGX_MAIL_AUTH_NONE_ENABLED      0x0040
 
 
 #define NGX_MAIL_PARSE_INVALID_COMMAND  20
@@ -377,6 +382,8 @@
 ngx_int_t ngx_mail_auth_cram_md5_salt(ngx_mail_session_t *s,
     ngx_connection_t *c, char *prefix, size_t len);
 ngx_int_t ngx_mail_auth_cram_md5(ngx_mail_session_t *s, ngx_connection_t *c);
+ngx_int_t ngx_mail_auth_external(ngx_mail_session_t *s, ngx_connection_t *c,
+    ngx_uint_t n);
 ngx_int_t ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c);
 
 void ngx_mail_send(ngx_event_t *wev);
diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c
index a94434a..6b57358 100644
--- a/src/mail/ngx_mail_auth_http_module.c
+++ b/src/mail/ngx_mail_auth_http_module.c
@@ -151,6 +151,7 @@
     ngx_string("plain"),
     ngx_string("apop"),
     ngx_string("cram-md5"),
+    ngx_string("external"),
     ngx_string("none")
 };
 
diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c
index 901bb8f..9d4ef56 100644
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -612,6 +612,40 @@
 }
 
 
+ngx_int_t
+ngx_mail_auth_external(ngx_mail_session_t *s, ngx_connection_t *c,
+    ngx_uint_t n)
+{
+    ngx_str_t  *arg, external;
+
+    arg = s->args.elts;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+                   "mail auth external: \"%V\"", &arg[n]);
+
+    external.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
+    if (external.data == NULL) {
+        return NGX_ERROR;
+    }
+
+    if (ngx_decode_base64(&external, &arg[n]) != NGX_OK) {
+        ngx_log_error(NGX_LOG_INFO, c->log, 0,
+            "client sent invalid base64 encoding in AUTH EXTERNAL command");
+        return NGX_MAIL_PARSE_INVALID_COMMAND;
+    }
+
+    s->login.len = external.len;
+    s->login.data = external.data;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+                   "mail auth external: \"%V\"", &s->login);
+
+    s->auth_method = NGX_MAIL_AUTH_EXTERNAL;
+
+    return NGX_DONE;
+}
+
+
 void
 ngx_mail_send(ngx_event_t *wev)
 {
diff --git a/src/mail/ngx_mail_imap_handler.c b/src/mail/ngx_mail_imap_handler.c
index 57e2fb7..1c54457 100644
--- a/src/mail/ngx_mail_imap_handler.c
+++ b/src/mail/ngx_mail_imap_handler.c
@@ -222,6 +222,10 @@
         case ngx_imap_auth_cram_md5:
             rc = ngx_mail_auth_cram_md5(s, c);
             break;
+
+        case ngx_imap_auth_external:
+            rc = ngx_mail_auth_external(s, c, 0);
+            break;
         }
 
     } else if (rc == NGX_IMAP_NEXT) {
@@ -399,6 +403,13 @@
         }
 
         return NGX_ERROR;
+
+    case NGX_MAIL_AUTH_EXTERNAL:
+
+        ngx_str_set(&s->out, imap_username);
+        s->mail_state = ngx_imap_auth_external;
+
+        return NGX_OK;
     }
 
     return rc;
diff --git a/src/mail/ngx_mail_imap_module.c b/src/mail/ngx_mail_imap_module.c
index d281070..1f187fd 100644
--- a/src/mail/ngx_mail_imap_module.c
+++ b/src/mail/ngx_mail_imap_module.c
@@ -29,6 +29,7 @@
     { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
     { ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED },
     { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
+    { ngx_string("external"), NGX_MAIL_AUTH_EXTERNAL_ENABLED },
     { ngx_null_string, 0 }
 };
 
@@ -38,6 +39,7 @@
     ngx_string("AUTH=LOGIN"),
     ngx_null_string,  /* APOP */
     ngx_string("AUTH=CRAM-MD5"),
+    ngx_string("AUTH=EXTERNAL"),
     ngx_null_string   /* NONE */
 };
 
@@ -179,7 +181,7 @@
     }
 
     for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
-         m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
+         m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
          m <<= 1, i++)
     {
         if (m & conf->auth_methods) {
@@ -205,7 +207,7 @@
     auth = p;
 
     for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
-         m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
+         m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
          m <<= 1, i++)
     {
         if (m & conf->auth_methods) {
diff --git a/src/mail/ngx_mail_parse.c b/src/mail/ngx_mail_parse.c
index b158f5a..2c2cdff 100644
--- a/src/mail/ngx_mail_parse.c
+++ b/src/mail/ngx_mail_parse.c
@@ -905,13 +905,27 @@
 
     if (arg[0].len == 8) {
 
-        if (s->args.nelts != 1) {
-            return NGX_MAIL_PARSE_INVALID_COMMAND;
-        }
-
         if (ngx_strncasecmp(arg[0].data, (u_char *) "CRAM-MD5", 8) == 0) {
+
+            if (s->args.nelts != 1) {
+                return NGX_MAIL_PARSE_INVALID_COMMAND;
+            }
+
             return NGX_MAIL_AUTH_CRAM_MD5;
         }
+
+        if (ngx_strncasecmp(arg[0].data, (u_char *) "EXTERNAL", 8) == 0) {
+
+            if (s->args.nelts == 1) {
+                return NGX_MAIL_AUTH_EXTERNAL;
+            }
+
+            if (s->args.nelts == 2) {
+                return ngx_mail_auth_external(s, c, 1);
+            }
+        }
+
+        return NGX_MAIL_PARSE_INVALID_COMMAND;
     }
 
     return NGX_MAIL_PARSE_INVALID_COMMAND;
diff --git a/src/mail/ngx_mail_pop3_handler.c b/src/mail/ngx_mail_pop3_handler.c
index 51bc257..a2d5658 100644
--- a/src/mail/ngx_mail_pop3_handler.c
+++ b/src/mail/ngx_mail_pop3_handler.c
@@ -240,6 +240,10 @@
         case ngx_pop3_auth_cram_md5:
             rc = ngx_mail_auth_cram_md5(s, c);
             break;
+
+        case ngx_pop3_auth_external:
+            rc = ngx_mail_auth_external(s, c, 0);
+            break;
         }
     }
 
@@ -494,6 +498,13 @@
         }
 
         return NGX_ERROR;
+
+    case NGX_MAIL_AUTH_EXTERNAL:
+
+        ngx_str_set(&s->out, pop3_username);
+        s->mail_state = ngx_pop3_auth_external;
+
+        return NGX_OK;
     }
 
     return rc;
diff --git a/src/mail/ngx_mail_pop3_module.c b/src/mail/ngx_mail_pop3_module.c
index 73f8531..bd60e0a 100644
--- a/src/mail/ngx_mail_pop3_module.c
+++ b/src/mail/ngx_mail_pop3_module.c
@@ -29,23 +29,19 @@
     { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
     { ngx_string("apop"), NGX_MAIL_AUTH_APOP_ENABLED },
     { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
+    { ngx_string("external"), NGX_MAIL_AUTH_EXTERNAL_ENABLED },
     { ngx_null_string, 0 }
 };
 
 
-static ngx_str_t  ngx_mail_pop3_auth_plain_capability =
-    ngx_string("+OK methods supported:" CRLF
-               "LOGIN" CRLF
-               "PLAIN" CRLF
-               "." CRLF);
-
-
-static ngx_str_t  ngx_mail_pop3_auth_cram_md5_capability =
-    ngx_string("+OK methods supported:" CRLF
-               "LOGIN" CRLF
-               "PLAIN" CRLF
-               "CRAM-MD5" CRLF
-               "." CRLF);
+static ngx_str_t  ngx_mail_pop3_auth_methods_names[] = {
+    ngx_string("PLAIN"),
+    ngx_string("LOGIN"),
+    ngx_null_string,  /* APOP */
+    ngx_string("CRAM-MD5"),
+    ngx_string("EXTERNAL"),
+    ngx_null_string   /* NONE */
+};
 
 
 static ngx_mail_protocol_t  ngx_mail_pop3_protocol = {
@@ -140,13 +136,17 @@
     u_char      *p;
     size_t       size, stls_only_size;
     ngx_str_t   *c, *d;
-    ngx_uint_t   i;
+    ngx_uint_t   i, m;
 
     ngx_conf_merge_bitmask_value(conf->auth_methods,
                                  prev->auth_methods,
                                  (NGX_CONF_BITMASK_SET
                                   |NGX_MAIL_AUTH_PLAIN_ENABLED));
 
+    if (conf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED) {
+        conf->auth_methods |= NGX_MAIL_AUTH_LOGIN_ENABLED;
+    }
+
     if (conf->capabilities.nelts == 0) {
         conf->capabilities = prev->capabilities;
     }
@@ -179,11 +179,15 @@
         stls_only_size += c[i].len + sizeof(CRLF) - 1;
     }
 
-    if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
-        size += sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1;
+    size += sizeof("SASL") - 1 + sizeof(CRLF) - 1;
 
-    } else {
-        size += sizeof("SASL LOGIN PLAIN" CRLF) - 1;
+    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+         m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
+         m <<= 1, i++)
+    {
+        if (m & conf->auth_methods) {
+            size += 1 + ngx_mail_pop3_auth_methods_names[i].len;
+        }
     }
 
     p = ngx_pnalloc(cf->pool, size);
@@ -202,15 +206,21 @@
         *p++ = CR; *p++ = LF;
     }
 
-    if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
-        p = ngx_cpymem(p, "SASL LOGIN PLAIN CRAM-MD5" CRLF,
-                       sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1);
+    p = ngx_cpymem(p, "SASL", sizeof("SASL") - 1);
 
-    } else {
-        p = ngx_cpymem(p, "SASL LOGIN PLAIN" CRLF,
-                       sizeof("SASL LOGIN PLAIN" CRLF) - 1);
+    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+         m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
+         m <<= 1, i++)
+    {
+        if (m & conf->auth_methods) {
+            *p++ = ' ';
+            p = ngx_cpymem(p, ngx_mail_pop3_auth_methods_names[i].data,
+                           ngx_mail_pop3_auth_methods_names[i].len);
+        }
     }
 
+    *p++ = CR; *p++ = LF;
+
     *p++ = '.'; *p++ = CR; *p = LF;
 
 
@@ -231,13 +241,43 @@
     *p++ = '.'; *p++ = CR; *p = LF;
 
 
-    if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
-        conf->auth_capability = ngx_mail_pop3_auth_cram_md5_capability;
+    size = sizeof("+OK methods supported:" CRLF) - 1
+           + sizeof("." CRLF) - 1;
 
-    } else {
-        conf->auth_capability = ngx_mail_pop3_auth_plain_capability;
+    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+         m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
+         m <<= 1, i++)
+    {
+        if (m & conf->auth_methods) {
+            size += ngx_mail_pop3_auth_methods_names[i].len
+                    + sizeof(CRLF) - 1;
+        }
     }
 
+    p = ngx_pnalloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->auth_capability.data = p;
+    conf->auth_capability.len = size;
+
+    p = ngx_cpymem(p, "+OK methods supported:" CRLF,
+                   sizeof("+OK methods supported:" CRLF) - 1);
+
+    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+         m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
+         m <<= 1, i++)
+    {
+        if (m & conf->auth_methods) {
+            p = ngx_cpymem(p, ngx_mail_pop3_auth_methods_names[i].data,
+                           ngx_mail_pop3_auth_methods_names[i].len);
+            *p++ = CR; *p++ = LF;
+        }
+    }
+
+    *p++ = '.'; *p++ = CR; *p = LF;
+
 
     p = ngx_pnalloc(cf->pool, stls_only_size);
     if (p == NULL) {
diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c
index 81cc75f..47756c3 100644
--- a/src/mail/ngx_mail_smtp_handler.c
+++ b/src/mail/ngx_mail_smtp_handler.c
@@ -485,6 +485,10 @@
         case ngx_smtp_auth_cram_md5:
             rc = ngx_mail_auth_cram_md5(s, c);
             break;
+
+        case ngx_smtp_auth_external:
+            rc = ngx_mail_auth_external(s, c, 0);
+            break;
         }
     }
 
@@ -652,6 +656,13 @@
         }
 
         return NGX_ERROR;
+
+    case NGX_MAIL_AUTH_EXTERNAL:
+
+        ngx_str_set(&s->out, smtp_username);
+        s->mail_state = ngx_smtp_auth_external;
+
+        return NGX_OK;
     }
 
     return rc;
diff --git a/src/mail/ngx_mail_smtp_module.c b/src/mail/ngx_mail_smtp_module.c
index d5bb51c..f03bd90 100644
--- a/src/mail/ngx_mail_smtp_module.c
+++ b/src/mail/ngx_mail_smtp_module.c
@@ -21,6 +21,7 @@
     { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
     { ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED },
     { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
+    { ngx_string("external"), NGX_MAIL_AUTH_EXTERNAL_ENABLED },
     { ngx_string("none"), NGX_MAIL_AUTH_NONE_ENABLED },
     { ngx_null_string, 0 }
 };
@@ -31,6 +32,7 @@
     ngx_string("LOGIN"),
     ngx_null_string,  /* APOP */
     ngx_string("CRAM-MD5"),
+    ngx_string("EXTERNAL"),
     ngx_null_string   /* NONE */
 };
 
@@ -207,7 +209,7 @@
     auth_enabled = 0;
 
     for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
-         m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
+         m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
          m <<= 1, i++)
     {
         if (m & conf->auth_methods) {
@@ -250,7 +252,7 @@
         *p++ = 'A'; *p++ = 'U'; *p++ = 'T'; *p++ = 'H';
 
         for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
-             m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
+             m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
              m <<= 1, i++)
         {
             if (m & conf->auth_methods) {
diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c
index 4212e4a..c03b515 100644
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -433,6 +433,23 @@
 
         host = &u->resolved->host;
 
+        umcf = ngx_stream_get_module_main_conf(s, ngx_stream_upstream_module);
+
+        uscfp = umcf->upstreams.elts;
+
+        for (i = 0; i < umcf->upstreams.nelts; i++) {
+
+            uscf = uscfp[i];
+
+            if (uscf->host.len == host->len
+                && ((uscf->port == 0 && u->resolved->no_port)
+                     || uscf->port == u->resolved->port)
+                && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0)
+            {
+                goto found;
+            }
+        }
+
         if (u->resolved->sockaddr) {
 
             if (u->resolved->port == 0
@@ -456,23 +473,6 @@
             return;
         }
 
-        umcf = ngx_stream_get_module_main_conf(s, ngx_stream_upstream_module);
-
-        uscfp = umcf->upstreams.elts;
-
-        for (i = 0; i < umcf->upstreams.nelts; i++) {
-
-            uscf = uscfp[i];
-
-            if (uscf->host.len == host->len
-                && ((uscf->port == 0 && u->resolved->no_port)
-                     || uscf->port == u->resolved->port)
-                && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0)
-            {
-                goto found;
-            }
-        }
-
         if (u->resolved->port == 0) {
             ngx_log_error(NGX_LOG_ERR, c->log, 0,
                           "no port in upstream \"%V\"", host);
@@ -578,16 +578,14 @@
         return NGX_ERROR;
     }
 
-    if (url.addrs && url.addrs[0].sockaddr) {
+    if (url.addrs) {
         u->resolved->sockaddr = url.addrs[0].sockaddr;
         u->resolved->socklen = url.addrs[0].socklen;
+        u->resolved->name = url.addrs[0].name;
         u->resolved->naddrs = 1;
-        u->resolved->host = url.addrs[0].name;
-
-    } else {
-        u->resolved->host = url.host;
     }
 
+    u->resolved->host = url.host;
     u->resolved->port = url.port;
     u->resolved->no_port = url.no_port;
 
@@ -1184,7 +1182,7 @@
                    "upstream SSL server name: \"%s\"", name.data);
 
     if (SSL_set_tlsext_host_name(u->peer.connection->ssl->connection,
-                                 (const char *) name.data)
+                                 (char *) name.data)
         == 0)
     {
         ngx_ssl_error(NGX_LOG_ERR, s->connection->log, 0,
diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h
index fb9fe82..7a36775 100644
--- a/src/stream/ngx_stream_upstream.h
+++ b/src/stream/ngx_stream_upstream.h
@@ -105,6 +105,7 @@
 
     struct sockaddr                   *sockaddr;
     socklen_t                          socklen;
+    ngx_str_t                          name;
 
     ngx_resolver_ctx_t                *ctx;
 } ngx_stream_upstream_resolved_t;
diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c
index f2239a7..a4d539d 100644
--- a/src/stream/ngx_stream_upstream_round_robin.c
+++ b/src/stream/ngx_stream_upstream_round_robin.c
@@ -344,7 +344,7 @@
     if (ur->sockaddr) {
         peer[0].sockaddr = ur->sockaddr;
         peer[0].socklen = ur->socklen;
-        peer[0].name = ur->host;
+        peer[0].name = ur->name;
         peer[0].weight = 1;
         peer[0].effective_weight = 1;
         peer[0].current_weight = 0;