~ubuntu-branches/ubuntu/karmic/nginx/karmic

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Fabio Tranchitella
  • Date: 2009-05-31 18:38:56 UTC
  • mfrom: (1.1.11 upstream) (4.2.2 sid)
  • Revision ID: james.westby@ubuntu.com-20090531183856-lkdgdzr9m731fz92
Tags: 0.7.59-1
* New upstream release, first in Debian for the 0.7 branch. Among other
  issues, it also fixes the problem with wildcard dns names used with SSL.
  (Closes: #515904)
* debian/watch: updated.
* debian/postinst: fixed a bashism. (Closes: #507913)
* debian/conf/nginx.conf: removed default_type. (Closes: #509390)
* debian/control: updated Standards-Version to 3.8.1, no changes needed.
* debian/NEWS.Debian: documented the issues with
  server_names_hash_bucket_size. (Closes: #524785)

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
    ngx_flag_t           enable;
16
16
    ngx_flag_t           no_buffer;
17
17
 
18
 
    ngx_array_t         *types;     /* array of ngx_str_t */
 
18
    ngx_hash_t           types;
19
19
 
20
20
    ngx_bufs_t           bufs;
21
21
 
 
22
    size_t               postpone_gzipping;
22
23
    ngx_int_t            level;
23
24
    size_t               wbits;
24
25
    size_t               memlevel;
25
26
    ssize_t              min_length;
 
27
 
 
28
    ngx_array_t         *types_keys;
26
29
} ngx_http_gzip_conf_t;
27
30
 
28
31
 
32
35
    ngx_chain_t         *busy;
33
36
    ngx_chain_t         *out;
34
37
    ngx_chain_t        **last_out;
 
38
 
 
39
    ngx_chain_t         *copied;
 
40
    ngx_chain_t         *copy_buf;
 
41
 
35
42
    ngx_buf_t           *in_buf;
36
43
    ngx_buf_t           *out_buf;
37
44
    ngx_int_t            bufs;
38
45
 
39
 
    off_t                length;
40
 
 
41
46
    void                *preallocated;
42
47
    char                *free_mem;
43
48
    ngx_uint_t           allocated;
44
49
 
 
50
    int                  wbits;
 
51
    int                  memlevel;
 
52
 
45
53
    unsigned             flush:4;
46
54
    unsigned             redo:1;
47
55
    unsigned             done:1;
 
56
    unsigned             nomem:1;
 
57
    unsigned             gzheader:1;
 
58
    unsigned             buffering:1;
48
59
 
49
60
    size_t               zin;
50
61
    size_t               zout;
55
66
} ngx_http_gzip_ctx_t;
56
67
 
57
68
 
 
69
#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
 
70
 
 
71
struct gztrailer {
 
72
    uint32_t  crc32;
 
73
    uint32_t  zlen;
 
74
};
 
75
 
 
76
#else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */
 
77
 
 
78
struct gztrailer {
 
79
    u_char  crc32[4];
 
80
    u_char  zlen[4];
 
81
};
 
82
 
 
83
#endif
 
84
 
 
85
 
 
86
static void ngx_http_gzip_filter_memory(ngx_http_request_t *r,
 
87
    ngx_http_gzip_ctx_t *ctx);
 
88
static ngx_int_t ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx,
 
89
    ngx_chain_t *in);
 
90
static ngx_int_t ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r,
 
91
    ngx_http_gzip_ctx_t *ctx);
 
92
static ngx_int_t ngx_http_gzip_filter_gzheader(ngx_http_request_t *r,
 
93
    ngx_http_gzip_ctx_t *ctx);
 
94
static ngx_int_t ngx_http_gzip_filter_add_data(ngx_http_request_t *r,
 
95
    ngx_http_gzip_ctx_t *ctx);
 
96
static ngx_int_t ngx_http_gzip_filter_get_buf(ngx_http_request_t *r,
 
97
    ngx_http_gzip_ctx_t *ctx);
 
98
static ngx_int_t ngx_http_gzip_filter_deflate(ngx_http_request_t *r,
 
99
    ngx_http_gzip_ctx_t *ctx);
 
100
static ngx_int_t ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r,
 
101
    ngx_http_gzip_ctx_t *ctx);
 
102
 
58
103
static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items,
59
104
    u_int size);
60
105
static void ngx_http_gzip_filter_free(void *opaque, void *address);
61
 
static void ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx);
 
106
static void ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r,
 
107
    ngx_http_gzip_ctx_t *ctx);
62
108
 
63
109
static ngx_int_t ngx_http_gzip_add_variables(ngx_conf_t *cf);
64
110
static ngx_int_t ngx_http_gzip_ratio_variable(ngx_http_request_t *r,
68
114
static void *ngx_http_gzip_create_conf(ngx_conf_t *cf);
69
115
static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf,
70
116
    void *parent, void *child);
71
 
static char *ngx_http_gzip_types(ngx_conf_t *cf, ngx_command_t *cmd,
72
 
    void *conf);
73
117
static char *ngx_http_gzip_window(ngx_conf_t *cf, void *post, void *data);
74
118
static char *ngx_http_gzip_hash(ngx_conf_t *cf, void *post, void *data);
75
119
 
101
145
 
102
146
    { ngx_string("gzip_types"),
103
147
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
104
 
      ngx_http_gzip_types,
 
148
      ngx_http_types_slot,
105
149
      NGX_HTTP_LOC_CONF_OFFSET,
106
 
      0,
107
 
      NULL },
 
150
      offsetof(ngx_http_gzip_conf_t, types_keys),
 
151
      &ngx_http_html_default_types[0] },
108
152
 
109
153
    { ngx_string("gzip_comp_level"),
110
154
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
127
171
      offsetof(ngx_http_gzip_conf_t, memlevel),
128
172
      &ngx_http_gzip_hash_p },
129
173
 
 
174
    { ngx_string("postpone_gzipping"),
 
175
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
 
176
      ngx_conf_set_size_slot,
 
177
      NGX_HTTP_LOC_CONF_OFFSET,
 
178
      offsetof(ngx_http_gzip_conf_t, postpone_gzipping),
 
179
      NULL },
 
180
 
130
181
    { ngx_string("gzip_no_buffer"),
131
182
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
132
183
      ngx_conf_set_flag_slot,
176
227
};
177
228
 
178
229
 
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
230
static ngx_str_t  ngx_http_gzip_ratio = ngx_string("gzip_ratio");
199
231
 
200
232
static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
204
236
static ngx_int_t
205
237
ngx_http_gzip_header_filter(ngx_http_request_t *r)
206
238
{
207
 
    ngx_str_t             *type;
208
 
    ngx_uint_t             i;
209
239
    ngx_table_elt_t       *h;
210
240
    ngx_http_gzip_ctx_t   *ctx;
211
241
    ngx_http_gzip_conf_t  *conf;
217
247
            && r->headers_out.status != NGX_HTTP_FORBIDDEN
218
248
            && r->headers_out.status != NGX_HTTP_NOT_FOUND)
219
249
        || 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)
 
254
        || ngx_http_test_content_type(r, &conf->types) == NULL
225
255
        || ngx_http_gzip_ok(r) != NGX_OK)
226
256
    {
227
257
        return ngx_http_next_header_filter(r);
228
258
    }
229
259
 
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;
237
 
        }
238
 
    }
239
 
 
240
 
    return ngx_http_next_header_filter(r);
241
 
 
242
 
found:
243
 
 
244
260
    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gzip_ctx_t));
245
261
    if (ctx == NULL) {
246
262
        return NGX_ERROR;
249
265
    ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module);
250
266
 
251
267
    ctx->request = r;
 
268
    ctx->buffering = (conf->postpone_gzipping != 0);
 
269
 
 
270
    ngx_http_gzip_filter_memory(r, ctx);
252
271
 
253
272
    h = ngx_list_push(&r->headers_out.headers);
254
273
    if (h == NULL) {
263
282
 
264
283
    r->headers_out.content_encoding = h;
265
284
 
266
 
    ctx->length = r->headers_out.content_length_n;
267
 
 
268
285
    r->main_filter_need_in_memory = 1;
269
286
 
270
287
    ngx_http_clear_content_length(r);
277
294
static ngx_int_t
278
295
ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
279
296
{
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;
 
297
    int                   rc;
 
298
    ngx_chain_t          *cl;
 
299
    ngx_http_gzip_ctx_t  *ctx;
287
300
 
288
301
    ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module);
289
302
 
291
304
        return ngx_http_next_body_filter(r, in);
292
305
    }
293
306
 
294
 
    conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
 
307
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
 
308
                   "http gzip filter");
 
309
 
 
310
    if (ctx->buffering) {
 
311
 
 
312
        /*
 
313
         * With default memory settings zlib starts to output gzipped data
 
314
         * only after it has got about 90K, so it makes sense to allocate
 
315
         * zlib memory (200-400K) only after we have enough data to compress.
 
316
         * Although we copy buffers, nevertheless for not big responses
 
317
         * this allows to allocate zlib memory, to compress and to output
 
318
         * the response in one step using hot CPU cache.
 
319
         */
 
320
 
 
321
        if (in) {
 
322
            switch (ngx_http_gzip_filter_buffer(ctx, in)) {
 
323
 
 
324
            case NGX_OK:
 
325
                return NGX_OK;
 
326
 
 
327
            case NGX_DONE:
 
328
                in = NULL;
 
329
                break;
 
330
 
 
331
            default:  /* NGX_ERROR */
 
332
                goto failed;
 
333
            }
 
334
 
 
335
        } else {
 
336
            ctx->buffering = 0;
 
337
        }
 
338
    }
295
339
 
296
340
    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;
 
341
        if (ngx_http_gzip_filter_deflate_start(r, ctx) != NGX_OK) {
 
342
            goto failed;
 
343
        }
376
344
    }
377
345
 
378
346
    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;
 
347
        if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
 
348
            goto failed;
 
349
        }
 
350
    }
 
351
 
 
352
    if (ctx->nomem) {
 
353
 
 
354
        /* flush busy buffers */
 
355
 
 
356
        if (ngx_http_next_body_filter(r, NULL) == NGX_ERROR) {
 
357
            goto failed;
 
358
        }
 
359
 
 
360
        cl = NULL;
 
361
 
 
362
        ngx_chain_update_chains(&ctx->free, &ctx->busy, &cl,
 
363
                                (ngx_buf_tag_t) &ngx_http_gzip_filter_module);
 
364
        ctx->nomem = 0;
 
365
    }
386
366
 
387
367
    for ( ;; ) {
388
368
 
 
369
        /* cycle while we can write to a client */
 
370
 
389
371
        for ( ;; ) {
390
372
 
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
 
 
 
373
            /* cycle while there is data to feed zlib and ... */
 
374
 
 
375
            rc = ngx_http_gzip_filter_add_data(r, ctx);
 
376
 
 
377
            if (rc == NGX_DECLINED) {
 
378
                break;
 
379
            }
 
380
 
 
381
            if (rc == NGX_AGAIN) {
525
382
                continue;
526
383
            }
527
384
 
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
 
            }
 
385
 
 
386
            /* ... there are buffers to write zlib output */
 
387
 
 
388
            rc = ngx_http_gzip_filter_get_buf(r, ctx);
 
389
 
 
390
            if (rc == NGX_DECLINED) {
 
391
                break;
 
392
            }
 
393
 
 
394
            if (rc == NGX_ERROR) {
 
395
                goto failed;
 
396
            }
 
397
 
 
398
 
 
399
            rc = ngx_http_gzip_filter_deflate(r, ctx);
 
400
 
 
401
            if (rc == NGX_OK) {
 
402
                break;
 
403
            }
 
404
 
 
405
            if (rc == NGX_ERROR) {
 
406
                goto failed;
 
407
            }
 
408
 
 
409
            /* rc == NGX_AGAIN */
647
410
        }
648
411
 
649
412
        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
 
        }
 
413
            ngx_http_gzip_filter_free_copy_buf(r, ctx);
 
414
 
 
415
            return ctx->busy ? NGX_AGAIN : NGX_OK;
 
416
        }
 
417
 
 
418
        if (!ctx->gzheader) {
 
419
            if (ngx_http_gzip_filter_gzheader(r, ctx) != NGX_OK) {
 
420
                goto failed;
 
421
            }
 
422
        }
 
423
 
 
424
        rc = ngx_http_next_body_filter(r, ctx->out);
 
425
 
 
426
        if (rc == NGX_ERROR) {
 
427
            goto failed;
 
428
        }
 
429
 
 
430
        ngx_http_gzip_filter_free_copy_buf(r, ctx);
671
431
 
672
432
        ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out,
673
433
                                (ngx_buf_tag_t) &ngx_http_gzip_filter_module);
674
434
        ctx->last_out = &ctx->out;
675
435
 
 
436
        ctx->nomem = 0;
 
437
 
676
438
        if (ctx->done) {
677
 
            return last;
678
 
        }
679
 
    }
 
439
            return rc;
 
440
        }
 
441
    }
 
442
 
 
443
    /* unreachable */
 
444
 
 
445
failed:
 
446
 
 
447
    ctx->done = 1;
 
448
 
 
449
    if (ctx->preallocated) {
 
450
        deflateEnd(&ctx->zstream);
 
451
 
 
452
        ngx_pfree(r->pool, ctx->preallocated);
 
453
    }
 
454
 
 
455
    ngx_http_gzip_filter_free_copy_buf(r, ctx);
 
456
 
 
457
    return NGX_ERROR;
 
458
}
 
459
 
 
460
 
 
461
static void
 
462
ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
 
463
{
 
464
    int                    wbits, memlevel;
 
465
    ngx_http_gzip_conf_t  *conf;
 
466
 
 
467
    conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
 
468
 
 
469
    wbits = conf->wbits;
 
470
    memlevel = conf->memlevel;
 
471
 
 
472
    if (r->headers_out.content_length_n > 0) {
 
473
 
 
474
        /* the actual zlib window size is smaller by 262 bytes */
 
475
 
 
476
        while (r->headers_out.content_length_n < ((1 << (wbits - 1)) - 262)) {
 
477
            wbits--;
 
478
            memlevel--;
 
479
        }
 
480
    }
 
481
 
 
482
    ctx->wbits = wbits;
 
483
    ctx->memlevel = memlevel;
 
484
 
 
485
    /*
 
486
     * We preallocate a memory for zlib in one buffer (200K-400K), this
 
487
     * decreases a number of malloc() and free() calls and also probably
 
488
     * decreases a number of syscalls (sbrk()/mmap() and so on).
 
489
     * Besides we free the memory as soon as a gzipping will complete
 
490
     * and do not wait while a whole response will be sent to a client.
 
491
     *
 
492
     * 8K is for zlib deflate_state, it takes
 
493
     *  *) 5816 bytes on i386 and sparc64 (32-bit mode)
 
494
     *  *) 5920 bytes on amd64 and sparc64
 
495
     */
 
496
 
 
497
    ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9));
 
498
}
 
499
 
 
500
 
 
501
static ngx_int_t
 
502
ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx, ngx_chain_t *in)
 
503
{
 
504
    size_t                 size, buffered;
 
505
    ngx_buf_t             *b, *buf;
 
506
    ngx_chain_t           *cl, **ll;
 
507
    ngx_http_request_t    *r;
 
508
    ngx_http_gzip_conf_t  *conf;
 
509
 
 
510
    r = ctx->request;
 
511
 
 
512
    r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED;
 
513
 
 
514
    buffered = 0;
 
515
    ll = &ctx->in;
 
516
 
 
517
    for (cl = ctx->in; cl; cl = cl->next) {
 
518
        buffered += cl->buf->last - cl->buf->pos;
 
519
        ll = &cl->next;
 
520
    }
 
521
 
 
522
    conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
 
523
 
 
524
    while (in) {
 
525
        cl = ngx_alloc_chain_link(r->pool);
 
526
        if (cl == NULL) {
 
527
            return NGX_ERROR;
 
528
        }
 
529
 
 
530
        b = in->buf;
 
531
 
 
532
        size = b->last - b->pos;
 
533
        buffered += size;
 
534
 
 
535
        if (b->flush || b->last_buf || buffered > conf->postpone_gzipping) {
 
536
            ctx->buffering = 0;
 
537
        }
 
538
 
 
539
        if (ctx->buffering && size) {
 
540
 
 
541
            buf = ngx_create_temp_buf(r->pool, size);
 
542
            if (buf == NULL) {
 
543
                return NGX_ERROR;
 
544
            }
 
545
 
 
546
            buf->last = ngx_cpymem(buf->pos, b->pos, size);
 
547
            b->pos = b->last;
 
548
 
 
549
            buf->last_buf = b->last_buf;
 
550
            buf->tag = (ngx_buf_tag_t) &ngx_http_gzip_filter_module;
 
551
 
 
552
            cl->buf = buf;
 
553
 
 
554
        } else {
 
555
            cl->buf = b;
 
556
        }
 
557
 
 
558
        *ll = cl;
 
559
        ll = &cl->next;
 
560
        in = in->next;
 
561
    }
 
562
 
 
563
    *ll = NULL;
 
564
 
 
565
    return ctx->buffering ? NGX_OK : NGX_DONE;
 
566
}
 
567
 
 
568
 
 
569
static ngx_int_t
 
570
ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r,
 
571
    ngx_http_gzip_ctx_t *ctx)
 
572
{
 
573
    int                    rc;
 
574
    ngx_http_gzip_conf_t  *conf;
 
575
 
 
576
    conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
 
577
 
 
578
    ctx->preallocated = ngx_palloc(r->pool, ctx->allocated);
 
579
    if (ctx->preallocated == NULL) {
 
580
        return NGX_ERROR;
 
581
    }
 
582
 
 
583
    ctx->free_mem = ctx->preallocated;
 
584
 
 
585
    ctx->zstream.zalloc = ngx_http_gzip_filter_alloc;
 
586
    ctx->zstream.zfree = ngx_http_gzip_filter_free;
 
587
    ctx->zstream.opaque = ctx;
 
588
 
 
589
    rc = deflateInit2(&ctx->zstream, (int) conf->level, Z_DEFLATED,
 
590
                      - ctx->wbits, ctx->memlevel, Z_DEFAULT_STRATEGY);
 
591
 
 
592
    if (rc != Z_OK) {
 
593
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
 
594
                      "deflateInit2() failed: %d", rc);
 
595
        return NGX_ERROR;
 
596
    }
 
597
 
 
598
    ctx->last_out = &ctx->out;
 
599
    ctx->crc32 = crc32(0L, Z_NULL, 0);
 
600
    ctx->flush = Z_NO_FLUSH;
 
601
 
 
602
    return NGX_OK;
 
603
}
 
604
 
 
605
 
 
606
static ngx_int_t
 
607
ngx_http_gzip_filter_gzheader(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
 
608
{
 
609
    ngx_buf_t      *b;
 
610
    ngx_chain_t    *cl;
 
611
    static u_char  gzheader[10] =
 
612
                               { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
 
613
 
 
614
    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
 
615
    if (b == NULL) {
 
616
        return NGX_ERROR;
 
617
    }
 
618
 
 
619
    b->memory = 1;
 
620
    b->pos = gzheader;
 
621
    b->last = b->pos + 10;
 
622
 
 
623
    cl = ngx_alloc_chain_link(r->pool);
 
624
    if (cl == NULL) {
 
625
        return NGX_ERROR;
 
626
    }
 
627
 
 
628
    cl->buf = b;
 
629
    cl->next = ctx->out;
 
630
    ctx->out = cl;
 
631
 
 
632
    ctx->gzheader = 1;
 
633
 
 
634
    return NGX_OK;
 
635
}
 
636
 
 
637
 
 
638
static ngx_int_t
 
639
ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
 
640
{
 
641
    if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) {
 
642
        return NGX_OK;
 
643
    }
 
644
 
 
645
    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
 
646
                   "gzip in: %p", ctx->in);
 
647
 
 
648
    if (ctx->in == NULL) {
 
649
        return NGX_DECLINED;
 
650
    }
 
651
 
 
652
    if (ctx->copy_buf) {
 
653
 
 
654
        /*
 
655
         * to avoid CPU cache trashing we do not free() just quit buf,
 
656
         * but postpone free()ing after zlib compressing and data output
 
657
         */
 
658
 
 
659
        ctx->copy_buf->next = ctx->copied;
 
660
        ctx->copied = ctx->copy_buf;
 
661
        ctx->copy_buf = NULL;
 
662
    }
 
663
 
 
664
    ctx->in_buf = ctx->in->buf;
 
665
 
 
666
    if (ctx->in_buf->tag == (ngx_buf_tag_t) &ngx_http_gzip_filter_module) {
 
667
        ctx->copy_buf = ctx->in;
 
668
    }
 
669
 
 
670
    ctx->in = ctx->in->next;
 
671
 
 
672
    ctx->zstream.next_in = ctx->in_buf->pos;
 
673
    ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos;
 
674
 
 
675
    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
 
676
                   "gzip in_buf:%p ni:%p ai:%ud",
 
677
                   ctx->in_buf,
 
678
                   ctx->zstream.next_in, ctx->zstream.avail_in);
 
679
 
 
680
    if (ctx->in_buf->last_buf) {
 
681
        ctx->flush = Z_FINISH;
 
682
 
 
683
    } else if (ctx->in_buf->flush) {
 
684
        ctx->flush = Z_SYNC_FLUSH;
 
685
    }
 
686
 
 
687
    if (ctx->zstream.avail_in) {
 
688
 
 
689
        ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in,
 
690
                           ctx->zstream.avail_in);
 
691
 
 
692
    } else if (ctx->flush == Z_NO_FLUSH) {
 
693
        return NGX_AGAIN;
 
694
    }
 
695
 
 
696
    return NGX_OK;
 
697
}
 
698
 
 
699
 
 
700
static ngx_int_t
 
701
ngx_http_gzip_filter_get_buf(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
 
702
{
 
703
    ngx_http_gzip_conf_t  *conf;
 
704
 
 
705
    if (ctx->zstream.avail_out) {
 
706
        return NGX_OK;
 
707
    }
 
708
 
 
709
    conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
 
710
 
 
711
    if (ctx->free) {
 
712
        ctx->out_buf = ctx->free->buf;
 
713
        ctx->free = ctx->free->next;
 
714
 
 
715
    } else if (ctx->bufs < conf->bufs.num) {
 
716
 
 
717
        ctx->out_buf = ngx_create_temp_buf(r->pool, conf->bufs.size);
 
718
        if (ctx->out_buf == NULL) {
 
719
            return NGX_ERROR;
 
720
        }
 
721
 
 
722
        ctx->out_buf->tag = (ngx_buf_tag_t) &ngx_http_gzip_filter_module;
 
723
        ctx->out_buf->recycled = 1;
 
724
        ctx->bufs++;
 
725
 
 
726
    } else {
 
727
        ctx->nomem = 1;
 
728
        return NGX_DECLINED;
 
729
    }
 
730
 
 
731
    ctx->zstream.next_out = ctx->out_buf->pos;
 
732
    ctx->zstream.avail_out = conf->bufs.size;
 
733
 
 
734
    return NGX_OK;
 
735
}
 
736
 
 
737
 
 
738
static ngx_int_t
 
739
ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
 
740
{
 
741
    int                    rc;
 
742
    ngx_chain_t           *cl;
 
743
    ngx_http_gzip_conf_t  *conf;
 
744
 
 
745
    ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
 
746
                 "deflate in: ni:%p no:%p ai:%ud ao:%ud fl:%d redo:%d",
 
747
                 ctx->zstream.next_in, ctx->zstream.next_out,
 
748
                 ctx->zstream.avail_in, ctx->zstream.avail_out,
 
749
                 ctx->flush, ctx->redo);
 
750
 
 
751
    rc = deflate(&ctx->zstream, ctx->flush);
 
752
 
 
753
    if (rc != Z_OK && rc != Z_STREAM_END) {
 
754
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
 
755
                      "deflate() failed: %d, %d", ctx->flush, rc);
 
756
        return NGX_ERROR;
 
757
    }
 
758
 
 
759
    ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
 
760
                   "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
 
761
                   ctx->zstream.next_in, ctx->zstream.next_out,
 
762
                   ctx->zstream.avail_in, ctx->zstream.avail_out,
 
763
                   rc);
 
764
 
 
765
    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
 
766
                   "gzip in_buf:%p pos:%p",
 
767
                   ctx->in_buf, ctx->in_buf->pos);
 
768
 
 
769
    if (ctx->zstream.next_in) {
 
770
        ctx->in_buf->pos = ctx->zstream.next_in;
 
771
 
 
772
        if (ctx->zstream.avail_in == 0) {
 
773
            ctx->zstream.next_in = NULL;
 
774
        }
 
775
    }
 
776
 
 
777
    ctx->out_buf->last = ctx->zstream.next_out;
 
778
 
 
779
    if (ctx->zstream.avail_out == 0) {
 
780
 
 
781
        /* zlib wants to output some more gzipped data */
 
782
 
 
783
        cl = ngx_alloc_chain_link(r->pool);
 
784
        if (cl == NULL) {
 
785
            return NGX_ERROR;
 
786
        }
 
787
 
 
788
        cl->buf = ctx->out_buf;
 
789
        cl->next = NULL;
 
790
        *ctx->last_out = cl;
 
791
        ctx->last_out = &cl->next;
 
792
 
 
793
        ctx->redo = 1;
 
794
 
 
795
        return NGX_AGAIN;
 
796
    }
 
797
 
 
798
    ctx->redo = 0;
 
799
 
 
800
    if (ctx->flush == Z_SYNC_FLUSH) {
 
801
 
 
802
        ctx->zstream.avail_out = 0;
 
803
        ctx->out_buf->flush = 1;
 
804
        ctx->flush = Z_NO_FLUSH;
 
805
 
 
806
        cl = ngx_alloc_chain_link(r->pool);
 
807
        if (cl == NULL) {
 
808
            return NGX_ERROR;
 
809
        }
 
810
 
 
811
        cl->buf = ctx->out_buf;
 
812
        cl->next = NULL;
 
813
        *ctx->last_out = cl;
 
814
        ctx->last_out = &cl->next;
 
815
 
 
816
        return NGX_OK;
 
817
    }
 
818
 
 
819
    if (rc == Z_STREAM_END) {
 
820
 
 
821
        if (ngx_http_gzip_filter_deflate_end(r, ctx) != NGX_OK) {
 
822
            return NGX_ERROR;
 
823
        }
 
824
 
 
825
        return NGX_OK;
 
826
    }
 
827
 
 
828
    conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
 
829
 
 
830
    if (conf->no_buffer && ctx->in == NULL) {
 
831
 
 
832
        cl = ngx_alloc_chain_link(r->pool);
 
833
        if (cl == NULL) {
 
834
            return NGX_ERROR;
 
835
        }
 
836
 
 
837
        cl->buf = ctx->out_buf;
 
838
        cl->next = NULL;
 
839
        *ctx->last_out = cl;
 
840
        ctx->last_out = &cl->next;
 
841
 
 
842
        return NGX_OK;
 
843
    }
 
844
 
 
845
    return NGX_AGAIN;
 
846
}
 
847
 
 
848
 
 
849
static ngx_int_t
 
850
ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r,
 
851
    ngx_http_gzip_ctx_t *ctx)
 
852
{
 
853
    int                rc;
 
854
    ngx_buf_t         *b;
 
855
    ngx_chain_t       *cl;
 
856
    struct gztrailer  *trailer;
 
857
 
 
858
    ctx->zin = ctx->zstream.total_in;
 
859
    ctx->zout = 10 + ctx->zstream.total_out + 8;
 
860
 
 
861
    rc = deflateEnd(&ctx->zstream);
 
862
 
 
863
    if (rc != Z_OK) {
 
864
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
 
865
                      "deflateEnd() failed: %d", rc);
 
866
        return NGX_ERROR;
 
867
    }
 
868
 
 
869
    ngx_pfree(r->pool, ctx->preallocated);
 
870
 
 
871
    cl = ngx_alloc_chain_link(r->pool);
 
872
    if (cl == NULL) {
 
873
        return NGX_ERROR;
 
874
    }
 
875
 
 
876
    cl->buf = ctx->out_buf;
 
877
    cl->next = NULL;
 
878
    *ctx->last_out = cl;
 
879
    ctx->last_out = &cl->next;
 
880
 
 
881
    if (ctx->zstream.avail_out >= 8) {
 
882
        trailer = (struct gztrailer *) ctx->out_buf->last;
 
883
        ctx->out_buf->last += 8;
 
884
        ctx->out_buf->last_buf = 1;
 
885
 
 
886
    } else {
 
887
        b = ngx_create_temp_buf(r->pool, 8);
 
888
        if (b == NULL) {
 
889
            return NGX_ERROR;
 
890
        }
 
891
 
 
892
        b->last_buf = 1;
 
893
 
 
894
        cl = ngx_alloc_chain_link(r->pool);
 
895
        if (cl == NULL) {
 
896
            return NGX_ERROR;
 
897
        }
 
898
 
 
899
        cl->buf = b;
 
900
        cl->next = NULL;
 
901
        *ctx->last_out = cl;
 
902
        ctx->last_out = &cl->next;
 
903
        trailer = (struct gztrailer *) b->pos;
 
904
        b->last += 8;
 
905
    }
 
906
 
 
907
#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
 
908
 
 
909
    trailer->crc32 = ctx->crc32;
 
910
    trailer->zlen = ctx->zin;
 
911
 
 
912
#else
 
913
 
 
914
    trailer->crc32[0] = (u_char) (ctx->crc32 & 0xff);
 
915
    trailer->crc32[1] = (u_char) ((ctx->crc32 >> 8) & 0xff);
 
916
    trailer->crc32[2] = (u_char) ((ctx->crc32 >> 16) & 0xff);
 
917
    trailer->crc32[3] = (u_char) ((ctx->crc32 >> 24) & 0xff);
 
918
 
 
919
    trailer->zlen[0] = (u_char) (ctx->zin & 0xff);
 
920
    trailer->zlen[1] = (u_char) ((ctx->zin >> 8) & 0xff);
 
921
    trailer->zlen[2] = (u_char) ((ctx->zin >> 16) & 0xff);
 
922
    trailer->zlen[3] = (u_char) ((ctx->zin >> 24) & 0xff);
 
923
 
 
924
#endif
 
925
 
 
926
    ctx->zstream.avail_in = 0;
 
927
    ctx->zstream.avail_out = 0;
 
928
 
 
929
    ctx->done = 1;
 
930
 
 
931
    r->connection->buffered &= ~NGX_HTTP_GZIP_BUFFERED;
 
932
 
 
933
    return NGX_OK;
680
934
}
681
935
 
682
936
 
690
944
 
691
945
    alloc = items * size;
692
946
 
693
 
    if (alloc % 512 != 0) {
 
947
    if (alloc % 512 != 0 && alloc < 8192) {
694
948
 
695
949
        /*
696
950
         * The zlib deflate_state allocation, it takes about 6K,
697
951
         * we allocate 8K.  Other allocations are divisible by 512.
698
952
         */
699
953
 
700
 
        alloc = (alloc + ngx_pagesize - 1) & ~(ngx_pagesize - 1);
 
954
        alloc = 8192;
701
955
    }
702
956
 
703
957
    if (alloc <= ctx->allocated) {
735
989
 
736
990
 
737
991
static void
738
 
ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx)
 
992
ngx_http_gzip_filter_free_copy_buf(ngx_http_request_t *r,
 
993
    ngx_http_gzip_ctx_t *ctx)
739
994
{
740
 
    deflateEnd(&ctx->zstream);
 
995
    ngx_chain_t  *cl;
741
996
 
742
 
    if (ctx->preallocated) {
743
 
        ngx_pfree(ctx->request->pool, ctx->preallocated);
 
997
    for (cl = ctx->copied; cl; cl = cl->next) {
 
998
        ngx_pfree(r->pool, cl->buf->start);
744
999
    }
745
1000
 
746
 
    ctx->zstream.avail_in = 0;
747
 
    ctx->zstream.avail_out = 0;
748
 
 
749
 
    ctx->done = 1;
750
 
 
751
 
    return;
 
1001
    ctx->copied = NULL;
752
1002
}
753
1003
 
754
1004
 
786
1036
        return NGX_OK;
787
1037
    }
788
1038
 
789
 
    v->data = ngx_palloc(r->pool, NGX_INT32_LEN + 3);
 
1039
    v->data = ngx_pnalloc(r->pool, NGX_INT32_LEN + 3);
790
1040
    if (v->data == NULL) {
791
1041
        return NGX_ERROR;
792
1042
    }
826
1076
     * set by ngx_pcalloc():
827
1077
     *
828
1078
     *     conf->bufs.num = 0;
829
 
     *     conf->types = NULL;
 
1079
     *     conf->types = { NULL };
 
1080
     *     conf->types_keys = NULL;
830
1081
     */
831
1082
 
832
1083
    conf->enable = NGX_CONF_UNSET;
833
1084
    conf->no_buffer = NGX_CONF_UNSET;
834
1085
 
 
1086
    conf->postpone_gzipping = NGX_CONF_UNSET_SIZE;
835
1087
    conf->level = NGX_CONF_UNSET;
836
 
    conf->wbits = (size_t) NGX_CONF_UNSET;
837
 
    conf->memlevel = (size_t) NGX_CONF_UNSET;
 
1088
    conf->wbits = NGX_CONF_UNSET_SIZE;
 
1089
    conf->memlevel = NGX_CONF_UNSET_SIZE;
838
1090
    conf->min_length = NGX_CONF_UNSET;
839
1091
 
840
1092
    return conf;
847
1099
    ngx_http_gzip_conf_t *prev = parent;
848
1100
    ngx_http_gzip_conf_t *conf = child;
849
1101
 
850
 
    ngx_str_t  *type;
851
 
 
852
1102
    ngx_conf_merge_value(conf->enable, prev->enable, 0);
853
 
 
854
 
    ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 4, ngx_pagesize);
855
 
 
 
1103
    ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0);
 
1104
 
 
1105
    ngx_conf_merge_bufs_value(conf->bufs, prev->bufs,
 
1106
                              (128 * 1024) / ngx_pagesize, ngx_pagesize);
 
1107
 
 
1108
    ngx_conf_merge_size_value(conf->postpone_gzipping, prev->postpone_gzipping,
 
1109
                              0);
856
1110
    ngx_conf_merge_value(conf->level, prev->level, 1);
857
1111
    ngx_conf_merge_size_value(conf->wbits, prev->wbits, MAX_WBITS);
858
1112
    ngx_conf_merge_size_value(conf->memlevel, prev->memlevel,
859
1113
                              MAX_MEM_LEVEL - 1);
860
1114
    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
 
        }
 
1115
 
 
1116
    if (ngx_http_merge_types(cf, conf->types_keys, &conf->types,
 
1117
                             prev->types_keys, &prev->types,
 
1118
                             ngx_http_html_default_types)
 
1119
        != NGX_OK)
 
1120
    {
 
1121
        return NGX_CONF_ERROR;
881
1122
    }
882
1123
 
883
1124
    return NGX_CONF_OK;
898
1139
 
899
1140
 
900
1141
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
1142
ngx_http_gzip_window(ngx_conf_t *cf, void *post, void *data)
952
1143
{
953
 
    int *np = data;
 
1144
    size_t *np = data;
954
1145
 
955
 
    int  wbits, wsize;
 
1146
    size_t  wbits, wsize;
956
1147
 
957
1148
    wbits = 15;
958
1149
 
974
1165
static char *
975
1166
ngx_http_gzip_hash(ngx_conf_t *cf, void *post, void *data)
976
1167
{
977
 
    int *np = data;
 
1168
    size_t *np = data;
978
1169
 
979
 
    int  memlevel, hsize;
 
1170
    size_t  memlevel, hsize;
980
1171
 
981
1172
    memlevel = 9;
982
1173