1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * mod_deflate.c: Perform deflate content-encoding on the fly
19 *
20 * Written by Ian Holsman, Justin Erenkrantz, and Nick Kew
21 */
22
23/*
24 * Portions of this software are based upon zlib code by Jean-loup Gailly
25 * (zlib functions gz_open and gzwrite, check_header)
26 */
27
28/* zlib flags */
29#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
30#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
31#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
32#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
33#define COMMENT      0x10 /* bit 4 set: file comment present */
34#define RESERVED     0xE0 /* bits 5..7: reserved */
35
36
37#include "httpd.h"
38#include "http_config.h"
39#include "http_log.h"
40#include "apr_lib.h"
41#include "apr_strings.h"
42#include "apr_general.h"
43#include "util_filter.h"
44#include "apr_buckets.h"
45#include "http_request.h"
46#define APR_WANT_STRFUNC
47#include "apr_want.h"
48#include "mod_ssl.h"
49
50#include "zlib.h"
51
52static const char deflateFilterName[] = "DEFLATE";
53module AP_MODULE_DECLARE_DATA deflate_module;
54
55typedef struct deflate_filter_config_t
56{
57    int windowSize;
58    int memlevel;
59    int compressionlevel;
60    apr_size_t bufferSize;
61    char *note_ratio_name;
62    char *note_input_name;
63    char *note_output_name;
64} deflate_filter_config;
65
66/* RFC 1952 Section 2.3 defines the gzip header:
67 *
68 * +---+---+---+---+---+---+---+---+---+---+
69 * |ID1|ID2|CM |FLG|     MTIME     |XFL|OS |
70 * +---+---+---+---+---+---+---+---+---+---+
71 */
72static const char gzip_header[10] =
73{ '\037', '\213', Z_DEFLATED, 0,
74  0, 0, 0, 0, /* mtime */
75  0, 0x03 /* Unix OS_CODE */
76};
77
78/* magic header */
79static const char deflate_magic[2] = { '\037', '\213' };
80
81/* windowsize is negative to suppress Zlib header */
82#define DEFAULT_COMPRESSION Z_DEFAULT_COMPRESSION
83#define DEFAULT_WINDOWSIZE -15
84#define DEFAULT_MEMLEVEL 9
85#define DEFAULT_BUFFERSIZE 8096
86
87static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *mod_deflate_ssl_var = NULL;
88
89/* Check whether a request is gzipped, so we can un-gzip it.
90 * If a request has multiple encodings, we need the gzip
91 * to be the outermost non-identity encoding.
92 */
93static int check_gzip(request_rec *r, apr_table_t *hdrs1, apr_table_t *hdrs2)
94{
95    int found = 0;
96    apr_table_t *hdrs = hdrs1;
97    const char *encoding = apr_table_get(hdrs, "Content-Encoding");
98
99    if (!encoding && (hdrs2 != NULL)) {
100        /* the output filter has two tables and a content_encoding to check */
101        encoding = apr_table_get(hdrs2, "Content-Encoding");
102        hdrs = hdrs2;
103        if (!encoding) {
104            encoding = r->content_encoding;
105            hdrs = NULL;
106        }
107    }
108    if (encoding && *encoding) {
109
110        /* check the usual/simple case first */
111        if (!strcasecmp(encoding, "gzip")
112            || !strcasecmp(encoding, "x-gzip")) {
113            found = 1;
114            if (hdrs) {
115                apr_table_unset(hdrs, "Content-Encoding");
116            }
117            else {
118                r->content_encoding = NULL;
119            }
120        }
121        else if (ap_strchr_c(encoding, ',') != NULL) {
122            /* If the outermost encoding isn't gzip, there's nowt
123             * we can do.  So only check the last non-identity token
124             */
125            char *new_encoding = apr_pstrdup(r->pool, encoding);
126            char *ptr;
127            for(;;) {
128                char *token = ap_strrchr(new_encoding, ',');
129                if (!token) {        /* gzip:identity or other:identity */
130                    if (!strcasecmp(new_encoding, "gzip")
131                        || !strcasecmp(new_encoding, "x-gzip")) {
132                        found = 1;
133                        if (hdrs) {
134                            apr_table_unset(hdrs, "Content-Encoding");
135                        }
136                        else {
137                            r->content_encoding = NULL;
138                        }
139                    }
140                    break; /* seen all tokens */
141                }
142                for (ptr=token+1; apr_isspace(*ptr); ++ptr);
143                if (!strcasecmp(ptr, "gzip")
144                    || !strcasecmp(ptr, "x-gzip")) {
145                    *token = '\0';
146                    if (hdrs) {
147                        apr_table_setn(hdrs, "Content-Encoding", new_encoding);
148                    }
149                    else {
150                        r->content_encoding = new_encoding;
151                    }
152                    found = 1;
153                }
154                else if (!ptr[0] || !strcasecmp(ptr, "identity")) {
155                    *token = '\0';
156                    continue; /* strip the token and find the next one */
157                }
158                break; /* found a non-identity token */
159            }
160        }
161    }
162    /*
163     * If we have dealt with the headers above but content_encoding was set
164     * before sync it with the new value in the hdrs table as
165     * r->content_encoding takes precedence later on in the http_header_filter
166     * and hence would destroy what we have just set in the hdrs table.
167     */
168    if (hdrs && r->content_encoding) {
169        r->content_encoding = apr_table_get(hdrs, "Content-Encoding");
170    }
171    return found;
172}
173
174/* Outputs a long in LSB order to the given file
175 * only the bottom 4 bits are required for the deflate file format.
176 */
177static void putLong(unsigned char *string, unsigned long x)
178{
179    string[0] = (unsigned char)(x & 0xff);
180    string[1] = (unsigned char)((x & 0xff00) >> 8);
181    string[2] = (unsigned char)((x & 0xff0000) >> 16);
182    string[3] = (unsigned char)((x & 0xff000000) >> 24);
183}
184
185/* Inputs a string and returns a long.
186 */
187static unsigned long getLong(unsigned char *string)
188{
189    return ((unsigned long)string[0])
190          | (((unsigned long)string[1]) << 8)
191          | (((unsigned long)string[2]) << 16)
192          | (((unsigned long)string[3]) << 24);
193}
194
195static void *create_deflate_server_config(apr_pool_t *p, server_rec *s)
196{
197    deflate_filter_config *c = apr_pcalloc(p, sizeof *c);
198
199    c->memlevel   = DEFAULT_MEMLEVEL;
200    c->windowSize = DEFAULT_WINDOWSIZE;
201    c->bufferSize = DEFAULT_BUFFERSIZE;
202    c->compressionlevel = DEFAULT_COMPRESSION;
203
204    return c;
205}
206
207static const char *deflate_set_window_size(cmd_parms *cmd, void *dummy,
208                                           const char *arg)
209{
210    deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
211                                                    &deflate_module);
212    int i;
213
214    i = atoi(arg);
215
216    if (i < 1 || i > 15)
217        return "DeflateWindowSize must be between 1 and 15";
218
219    c->windowSize = i * -1;
220
221    return NULL;
222}
223
224static const char *deflate_set_buffer_size(cmd_parms *cmd, void *dummy,
225                                           const char *arg)
226{
227    deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
228                                                    &deflate_module);
229    int n = atoi(arg);
230
231    if (n <= 0) {
232        return "DeflateBufferSize should be positive";
233    }
234
235    c->bufferSize = (apr_size_t)n;
236
237    return NULL;
238}
239static const char *deflate_set_note(cmd_parms *cmd, void *dummy,
240                                    const char *arg1, const char *arg2)
241{
242    deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
243                                                    &deflate_module);
244
245    if (arg2 == NULL) {
246        c->note_ratio_name = apr_pstrdup(cmd->pool, arg1);
247    }
248    else if (!strcasecmp(arg1, "ratio")) {
249        c->note_ratio_name = apr_pstrdup(cmd->pool, arg2);
250    }
251    else if (!strcasecmp(arg1, "input")) {
252        c->note_input_name = apr_pstrdup(cmd->pool, arg2);
253    }
254    else if (!strcasecmp(arg1, "output")) {
255        c->note_output_name = apr_pstrdup(cmd->pool, arg2);
256    }
257    else {
258        return apr_psprintf(cmd->pool, "Unknown note type %s", arg1);
259    }
260
261    return NULL;
262}
263
264static const char *deflate_set_memlevel(cmd_parms *cmd, void *dummy,
265                                        const char *arg)
266{
267    deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
268                                                    &deflate_module);
269    int i;
270
271    i = atoi(arg);
272
273    if (i < 1 || i > 9)
274        return "DeflateMemLevel must be between 1 and 9";
275
276    c->memlevel = i;
277
278    return NULL;
279}
280
281static const char *deflate_set_compressionlevel(cmd_parms *cmd, void *dummy,
282                                        const char *arg)
283{
284    deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
285                                                    &deflate_module);
286    int i;
287
288    i = atoi(arg);
289
290    if (i < 1 || i > 9)
291        return "Compression Level must be between 1 and 9";
292
293    c->compressionlevel = i;
294
295    return NULL;
296}
297
298typedef struct deflate_ctx_t
299{
300    z_stream stream;
301    unsigned char *buffer;
302    unsigned long crc;
303    apr_bucket_brigade *bb, *proc_bb;
304    int (*libz_end_func)(z_streamp);
305    unsigned char *validation_buffer;
306    apr_size_t validation_buffer_length;
307    unsigned int inflate_init:1;
308    unsigned int filter_init:1;
309    unsigned int done:1;
310} deflate_ctx;
311
312/* Number of validation bytes (CRC and length) after the compressed data */
313#define VALIDATION_SIZE 8
314/* Do not update ctx->crc, see comment in flush_libz_buffer */
315#define NO_UPDATE_CRC 0
316/* Do update ctx->crc, see comment in flush_libz_buffer */
317#define UPDATE_CRC 1
318
319static int flush_libz_buffer(deflate_ctx *ctx, deflate_filter_config *c,
320                             struct apr_bucket_alloc_t *bucket_alloc,
321                             int (*libz_func)(z_streamp, int), int flush,
322                             int crc)
323{
324    int zRC = Z_OK;
325    int done = 0;
326    unsigned int deflate_len;
327    apr_bucket *b;
328
329    for (;;) {
330         deflate_len = c->bufferSize - ctx->stream.avail_out;
331
332         if (deflate_len != 0) {
333             /*
334              * Do we need to update ctx->crc? Usually this is the case for
335              * inflate action where we need to do a crc on the output, whereas
336              * in the deflate case we need to do a crc on the input
337              */
338             if (crc) {
339                 ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
340                                  deflate_len);
341             }
342             b = apr_bucket_heap_create((char *)ctx->buffer,
343                                        deflate_len, NULL,
344                                        bucket_alloc);
345             APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
346             ctx->stream.next_out = ctx->buffer;
347             ctx->stream.avail_out = c->bufferSize;
348         }
349
350         if (done)
351             break;
352
353         zRC = libz_func(&ctx->stream, flush);
354
355         /*
356          * We can ignore Z_BUF_ERROR because:
357          * When we call libz_func we can assume that
358          *
359          * - avail_in is zero (due to the surrounding code that calls
360          *   flush_libz_buffer)
361          * - avail_out is non zero due to our actions some lines above
362          *
363          * So the only reason for Z_BUF_ERROR is that the internal libz
364          * buffers are now empty and thus we called libz_func one time
365          * too often. This does not hurt. It simply says that we are done.
366          */
367         if (zRC == Z_BUF_ERROR) {
368             zRC = Z_OK;
369             break;
370         }
371
372         done = (ctx->stream.avail_out != 0 || zRC == Z_STREAM_END);
373
374         if (zRC != Z_OK && zRC != Z_STREAM_END)
375             break;
376    }
377    return zRC;
378}
379
380static apr_status_t deflate_ctx_cleanup(void *data)
381{
382    deflate_ctx *ctx = (deflate_ctx *)data;
383
384    if (ctx)
385        ctx->libz_end_func(&ctx->stream);
386    return APR_SUCCESS;
387}
388
389/* ETag must be unique among the possible representations, so a change
390 * to content-encoding requires a corresponding change to the ETag.
391 * This routine appends -transform (e.g., -gzip) to the entity-tag
392 * value inside the double-quotes if an ETag has already been set
393 * and its value already contains double-quotes. PR 39727
394 */
395static void deflate_check_etag(request_rec *r, const char *transform)
396{
397    const char *etag = apr_table_get(r->headers_out, "ETag");
398    apr_size_t etaglen;
399
400    if ((etag && ((etaglen = strlen(etag)) > 2))) {
401        if (etag[etaglen - 1] == '"') {
402            apr_size_t transformlen = strlen(transform);
403            char *newtag = apr_palloc(r->pool, etaglen + transformlen + 2);
404            char *d = newtag;
405            char *e = d + etaglen - 1;
406            const char *s = etag;
407
408            for (; d < e; ++d, ++s) {
409                *d = *s;          /* copy etag to newtag up to last quote */
410            }
411            *d++ = '-';           /* append dash to newtag */
412            s = transform;
413            e = d + transformlen;
414            for (; d < e; ++d, ++s) {
415                *d = *s;          /* copy transform to newtag */
416            }
417            *d++ = '"';           /* append quote to newtag */
418            *d   = '\0';          /* null terminate newtag */
419
420            apr_table_setn(r->headers_out, "ETag", newtag);
421        }
422    }
423}
424
425static int have_ssl_compression(request_rec *r)
426{
427    const char *comp;
428    if (mod_deflate_ssl_var == NULL)
429        return 0;
430    comp = mod_deflate_ssl_var(r->pool, r->server, r->connection, r,
431                               "SSL_COMPRESS_METHOD");
432    if (comp == NULL || *comp == '\0' || strcmp(comp, "NULL") == 0)
433        return 0;
434    return 1;
435}
436
437static apr_status_t deflate_out_filter(ap_filter_t *f,
438                                       apr_bucket_brigade *bb)
439{
440    apr_bucket *e;
441    request_rec *r = f->r;
442    deflate_ctx *ctx = f->ctx;
443    int zRC;
444    apr_size_t len = 0, blen;
445    const char *data;
446    deflate_filter_config *c;
447
448    /* Do nothing if asked to filter nothing. */
449    if (APR_BRIGADE_EMPTY(bb)) {
450        return APR_SUCCESS;
451    }
452
453    c = ap_get_module_config(r->server->module_config,
454                             &deflate_module);
455
456    /* If we don't have a context, we need to ensure that it is okay to send
457     * the deflated content.  If we have a context, that means we've done
458     * this before and we liked it.
459     * This could be not so nice if we always fail.  But, if we succeed,
460     * we're in better shape.
461     */
462    if (!ctx) {
463        char *token;
464        const char *encoding;
465
466        if (have_ssl_compression(r)) {
467            ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
468                          "Compression enabled at SSL level; not compressing "
469                          "at HTTP level.");
470            ap_remove_output_filter(f);
471            return ap_pass_brigade(f->next, bb);
472        }
473
474        /* We have checked above that bb is not empty */
475        e = APR_BRIGADE_LAST(bb);
476        if (APR_BUCKET_IS_EOS(e)) {
477            /*
478             * If we already know the size of the response, we can skip
479             * compression on responses smaller than the compression overhead.
480             * However, if we compress, we must initialize deflate_out before
481             * calling ap_pass_brigade() for the first time.  Otherwise the
482             * headers will be sent to the client without
483             * "Content-Encoding: gzip".
484             */
485            e = APR_BRIGADE_FIRST(bb);
486            while (1) {
487                apr_status_t rc;
488                if (APR_BUCKET_IS_EOS(e)) {
489                    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
490                                  "Not compressing very small response of %"
491                                  APR_SIZE_T_FMT " bytes", len);
492                    ap_remove_output_filter(f);
493                    return ap_pass_brigade(f->next, bb);
494                }
495                if (APR_BUCKET_IS_METADATA(e)) {
496                    e = APR_BUCKET_NEXT(e);
497                    continue;
498                }
499
500                rc = apr_bucket_read(e, &data, &blen, APR_BLOCK_READ);
501                if (rc != APR_SUCCESS)
502                    return rc;
503                len += blen;
504                /* 50 is for Content-Encoding and Vary headers and ETag suffix */
505                if (len > sizeof(gzip_header) + VALIDATION_SIZE + 50)
506                    break;
507
508                e = APR_BUCKET_NEXT(e);
509            }
510        }
511
512        ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx));
513
514        /*
515         * Only work on main request, not subrequests,
516         * that are not a 204 response with no content
517         * and are not tagged with the no-gzip env variable
518         * and not a partial response to a Range request.
519         */
520        if ((r->main != NULL) || (r->status == HTTP_NO_CONTENT) ||
521            apr_table_get(r->subprocess_env, "no-gzip") ||
522            apr_table_get(r->headers_out, "Content-Range")
523           ) {
524            if (APLOG_R_IS_LEVEL(r, APLOG_TRACE1)) {
525                const char *reason =
526                    (r->main != NULL)                           ? "subrequest" :
527                    (r->status == HTTP_NO_CONTENT)              ? "no content" :
528                    apr_table_get(r->subprocess_env, "no-gzip") ? "no-gzip" :
529                    "content-range";
530                ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
531                              "Not compressing (%s)", reason);
532            }
533            ap_remove_output_filter(f);
534            return ap_pass_brigade(f->next, bb);
535        }
536
537        /* Some browsers might have problems with content types
538         * other than text/html, so set gzip-only-text/html
539         * (with browsermatch) for them
540         */
541        if (r->content_type == NULL
542             || strncmp(r->content_type, "text/html", 9)) {
543            const char *env_value = apr_table_get(r->subprocess_env,
544                                                  "gzip-only-text/html");
545            if ( env_value && (strcmp(env_value,"1") == 0) ) {
546                ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
547                              "Not compressing, (gzip-only-text/html)");
548                ap_remove_output_filter(f);
549                return ap_pass_brigade(f->next, bb);
550            }
551        }
552
553        /* Let's see what our current Content-Encoding is.
554         * If it's already encoded, don't compress again.
555         * (We could, but let's not.)
556         */
557        encoding = apr_table_get(r->headers_out, "Content-Encoding");
558        if (encoding) {
559            const char *err_enc;
560
561            err_enc = apr_table_get(r->err_headers_out, "Content-Encoding");
562            if (err_enc) {
563                encoding = apr_pstrcat(r->pool, encoding, ",", err_enc, NULL);
564            }
565        }
566        else {
567            encoding = apr_table_get(r->err_headers_out, "Content-Encoding");
568        }
569
570        if (r->content_encoding) {
571            encoding = encoding ? apr_pstrcat(r->pool, encoding, ",",
572                                              r->content_encoding, NULL)
573                                : r->content_encoding;
574        }
575
576        if (encoding) {
577            const char *tmp = encoding;
578
579            token = ap_get_token(r->pool, &tmp, 0);
580            while (token && *token) {
581                /* stolen from mod_negotiation: */
582                if (strcmp(token, "identity") && strcmp(token, "7bit") &&
583                    strcmp(token, "8bit") && strcmp(token, "binary")) {
584                    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
585                                  "Not compressing (content-encoding already "
586                                  " set: %s)", token);
587                    ap_remove_output_filter(f);
588                    return ap_pass_brigade(f->next, bb);
589                }
590
591                /* Otherwise, skip token */
592                if (*tmp) {
593                    ++tmp;
594                }
595                token = (*tmp) ? ap_get_token(r->pool, &tmp, 0) : NULL;
596            }
597        }
598
599        /* Even if we don't accept this request based on it not having
600         * the Accept-Encoding, we need to note that we were looking
601         * for this header and downstream proxies should be aware of that.
602         */
603        apr_table_mergen(r->headers_out, "Vary", "Accept-Encoding");
604
605        /* force-gzip will just force it out regardless if the browser
606         * can actually do anything with it.
607         */
608        if (!apr_table_get(r->subprocess_env, "force-gzip")) {
609            const char *accepts;
610            /* if they don't have the line, then they can't play */
611            accepts = apr_table_get(r->headers_in, "Accept-Encoding");
612            if (accepts == NULL) {
613                ap_remove_output_filter(f);
614                return ap_pass_brigade(f->next, bb);
615            }
616
617            token = ap_get_token(r->pool, &accepts, 0);
618            while (token && token[0] && strcasecmp(token, "gzip")) {
619                /* skip parameters, XXX: ;q=foo evaluation? */
620                while (*accepts == ';') {
621                    ++accepts;
622                    ap_get_token(r->pool, &accepts, 1);
623                }
624
625                /* retrieve next token */
626                if (*accepts == ',') {
627                    ++accepts;
628                }
629                token = (*accepts) ? ap_get_token(r->pool, &accepts, 0) : NULL;
630            }
631
632            /* No acceptable token found. */
633            if (token == NULL || token[0] == '\0') {
634                ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
635                              "Not compressing (no Accept-Encoding: gzip)");
636                ap_remove_output_filter(f);
637                return ap_pass_brigade(f->next, bb);
638            }
639        }
640        else {
641            ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
642                          "Forcing compression (force-gzip set)");
643        }
644
645        /* At this point we have decided to filter the content. Let's try to
646         * to initialize zlib (except for 304 responses, where we will only
647         * send out the headers).
648         */
649
650        if (r->status != HTTP_NOT_MODIFIED) {
651            ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
652            ctx->buffer = apr_palloc(r->pool, c->bufferSize);
653            ctx->libz_end_func = deflateEnd;
654
655            zRC = deflateInit2(&ctx->stream, c->compressionlevel, Z_DEFLATED,
656                               c->windowSize, c->memlevel,
657                               Z_DEFAULT_STRATEGY);
658
659            if (zRC != Z_OK) {
660                deflateEnd(&ctx->stream);
661                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01383)
662                              "unable to init Zlib: "
663                              "deflateInit2 returned %d: URL %s",
664                              zRC, r->uri);
665                /*
666                 * Remove ourselves as it does not make sense to return:
667                 * We are not able to init libz and pass data down the chain
668                 * uncompressed.
669                 */
670                ap_remove_output_filter(f);
671                return ap_pass_brigade(f->next, bb);
672            }
673            /*
674             * Register a cleanup function to ensure that we cleanup the internal
675             * libz resources.
676             */
677            apr_pool_cleanup_register(r->pool, ctx, deflate_ctx_cleanup,
678                                      apr_pool_cleanup_null);
679
680            /* Set the filter init flag so subsequent invocations know we are
681             * active.
682             */
683            ctx->filter_init = 1;
684        }
685
686        /*
687         * Zlib initialization worked, so we can now change the important
688         * content metadata before sending the response out.
689         */
690
691        /* If the entire Content-Encoding is "identity", we can replace it. */
692        if (!encoding || !strcasecmp(encoding, "identity")) {
693            apr_table_setn(r->headers_out, "Content-Encoding", "gzip");
694        }
695        else {
696            apr_table_mergen(r->headers_out, "Content-Encoding", "gzip");
697        }
698        /* Fix r->content_encoding if it was set before */
699        if (r->content_encoding) {
700            r->content_encoding = apr_table_get(r->headers_out,
701                                                "Content-Encoding");
702        }
703        apr_table_unset(r->headers_out, "Content-Length");
704        apr_table_unset(r->headers_out, "Content-MD5");
705        deflate_check_etag(r, "gzip");
706
707        /* For a 304 response, only change the headers */
708        if (r->status == HTTP_NOT_MODIFIED) {
709            ap_remove_output_filter(f);
710            return ap_pass_brigade(f->next, bb);
711        }
712
713        /* add immortal gzip header */
714        e = apr_bucket_immortal_create(gzip_header, sizeof gzip_header,
715                                       f->c->bucket_alloc);
716        APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
717
718        /* initialize deflate output buffer */
719        ctx->stream.next_out = ctx->buffer;
720        ctx->stream.avail_out = c->bufferSize;
721    } else if (!ctx->filter_init) {
722        /* Hmm.  We've run through the filter init before as we have a ctx,
723         * but we never initialized.  We probably have a dangling ref.  Bail.
724         */
725        return ap_pass_brigade(f->next, bb);
726    }
727
728    while (!APR_BRIGADE_EMPTY(bb))
729    {
730        apr_bucket *b;
731
732        /*
733         * Optimization: If we are a HEAD request and bytes_sent is not zero
734         * it means that we have passed the content-length filter once and
735         * have more data to sent. This means that the content-length filter
736         * could not determine our content-length for the response to the
737         * HEAD request anyway (the associated GET request would deliver the
738         * body in chunked encoding) and we can stop compressing.
739         */
740        if (r->header_only && r->bytes_sent) {
741            ap_remove_output_filter(f);
742            return ap_pass_brigade(f->next, bb);
743        }
744
745        e = APR_BRIGADE_FIRST(bb);
746
747        if (APR_BUCKET_IS_EOS(e)) {
748            char *buf;
749
750            ctx->stream.avail_in = 0; /* should be zero already anyway */
751            /* flush the remaining data from the zlib buffers */
752            flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate, Z_FINISH,
753                              NO_UPDATE_CRC);
754
755            buf = apr_palloc(r->pool, VALIDATION_SIZE);
756            putLong((unsigned char *)&buf[0], ctx->crc);
757            putLong((unsigned char *)&buf[4], ctx->stream.total_in);
758
759            b = apr_bucket_pool_create(buf, VALIDATION_SIZE, r->pool,
760                                       f->c->bucket_alloc);
761            APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
762            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01384)
763                          "Zlib: Compressed %ld to %ld : URL %s",
764                          ctx->stream.total_in, ctx->stream.total_out, r->uri);
765
766            /* leave notes for logging */
767            if (c->note_input_name) {
768                apr_table_setn(r->notes, c->note_input_name,
769                               (ctx->stream.total_in > 0)
770                                ? apr_off_t_toa(r->pool,
771                                                ctx->stream.total_in)
772                                : "-");
773            }
774
775            if (c->note_output_name) {
776                apr_table_setn(r->notes, c->note_output_name,
777                               (ctx->stream.total_in > 0)
778                                ? apr_off_t_toa(r->pool,
779                                                ctx->stream.total_out)
780                                : "-");
781            }
782
783            if (c->note_ratio_name) {
784                apr_table_setn(r->notes, c->note_ratio_name,
785                               (ctx->stream.total_in > 0)
786                                ? apr_itoa(r->pool,
787                                           (int)(ctx->stream.total_out
788                                                 * 100
789                                                 / ctx->stream.total_in))
790                                : "-");
791            }
792
793            deflateEnd(&ctx->stream);
794            /* No need for cleanup any longer */
795            apr_pool_cleanup_kill(r->pool, ctx, deflate_ctx_cleanup);
796
797            /* Remove EOS from the old list, and insert into the new. */
798            APR_BUCKET_REMOVE(e);
799            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
800
801            /* Okay, we've seen the EOS.
802             * Time to pass it along down the chain.
803             */
804            return ap_pass_brigade(f->next, ctx->bb);
805        }
806
807        if (APR_BUCKET_IS_FLUSH(e)) {
808            apr_status_t rv;
809
810            /* flush the remaining data from the zlib buffers */
811            zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate,
812                                    Z_SYNC_FLUSH, NO_UPDATE_CRC);
813            if (zRC != Z_OK) {
814                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01385)
815                              "Zlib error %d flushing zlib output buffer (%s)",
816                              zRC, ctx->stream.msg);
817                return APR_EGENERAL;
818            }
819
820            /* Remove flush bucket from old brigade anf insert into the new. */
821            APR_BUCKET_REMOVE(e);
822            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
823            rv = ap_pass_brigade(f->next, ctx->bb);
824            if (rv != APR_SUCCESS) {
825                return rv;
826            }
827            continue;
828        }
829
830        if (APR_BUCKET_IS_METADATA(e)) {
831            /*
832             * Remove meta data bucket from old brigade and insert into the
833             * new.
834             */
835            APR_BUCKET_REMOVE(e);
836            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
837            continue;
838        }
839
840        /* read */
841        apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
842
843        /* This crc32 function is from zlib. */
844        ctx->crc = crc32(ctx->crc, (const Bytef *)data, len);
845
846        /* write */
847        ctx->stream.next_in = (unsigned char *)data; /* We just lost const-ness,
848                                                      * but we'll just have to
849                                                      * trust zlib */
850        ctx->stream.avail_in = len;
851
852        while (ctx->stream.avail_in != 0) {
853            if (ctx->stream.avail_out == 0) {
854                apr_status_t rv;
855
856                ctx->stream.next_out = ctx->buffer;
857                len = c->bufferSize - ctx->stream.avail_out;
858
859                b = apr_bucket_heap_create((char *)ctx->buffer, len,
860                                           NULL, f->c->bucket_alloc);
861                APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
862                ctx->stream.avail_out = c->bufferSize;
863                /* Send what we have right now to the next filter. */
864                rv = ap_pass_brigade(f->next, ctx->bb);
865                if (rv != APR_SUCCESS) {
866                    return rv;
867                }
868            }
869
870            zRC = deflate(&(ctx->stream), Z_NO_FLUSH);
871
872            if (zRC != Z_OK) {
873                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01386)
874                              "Zlib error %d deflating data (%s)", zRC,
875                              ctx->stream.msg);
876                return APR_EGENERAL;
877            }
878        }
879
880        apr_bucket_delete(e);
881    }
882
883    apr_brigade_cleanup(bb);
884    return APR_SUCCESS;
885}
886
887/* This is the deflate input filter (inflates).  */
888static apr_status_t deflate_in_filter(ap_filter_t *f,
889                                      apr_bucket_brigade *bb,
890                                      ap_input_mode_t mode,
891                                      apr_read_type_e block,
892                                      apr_off_t readbytes)
893{
894    apr_bucket *bkt;
895    request_rec *r = f->r;
896    deflate_ctx *ctx = f->ctx;
897    int zRC;
898    apr_status_t rv;
899    deflate_filter_config *c;
900
901    /* just get out of the way of things we don't want. */
902    if (mode != AP_MODE_READBYTES) {
903        return ap_get_brigade(f->next, bb, mode, block, readbytes);
904    }
905
906    c = ap_get_module_config(r->server->module_config, &deflate_module);
907
908    if (!ctx) {
909        char deflate_hdr[10];
910        apr_size_t len;
911
912        /* only work on main request/no subrequests */
913        if (!ap_is_initial_req(r)) {
914            ap_remove_input_filter(f);
915            return ap_get_brigade(f->next, bb, mode, block, readbytes);
916        }
917
918        /* We can't operate on Content-Ranges */
919        if (apr_table_get(r->headers_in, "Content-Range") != NULL) {
920            ap_remove_input_filter(f);
921            return ap_get_brigade(f->next, bb, mode, block, readbytes);
922        }
923
924        /* Check whether request body is gzipped.
925         *
926         * If it is, we're transforming the contents, invalidating
927         * some request headers including Content-Encoding.
928         *
929         * If not, we just remove ourself.
930         */
931        if (check_gzip(r, r->headers_in, NULL) == 0) {
932            ap_remove_input_filter(f);
933            return ap_get_brigade(f->next, bb, mode, block, readbytes);
934        }
935
936        f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
937        ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
938        ctx->proc_bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
939        ctx->buffer = apr_palloc(r->pool, c->bufferSize);
940
941        rv = ap_get_brigade(f->next, ctx->bb, AP_MODE_READBYTES, block, 10);
942        if (rv != APR_SUCCESS) {
943            return rv;
944        }
945
946        /* zero length body? step aside */
947        bkt = APR_BRIGADE_FIRST(ctx->bb);
948        if (APR_BUCKET_IS_EOS(bkt)) {
949            ap_remove_input_filter(f);
950            return ap_get_brigade(f->next, bb, mode, block, readbytes);
951        }
952
953        apr_table_unset(r->headers_in, "Content-Length");
954        apr_table_unset(r->headers_in, "Content-MD5");
955
956        len = 10;
957        rv = apr_brigade_flatten(ctx->bb, deflate_hdr, &len);
958        if (rv != APR_SUCCESS) {
959            return rv;
960        }
961
962        /* We didn't get the magic bytes. */
963        if (len != 10 ||
964            deflate_hdr[0] != deflate_magic[0] ||
965            deflate_hdr[1] != deflate_magic[1]) {
966            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01387) "Zlib: Invalid header");
967            return APR_EGENERAL;
968        }
969
970        /* We can't handle flags for now. */
971        if (deflate_hdr[3] != 0) {
972            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01388)
973                          "Zlib: Unsupported flags %02x", (int)deflate_hdr[3]);
974            return APR_EGENERAL;
975        }
976
977        zRC = inflateInit2(&ctx->stream, c->windowSize);
978
979        if (zRC != Z_OK) {
980            f->ctx = NULL;
981            inflateEnd(&ctx->stream);
982            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01389)
983                          "unable to init Zlib: "
984                          "inflateInit2 returned %d: URL %s",
985                          zRC, r->uri);
986            ap_remove_input_filter(f);
987            return ap_get_brigade(f->next, bb, mode, block, readbytes);
988        }
989
990        /* initialize deflate output buffer */
991        ctx->stream.next_out = ctx->buffer;
992        ctx->stream.avail_out = c->bufferSize;
993
994        apr_brigade_cleanup(ctx->bb);
995    }
996
997    if (APR_BRIGADE_EMPTY(ctx->proc_bb)) {
998        rv = ap_get_brigade(f->next, ctx->bb, mode, block, readbytes);
999
1000        if (rv != APR_SUCCESS) {
1001            /* What about APR_EAGAIN errors? */
1002            inflateEnd(&ctx->stream);
1003            return rv;
1004        }
1005
1006        for (bkt = APR_BRIGADE_FIRST(ctx->bb);
1007             bkt != APR_BRIGADE_SENTINEL(ctx->bb);
1008             bkt = APR_BUCKET_NEXT(bkt))
1009        {
1010            const char *data;
1011            apr_size_t len;
1012
1013            if (APR_BUCKET_IS_EOS(bkt)) {
1014                if (!ctx->done) {
1015                    inflateEnd(&ctx->stream);
1016                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02481)
1017                                  "Encountered premature end-of-stream while inflating");
1018                    return APR_EGENERAL;
1019                }
1020
1021                /* Move everything to the returning brigade. */
1022                APR_BUCKET_REMOVE(bkt);
1023                APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, bkt);
1024                ap_remove_input_filter(f);
1025                break;
1026            }
1027
1028            if (APR_BUCKET_IS_FLUSH(bkt)) {
1029                apr_bucket *tmp_heap;
1030                zRC = inflate(&(ctx->stream), Z_SYNC_FLUSH);
1031                if (zRC != Z_OK) {
1032                    inflateEnd(&ctx->stream);
1033                    ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01391)
1034                                  "Zlib error %d inflating data (%s)", zRC,
1035                                  ctx->stream.msg);
1036                    return APR_EGENERAL;
1037                }
1038
1039                ctx->stream.next_out = ctx->buffer;
1040                len = c->bufferSize - ctx->stream.avail_out;
1041
1042                ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1043                tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
1044                                                 NULL, f->c->bucket_alloc);
1045                APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
1046                ctx->stream.avail_out = c->bufferSize;
1047
1048                /* Move everything to the returning brigade. */
1049                APR_BUCKET_REMOVE(bkt);
1050                APR_BRIGADE_CONCAT(bb, ctx->bb);
1051                break;
1052            }
1053
1054            /* sanity check - data after completed compressed body and before eos? */
1055            if (ctx->done) {
1056                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02482)
1057                              "Encountered extra data after compressed data");
1058                return APR_EGENERAL;
1059            }
1060
1061            /* read */
1062            apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ);
1063
1064            /* pass through zlib inflate. */
1065            ctx->stream.next_in = (unsigned char *)data;
1066            ctx->stream.avail_in = len;
1067
1068            zRC = Z_OK;
1069
1070            while (ctx->stream.avail_in != 0) {
1071                if (ctx->stream.avail_out == 0) {
1072                    apr_bucket *tmp_heap;
1073                    ctx->stream.next_out = ctx->buffer;
1074                    len = c->bufferSize - ctx->stream.avail_out;
1075
1076                    ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1077                    tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
1078                                                      NULL, f->c->bucket_alloc);
1079                    APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
1080                    ctx->stream.avail_out = c->bufferSize;
1081                }
1082
1083                zRC = inflate(&ctx->stream, Z_NO_FLUSH);
1084
1085                if (zRC == Z_STREAM_END) {
1086                    break;
1087                }
1088
1089                if (zRC != Z_OK) {
1090                    inflateEnd(&ctx->stream);
1091                    ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01392)
1092                                  "Zlib error %d inflating data (%s)", zRC,
1093                                  ctx->stream.msg);
1094                    return APR_EGENERAL;
1095                }
1096            }
1097            if (zRC == Z_STREAM_END) {
1098                apr_bucket *tmp_heap;
1099                apr_size_t avail;
1100
1101                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01393)
1102                              "Zlib: Inflated %ld to %ld : URL %s",
1103                              ctx->stream.total_in, ctx->stream.total_out,
1104                              r->uri);
1105
1106                len = c->bufferSize - ctx->stream.avail_out;
1107
1108                ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1109                tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
1110                                                  NULL, f->c->bucket_alloc);
1111                APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
1112                ctx->stream.avail_out = c->bufferSize;
1113
1114                avail = ctx->stream.avail_in;
1115
1116                /* Is the remaining 8 bytes already in the avail stream? */
1117                if (avail >= 8) {
1118                    unsigned long compCRC, compLen;
1119                    compCRC = getLong(ctx->stream.next_in);
1120                    if (ctx->crc != compCRC) {
1121                        inflateEnd(&ctx->stream);
1122                        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01394)
1123                                      "Zlib: CRC error inflating data");
1124                        return APR_EGENERAL;
1125                    }
1126                    ctx->stream.next_in += 4;
1127                    compLen = getLong(ctx->stream.next_in);
1128                    if (ctx->stream.total_out != compLen) {
1129                        inflateEnd(&ctx->stream);
1130                        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01395)
1131                                      "Zlib: Length %ld of inflated data does "
1132                                      "not match expected value %ld",
1133                                      ctx->stream.total_out, compLen);
1134                        return APR_EGENERAL;
1135                    }
1136                }
1137                else {
1138                    /* FIXME: We need to grab the 8 verification bytes
1139                     * from the wire! */
1140                    inflateEnd(&ctx->stream);
1141                    ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01396)
1142                                  "Verification data not available (bug?)");
1143                    return APR_EGENERAL;
1144                }
1145
1146                inflateEnd(&ctx->stream);
1147
1148                ctx->done = 1;
1149
1150                /* Did we have trailing data behind the closing 8 bytes? */
1151                if (avail > 8) {
1152                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02485)
1153                                  "Encountered extra data after compressed data");
1154                    return APR_EGENERAL;
1155                }
1156            }
1157
1158        }
1159        apr_brigade_cleanup(ctx->bb);
1160    }
1161
1162    /* If we are about to return nothing for a 'blocking' read and we have
1163     * some data in our zlib buffer, flush it out so we can return something.
1164     */
1165    if (block == APR_BLOCK_READ &&
1166        APR_BRIGADE_EMPTY(ctx->proc_bb) &&
1167        ctx->stream.avail_out < c->bufferSize) {
1168        apr_bucket *tmp_heap;
1169        apr_size_t len;
1170        ctx->stream.next_out = ctx->buffer;
1171        len = c->bufferSize - ctx->stream.avail_out;
1172
1173        ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1174        tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
1175                                          NULL, f->c->bucket_alloc);
1176        APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
1177        ctx->stream.avail_out = c->bufferSize;
1178    }
1179
1180    if (!APR_BRIGADE_EMPTY(ctx->proc_bb)) {
1181        if (apr_brigade_partition(ctx->proc_bb, readbytes, &bkt) == APR_INCOMPLETE) {
1182            APR_BRIGADE_CONCAT(bb, ctx->proc_bb);
1183        }
1184        else {
1185            APR_BRIGADE_CONCAT(bb, ctx->proc_bb);
1186            apr_brigade_split_ex(bb, bkt, ctx->proc_bb);
1187        }
1188    }
1189
1190    return APR_SUCCESS;
1191}
1192
1193
1194/* Filter to inflate for a content-transforming proxy.  */
1195static apr_status_t inflate_out_filter(ap_filter_t *f,
1196                                      apr_bucket_brigade *bb)
1197{
1198    int zlib_method;
1199    int zlib_flags;
1200    apr_bucket *e;
1201    request_rec *r = f->r;
1202    deflate_ctx *ctx = f->ctx;
1203    int zRC;
1204    apr_status_t rv;
1205    deflate_filter_config *c;
1206
1207    /* Do nothing if asked to filter nothing. */
1208    if (APR_BRIGADE_EMPTY(bb)) {
1209        return APR_SUCCESS;
1210    }
1211
1212    c = ap_get_module_config(r->server->module_config, &deflate_module);
1213
1214    if (!ctx) {
1215
1216        /*
1217         * Only work on main request, not subrequests,
1218         * that are not a 204 response with no content
1219         * and not a partial response to a Range request,
1220         * and only when Content-Encoding ends in gzip.
1221         */
1222        if (!ap_is_initial_req(r) || (r->status == HTTP_NO_CONTENT) ||
1223            (apr_table_get(r->headers_out, "Content-Range") != NULL) ||
1224            (check_gzip(r, r->headers_out, r->err_headers_out) == 0)
1225           ) {
1226            ap_remove_output_filter(f);
1227            return ap_pass_brigade(f->next, bb);
1228        }
1229
1230        /*
1231         * At this point we have decided to filter the content, so change
1232         * important content metadata before sending any response out.
1233         * Content-Encoding was already reset by the check_gzip() call.
1234         */
1235        apr_table_unset(r->headers_out, "Content-Length");
1236        apr_table_unset(r->headers_out, "Content-MD5");
1237        deflate_check_etag(r, "gunzip");
1238
1239        /* For a 304 response, only change the headers */
1240        if (r->status == HTTP_NOT_MODIFIED) {
1241            ap_remove_output_filter(f);
1242            return ap_pass_brigade(f->next, bb);
1243        }
1244
1245        f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
1246        ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
1247        ctx->buffer = apr_palloc(r->pool, c->bufferSize);
1248        ctx->libz_end_func = inflateEnd;
1249        ctx->validation_buffer = NULL;
1250        ctx->validation_buffer_length = 0;
1251
1252        zRC = inflateInit2(&ctx->stream, c->windowSize);
1253
1254        if (zRC != Z_OK) {
1255            f->ctx = NULL;
1256            inflateEnd(&ctx->stream);
1257            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01397)
1258                          "unable to init Zlib: "
1259                          "inflateInit2 returned %d: URL %s",
1260                          zRC, r->uri);
1261            /*
1262             * Remove ourselves as it does not make sense to return:
1263             * We are not able to init libz and pass data down the chain
1264             * compressed.
1265             */
1266            ap_remove_output_filter(f);
1267            return ap_pass_brigade(f->next, bb);
1268        }
1269
1270        /*
1271         * Register a cleanup function to ensure that we cleanup the internal
1272         * libz resources.
1273         */
1274        apr_pool_cleanup_register(r->pool, ctx, deflate_ctx_cleanup,
1275                                  apr_pool_cleanup_null);
1276
1277        /* initialize inflate output buffer */
1278        ctx->stream.next_out = ctx->buffer;
1279        ctx->stream.avail_out = c->bufferSize;
1280
1281        ctx->inflate_init = 0;
1282    }
1283
1284    while (!APR_BRIGADE_EMPTY(bb))
1285    {
1286        const char *data;
1287        apr_bucket *b;
1288        apr_size_t len;
1289
1290        e = APR_BRIGADE_FIRST(bb);
1291
1292        if (APR_BUCKET_IS_EOS(e)) {
1293            /*
1294             * We are really done now. Ensure that we never return here, even
1295             * if a second EOS bucket falls down the chain. Thus remove
1296             * ourselves.
1297             */
1298            ap_remove_output_filter(f);
1299            /* should be zero already anyway */
1300            ctx->stream.avail_in = 0;
1301            /*
1302             * Flush the remaining data from the zlib buffers. It is correct
1303             * to use Z_SYNC_FLUSH in this case and not Z_FINISH as in the
1304             * deflate case. In the inflate case Z_FINISH requires to have a
1305             * large enough output buffer to put ALL data in otherwise it
1306             * fails, whereas in the deflate case you can empty a filled output
1307             * buffer and call it again until no more output can be created.
1308             */
1309            flush_libz_buffer(ctx, c, f->c->bucket_alloc, inflate, Z_SYNC_FLUSH,
1310                              UPDATE_CRC);
1311            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01398)
1312                          "Zlib: Inflated %ld to %ld : URL %s",
1313                          ctx->stream.total_in, ctx->stream.total_out, r->uri);
1314
1315            if (ctx->validation_buffer_length == VALIDATION_SIZE) {
1316                unsigned long compCRC, compLen;
1317                compCRC = getLong(ctx->validation_buffer);
1318                if (ctx->crc != compCRC) {
1319                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01399)
1320                                  "Zlib: Checksum of inflated stream invalid");
1321                    return APR_EGENERAL;
1322                }
1323                ctx->validation_buffer += VALIDATION_SIZE / 2;
1324                compLen = getLong(ctx->validation_buffer);
1325                if (ctx->stream.total_out != compLen) {
1326                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01400)
1327                                  "Zlib: Length of inflated stream invalid");
1328                    return APR_EGENERAL;
1329                }
1330            }
1331            else {
1332                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01401)
1333                              "Zlib: Validation bytes not present");
1334                return APR_EGENERAL;
1335            }
1336
1337            inflateEnd(&ctx->stream);
1338            /* No need for cleanup any longer */
1339            apr_pool_cleanup_kill(r->pool, ctx, deflate_ctx_cleanup);
1340
1341            /* Remove EOS from the old list, and insert into the new. */
1342            APR_BUCKET_REMOVE(e);
1343            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
1344
1345            /*
1346             * Okay, we've seen the EOS.
1347             * Time to pass it along down the chain.
1348             */
1349            return ap_pass_brigade(f->next, ctx->bb);
1350        }
1351
1352        if (APR_BUCKET_IS_FLUSH(e)) {
1353            apr_status_t rv;
1354
1355            /* flush the remaining data from the zlib buffers */
1356            zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, inflate,
1357                                    Z_SYNC_FLUSH, UPDATE_CRC);
1358            if (zRC != Z_OK) {
1359                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01402)
1360                              "Zlib error %d flushing inflate buffer (%s)",
1361                              zRC, ctx->stream.msg);
1362                return APR_EGENERAL;
1363            }
1364
1365            /* Remove flush bucket from old brigade anf insert into the new. */
1366            APR_BUCKET_REMOVE(e);
1367            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
1368            rv = ap_pass_brigade(f->next, ctx->bb);
1369            if (rv != APR_SUCCESS) {
1370                return rv;
1371            }
1372            continue;
1373        }
1374
1375        if (APR_BUCKET_IS_METADATA(e)) {
1376            /*
1377             * Remove meta data bucket from old brigade and insert into the
1378             * new.
1379             */
1380            APR_BUCKET_REMOVE(e);
1381            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
1382            continue;
1383        }
1384
1385        /* read */
1386        apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
1387
1388        /* first bucket contains zlib header */
1389        if (!ctx->inflate_init) {
1390            ctx->inflate_init = 1;
1391            if (len < 10) {
1392                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01403)
1393                              "Insufficient data for inflate");
1394                return APR_EGENERAL;
1395            }
1396            else  {
1397                zlib_method = data[2];
1398                zlib_flags = data[3];
1399                if (zlib_method != Z_DEFLATED) {
1400                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01404)
1401                                  "inflate: data not deflated!");
1402                    ap_remove_output_filter(f);
1403                    return ap_pass_brigade(f->next, bb);
1404                }
1405                if (data[0] != deflate_magic[0] ||
1406                    data[1] != deflate_magic[1] ||
1407                    (zlib_flags & RESERVED) != 0) {
1408                        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01405)
1409                                      "inflate: bad header");
1410                    return APR_EGENERAL ;
1411                }
1412                data += 10 ;
1413                len -= 10 ;
1414           }
1415           if (zlib_flags & EXTRA_FIELD) {
1416               unsigned int bytes = (unsigned int)(data[0]);
1417               bytes += ((unsigned int)(data[1])) << 8;
1418               bytes += 2;
1419               if (len < bytes) {
1420                   ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01406)
1421                                 "inflate: extra field too big (not "
1422                                 "supported)");
1423                   return APR_EGENERAL;
1424               }
1425               data += bytes;
1426               len -= bytes;
1427           }
1428           if (zlib_flags & ORIG_NAME) {
1429               while (len-- && *data++);
1430           }
1431           if (zlib_flags & COMMENT) {
1432               while (len-- && *data++);
1433           }
1434           if (zlib_flags & HEAD_CRC) {
1435                len -= 2;
1436                data += 2;
1437           }
1438        }
1439
1440        /* pass through zlib inflate. */
1441        ctx->stream.next_in = (unsigned char *)data;
1442        ctx->stream.avail_in = len;
1443
1444        if (ctx->validation_buffer) {
1445            if (ctx->validation_buffer_length < VALIDATION_SIZE) {
1446                apr_size_t copy_size;
1447
1448                copy_size = VALIDATION_SIZE - ctx->validation_buffer_length;
1449                if (copy_size > ctx->stream.avail_in)
1450                    copy_size = ctx->stream.avail_in;
1451                memcpy(ctx->validation_buffer + ctx->validation_buffer_length,
1452                       ctx->stream.next_in, copy_size);
1453                /* Saved copy_size bytes */
1454                ctx->stream.avail_in -= copy_size;
1455                ctx->validation_buffer_length += copy_size;
1456            }
1457            if (ctx->stream.avail_in) {
1458                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01407)
1459                              "Zlib: %d bytes of garbage at the end of "
1460                              "compressed stream.", ctx->stream.avail_in);
1461                /*
1462                 * There is nothing worth consuming for zlib left, because it is
1463                 * either garbage data or the data has been copied to the
1464                 * validation buffer (processing validation data is no business
1465                 * for zlib). So set ctx->stream.avail_in to zero to indicate
1466                 * this to the following while loop.
1467                 */
1468                ctx->stream.avail_in = 0;
1469            }
1470        }
1471
1472        while (ctx->stream.avail_in != 0) {
1473            if (ctx->stream.avail_out == 0) {
1474
1475                ctx->stream.next_out = ctx->buffer;
1476                len = c->bufferSize - ctx->stream.avail_out;
1477
1478                ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1479                b = apr_bucket_heap_create((char *)ctx->buffer, len,
1480                                           NULL, f->c->bucket_alloc);
1481                APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
1482                ctx->stream.avail_out = c->bufferSize;
1483                /* Send what we have right now to the next filter. */
1484                rv = ap_pass_brigade(f->next, ctx->bb);
1485                if (rv != APR_SUCCESS) {
1486                    return rv;
1487                }
1488            }
1489
1490            zRC = inflate(&ctx->stream, Z_NO_FLUSH);
1491
1492            if (zRC == Z_STREAM_END) {
1493                /*
1494                 * We have inflated all data. Now try to capture the
1495                 * validation bytes. We may not have them all available
1496                 * right now, but capture what is there.
1497                 */
1498                ctx->validation_buffer = apr_pcalloc(f->r->pool,
1499                                                     VALIDATION_SIZE);
1500                if (ctx->stream.avail_in > VALIDATION_SIZE) {
1501                    ctx->validation_buffer_length = VALIDATION_SIZE;
1502                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01408)
1503                                  "Zlib: %d bytes of garbage at the end of "
1504                                  "compressed stream.",
1505                                  ctx->stream.avail_in - VALIDATION_SIZE);
1506                } else if (ctx->stream.avail_in > 0) {
1507                           ctx->validation_buffer_length = ctx->stream.avail_in;
1508                }
1509                if (ctx->validation_buffer_length)
1510                    memcpy(ctx->validation_buffer, ctx->stream.next_in,
1511                           ctx->validation_buffer_length);
1512                break;
1513            }
1514
1515            if (zRC != Z_OK) {
1516                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01409)
1517                              "Zlib error %d inflating data (%s)", zRC,
1518                              ctx->stream.msg);
1519                return APR_EGENERAL;
1520            }
1521        }
1522
1523        apr_bucket_delete(e);
1524    }
1525
1526    apr_brigade_cleanup(bb);
1527    return APR_SUCCESS;
1528}
1529
1530static int mod_deflate_post_config(apr_pool_t *pconf, apr_pool_t *plog,
1531                                   apr_pool_t *ptemp, server_rec *s)
1532{
1533    mod_deflate_ssl_var = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
1534    return OK;
1535}
1536
1537
1538#define PROTO_FLAGS AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH
1539static void register_hooks(apr_pool_t *p)
1540{
1541    ap_register_output_filter(deflateFilterName, deflate_out_filter, NULL,
1542                              AP_FTYPE_CONTENT_SET);
1543    ap_register_output_filter("INFLATE", inflate_out_filter, NULL,
1544                              AP_FTYPE_RESOURCE-1);
1545    ap_register_input_filter(deflateFilterName, deflate_in_filter, NULL,
1546                              AP_FTYPE_CONTENT_SET);
1547    ap_hook_post_config(mod_deflate_post_config, NULL, NULL, APR_HOOK_MIDDLE);
1548}
1549
1550static const command_rec deflate_filter_cmds[] = {
1551    AP_INIT_TAKE12("DeflateFilterNote", deflate_set_note, NULL, RSRC_CONF,
1552                  "Set a note to report on compression ratio"),
1553    AP_INIT_TAKE1("DeflateWindowSize", deflate_set_window_size, NULL,
1554                  RSRC_CONF, "Set the Deflate window size (1-15)"),
1555    AP_INIT_TAKE1("DeflateBufferSize", deflate_set_buffer_size, NULL, RSRC_CONF,
1556                  "Set the Deflate Buffer Size"),
1557    AP_INIT_TAKE1("DeflateMemLevel", deflate_set_memlevel, NULL, RSRC_CONF,
1558                  "Set the Deflate Memory Level (1-9)"),
1559    AP_INIT_TAKE1("DeflateCompressionLevel", deflate_set_compressionlevel, NULL, RSRC_CONF,
1560                  "Set the Deflate Compression Level (1-9)"),
1561    {NULL}
1562};
1563
1564AP_DECLARE_MODULE(deflate) = {
1565    STANDARD20_MODULE_STUFF,
1566    NULL,                         /* dir config creater */
1567    NULL,                         /* dir merger --- default is to override */
1568    create_deflate_server_config, /* server config */
1569    NULL,                         /* merge server config */
1570    deflate_filter_cmds,          /* command table */
1571    register_hooks                /* register hooks */
1572};
1573