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)