diff options
author | Roman Arutyunyan <arut@nginx.com> | 2018-08-29 15:56:42 +0300 |
---|---|---|
committer | Roman Arutyunyan <arut@nginx.com> | 2018-08-29 15:56:42 +0300 |
commit | d9908c6c9a8ef01b36dc604ace4c00c09135372e (patch) | |
tree | c1ba2dbc26a26180b177c0af24cdbea60b0276c2 /src | |
parent | 73d467cecd4fa6efc748a1186782154931269e36 (diff) | |
download | nginx-d9908c6c9a8ef01b36dc604ace4c00c09135372e.tar.gz nginx-d9908c6c9a8ef01b36dc604ace4c00c09135372e.zip |
Stream: avoid potential infinite loop at preread phase.
Previously the preread phase code ignored NGX_AGAIN value returned from
c->recv() and relied only on c->read->ready. But this flag is not reliable and
should only be checked for optimization purposes. For example, when using
SSL, c->read->ready may be set when no input is available. This can lead to
calling preread handler infinitely in a loop.
Diffstat (limited to 'src')
-rw-r--r-- | src/stream/ngx_stream_core_module.c | 36 |
1 files changed, 21 insertions, 15 deletions
diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index 96e7c9ac8..3c4027b77 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -249,34 +249,40 @@ ngx_stream_core_preread_phase(ngx_stream_session_t *s, } if (!c->read->ready) { - if (ngx_handle_read_event(c->read, 0) != NGX_OK) { - rc = NGX_ERROR; - break; - } - - if (!c->read->timer_set) { - ngx_add_timer(c->read, cscf->preread_timeout); - } - - c->read->handler = ngx_stream_session_handler; - - return NGX_OK; + break; } n = c->recv(c, c->buffer->last, size); - if (n == NGX_ERROR) { + if (n == NGX_ERROR || n == 0) { rc = NGX_STREAM_OK; break; } - if (n > 0) { - c->buffer->last += n; + if (n == NGX_AGAIN) { + break; } + c->buffer->last += n; + rc = ph->handler(s); } + if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return NGX_OK; + } + + if (!c->read->timer_set) { + ngx_add_timer(c->read, cscf->preread_timeout); + } + + c->read->handler = ngx_stream_session_handler; + + return NGX_OK; + } + if (c->read->timer_set) { ngx_del_timer(c->read); } |