~ubuntu-branches/ubuntu/trusty/nginx/trusty-proposed

« back to all changes in this revision

Viewing changes to src/http/modules/ngx_http_gzip_filter_module.c

  • Committer: Package Import Robot
  • Author(s): Kartik Mistry
  • Date: 2013-04-25 12:51:45 UTC
  • mfrom: (1.3.28)
  • mto: (1.3.29) (15.1.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 64.
  • Revision ID: package-import@ubuntu.com-20130425125145-ugl0wor6bq0u5eae
Tags: upstream-1.4.0
ImportĀ upstreamĀ versionĀ 1.4.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
 
2
2
/*
3
3
 * Copyright (C) Igor Sysoev
 
4
 * Copyright (C) Nginx, Inc.
4
5
 */
5
6
 
6
7
 
15
16
    ngx_flag_t           enable;
16
17
    ngx_flag_t           no_buffer;
17
18
 
18
 
    ngx_array_t         *types;     /* array of ngx_str_t */
 
19
    ngx_hash_t           types;
19
20
 
20
21
    ngx_bufs_t           bufs;
21
22
 
 
23
    size_t               postpone_gzipping;
22
24
    ngx_int_t            level;
23
25
    size_t               wbits;
24
26
    size_t               memlevel;
25
27
    ssize_t              min_length;
 
28
 
 
29
    ngx_array_t         *types_keys;
26
30
} ngx_http_gzip_conf_t;
27
31
 
28
32
 
32
36
    ngx_chain_t         *busy;
33
37
    ngx_chain_t         *out;
34
38
    ngx_chain_t        **last_out;
 
39
 
 
40
    ngx_chain_t         *copied;
 
41
    ngx_chain_t         *copy_buf;
 
42
 
35
43
    ngx_buf_t           *in_buf;
36
44
    ngx_buf_t           *out_buf;
37
45
    ngx_int_t            bufs;
38
46
 
39
 
    off_t                length;
40
 
 
41
47
    void                *preallocated;
42
48
    char                *free_mem;
43
49
    ngx_uint_t           allocated;
44
50
 
 
51
    int                  wbits;
 
52
    int                  memlevel;
 
53
 
45
54
    unsigned             flush:4;
46
55
    unsigned             redo:1;
47
56
    unsigned             done:1;
 
57
    unsigned             nomem:1;
 
58
    unsigned             gzheader:1;
 
59
    unsigned             buffering:1;
48
60
 
49
61
    size_t               zin;
50
62
    size_t               zout;
55
67
} ngx_http_gzip_ctx_t;
56
68
 
57
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
 
58
104
static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items,
59
105
    u_int size);
60
106
static void ngx_http_gzip_filter_free(void *opaque, void *address);
61
 
static void ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx);
 
107
static void ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r,
 
108
    ngx_http_gzip_ctx_t *ctx);
62
109
 
63
110
static ngx_int_t ngx_http_gzip_add_variables(ngx_conf_t *cf);
64
111
static ngx_int_t ngx_http_gzip_ratio_variable(ngx_http_request_t *r,
68
115
static void *ngx_http_gzip_create_conf(ngx_conf_t *cf);
69
116
static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf,
70
117
    void *parent, void *child);
71
 
static char *ngx_http_gzip_types(ngx_conf_t *cf, ngx_command_t *cmd,
72
 
    void *conf);
73
118
static char *ngx_http_gzip_window(ngx_conf_t *cf, void *post, void *data);
74
119
static char *ngx_http_gzip_hash(ngx_conf_t *cf, void *post, void *data);
75
120
 
101
146
 
102
147
    { ngx_string("gzip_types"),
103
148
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
104
 
      ngx_http_gzip_types,
 
149
      ngx_http_types_slot,
105
150
      NGX_HTTP_LOC_CONF_OFFSET,
106
 
      0,
107
 
      NULL },
 
151
      offsetof(ngx_http_gzip_conf_t, types_keys),
 
152
      &ngx_http_html_default_types[0] },
108
153
 
109
154
    { ngx_string("gzip_comp_level"),
110
155
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
127
172
      offsetof(ngx_http_gzip_conf_t, memlevel),
128
173
      &ngx_http_gzip_hash_p },
129
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
 
130
182
    { ngx_string("gzip_no_buffer"),
131
183
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
132
184
      ngx_conf_set_flag_slot,
176
228
};
177
229
 
178
230
 
179
 
static u_char  gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
180
 
 
181
 
#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
182
 
 
183
 
struct gztrailer {
184
 
    uint32_t  crc32;
185
 
    uint32_t  zlen;
186
 
};
187
 
 
188
 
#else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */
189
 
 
190
 
struct gztrailer {
191
 
    u_char  crc32[4];
192
 
    u_char  zlen[4];
193
 
};
194
 
 
195
 
#endif
196
 
 
197
 
 
198
231
static ngx_str_t  ngx_http_gzip_ratio = ngx_string("gzip_ratio");
199
232
 
200
233
static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
204
237
static ngx_int_t
205
238
ngx_http_gzip_header_filter(ngx_http_request_t *r)
206
239
{
207
 
    ngx_str_t             *type;
208
 
    ngx_uint_t             i;
209
240
    ngx_table_elt_t       *h;
210
241
    ngx_http_gzip_ctx_t   *ctx;
211
242
    ngx_http_gzip_conf_t  *conf;
216
247
        || (r->headers_out.status != NGX_HTTP_OK
217
248
            && r->headers_out.status != NGX_HTTP_FORBIDDEN
218
249
            && r->headers_out.status != NGX_HTTP_NOT_FOUND)
219
 
        || r->header_only
220
 
        || r->headers_out.content_type.len == 0
221
250
        || (r->headers_out.content_encoding
222
251
            && r->headers_out.content_encoding->value.len)
223
252
        || (r->headers_out.content_length_n != -1
224
253
            && r->headers_out.content_length_n < conf->min_length)
225
 
        || ngx_http_gzip_ok(r) != NGX_OK)
226
 
    {
227
 
        return ngx_http_next_header_filter(r);
228
 
    }
229
 
 
230
 
    type = conf->types->elts;
231
 
    for (i = 0; i < conf->types->nelts; i++) {
232
 
        if (r->headers_out.content_type.len >= type[i].len
233
 
            && ngx_strncasecmp(r->headers_out.content_type.data,
234
 
                               type[i].data, type[i].len) == 0)
235
 
        {
236
 
            goto found;
 
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);
237
277
        }
 
278
 
 
279
    } else if (!r->gzip_ok) {
 
280
        return ngx_http_next_header_filter(r);
238
281
    }
239
282
 
240
 
    return ngx_http_next_header_filter(r);
241
 
 
242
 
found:
243
 
 
244
283
    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gzip_ctx_t));
245
284
    if (ctx == NULL) {
246
285
        return NGX_ERROR;
249
288
    ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module);
250
289
 
251
290
    ctx->request = r;
 
291
    ctx->buffering = (conf->postpone_gzipping != 0);
 
292
 
 
293
    ngx_http_gzip_filter_memory(r, ctx);
252
294
 
253
295
    h = ngx_list_push(&r->headers_out.headers);
254
296
    if (h == NULL) {
256
298
    }
257
299
 
258
300
    h->hash = 1;
259
 
    h->key.len = sizeof("Content-Encoding") - 1;
260
 
    h->key.data = (u_char *) "Content-Encoding";
261
 
    h->value.len = sizeof("gzip") - 1;
262
 
    h->value.data = (u_char *) "gzip";
263
 
 
 
301
    ngx_str_set(&h->key, "Content-Encoding");
 
302
    ngx_str_set(&h->value, "gzip");
264
303
    r->headers_out.content_encoding = h;
265
304
 
266
 
    ctx->length = r->headers_out.content_length_n;
267
 
 
268
305
    r->main_filter_need_in_memory = 1;
269
306
 
270
307
    ngx_http_clear_content_length(r);
271
308
    ngx_http_clear_accept_ranges(r);
 
309
    ngx_http_clear_etag(r);
272
310
 
273
311
    return ngx_http_next_header_filter(r);
274
312
}
277
315
static ngx_int_t
278
316
ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
279
317
{
280
 
    int                    rc, wbits, memlevel;
281
 
    ngx_int_t              last;
282
 
    struct gztrailer      *trailer;
283
 
    ngx_buf_t             *b;
284
 
    ngx_chain_t           *cl, out;
285
 
    ngx_http_gzip_ctx_t   *ctx;
286
 
    ngx_http_gzip_conf_t  *conf;
 
318
    int                   rc;
 
319
    ngx_chain_t          *cl;
 
320
    ngx_http_gzip_ctx_t  *ctx;
287
321
 
288
322
    ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module);
289
323
 
290
 
    if (ctx == NULL || ctx->done) {
 
324
    if (ctx == NULL || ctx->done || r->header_only) {
291
325
        return ngx_http_next_body_filter(r, in);
292
326
    }
293
327
 
294
 
    conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
 
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
    }
295
360
 
296
361
    if (ctx->preallocated == NULL) {
297
 
        wbits = conf->wbits;
298
 
        memlevel = conf->memlevel;
299
 
 
300
 
        if (ctx->length > 0) {
301
 
 
302
 
            /* the actual zlib window size is smaller by 262 bytes */
303
 
 
304
 
            while (ctx->length < ((1 << (wbits - 1)) - 262)) {
305
 
                wbits--;
306
 
                memlevel--;
307
 
            }
308
 
        }
309
 
 
310
 
        /*
311
 
         * We preallocate a memory for zlib in one buffer (200K-400K), this
312
 
         * decreases a number of malloc() and free() calls and also probably
313
 
         * decreases a number of syscalls (sbrk() and so on).
314
 
         * Besides we free this memory as soon as the gzipping will complete
315
 
         * and do not wait while a whole response will be sent to a client.
316
 
         *
317
 
         * 8K is for zlib deflate_state, it takes
318
 
         *  *) 5816 bytes on i386 and sparc64 (32-bit mode)
319
 
         *  *) 5920 bytes on amd64 and sparc64
320
 
         */
321
 
 
322
 
        ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9));
323
 
 
324
 
        ctx->preallocated = ngx_palloc(r->pool, ctx->allocated);
325
 
        if (ctx->preallocated == NULL) {
326
 
            return NGX_ERROR;
327
 
        }
328
 
 
329
 
        ctx->free_mem = ctx->preallocated;
330
 
 
331
 
        ctx->zstream.zalloc = ngx_http_gzip_filter_alloc;
332
 
        ctx->zstream.zfree = ngx_http_gzip_filter_free;
333
 
        ctx->zstream.opaque = ctx;
334
 
 
335
 
        rc = deflateInit2(&ctx->zstream, (int) conf->level, Z_DEFLATED,
336
 
                          -wbits, memlevel, Z_DEFAULT_STRATEGY);
337
 
 
338
 
        if (rc != Z_OK) {
339
 
            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
340
 
                          "deflateInit2() failed: %d", rc);
341
 
            ngx_http_gzip_error(ctx);
342
 
            return NGX_ERROR;
343
 
        }
344
 
 
345
 
        b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
346
 
        if (b == NULL) {
347
 
            ngx_http_gzip_error(ctx);
348
 
            return NGX_ERROR;
349
 
        }
350
 
 
351
 
        b->memory = 1;
352
 
        b->pos = gzheader;
353
 
        b->last = b->pos + 10;
354
 
 
355
 
        out.buf = b;
356
 
        out.next = NULL;
357
 
 
358
 
        /*
359
 
         * We pass the gzheader to the next filter now to avoid its linking
360
 
         * to the ctx->busy chain.  zlib does not usually output the compressed
361
 
         * data in the initial iterations, so the gzheader that was linked
362
 
         * to the ctx->busy chain would be flushed by ngx_http_write_filter().
363
 
         */
364
 
 
365
 
        if (ngx_http_next_body_filter(r, &out) == NGX_ERROR) {
366
 
            ngx_http_gzip_error(ctx);
367
 
            return NGX_ERROR;
368
 
        }
369
 
 
370
 
        r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED;
371
 
 
372
 
        ctx->last_out = &ctx->out;
373
 
 
374
 
        ctx->crc32 = crc32(0L, Z_NULL, 0);
375
 
        ctx->flush = Z_NO_FLUSH;
 
362
        if (ngx_http_gzip_filter_deflate_start(r, ctx) != NGX_OK) {
 
363
            goto failed;
 
364
        }
376
365
    }
377
366
 
378
367
    if (in) {
379
 
        if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) {
380
 
            ngx_http_gzip_error(ctx);
381
 
            return NGX_ERROR;
382
 
        }
383
 
    }
384
 
 
385
 
    last = NGX_NONE;
 
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
    }
386
387
 
387
388
    for ( ;; ) {
388
389
 
 
390
        /* cycle while we can write to a client */
 
391
 
389
392
        for ( ;; ) {
390
393
 
391
 
            /* does zlib need a new data ? */
392
 
 
393
 
            if (ctx->zstream.avail_in == 0
394
 
                && ctx->flush == Z_NO_FLUSH
395
 
                && !ctx->redo)
396
 
            {
397
 
                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
398
 
                               "gzip in: %p", ctx->in);
399
 
 
400
 
                if (ctx->in == NULL) {
401
 
                    break;
402
 
                }
403
 
 
404
 
                ctx->in_buf = ctx->in->buf;
405
 
                ctx->in = ctx->in->next;
406
 
 
407
 
                ctx->zstream.next_in = ctx->in_buf->pos;
408
 
                ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos;
409
 
 
410
 
                ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
411
 
                               "gzip in_buf:%p ni:%p ai:%ud",
412
 
                               ctx->in_buf,
413
 
                               ctx->zstream.next_in, ctx->zstream.avail_in);
414
 
 
415
 
                /* STUB */
416
 
                if (ctx->in_buf->last < ctx->in_buf->pos) {
417
 
                    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
418
 
                                  "zstream.avail_in is huge");
419
 
                    ctx->done = 1;
420
 
                    return NGX_ERROR;
421
 
                }
422
 
                /**/
423
 
 
424
 
                if (ctx->in_buf->last_buf) {
425
 
                    ctx->flush = Z_FINISH;
426
 
 
427
 
                } else if (ctx->in_buf->flush) {
428
 
                    ctx->flush = Z_SYNC_FLUSH;
429
 
                }
430
 
 
431
 
                if (ctx->zstream.avail_in == 0) {
432
 
                    if (ctx->flush == Z_NO_FLUSH) {
433
 
                        continue;
434
 
                    }
435
 
 
436
 
                } else {
437
 
                    ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in,
438
 
                                       ctx->zstream.avail_in);
439
 
                }
440
 
            }
441
 
 
442
 
 
443
 
            /* is there a space for the gzipped data ? */
444
 
 
445
 
            if (ctx->zstream.avail_out == 0) {
446
 
 
447
 
                if (ctx->free) {
448
 
                    ctx->out_buf = ctx->free->buf;
449
 
                    ctx->free = ctx->free->next;
450
 
 
451
 
                } else if (ctx->bufs < conf->bufs.num) {
452
 
                    ctx->out_buf = ngx_create_temp_buf(r->pool,
453
 
                                                       conf->bufs.size);
454
 
                    if (ctx->out_buf == NULL) {
455
 
                        ngx_http_gzip_error(ctx);
456
 
                        return NGX_ERROR;
457
 
                    }
458
 
 
459
 
                    ctx->out_buf->tag = (ngx_buf_tag_t)
460
 
                                                  &ngx_http_gzip_filter_module;
461
 
                    ctx->out_buf->recycled = 1;
462
 
                    ctx->bufs++;
463
 
 
464
 
                } else {
465
 
                    break;
466
 
                }
467
 
 
468
 
                ctx->zstream.next_out = ctx->out_buf->pos;
469
 
                ctx->zstream.avail_out = conf->bufs.size;
470
 
            }
471
 
 
472
 
            ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
473
 
                         "deflate in: ni:%p no:%p ai:%ud ao:%ud fl:%d redo:%d",
474
 
                         ctx->zstream.next_in, ctx->zstream.next_out,
475
 
                         ctx->zstream.avail_in, ctx->zstream.avail_out,
476
 
                         ctx->flush, ctx->redo);
477
 
 
478
 
            rc = deflate(&ctx->zstream, ctx->flush);
479
 
 
480
 
            if (rc != Z_OK && rc != Z_STREAM_END) {
481
 
                ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
482
 
                              "deflate() failed: %d, %d", ctx->flush, rc);
483
 
                ngx_http_gzip_error(ctx);
484
 
                return NGX_ERROR;
485
 
            }
486
 
 
487
 
            ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
488
 
                           "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
489
 
                           ctx->zstream.next_in, ctx->zstream.next_out,
490
 
                           ctx->zstream.avail_in, ctx->zstream.avail_out,
491
 
                           rc);
492
 
 
493
 
            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
494
 
                           "gzip in_buf:%p pos:%p",
495
 
                           ctx->in_buf, ctx->in_buf->pos);
496
 
 
497
 
 
498
 
            if (ctx->zstream.next_in) {
499
 
                ctx->in_buf->pos = ctx->zstream.next_in;
500
 
 
501
 
                if (ctx->zstream.avail_in == 0) {
502
 
                    ctx->zstream.next_in = NULL;
503
 
                }
504
 
            }
505
 
 
506
 
            ctx->out_buf->last = ctx->zstream.next_out;
507
 
 
508
 
            if (ctx->zstream.avail_out == 0) {
509
 
 
510
 
                /* zlib wants to output some more gzipped data */
511
 
 
512
 
                cl = ngx_alloc_chain_link(r->pool);
513
 
                if (cl == NULL) {
514
 
                    ngx_http_gzip_error(ctx);
515
 
                    return NGX_ERROR;
516
 
                }
517
 
 
518
 
                cl->buf = ctx->out_buf;
519
 
                cl->next = NULL;
520
 
                *ctx->last_out = cl;
521
 
                ctx->last_out = &cl->next;
522
 
 
523
 
                ctx->redo = 1;
524
 
 
 
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) {
525
403
                continue;
526
404
            }
527
405
 
528
 
            ctx->redo = 0;
529
 
 
530
 
            if (ctx->flush == Z_SYNC_FLUSH) {
531
 
 
532
 
                ctx->zstream.avail_out = 0;
533
 
                ctx->out_buf->flush = 1;
534
 
                ctx->flush = Z_NO_FLUSH;
535
 
 
536
 
                cl = ngx_alloc_chain_link(r->pool);
537
 
                if (cl == NULL) {
538
 
                    ngx_http_gzip_error(ctx);
539
 
                    return NGX_ERROR;
540
 
                }
541
 
 
542
 
                cl->buf = ctx->out_buf;
543
 
                cl->next = NULL;
544
 
                *ctx->last_out = cl;
545
 
                ctx->last_out = &cl->next;
546
 
 
547
 
                break;
548
 
            }
549
 
 
550
 
            if (rc == Z_STREAM_END) {
551
 
 
552
 
                ctx->zin = ctx->zstream.total_in;
553
 
                ctx->zout = 10 + ctx->zstream.total_out + 8;
554
 
 
555
 
                rc = deflateEnd(&ctx->zstream);
556
 
 
557
 
                if (rc != Z_OK) {
558
 
                    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
559
 
                                  "deflateEnd() failed: %d", rc);
560
 
                    ngx_http_gzip_error(ctx);
561
 
                    return NGX_ERROR;
562
 
                }
563
 
 
564
 
                ngx_pfree(r->pool, ctx->preallocated);
565
 
 
566
 
                cl = ngx_alloc_chain_link(r->pool);
567
 
                if (cl == NULL) {
568
 
                    ngx_http_gzip_error(ctx);
569
 
                    return NGX_ERROR;
570
 
                }
571
 
 
572
 
                cl->buf = ctx->out_buf;
573
 
                cl->next = NULL;
574
 
                *ctx->last_out = cl;
575
 
                ctx->last_out = &cl->next;
576
 
 
577
 
                if (ctx->zstream.avail_out >= 8) {
578
 
                    trailer = (struct gztrailer *) ctx->out_buf->last;
579
 
                    ctx->out_buf->last += 8;
580
 
                    ctx->out_buf->last_buf = 1;
581
 
 
582
 
                } else {
583
 
                    b = ngx_create_temp_buf(r->pool, 8);
584
 
                    if (b == NULL) {
585
 
                        ngx_http_gzip_error(ctx);
586
 
                        return NGX_ERROR;
587
 
                    }
588
 
 
589
 
                    b->last_buf = 1;
590
 
 
591
 
                    cl = ngx_alloc_chain_link(r->pool);
592
 
                    if (cl == NULL) {
593
 
                        ngx_http_gzip_error(ctx);
594
 
                        return NGX_ERROR;
595
 
                    }
596
 
 
597
 
                    cl->buf = b;
598
 
                    cl->next = NULL;
599
 
                    *ctx->last_out = cl;
600
 
                    ctx->last_out = &cl->next;
601
 
                    trailer = (struct gztrailer *) b->pos;
602
 
                    b->last += 8;
603
 
                }
604
 
 
605
 
#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
606
 
 
607
 
                trailer->crc32 = ctx->crc32;
608
 
                trailer->zlen = ctx->zin;
609
 
 
610
 
#else
611
 
                trailer->crc32[0] = (u_char) (ctx->crc32 & 0xff);
612
 
                trailer->crc32[1] = (u_char) ((ctx->crc32 >> 8) & 0xff);
613
 
                trailer->crc32[2] = (u_char) ((ctx->crc32 >> 16) & 0xff);
614
 
                trailer->crc32[3] = (u_char) ((ctx->crc32 >> 24) & 0xff);
615
 
 
616
 
                trailer->zlen[0] = (u_char) (ctx->zin & 0xff);
617
 
                trailer->zlen[1] = (u_char) ((ctx->zin >> 8) & 0xff);
618
 
                trailer->zlen[2] = (u_char) ((ctx->zin >> 16) & 0xff);
619
 
                trailer->zlen[3] = (u_char) ((ctx->zin >> 24) & 0xff);
620
 
#endif
621
 
 
622
 
                ctx->zstream.avail_in = 0;
623
 
                ctx->zstream.avail_out = 0;
624
 
 
625
 
                ctx->done = 1;
626
 
 
627
 
                r->connection->buffered &= ~NGX_HTTP_GZIP_BUFFERED;
628
 
 
629
 
                break;
630
 
            }
631
 
 
632
 
            if (conf->no_buffer && ctx->in == NULL) {
633
 
 
634
 
                cl = ngx_alloc_chain_link(r->pool);
635
 
                if (cl == NULL) {
636
 
                    ngx_http_gzip_error(ctx);
637
 
                    return NGX_ERROR;
638
 
                }
639
 
 
640
 
                cl->buf = ctx->out_buf;
641
 
                cl->next = NULL;
642
 
                *ctx->last_out = cl;
643
 
                ctx->last_out = &cl->next;
644
 
 
645
 
                break;
646
 
            }
 
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 */
647
431
        }
648
432
 
649
433
        if (ctx->out == NULL) {
650
 
 
651
 
            if (last == NGX_AGAIN) {
652
 
                return NGX_AGAIN;
653
 
            }
654
 
 
655
 
            if (ctx->busy == NULL) {
656
 
                return NGX_OK;
657
 
            }
658
 
        }
659
 
 
660
 
        last = ngx_http_next_body_filter(r, ctx->out);
661
 
 
662
 
        /*
663
 
         * we do not check NGX_AGAIN here because the downstream filters
664
 
         * may free some buffers and zlib may compress some data into them
665
 
         */
666
 
 
667
 
        if (last == NGX_ERROR) {
668
 
            ngx_http_gzip_error(ctx);
669
 
            return NGX_ERROR;
670
 
        }
671
 
 
672
 
        ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out,
 
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,
673
454
                                (ngx_buf_tag_t) &ngx_http_gzip_filter_module);
674
455
        ctx->last_out = &ctx->out;
675
456
 
 
457
        ctx->nomem = 0;
 
458
 
676
459
        if (ctx->done) {
677
 
            return last;
678
 
        }
679
 
    }
 
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;
680
975
}
681
976
 
682
977
 
690
985
 
691
986
    alloc = items * size;
692
987
 
693
 
    if (alloc % 512 != 0) {
 
988
    if (alloc % 512 != 0 && alloc < 8192) {
694
989
 
695
990
        /*
696
991
         * The zlib deflate_state allocation, it takes about 6K,
697
992
         * we allocate 8K.  Other allocations are divisible by 512.
698
993
         */
699
994
 
700
 
        alloc = (alloc + ngx_pagesize - 1) & ~(ngx_pagesize - 1);
 
995
        alloc = 8192;
701
996
    }
702
997
 
703
998
    if (alloc <= ctx->allocated) {
735
1030
 
736
1031
 
737
1032
static void
738
 
ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx)
 
1033
ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r,
 
1034
    ngx_http_gzip_ctx_t *ctx)
739
1035
{
740
 
    deflateEnd(&ctx->zstream);
 
1036
    ngx_chain_t  *cl;
741
1037
 
742
 
    if (ctx->preallocated) {
743
 
        ngx_pfree(ctx->request->pool, ctx->preallocated);
 
1038
    for (cl = ctx->copied; cl; cl = cl->next) {
 
1039
        ngx_pfree(r->pool, cl->buf->start);
744
1040
    }
745
1041
 
746
 
    ctx->zstream.avail_in = 0;
747
 
    ctx->zstream.avail_out = 0;
748
 
 
749
 
    ctx->done = 1;
750
 
 
751
 
    return;
 
1042
    ctx->copied = NULL;
752
1043
}
753
1044
 
754
1045
 
786
1077
        return NGX_OK;
787
1078
    }
788
1079
 
789
 
    v->data = ngx_palloc(r->pool, NGX_INT32_LEN + 3);
 
1080
    v->data = ngx_pnalloc(r->pool, NGX_INT32_LEN + 3);
790
1081
    if (v->data == NULL) {
791
1082
        return NGX_ERROR;
792
1083
    }
819
1110
 
820
1111
    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_gzip_conf_t));
821
1112
    if (conf == NULL) {
822
 
        return NGX_CONF_ERROR;
 
1113
        return NULL;
823
1114
    }
824
1115
 
825
1116
    /*
826
1117
     * set by ngx_pcalloc():
827
1118
     *
828
1119
     *     conf->bufs.num = 0;
829
 
     *     conf->types = NULL;
 
1120
     *     conf->types = { NULL };
 
1121
     *     conf->types_keys = NULL;
830
1122
     */
831
1123
 
832
1124
    conf->enable = NGX_CONF_UNSET;
833
1125
    conf->no_buffer = NGX_CONF_UNSET;
834
1126
 
 
1127
    conf->postpone_gzipping = NGX_CONF_UNSET_SIZE;
835
1128
    conf->level = NGX_CONF_UNSET;
836
 
    conf->wbits = (size_t) NGX_CONF_UNSET;
837
 
    conf->memlevel = (size_t) NGX_CONF_UNSET;
 
1129
    conf->wbits = NGX_CONF_UNSET_SIZE;
 
1130
    conf->memlevel = NGX_CONF_UNSET_SIZE;
838
1131
    conf->min_length = NGX_CONF_UNSET;
839
1132
 
840
1133
    return conf;
847
1140
    ngx_http_gzip_conf_t *prev = parent;
848
1141
    ngx_http_gzip_conf_t *conf = child;
849
1142
 
850
 
    ngx_str_t  *type;
851
 
 
852
1143
    ngx_conf_merge_value(conf->enable, prev->enable, 0);
853
 
 
854
 
    ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 4, ngx_pagesize);
855
 
 
 
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);
856
1151
    ngx_conf_merge_value(conf->level, prev->level, 1);
857
1152
    ngx_conf_merge_size_value(conf->wbits, prev->wbits, MAX_WBITS);
858
1153
    ngx_conf_merge_size_value(conf->memlevel, prev->memlevel,
859
1154
                              MAX_MEM_LEVEL - 1);
860
1155
    ngx_conf_merge_value(conf->min_length, prev->min_length, 20);
861
 
    ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0);
862
 
 
863
 
    if (conf->types == NULL) {
864
 
        if (prev->types == NULL) {
865
 
            conf->types = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t));
866
 
            if (conf->types == NULL) {
867
 
                return NGX_CONF_ERROR;
868
 
            }
869
 
 
870
 
            type = ngx_array_push(conf->types);
871
 
            if (type == NULL) {
872
 
                return NGX_CONF_ERROR;
873
 
            }
874
 
 
875
 
            type->len = sizeof("text/html") - 1;
876
 
            type->data = (u_char *) "text/html";
877
 
 
878
 
        } else {
879
 
            conf->types = prev->types;
880
 
        }
 
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;
881
1163
    }
882
1164
 
883
1165
    return NGX_CONF_OK;
898
1180
 
899
1181
 
900
1182
static char *
901
 
ngx_http_gzip_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
902
 
{
903
 
    ngx_http_gzip_conf_t *gcf = conf;
904
 
 
905
 
    ngx_str_t   *value, *type;
906
 
    ngx_uint_t   i;
907
 
 
908
 
    if (gcf->types == NULL) {
909
 
        gcf->types = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
910
 
        if (gcf->types == NULL) {
911
 
            return NGX_CONF_ERROR;
912
 
        }
913
 
 
914
 
        type = ngx_array_push(gcf->types);
915
 
        if (type == NULL) {
916
 
            return NGX_CONF_ERROR;
917
 
        }
918
 
 
919
 
        type->len = sizeof("text/html") - 1;
920
 
        type->data = (u_char *) "text/html";
921
 
    }
922
 
 
923
 
    value = cf->args->elts;
924
 
 
925
 
    for (i = 1; i < cf->args->nelts; i++) {
926
 
 
927
 
        if (ngx_strcmp(value[i].data, "text/html") == 0) {
928
 
            continue;
929
 
        }
930
 
 
931
 
        type = ngx_array_push(gcf->types);
932
 
        if (type == NULL) {
933
 
            return NGX_CONF_ERROR;
934
 
        }
935
 
 
936
 
        type->len = value[i].len;
937
 
 
938
 
        type->data = ngx_palloc(cf->pool, type->len + 1);
939
 
        if (type->data == NULL) {
940
 
            return NGX_CONF_ERROR;
941
 
        }
942
 
 
943
 
        ngx_cpystrn(type->data, value[i].data, type->len + 1);
944
 
    }
945
 
 
946
 
    return NGX_CONF_OK;
947
 
}
948
 
 
949
 
 
950
 
static char *
951
1183
ngx_http_gzip_window(ngx_conf_t *cf, void *post, void *data)
952
1184
{
953
 
    int *np = data;
 
1185
    size_t *np = data;
954
1186
 
955
 
    int  wbits, wsize;
 
1187
    size_t  wbits, wsize;
956
1188
 
957
1189
    wbits = 15;
958
1190
 
974
1206
static char *
975
1207
ngx_http_gzip_hash(ngx_conf_t *cf, void *post, void *data)
976
1208
{
977
 
    int *np = data;
 
1209
    size_t *np = data;
978
1210
 
979
 
    int  memlevel, hsize;
 
1211
    size_t  memlevel, hsize;
980
1212
 
981
1213
    memlevel = 9;
982
1214