~ubuntu-branches/ubuntu/karmic/apache2/karmic-security

« back to all changes in this revision

Viewing changes to modules/filters/mod_deflate.c

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Fritsch
  • Date: 2008-10-01 11:50:18 UTC
  • mfrom: (34 intrepid)
  • mto: (14.2.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 40.
  • Revision ID: james.westby@ubuntu.com-20081001115018-1022gw429ce4pqyp
Tags: 2.2.9-10
Regression fix from upstream svn for mod_proxy_http:
Don't trigger a retry by the client if a failure to read the response line
was the result of a timeout.

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
#include "httpd.h"
38
38
#include "http_config.h"
39
39
#include "http_log.h"
 
40
#include "apr_lib.h"
40
41
#include "apr_strings.h"
41
42
#include "apr_general.h"
42
43
#include "util_filter.h"
82
83
#define DEFAULT_MEMLEVEL 9
83
84
#define DEFAULT_BUFFERSIZE 8096
84
85
 
 
86
 
 
87
/* Check whether a request is gzipped, so we can un-gzip it.
 
88
 * If a request has multiple encodings, we need the gzip
 
89
 * to be the outermost non-identity encoding.
 
90
 */
 
91
static int check_gzip(request_rec *r, apr_table_t *hdrs1, apr_table_t *hdrs2)
 
92
{
 
93
    int found = 0;
 
94
    apr_table_t *hdrs = hdrs1;
 
95
    const char *encoding = apr_table_get(hdrs, "Content-Encoding");
 
96
 
 
97
    if (!encoding && (hdrs2 != NULL)) {
 
98
        /* the output filter has two tables and a content_encoding to check */
 
99
        encoding = apr_table_get(hdrs2, "Content-Encoding");
 
100
        hdrs = hdrs2;
 
101
        if (!encoding) {
 
102
            encoding = r->content_encoding;
 
103
            hdrs = NULL;
 
104
        }
 
105
    }
 
106
    if (encoding && *encoding) {
 
107
 
 
108
        /* check the usual/simple case first */
 
109
        if (!strcasecmp(encoding, "gzip")
 
110
            || !strcasecmp(encoding, "x-gzip")) {
 
111
            found = 1;
 
112
            if (hdrs) {
 
113
                apr_table_unset(hdrs, "Content-Encoding");
 
114
            }
 
115
            else {
 
116
                r->content_encoding = NULL;
 
117
            }
 
118
        }
 
119
        else if (ap_strchr_c(encoding, ',') != NULL) {
 
120
            /* If the outermost encoding isn't gzip, there's nowt
 
121
             * we can do.  So only check the last non-identity token
 
122
             */
 
123
            char *new_encoding = apr_pstrdup(r->pool, encoding);
 
124
            char *ptr;
 
125
            for(;;) {
 
126
                char *token = ap_strrchr(new_encoding, ',');
 
127
                if (!token) {        /* gzip:identity or other:identity */
 
128
                    if (!strcasecmp(new_encoding, "gzip")
 
129
                        || !strcasecmp(new_encoding, "x-gzip")) {
 
130
                        found = 1;
 
131
                        if (hdrs) {
 
132
                            apr_table_unset(hdrs, "Content-Encoding");
 
133
                        }
 
134
                        else {
 
135
                            r->content_encoding = NULL;
 
136
                        }
 
137
                    }
 
138
                    break; /* seen all tokens */
 
139
                }
 
140
                for (ptr=token+1; apr_isspace(*ptr); ++ptr);
 
141
                if (!strcasecmp(ptr, "gzip")
 
142
                    || !strcasecmp(ptr, "x-gzip")) {
 
143
                    *token = '\0';
 
144
                    if (hdrs) {
 
145
                        apr_table_setn(hdrs, "Content-Encoding", new_encoding);
 
146
                    }
 
147
                    else {
 
148
                        r->content_encoding = new_encoding;
 
149
                    }
 
150
                    found = 1;
 
151
                }
 
152
                else if (!ptr[0] || !strcasecmp(ptr, "identity")) {
 
153
                    *token = '\0';
 
154
                    continue; /* strip the token and find the next one */
 
155
                }
 
156
                break; /* found a non-identity token */
 
157
            }
 
158
        }
 
159
    }
 
160
    return found;
 
161
}
 
162
 
85
163
/* Outputs a long in LSB order to the given file
86
164
 * only the bottom 4 bits are required for the deflate file format.
87
165
 */
212
290
    unsigned char *buffer;
213
291
    unsigned long crc;
214
292
    apr_bucket_brigade *bb, *proc_bb;
 
293
    int (*libz_end_func)(z_streamp);
 
294
    unsigned char *validation_buffer;
 
295
    apr_size_t validation_buffer_length;
 
296
    int inflate_init;
215
297
} deflate_ctx;
216
298
 
 
299
/* Number of validation bytes (CRC and length) after the compressed data */
 
300
#define VALIDATION_SIZE 8
 
301
/* Do not update ctx->crc, see comment in flush_libz_buffer */
 
302
#define NO_UPDATE_CRC 0
 
303
/* Do update ctx->crc, see comment in flush_libz_buffer */
 
304
#define UPDATE_CRC 1
 
305
 
 
306
static int flush_libz_buffer(deflate_ctx *ctx, deflate_filter_config *c,
 
307
                             struct apr_bucket_alloc_t *bucket_alloc,
 
308
                             int (*libz_func)(z_streamp, int), int flush,
 
309
                             int crc)
 
310
{
 
311
    int zRC = Z_OK;
 
312
    int done = 0;
 
313
    unsigned int deflate_len;
 
314
    apr_bucket *b;
 
315
 
 
316
    for (;;) {
 
317
         deflate_len = c->bufferSize - ctx->stream.avail_out;
 
318
 
 
319
         if (deflate_len != 0) {
 
320
             /*
 
321
              * Do we need to update ctx->crc? Usually this is the case for
 
322
              * inflate action where we need to do a crc on the output, whereas
 
323
              * in the deflate case we need to do a crc on the input
 
324
              */
 
325
             if (crc) {
 
326
                 ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
 
327
                                  deflate_len);
 
328
             }
 
329
             b = apr_bucket_heap_create((char *)ctx->buffer,
 
330
                                        deflate_len, NULL,
 
331
                                        bucket_alloc);
 
332
             APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
 
333
             ctx->stream.next_out = ctx->buffer;
 
334
             ctx->stream.avail_out = c->bufferSize;
 
335
         }
 
336
 
 
337
         if (done)
 
338
             break;
 
339
 
 
340
         zRC = libz_func(&ctx->stream, flush);
 
341
 
 
342
         /*
 
343
          * We can ignore Z_BUF_ERROR because:
 
344
          * When we call libz_func we can assume that
 
345
          *
 
346
          * - avail_in is zero (due to the surrounding code that calls
 
347
          *   flush_libz_buffer)
 
348
          * - avail_out is non zero due to our actions some lines above
 
349
          *
 
350
          * So the only reason for Z_BUF_ERROR is that the internal libz
 
351
          * buffers are now empty and thus we called libz_func one time
 
352
          * too often. This does not hurt. It simply says that we are done.
 
353
          */
 
354
         if (zRC == Z_BUF_ERROR) {
 
355
             zRC = Z_OK;
 
356
             break;
 
357
         }
 
358
 
 
359
         done = (ctx->stream.avail_out != 0 || zRC == Z_STREAM_END);
 
360
 
 
361
         if (zRC != Z_OK && zRC != Z_STREAM_END)
 
362
             break;
 
363
    }
 
364
    return zRC;
 
365
}
 
366
 
 
367
static apr_status_t deflate_ctx_cleanup(void *data)
 
368
{
 
369
    deflate_ctx *ctx = (deflate_ctx *)data;
 
370
 
 
371
    if (ctx)
 
372
        ctx->libz_end_func(&ctx->stream);
 
373
    return APR_SUCCESS;
 
374
}
 
375
/* PR 39727: we're screwing up our clients if we leave a strong ETag
 
376
 * header while transforming content.  Henrik Nordstrom suggests
 
377
 * appending ";gzip".
 
378
 *
 
379
 * Pending a more thorough review of our Etag handling, let's just
 
380
 * implement his suggestion.  It fixes the bug, or at least turns it
 
381
 * from a showstopper to an inefficiency.  And it breaks nothing that
 
382
 * wasn't already broken.
 
383
 */
 
384
static void deflate_check_etag(request_rec *r, const char *transform)
 
385
{
 
386
    const char *etag = apr_table_get(r->headers_out, "ETag");
 
387
    if (etag && (((etag[0] != 'W') && (etag[0] !='w')) || (etag[1] != '/'))) {
 
388
        apr_table_set(r->headers_out, "ETag",
 
389
                      apr_pstrcat(r->pool, etag, "-", transform, NULL));
 
390
    }
 
391
}
217
392
static apr_status_t deflate_out_filter(ap_filter_t *f,
218
393
                                       apr_bucket_brigade *bb)
219
394
{
221
396
    request_rec *r = f->r;
222
397
    deflate_ctx *ctx = f->ctx;
223
398
    int zRC;
224
 
    deflate_filter_config *c = ap_get_module_config(r->server->module_config,
225
 
                                                    &deflate_module);
 
399
    deflate_filter_config *c;
226
400
 
227
401
    /* Do nothing if asked to filter nothing. */
228
402
    if (APR_BRIGADE_EMPTY(bb)) {
229
 
        return APR_SUCCESS;
 
403
        return ap_pass_brigade(f->next, bb);
230
404
    }
231
405
 
 
406
    c = ap_get_module_config(r->server->module_config,
 
407
                             &deflate_module);
 
408
 
232
409
    /* If we don't have a context, we need to ensure that it is okay to send
233
410
     * the deflated content.  If we have a context, that means we've done
234
411
     * this before and we liked it.
253
430
            return ap_pass_brigade(f->next, bb);
254
431
        }
255
432
 
 
433
        /* We can't operate on Content-Ranges */
 
434
        if (apr_table_get(r->headers_out, "Content-Range") != NULL) {
 
435
            ap_remove_output_filter(f);
 
436
            return ap_pass_brigade(f->next, bb);
 
437
        }
 
438
 
256
439
        /* Some browsers might have problems with content types
257
440
         * other than text/html, so set gzip-only-text/html
258
441
         * (with browsermatch) for them
362
545
        ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx));
363
546
        ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
364
547
        ctx->buffer = apr_palloc(r->pool, c->bufferSize);
 
548
        ctx->libz_end_func = deflateEnd;
365
549
 
366
550
        zRC = deflateInit2(&ctx->stream, c->compressionlevel, Z_DEFLATED,
367
551
                           c->windowSize, c->memlevel,
368
552
                           Z_DEFAULT_STRATEGY);
369
553
 
370
554
        if (zRC != Z_OK) {
371
 
            f->ctx = NULL;
 
555
            deflateEnd(&ctx->stream);
372
556
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
373
557
                          "unable to init Zlib: "
374
558
                          "deflateInit2 returned %d: URL %s",
375
559
                          zRC, r->uri);
 
560
            /*
 
561
             * Remove ourselves as it does not make sense to return:
 
562
             * We are not able to init libz and pass data down the chain
 
563
             * uncompressed.
 
564
             */
 
565
            ap_remove_output_filter(f);
376
566
            return ap_pass_brigade(f->next, bb);
377
567
        }
 
568
        /*
 
569
         * Register a cleanup function to ensure that we cleanup the internal
 
570
         * libz resources.
 
571
         */
 
572
        apr_pool_cleanup_register(r->pool, ctx, deflate_ctx_cleanup,
 
573
                                  apr_pool_cleanup_null);
378
574
 
379
575
        /* add immortal gzip header */
380
576
        e = apr_bucket_immortal_create(gzip_header, sizeof gzip_header,
389
585
            apr_table_mergen(r->headers_out, "Content-Encoding", "gzip");
390
586
        }
391
587
        apr_table_unset(r->headers_out, "Content-Length");
 
588
        apr_table_unset(r->headers_out, "Content-MD5");
 
589
        deflate_check_etag(r, "gzip");
392
590
 
393
591
        /* initialize deflate output buffer */
394
592
        ctx->stream.next_out = ctx->buffer;
400
598
        const char *data;
401
599
        apr_bucket *b;
402
600
        apr_size_t len;
403
 
        int done = 0;
404
601
 
405
602
        e = APR_BRIGADE_FIRST(bb);
406
603
 
407
604
        if (APR_BUCKET_IS_EOS(e)) {
408
605
            char *buf;
409
 
            unsigned int deflate_len;
410
606
 
411
607
            ctx->stream.avail_in = 0; /* should be zero already anyway */
412
 
            for (;;) {
413
 
                deflate_len = c->bufferSize - ctx->stream.avail_out;
414
 
 
415
 
                if (deflate_len != 0) {
416
 
                    b = apr_bucket_heap_create((char *)ctx->buffer,
417
 
                                               deflate_len, NULL,
418
 
                                               f->c->bucket_alloc);
419
 
                    APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
420
 
                    ctx->stream.next_out = ctx->buffer;
421
 
                    ctx->stream.avail_out = c->bufferSize;
422
 
                }
423
 
 
424
 
                if (done) {
425
 
                    break;
426
 
                }
427
 
 
428
 
                zRC = deflate(&ctx->stream, Z_FINISH);
429
 
 
430
 
                if (deflate_len == 0 && zRC == Z_BUF_ERROR) {
431
 
                    zRC = Z_OK;
432
 
                }
433
 
 
434
 
                done = (ctx->stream.avail_out != 0 || zRC == Z_STREAM_END);
435
 
 
436
 
                if (zRC != Z_OK && zRC != Z_STREAM_END) {
437
 
                    break;
438
 
                }
439
 
            }
440
 
 
441
 
            buf = apr_palloc(r->pool, 8);
 
608
            /* flush the remaining data from the zlib buffers */
 
609
            flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate, Z_FINISH,
 
610
                              NO_UPDATE_CRC);
 
611
 
 
612
            buf = apr_palloc(r->pool, VALIDATION_SIZE);
442
613
            putLong((unsigned char *)&buf[0], ctx->crc);
443
614
            putLong((unsigned char *)&buf[4], ctx->stream.total_in);
444
615
 
445
 
            b = apr_bucket_pool_create(buf, 8, r->pool, f->c->bucket_alloc);
 
616
            b = apr_bucket_pool_create(buf, VALIDATION_SIZE, r->pool,
 
617
                                       f->c->bucket_alloc);
446
618
            APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
447
619
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
448
620
                          "Zlib: Compressed %ld to %ld : URL %s",
476
648
            }
477
649
 
478
650
            deflateEnd(&ctx->stream);
 
651
            /* No need for cleanup any longer */
 
652
            apr_pool_cleanup_kill(r->pool, ctx, deflate_ctx_cleanup);
479
653
 
480
654
            /* Remove EOS from the old list, and insert into the new. */
481
655
            APR_BUCKET_REMOVE(e);
488
662
        }
489
663
 
490
664
        if (APR_BUCKET_IS_FLUSH(e)) {
491
 
            apr_bucket *bkt;
492
665
            apr_status_t rv;
493
666
 
494
 
            apr_bucket_delete(e);
495
 
 
496
 
            if (ctx->stream.avail_in > 0) {
497
 
                zRC = deflate(&(ctx->stream), Z_SYNC_FLUSH);
498
 
                if (zRC != Z_OK) {
499
 
                    return APR_EGENERAL;
500
 
                }
 
667
            /* flush the remaining data from the zlib buffers */
 
668
            zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate,
 
669
                                    Z_SYNC_FLUSH, NO_UPDATE_CRC);
 
670
            if (zRC != Z_OK) {
 
671
                return APR_EGENERAL;
501
672
            }
502
673
 
503
 
            ctx->stream.next_out = ctx->buffer;
504
 
            len = c->bufferSize - ctx->stream.avail_out;
505
 
 
506
 
            b = apr_bucket_heap_create((char *)ctx->buffer, len,
507
 
                                       NULL, f->c->bucket_alloc);
508
 
            APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
509
 
            ctx->stream.avail_out = c->bufferSize;
510
 
 
511
 
            bkt = apr_bucket_flush_create(f->c->bucket_alloc);
512
 
            APR_BRIGADE_INSERT_TAIL(ctx->bb, bkt);
 
674
            /* Remove flush bucket from old brigade anf insert into the new. */
 
675
            APR_BUCKET_REMOVE(e);
 
676
            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
513
677
            rv = ap_pass_brigade(f->next, ctx->bb);
514
678
            if (rv != APR_SUCCESS) {
515
679
                return rv;
517
681
            continue;
518
682
        }
519
683
 
 
684
        if (APR_BUCKET_IS_METADATA(e)) {
 
685
            /*
 
686
             * Remove meta data bucket from old brigade and insert into the
 
687
             * new.
 
688
             */
 
689
            APR_BUCKET_REMOVE(e);
 
690
            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
 
691
            continue;
 
692
        }
 
693
 
520
694
        /* read */
521
695
        apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
522
696
 
549
723
 
550
724
            zRC = deflate(&(ctx->stream), Z_NO_FLUSH);
551
725
 
552
 
            if (zRC != Z_OK)
 
726
            if (zRC != Z_OK) {
553
727
                return APR_EGENERAL;
 
728
            }
554
729
        }
555
730
 
556
731
        apr_bucket_delete(e);
582
757
    c = ap_get_module_config(r->server->module_config, &deflate_module);
583
758
 
584
759
    if (!ctx) {
585
 
        int found = 0;
586
 
        char *token, deflate_hdr[10];
587
 
        const char *encoding;
 
760
        char deflate_hdr[10];
588
761
        apr_size_t len;
589
762
 
590
763
        /* only work on main request/no subrequests */
593
766
            return ap_get_brigade(f->next, bb, mode, block, readbytes);
594
767
        }
595
768
 
596
 
        /* Let's see what our current Content-Encoding is.
597
 
         * If gzip is present, don't gzip again.  (We could, but let's not.)
 
769
        /* We can't operate on Content-Ranges */
 
770
        if (apr_table_get(r->headers_in, "Content-Range") != NULL) {
 
771
            ap_remove_input_filter(f);
 
772
            return ap_get_brigade(f->next, bb, mode, block, readbytes);
 
773
        }
 
774
 
 
775
        /* Check whether request body is gzipped.
 
776
         *
 
777
         * If it is, we're transforming the contents, invalidating
 
778
         * some request headers including Content-Encoding.
 
779
         *
 
780
         * If not, we just remove ourself.
598
781
         */
599
 
        encoding = apr_table_get(r->headers_in, "Content-Encoding");
600
 
        if (encoding) {
601
 
            const char *tmp = encoding;
602
 
 
603
 
            token = ap_get_token(r->pool, &tmp, 0);
604
 
            while (token && token[0]) {
605
 
                if (!strcasecmp(token, "gzip")) {
606
 
                    found = 1;
607
 
                    break;
608
 
                }
609
 
                /* Otherwise, skip token */
610
 
                tmp++;
611
 
                token = ap_get_token(r->pool, &tmp, 0);
612
 
            }
613
 
        }
614
 
 
615
 
        if (found == 0) {
 
782
        if (check_gzip(r, r->headers_in, NULL) == 0) {
616
783
            ap_remove_input_filter(f);
617
784
            return ap_get_brigade(f->next, bb, mode, block, readbytes);
618
785
        }
627
794
            return rv;
628
795
        }
629
796
 
 
797
        apr_table_unset(r->headers_in, "Content-Length");
 
798
        apr_table_unset(r->headers_in, "Content-MD5");
 
799
 
630
800
        len = 10;
631
801
        rv = apr_brigade_flatten(ctx->bb, deflate_hdr, &len);
632
802
        if (rv != APR_SUCCESS) {
831
1001
{
832
1002
    int zlib_method;
833
1003
    int zlib_flags;
834
 
    int deflate_init = 1;
835
 
    apr_bucket *bkt;
 
1004
    apr_bucket *e;
836
1005
    request_rec *r = f->r;
837
1006
    deflate_ctx *ctx = f->ctx;
838
1007
    int zRC;
841
1010
 
842
1011
    /* Do nothing if asked to filter nothing. */
843
1012
    if (APR_BRIGADE_EMPTY(bb)) {
844
 
        return APR_SUCCESS;
 
1013
        return ap_pass_brigade(f->next, bb);
845
1014
    }
846
1015
 
847
1016
    c = ap_get_module_config(r->server->module_config, &deflate_module);
848
1017
 
849
1018
    if (!ctx) {
850
 
        int found = 0;
851
 
        char *token;
852
 
        const char *encoding;
853
1019
 
854
1020
        /* only work on main request/no subrequests */
855
1021
        if (!ap_is_initial_req(r)) {
857
1023
            return ap_pass_brigade(f->next, bb);
858
1024
        }
859
1025
 
860
 
        /* Let's see what our current Content-Encoding is.
861
 
         * If gzip is present, don't gzip again.  (We could, but let's not.)
 
1026
        /* We can't operate on Content-Ranges */
 
1027
        if (apr_table_get(r->headers_out, "Content-Range") != NULL) {
 
1028
            ap_remove_output_filter(f);
 
1029
            return ap_pass_brigade(f->next, bb);
 
1030
        }
 
1031
 
 
1032
        /*
 
1033
         * Let's see what our current Content-Encoding is.
 
1034
         * Only inflate if gzipped.
862
1035
         */
863
 
        encoding = apr_table_get(r->headers_out, "Content-Encoding");
864
 
        if (encoding) {
865
 
            const char *tmp = encoding;
866
 
 
867
 
            token = ap_get_token(r->pool, &tmp, 0);
868
 
            while (token && token[0]) {
869
 
                if (!strcasecmp(token, "gzip")) {
870
 
                    found = 1;
871
 
                    break;
872
 
                }
873
 
                /* Otherwise, skip token */
874
 
                tmp++;
875
 
                token = ap_get_token(r->pool, &tmp, 0);
876
 
            }
877
 
        }
878
 
 
879
 
        if (found == 0) {
 
1036
        if (check_gzip(r, r->headers_out, r->err_headers_out) == 0) {
880
1037
            ap_remove_output_filter(f);
881
1038
            return ap_pass_brigade(f->next, bb);
882
1039
        }
883
 
        apr_table_unset(r->headers_out, "Content-Encoding");
884
1040
 
885
1041
        /* No need to inflate HEAD or 204/304 */
886
1042
        if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(bb))) {
888
1044
            return ap_pass_brigade(f->next, bb);
889
1045
        }
890
1046
 
891
 
 
892
1047
        f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
893
 
        ctx->proc_bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
 
1048
        ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
894
1049
        ctx->buffer = apr_palloc(r->pool, c->bufferSize);
895
 
 
 
1050
        ctx->libz_end_func = inflateEnd;
 
1051
        ctx->validation_buffer = NULL;
 
1052
        ctx->validation_buffer_length = 0;
896
1053
 
897
1054
        zRC = inflateInit2(&ctx->stream, c->windowSize);
898
1055
 
903
1060
                          "unable to init Zlib: "
904
1061
                          "inflateInit2 returned %d: URL %s",
905
1062
                          zRC, r->uri);
 
1063
            /*
 
1064
             * Remove ourselves as it does not make sense to return:
 
1065
             * We are not able to init libz and pass data down the chain
 
1066
             * compressed.
 
1067
             */
906
1068
            ap_remove_output_filter(f);
907
1069
            return ap_pass_brigade(f->next, bb);
908
1070
        }
909
1071
 
910
 
        /* initialize deflate output buffer */
 
1072
        /*
 
1073
         * Register a cleanup function to ensure that we cleanup the internal
 
1074
         * libz resources.
 
1075
         */
 
1076
        apr_pool_cleanup_register(r->pool, ctx, deflate_ctx_cleanup,
 
1077
                                  apr_pool_cleanup_null);
 
1078
 
 
1079
        /* these are unlikely to be set anyway, but ... */
 
1080
        apr_table_unset(r->headers_out, "Content-Length");
 
1081
        apr_table_unset(r->headers_out, "Content-MD5");
 
1082
        deflate_check_etag(r, "gunzip");
 
1083
 
 
1084
        /* initialize inflate output buffer */
911
1085
        ctx->stream.next_out = ctx->buffer;
912
1086
        ctx->stream.avail_out = c->bufferSize;
913
1087
 
914
 
        deflate_init = 0;
 
1088
        ctx->inflate_init = 0;
915
1089
    }
916
1090
 
917
 
    for (bkt = APR_BRIGADE_FIRST(bb);
918
 
         bkt != APR_BRIGADE_SENTINEL(bb);
919
 
         bkt = APR_BUCKET_NEXT(bkt))
 
1091
    while (!APR_BRIGADE_EMPTY(bb))
920
1092
    {
921
1093
        const char *data;
 
1094
        apr_bucket *b;
922
1095
        apr_size_t len;
923
1096
 
924
 
        /* If we actually see the EOS, that means we screwed up! */
925
 
        /* no it doesn't - not in a HEAD or 204/304 */
926
 
        if (APR_BUCKET_IS_EOS(bkt)) {
 
1097
        e = APR_BRIGADE_FIRST(bb);
 
1098
 
 
1099
        if (APR_BUCKET_IS_EOS(e)) {
 
1100
            /*
 
1101
             * We are really done now. Ensure that we never return here, even
 
1102
             * if a second EOS bucket falls down the chain. Thus remove
 
1103
             * ourselves.
 
1104
             */
 
1105
            ap_remove_output_filter(f);
 
1106
            /* should be zero already anyway */
 
1107
            ctx->stream.avail_in = 0;
 
1108
            /*
 
1109
             * Flush the remaining data from the zlib buffers. It is correct
 
1110
             * to use Z_SYNC_FLUSH in this case and not Z_FINISH as in the
 
1111
             * deflate case. In the inflate case Z_FINISH requires to have a
 
1112
             * large enough output buffer to put ALL data in otherwise it
 
1113
             * fails, whereas in the deflate case you can empty a filled output
 
1114
             * buffer and call it again until no more output can be created.
 
1115
             */
 
1116
            flush_libz_buffer(ctx, c, f->c->bucket_alloc, inflate, Z_SYNC_FLUSH,
 
1117
                              UPDATE_CRC);
 
1118
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
 
1119
                          "Zlib: Inflated %ld to %ld : URL %s",
 
1120
                          ctx->stream.total_in, ctx->stream.total_out, r->uri);
 
1121
 
 
1122
            if (ctx->validation_buffer_length == VALIDATION_SIZE) {
 
1123
                unsigned long compCRC, compLen;
 
1124
                compCRC = getLong(ctx->validation_buffer);
 
1125
                if (ctx->crc != compCRC) {
 
1126
                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
 
1127
                                  "Zlib: Checksum of inflated stream invalid");
 
1128
                    return APR_EGENERAL;
 
1129
                }
 
1130
                ctx->validation_buffer += VALIDATION_SIZE / 2;
 
1131
                compLen = getLong(ctx->validation_buffer);
 
1132
                if (ctx->stream.total_out != compLen) {
 
1133
                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
 
1134
                                  "Zlib: Length of inflated stream invalid");
 
1135
                    return APR_EGENERAL;
 
1136
                }
 
1137
            }
 
1138
            else {
 
1139
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
 
1140
                              "Zlib: Validation bytes not present");
 
1141
                return APR_EGENERAL;
 
1142
            }
 
1143
 
927
1144
            inflateEnd(&ctx->stream);
928
 
            return ap_pass_brigade(f->next, bb);
 
1145
            /* No need for cleanup any longer */
 
1146
            apr_pool_cleanup_kill(r->pool, ctx, deflate_ctx_cleanup);
 
1147
 
 
1148
            /* Remove EOS from the old list, and insert into the new. */
 
1149
            APR_BUCKET_REMOVE(e);
 
1150
            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
 
1151
 
 
1152
            /*
 
1153
             * Okay, we've seen the EOS.
 
1154
             * Time to pass it along down the chain.
 
1155
             */
 
1156
            return ap_pass_brigade(f->next, ctx->bb);
929
1157
        }
930
1158
 
931
 
        if (APR_BUCKET_IS_FLUSH(bkt)) {
932
 
            apr_bucket *tmp_heap;
933
 
            zRC = inflate(&(ctx->stream), Z_SYNC_FLUSH);
 
1159
        if (APR_BUCKET_IS_FLUSH(e)) {
 
1160
            apr_status_t rv;
 
1161
 
 
1162
            /* flush the remaining data from the zlib buffers */
 
1163
            zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, inflate,
 
1164
                                    Z_SYNC_FLUSH, UPDATE_CRC);
934
1165
            if (zRC != Z_OK) {
935
 
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
936
 
                              "Inflate error %d on flush", zRC);
937
 
                inflateEnd(&ctx->stream);
938
1166
                return APR_EGENERAL;
939
1167
            }
940
1168
 
941
 
            ctx->stream.next_out = ctx->buffer;
942
 
            len = c->bufferSize - ctx->stream.avail_out;
943
 
 
944
 
            ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
945
 
            tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
946
 
                                             NULL, f->c->bucket_alloc);
947
 
            APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
948
 
            ctx->stream.avail_out = c->bufferSize;
949
 
 
950
 
            /* Move everything to the returning brigade. */
951
 
            APR_BUCKET_REMOVE(bkt);
952
 
            break;
 
1169
            /* Remove flush bucket from old brigade anf insert into the new. */
 
1170
            APR_BUCKET_REMOVE(e);
 
1171
            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
 
1172
            rv = ap_pass_brigade(f->next, ctx->bb);
 
1173
            if (rv != APR_SUCCESS) {
 
1174
                return rv;
 
1175
            }
 
1176
            continue;
 
1177
        }
 
1178
 
 
1179
        if (APR_BUCKET_IS_METADATA(e)) {
 
1180
            /*
 
1181
             * Remove meta data bucket from old brigade and insert into the
 
1182
             * new.
 
1183
             */
 
1184
            APR_BUCKET_REMOVE(e);
 
1185
            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
 
1186
            continue;
953
1187
        }
954
1188
 
955
1189
        /* read */
956
 
        apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ);
 
1190
        apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
957
1191
 
958
1192
        /* first bucket contains zlib header */
959
 
        if (!deflate_init++) {
 
1193
        if (!ctx->inflate_init++) {
960
1194
            if (len < 10) {
961
1195
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
962
1196
                              "Insufficient data for inflate");
1010
1244
        ctx->stream.next_in = (unsigned char *)data;
1011
1245
        ctx->stream.avail_in = len;
1012
1246
 
 
1247
        if (ctx->validation_buffer) {
 
1248
            if (ctx->validation_buffer_length < VALIDATION_SIZE) {
 
1249
                apr_size_t copy_size;
 
1250
 
 
1251
                copy_size = VALIDATION_SIZE - ctx->validation_buffer_length;
 
1252
                if (copy_size > ctx->stream.avail_in)
 
1253
                    copy_size = ctx->stream.avail_in;
 
1254
                memcpy(ctx->validation_buffer + ctx->validation_buffer_length,
 
1255
                       ctx->stream.next_in, copy_size);
 
1256
                /* Saved copy_size bytes */
 
1257
                ctx->stream.avail_in -= copy_size;
 
1258
                ctx->validation_buffer_length += copy_size;
 
1259
            }
 
1260
            if (ctx->stream.avail_in) {
 
1261
                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
 
1262
                              "Zlib: %d bytes of garbage at the end of "
 
1263
                              "compressed stream.", ctx->stream.avail_in);
 
1264
                /*
 
1265
                 * There is nothing worth consuming for zlib left, because it is
 
1266
                 * either garbage data or the data has been copied to the
 
1267
                 * validation buffer (processing validation data is no business
 
1268
                 * for zlib). So set ctx->stream.avail_in to zero to indicate
 
1269
                 * this to the following while loop.
 
1270
                 */
 
1271
                ctx->stream.avail_in = 0;
 
1272
            }
 
1273
        }
 
1274
 
1013
1275
        zRC = Z_OK;
1014
1276
 
1015
1277
        while (ctx->stream.avail_in != 0) {
1016
1278
            if (ctx->stream.avail_out == 0) {
1017
 
                apr_bucket *tmp_heap;
 
1279
 
1018
1280
                ctx->stream.next_out = ctx->buffer;
1019
1281
                len = c->bufferSize - ctx->stream.avail_out;
1020
1282
 
1021
1283
                ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1022
 
                tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
1023
 
                                                  NULL, f->c->bucket_alloc);
1024
 
                APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
 
1284
                b = apr_bucket_heap_create((char *)ctx->buffer, len,
 
1285
                                           NULL, f->c->bucket_alloc);
 
1286
                APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
1025
1287
                ctx->stream.avail_out = c->bufferSize;
 
1288
                /* Send what we have right now to the next filter. */
 
1289
                rv = ap_pass_brigade(f->next, ctx->bb);
 
1290
                if (rv != APR_SUCCESS) {
 
1291
                    return rv;
 
1292
                }
1026
1293
            }
1027
1294
 
1028
1295
            zRC = inflate(&ctx->stream, Z_NO_FLUSH);
1029
1296
 
1030
1297
            if (zRC == Z_STREAM_END) {
 
1298
                /*
 
1299
                 * We have inflated all data. Now try to capture the
 
1300
                 * validation bytes. We may not have them all available
 
1301
                 * right now, but capture what is there.
 
1302
                 */
 
1303
                ctx->validation_buffer = apr_pcalloc(f->r->pool,
 
1304
                                                     VALIDATION_SIZE);
 
1305
                if (ctx->stream.avail_in > VALIDATION_SIZE) {
 
1306
                    ctx->validation_buffer_length = VALIDATION_SIZE;
 
1307
                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
 
1308
                                  "Zlib: %d bytes of garbage at the end of "
 
1309
                                  "compressed stream.",
 
1310
                                  ctx->stream.avail_in - VALIDATION_SIZE);
 
1311
                } else if (ctx->stream.avail_in > 0) {
 
1312
                           ctx->validation_buffer_length = ctx->stream.avail_in;
 
1313
                }
 
1314
                if (ctx->validation_buffer_length)
 
1315
                    memcpy(ctx->validation_buffer, ctx->stream.next_in,
 
1316
                           ctx->validation_buffer_length);
1031
1317
                break;
1032
1318
            }
1033
1319
 
1034
1320
            if (zRC != Z_OK) {
1035
 
                    inflateEnd(&ctx->stream);
1036
 
                    return APR_EGENERAL;
1037
 
            }
1038
 
        }
1039
 
        if (zRC == Z_STREAM_END) {
1040
 
            apr_bucket *tmp_heap, *eos;
1041
 
 
1042
 
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1043
 
                          "Zlib: Inflated %ld to %ld : URL %s",
1044
 
                          ctx->stream.total_in, ctx->stream.total_out,
1045
 
                          r->uri);
1046
 
 
1047
 
            len = c->bufferSize - ctx->stream.avail_out;
1048
 
 
1049
 
            ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1050
 
            tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
1051
 
                                              NULL, f->c->bucket_alloc);
1052
 
            APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
1053
 
            ctx->stream.avail_out = c->bufferSize;
1054
 
 
1055
 
            /* Is the remaining 8 bytes already in the avail stream? */
1056
 
            if (ctx->stream.avail_in >= 8) {
1057
 
                unsigned long compCRC, compLen;
1058
 
                compCRC = getLong(ctx->stream.next_in);
1059
 
                if (ctx->crc != compCRC) {
1060
 
                    inflateEnd(&ctx->stream);
1061
 
                    return APR_EGENERAL;
1062
 
                }
1063
 
                ctx->stream.next_in += 4;
1064
 
                compLen = getLong(ctx->stream.next_in);
1065
 
                if (ctx->stream.total_out != compLen) {
1066
 
                    inflateEnd(&ctx->stream);
1067
 
                    return APR_EGENERAL;
1068
 
                }
1069
 
            }
1070
 
            else {
1071
 
                /* FIXME: We need to grab the 8 verification bytes
1072
 
                 * from the wire! */
1073
 
                inflateEnd(&ctx->stream);
1074
1321
                return APR_EGENERAL;
1075
1322
            }
1076
 
 
1077
 
            inflateEnd(&ctx->stream);
1078
 
 
1079
 
            eos = apr_bucket_eos_create(f->c->bucket_alloc);
1080
 
            APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, eos);
1081
 
            break;
1082
1323
        }
1083
1324
 
 
1325
        apr_bucket_delete(e);
1084
1326
    }
1085
1327
 
1086
 
    rv = ap_pass_brigade(f->next, ctx->proc_bb);
1087
 
    apr_brigade_cleanup(ctx->proc_bb);
1088
 
    return rv ;
 
1328
    apr_brigade_cleanup(bb);
 
1329
    return APR_SUCCESS;
1089
1330
}
1090
1331
 
 
1332
#define PROTO_FLAGS AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH
1091
1333
static void register_hooks(apr_pool_t *p)
1092
1334
{
1093
1335
    ap_register_output_filter(deflateFilterName, deflate_out_filter, NULL,