Annotation of embedaddon/nginx/src/http/modules/ngx_http_gzip_filter_module.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Igor Sysoev
                      4:  * Copyright (C) Nginx, Inc.
                      5:  */
                      6: 
                      7: 
                      8: #include <ngx_config.h>
                      9: #include <ngx_core.h>
                     10: #include <ngx_http.h>
                     11: 
                     12: #include <zlib.h>
                     13: 
                     14: 
                     15: typedef struct {
                     16:     ngx_flag_t           enable;
                     17:     ngx_flag_t           no_buffer;
                     18: 
                     19:     ngx_hash_t           types;
                     20: 
                     21:     ngx_bufs_t           bufs;
                     22: 
                     23:     size_t               postpone_gzipping;
                     24:     ngx_int_t            level;
                     25:     size_t               wbits;
                     26:     size_t               memlevel;
                     27:     ssize_t              min_length;
                     28: 
                     29:     ngx_array_t         *types_keys;
                     30: } ngx_http_gzip_conf_t;
                     31: 
                     32: 
                     33: typedef struct {
                     34:     ngx_chain_t         *in;
                     35:     ngx_chain_t         *free;
                     36:     ngx_chain_t         *busy;
                     37:     ngx_chain_t         *out;
                     38:     ngx_chain_t        **last_out;
                     39: 
                     40:     ngx_chain_t         *copied;
                     41:     ngx_chain_t         *copy_buf;
                     42: 
                     43:     ngx_buf_t           *in_buf;
                     44:     ngx_buf_t           *out_buf;
                     45:     ngx_int_t            bufs;
                     46: 
                     47:     void                *preallocated;
                     48:     char                *free_mem;
                     49:     ngx_uint_t           allocated;
                     50: 
                     51:     int                  wbits;
                     52:     int                  memlevel;
                     53: 
                     54:     unsigned             flush:4;
                     55:     unsigned             redo:1;
                     56:     unsigned             done:1;
                     57:     unsigned             nomem:1;
                     58:     unsigned             gzheader:1;
                     59:     unsigned             buffering:1;
                     60: 
                     61:     size_t               zin;
                     62:     size_t               zout;
                     63: 
                     64:     uint32_t             crc32;
                     65:     z_stream             zstream;
                     66:     ngx_http_request_t  *request;
                     67: } ngx_http_gzip_ctx_t;
                     68: 
                     69: 
                     70: #if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
                     71: 
                     72: struct gztrailer {
                     73:     uint32_t  crc32;
                     74:     uint32_t  zlen;
                     75: };
                     76: 
                     77: #else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */
                     78: 
                     79: struct gztrailer {
                     80:     u_char  crc32[4];
                     81:     u_char  zlen[4];
                     82: };
                     83: 
                     84: #endif
                     85: 
                     86: 
                     87: static void ngx_http_gzip_filter_memory(ngx_http_request_t *r,
                     88:     ngx_http_gzip_ctx_t *ctx);
                     89: static ngx_int_t ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx,
                     90:     ngx_chain_t *in);
                     91: static ngx_int_t ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r,
                     92:     ngx_http_gzip_ctx_t *ctx);
                     93: static ngx_int_t ngx_http_gzip_filter_gzheader(ngx_http_request_t *r,
                     94:     ngx_http_gzip_ctx_t *ctx);
                     95: static ngx_int_t ngx_http_gzip_filter_add_data(ngx_http_request_t *r,
                     96:     ngx_http_gzip_ctx_t *ctx);
                     97: static ngx_int_t ngx_http_gzip_filter_get_buf(ngx_http_request_t *r,
                     98:     ngx_http_gzip_ctx_t *ctx);
                     99: static ngx_int_t ngx_http_gzip_filter_deflate(ngx_http_request_t *r,
                    100:     ngx_http_gzip_ctx_t *ctx);
                    101: static ngx_int_t ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r,
                    102:     ngx_http_gzip_ctx_t *ctx);
                    103: 
                    104: static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items,
                    105:     u_int size);
                    106: static void ngx_http_gzip_filter_free(void *opaque, void *address);
                    107: static void ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r,
                    108:     ngx_http_gzip_ctx_t *ctx);
                    109: 
                    110: static ngx_int_t ngx_http_gzip_add_variables(ngx_conf_t *cf);
                    111: static ngx_int_t ngx_http_gzip_ratio_variable(ngx_http_request_t *r,
                    112:     ngx_http_variable_value_t *v, uintptr_t data);
                    113: 
                    114: static ngx_int_t ngx_http_gzip_filter_init(ngx_conf_t *cf);
                    115: static void *ngx_http_gzip_create_conf(ngx_conf_t *cf);
                    116: static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf,
                    117:     void *parent, void *child);
                    118: static char *ngx_http_gzip_window(ngx_conf_t *cf, void *post, void *data);
                    119: static char *ngx_http_gzip_hash(ngx_conf_t *cf, void *post, void *data);
                    120: 
                    121: 
                    122: static ngx_conf_num_bounds_t  ngx_http_gzip_comp_level_bounds = {
                    123:     ngx_conf_check_num_bounds, 1, 9
                    124: };
                    125: 
                    126: static ngx_conf_post_handler_pt  ngx_http_gzip_window_p = ngx_http_gzip_window;
                    127: static ngx_conf_post_handler_pt  ngx_http_gzip_hash_p = ngx_http_gzip_hash;
                    128: 
                    129: 
                    130: static ngx_command_t  ngx_http_gzip_filter_commands[] = {
                    131: 
                    132:     { ngx_string("gzip"),
                    133:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                    134:                         |NGX_CONF_FLAG,
                    135:       ngx_conf_set_flag_slot,
                    136:       NGX_HTTP_LOC_CONF_OFFSET,
                    137:       offsetof(ngx_http_gzip_conf_t, enable),
                    138:       NULL },
                    139: 
                    140:     { ngx_string("gzip_buffers"),
                    141:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
                    142:       ngx_conf_set_bufs_slot,
                    143:       NGX_HTTP_LOC_CONF_OFFSET,
                    144:       offsetof(ngx_http_gzip_conf_t, bufs),
                    145:       NULL },
                    146: 
                    147:     { ngx_string("gzip_types"),
                    148:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
                    149:       ngx_http_types_slot,
                    150:       NGX_HTTP_LOC_CONF_OFFSET,
                    151:       offsetof(ngx_http_gzip_conf_t, types_keys),
                    152:       &ngx_http_html_default_types[0] },
                    153: 
                    154:     { ngx_string("gzip_comp_level"),
                    155:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    156:       ngx_conf_set_num_slot,
                    157:       NGX_HTTP_LOC_CONF_OFFSET,
                    158:       offsetof(ngx_http_gzip_conf_t, level),
                    159:       &ngx_http_gzip_comp_level_bounds },
                    160: 
                    161:     { ngx_string("gzip_window"),
                    162:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    163:       ngx_conf_set_size_slot,
                    164:       NGX_HTTP_LOC_CONF_OFFSET,
                    165:       offsetof(ngx_http_gzip_conf_t, wbits),
                    166:       &ngx_http_gzip_window_p },
                    167: 
                    168:     { ngx_string("gzip_hash"),
                    169:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    170:       ngx_conf_set_size_slot,
                    171:       NGX_HTTP_LOC_CONF_OFFSET,
                    172:       offsetof(ngx_http_gzip_conf_t, memlevel),
                    173:       &ngx_http_gzip_hash_p },
                    174: 
                    175:     { ngx_string("postpone_gzipping"),
                    176:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    177:       ngx_conf_set_size_slot,
                    178:       NGX_HTTP_LOC_CONF_OFFSET,
                    179:       offsetof(ngx_http_gzip_conf_t, postpone_gzipping),
                    180:       NULL },
                    181: 
                    182:     { ngx_string("gzip_no_buffer"),
                    183:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
                    184:       ngx_conf_set_flag_slot,
                    185:       NGX_HTTP_LOC_CONF_OFFSET,
                    186:       offsetof(ngx_http_gzip_conf_t, no_buffer),
                    187:       NULL },
                    188: 
                    189:     { ngx_string("gzip_min_length"),
                    190:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    191:       ngx_conf_set_size_slot,
                    192:       NGX_HTTP_LOC_CONF_OFFSET,
                    193:       offsetof(ngx_http_gzip_conf_t, min_length),
                    194:       NULL },
                    195: 
                    196:       ngx_null_command
                    197: };
                    198: 
                    199: 
                    200: static ngx_http_module_t  ngx_http_gzip_filter_module_ctx = {
                    201:     ngx_http_gzip_add_variables,           /* preconfiguration */
                    202:     ngx_http_gzip_filter_init,             /* postconfiguration */
                    203: 
                    204:     NULL,                                  /* create main configuration */
                    205:     NULL,                                  /* init main configuration */
                    206: 
                    207:     NULL,                                  /* create server configuration */
                    208:     NULL,                                  /* merge server configuration */
                    209: 
                    210:     ngx_http_gzip_create_conf,             /* create location configuration */
                    211:     ngx_http_gzip_merge_conf               /* merge location configuration */
                    212: };
                    213: 
                    214: 
                    215: ngx_module_t  ngx_http_gzip_filter_module = {
                    216:     NGX_MODULE_V1,
                    217:     &ngx_http_gzip_filter_module_ctx,      /* module context */
                    218:     ngx_http_gzip_filter_commands,         /* module directives */
                    219:     NGX_HTTP_MODULE,                       /* module type */
                    220:     NULL,                                  /* init master */
                    221:     NULL,                                  /* init module */
                    222:     NULL,                                  /* init process */
                    223:     NULL,                                  /* init thread */
                    224:     NULL,                                  /* exit thread */
                    225:     NULL,                                  /* exit process */
                    226:     NULL,                                  /* exit master */
                    227:     NGX_MODULE_V1_PADDING
                    228: };
                    229: 
                    230: 
                    231: static ngx_str_t  ngx_http_gzip_ratio = ngx_string("gzip_ratio");
                    232: 
                    233: static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
                    234: static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
                    235: 
                    236: 
                    237: static ngx_int_t
                    238: ngx_http_gzip_header_filter(ngx_http_request_t *r)
                    239: {
                    240:     ngx_table_elt_t       *h;
                    241:     ngx_http_gzip_ctx_t   *ctx;
                    242:     ngx_http_gzip_conf_t  *conf;
                    243: 
                    244:     conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
                    245: 
                    246:     if (!conf->enable
                    247:         || (r->headers_out.status != NGX_HTTP_OK
                    248:             && r->headers_out.status != NGX_HTTP_FORBIDDEN
                    249:             && r->headers_out.status != NGX_HTTP_NOT_FOUND)
                    250:         || (r->headers_out.content_encoding
                    251:             && r->headers_out.content_encoding->value.len)
                    252:         || (r->headers_out.content_length_n != -1
                    253:             && r->headers_out.content_length_n < conf->min_length)
                    254:         || ngx_http_test_content_type(r, &conf->types) == NULL
                    255:         || r->header_only)
                    256:     {
                    257:         return ngx_http_next_header_filter(r);
                    258:     }
                    259: 
                    260:     r->gzip_vary = 1;
                    261: 
                    262: #if (NGX_HTTP_DEGRADATION)
                    263:     {
                    264:     ngx_http_core_loc_conf_t  *clcf;
                    265: 
                    266:     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
                    267: 
                    268:     if (clcf->gzip_disable_degradation && ngx_http_degraded(r)) {
                    269:         return ngx_http_next_header_filter(r);
                    270:     }
                    271:     }
                    272: #endif
                    273: 
                    274:     if (!r->gzip_tested) {
                    275:         if (ngx_http_gzip_ok(r) != NGX_OK) {
                    276:             return ngx_http_next_header_filter(r);
                    277:         }
                    278: 
                    279:     } else if (!r->gzip_ok) {
                    280:         return ngx_http_next_header_filter(r);
                    281:     }
                    282: 
                    283:     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gzip_ctx_t));
                    284:     if (ctx == NULL) {
                    285:         return NGX_ERROR;
                    286:     }
                    287: 
                    288:     ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module);
                    289: 
                    290:     ctx->request = r;
                    291:     ctx->buffering = (conf->postpone_gzipping != 0);
                    292: 
                    293:     ngx_http_gzip_filter_memory(r, ctx);
                    294: 
                    295:     h = ngx_list_push(&r->headers_out.headers);
                    296:     if (h == NULL) {
                    297:         return NGX_ERROR;
                    298:     }
                    299: 
                    300:     h->hash = 1;
                    301:     ngx_str_set(&h->key, "Content-Encoding");
                    302:     ngx_str_set(&h->value, "gzip");
                    303:     r->headers_out.content_encoding = h;
                    304: 
                    305:     r->main_filter_need_in_memory = 1;
                    306: 
                    307:     ngx_http_clear_content_length(r);
                    308:     ngx_http_clear_accept_ranges(r);
                    309:     ngx_http_clear_etag(r);
                    310: 
                    311:     return ngx_http_next_header_filter(r);
                    312: }
                    313: 
                    314: 
                    315: static ngx_int_t
                    316: ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
                    317: {
                    318:     int                   rc;
                    319:     ngx_chain_t          *cl;
                    320:     ngx_http_gzip_ctx_t  *ctx;
                    321: 
                    322:     ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module);
                    323: 
                    324:     if (ctx == NULL || ctx->done || r->header_only) {
                    325:         return ngx_http_next_body_filter(r, in);
                    326:     }
                    327: 
                    328:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    329:                    "http gzip filter");
                    330: 
                    331:     if (ctx->buffering) {
                    332: 
                    333:         /*
                    334:          * With default memory settings zlib starts to output gzipped data
                    335:          * only after it has got about 90K, so it makes sense to allocate
                    336:          * zlib memory (200-400K) only after we have enough data to compress.
                    337:          * Although we copy buffers, nevertheless for not big responses
                    338:          * this allows to allocate zlib memory, to compress and to output
                    339:          * the response in one step using hot CPU cache.
                    340:          */
                    341: 
                    342:         if (in) {
                    343:             switch (ngx_http_gzip_filter_buffer(ctx, in)) {
                    344: 
                    345:             case NGX_OK:
                    346:                 return NGX_OK;
                    347: 
                    348:             case NGX_DONE:
                    349:                 in = NULL;
                    350:                 break;
                    351: 
                    352:             default:  /* NGX_ERROR */
                    353:                 goto failed;
                    354:             }
                    355: 
                    356:         } else {
                    357:             ctx->buffering = 0;
                    358:         }
                    359:     }
                    360: 
                    361:     if (ctx->preallocated == NULL) {
                    362:         if (ngx_http_gzip_filter_deflate_start(r, ctx) != NGX_OK) {
                    363:             goto failed;
                    364:         }
                    365:     }
                    366: 
                    367:     if (in) {
                    368:         if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
                    369:             goto failed;
                    370:         }
                    371:     }
                    372: 
                    373:     if (ctx->nomem) {
                    374: 
                    375:         /* flush busy buffers */
                    376: 
                    377:         if (ngx_http_next_body_filter(r, NULL) == NGX_ERROR) {
                    378:             goto failed;
                    379:         }
                    380: 
                    381:         cl = NULL;
                    382: 
                    383:         ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &cl,
                    384:                                 (ngx_buf_tag_t) &ngx_http_gzip_filter_module);
                    385:         ctx->nomem = 0;
                    386:     }
                    387: 
                    388:     for ( ;; ) {
                    389: 
                    390:         /* cycle while we can write to a client */
                    391: 
                    392:         for ( ;; ) {
                    393: 
                    394:             /* cycle while there is data to feed zlib and ... */
                    395: 
                    396:             rc = ngx_http_gzip_filter_add_data(r, ctx);
                    397: 
                    398:             if (rc == NGX_DECLINED) {
                    399:                 break;
                    400:             }
                    401: 
                    402:             if (rc == NGX_AGAIN) {
                    403:                 continue;
                    404:             }
                    405: 
                    406: 
                    407:             /* ... there are buffers to write zlib output */
                    408: 
                    409:             rc = ngx_http_gzip_filter_get_buf(r, ctx);
                    410: 
                    411:             if (rc == NGX_DECLINED) {
                    412:                 break;
                    413:             }
                    414: 
                    415:             if (rc == NGX_ERROR) {
                    416:                 goto failed;
                    417:             }
                    418: 
                    419: 
                    420:             rc = ngx_http_gzip_filter_deflate(r, ctx);
                    421: 
                    422:             if (rc == NGX_OK) {
                    423:                 break;
                    424:             }
                    425: 
                    426:             if (rc == NGX_ERROR) {
                    427:                 goto failed;
                    428:             }
                    429: 
                    430:             /* rc == NGX_AGAIN */
                    431:         }
                    432: 
                    433:         if (ctx->out == NULL) {
                    434:             ngx_http_gzip_filter_free_copy_buf(r, ctx);
                    435: 
                    436:             return ctx->busy ? NGX_AGAIN : NGX_OK;
                    437:         }
                    438: 
                    439:         if (!ctx->gzheader) {
                    440:             if (ngx_http_gzip_filter_gzheader(r, ctx) != NGX_OK) {
                    441:                 goto failed;
                    442:             }
                    443:         }
                    444: 
                    445:         rc = ngx_http_next_body_filter(r, ctx->out);
                    446: 
                    447:         if (rc == NGX_ERROR) {
                    448:             goto failed;
                    449:         }
                    450: 
                    451:         ngx_http_gzip_filter_free_copy_buf(r, ctx);
                    452: 
                    453:         ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &ctx->out,
                    454:                                 (ngx_buf_tag_t) &ngx_http_gzip_filter_module);
                    455:         ctx->last_out = &ctx->out;
                    456: 
                    457:         ctx->nomem = 0;
                    458: 
                    459:         if (ctx->done) {
                    460:             return rc;
                    461:         }
                    462:     }
                    463: 
                    464:     /* unreachable */
                    465: 
                    466: failed:
                    467: 
                    468:     ctx->done = 1;
                    469: 
                    470:     if (ctx->preallocated) {
                    471:         deflateEnd(&ctx->zstream);
                    472: 
                    473:         ngx_pfree(r->pool, ctx->preallocated);
                    474:     }
                    475: 
                    476:     ngx_http_gzip_filter_free_copy_buf(r, ctx);
                    477: 
                    478:     return NGX_ERROR;
                    479: }
                    480: 
                    481: 
                    482: static void
                    483: ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
                    484: {
                    485:     int                    wbits, memlevel;
                    486:     ngx_http_gzip_conf_t  *conf;
                    487: 
                    488:     conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
                    489: 
                    490:     wbits = conf->wbits;
                    491:     memlevel = conf->memlevel;
                    492: 
                    493:     if (r->headers_out.content_length_n > 0) {
                    494: 
                    495:         /* the actual zlib window size is smaller by 262 bytes */
                    496: 
                    497:         while (r->headers_out.content_length_n < ((1 << (wbits - 1)) - 262)) {
                    498:             wbits--;
                    499:             memlevel--;
                    500:         }
                    501: 
                    502:         if (memlevel < 1) {
                    503:             memlevel = 1;
                    504:         }
                    505:     }
                    506: 
                    507:     ctx->wbits = wbits;
                    508:     ctx->memlevel = memlevel;
                    509: 
                    510:     /*
                    511:      * We preallocate a memory for zlib in one buffer (200K-400K), this
                    512:      * decreases a number of malloc() and free() calls and also probably
                    513:      * decreases a number of syscalls (sbrk()/mmap() and so on).
                    514:      * Besides we free the memory as soon as a gzipping will complete
                    515:      * and do not wait while a whole response will be sent to a client.
                    516:      *
                    517:      * 8K is for zlib deflate_state, it takes
                    518:      *  *) 5816 bytes on i386 and sparc64 (32-bit mode)
                    519:      *  *) 5920 bytes on amd64 and sparc64
                    520:      */
                    521: 
                    522:     ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9));
                    523: }
                    524: 
                    525: 
                    526: static ngx_int_t
                    527: ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx, ngx_chain_t *in)
                    528: {
                    529:     size_t                 size, buffered;
                    530:     ngx_buf_t             *b, *buf;
                    531:     ngx_chain_t           *cl, **ll;
                    532:     ngx_http_request_t    *r;
                    533:     ngx_http_gzip_conf_t  *conf;
                    534: 
                    535:     r = ctx->request;
                    536: 
                    537:     r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED;
                    538: 
                    539:     buffered = 0;
                    540:     ll = &ctx->in;
                    541: 
                    542:     for (cl = ctx->in; cl; cl = cl->next) {
                    543:         buffered += cl->buf->last - cl->buf->pos;
                    544:         ll = &cl->next;
                    545:     }
                    546: 
                    547:     conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
                    548: 
                    549:     while (in) {
                    550:         cl = ngx_alloc_chain_link(r->pool);
                    551:         if (cl == NULL) {
                    552:             return NGX_ERROR;
                    553:         }
                    554: 
                    555:         b = in->buf;
                    556: 
                    557:         size = b->last - b->pos;
                    558:         buffered += size;
                    559: 
                    560:         if (b->flush || b->last_buf || buffered > conf->postpone_gzipping) {
                    561:             ctx->buffering = 0;
                    562:         }
                    563: 
                    564:         if (ctx->buffering && size) {
                    565: 
                    566:             buf = ngx_create_temp_buf(r->pool, size);
                    567:             if (buf == NULL) {
                    568:                 return NGX_ERROR;
                    569:             }
                    570: 
                    571:             buf->last = ngx_cpymem(buf->pos, b->pos, size);
                    572:             b->pos = b->last;
                    573: 
                    574:             buf->last_buf = b->last_buf;
                    575:             buf->tag = (ngx_buf_tag_t) &ngx_http_gzip_filter_module;
                    576: 
                    577:             cl->buf = buf;
                    578: 
                    579:         } else {
                    580:             cl->buf = b;
                    581:         }
                    582: 
                    583:         *ll = cl;
                    584:         ll = &cl->next;
                    585:         in = in->next;
                    586:     }
                    587: 
                    588:     *ll = NULL;
                    589: 
                    590:     return ctx->buffering ? NGX_OK : NGX_DONE;
                    591: }
                    592: 
                    593: 
                    594: static ngx_int_t
                    595: ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r,
                    596:     ngx_http_gzip_ctx_t *ctx)
                    597: {
                    598:     int                    rc;
                    599:     ngx_http_gzip_conf_t  *conf;
                    600: 
                    601:     conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
                    602: 
                    603:     ctx->preallocated = ngx_palloc(r->pool, ctx->allocated);
                    604:     if (ctx->preallocated == NULL) {
                    605:         return NGX_ERROR;
                    606:     }
                    607: 
                    608:     ctx->free_mem = ctx->preallocated;
                    609: 
                    610:     ctx->zstream.zalloc = ngx_http_gzip_filter_alloc;
                    611:     ctx->zstream.zfree = ngx_http_gzip_filter_free;
                    612:     ctx->zstream.opaque = ctx;
                    613: 
                    614:     rc = deflateInit2(&ctx->zstream, (int) conf->level, Z_DEFLATED,
                    615:                       - ctx->wbits, ctx->memlevel, Z_DEFAULT_STRATEGY);
                    616: 
                    617:     if (rc != Z_OK) {
                    618:         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                    619:                       "deflateInit2() failed: %d", rc);
                    620:         return NGX_ERROR;
                    621:     }
                    622: 
                    623:     r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED;
                    624: 
                    625:     ctx->last_out = &ctx->out;
                    626:     ctx->crc32 = crc32(0L, Z_NULL, 0);
                    627:     ctx->flush = Z_NO_FLUSH;
                    628: 
                    629:     return NGX_OK;
                    630: }
                    631: 
                    632: 
                    633: static ngx_int_t
                    634: ngx_http_gzip_filter_gzheader(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
                    635: {
                    636:     ngx_buf_t      *b;
                    637:     ngx_chain_t    *cl;
                    638:     static u_char  gzheader[10] =
                    639:                                { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
                    640: 
                    641:     b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
                    642:     if (b == NULL) {
                    643:         return NGX_ERROR;
                    644:     }
                    645: 
                    646:     b->memory = 1;
                    647:     b->pos = gzheader;
                    648:     b->last = b->pos + 10;
                    649: 
                    650:     cl = ngx_alloc_chain_link(r->pool);
                    651:     if (cl == NULL) {
                    652:         return NGX_ERROR;
                    653:     }
                    654: 
                    655:     cl->buf = b;
                    656:     cl->next = ctx->out;
                    657:     ctx->out = cl;
                    658: 
                    659:     ctx->gzheader = 1;
                    660: 
                    661:     return NGX_OK;
                    662: }
                    663: 
                    664: 
                    665: static ngx_int_t
                    666: ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
                    667: {
                    668:     if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) {
                    669:         return NGX_OK;
                    670:     }
                    671: 
                    672:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    673:                    "gzip in: %p", ctx->in);
                    674: 
                    675:     if (ctx->in == NULL) {
                    676:         return NGX_DECLINED;
                    677:     }
                    678: 
                    679:     if (ctx->copy_buf) {
                    680: 
                    681:         /*
                    682:          * to avoid CPU cache trashing we do not free() just quit buf,
                    683:          * but postpone free()ing after zlib compressing and data output
                    684:          */
                    685: 
                    686:         ctx->copy_buf->next = ctx->copied;
                    687:         ctx->copied = ctx->copy_buf;
                    688:         ctx->copy_buf = NULL;
                    689:     }
                    690: 
                    691:     ctx->in_buf = ctx->in->buf;
                    692: 
                    693:     if (ctx->in_buf->tag == (ngx_buf_tag_t) &ngx_http_gzip_filter_module) {
                    694:         ctx->copy_buf = ctx->in;
                    695:     }
                    696: 
                    697:     ctx->in = ctx->in->next;
                    698: 
                    699:     ctx->zstream.next_in = ctx->in_buf->pos;
                    700:     ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos;
                    701: 
                    702:     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    703:                    "gzip in_buf:%p ni:%p ai:%ud",
                    704:                    ctx->in_buf,
                    705:                    ctx->zstream.next_in, ctx->zstream.avail_in);
                    706: 
                    707:     if (ctx->in_buf->last_buf) {
                    708:         ctx->flush = Z_FINISH;
                    709: 
                    710:     } else if (ctx->in_buf->flush) {
                    711:         ctx->flush = Z_SYNC_FLUSH;
                    712:     }
                    713: 
                    714:     if (ctx->zstream.avail_in) {
                    715: 
                    716:         ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in,
                    717:                            ctx->zstream.avail_in);
                    718: 
                    719:     } else if (ctx->flush == Z_NO_FLUSH) {
                    720:         return NGX_AGAIN;
                    721:     }
                    722: 
                    723:     return NGX_OK;
                    724: }
                    725: 
                    726: 
                    727: static ngx_int_t
                    728: ngx_http_gzip_filter_get_buf(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
                    729: {
                    730:     ngx_http_gzip_conf_t  *conf;
                    731: 
                    732:     if (ctx->zstream.avail_out) {
                    733:         return NGX_OK;
                    734:     }
                    735: 
                    736:     conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
                    737: 
                    738:     if (ctx->free) {
                    739:         ctx->out_buf = ctx->free->buf;
                    740:         ctx->free = ctx->free->next;
                    741: 
                    742:     } else if (ctx->bufs < conf->bufs.num) {
                    743: 
                    744:         ctx->out_buf = ngx_create_temp_buf(r->pool, conf->bufs.size);
                    745:         if (ctx->out_buf == NULL) {
                    746:             return NGX_ERROR;
                    747:         }
                    748: 
                    749:         ctx->out_buf->tag = (ngx_buf_tag_t) &ngx_http_gzip_filter_module;
                    750:         ctx->out_buf->recycled = 1;
                    751:         ctx->bufs++;
                    752: 
                    753:     } else {
                    754:         ctx->nomem = 1;
                    755:         return NGX_DECLINED;
                    756:     }
                    757: 
                    758:     ctx->zstream.next_out = ctx->out_buf->pos;
                    759:     ctx->zstream.avail_out = conf->bufs.size;
                    760: 
                    761:     return NGX_OK;
                    762: }
                    763: 
                    764: 
                    765: static ngx_int_t
                    766: ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
                    767: {
                    768:     int                    rc;
                    769:     ngx_buf_t             *b;
                    770:     ngx_chain_t           *cl;
                    771:     ngx_http_gzip_conf_t  *conf;
                    772: 
                    773:     ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    774:                  "deflate in: ni:%p no:%p ai:%ud ao:%ud fl:%d redo:%d",
                    775:                  ctx->zstream.next_in, ctx->zstream.next_out,
                    776:                  ctx->zstream.avail_in, ctx->zstream.avail_out,
                    777:                  ctx->flush, ctx->redo);
                    778: 
                    779:     rc = deflate(&ctx->zstream, ctx->flush);
                    780: 
                    781:     if (rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) {
                    782:         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                    783:                       "deflate() failed: %d, %d", ctx->flush, rc);
                    784:         return NGX_ERROR;
                    785:     }
                    786: 
                    787:     ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    788:                    "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
                    789:                    ctx->zstream.next_in, ctx->zstream.next_out,
                    790:                    ctx->zstream.avail_in, ctx->zstream.avail_out,
                    791:                    rc);
                    792: 
                    793:     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    794:                    "gzip in_buf:%p pos:%p",
                    795:                    ctx->in_buf, ctx->in_buf->pos);
                    796: 
                    797:     if (ctx->zstream.next_in) {
                    798:         ctx->in_buf->pos = ctx->zstream.next_in;
                    799: 
                    800:         if (ctx->zstream.avail_in == 0) {
                    801:             ctx->zstream.next_in = NULL;
                    802:         }
                    803:     }
                    804: 
                    805:     ctx->out_buf->last = ctx->zstream.next_out;
                    806: 
                    807:     if (ctx->zstream.avail_out == 0) {
                    808: 
                    809:         /* zlib wants to output some more gzipped data */
                    810: 
                    811:         cl = ngx_alloc_chain_link(r->pool);
                    812:         if (cl == NULL) {
                    813:             return NGX_ERROR;
                    814:         }
                    815: 
                    816:         cl->buf = ctx->out_buf;
                    817:         cl->next = NULL;
                    818:         *ctx->last_out = cl;
                    819:         ctx->last_out = &cl->next;
                    820: 
                    821:         ctx->redo = 1;
                    822: 
                    823:         return NGX_AGAIN;
                    824:     }
                    825: 
                    826:     ctx->redo = 0;
                    827: 
                    828:     if (ctx->flush == Z_SYNC_FLUSH) {
                    829: 
                    830:         ctx->flush = Z_NO_FLUSH;
                    831: 
                    832:         cl = ngx_alloc_chain_link(r->pool);
                    833:         if (cl == NULL) {
                    834:             return NGX_ERROR;
                    835:         }
                    836: 
                    837:         b = ctx->out_buf;
                    838: 
                    839:         if (ngx_buf_size(b) == 0) {
                    840: 
                    841:             b = ngx_calloc_buf(ctx->request->pool);
                    842:             if (b == NULL) {
                    843:                 return NGX_ERROR;
                    844:             }
                    845: 
                    846:         } else {
                    847:             ctx->zstream.avail_out = 0;
                    848:         }
                    849: 
                    850:         b->flush = 1;
                    851: 
                    852:         cl->buf = b;
                    853:         cl->next = NULL;
                    854:         *ctx->last_out = cl;
                    855:         ctx->last_out = &cl->next;
                    856: 
                    857:         return NGX_OK;
                    858:     }
                    859: 
                    860:     if (rc == Z_STREAM_END) {
                    861: 
                    862:         if (ngx_http_gzip_filter_deflate_end(r, ctx) != NGX_OK) {
                    863:             return NGX_ERROR;
                    864:         }
                    865: 
                    866:         return NGX_OK;
                    867:     }
                    868: 
                    869:     conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
                    870: 
                    871:     if (conf->no_buffer && ctx->in == NULL) {
                    872: 
                    873:         cl = ngx_alloc_chain_link(r->pool);
                    874:         if (cl == NULL) {
                    875:             return NGX_ERROR;
                    876:         }
                    877: 
                    878:         cl->buf = ctx->out_buf;
                    879:         cl->next = NULL;
                    880:         *ctx->last_out = cl;
                    881:         ctx->last_out = &cl->next;
                    882: 
                    883:         return NGX_OK;
                    884:     }
                    885: 
                    886:     return NGX_AGAIN;
                    887: }
                    888: 
                    889: 
                    890: static ngx_int_t
                    891: ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r,
                    892:     ngx_http_gzip_ctx_t *ctx)
                    893: {
                    894:     int                rc;
                    895:     ngx_buf_t         *b;
                    896:     ngx_chain_t       *cl;
                    897:     struct gztrailer  *trailer;
                    898: 
                    899:     ctx->zin = ctx->zstream.total_in;
                    900:     ctx->zout = 10 + ctx->zstream.total_out + 8;
                    901: 
                    902:     rc = deflateEnd(&ctx->zstream);
                    903: 
                    904:     if (rc != Z_OK) {
                    905:         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                    906:                       "deflateEnd() failed: %d", rc);
                    907:         return NGX_ERROR;
                    908:     }
                    909: 
                    910:     ngx_pfree(r->pool, ctx->preallocated);
                    911: 
                    912:     cl = ngx_alloc_chain_link(r->pool);
                    913:     if (cl == NULL) {
                    914:         return NGX_ERROR;
                    915:     }
                    916: 
                    917:     cl->buf = ctx->out_buf;
                    918:     cl->next = NULL;
                    919:     *ctx->last_out = cl;
                    920:     ctx->last_out = &cl->next;
                    921: 
                    922:     if (ctx->zstream.avail_out >= 8) {
                    923:         trailer = (struct gztrailer *) ctx->out_buf->last;
                    924:         ctx->out_buf->last += 8;
                    925:         ctx->out_buf->last_buf = 1;
                    926: 
                    927:     } else {
                    928:         b = ngx_create_temp_buf(r->pool, 8);
                    929:         if (b == NULL) {
                    930:             return NGX_ERROR;
                    931:         }
                    932: 
                    933:         b->last_buf = 1;
                    934: 
                    935:         cl = ngx_alloc_chain_link(r->pool);
                    936:         if (cl == NULL) {
                    937:             return NGX_ERROR;
                    938:         }
                    939: 
                    940:         cl->buf = b;
                    941:         cl->next = NULL;
                    942:         *ctx->last_out = cl;
                    943:         ctx->last_out = &cl->next;
                    944:         trailer = (struct gztrailer *) b->pos;
                    945:         b->last += 8;
                    946:     }
                    947: 
                    948: #if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
                    949: 
                    950:     trailer->crc32 = ctx->crc32;
                    951:     trailer->zlen = ctx->zin;
                    952: 
                    953: #else
                    954: 
                    955:     trailer->crc32[0] = (u_char) (ctx->crc32 & 0xff);
                    956:     trailer->crc32[1] = (u_char) ((ctx->crc32 >> 8) & 0xff);
                    957:     trailer->crc32[2] = (u_char) ((ctx->crc32 >> 16) & 0xff);
                    958:     trailer->crc32[3] = (u_char) ((ctx->crc32 >> 24) & 0xff);
                    959: 
                    960:     trailer->zlen[0] = (u_char) (ctx->zin & 0xff);
                    961:     trailer->zlen[1] = (u_char) ((ctx->zin >> 8) & 0xff);
                    962:     trailer->zlen[2] = (u_char) ((ctx->zin >> 16) & 0xff);
                    963:     trailer->zlen[3] = (u_char) ((ctx->zin >> 24) & 0xff);
                    964: 
                    965: #endif
                    966: 
                    967:     ctx->zstream.avail_in = 0;
                    968:     ctx->zstream.avail_out = 0;
                    969: 
                    970:     ctx->done = 1;
                    971: 
                    972:     r->connection->buffered &= ~NGX_HTTP_GZIP_BUFFERED;
                    973: 
                    974:     return NGX_OK;
                    975: }
                    976: 
                    977: 
                    978: static void *
                    979: ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size)
                    980: {
                    981:     ngx_http_gzip_ctx_t *ctx = opaque;
                    982: 
                    983:     void        *p;
                    984:     ngx_uint_t   alloc;
                    985: 
                    986:     alloc = items * size;
                    987: 
                    988:     if (alloc % 512 != 0 && alloc < 8192) {
                    989: 
                    990:         /*
                    991:          * The zlib deflate_state allocation, it takes about 6K,
                    992:          * we allocate 8K.  Other allocations are divisible by 512.
                    993:          */
                    994: 
                    995:         alloc = 8192;
                    996:     }
                    997: 
                    998:     if (alloc <= ctx->allocated) {
                    999:         p = ctx->free_mem;
                   1000:         ctx->free_mem += alloc;
                   1001:         ctx->allocated -= alloc;
                   1002: 
                   1003:         ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0,
                   1004:                        "gzip alloc: n:%ud s:%ud a:%ud p:%p",
                   1005:                        items, size, alloc, p);
                   1006: 
                   1007:         return p;
                   1008:     }
                   1009: 
                   1010:     ngx_log_error(NGX_LOG_ALERT, ctx->request->connection->log, 0,
                   1011:                   "gzip filter failed to use preallocated memory: %ud of %ud",
                   1012:                   items * size, ctx->allocated);
                   1013: 
                   1014:     p = ngx_palloc(ctx->request->pool, items * size);
                   1015: 
                   1016:     return p;
                   1017: }
                   1018: 
                   1019: 
                   1020: static void
                   1021: ngx_http_gzip_filter_free(void *opaque, void *address)
                   1022: {
                   1023: #if 0
                   1024:     ngx_http_gzip_ctx_t *ctx = opaque;
                   1025: 
                   1026:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0,
                   1027:                    "gzip free: %p", address);
                   1028: #endif
                   1029: }
                   1030: 
                   1031: 
                   1032: static void
                   1033: ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r,
                   1034:     ngx_http_gzip_ctx_t *ctx)
                   1035: {
                   1036:     ngx_chain_t  *cl;
                   1037: 
                   1038:     for (cl = ctx->copied; cl; cl = cl->next) {
                   1039:         ngx_pfree(r->pool, cl->buf->start);
                   1040:     }
                   1041: 
                   1042:     ctx->copied = NULL;
                   1043: }
                   1044: 
                   1045: 
                   1046: static ngx_int_t
                   1047: ngx_http_gzip_add_variables(ngx_conf_t *cf)
                   1048: {
                   1049:     ngx_http_variable_t  *var;
                   1050: 
                   1051:     var = ngx_http_add_variable(cf, &ngx_http_gzip_ratio, NGX_HTTP_VAR_NOHASH);
                   1052:     if (var == NULL) {
                   1053:         return NGX_ERROR;
                   1054:     }
                   1055: 
                   1056:     var->get_handler = ngx_http_gzip_ratio_variable;
                   1057: 
                   1058:     return NGX_OK;
                   1059: }
                   1060: 
                   1061: 
                   1062: static ngx_int_t
                   1063: ngx_http_gzip_ratio_variable(ngx_http_request_t *r,
                   1064:     ngx_http_variable_value_t *v, uintptr_t data)
                   1065: {
                   1066:     ngx_uint_t            zint, zfrac;
                   1067:     ngx_http_gzip_ctx_t  *ctx;
                   1068: 
                   1069:     v->valid = 1;
                   1070:     v->no_cacheable = 0;
                   1071:     v->not_found = 0;
                   1072: 
                   1073:     ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module);
                   1074: 
                   1075:     if (ctx == NULL || ctx->zout == 0) {
                   1076:         v->not_found = 1;
                   1077:         return NGX_OK;
                   1078:     }
                   1079: 
                   1080:     v->data = ngx_pnalloc(r->pool, NGX_INT32_LEN + 3);
                   1081:     if (v->data == NULL) {
                   1082:         return NGX_ERROR;
                   1083:     }
                   1084: 
                   1085:     zint = (ngx_uint_t) (ctx->zin / ctx->zout);
                   1086:     zfrac = (ngx_uint_t) ((ctx->zin * 100 / ctx->zout) % 100);
                   1087: 
                   1088:     if ((ctx->zin * 1000 / ctx->zout) % 10 > 4) {
                   1089: 
                   1090:         /* the rounding, e.g., 2.125 to 2.13 */
                   1091: 
                   1092:         zfrac++;
                   1093: 
                   1094:         if (zfrac > 99) {
                   1095:             zint++;
                   1096:             zfrac = 0;
                   1097:         }
                   1098:     }
                   1099: 
                   1100:     v->len = ngx_sprintf(v->data, "%ui.%02ui", zint, zfrac) - v->data;
                   1101: 
                   1102:     return NGX_OK;
                   1103: }
                   1104: 
                   1105: 
                   1106: static void *
                   1107: ngx_http_gzip_create_conf(ngx_conf_t *cf)
                   1108: {
                   1109:     ngx_http_gzip_conf_t  *conf;
                   1110: 
                   1111:     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_gzip_conf_t));
                   1112:     if (conf == NULL) {
                   1113:         return NULL;
                   1114:     }
                   1115: 
                   1116:     /*
                   1117:      * set by ngx_pcalloc():
                   1118:      *
                   1119:      *     conf->bufs.num = 0;
                   1120:      *     conf->types = { NULL };
                   1121:      *     conf->types_keys = NULL;
                   1122:      */
                   1123: 
                   1124:     conf->enable = NGX_CONF_UNSET;
                   1125:     conf->no_buffer = NGX_CONF_UNSET;
                   1126: 
                   1127:     conf->postpone_gzipping = NGX_CONF_UNSET_SIZE;
                   1128:     conf->level = NGX_CONF_UNSET;
                   1129:     conf->wbits = NGX_CONF_UNSET_SIZE;
                   1130:     conf->memlevel = NGX_CONF_UNSET_SIZE;
                   1131:     conf->min_length = NGX_CONF_UNSET;
                   1132: 
                   1133:     return conf;
                   1134: }
                   1135: 
                   1136: 
                   1137: static char *
                   1138: ngx_http_gzip_merge_conf(ngx_conf_t *cf, void *parent, void *child)
                   1139: {
                   1140:     ngx_http_gzip_conf_t *prev = parent;
                   1141:     ngx_http_gzip_conf_t *conf = child;
                   1142: 
                   1143:     ngx_conf_merge_value(conf->enable, prev->enable, 0);
                   1144:     ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0);
                   1145: 
                   1146:     ngx_conf_merge_bufs_value(conf->bufs, prev->bufs,
                   1147:                               (128 * 1024) / ngx_pagesize, ngx_pagesize);
                   1148: 
                   1149:     ngx_conf_merge_size_value(conf->postpone_gzipping, prev->postpone_gzipping,
                   1150:                               0);
                   1151:     ngx_conf_merge_value(conf->level, prev->level, 1);
                   1152:     ngx_conf_merge_size_value(conf->wbits, prev->wbits, MAX_WBITS);
                   1153:     ngx_conf_merge_size_value(conf->memlevel, prev->memlevel,
                   1154:                               MAX_MEM_LEVEL - 1);
                   1155:     ngx_conf_merge_value(conf->min_length, prev->min_length, 20);
                   1156: 
                   1157:     if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
                   1158:                              &prev->types_keys, &prev->types,
                   1159:                              ngx_http_html_default_types)
                   1160:         != NGX_OK)
                   1161:     {
                   1162:         return NGX_CONF_ERROR;
                   1163:     }
                   1164: 
                   1165:     return NGX_CONF_OK;
                   1166: }
                   1167: 
                   1168: 
                   1169: static ngx_int_t
                   1170: ngx_http_gzip_filter_init(ngx_conf_t *cf)
                   1171: {
                   1172:     ngx_http_next_header_filter = ngx_http_top_header_filter;
                   1173:     ngx_http_top_header_filter = ngx_http_gzip_header_filter;
                   1174: 
                   1175:     ngx_http_next_body_filter = ngx_http_top_body_filter;
                   1176:     ngx_http_top_body_filter = ngx_http_gzip_body_filter;
                   1177: 
                   1178:     return NGX_OK;
                   1179: }
                   1180: 
                   1181: 
                   1182: static char *
                   1183: ngx_http_gzip_window(ngx_conf_t *cf, void *post, void *data)
                   1184: {
                   1185:     size_t *np = data;
                   1186: 
                   1187:     size_t  wbits, wsize;
                   1188: 
                   1189:     wbits = 15;
                   1190: 
                   1191:     for (wsize = 32 * 1024; wsize > 256; wsize >>= 1) {
                   1192: 
                   1193:         if (wsize == *np) {
                   1194:             *np = wbits;
                   1195: 
                   1196:             return NGX_CONF_OK;
                   1197:         }
                   1198: 
                   1199:         wbits--;
                   1200:     }
                   1201: 
                   1202:     return "must be 512, 1k, 2k, 4k, 8k, 16k, or 32k";
                   1203: }
                   1204: 
                   1205: 
                   1206: static char *
                   1207: ngx_http_gzip_hash(ngx_conf_t *cf, void *post, void *data)
                   1208: {
                   1209:     size_t *np = data;
                   1210: 
                   1211:     size_t  memlevel, hsize;
                   1212: 
                   1213:     memlevel = 9;
                   1214: 
                   1215:     for (hsize = 128 * 1024; hsize > 256; hsize >>= 1) {
                   1216: 
                   1217:         if (hsize == *np) {
                   1218:             *np = memlevel;
                   1219: 
                   1220:             return NGX_CONF_OK;
                   1221:         }
                   1222: 
                   1223:         memlevel--;
                   1224:     }
                   1225: 
                   1226:     return "must be 512, 1k, 2k, 4k, 8k, 16k, 32k, 64k, or 128k";
                   1227: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>