Mercurial > hg > nginx
comparison src/http/v2/ngx_http_v2.c @ 6889:09cf90250844 stable-1.10
HTTP/2: graceful shutdown of active connections (closes #1106).
Previously, while shutting down gracefully, the HTTP/2 connections were
closed in transition to idle state after all active streams have been
processed. That might never happen if the client continued opening new
streams.
Now, nginx sends GOAWAY to all HTTP/2 connections and ignores further
attempts to open new streams. A worker process will quit as soon as
processing of already opened streams is finished.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Thu, 20 Oct 2016 16:15:03 +0300 |
parents | 85c3740b6745 |
children | 16487f9e6665 |
comparison
equal
deleted
inserted
replaced
6888:70539dd7abe5 | 6889:09cf90250844 |
---|---|
134 ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); | 134 ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); |
135 static ngx_int_t ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c, | 135 static ngx_int_t ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c, |
136 ngx_uint_t sid, size_t window); | 136 ngx_uint_t sid, size_t window); |
137 static ngx_int_t ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c, | 137 static ngx_int_t ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c, |
138 ngx_uint_t sid, ngx_uint_t status); | 138 ngx_uint_t sid, ngx_uint_t status); |
139 static ngx_int_t ngx_http_v2_send_goaway(ngx_http_v2_connection_t *h2c, | |
140 ngx_uint_t status); | |
139 | 141 |
140 static ngx_http_v2_out_frame_t *ngx_http_v2_get_frame( | 142 static ngx_http_v2_out_frame_t *ngx_http_v2_get_frame( |
141 ngx_http_v2_connection_t *h2c, size_t length, ngx_uint_t type, | 143 ngx_http_v2_connection_t *h2c, size_t length, ngx_uint_t type, |
142 u_char flags, ngx_uint_t sid); | 144 u_char flags, ngx_uint_t sid); |
143 static ngx_int_t ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c, | 145 static ngx_int_t ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c, |
291 c->data = h2c; | 293 c->data = h2c; |
292 | 294 |
293 rev->handler = ngx_http_v2_read_handler; | 295 rev->handler = ngx_http_v2_read_handler; |
294 c->write->handler = ngx_http_v2_write_handler; | 296 c->write->handler = ngx_http_v2_write_handler; |
295 | 297 |
298 c->idle = 1; | |
299 | |
296 ngx_http_v2_read_handler(rev); | 300 ngx_http_v2_read_handler(rev); |
297 } | 301 } |
298 | 302 |
299 | 303 |
300 static void | 304 static void |
317 } | 321 } |
318 | 322 |
319 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler"); | 323 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler"); |
320 | 324 |
321 h2c->blocked = 1; | 325 h2c->blocked = 1; |
326 | |
327 if (c->close) { | |
328 c->close = 0; | |
329 h2c->goaway = 1; | |
330 | |
331 if (ngx_http_v2_send_goaway(h2c, NGX_HTTP_V2_NO_ERROR) == NGX_ERROR) { | |
332 ngx_http_v2_finalize_connection(h2c, 0); | |
333 return; | |
334 } | |
335 | |
336 if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) { | |
337 ngx_http_v2_finalize_connection(h2c, 0); | |
338 return; | |
339 } | |
340 | |
341 h2c->blocked = 0; | |
342 | |
343 return; | |
344 } | |
322 | 345 |
323 h2mcf = ngx_http_get_module_main_conf(h2c->http_connection->conf_ctx, | 346 h2mcf = ngx_http_get_module_main_conf(h2c->http_connection->conf_ctx, |
324 ngx_http_v2_module); | 347 ngx_http_v2_module); |
325 | 348 |
326 available = h2mcf->recv_buffer_size - 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE; | 349 available = h2mcf->recv_buffer_size - 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE; |
631 } | 654 } |
632 | 655 |
633 /* rc == NGX_OK */ | 656 /* rc == NGX_OK */ |
634 } | 657 } |
635 | 658 |
659 if (h2c->goaway) { | |
660 ngx_http_close_connection(c); | |
661 return; | |
662 } | |
663 | |
636 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | 664 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, |
637 ngx_http_v2_module); | 665 ngx_http_v2_module); |
638 if (h2c->state.incomplete) { | 666 if (h2c->state.incomplete) { |
639 ngx_add_timer(c->read, h2scf->recv_timeout); | 667 ngx_add_timer(c->read, h2scf->recv_timeout); |
640 return; | 668 return; |
641 } | 669 } |
642 | 670 |
643 if (ngx_terminate || ngx_exiting) { | |
644 ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); | |
645 return; | |
646 } | |
647 | |
648 ngx_destroy_pool(h2c->pool); | 671 ngx_destroy_pool(h2c->pool); |
649 | 672 |
650 h2c->pool = NULL; | 673 h2c->pool = NULL; |
651 h2c->free_frames = NULL; | 674 h2c->free_frames = NULL; |
652 h2c->free_fake_connections = NULL; | 675 h2c->free_fake_connections = NULL; |
656 ngx_ssl_free_buffer(c); | 679 ngx_ssl_free_buffer(c); |
657 } | 680 } |
658 #endif | 681 #endif |
659 | 682 |
660 c->destroyed = 1; | 683 c->destroyed = 1; |
661 c->idle = 1; | |
662 ngx_reusable_connection(c, 1); | 684 ngx_reusable_connection(c, 1); |
663 | 685 |
664 c->write->handler = ngx_http_empty_handler; | 686 c->write->handler = ngx_http_empty_handler; |
665 c->read->handler = ngx_http_v2_idle_handler; | 687 c->read->handler = ngx_http_v2_idle_handler; |
666 | 688 |
1023 if (h2c->state.length == size) { | 1045 if (h2c->state.length == size) { |
1024 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | 1046 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, |
1025 "client sent HEADERS frame with empty header block"); | 1047 "client sent HEADERS frame with empty header block"); |
1026 | 1048 |
1027 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | 1049 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); |
1050 } | |
1051 | |
1052 if (h2c->goaway) { | |
1053 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
1054 "skipping http2 HEADERS frame"); | |
1055 return ngx_http_v2_state_skip(h2c, pos, end); | |
1028 } | 1056 } |
1029 | 1057 |
1030 if ((size_t) (end - pos) < size) { | 1058 if ((size_t) (end - pos) < size) { |
1031 return ngx_http_v2_state_save(h2c, pos, end, | 1059 return ngx_http_v2_state_save(h2c, pos, end, |
1032 ngx_http_v2_state_headers); | 1060 ngx_http_v2_state_headers); |
4160 } | 4188 } |
4161 | 4189 |
4162 #endif | 4190 #endif |
4163 | 4191 |
4164 c->destroyed = 0; | 4192 c->destroyed = 0; |
4165 c->idle = 0; | |
4166 ngx_reusable_connection(c, 0); | 4193 ngx_reusable_connection(c, 0); |
4167 | 4194 |
4168 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | 4195 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, |
4169 ngx_http_v2_module); | 4196 ngx_http_v2_module); |
4170 | 4197 |
4195 | 4222 |
4196 c = h2c->connection; | 4223 c = h2c->connection; |
4197 | 4224 |
4198 h2c->blocked = 1; | 4225 h2c->blocked = 1; |
4199 | 4226 |
4200 if (!c->error && ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) { | 4227 if (!c->error && !h2c->goaway) { |
4201 (void) ngx_http_v2_send_output_queue(h2c); | 4228 if (ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) { |
4229 (void) ngx_http_v2_send_output_queue(h2c); | |
4230 } | |
4202 } | 4231 } |
4203 | 4232 |
4204 c->error = 1; | 4233 c->error = 1; |
4205 | 4234 |
4206 if (!h2c->processing) { | 4235 if (!h2c->processing) { |