aboutsummaryrefslogtreecommitdiff
path: root/src/stream/ngx_stream_core_module.c
diff options
context:
space:
mode:
authorRoman Arutyunyan <arut@nginx.com>2018-08-29 15:56:42 +0300
committerRoman Arutyunyan <arut@nginx.com>2018-08-29 15:56:42 +0300
commitd9908c6c9a8ef01b36dc604ace4c00c09135372e (patch)
treec1ba2dbc26a26180b177c0af24cdbea60b0276c2 /src/stream/ngx_stream_core_module.c
parent73d467cecd4fa6efc748a1186782154931269e36 (diff)
downloadnginx-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/stream/ngx_stream_core_module.c')
-rw-r--r--src/stream/ngx_stream_core_module.c36
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);
}