[nginx] Moved handling of wev->delayed to the connection event handler.

Maxim Dounin mdounin at mdounin.ru
Sun Apr 2 13:28:09 UTC 2017


details:   http://hg.nginx.org/nginx/rev/903fb1ddc07f
branches:  
changeset: 6961:903fb1ddc07f
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Sun Apr 02 14:32:29 2017 +0300
description:
Moved handling of wev->delayed to the connection event handler.

With post_action or subrequests, it is possible that the timer set for
wev->delayed will expire while the active subrequest write event handler
is not ready to handle this.  This results in request hangs as observed
with limit_rate / sendfile_max_chunk and post_action (ticket #776) or
subrequests (ticket #1228).

Moving the handling to the connection event handler fixes the hangs observed,
and also slightly simplifies the code.

diffstat:

 src/http/modules/ngx_http_limit_req_module.c |   5 +-
 src/http/modules/perl/ngx_http_perl_module.c |   5 +-
 src/http/ngx_http_request.c                  |  37 +++++++----------
 src/http/ngx_http_upstream.c                 |  59 ++++-----------------------
 4 files changed, 27 insertions(+), 79 deletions(-)

diffs (187 lines):

diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c
--- a/src/http/modules/ngx_http_limit_req_module.c
+++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -294,7 +294,7 @@ ngx_http_limit_req_delay(ngx_http_reques
 
     wev = r->connection->write;
 
-    if (wev->delayed && !wev->timedout) {
+    if (wev->delayed) {
 
         if (ngx_handle_write_event(wev, 0) != NGX_OK) {
             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -303,9 +303,6 @@ ngx_http_limit_req_delay(ngx_http_reques
         return;
     }
 
-    wev->delayed = 0;
-    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/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -278,7 +278,7 @@ ngx_http_perl_sleep_handler(ngx_http_req
 
     wev = r->connection->write;
 
-    if (wev->delayed && !wev->timedout) {
+    if (wev->delayed) {
 
         if (ngx_handle_write_event(wev, 0) != NGX_OK) {
             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -287,9 +287,6 @@ ngx_http_perl_sleep_handler(ngx_http_req
         return;
     }
 
-    wev->delayed = 0;
-    wev->timedout = 0;
-
     ngx_http_perl_handle_request(r);
 }
 
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -2198,6 +2198,11 @@ ngx_http_request_handler(ngx_event_t *ev
     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);
 
@@ -2621,34 +2626,22 @@ ngx_http_writer(ngx_http_request_t *r)
     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_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_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;
     }
 
     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);
         }
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1232,6 +1232,11 @@ ngx_http_upstream_handler(ngx_event_t *e
     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);
 
@@ -3796,31 +3801,9 @@ ngx_http_upstream_process_downstream(ngx
 
     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 {
 
@@ -3865,30 +3848,8 @@ ngx_http_upstream_process_upstream(ngx_h
 
     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 {
 


More information about the nginx-devel mailing list