summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Dounin <mdounin@mdounin.ru>2017-04-02 14:32:29 +0300
committerMaxim Dounin <mdounin@mdounin.ru>2017-04-02 14:32:29 +0300
commit5d5f0dcac4e3bbd4464aa1185d7fd51587a3119e (patch)
treea5416b5d2589f61f3caa0ec749a1763dc7f19c53
parent96e4e84ce273664d0ee43c5c5b7d14efa6f86d39 (diff)
downloadnginx-5d5f0dcac4e3bbd4464aa1185d7fd51587a3119e.tar.gz
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.
-rw-r--r--src/http/modules/ngx_http_limit_req_module.c5
-rw-r--r--src/http/modules/perl/ngx_http_perl_module.c5
-rw-r--r--src/http/ngx_http_request.c35
-rw-r--r--src/http/ngx_http_upstream.c59
4 files changed, 26 insertions, 78 deletions
diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c
index 4a79b479b..579b13c84 100644
--- 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_request_t *r)
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_request_t *r)
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
index 79ded0f2f..6d3be9128 100644
--- 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_request_t *r)
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_request_t *r)
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
index dd5491021..8619552ee 100644
--- 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
index 2725984c4..43079563d 100644
--- 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 *ev)
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_http_request_t *r)
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_http_request_t *r,
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 {