comparison src/stream/ngx_stream_core_module.c @ 7345:fe767c99c2ad

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.
author Roman Arutyunyan <arut@nginx.com>
date Wed, 29 Aug 2018 15:56:42 +0300
parents 7f955d3b9a0d
children 4f9b72a229c1
comparison
equal deleted inserted replaced
7344:5f6d2e102f4c 7345:fe767c99c2ad
247 rc = NGX_STREAM_OK; 247 rc = NGX_STREAM_OK;
248 break; 248 break;
249 } 249 }
250 250
251 if (!c->read->ready) { 251 if (!c->read->ready) {
252 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { 252 break;
253 rc = NGX_ERROR;
254 break;
255 }
256
257 if (!c->read->timer_set) {
258 ngx_add_timer(c->read, cscf->preread_timeout);
259 }
260
261 c->read->handler = ngx_stream_session_handler;
262
263 return NGX_OK;
264 } 253 }
265 254
266 n = c->recv(c, c->buffer->last, size); 255 n = c->recv(c, c->buffer->last, size);
267 256
268 if (n == NGX_ERROR) { 257 if (n == NGX_ERROR || n == 0) {
269 rc = NGX_STREAM_OK; 258 rc = NGX_STREAM_OK;
270 break; 259 break;
271 } 260 }
272 261
273 if (n > 0) { 262 if (n == NGX_AGAIN) {
274 c->buffer->last += n; 263 break;
275 } 264 }
265
266 c->buffer->last += n;
276 267
277 rc = ph->handler(s); 268 rc = ph->handler(s);
269 }
270
271 if (rc == NGX_AGAIN) {
272 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
273 ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
274 return NGX_OK;
275 }
276
277 if (!c->read->timer_set) {
278 ngx_add_timer(c->read, cscf->preread_timeout);
279 }
280
281 c->read->handler = ngx_stream_session_handler;
282
283 return NGX_OK;
278 } 284 }
279 285
280 if (c->read->timer_set) { 286 if (c->read->timer_set) {
281 ngx_del_timer(c->read); 287 ngx_del_timer(c->read);
282 } 288 }