# HG changeset patch # User Maxim Dounin # Date 1491132749 -10800 # Node ID 903fb1ddc07f6b4345d88428898d95aadfc0223f # Parent 1c5e5e5b008df7c040ddd51b26fcd49bfa173b47 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. 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 {