Mercurial > hg > nginx
comparison src/http/v2/ngx_http_v2_module.c @ 6566:ce94f07d5082
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
6565:3af0e65a461a | 6566:ce94f07d5082 |
---|---|
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; |