Mercurial > hg > nginx-vendor-1-0
comparison src/http/modules/ngx_http_gzip_filter_module.c @ 454:a8424ffa495c NGINX_0_7_39
nginx 0.7.39
*) Bugfix: large response with SSI might hang, if gzipping was enabled;
the bug had appeared in 0.7.28.
Thanks to Artem Bokhan.
*) Bugfix: a segmentation fault might occur in worker process, if short
static variants are used in a "try_files" directive.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 02 Mar 2009 00:00:00 +0300 |
parents | 6281966854a5 |
children | f39b9e29530d |
comparison
equal
deleted
inserted
replaced
453:9ef0e36f3cd5 | 454:a8424ffa495c |
---|---|
17 | 17 |
18 ngx_hash_t types; | 18 ngx_hash_t types; |
19 | 19 |
20 ngx_bufs_t bufs; | 20 ngx_bufs_t bufs; |
21 | 21 |
22 size_t postpone_gzipping; | |
22 ngx_int_t level; | 23 ngx_int_t level; |
23 size_t wbits; | 24 size_t wbits; |
24 size_t memlevel; | 25 size_t memlevel; |
25 ssize_t min_length; | 26 ssize_t min_length; |
26 | 27 |
82 #endif | 83 #endif |
83 | 84 |
84 | 85 |
85 static void ngx_http_gzip_filter_memory(ngx_http_request_t *r, | 86 static void ngx_http_gzip_filter_memory(ngx_http_request_t *r, |
86 ngx_http_gzip_ctx_t *ctx); | 87 ngx_http_gzip_ctx_t *ctx); |
87 static ngx_int_t ngx_http_gzip_filter_copy_recycled(ngx_http_gzip_ctx_t *ctx, | 88 static ngx_int_t ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx, |
88 ngx_chain_t *in); | 89 ngx_chain_t *in); |
89 static ngx_int_t ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, | 90 static ngx_int_t ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, |
90 ngx_http_gzip_ctx_t *ctx); | 91 ngx_http_gzip_ctx_t *ctx); |
91 static ngx_int_t ngx_http_gzip_filter_gzheader(ngx_http_request_t *r, | 92 static ngx_int_t ngx_http_gzip_filter_gzheader(ngx_http_request_t *r, |
92 ngx_http_gzip_ctx_t *ctx); | 93 ngx_http_gzip_ctx_t *ctx); |
167 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | 168 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
168 ngx_conf_set_size_slot, | 169 ngx_conf_set_size_slot, |
169 NGX_HTTP_LOC_CONF_OFFSET, | 170 NGX_HTTP_LOC_CONF_OFFSET, |
170 offsetof(ngx_http_gzip_conf_t, memlevel), | 171 offsetof(ngx_http_gzip_conf_t, memlevel), |
171 &ngx_http_gzip_hash_p }, | 172 &ngx_http_gzip_hash_p }, |
173 | |
174 { ngx_string("postpone_gzipping"), | |
175 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
176 ngx_conf_set_size_slot, | |
177 NGX_HTTP_LOC_CONF_OFFSET, | |
178 offsetof(ngx_http_gzip_conf_t, postpone_gzipping), | |
179 NULL }, | |
172 | 180 |
173 { ngx_string("gzip_no_buffer"), | 181 { ngx_string("gzip_no_buffer"), |
174 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | 182 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, |
175 ngx_conf_set_flag_slot, | 183 ngx_conf_set_flag_slot, |
176 NGX_HTTP_LOC_CONF_OFFSET, | 184 NGX_HTTP_LOC_CONF_OFFSET, |
255 } | 263 } |
256 | 264 |
257 ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module); | 265 ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module); |
258 | 266 |
259 ctx->request = r; | 267 ctx->request = r; |
260 ctx->buffering = 1; | 268 ctx->buffering = (conf->postpone_gzipping != 0); |
261 | 269 |
262 ngx_http_gzip_filter_memory(r, ctx); | 270 ngx_http_gzip_filter_memory(r, ctx); |
263 | 271 |
264 h = ngx_list_push(&r->headers_out.headers); | 272 h = ngx_list_push(&r->headers_out.headers); |
265 if (h == NULL) { | 273 if (h == NULL) { |
299 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 307 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
300 "http gzip filter"); | 308 "http gzip filter"); |
301 | 309 |
302 if (ctx->buffering) { | 310 if (ctx->buffering) { |
303 | 311 |
312 /* | |
313 * With default memory settings zlib starts to output gzipped data | |
314 * only after it has got about 90K, so it makes sense to allocate | |
315 * zlib memory (200-400K) only after we have enough data to compress. | |
316 * Although we copy buffers, nevertheless for not big responses | |
317 * this allows to allocate zlib memory, to compress and to output | |
318 * the response in one step using hot CPU cache. | |
319 */ | |
320 | |
304 if (in) { | 321 if (in) { |
305 switch (ngx_http_gzip_filter_copy_recycled(ctx, in)) { | 322 switch (ngx_http_gzip_filter_buffer(ctx, in)) { |
306 | 323 |
307 case NGX_OK: | 324 case NGX_OK: |
308 return NGX_OK; | 325 return NGX_OK; |
309 | 326 |
310 case NGX_DONE: | 327 case NGX_DONE: |
325 goto failed; | 342 goto failed; |
326 } | 343 } |
327 } | 344 } |
328 | 345 |
329 if (in) { | 346 if (in) { |
330 if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { | 347 if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { |
331 goto failed; | 348 goto failed; |
332 } | 349 } |
333 } | 350 } |
334 | 351 |
335 if (ctx->nomem) { | 352 if (ctx->nomem) { |
480 ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9)); | 497 ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9)); |
481 } | 498 } |
482 | 499 |
483 | 500 |
484 static ngx_int_t | 501 static ngx_int_t |
485 ngx_http_gzip_filter_copy_recycled(ngx_http_gzip_ctx_t *ctx, ngx_chain_t *in) | 502 ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx, ngx_chain_t *in) |
486 { | 503 { |
487 size_t size, buffered; | 504 size_t size, buffered; |
488 ngx_buf_t *b, *buf; | 505 ngx_buf_t *b, *buf; |
489 ngx_chain_t *cl, **ll; | 506 ngx_chain_t *cl, **ll; |
490 ngx_http_request_t *r; | 507 ngx_http_request_t *r; |
508 ngx_http_gzip_conf_t *conf; | |
491 | 509 |
492 r = ctx->request; | 510 r = ctx->request; |
493 | 511 |
494 r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED; | 512 r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED; |
495 | 513 |
498 | 516 |
499 for (cl = ctx->in; cl; cl = cl->next) { | 517 for (cl = ctx->in; cl; cl = cl->next) { |
500 buffered += cl->buf->last - cl->buf->pos; | 518 buffered += cl->buf->last - cl->buf->pos; |
501 ll = &cl->next; | 519 ll = &cl->next; |
502 } | 520 } |
521 | |
522 conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); | |
503 | 523 |
504 while (in) { | 524 while (in) { |
505 cl = ngx_alloc_chain_link(r->pool); | 525 cl = ngx_alloc_chain_link(r->pool); |
506 if (cl == NULL) { | 526 if (cl == NULL) { |
507 return NGX_ERROR; | 527 return NGX_ERROR; |
510 b = in->buf; | 530 b = in->buf; |
511 | 531 |
512 size = b->last - b->pos; | 532 size = b->last - b->pos; |
513 buffered += size; | 533 buffered += size; |
514 | 534 |
515 if (b->flush || b->last_buf) { | 535 if (b->flush || b->last_buf || buffered > conf->postpone_gzipping) { |
516 ctx->buffering = 0; | 536 ctx->buffering = 0; |
517 | 537 } |
518 } else if (buffered > ctx->allocated / 2) { | 538 |
519 | 539 if (ctx->buffering && size) { |
520 /* | |
521 * With default memory settings zlib starts to output gzipped data | |
522 * only after it has got about 90K, so it makes sense to allocate | |
523 * zlib memory (200-400K) only after we have enough data | |
524 * to compress. Although we copy recycled buffers, nevertheless | |
525 * for responses up to 120K this allows to allocate zlib memory, | |
526 * to compress and to output the response in one step | |
527 * using hot CPU cache. | |
528 */ | |
529 | |
530 ctx->buffering = 0; | |
531 } | |
532 | |
533 if (ctx->buffering && size && b->recycled) { | |
534 | 540 |
535 buf = ngx_create_temp_buf(r->pool, size); | 541 buf = ngx_create_temp_buf(r->pool, size); |
536 if (buf == NULL) { | 542 if (buf == NULL) { |
537 return NGX_ERROR; | 543 return NGX_ERROR; |
538 } | 544 } |
1075 */ | 1081 */ |
1076 | 1082 |
1077 conf->enable = NGX_CONF_UNSET; | 1083 conf->enable = NGX_CONF_UNSET; |
1078 conf->no_buffer = NGX_CONF_UNSET; | 1084 conf->no_buffer = NGX_CONF_UNSET; |
1079 | 1085 |
1086 conf->postpone_gzipping = NGX_CONF_UNSET_SIZE; | |
1080 conf->level = NGX_CONF_UNSET; | 1087 conf->level = NGX_CONF_UNSET; |
1081 conf->wbits = (size_t) NGX_CONF_UNSET; | 1088 conf->wbits = NGX_CONF_UNSET_SIZE; |
1082 conf->memlevel = (size_t) NGX_CONF_UNSET; | 1089 conf->memlevel = NGX_CONF_UNSET_SIZE; |
1083 conf->min_length = NGX_CONF_UNSET; | 1090 conf->min_length = NGX_CONF_UNSET; |
1084 | 1091 |
1085 return conf; | 1092 return conf; |
1086 } | 1093 } |
1087 | 1094 |
1091 { | 1098 { |
1092 ngx_http_gzip_conf_t *prev = parent; | 1099 ngx_http_gzip_conf_t *prev = parent; |
1093 ngx_http_gzip_conf_t *conf = child; | 1100 ngx_http_gzip_conf_t *conf = child; |
1094 | 1101 |
1095 ngx_conf_merge_value(conf->enable, prev->enable, 0); | 1102 ngx_conf_merge_value(conf->enable, prev->enable, 0); |
1103 ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0); | |
1096 | 1104 |
1097 ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, | 1105 ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, |
1098 (128 * 1024) / ngx_pagesize, ngx_pagesize); | 1106 (128 * 1024) / ngx_pagesize, ngx_pagesize); |
1099 | 1107 |
1108 ngx_conf_merge_size_value(conf->postpone_gzipping, prev->postpone_gzipping, | |
1109 0); | |
1100 ngx_conf_merge_value(conf->level, prev->level, 1); | 1110 ngx_conf_merge_value(conf->level, prev->level, 1); |
1101 ngx_conf_merge_size_value(conf->wbits, prev->wbits, MAX_WBITS); | 1111 ngx_conf_merge_size_value(conf->wbits, prev->wbits, MAX_WBITS); |
1102 ngx_conf_merge_size_value(conf->memlevel, prev->memlevel, | 1112 ngx_conf_merge_size_value(conf->memlevel, prev->memlevel, |
1103 MAX_MEM_LEVEL - 1); | 1113 MAX_MEM_LEVEL - 1); |
1104 ngx_conf_merge_value(conf->min_length, prev->min_length, 20); | 1114 ngx_conf_merge_value(conf->min_length, prev->min_length, 20); |
1105 ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0); | |
1106 | 1115 |
1107 if (ngx_http_merge_types(cf, conf->types_keys, &conf->types, | 1116 if (ngx_http_merge_types(cf, conf->types_keys, &conf->types, |
1108 prev->types_keys, &prev->types, | 1117 prev->types_keys, &prev->types, |
1109 ngx_http_html_default_types) | 1118 ngx_http_html_default_types) |
1110 != NGX_OK) | 1119 != NGX_OK) |