comparison src/http/v2/ngx_http_v2_module.c @ 6750:cb330cd39030 stable-1.10

HTTP/2: implemented preread buffer for request body (closes #959). Previously, the stream's window was kept zero in order to prevent a client from sending the request body before it was requested (see 887cca40ba6a for details). Until such initial window was acknowledged all requests with data were rejected (see 0aa07850922f for details). That approach revealed a number of problems: 1. Some clients (notably MS IE/Edge, Safari, iOS applications) show an error or even crash if a stream is rejected; 2. This requires at least one RTT for every request with body before the client receives window update and able to send data. To overcome these problems the new directive "http2_body_preread_size" is introduced. It sets the initial window and configures a special per stream preread buffer that is used to save all incoming data before the body is requested and processed. If the directive's value is lower than the default initial window (65535), as previously, all streams with data will be rejected until the new window is acknowledged. Otherwise, no special processing is used and all requests with data are welcome right from the connection start. The default value is chosen to be 64k, which is bigger than the default initial window. Setting it to zero is fully complaint to the previous behavior.
author Valentin Bartenev <vbart@nginx.com>
date Tue, 24 May 2016 17:37:52 +0300
parents 2cd019520210
children 9027991e2f37
comparison
equal deleted inserted replaced
6749:f88a145b093e 6750:cb330cd39030
28 void *child); 28 void *child);
29 29
30 static char *ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post, 30 static char *ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post,
31 void *data); 31 void *data);
32 static char *ngx_http_v2_pool_size(ngx_conf_t *cf, void *post, void *data); 32 static char *ngx_http_v2_pool_size(ngx_conf_t *cf, void *post, void *data);
33 static char *ngx_http_v2_preread_size(ngx_conf_t *cf, void *post, void *data);
33 static char *ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, 34 static char *ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post,
34 void *data); 35 void *data);
35 static char *ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data); 36 static char *ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data);
36 static char *ngx_http_v2_spdy_deprecated(ngx_conf_t *cf, ngx_command_t *cmd, 37 static char *ngx_http_v2_spdy_deprecated(ngx_conf_t *cf, ngx_command_t *cmd,
37 void *conf); 38 void *conf);
39 40
40 static ngx_conf_post_t ngx_http_v2_recv_buffer_size_post = 41 static ngx_conf_post_t ngx_http_v2_recv_buffer_size_post =
41 { ngx_http_v2_recv_buffer_size }; 42 { ngx_http_v2_recv_buffer_size };
42 static ngx_conf_post_t ngx_http_v2_pool_size_post = 43 static ngx_conf_post_t ngx_http_v2_pool_size_post =
43 { ngx_http_v2_pool_size }; 44 { ngx_http_v2_pool_size };
45 static ngx_conf_post_t ngx_http_v2_preread_size_post =
46 { ngx_http_v2_preread_size };
44 static ngx_conf_post_t ngx_http_v2_streams_index_mask_post = 47 static ngx_conf_post_t ngx_http_v2_streams_index_mask_post =
45 { ngx_http_v2_streams_index_mask }; 48 { ngx_http_v2_streams_index_mask };
46 static ngx_conf_post_t ngx_http_v2_chunk_size_post = 49 static ngx_conf_post_t ngx_http_v2_chunk_size_post =
47 { ngx_http_v2_chunk_size }; 50 { ngx_http_v2_chunk_size };
48 51
81 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, 84 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
82 ngx_conf_set_size_slot, 85 ngx_conf_set_size_slot,
83 NGX_HTTP_SRV_CONF_OFFSET, 86 NGX_HTTP_SRV_CONF_OFFSET,
84 offsetof(ngx_http_v2_srv_conf_t, max_header_size), 87 offsetof(ngx_http_v2_srv_conf_t, max_header_size),
85 NULL }, 88 NULL },
89
90 { ngx_string("http2_body_preread_size"),
91 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
92 ngx_conf_set_size_slot,
93 NGX_HTTP_SRV_CONF_OFFSET,
94 offsetof(ngx_http_v2_srv_conf_t, preread_size),
95 &ngx_http_v2_preread_size_post },
86 96
87 { ngx_string("http2_streams_index_size"), 97 { ngx_string("http2_streams_index_size"),
88 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, 98 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
89 ngx_conf_set_num_slot, 99 ngx_conf_set_num_slot,
90 NGX_HTTP_SRV_CONF_OFFSET, 100 NGX_HTTP_SRV_CONF_OFFSET,
314 h2scf->concurrent_streams = NGX_CONF_UNSET_UINT; 324 h2scf->concurrent_streams = NGX_CONF_UNSET_UINT;
315 325
316 h2scf->max_field_size = NGX_CONF_UNSET_SIZE; 326 h2scf->max_field_size = NGX_CONF_UNSET_SIZE;
317 h2scf->max_header_size = NGX_CONF_UNSET_SIZE; 327 h2scf->max_header_size = NGX_CONF_UNSET_SIZE;
318 328
329 h2scf->preread_size = NGX_CONF_UNSET_SIZE;
330
319 h2scf->streams_index_mask = NGX_CONF_UNSET_UINT; 331 h2scf->streams_index_mask = NGX_CONF_UNSET_UINT;
320 332
321 h2scf->recv_timeout = NGX_CONF_UNSET_MSEC; 333 h2scf->recv_timeout = NGX_CONF_UNSET_MSEC;
322 h2scf->idle_timeout = NGX_CONF_UNSET_MSEC; 334 h2scf->idle_timeout = NGX_CONF_UNSET_MSEC;
323 335
339 ngx_conf_merge_size_value(conf->max_field_size, prev->max_field_size, 351 ngx_conf_merge_size_value(conf->max_field_size, prev->max_field_size,
340 4096); 352 4096);
341 ngx_conf_merge_size_value(conf->max_header_size, prev->max_header_size, 353 ngx_conf_merge_size_value(conf->max_header_size, prev->max_header_size,
342 16384); 354 16384);
343 355
356 ngx_conf_merge_size_value(conf->preread_size, prev->preread_size, 65536);
357
344 ngx_conf_merge_uint_value(conf->streams_index_mask, 358 ngx_conf_merge_uint_value(conf->streams_index_mask,
345 prev->streams_index_mask, 32 - 1); 359 prev->streams_index_mask, 32 - 1);
346 360
347 ngx_conf_merge_msec_value(conf->recv_timeout, 361 ngx_conf_merge_msec_value(conf->recv_timeout,
348 prev->recv_timeout, 30000); 362 prev->recv_timeout, 30000);
418 return NGX_CONF_OK; 432 return NGX_CONF_OK;
419 } 433 }
420 434
421 435
422 static char * 436 static char *
437 ngx_http_v2_preread_size(ngx_conf_t *cf, void *post, void *data)
438 {
439 size_t *sp = data;
440
441 if (*sp > NGX_HTTP_V2_MAX_WINDOW) {
442 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
443 "the maximum body preread buffer size is %uz",
444 NGX_HTTP_V2_MAX_WINDOW);
445
446 return NGX_CONF_ERROR;
447 }
448
449 return NGX_CONF_OK;
450 }
451
452
453 static char *
423 ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, void *data) 454 ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, void *data)
424 { 455 {
425 ngx_uint_t *np = data; 456 ngx_uint_t *np = data;
426 457
427 ngx_uint_t mask; 458 ngx_uint_t mask;