comparison src/http/v2/ngx_http_v2.c @ 6778:5e95b9fb33b7

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 57148b755320
children 9027991e2f37
comparison
equal deleted inserted replaced
6777:563a1ee345a4 6778:5e95b9fb33b7
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) {