Mercurial > hg > nginx
comparison src/http/ngx_http_request.c @ 6412:4ba91a4c66a3
HTTP/2: implemented per request timeouts (closes #626).
Previously, there were only three timeouts used globally for the whole HTTP/2
connection:
1. Idle timeout for inactivity when there are no streams in processing
(the "http2_idle_timeout" directive);
2. Receive timeout for incomplete frames when there are no streams in
processing (the "http2_recv_timeout" directive);
3. Send timeout when there are frames waiting in the output queue
(the "send_timeout" directive on a server level).
Reaching one of these timeouts leads to HTTP/2 connection close.
This left a number of scenarios when a connection can get stuck without any
processing and timeouts:
1. A client has sent the headers block partially so nginx starts processing
a new stream but cannot continue without the rest of HEADERS and/or
CONTINUATION frames;
2. When nginx waits for the request body;
3. All streams are stuck on exhausted connection or stream windows.
The first idea that was rejected was to detect when the whole connection
gets stuck because of these situations and set the global receive timeout.
The disadvantage of such approach would be inconsistent behaviour in some
typical use cases. For example, if a user never replies to the browser's
question about where to save the downloaded file, the stream will be
eventually closed by a timeout. On the other hand, this will not happen
if there's some activity in other concurrent streams.
Now almost all the request timeouts work like in HTTP/1.x connections, so
the "client_header_timeout", "client_body_timeout", and "send_timeout" are
respected. These timeouts close the request.
The global timeouts work as before.
Previously, the c->write->delayed flag was abused to avoid setting timeouts on
stream events. Now, the "active" and "ready" flags are manipulated instead to
control the processing of individual streams.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Wed, 24 Feb 2016 15:58:07 +0300 |
parents | 71edd9192f24 |
children | f01ab2dbcfdc |
comparison
equal
deleted
inserted
replaced
6411:8ec349bb60b2 | 6412:4ba91a4c66a3 |
---|---|
2571 r->read_event_handler = r->discard_body ? | 2571 r->read_event_handler = r->discard_body ? |
2572 ngx_http_discarded_request_body_handler: | 2572 ngx_http_discarded_request_body_handler: |
2573 ngx_http_test_reading; | 2573 ngx_http_test_reading; |
2574 r->write_event_handler = ngx_http_writer; | 2574 r->write_event_handler = ngx_http_writer; |
2575 | 2575 |
2576 #if (NGX_HTTP_V2) | |
2577 if (r->stream) { | |
2578 return NGX_OK; | |
2579 } | |
2580 #endif | |
2581 | |
2582 wev = r->connection->write; | 2576 wev = r->connection->write; |
2583 | 2577 |
2584 if (wev->ready && wev->delayed) { | 2578 if (wev->ready && wev->delayed) { |
2585 return NGX_OK; | 2579 return NGX_OK; |
2586 } | 2580 } |
2661 ngx_http_finalize_request(r, rc); | 2655 ngx_http_finalize_request(r, rc); |
2662 return; | 2656 return; |
2663 } | 2657 } |
2664 | 2658 |
2665 if (r->buffered || r->postponed || (r == r->main && c->buffered)) { | 2659 if (r->buffered || r->postponed || (r == r->main && c->buffered)) { |
2666 | |
2667 #if (NGX_HTTP_V2) | |
2668 if (r->stream) { | |
2669 return; | |
2670 } | |
2671 #endif | |
2672 | 2660 |
2673 if (!wev->delayed) { | 2661 if (!wev->delayed) { |
2674 ngx_add_timer(wev, clcf->send_timeout); | 2662 ngx_add_timer(wev, clcf->send_timeout); |
2675 } | 2663 } |
2676 | 2664 |