Merge branch 'nginx' (nginx-1.17.9).

Change-Id: Idf8e5a2c793adb565b26c5b113327a3fdcb7f0ae
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index 44ef2f1..c9a99e0 100644
--- a/.hgtags
+++ b/.hgtags
@@ -447,3 +447,4 @@
 de68d0d94320cbf033599c6f3ca37e5335c67fd7 release-1.17.6
 e56295fe0ea76bf53b06bffa77a2d3a9a335cb8c release-1.17.7
 fdacd273711ddf20f778c1fb91529ab53979a454 release-1.17.8
+5e8d52bca714d4b85284ddb649d1ba4a3ca978a8 release-1.17.9
diff --git a/BUILD b/BUILD
index b72c379..2723306 100644
--- a/BUILD
+++ b/BUILD
@@ -1520,5 +1520,5 @@
     preinst = "@nginx_pkgoss//:debian_preinst",
     prerm = "@nginx_pkgoss//:debian_prerm",
     section = "httpd",
-    version = "1.17.8",
+    version = "1.17.9",
 )
diff --git a/build.bzl b/build.bzl
index aed616e..ec52740 100644
--- a/build.bzl
+++ b/build.bzl
@@ -673,9 +673,9 @@
         name = "nginx_pkgoss",
         build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) +
                              _PKGOSS_BUILD_FILE_TAIL,
-        commit = "8c658c22ad1b25f46ae166fb02a17fa18bb080eb",  # nginx-1.17.8
+        commit = "30e01364d235891447d90fa9b28352118f0f1114",  # nginx-1.17.9
         remote = "https://nginx.googlesource.com/nginx-pkgoss",
-        shallow_since = "1579613828 +0300",
+        shallow_since = "1583256764 +0300",
     )
 
 def nginx_repositories_zlib(bind):
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 0bf680c..818b983 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,82 @@
 <change_log title="nginx">
 
 
+<changes ver="1.17.9" date="2020-03-03">
+
+<change type="change">
+<para lang="ru">
+теперь nginx не разрешает
+несколько строк "Host" в заголовке запроса.
+</para>
+<para lang="en">
+now nginx does not allow
+several "Host" request header lines.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+nginx игнорировал дополнительные
+строки "Transfer-Encoding" в заголовке запроса.
+</para>
+<para lang="en">
+nginx ignored additional
+"Transfer-Encoding" request header lines.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+утечки сокетов при использовании HTTP/2.
+</para>
+<para lang="en">
+socket leak when using HTTP/2.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в рабочем процессе мог произойти segmentation fault,
+если использовался OCSP stapling.
+</para>
+<para lang="en">
+a segmentation fault might occur in a worker process
+if OCSP stapling was used.
+</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">
+при перенаправлении ошибок с кодом 494 с помощью директивы error_page
+nginx возвращал ответ с кодом 494 вместо 400.
+</para>
+<para lang="en">
+nginx used status code 494 instead of 400
+if errors with code 494 were redirected with the "error_page" directive.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+утечки сокетов при использовании подзапросов в модуле njs и директивы aio.
+</para>
+<para lang="en">
+socket leak when using subrequests in the njs module and the "aio" directive.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="1.17.8" date="2020-01-21">
 
 <change type="feature">
diff --git a/misc/GNUmakefile b/misc/GNUmakefile
index 6938fe9..0055730 100644
--- a/misc/GNUmakefile
+++ b/misc/GNUmakefile
@@ -8,7 +8,7 @@
 OBJS =		objs.msvc8
 OPENSSL =	openssl-1.1.1d
 ZLIB =		zlib-1.2.11
-PCRE =		pcre-8.43
+PCRE =		pcre-8.44
 
 
 release: export
diff --git a/src/core/nginx.h b/src/core/nginx.h
index c539c38..656d5c1 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
 #define NGINX_NAME         "nginx"
 #endif
 
-#define nginx_version      1017008
-#define NGINX_VERSION      "1.17.8"
+#define nginx_version      1017009
+#define NGINX_VERSION      "1.17.9"
 #define NGINX_VER          NGINX_NAME "/" NGINX_VERSION
 
 #ifdef NGX_BUILD
diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c
index 618bf78..c1006ab 100644
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -3116,6 +3116,13 @@
                        "chunk samples sizes:%uL",
                        trak->start_chunk_samples_size);
 
+        if (trak->start_chunk_samples_size > (uint64_t) mp4->end) {
+            ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+                          "too large mp4 start samples size in \"%s\"",
+                          mp4->file.name.data);
+            return NGX_ERROR;
+        }
+
         if (mp4->length) {
             if (trak->end_sample - trak->start_sample > entries) {
                 ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
@@ -3135,6 +3142,13 @@
             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
                            "mp4 stsz end_chunk_samples_size:%uL",
                            trak->end_chunk_samples_size);
+
+            if (trak->end_chunk_samples_size > (uint64_t) mp4->end) {
+                ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+                              "too large mp4 end samples size in \"%s\"",
+                              mp4->file.name.data);
+                return NGX_ERROR;
+            }
         }
 
         atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos);
@@ -3226,6 +3240,7 @@
 {
     size_t                atom_size;
     uint32_t              entries;
+    uint64_t              chunk_offset, samples_size;
     ngx_buf_t            *atom, *data;
     ngx_mp4_stco_atom_t  *stco_atom;
 
@@ -3256,8 +3271,19 @@
 
     data->pos += trak->start_chunk * sizeof(uint32_t);
 
-    trak->start_offset = ngx_mp4_get_32value(data->pos);
-    trak->start_offset += trak->start_chunk_samples_size;
+    chunk_offset = ngx_mp4_get_32value(data->pos);
+    samples_size = trak->start_chunk_samples_size;
+
+    if (chunk_offset > (uint64_t) mp4->end - samples_size
+        || chunk_offset + samples_size > NGX_MAX_UINT32_VALUE)
+    {
+        ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+                      "too large chunk offset in \"%s\"",
+                      mp4->file.name.data);
+        return NGX_ERROR;
+    }
+
+    trak->start_offset = chunk_offset + samples_size;
     ngx_mp4_set_32value(data->pos, trak->start_offset);
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
@@ -3276,9 +3302,19 @@
         data->last = data->pos + entries * sizeof(uint32_t);
 
         if (entries) {
-            trak->end_offset =
-                            ngx_mp4_get_32value(data->last - sizeof(uint32_t));
-            trak->end_offset += trak->end_chunk_samples_size;
+            chunk_offset = ngx_mp4_get_32value(data->last - sizeof(uint32_t));
+            samples_size = trak->end_chunk_samples_size;
+
+            if (chunk_offset > (uint64_t) mp4->end - samples_size
+                || chunk_offset + samples_size > NGX_MAX_UINT32_VALUE)
+            {
+                ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+                              "too large chunk offset in \"%s\"",
+                              mp4->file.name.data);
+                return NGX_ERROR;
+            }
+
+            trak->end_offset = chunk_offset + samples_size;
 
             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
                            "end chunk offset:%O", trak->end_offset);
@@ -3409,7 +3445,7 @@
     ngx_http_mp4_trak_t *trak)
 {
     size_t                atom_size;
-    uint64_t              entries;
+    uint64_t              entries, chunk_offset, samples_size;
     ngx_buf_t            *atom, *data;
     ngx_mp4_co64_atom_t  *co64_atom;
 
@@ -3440,8 +3476,17 @@
 
     data->pos += trak->start_chunk * sizeof(uint64_t);
 
-    trak->start_offset = ngx_mp4_get_64value(data->pos);
-    trak->start_offset += trak->start_chunk_samples_size;
+    chunk_offset = ngx_mp4_get_64value(data->pos);
+    samples_size = trak->start_chunk_samples_size;
+
+    if (chunk_offset > (uint64_t) mp4->end - samples_size) {
+        ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+                      "too large chunk offset in \"%s\"",
+                      mp4->file.name.data);
+        return NGX_ERROR;
+    }
+
+    trak->start_offset = chunk_offset + samples_size;
     ngx_mp4_set_64value(data->pos, trak->start_offset);
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
@@ -3460,9 +3505,17 @@
         data->last = data->pos + entries * sizeof(uint64_t);
 
         if (entries) {
-            trak->end_offset =
-                            ngx_mp4_get_64value(data->last - sizeof(uint64_t));
-            trak->end_offset += trak->end_chunk_samples_size;
+            chunk_offset = ngx_mp4_get_64value(data->last - sizeof(uint64_t));
+            samples_size = trak->end_chunk_samples_size;
+
+            if (chunk_offset > (uint64_t) mp4->end - samples_size) {
+                ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+                              "too large chunk offset in \"%s\"",
+                              mp4->file.name.data);
+                return NGX_ERROR;
+            }
+
+            trak->end_offset = chunk_offset + samples_size;
 
             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
                            "end chunk offset:%O", trak->end_offset);
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index cb3e531..d4f7b9d 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -2667,43 +2667,41 @@
     u_char *xff, size_t xfflen, ngx_array_t *proxies, int recursive)
 {
     u_char      *p;
-    ngx_int_t    rc;
     ngx_addr_t   paddr;
+    ngx_uint_t   found;
 
-    if (ngx_cidr_match(addr->sockaddr, proxies) != NGX_OK) {
-        return NGX_DECLINED;
-    }
+    found = 0;
 
-    for (p = xff + xfflen - 1; p > xff; p--, xfflen--) {
-        if (*p != ' ' && *p != ',') {
-            break;
-        }
-    }
+    do {
 
-    for ( /* void */ ; p > xff; p--) {
-        if (*p == ' ' || *p == ',') {
-            p++;
-            break;
-        }
-    }
-
-    if (ngx_parse_addr_port(r->pool, &paddr, p, xfflen - (p - xff)) != NGX_OK) {
-        return NGX_DECLINED;
-    }
-
-    *addr = paddr;
-
-    if (recursive && p > xff) {
-        rc = ngx_http_get_forwarded_addr_internal(r, addr, xff, p - 1 - xff,
-                                                  proxies, 1);
-
-        if (rc == NGX_DECLINED) {
-            return NGX_DONE;
+        if (ngx_cidr_match(addr->sockaddr, proxies) != NGX_OK) {
+            return found ? NGX_DONE : NGX_DECLINED;
         }
 
-        /* rc == NGX_OK || rc == NGX_DONE  */
-        return rc;
-    }
+        for (p = xff + xfflen - 1; p > xff; p--, xfflen--) {
+            if (*p != ' ' && *p != ',') {
+                break;
+            }
+        }
+
+        for ( /* void */ ; p > xff; p--) {
+            if (*p == ' ' || *p == ',') {
+                p++;
+                break;
+            }
+        }
+
+        if (ngx_parse_addr_port(r->pool, &paddr, p, xfflen - (p - xff))
+            != NGX_OK)
+        {
+            return found ? NGX_DONE : NGX_DECLINED;
+        }
+
+        *addr = paddr;
+        found = 1;
+        xfflen = p - 1 - xff;
+
+    } while (recursive && p > xff);
 
     return NGX_OK;
 }
@@ -4689,6 +4687,7 @@
                 case NGX_HTTP_TO_HTTPS:
                 case NGX_HTTPS_CERT_ERROR:
                 case NGX_HTTPS_NO_CERT:
+                case NGX_HTTP_REQUEST_HEADER_TOO_LARGE:
                     err->overwrite = NGX_HTTP_BAD_REQUEST;
             }
         }
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 51618c2..f6ed394 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -131,7 +131,7 @@
 
     { ngx_string("Transfer-Encoding"),
                  offsetof(ngx_http_headers_in_t, transfer_encoding),
-                 ngx_http_process_header_line },
+                 ngx_http_process_unique_header_line },
 
     { ngx_string("TE"),
                  offsetof(ngx_http_headers_in_t, te),
@@ -748,6 +748,8 @@
                 return;
             }
 
+            ngx_reusable_connection(c, 0);
+
             rc = ngx_ssl_handshake(c);
 
             if (rc == NGX_AGAIN) {
@@ -756,8 +758,6 @@
                     ngx_add_timer(rev, c->listening->post_accept_timeout);
                 }
 
-                ngx_reusable_connection(c, 0);
-
                 c->ssl->handler = ngx_http_ssl_handshake_handler;
                 return;
             }
@@ -1910,10 +1910,18 @@
     ngx_int_t  rc;
     ngx_str_t  host;
 
-    if (r->headers_in.host == NULL) {
-        r->headers_in.host = h;
+    if (r->headers_in.host) {
+        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+                      "client sent duplicate host header: \"%V: %V\", "
+                      "previous value: \"%V: %V\"",
+                      &h->key, &h->value, &r->headers_in.host->key,
+                      &r->headers_in.host->value);
+        ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+        return NGX_ERROR;
     }
 
+    r->headers_in.host = h;
+
     host = h->value;
 
     rc = ngx_http_validate_host(&host, r->pool, 0);
@@ -2123,10 +2131,7 @@
             r->headers_in.content_length_n = -1;
             r->headers_in.chunked = 1;
 
-        } else if (r->headers_in.transfer_encoding->value.len != 8
-            || ngx_strncasecmp(r->headers_in.transfer_encoding->value.data,
-                               (u_char *) "identity", 8) != 0)
-        {
+        } else {
             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                           "client sent unknown \"Transfer-Encoding\": \"%V\"",
                           &r->headers_in.transfer_encoding->value);
@@ -2654,26 +2659,6 @@
     }
 
     if (r != r->main) {
-        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
-        if (r->background) {
-            if (!r->logged) {
-                if (clcf->log_subrequest) {
-                    ngx_http_log_request(r);
-                }
-
-                r->logged = 1;
-
-            } else {
-                ngx_log_error(NGX_LOG_ALERT, c->log, 0,
-                              "subrequest: \"%V?%V\" logged again",
-                              &r->uri, &r->args);
-            }
-
-            r->done = 1;
-            ngx_http_finalize_connection(r);
-            return;
-        }
 
         if (r->buffered || r->postponed) {
 
@@ -2686,11 +2671,12 @@
 
         pr = r->parent;
 
-        if (r == c->data) {
-
-            r->main->count--;
+        if (r == c->data || r->background) {
 
             if (!r->logged) {
+
+                clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
                 if (clcf->log_subrequest) {
                     ngx_http_log_request(r);
                 }
@@ -2705,6 +2691,13 @@
 
             r->done = 1;
 
+            if (r->background) {
+                ngx_http_finalize_connection(r);
+                return;
+            }
+
+            r->main->count--;
+
             if (pr->postponed && pr->postponed->request == r) {
                 pr->postponed = pr->postponed->next;
             }
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index f677e8e..b07d5b9 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -1720,8 +1720,13 @@
     ngx_http_v2_stream_t  *stream;
 
     if (h2c->state.length) {
-        h2c->state.handler = ngx_http_v2_state_header_block;
-        return pos;
+        if (end - pos > 0) {
+            h2c->state.handler = ngx_http_v2_state_header_block;
+            return pos;
+        }
+
+        return ngx_http_v2_state_headers_save(h2c, pos, end,
+                                              ngx_http_v2_state_header_block);
     }
 
     if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)) {