Merge branch 'nginx' (nginx-1.17.4).

Change-Id: Ieb1e8b9a7e6d883c7a15fbe2868093a07691f17a
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index ec85611..19ec901 100644
--- a/.hgtags
+++ b/.hgtags
@@ -442,3 +442,4 @@
 7816bd7dabf6ee86c53c073b90a7143161546e06 release-1.17.1
 2fc9f853a6b7cd29dc84e0af2ed3cf78e0da6ca8 release-1.17.2
 ed4303aa1b31a9aad5440640c0840d9d0af45fed release-1.17.3
+ce2ced3856909f36f8130c99eaa4dbdbae636ddc release-1.17.4
diff --git a/BUILD b/BUILD
index 10b0b42..bfe49ee 100644
--- a/BUILD
+++ b/BUILD
@@ -1520,5 +1520,5 @@
     preinst = "@nginx_pkgoss//:debian_preinst",
     prerm = "@nginx_pkgoss//:debian_prerm",
     section = "httpd",
-    version = "1.17.3",
+    version = "1.17.4",
 )
diff --git a/build.bzl b/build.bzl
index 76b5029..662cfa4 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 = "f1d1a9fbc78c37a28de92df4e4cbed9268aa7304",  # nginx-1.17.3
+        commit = "b111e7858767a7f112093e752eba1a27a69bf778",  # nginx-1.17.4
         remote = "https://nginx.googlesource.com/nginx-pkgoss",
-        shallow_since = "1565719153 +0300",
+        shallow_since = "1569336583 +0300",
     )
 
 def nginx_repositories_zlib(bind):
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 492b469..fd7e308 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,95 @@
 <change_log title="nginx">
 
 
+<changes ver="1.17.4" date="2019-09-24">
+
+<change type="change">
+<para lang="ru">
+улучшено детектирование некорректного поведения клиентов в HTTP/2.
+</para>
+<para lang="en">
+better detection of incorrect client behavior in HTTP/2.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+в обработке непрочитанного тела запроса
+при возврате ошибок в HTTP/2.
+</para>
+<para lang="en">
+in handling of not fully read client request body
+when returning errors in HTTP/2.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+директива worker_shutdown_timeout могла не работать
+при использовании HTTP/2.
+</para>
+<para lang="en">
+the "worker_shutdown_timeout" directive might not work
+when using HTTP/2.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при использовании HTTP/2 и директивы proxy_request_buffering
+в рабочем процессе мог произойти segmentation fault.
+</para>
+<para lang="en">
+a segmentation fault might occur in a worker process
+when using HTTP/2 and the "proxy_request_buffering" directive.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+на Windows при использовании SSL
+уровень записи в лог ошибки ECONNABORTED был "crit" вместо "error".
+</para>
+<para lang="en">
+the ECONNABORTED error log level was "crit" instead of "error"
+on Windows when using SSL.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+nginx игнорировал лишние данные при использовании chunked transfer encoding.
+</para>
+<para lang="en">
+nginx ignored extra data when using chunked transfer encoding.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+если использовалась директива return и
+при чтении тела запроса возникала ошибка,
+nginx всегда возвращал ошибку 500.
+</para>
+<para lang="en">
+nginx always returned the 500 error
+if the "return" directive was used
+and an error occurred during reading client request body.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в обработке ошибок выделения памяти.
+</para>
+<para lang="en">
+in memory allocation error handling.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="1.17.3" date="2019-08-13">
 
 <change type="security">
diff --git a/misc/GNUmakefile b/misc/GNUmakefile
index 2a34ae5..6938fe9 100644
--- a/misc/GNUmakefile
+++ b/misc/GNUmakefile
@@ -6,7 +6,7 @@
 
 CC =		cl
 OBJS =		objs.msvc8
-OPENSSL =	openssl-1.1.1c
+OPENSSL =	openssl-1.1.1d
 ZLIB =		zlib-1.2.11
 PCRE =		pcre-8.43
 
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 3b0b837..053201d 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
 #define NGINX_NAME         "nginx"
 #endif
 
-#define nginx_version      1017003
-#define NGINX_VERSION      "1.17.3"
+#define nginx_version      1017004
+#define NGINX_VERSION      "1.17.4"
 #define NGINX_VER          NGINX_NAME "/" NGINX_VERSION
 
 #ifdef NGX_BUILD
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index 593645d..e51712c 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -972,7 +972,8 @@
 
             name = ngx_resolver_dup(r, rn->name, rn->nlen);
             if (name == NULL) {
-                goto failed;
+                ngx_resolver_free(r, ctx);
+                return NGX_ERROR;
             }
 
             ctx->name.len = rn->nlen;
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 5abd167..b8d7b08 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -2837,6 +2837,9 @@
     if (sslerr == SSL_ERROR_SYSCALL) {
 
         if (err == NGX_ECONNRESET
+#if (NGX_WIN32)
+            || err == NGX_ECONNABORTED
+#endif
             || err == NGX_EPIPE
             || err == NGX_ENOTCONN
             || err == NGX_ETIMEDOUT
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index 9adce1b..74741f5 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -790,7 +790,7 @@
 
         if (conf->client_certificate.len == 0 && conf->verify != 3) {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no ssl_client_certificate for ssl_client_verify");
+                          "no ssl_client_certificate for ssl_verify_client");
             return NGX_CONF_ERROR;
         }
 
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 110cb8a..1afdb19 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1660,8 +1660,10 @@
     ngx_buf_t    *b;
     ngx_chain_t   out;
 
-    if (ngx_http_discard_request_body(r) != NGX_OK) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    rc = ngx_http_discard_request_body(r);
+
+    if (rc != NGX_OK) {
+        return rc;
     }
 
     r->headers_out.status = status;
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index d9a1dbe..8e1b118 100644
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -2268,6 +2268,9 @@
                 break;
             case LF:
                 state = sw_chunk_start;
+                break;
+            default:
+                goto invalid;
             }
             break;
 
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index 8d0d54f..345d1fc 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -355,6 +355,11 @@
     if (c->close) {
         c->close = 0;
 
+        if (c->error) {
+            ngx_http_v2_finalize_connection(h2c, 0);
+            return;
+        }
+
         if (!h2c->goaway) {
             h2c->goaway = 1;
 
@@ -420,6 +425,14 @@
 
         } while (p != end);
 
+        h2c->total_bytes += n;
+
+        if (h2c->total_bytes / 8 > h2c->payload_bytes + 1048576) {
+            ngx_log_error(NGX_LOG_INFO, c->log, 0, "http2 flood detected");
+            ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR);
+            return;
+        }
+
     } while (rev->ready);
 
     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
@@ -506,13 +519,12 @@
     ngx_http_core_loc_conf_t  *clcf;
 
     c = h2c->connection;
+    wev = c->write;
 
     if (c->error) {
-        return NGX_ERROR;
+        goto error;
     }
 
-    wev = c->write;
-
     if (!wev->ready) {
         return NGX_AGAIN;
     }
@@ -948,6 +960,15 @@
         return ngx_http_v2_state_skip_padded(h2c, pos, end);
     }
 
+    r = stream->request;
+
+    if (r->reading_body && !r->request_body_no_buffering) {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
+                       "skipping http2 DATA frame");
+
+        return ngx_http_v2_state_skip_padded(h2c, pos, end);
+    }
+
     size = end - pos;
 
     if (size >= h2c->state.length) {
@@ -955,7 +976,7 @@
         stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
     }
 
-    r = stream->request;
+    h2c->payload_bytes += size;
 
     if (r->request_body) {
         rc = ngx_http_v2_process_request_body(r, pos, size, stream->in_closed);
@@ -1101,20 +1122,19 @@
         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
     }
 
-    h2c->last_sid = h2c->state.sid;
-
-    h2c->state.pool = ngx_create_pool(1024, h2c->connection->log);
-    if (h2c->state.pool == NULL) {
-        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
-    }
-
     if (depend == h2c->state.sid) {
         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
                       "client sent HEADERS frame for stream %ui "
                       "with incorrect dependency", h2c->state.sid);
 
-        status = NGX_HTTP_V2_PROTOCOL_ERROR;
-        goto rst_stream;
+        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
+    }
+
+    h2c->last_sid = h2c->state.sid;
+
+    h2c->state.pool = ngx_create_pool(1024, h2c->connection->log);
+    if (h2c->state.pool == NULL) {
+        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
     }
 
     h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
@@ -1843,28 +1863,7 @@
                       "client sent PRIORITY frame for stream %ui "
                       "with incorrect dependency", h2c->state.sid);
 
-        node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
-
-        if (node && node->stream) {
-            if (ngx_http_v2_terminate_stream(h2c, node->stream,
-                                             NGX_HTTP_V2_PROTOCOL_ERROR)
-                == NGX_ERROR)
-            {
-                return ngx_http_v2_connection_error(h2c,
-                                                    NGX_HTTP_V2_INTERNAL_ERROR);
-            }
-
-        } else {
-            if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid,
-                                            NGX_HTTP_V2_PROTOCOL_ERROR)
-                == NGX_ERROR)
-            {
-                return ngx_http_v2_connection_error(h2c,
-                                                    NGX_HTTP_V2_INTERNAL_ERROR);
-            }
-        }
-
-        return ngx_http_v2_state_complete(h2c, pos, end);
+        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
     }
 
     node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1);
@@ -2276,41 +2275,11 @@
                    h2c->state.sid, window);
 
     if (window == 0) {
-        if (h2c->state.sid == 0) {
-            ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
-                          "client sent WINDOW_UPDATE frame "
-                          "with incorrect window increment 0");
-
-            return ngx_http_v2_connection_error(h2c,
-                                                NGX_HTTP_V2_PROTOCOL_ERROR);
-        }
-
         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
-                      "client sent WINDOW_UPDATE frame for stream %ui "
-                      "with incorrect window increment 0", h2c->state.sid);
+                      "client sent WINDOW_UPDATE frame "
+                      "with incorrect window increment 0");
 
-        node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
-
-        if (node && node->stream) {
-            if (ngx_http_v2_terminate_stream(h2c, node->stream,
-                                             NGX_HTTP_V2_PROTOCOL_ERROR)
-                == NGX_ERROR)
-            {
-                return ngx_http_v2_connection_error(h2c,
-                                                    NGX_HTTP_V2_INTERNAL_ERROR);
-            }
-
-        } else {
-            if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid,
-                                            NGX_HTTP_V2_PROTOCOL_ERROR)
-                == NGX_ERROR)
-            {
-                return ngx_http_v2_connection_error(h2c,
-                                                    NGX_HTTP_V2_INTERNAL_ERROR);
-            }
-        }
-
-        return ngx_http_v2_state_complete(h2c, pos, end);
+        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
     }
 
     if (h2c->state.sid) {
@@ -2997,9 +2966,9 @@
                       "requested control frame is too large: %uz", length);
         return NULL;
     }
+#endif
 
     frame->length = length;
-#endif
 
     buf->last = ngx_http_v2_write_len_and_type(buf->pos, length, type);
 
@@ -3026,6 +2995,8 @@
     frame->next = h2c->free_frames;
     h2c->free_frames = frame;
 
+    h2c->total_bytes += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length;
+
     return NGX_OK;
 }
 
@@ -3811,7 +3782,8 @@
 static void
 ngx_http_v2_run_request(ngx_http_request_t *r)
 {
-    ngx_connection_t  *fc;
+    ngx_connection_t          *fc;
+    ngx_http_v2_connection_t  *h2c;
 
     fc = r->connection;
 
@@ -3843,6 +3815,10 @@
         r->headers_in.chunked = 1;
     }
 
+    h2c = r->stream->connection;
+
+    h2c->payload_bytes += r->request_length;
+
     ngx_http_process_request(r);
 
 failed:
@@ -4378,33 +4354,11 @@
             }
 
         } else if (!stream->in_closed) {
-#if 0
             if (ngx_http_v2_send_rst_stream(h2c, node->id, NGX_HTTP_V2_NO_ERROR)
                 != NGX_OK)
             {
                 h2c->connection->error = 1;
             }
-#else
-            /*
-             * At the time of writing at least the latest versions of Chrome
-             * do not properly handle RST_STREAM with NO_ERROR status.
-             *
-             * See: https://bugs.chromium.org/p/chromium/issues/detail?id=603182
-             *
-             * As a workaround, the stream window is maximized before closing
-             * the stream.  This allows a client to send up to 2 GB of data
-             * before getting blocked on flow control.
-             */
-
-            if (stream->recv_window < NGX_HTTP_V2_MAX_WINDOW
-                && ngx_http_v2_send_window_update(h2c, node->id,
-                                                  NGX_HTTP_V2_MAX_WINDOW
-                                                  - stream->recv_window)
-                   != NGX_OK)
-            {
-                h2c->connection->error = 1;
-            }
-#endif
         }
     }
 
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
index 69d55d1..59ddf54 100644
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -119,6 +119,9 @@
     ngx_connection_t                *connection;
     ngx_http_connection_t           *http_connection;
 
+    off_t                            total_bytes;
+    off_t                            payload_bytes;
+
     ngx_uint_t                       processing;
     ngx_uint_t                       frames;
     ngx_uint_t                       idle;
diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c
index f1618ae..5a38737 100644
--- a/src/http/v2/ngx_http_v2_filter_module.c
+++ b/src/http/v2/ngx_http_v2_filter_module.c
@@ -1886,6 +1886,8 @@
     stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE
                                     + frame->length;
 
+    h2c->payload_bytes += frame->length;
+
     ngx_http_v2_handle_frame(stream, frame);
 
     ngx_http_v2_handle_stream(h2c, stream);
@@ -1940,6 +1942,8 @@
     stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE
                                     + frame->length;
 
+    h2c->payload_bytes += frame->length;
+
     ngx_http_v2_handle_frame(stream, frame);
 
     ngx_http_v2_handle_stream(h2c, stream);
@@ -2033,6 +2037,8 @@
 
     stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE;
 
+    h2c->payload_bytes += frame->length;
+
     ngx_http_v2_handle_frame(stream, frame);
 
     ngx_http_v2_handle_stream(h2c, stream);
@@ -2045,12 +2051,17 @@
 ngx_http_v2_handle_frame(ngx_http_v2_stream_t *stream,
     ngx_http_v2_out_frame_t *frame)
 {
-    ngx_http_request_t  *r;
+    ngx_http_request_t        *r;
+    ngx_http_v2_connection_t  *h2c;
 
     r = stream->request;
 
     r->connection->sent += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length;
 
+    h2c = stream->connection;
+
+    h2c->total_bytes += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length;
+
     if (frame->fin) {
         stream->out_closed = 1;
     }
diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c
index 5544f75..e193b29 100644
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -388,7 +388,7 @@
 
         if (conf->client_certificate.len == 0 && conf->verify != 3) {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no ssl_client_certificate for ssl_client_verify");
+                          "no ssl_client_certificate for ssl_verify_client");
             return NGX_CONF_ERROR;
         }
 
diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c
index ec9524e..79f30a8 100644
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -745,7 +745,7 @@
 
         if (conf->client_certificate.len == 0 && conf->verify != 3) {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no ssl_client_certificate for ssl_client_verify");
+                          "no ssl_client_certificate for ssl_verify_client");
             return NGX_CONF_ERROR;
         }