Merge branch 'nginx' (nginx-1.11.13).

Change-Id: I09f3e38baa909424d0c9ee898b8486cec97ea303
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index f56b37f..818243e 100644
--- a/.hgtags
+++ b/.hgtags
@@ -411,3 +411,4 @@
 1ad0999a7ded3d4fb01c7acf8ff57c80b643da7e release-1.11.10
 d8b321a876d6254e9e98795e3b194ef053290354 release-1.11.11
 7f394e433f0003222aa6531931ecc0b24740d5e4 release-1.11.12
+3d0e8655f897959e48cc74e87670bb5492a58871 release-1.11.13
diff --git a/BUILD b/BUILD
index ae282e2..55656bf 100644
--- a/BUILD
+++ b/BUILD
@@ -1468,5 +1468,5 @@
     preinst = "@nginx_pkgoss//:debian_preinst",
     prerm = "@nginx_pkgoss//:debian_prerm",
     section = "httpd",
-    version = "1.11.12",
+    version = "1.11.13",
 )
diff --git a/build.bzl b/build.bzl
index 38e8c35..42b6b32 100644
--- a/build.bzl
+++ b/build.bzl
@@ -663,7 +663,7 @@
         name = "nginx_pkgoss",
         build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) +
                              _PKGOSS_BUILD_FILE_TAIL,
-        commit = "6875999d1ccf62b0ecdc3cbad5f3b0a0c6f4069d",  # nginx-1.11.12
+        commit = "5ca52610ad80ed63446d4b833ffc4a7f9130d230",  # nginx-1.11.13
         remote = "https://nginx.googlesource.com/nginx-pkgoss",
     )
 
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 6106043..ea39ab2 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,97 @@
 <change_log title="nginx">
 
 
+<changes ver="1.11.13" date="2017-04-04">
+
+<change type="feature">
+<para lang="ru">
+параметр http_429 в директивах proxy_next_upstream, fastcgi_next_upstream,
+scgi_next_upstream и uwsgi_next_upstream.<br/>
+Спасибо Piotr Sikora.
+</para>
+<para lang="en">
+the "http_429" parameter of the "proxy_next_upstream", "fastcgi_next_upstream",
+"scgi_next_upstream", and "uwsgi_next_upstream" directives.<br/>
+Thanks to Piotr Sikora.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в обработке ошибок выделения памяти.
+</para>
+<para lang="en">
+in memory allocation error handling.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при использовании директив sendfile и timer_resolution на Linux
+запросы могли зависать.
+</para>
+<para lang="en">
+requests might hang
+when using the "sendfile" and "timer_resolution" directives on Linux.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при использовании с подзапросами директив sendfile и aio_write
+запросы могли зависать.
+</para>
+<para lang="en">
+requests might hang
+when using the "sendfile" and "aio_write" directives with subrequests.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в модуле ngx_http_v2_module.<br/>
+Спасибо Piotr Sikora.
+</para>
+<para lang="en">
+in the ngx_http_v2_module.<br/>
+Thanks to Piotr Sikora.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при использовании HTTP/2 в рабочем процессе мог произойти segmentation fault.
+</para>
+<para lang="en">
+a segmentation fault might occur in a worker process when using HTTP/2.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+запросы могли зависать
+при использовании с подзапросами директив limit_rate, sendfile_max_chunk,
+limit_req или метода $r->sleep() встроенного перла.
+</para>
+<para lang="en">
+requests might hang
+when using the "limit_rate", "sendfile_max_chunk", "limit_req" directives,
+or the $r->sleep() embedded perl method with subrequests.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в модуле ngx_http_slice_module.
+</para>
+<para lang="en">
+in the ngx_http_slice_module.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="1.11.12" date="2017-03-24">
 
 <change type="bugfix">
diff --git a/src/core/nginx.h b/src/core/nginx.h
index eb5bf53..12d96ee 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
 #define NGINX_NAME         "nginx"
 #endif
 
-#define nginx_version      1011012
-#define NGINX_VERSION      "1.11.12"
+#define nginx_version      1011013
+#define NGINX_VERSION      "1.11.13"
 #define NGINX_VER          NGINX_NAME "/" NGINX_VERSION
 
 #ifdef NGX_BUILD
diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c
index 3dfdf2e..aee7a58 100644
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -115,16 +115,14 @@
 
     n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;
 
-    cycle->paths.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *));
-    if (cycle->paths.elts == NULL) {
+    if (ngx_array_init(&cycle->paths, pool, n, sizeof(ngx_path_t *))
+        != NGX_OK)
+    {
         ngx_destroy_pool(pool);
         return NULL;
     }
 
-    cycle->paths.nelts = 0;
-    cycle->paths.size = sizeof(ngx_path_t *);
-    cycle->paths.nalloc = n;
-    cycle->paths.pool = pool;
+    ngx_memzero(cycle->paths.elts, n * sizeof(ngx_path_t *));
 
 
     if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t))
@@ -175,16 +173,14 @@
 
     n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
 
-    cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t));
-    if (cycle->listening.elts == NULL) {
+    if (ngx_array_init(&cycle->listening, pool, n, sizeof(ngx_listening_t))
+        != NGX_OK)
+    {
         ngx_destroy_pool(pool);
         return NULL;
     }
 
-    cycle->listening.nelts = 0;
-    cycle->listening.size = sizeof(ngx_listening_t);
-    cycle->listening.nalloc = n;
-    cycle->listening.pool = pool;
+    ngx_memzero(cycle->listening.elts, n * sizeof(ngx_listening_t));
 
 
     ngx_queue_init(&cycle->reusable_connections_queue);
@@ -768,15 +764,15 @@
         }
 
         n = 10;
-        ngx_old_cycles.elts = ngx_pcalloc(ngx_temp_pool,
-                                          n * sizeof(ngx_cycle_t *));
-        if (ngx_old_cycles.elts == NULL) {
+
+        if (ngx_array_init(&ngx_old_cycles, ngx_temp_pool, n,
+                           sizeof(ngx_cycle_t *))
+            != NGX_OK)
+        {
             exit(1);
         }
-        ngx_old_cycles.nelts = 0;
-        ngx_old_cycles.size = sizeof(ngx_cycle_t *);
-        ngx_old_cycles.nalloc = n;
-        ngx_old_cycles.pool = ngx_temp_pool;
+
+        ngx_memzero(ngx_old_cycles.elts, n * sizeof(ngx_cycle_t *));
 
         ngx_cleaner_event.handler = ngx_clean_old_cycles;
         ngx_cleaner_event.log = cycle->log;
diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c
index 71c4f17..8237fef 100644
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -500,8 +500,7 @@
 #endif
 
     shm.size = size;
-    shm.name.len = sizeof("nginx_shared_zone") - 1;
-    shm.name.data = (u_char *) "nginx_shared_zone";
+    ngx_str_set(&shm.name, "nginx_shared_zone");
     shm.log = cycle->log;
 
     if (ngx_shm_alloc(&shm) != NGX_OK) {
diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c
index d3544db..c144b31 100644
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -217,13 +217,13 @@
         if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
             != NGX_OK)
         {
-            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err,
-                           "%s \"%s\" failed", of.failed, path.data);
-
             if (of.err == 0) {
                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
             }
 
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err,
+                           "%s \"%s\" failed", of.failed, path.data);
+
 #if (NGX_HAVE_OPENAT)
             if (of.err == NGX_EMLINK
                 || of.err == NGX_ELOOP)
diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c
index ec3aadf..9e7def8 100644
--- a/src/http/modules/ngx_http_limit_req_module.c
+++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -276,6 +276,8 @@
 
     r->read_event_handler = ngx_http_test_reading;
     r->write_event_handler = ngx_http_limit_req_delay;
+
+    r->connection->write->delayed = 1;
     ngx_add_timer(r->connection->write, delay);
 
     return NGX_AGAIN;
@@ -292,7 +294,7 @@
 
     wev = r->connection->write;
 
-    if (!wev->timedout) {
+    if (wev->delayed) {
 
         if (ngx_handle_write_event(wev, 0) != NGX_OK) {
             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -301,8 +303,6 @@
         return;
     }
 
-    wev->timedout = 0;
-
     if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
         return;
diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c
index 330dc7e..917ed55 100644
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -552,6 +552,11 @@
     if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
         != NGX_OK)
     {
+        if (of.err == 0) {
+            /* simulate successful logging */
+            return len;
+        }
+
         ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                       "%s \"%s\" failed", of.failed, log.data);
         /* simulate successful logging */
diff --git a/src/http/modules/ngx_http_slice_filter_module.c b/src/http/modules/ngx_http_slice_filter_module.c
index 2005939..7758342 100644
--- a/src/http/modules/ngx_http_slice_filter_module.c
+++ b/src/http/modules/ngx_http_slice_filter_module.c
@@ -11,23 +11,25 @@
 
 
 typedef struct {
-    size_t      size;
+    size_t               size;
 } ngx_http_slice_loc_conf_t;
 
 
 typedef struct {
-    off_t       start;
-    off_t       end;
-    ngx_str_t   range;
-    ngx_str_t   etag;
-    ngx_uint_t  last;  /* unsigned  last:1; */
+    off_t                start;
+    off_t                end;
+    ngx_str_t            range;
+    ngx_str_t            etag;
+    unsigned             last:1;
+    unsigned             active:1;
+    ngx_http_request_t  *sr;
 } ngx_http_slice_ctx_t;
 
 
 typedef struct {
-    off_t       start;
-    off_t       end;
-    off_t       complete_length;
+    off_t                start;
+    off_t                end;
+    off_t                complete_length;
 } ngx_http_slice_content_range_t;
 
 
@@ -169,6 +171,7 @@
     }
 
     ctx->start = end;
+    ctx->active = 1;
 
     r->headers_out.status = NGX_HTTP_OK;
     r->headers_out.status_line.len = 0;
@@ -209,7 +212,6 @@
 {
     ngx_int_t                   rc;
     ngx_chain_t                *cl;
-    ngx_http_request_t         *sr;
     ngx_http_slice_ctx_t       *ctx;
     ngx_http_slice_loc_conf_t  *slcf;
 
@@ -234,6 +236,16 @@
         return rc;
     }
 
+    if (ctx->sr && !ctx->sr->done) {
+        return rc;
+    }
+
+    if (!ctx->active) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "missing slice response");
+        return NGX_ERROR;
+    }
+
     if (ctx->start >= ctx->end) {
         ngx_http_set_ctx(r, NULL, ngx_http_slice_filter_module);
         ngx_http_send_special(r, NGX_HTTP_LAST);
@@ -244,14 +256,14 @@
         return rc;
     }
 
-    if (ngx_http_subrequest(r, &r->uri, &r->args, &sr, NULL,
+    if (ngx_http_subrequest(r, &r->uri, &r->args, &ctx->sr, NULL,
                             NGX_HTTP_SUBREQUEST_CLONE)
         != NGX_OK)
     {
         return NGX_ERROR;
     }
 
-    ngx_http_set_ctx(sr, ctx, ngx_http_slice_filter_module);
+    ngx_http_set_ctx(ctx->sr, ctx, ngx_http_slice_filter_module);
 
     slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module);
 
@@ -259,6 +271,8 @@
                                  ctx->start + (off_t) slcf->size - 1)
                      - ctx->range.data;
 
+    ctx->active = 0;
+
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http slice subrequest: \"%V\"", &ctx->range);
 
diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs
index 287d16e..865346a 100644
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -1001,6 +1001,7 @@
 
     ctx->next = SvRV(ST(2));
 
+    r->connection->write->delayed = 1;
     ngx_add_timer(r->connection->write, sleep);
 
     r->write_event_handler = ngx_http_perl_sleep_handler;
diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c
index 2796319..6d3be91 100644
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -278,15 +278,16 @@
 
     wev = r->connection->write;
 
-    if (wev->timedout) {
-        wev->timedout = 0;
-        ngx_http_perl_handle_request(r);
+    if (wev->delayed) {
+
+        if (ngx_handle_write_event(wev, 0) != NGX_OK) {
+            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        }
+
         return;
     }
 
-    if (ngx_handle_write_event(wev, 0) != NGX_OK) {
-        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-    }
+    ngx_http_perl_handle_request(r);
 }
 
 
diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c
index c696fb6..c8ad5da 100644
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -187,15 +187,24 @@
 ngx_http_copy_aio_event_handler(ngx_event_t *ev)
 {
     ngx_event_aio_t     *aio;
+    ngx_connection_t    *c;
     ngx_http_request_t  *r;
 
     aio = ev->data;
     r = aio->data;
+    c = r->connection;
+
+    ngx_http_set_log_request(c->log, r);
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http aio: \"%V?%V\"", &r->uri, &r->args);
 
     r->main->blocked--;
     r->aio = 0;
 
-    r->connection->write->handler(r->connection->write);
+    r->write_event_handler(r);
+
+    ngx_http_run_posted_requests(c);
 }
 
 
@@ -300,14 +309,33 @@
 static void
 ngx_http_copy_thread_event_handler(ngx_event_t *ev)
 {
+    ngx_connection_t    *c;
     ngx_http_request_t  *r;
 
     r = ev->data;
+    c = r->connection;
+
+    ngx_http_set_log_request(c->log, r);
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http thread: \"%V?%V\"", &r->uri, &r->args);
 
     r->main->blocked--;
     r->aio = 0;
 
-    r->connection->write->handler(r->connection->write);
+    if (r->done) {
+        /*
+         * trigger connection event handler if the subrequest was
+         * already finalized; this can happen if the handler is used
+         * for sendfile() in threads
+         */
+
+        c->write->handler(c->write);
+
+    } else {
+        r->write_event_handler(r);
+        ngx_http_run_posted_requests(c);
+    }
 }
 
 #endif
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 9ab2e1f..734e1d8 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1314,6 +1314,11 @@
         if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
             != NGX_OK)
         {
+            if (of.err == 0) {
+                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+                return NGX_OK;
+            }
+
             if (of.err != NGX_ENOENT
                 && of.err != NGX_ENOTDIR
                 && of.err != NGX_ENAMETOOLONG)
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index a9a9206..9ede5c6 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -2285,6 +2285,11 @@
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "http run request: \"%V?%V\"", &r->uri, &r->args);
 
+    if (ev->delayed && ev->timedout) {
+        ev->delayed = 0;
+        ev->timedout = 0;
+    }
+
     if (ev->write) {
         r->write_event_handler(r);
 
@@ -2694,7 +2699,7 @@
 static void
 ngx_http_writer(ngx_http_request_t *r)
 {
-    int                        rc;
+    ngx_int_t                  rc;
     ngx_event_t               *wev;
     ngx_connection_t          *c;
     ngx_http_core_loc_conf_t  *clcf;
@@ -2708,34 +2713,22 @@
     clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module);
 
     if (wev->timedout) {
-        if (!wev->delayed) {
-            ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
-                          "client timed out");
-            c->timedout = 1;
+        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
+                      "client timed out");
+        c->timedout = 1;
 
-            ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
-            return;
-        }
-
-        wev->timedout = 0;
-        wev->delayed = 0;
-
-        if (!wev->ready) {
-            ngx_add_timer(wev, clcf->send_timeout);
-
-            if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
-                ngx_http_close_request(r, 0);
-            }
-
-            return;
-        }
-
+        ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
+        return;
     }
 
     if (wev->delayed || r->aio) {
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
                        "http writer delayed");
 
+        if (!wev->delayed) {
+            ngx_add_timer(wev, clcf->send_timeout);
+        }
+
         if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
             ngx_http_close_request(r, 0);
         }
@@ -2746,7 +2739,7 @@
     rc = ngx_http_output_filter(r, NULL);
 
     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                   "http writer output filter: %d, \"%V?%V\"",
+                   "http writer output filter: %i, \"%V?%V\"",
                    rc, &r->uri, &r->args);
 
     if (rc == NGX_ERROR) {
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
index cc4d679..96f3ec6 100644
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -1513,6 +1513,12 @@
     if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
         != NGX_OK)
     {
+        if (of.err == 0) {
+            e->ip = ngx_http_script_exit;
+            e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
+            return;
+        }
+
         if (of.err != NGX_ENOENT
             && of.err != NGX_ENOTDIR
             && of.err != NGX_ENAMETOOLONG)
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index d04dbbb..9e1f3b0 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1247,6 +1247,11 @@
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "http upstream request: \"%V?%V\"", &r->uri, &r->args);
 
+    if (ev->delayed && ev->timedout) {
+        ev->delayed = 0;
+        ev->timedout = 0;
+    }
+
     if (ev->write) {
         u->write_event_handler(r, u);
 
@@ -3805,9 +3810,19 @@
     r->main->blocked--;
     r->aio = 0;
 
-    r->write_event_handler(r);
+    if (r->done) {
+        /*
+         * trigger connection event handler if the subrequest was
+         * already finalized; this can happen if the handler is used
+         * for sendfile() in threads
+         */
 
-    ngx_http_run_posted_requests(c);
+        c->write->handler(c->write);
+
+    } else {
+        r->write_event_handler(r);
+        ngx_http_run_posted_requests(c);
+    }
 }
 
 #endif
@@ -3855,31 +3870,9 @@
 
     if (wev->timedout) {
 
-        if (wev->delayed) {
-
-            wev->timedout = 0;
-            wev->delayed = 0;
-
-            if (!wev->ready) {
-                ngx_add_timer(wev, p->send_timeout);
-
-                if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
-                    ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
-                }
-
-                return;
-            }
-
-            if (ngx_event_pipe(p, wev->write) == NGX_ABORT) {
-                ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
-                return;
-            }
-
-        } else {
-            p->downstream_error = 1;
-            c->timedout = 1;
-            ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
-        }
+        p->downstream_error = 1;
+        c->timedout = 1;
+        ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
 
     } else {
 
@@ -3924,30 +3917,8 @@
 
     if (rev->timedout) {
 
-        if (rev->delayed) {
-
-            rev->timedout = 0;
-            rev->delayed = 0;
-
-            if (!rev->ready) {
-                ngx_add_timer(rev, p->read_timeout);
-
-                if (ngx_handle_read_event(rev, 0) != NGX_OK) {
-                    ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
-                }
-
-                return;
-            }
-
-            if (ngx_event_pipe(p, 0) == NGX_ABORT) {
-                ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
-                return;
-            }
-
-        } else {
-            p->upstream_error = 1;
-            ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
-        }
+        p->upstream_error = 1;
+        ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
 
     } else {
 
@@ -4184,8 +4155,7 @@
     if (u->peer.sockaddr) {
 
         if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_403
-            || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404
-            || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_429)
+            || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404)
         {
             state = NGX_PEER_NEXT;
 
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index 34f0dac..4910ad8 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -817,7 +817,7 @@
                                                 NGX_HTTP_V2_PROTOCOL_ERROR);
         }
 
-        h2c->state.length -= h2c->state.padding + 1;
+        h2c->state.length -= 1 + h2c->state.padding;
     }
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
@@ -942,7 +942,7 @@
 
     if (size >= h2c->state.length) {
         size = h2c->state.length;
-        stream->in_closed  = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
+        stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
     }
 
     r = stream->request;
@@ -1910,7 +1910,7 @@
 
     if (node == NULL || node->stream == NULL) {
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
-                        "unknown http2 stream");
+                       "unknown http2 stream");
 
         return ngx_http_v2_state_complete(h2c, pos, end);
     }
@@ -2048,6 +2048,7 @@
             break;
 
         case NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING:
+
             if (value > NGX_HTTP_V2_MAX_FRAME_SIZE
                 || value < NGX_HTTP_V2_DEFAULT_FRAME_SIZE)
             {
@@ -3133,7 +3134,7 @@
     }
 
     ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
-                  "client sent unknown pseudo header \"%V\"",
+                  "client sent unknown pseudo-header \":%V\"",
                   &header->name);
 
     return NGX_DECLINED;
@@ -3280,14 +3281,14 @@
 {
     if (r->schema_start) {
         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
-                      "client sent duplicate :schema header");
+                      "client sent duplicate :scheme header");
 
         return NGX_DECLINED;
     }
 
     if (header->value.len == 0) {
         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
-                      "client sent empty :schema header");
+                      "client sent empty :scheme header");
 
         return NGX_DECLINED;
     }
@@ -4194,6 +4195,14 @@
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
                    "http2 handle connection handler");
 
+    c = rev->data;
+    h2c = c->data;
+
+    if (c->error) {
+        ngx_http_v2_finalize_connection(h2c, 0);
+        return;
+    }
+
     rev->handler = ngx_http_v2_read_handler;
 
     if (rev->ready) {
@@ -4201,9 +4210,6 @@
         return;
     }
 
-    c = rev->data;
-    h2c = c->data;
-
     if (h2c->last_out && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
         ngx_http_v2_finalize_connection(h2c, 0);
         return;
@@ -4326,7 +4332,10 @@
 
             if (stream->queued) {
                 stream->queued = 0;
+
                 ev = fc->write;
+                ev->active = 0;
+                ev->ready = 1;
 
             } else {
                 ev = fc->read;
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
index cddfccd..7d2a2ea 100644
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -249,8 +249,8 @@
 {
     ngx_http_v2_out_frame_t  **out;
 
-    for (out = &h2c->last_out; *out; out = &(*out)->next)
-    {
+    for (out = &h2c->last_out; *out; out = &(*out)->next) {
+
         if ((*out)->blocked || (*out)->stream == NULL) {
             break;
         }
diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c
index 3c0696a..b44724c 100644
--- a/src/os/unix/ngx_linux_sendfile_chain.c
+++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -20,8 +20,8 @@
 #error sendfile64() is required!
 #endif
 
-static ngx_int_t ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file,
-    size_t size, size_t *sent);
+static ssize_t ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file,
+    size_t size);
 static void ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log);
 #endif
 
@@ -56,10 +56,6 @@
     ngx_chain_t   *cl;
     ngx_iovec_t    header;
     struct iovec   headers[NGX_IOVS_PREALLOCATE];
-#if (NGX_THREADS)
-    ngx_int_t      rc;
-    ngx_uint_t     thread_handled, thread_complete;
-#endif
 
     wev = c->write;
 
@@ -82,10 +78,6 @@
 
     for ( ;; ) {
         prev_send = send;
-#if (NGX_THREADS)
-        thread_handled = 0;
-        thread_complete = 0;
-#endif
 
         /* create the iovec and coalesce the neighbouring bufs */
 
@@ -179,38 +171,19 @@
             }
 #endif
 
-#if (NGX_THREADS)
-            if (file->file->thread_handler) {
-                rc = ngx_linux_sendfile_thread(c, file, file_size, &sent);
+            n = ngx_linux_sendfile(c, file, file_size);
 
-                switch (rc) {
-                case NGX_OK:
-                    thread_handled = 1;
-                    break;
-
-                case NGX_DONE:
-                    thread_complete = 1;
-                    break;
-
-                case NGX_AGAIN:
-                    break;
-
-                default: /* NGX_ERROR */
-                    return NGX_CHAIN_ERROR;
-                }
-
-            } else
-#endif
-            {
-                n = ngx_linux_sendfile(c, file, file_size);
-
-                if (n == NGX_ERROR) {
-                    return NGX_CHAIN_ERROR;
-                }
-
-                sent = (n == NGX_AGAIN) ? 0 : n;
+            if (n == NGX_ERROR) {
+                return NGX_CHAIN_ERROR;
             }
 
+            if (n == NGX_DONE) {
+                /* thread task posted */
+                return in;
+            }
+
+            sent = (n == NGX_AGAIN) ? 0 : n;
+
         } else {
             n = ngx_writev(c, &header);
 
@@ -225,21 +198,27 @@
 
         in = ngx_chain_update_sent(in, sent);
 
-        if ((size_t) (send - prev_send) != sent) {
-#if (NGX_THREADS)
-            if (thread_handled) {
-                return in;
-            }
-
-            if (thread_complete) {
-                send = prev_send + sent;
-                continue;
-            }
-#endif
+        if (n == NGX_AGAIN) {
             wev->ready = 0;
             return in;
         }
 
+        if ((size_t) (send - prev_send) != sent) {
+
+            /*
+             * sendfile() on Linux 4.3+ might be interrupted at any time,
+             * and provides no indication if it was interrupted or not,
+             * so we have to retry till an explicit EAGAIN
+             *
+             * sendfile() in threads can also report less bytes written
+             * than we are prepared to send now, since it was started in
+             * some point in the past, so we again have to retry
+             */
+
+            send = prev_send + sent;
+            continue;
+        }
+
         if (send >= limit || in == NULL) {
             return in;
         }
@@ -258,6 +237,14 @@
     ssize_t    n;
     ngx_err_t  err;
 
+#if (NGX_THREADS)
+
+    if (file->file->thread_handler) {
+        return ngx_linux_sendfile_thread(c, file, size);
+    }
+
+#endif
+
 #if (NGX_HAVE_SENDFILE64)
     offset = file->file_pos;
 #else
@@ -324,9 +311,8 @@
 } ngx_linux_sendfile_ctx_t;
 
 
-static ngx_int_t
-ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size,
-    size_t *sent)
+static ssize_t
+ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size)
 {
     ngx_event_t               *wev;
     ngx_thread_task_t         *task;
@@ -356,10 +342,14 @@
         task->event.complete = 0;
 
         if (ctx->err == NGX_EAGAIN) {
-            *sent = 0;
+            /*
+             * if wev->complete is set, this means that a write event
+             * happened while we were waiting for the thread task, so
+             * we have to retry sending even on EAGAIN
+             */
 
             if (wev->complete) {
-                return NGX_DONE;
+                return 0;
             }
 
             return NGX_AGAIN;
@@ -384,13 +374,7 @@
             return NGX_ERROR;
         }
 
-        *sent = ctx->sent;
-
-        if (ctx->sent == ctx->size || wev->complete) {
-            return NGX_DONE;
-        }
-
-        return NGX_AGAIN;
+        return ctx->sent;
     }
 
     if (task->event.active && ctx->file == file) {
@@ -399,9 +383,7 @@
          * or multiple calls of the next body filter from a filter
          */
 
-        *sent = 0;
-
-        return NGX_OK;
+        return NGX_DONE;
     }
 
     ctx->file = file;
@@ -414,9 +396,7 @@
         return NGX_ERROR;
     }
 
-    *sent = 0;
-
-    return NGX_OK;
+    return NGX_DONE;
 }
 
 
diff --git a/src/stream/ngx_stream_log_module.c b/src/stream/ngx_stream_log_module.c
index 6b29340..466bdda 100644
--- a/src/stream/ngx_stream_log_module.c
+++ b/src/stream/ngx_stream_log_module.c
@@ -443,6 +443,11 @@
                              s->connection->pool)
         != NGX_OK)
     {
+        if (of.err == 0) {
+            /* simulate successful logging */
+            return len;
+        }
+
         ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno,
                       "%s \"%s\" failed", of.failed, log.data);
         /* simulate successful logging */