/[Apache-SVN]/httpd/httpd/trunk/modules/filters/mod_deflate.c
ViewVC logotype

Contents of /httpd/httpd/trunk/modules/filters/mod_deflate.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 743595 - (hide annotations)
Thu Feb 12 01:59:27 2009 UTC (9 months, 1 week ago) by fielding
File MIME type: text/plain
File size: 50355 byte(s)
Reimplement deflate_check_etag() so that it isn't such a pig
and correctly works with weak etags.  Related to PR 39727.

Note that there remains an error in ap_meets_conditions because
that function does not currently check for a transformed etag.
I am working on that.
1 fielding 420983 /* 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 jerenkrantz 94979 *
8 nd 102525 * http://www.apache.org/licenses/LICENSE-2.0
9 jerenkrantz 94979 *
10 nd 102525 * 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 jerenkrantz 94979 */
16    
17     /*
18 pquerna 161738 * mod_deflate.c: Perform deflate content-encoding on the fly
19 jerenkrantz 94979 *
20 ianh 103405 * Written by Ian Holsman, Justin Erenkrantz, and Nick Kew
21 jerenkrantz 94979 */
22    
23 nd 102525 /*
24 niq 104034 * Portions of this software are based upon zlib code by Jean-loup Gailly
25     * (zlib functions gz_open and gzwrite, check_header)
26 nd 102525 */
27    
28 niq 104034 /* 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 jerenkrantz 94979 #include "httpd.h"
38     #include "http_config.h"
39     #include "http_log.h"
40 niq 560937 #include "apr_lib.h"
41 jerenkrantz 94979 #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 trawick 95548 #define APR_WANT_STRFUNC
47     #include "apr_want.h"
48 jerenkrantz 94979
49     #include "zlib.h"
50    
51     static const char deflateFilterName[] = "DEFLATE";
52     module AP_MODULE_DECLARE_DATA deflate_module;
53    
54     typedef struct deflate_filter_config_t
55     {
56     int windowSize;
57     int memlevel;
58 ianh 98895 int compressionlevel;
59 wrowe 95676 apr_size_t bufferSize;
60 nd 98154 char *note_ratio_name;
61     char *note_input_name;
62     char *note_output_name;
63 jerenkrantz 94979 } deflate_filter_config;
64    
65 jorton 105410 /* RFC 1952 Section 2.3 defines the gzip header:
66     *
67     * +---+---+---+---+---+---+---+---+---+---+
68     * |ID1|ID2|CM |FLG| MTIME |XFL|OS |
69     * +---+---+---+---+---+---+---+---+---+---+
70     */
71 jim 332306 static const char gzip_header[10] =
72 jorton 105410 { '\037', '\213', Z_DEFLATED, 0,
73     0, 0, 0, 0, /* mtime */
74     0, 0x03 /* Unix OS_CODE */
75     };
76    
77     /* magic header */
78     static const char deflate_magic[2] = { '\037', '\213' };
79    
80 jerenkrantz 94979 /* windowsize is negative to suppress Zlib header */
81 ianh 98895 #define DEFAULT_COMPRESSION Z_DEFAULT_COMPRESSION
82 jerenkrantz 94979 #define DEFAULT_WINDOWSIZE -15
83     #define DEFAULT_MEMLEVEL 9
84 jerenkrantz 94987 #define DEFAULT_BUFFERSIZE 8096
85 jerenkrantz 94979
86 niq 562507
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 niq 563803 static int check_gzip(request_rec *r, apr_table_t *hdrs1, apr_table_t *hdrs2)
92 niq 562507 {
93     int found = 0;
94 niq 563803 apr_table_t *hdrs = hdrs1;
95 niq 562507 const char *encoding = apr_table_get(hdrs, "Content-Encoding");
96 niq 563317
97     if (!encoding && (hdrs2 != NULL)) {
98 niq 563803 /* the output filter has two tables and a content_encoding to check */
99 niq 563317 encoding = apr_table_get(hdrs2, "Content-Encoding");
100 niq 563803 hdrs = hdrs2;
101     if (!encoding) {
102     encoding = r->content_encoding;
103     hdrs = NULL;
104     }
105 niq 563317 }
106 niq 562507 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 niq 563803 if (hdrs) {
113     apr_table_unset(hdrs, "Content-Encoding");
114     }
115     else {
116     r->content_encoding = NULL;
117     }
118 niq 562507 }
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 niq 563803 char *new_encoding = apr_pstrdup(r->pool, encoding);
124 niq 562507 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 niq 563803 if (hdrs) {
132     apr_table_unset(hdrs, "Content-Encoding");
133     }
134     else {
135     r->content_encoding = NULL;
136     }
137 niq 562507 }
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 niq 563803 if (hdrs) {
145     apr_table_setn(hdrs, "Content-Encoding", new_encoding);
146     }
147     else {
148     r->content_encoding = new_encoding;
149     }
150 niq 562507 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 rpluem 726794 /*
161     * If we have dealt with the headers above but content_encoding was set
162     * before sync it with the new value in the hdrs table as
163     * r->content_encoding takes precedence later on in the http_header_filter
164     * and hence would destroy what we have just set in the hdrs table.
165     */
166     if (hdrs && r->content_encoding) {
167     r->content_encoding = apr_table_get(hdrs, "Content-Encoding");
168     }
169 niq 562507 return found;
170     }
171    
172 jerenkrantz 94979 /* Outputs a long in LSB order to the given file
173     * only the bottom 4 bits are required for the deflate file format.
174     */
175 jerenkrantz 95397 static void putLong(unsigned char *string, unsigned long x)
176 jerenkrantz 94979 {
177 jerenkrantz 95397 string[0] = (unsigned char)(x & 0xff);
178     string[1] = (unsigned char)((x & 0xff00) >> 8);
179     string[2] = (unsigned char)((x & 0xff0000) >> 16);
180     string[3] = (unsigned char)((x & 0xff000000) >> 24);
181 jerenkrantz 94979 }
182    
183 jerenkrantz 95345 /* Inputs a string and returns a long.
184     */
185 trawick 95350 static unsigned long getLong(unsigned char *string)
186 jerenkrantz 95345 {
187 jerenkrantz 95397 return ((unsigned long)string[0])
188     | (((unsigned long)string[1]) << 8)
189     | (((unsigned long)string[2]) << 16)
190     | (((unsigned long)string[3]) << 24);
191 jerenkrantz 95345 }
192    
193 jerenkrantz 94979 static void *create_deflate_server_config(apr_pool_t *p, server_rec *s)
194     {
195     deflate_filter_config *c = apr_pcalloc(p, sizeof *c);
196    
197     c->memlevel = DEFAULT_MEMLEVEL;
198     c->windowSize = DEFAULT_WINDOWSIZE;
199 jerenkrantz 94987 c->bufferSize = DEFAULT_BUFFERSIZE;
200 ianh 98895 c->compressionlevel = DEFAULT_COMPRESSION;
201 jerenkrantz 94979
202     return c;
203     }
204    
205     static const char *deflate_set_window_size(cmd_parms *cmd, void *dummy,
206     const char *arg)
207     {
208     deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
209     &deflate_module);
210     int i;
211    
212     i = atoi(arg);
213    
214     if (i < 1 || i > 15)
215     return "DeflateWindowSize must be between 1 and 15";
216    
217     c->windowSize = i * -1;
218    
219     return NULL;
220     }
221    
222 jerenkrantz 94987 static const char *deflate_set_buffer_size(cmd_parms *cmd, void *dummy,
223     const char *arg)
224     {
225     deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
226     &deflate_module);
227 wrowe 95676 int n = atoi(arg);
228 jerenkrantz 94987
229 wrowe 95676 if (n <= 0) {
230 jerenkrantz 94987 return "DeflateBufferSize should be positive";
231     }
232    
233 wrowe 95676 c->bufferSize = (apr_size_t)n;
234    
235 jerenkrantz 94987 return NULL;
236     }
237 jerenkrantz 94979 static const char *deflate_set_note(cmd_parms *cmd, void *dummy,
238 nd 98149 const char *arg1, const char *arg2)
239 jerenkrantz 94979 {
240     deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
241     &deflate_module);
242 jim 332306
243 nd 98149 if (arg2 == NULL) {
244 nd 98154 c->note_ratio_name = apr_pstrdup(cmd->pool, arg1);
245 nd 98149 }
246     else if (!strcasecmp(arg1, "ratio")) {
247 nd 98154 c->note_ratio_name = apr_pstrdup(cmd->pool, arg2);
248 nd 98149 }
249     else if (!strcasecmp(arg1, "input")) {
250 nd 98154 c->note_input_name = apr_pstrdup(cmd->pool, arg2);
251 nd 98149 }
252     else if (!strcasecmp(arg1, "output")) {
253 nd 98154 c->note_output_name = apr_pstrdup(cmd->pool, arg2);
254 nd 98149 }
255     else {
256     return apr_psprintf(cmd->pool, "Unknown note type %s", arg1);
257     }
258 jerenkrantz 94979
259     return NULL;
260     }
261    
262     static const char *deflate_set_memlevel(cmd_parms *cmd, void *dummy,
263     const char *arg)
264     {
265     deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
266     &deflate_module);
267     int i;
268    
269     i = atoi(arg);
270    
271     if (i < 1 || i > 9)
272     return "DeflateMemLevel must be between 1 and 9";
273    
274     c->memlevel = i;
275    
276     return NULL;
277     }
278    
279 ianh 98895 static const char *deflate_set_compressionlevel(cmd_parms *cmd, void *dummy,
280     const char *arg)
281     {
282     deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
283     &deflate_module);
284     int i;
285    
286     i = atoi(arg);
287    
288     if (i < 1 || i > 9)
289     return "Compression Level must be between 1 and 9";
290    
291     c->compressionlevel = i;
292    
293     return NULL;
294     }
295    
296 jerenkrantz 94979 typedef struct deflate_ctx_t
297     {
298     z_stream stream;
299 jerenkrantz 94987 unsigned char *buffer;
300 jerenkrantz 94979 unsigned long crc;
301 jerenkrantz 95345 apr_bucket_brigade *bb, *proc_bb;
302 rpluem 425109 int (*libz_end_func)(z_streamp);
303 rpluem 426799 unsigned char *validation_buffer;
304     apr_size_t validation_buffer_length;
305 niq 580598 int inflate_init;
306 jerenkrantz 94979 } deflate_ctx;
307    
308 rpluem 426791 /* Number of validation bytes (CRC and length) after the compressed data */
309     #define VALIDATION_SIZE 8
310 rpluem 426790 /* Do not update ctx->crc, see comment in flush_libz_buffer */
311     #define NO_UPDATE_CRC 0
312     /* Do update ctx->crc, see comment in flush_libz_buffer */
313     #define UPDATE_CRC 1
314    
315 rpluem 423940 static int flush_libz_buffer(deflate_ctx *ctx, deflate_filter_config *c,
316 rpluem 422731 struct apr_bucket_alloc_t *bucket_alloc,
317 rpluem 426790 int (*libz_func)(z_streamp, int), int flush,
318     int crc)
319 rpluem 422731 {
320 rpluem 424950 int zRC = Z_OK;
321 rpluem 422731 int done = 0;
322     unsigned int deflate_len;
323     apr_bucket *b;
324    
325     for (;;) {
326     deflate_len = c->bufferSize - ctx->stream.avail_out;
327    
328     if (deflate_len != 0) {
329 rpluem 426790 /*
330     * Do we need to update ctx->crc? Usually this is the case for
331     * inflate action where we need to do a crc on the output, whereas
332     * in the deflate case we need to do a crc on the input
333     */
334     if (crc) {
335     ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
336     deflate_len);
337     }
338 rpluem 422731 b = apr_bucket_heap_create((char *)ctx->buffer,
339     deflate_len, NULL,
340     bucket_alloc);
341     APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
342     ctx->stream.next_out = ctx->buffer;
343     ctx->stream.avail_out = c->bufferSize;
344     }
345    
346     if (done)
347     break;
348    
349 rpluem 423940 zRC = libz_func(&ctx->stream, flush);
350 rpluem 422731
351 rpluem 426793 /*
352     * We can ignore Z_BUF_ERROR because:
353     * When we call libz_func we can assume that
354     *
355     * - avail_in is zero (due to the surrounding code that calls
356     * flush_libz_buffer)
357     * - avail_out is non zero due to our actions some lines above
358     *
359     * So the only reason for Z_BUF_ERROR is that the internal libz
360     * buffers are now empty and thus we called libz_func one time
361     * too often. This does not hurt. It simply says that we are done.
362     */
363     if (zRC == Z_BUF_ERROR) {
364 rpluem 422731 zRC = Z_OK;
365 rpluem 426793 break;
366     }
367 rpluem 422731
368     done = (ctx->stream.avail_out != 0 || zRC == Z_STREAM_END);
369    
370     if (zRC != Z_OK && zRC != Z_STREAM_END)
371     break;
372     }
373     return zRC;
374     }
375    
376 rpluem 425109 static apr_status_t deflate_ctx_cleanup(void *data)
377     {
378     deflate_ctx *ctx = (deflate_ctx *)data;
379    
380     if (ctx)
381     ctx->libz_end_func(&ctx->stream);
382     return APR_SUCCESS;
383     }
384 fielding 743595
385     /* ETag must be unique among the possible representations, so a change
386     * to content-encoding requires a corresponding change to the ETag.
387     * This routine appends -transform (e.g., -gzip) to the entity-tag
388     * value inside the double-quotes if an ETag has already been set
389     * and its value already contains double-quotes. PR 39727
390 niq 581198 */
391 niq 607219 static void deflate_check_etag(request_rec *r, const char *transform)
392 niq 581198 {
393     const char *etag = apr_table_get(r->headers_out, "ETag");
394 fielding 743595 apr_size_t etaglen;
395    
396     if ((etag && ((etaglen = strlen(etag)) > 2))) {
397     if (etag[etaglen - 1] == '"') {
398     apr_size_t transformlen = strlen(transform);
399     char *newtag = apr_palloc(r->pool, etaglen + transformlen + 2);
400     char *d = newtag;
401     char *e = d + etaglen - 1;
402     const char *s = etag;
403    
404     for (; d < e; ++d, ++s) {
405     *d = *s; /* copy etag to newtag up to last quote */
406     }
407     *d++ = '-'; /* append dash to newtag */
408     s = transform;
409     e = d + transformlen;
410     for (; d < e; ++d, ++s) {
411     *d = *s; /* copy transform to newtag */
412     }
413     *d++ = '"'; /* append quote to newtag */
414     *d = '\0'; /* null terminate newtag */
415    
416     apr_table_setn(r->headers_out, "ETag", newtag);
417 lars 740149 }
418     }
419 niq 581198 }
420 fielding 743595
421 jerenkrantz 94979 static apr_status_t deflate_out_filter(ap_filter_t *f,
422     apr_bucket_brigade *bb)
423     {
424     apr_bucket *e;
425     request_rec *r = f->r;
426     deflate_ctx *ctx = f->ctx;
427     int zRC;
428 rpluem 426795 deflate_filter_config *c;
429 jerenkrantz 94979
430 niq 104352 /* Do nothing if asked to filter nothing. */
431     if (APR_BRIGADE_EMPTY(bb)) {
432 rpluem 424759 return ap_pass_brigade(f->next, bb);
433 niq 104352 }
434    
435 rpluem 426795 c = ap_get_module_config(r->server->module_config,
436     &deflate_module);
437    
438 jerenkrantz 94979 /* If we don't have a context, we need to ensure that it is okay to send
439     * the deflated content. If we have a context, that means we've done
440     * this before and we liked it.
441     * This could be not so nice if we always fail. But, if we succeed,
442     * we're in better shape.
443     */
444     if (!ctx) {
445 jorton 105410 char *token;
446 niq 104352 const char *encoding;
447 jerenkrantz 94979
448     /* only work on main request/no subrequests */
449 colm 395079 if (r->main != NULL) {
450 jerenkrantz 94982 ap_remove_output_filter(f);
451 jerenkrantz 94979 return ap_pass_brigade(f->next, bb);
452     }
453    
454     /* some browsers might have problems, so set no-gzip
455     * (with browsermatch) for them
456     */
457     if (apr_table_get(r->subprocess_env, "no-gzip")) {
458 jerenkrantz 94982 ap_remove_output_filter(f);
459 jerenkrantz 94979 return ap_pass_brigade(f->next, bb);
460     }
461    
462 niq 563154 /* We can't operate on Content-Ranges */
463     if (apr_table_get(r->headers_out, "Content-Range") != NULL) {
464     ap_remove_output_filter(f);
465     return ap_pass_brigade(f->next, bb);
466     }
467    
468 jerenkrantz 94979 /* Some browsers might have problems with content types
469     * other than text/html, so set gzip-only-text/html
470     * (with browsermatch) for them
471     */
472 ianh 96318 if (r->content_type == NULL
473     || strncmp(r->content_type, "text/html", 9)) {
474     const char *env_value = apr_table_get(r->subprocess_env,
475     "gzip-only-text/html");
476 ianh 96588 if ( env_value && (strcmp(env_value,"1") == 0) ) {
477 ianh 96318 ap_remove_output_filter(f);
478 ianh 96590 return ap_pass_brigade(f->next, bb);
479 jim 332306 }
480 jerenkrantz 94979 }
481    
482 jerenkrantz 95339 /* Let's see what our current Content-Encoding is.
483 nd 101019 * If it's already encoded, don't compress again.
484     * (We could, but let's not.)
485 jerenkrantz 95339 */
486     encoding = apr_table_get(r->headers_out, "Content-Encoding");
487     if (encoding) {
488 nd 98948 const char *err_enc;
489    
490     err_enc = apr_table_get(r->err_headers_out, "Content-Encoding");
491     if (err_enc) {
492     encoding = apr_pstrcat(r->pool, encoding, ",", err_enc, NULL);
493     }
494     }
495     else {
496     encoding = apr_table_get(r->err_headers_out, "Content-Encoding");
497     }
498    
499 nd 99880 if (r->content_encoding) {
500     encoding = encoding ? apr_pstrcat(r->pool, encoding, ",",
501     r->content_encoding, NULL)
502     : r->content_encoding;
503     }
504    
505 nd 98948 if (encoding) {
506 jerenkrantz 95339 const char *tmp = encoding;
507    
508     token = ap_get_token(r->pool, &tmp, 0);
509 nd 101019 while (token && *token) {
510     /* stolen from mod_negotiation: */
511     if (strcmp(token, "identity") && strcmp(token, "7bit") &&
512     strcmp(token, "8bit") && strcmp(token, "binary")) {
513    
514 jerenkrantz 95339 ap_remove_output_filter(f);
515 ianh 103405 return ap_pass_brigade(f->next, bb);
516 jerenkrantz 95339 }
517 nd 101019
518 jerenkrantz 95339 /* Otherwise, skip token */
519 nd 101019 if (*tmp) {
520     ++tmp;
521     }
522     token = (*tmp) ? ap_get_token(r->pool, &tmp, 0) : NULL;
523 jerenkrantz 95339 }
524 ianh 95181 }
525    
526 jerenkrantz 97473 /* Even if we don't accept this request based on it not having
527     * the Accept-Encoding, we need to note that we were looking
528     * for this header and downstream proxies should be aware of that.
529     */
530 pquerna 161691 apr_table_mergen(r->headers_out, "Vary", "Accept-Encoding");
531 jerenkrantz 97473
532 ianh 103405 /* force-gzip will just force it out regardless if the browser
533     * can actually do anything with it.
534     */
535 jerenkrantz 103803 if (!apr_table_get(r->subprocess_env, "force-gzip")) {
536 ianh 103405 const char *accepts;
537     /* if they don't have the line, then they can't play */
538     accepts = apr_table_get(r->headers_in, "Accept-Encoding");
539     if (accepts == NULL) {
540     ap_remove_output_filter(f);
541     return ap_pass_brigade(f->next, bb);
542 nd 101015 }
543    
544 ianh 103405 token = ap_get_token(r->pool, &accepts, 0);
545     while (token && token[0] && strcasecmp(token, "gzip")) {
546     /* skip parameters, XXX: ;q=foo evaluation? */
547 jim 332306 while (*accepts == ';') {
548 ianh 103405 ++accepts;
549     token = ap_get_token(r->pool, &accepts, 1);
550     }
551    
552     /* retrieve next token */
553     if (*accepts == ',') {
554     ++accepts;
555     }
556     token = (*accepts) ? ap_get_token(r->pool, &accepts, 0) : NULL;
557 nd 101015 }
558 jerenkrantz 94979
559 ianh 103405 /* No acceptable token found. */
560     if (token == NULL || token[0] == '\0') {
561     ap_remove_output_filter(f);
562     return ap_pass_brigade(f->next, bb);
563     }
564 jerenkrantz 94979 }
565 ake 103910
566 jorton 109500 /* For a 304 or 204 response there is no entity included in
567     * the response and hence nothing to deflate. */
568     if (r->status == HTTP_NOT_MODIFIED || r->status == HTTP_NO_CONTENT) {
569 niq 104352 ap_remove_output_filter(f);
570 ake 103910 return ap_pass_brigade(f->next, bb);
571     }
572    
573 jerenkrantz 94979 /* We're cool with filtering this. */
574     ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx));
575     ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
576 jerenkrantz 94987 ctx->buffer = apr_palloc(r->pool, c->bufferSize);
577 rpluem 425109 ctx->libz_end_func = deflateEnd;
578 jerenkrantz 95339
579 ianh 98895 zRC = deflateInit2(&ctx->stream, c->compressionlevel, Z_DEFLATED,
580 jerenkrantz 94979 c->windowSize, c->memlevel,
581     Z_DEFAULT_STRATEGY);
582    
583     if (zRC != Z_OK) {
584 rpluem 426795 deflateEnd(&ctx->stream);
585 trawick 95151 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
586 jerenkrantz 94979 "unable to init Zlib: "
587     "deflateInit2 returned %d: URL %s",
588     zRC, r->uri);
589 rpluem 422739 /*
590     * Remove ourselves as it does not make sense to return:
591     * We are not able to init libz and pass data down the chain
592     * uncompressed.
593     */
594     ap_remove_output_filter(f);
595 jerenkrantz 94979 return ap_pass_brigade(f->next, bb);
596     }
597 rpluem 425109 /*
598     * Register a cleanup function to ensure that we cleanup the internal
599     * libz resources.
600     */
601     apr_pool_cleanup_register(r->pool, ctx, deflate_ctx_cleanup,
602     apr_pool_cleanup_null);
603 jerenkrantz 94979
604 jorton 105410 /* add immortal gzip header */
605     e = apr_bucket_immortal_create(gzip_header, sizeof gzip_header,
606     f->c->bucket_alloc);
607 jerenkrantz 94979 APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
608    
609 jerenkrantz 95339 /* If the entire Content-Encoding is "identity", we can replace it. */
610     if (!encoding || !strcasecmp(encoding, "identity")) {
611     apr_table_setn(r->headers_out, "Content-Encoding", "gzip");
612     }
613     else {
614     apr_table_mergen(r->headers_out, "Content-Encoding", "gzip");
615     }
616 rpluem 726791 /* Fix r->content_encoding if it was set before */
617     if (r->content_encoding) {
618     r->content_encoding = apr_table_get(r->headers_out,
619     "Content-Encoding");
620     }
621 jerenkrantz 94979 apr_table_unset(r->headers_out, "Content-Length");
622 rpluem 563230 apr_table_unset(r->headers_out, "Content-MD5");
623 niq 607219 deflate_check_etag(r, "gzip");
624 jerenkrantz 95521
625     /* initialize deflate output buffer */
626     ctx->stream.next_out = ctx->buffer;
627     ctx->stream.avail_out = c->bufferSize;
628 jerenkrantz 94979 }
629 jim 332306
630 jorton 103810 while (!APR_BRIGADE_EMPTY(bb))
631 jwoolley 101788 {
632 jerenkrantz 94979 const char *data;
633     apr_bucket *b;
634     apr_size_t len;
635    
636 jorton 103810 e = APR_BRIGADE_FIRST(bb);
637    
638 jerenkrantz 94979 if (APR_BUCKET_IS_EOS(e)) {
639 jwoolley 95413 char *buf;
640 jerenkrantz 94979
641     ctx->stream.avail_in = 0; /* should be zero already anyway */
642 rpluem 422731 /* flush the remaining data from the zlib buffers */
643 rpluem 426790 flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate, Z_FINISH,
644     NO_UPDATE_CRC);
645 jerenkrantz 94979
646 rpluem 426791 buf = apr_palloc(r->pool, VALIDATION_SIZE);
647 jwoolley 95413 putLong((unsigned char *)&buf[0], ctx->crc);
648     putLong((unsigned char *)&buf[4], ctx->stream.total_in);
649 jerenkrantz 94979
650 rpluem 426791 b = apr_bucket_pool_create(buf, VALIDATION_SIZE, r->pool,
651     f->c->bucket_alloc);
652 jerenkrantz 94979 APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
653 trawick 95151 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
654 jerenkrantz 94979 "Zlib: Compressed %ld to %ld : URL %s",
655     ctx->stream.total_in, ctx->stream.total_out, r->uri);
656    
657 nd 98154 /* leave notes for logging */
658     if (c->note_input_name) {
659     apr_table_setn(r->notes, c->note_input_name,
660     (ctx->stream.total_in > 0)
661     ? apr_off_t_toa(r->pool,
662     ctx->stream.total_in)
663     : "-");
664     }
665 jerenkrantz 94979
666 nd 98154 if (c->note_output_name) {
667     apr_table_setn(r->notes, c->note_output_name,
668     (ctx->stream.total_in > 0)
669     ? apr_off_t_toa(r->pool,
670     ctx->stream.total_out)
671     : "-");
672     }
673    
674     if (c->note_ratio_name) {
675     apr_table_setn(r->notes, c->note_ratio_name,
676     (ctx->stream.total_in > 0)
677     ? apr_itoa(r->pool,
678     (int)(ctx->stream.total_out
679     * 100
680     / ctx->stream.total_in))
681     : "-");
682     }
683    
684 jerenkrantz 94979 deflateEnd(&ctx->stream);
685 rpluem 425109 /* No need for cleanup any longer */
686     apr_pool_cleanup_kill(r->pool, ctx, deflate_ctx_cleanup);
687 jerenkrantz 94979
688     /* Remove EOS from the old list, and insert into the new. */
689     APR_BUCKET_REMOVE(e);
690     APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
691    
692     /* Okay, we've seen the EOS.
693     * Time to pass it along down the chain.
694     */
695     return ap_pass_brigade(f->next, ctx->bb);
696     }
697    
698     if (APR_BUCKET_IS_FLUSH(e)) {
699 jerenkrantz 100730 apr_status_t rv;
700 jorton 103810
701 rpluem 422731 /* flush the remaining data from the zlib buffers */
702 rpluem 423940 zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate,
703 rpluem 426790 Z_SYNC_FLUSH, NO_UPDATE_CRC);
704 rpluem 422731 if (zRC != Z_OK) {
705     return APR_EGENERAL;
706 jerenkrantz 95341 }
707 jerenkrantz 94979
708 rpluem 422731 /* Remove flush bucket from old brigade anf insert into the new. */
709     APR_BUCKET_REMOVE(e);
710     APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
711 jerenkrantz 100730 rv = ap_pass_brigade(f->next, ctx->bb);
712     if (rv != APR_SUCCESS) {
713     return rv;
714     }
715 jerenkrantz 94979 continue;
716     }
717    
718 gregames 556028 if (APR_BUCKET_IS_METADATA(e)) {
719     /*
720     * Remove meta data bucket from old brigade and insert into the
721     * new.
722     */
723     APR_BUCKET_REMOVE(e);
724     APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
725     continue;
726 gregames 554011 }
727    
728 jerenkrantz 94979 /* read */
729     apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
730    
731     /* This crc32 function is from zlib. */
732     ctx->crc = crc32(ctx->crc, (const Bytef *)data, len);
733    
734     /* write */
735     ctx->stream.next_in = (unsigned char *)data; /* We just lost const-ness,
736     * but we'll just have to
737     * trust zlib */
738     ctx->stream.avail_in = len;
739    
740     while (ctx->stream.avail_in != 0) {
741     if (ctx->stream.avail_out == 0) {
742 jerenkrantz 100730 apr_status_t rv;
743    
744 jerenkrantz 94979 ctx->stream.next_out = ctx->buffer;
745 jerenkrantz 94987 len = c->bufferSize - ctx->stream.avail_out;
746 jerenkrantz 94979
747     b = apr_bucket_heap_create((char *)ctx->buffer, len,
748     NULL, f->c->bucket_alloc);
749     APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
750 jerenkrantz 94987 ctx->stream.avail_out = c->bufferSize;
751 jerenkrantz 100730 /* Send what we have right now to the next filter. */
752     rv = ap_pass_brigade(f->next, ctx->bb);
753     if (rv != APR_SUCCESS) {
754     return rv;
755     }
756 jerenkrantz 94979 }
757    
758     zRC = deflate(&(ctx->stream), Z_NO_FLUSH);
759    
760 rpluem 422736 if (zRC != Z_OK) {
761 jerenkrantz 94979 return APR_EGENERAL;
762 rpluem 422736 }
763 jerenkrantz 94979 }
764 jorton 103810
765     apr_bucket_delete(e);
766 jerenkrantz 94979 }
767    
768 jwoolley 97526 apr_brigade_cleanup(bb);
769 jerenkrantz 94979 return APR_SUCCESS;
770     }
771    
772 jerenkrantz 95345 /* This is the deflate input filter (inflates). */
773     static apr_status_t deflate_in_filter(ap_filter_t *f,
774     apr_bucket_brigade *bb,
775     ap_input_mode_t mode,
776     apr_read_type_e block,
777     apr_off_t readbytes)
778     {
779     apr_bucket *bkt;
780     request_rec *r = f->r;
781     deflate_ctx *ctx = f->ctx;
782     int zRC;
783     apr_status_t rv;
784     deflate_filter_config *c;
785    
786     /* just get out of the way of things we don't want. */
787     if (mode != AP_MODE_READBYTES) {
788     return ap_get_brigade(f->next, bb, mode, block, readbytes);
789     }
790    
791     c = ap_get_module_config(r->server->module_config, &deflate_module);
792    
793     if (!ctx) {
794 niq 562507 char deflate_hdr[10];
795 jerenkrantz 95345 apr_size_t len;
796    
797     /* only work on main request/no subrequests */
798 pquerna 105403 if (!ap_is_initial_req(r)) {
799 jerenkrantz 95345 ap_remove_input_filter(f);
800     return ap_get_brigade(f->next, bb, mode, block, readbytes);
801     }
802    
803 niq 563154 /* We can't operate on Content-Ranges */
804     if (apr_table_get(r->headers_in, "Content-Range") != NULL) {
805     ap_remove_input_filter(f);
806     return ap_get_brigade(f->next, bb, mode, block, readbytes);
807     }
808    
809 niq 560689 /* Check whether request body is gzipped.
810     *
811     * If it is, we're transforming the contents, invalidating
812     * some request headers including Content-Encoding.
813     *
814     * If not, we just remove ourself.
815 jerenkrantz 95345 */
816 niq 563803 if (check_gzip(r, r->headers_in, NULL) == 0) {
817 jerenkrantz 95345 ap_remove_input_filter(f);
818     return ap_get_brigade(f->next, bb, mode, block, readbytes);
819     }
820    
821     f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
822     ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
823     ctx->proc_bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
824     ctx->buffer = apr_palloc(r->pool, c->bufferSize);
825    
826     rv = ap_get_brigade(f->next, ctx->bb, AP_MODE_READBYTES, block, 10);
827     if (rv != APR_SUCCESS) {
828     return rv;
829     }
830 jerenkrantz 98689
831 niq 563133 apr_table_unset(r->headers_in, "Content-Length");
832     apr_table_unset(r->headers_in, "Content-MD5");
833    
834 jim 332306 len = 10;
835     rv = apr_brigade_flatten(ctx->bb, deflate_hdr, &len);
836 jerenkrantz 95345 if (rv != APR_SUCCESS) {
837     return rv;
838     }
839    
840     /* We didn't get the magic bytes. */
841     if (len != 10 ||
842     deflate_hdr[0] != deflate_magic[0] ||
843     deflate_hdr[1] != deflate_magic[1]) {
844     return APR_EGENERAL;
845     }
846    
847     /* We can't handle flags for now. */
848     if (deflate_hdr[3] != 0) {
849     return APR_EGENERAL;
850     }
851    
852     zRC = inflateInit2(&ctx->stream, c->windowSize);
853    
854     if (zRC != Z_OK) {
855     f->ctx = NULL;
856 jerenkrantz 98689 inflateEnd(&ctx->stream);
857 jerenkrantz 95345 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
858     "unable to init Zlib: "
859     "inflateInit2 returned %d: URL %s",
860     zRC, r->uri);
861     ap_remove_input_filter(f);
862     return ap_get_brigade(f->next, bb, mode, block, readbytes);
863     }
864    
865     /* initialize deflate output buffer */
866     ctx->stream.next_out = ctx->buffer;
867     ctx->stream.avail_out = c->bufferSize;
868    
869     apr_brigade_cleanup(ctx->bb);
870     }
871    
872     if (APR_BRIGADE_EMPTY(ctx->proc_bb)) {
873     rv = ap_get_brigade(f->next, ctx->bb, mode, block, readbytes);
874    
875     if (rv != APR_SUCCESS) {
876 jerenkrantz 98689 /* What about APR_EAGAIN errors? */
877     inflateEnd(&ctx->stream);
878 jerenkrantz 95345 return rv;
879     }
880    
881 jwoolley 101788 for (bkt = APR_BRIGADE_FIRST(ctx->bb);
882     bkt != APR_BRIGADE_SENTINEL(ctx->bb);
883     bkt = APR_BUCKET_NEXT(bkt))
884     {
885 jerenkrantz 95345 const char *data;
886     apr_size_t len;
887    
888     /* If we actually see the EOS, that means we screwed up! */
889     if (APR_BUCKET_IS_EOS(bkt)) {
890 jerenkrantz 98689 inflateEnd(&ctx->stream);
891 jerenkrantz 95345 return APR_EGENERAL;
892     }
893    
894     if (APR_BUCKET_IS_FLUSH(bkt)) {
895     apr_bucket *tmp_heap;
896     zRC = inflate(&(ctx->stream), Z_SYNC_FLUSH);
897     if (zRC != Z_OK) {
898 jerenkrantz 98689 inflateEnd(&ctx->stream);
899 jerenkrantz 95345 return APR_EGENERAL;
900     }
901    
902     ctx->stream.next_out = ctx->buffer;
903     len = c->bufferSize - ctx->stream.avail_out;
904    
905     ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
906     tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
907     NULL, f->c->bucket_alloc);
908     APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
909     ctx->stream.avail_out = c->bufferSize;
910    
911     /* Move everything to the returning brigade. */
912     APR_BUCKET_REMOVE(bkt);
913     APR_BRIGADE_CONCAT(bb, ctx->bb);
914     break;
915     }
916    
917     /* read */
918     apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ);
919    
920     /* pass through zlib inflate. */
921     ctx->stream.next_in = (unsigned char *)data;
922     ctx->stream.avail_in = len;
923    
924 jerenkrantz 95359 zRC = Z_OK;
925    
926 jerenkrantz 95345 while (ctx->stream.avail_in != 0) {
927     if (ctx->stream.avail_out == 0) {
928     apr_bucket *tmp_heap;
929     ctx->stream.next_out = ctx->buffer;
930     len = c->bufferSize - ctx->stream.avail_out;
931    
932     ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
933     tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
934     NULL, f->c->bucket_alloc);
935     APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
936     ctx->stream.avail_out = c->bufferSize;
937     }
938    
939     zRC = inflate(&ctx->stream, Z_NO_FLUSH);
940    
941     if (zRC == Z_STREAM_END) {
942     break;
943     }
944    
945     if (zRC != Z_OK) {
946 jerenkrantz 98689 inflateEnd(&ctx->stream);
947 jerenkrantz 95345 return APR_EGENERAL;
948     }
949     }
950     if (zRC == Z_STREAM_END) {
951     apr_bucket *tmp_heap, *eos;
952    
953     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
954     "Zlib: Inflated %ld to %ld : URL %s",
955     ctx->stream.total_in, ctx->stream.total_out,
956     r->uri);
957    
958     len = c->bufferSize - ctx->stream.avail_out;
959    
960     ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
961     tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
962     NULL, f->c->bucket_alloc);
963     APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
964     ctx->stream.avail_out = c->bufferSize;
965    
966     /* Is the remaining 8 bytes already in the avail stream? */
967     if (ctx->stream.avail_in >= 8) {
968     unsigned long compCRC, compLen;
969     compCRC = getLong(ctx->stream.next_in);
970     if (ctx->crc != compCRC) {
971 jerenkrantz 98689 inflateEnd(&ctx->stream);
972 jerenkrantz 95345 return APR_EGENERAL;
973     }
974     ctx->stream.next_in += 4;
975     compLen = getLong(ctx->stream.next_in);
976     if (ctx->stream.total_out != compLen) {
977 jerenkrantz 98689 inflateEnd(&ctx->stream);
978 jerenkrantz 95345 return APR_EGENERAL;
979     }
980     }
981     else {
982     /* FIXME: We need to grab the 8 verification bytes
983     * from the wire! */
984 jerenkrantz 98689 inflateEnd(&ctx->stream);
985 jerenkrantz 95345 return APR_EGENERAL;
986     }
987    
988     inflateEnd(&ctx->stream);
989 jerenkrantz 98689
990 jerenkrantz 95345 eos = apr_bucket_eos_create(f->c->bucket_alloc);
991 jim 332306 APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, eos);
992 jerenkrantz 95345 break;
993     }
994 jerenkrantz 95666
995 jerenkrantz 95345 }
996 jerenkrantz 95521 apr_brigade_cleanup(ctx->bb);
997 jerenkrantz 95345 }
998    
999 jerenkrantz 95666 /* If we are about to return nothing for a 'blocking' read and we have
1000     * some data in our zlib buffer, flush it out so we can return something.
1001     */
1002     if (block == APR_BLOCK_READ &&
1003     APR_BRIGADE_EMPTY(ctx->proc_bb) &&
1004     ctx->stream.avail_out < c->bufferSize) {
1005     apr_bucket *tmp_heap;
1006     apr_size_t len;
1007     ctx->stream.next_out = ctx->buffer;
1008     len = c->bufferSize - ctx->stream.avail_out;
1009    
1010     ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1011     tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
1012     NULL, f->c->bucket_alloc);
1013     APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
1014     ctx->stream.avail_out = c->bufferSize;
1015     }
1016    
1017 jerenkrantz 95345 if (!APR_BRIGADE_EMPTY(ctx->proc_bb)) {
1018     apr_bucket_brigade *newbb;
1019    
1020     /* May return APR_INCOMPLETE which is fine by us. */
1021     apr_brigade_partition(ctx->proc_bb, readbytes, &bkt);
1022    
1023     newbb = apr_brigade_split(ctx->proc_bb, bkt);
1024     APR_BRIGADE_CONCAT(bb, ctx->proc_bb);
1025     APR_BRIGADE_CONCAT(ctx->proc_bb, newbb);
1026     }
1027    
1028     return APR_SUCCESS;
1029     }
1030    
1031 ianh 103405
1032     /* Filter to inflate for a content-transforming proxy. */
1033     static apr_status_t inflate_out_filter(ap_filter_t *f,
1034     apr_bucket_brigade *bb)
1035     {
1036 nd 104166 int zlib_method;
1037     int zlib_flags;
1038 rpluem 426799 apr_bucket *e;
1039 ianh 103405 request_rec *r = f->r;
1040     deflate_ctx *ctx = f->ctx;
1041     int zRC;
1042     apr_status_t rv;
1043     deflate_filter_config *c;
1044    
1045 niq 104352 /* Do nothing if asked to filter nothing. */
1046     if (APR_BRIGADE_EMPTY(bb)) {
1047 rpluem 424759 return ap_pass_brigade(f->next, bb);
1048 niq 104352 }
1049    
1050 ianh 103405 c = ap_get_module_config(r->server->module_config, &deflate_module);
1051    
1052     if (!ctx) {
1053    
1054     /* only work on main request/no subrequests */
1055 pquerna 105403 if (!ap_is_initial_req(r)) {
1056 ianh 103405 ap_remove_output_filter(f);
1057     return ap_pass_brigade(f->next, bb);
1058     }
1059    
1060 niq 563154 /* We can't operate on Content-Ranges */
1061     if (apr_table_get(r->headers_out, "Content-Range") != NULL) {
1062     ap_remove_output_filter(f);
1063     return ap_pass_brigade(f->next, bb);
1064     }
1065    
1066 rpluem 475922 /*
1067     * Let's see what our current Content-Encoding is.
1068 niq 562507 * Only inflate if gzipped.
1069 ianh 103405 */
1070 niq 563803 if (check_gzip(r, r->headers_out, r->err_headers_out) == 0) {
1071 ianh 103405 ap_remove_output_filter(f);
1072     return ap_pass_brigade(f->next, bb);
1073     }
1074    
1075 niq 104352 /* No need to inflate HEAD or 204/304 */
1076     if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(bb))) {
1077     ap_remove_output_filter(f);
1078     return ap_pass_brigade(f->next, bb);
1079     }
1080    
1081 ianh 103405 f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
1082 rpluem 426799 ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
1083 ianh 103405 ctx->buffer = apr_palloc(r->pool, c->bufferSize);
1084 rpluem 426799 ctx->libz_end_func = inflateEnd;
1085     ctx->validation_buffer = NULL;
1086     ctx->validation_buffer_length = 0;
1087 ianh 103405
1088     zRC = inflateInit2(&ctx->stream, c->windowSize);
1089    
1090     if (zRC != Z_OK) {
1091     f->ctx = NULL;
1092     inflateEnd(&ctx->stream);
1093     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1094     "unable to init Zlib: "
1095     "inflateInit2 returned %d: URL %s",
1096     zRC, r->uri);
1097 rpluem 426799 /*
1098     * Remove ourselves as it does not make sense to return:
1099     * We are not able to init libz and pass data down the chain
1100     * compressed.
1101     */
1102 ianh 103405 ap_remove_output_filter(f);
1103     return ap_pass_brigade(f->next, bb);
1104     }
1105    
1106 rpluem 426799 /*
1107     * Register a cleanup function to ensure that we cleanup the internal
1108     * libz resources.
1109     */
1110     apr_pool_cleanup_register(r->pool, ctx, deflate_ctx_cleanup,
1111     apr_pool_cleanup_null);
1112    
1113 rpluem 563229 /* these are unlikely to be set anyway, but ... */
1114 rpluem 426799 apr_table_unset(r->headers_out, "Content-Length");
1115 rpluem 563229 apr_table_unset(r->headers_out, "Content-MD5");
1116 niq 607219 deflate_check_etag(r, "gunzip");
1117 rpluem 426799
1118     /* initialize inflate output buffer */
1119 ianh 103405 ctx->stream.next_out = ctx->buffer;
1120     ctx->stream.avail_out = c->bufferSize;
1121    
1122 niq 580598 ctx->inflate_init = 0;
1123 ianh 103405 }
1124    
1125 rpluem 426799 while (!APR_BRIGADE_EMPTY(bb))
1126 ianh 103405 {
1127     const char *data;
1128 rpluem 426799 apr_bucket *b;
1129 ianh 103405 apr_size_t len;
1130    
1131 rpluem 426799 e = APR_BRIGADE_FIRST(bb);
1132    
1133     if (APR_BUCKET_IS_EOS(e)) {
1134 rpluem 475406 /*
1135     * We are really done now. Ensure that we never return here, even
1136     * if a second EOS bucket falls down the chain. Thus remove
1137     * ourselves.
1138     */
1139     ap_remove_output_filter(f);
1140 rpluem 475922 /* should be zero already anyway */
1141     ctx->stream.avail_in = 0;
1142 rpluem 426799 /*
1143     * Flush the remaining data from the zlib buffers. It is correct
1144     * to use Z_SYNC_FLUSH in this case and not Z_FINISH as in the
1145     * deflate case. In the inflate case Z_FINISH requires to have a
1146     * large enough output buffer to put ALL data in otherwise it
1147     * fails, whereas in the deflate case you can empty a filled output
1148     * buffer and call it again until no more output can be created.
1149     */
1150     flush_libz_buffer(ctx, c, f->c->bucket_alloc, inflate, Z_SYNC_FLUSH,
1151     UPDATE_CRC);
1152     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1153     "Zlib: Inflated %ld to %ld : URL %s",
1154     ctx->stream.total_in, ctx->stream.total_out, r->uri);
1155    
1156     if (ctx->validation_buffer_length == VALIDATION_SIZE) {
1157     unsigned long compCRC, compLen;
1158     compCRC = getLong(ctx->validation_buffer);
1159     if (ctx->crc != compCRC) {
1160     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1161     "Zlib: Checksum of inflated stream invalid");
1162     return APR_EGENERAL;
1163     }
1164     ctx->validation_buffer += VALIDATION_SIZE / 2;
1165     compLen = getLong(ctx->validation_buffer);
1166     if (ctx->stream.total_out != compLen) {
1167     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1168     "Zlib: Length of inflated stream invalid");
1169     return APR_EGENERAL;
1170     }
1171     }
1172     else {
1173     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1174     "Zlib: Validation bytes not present");
1175     return APR_EGENERAL;
1176     }
1177    
1178 ianh 103405 inflateEnd(&ctx->stream);
1179 rpluem 426799 /* No need for cleanup any longer */
1180     apr_pool_cleanup_kill(r->pool, ctx, deflate_ctx_cleanup);
1181    
1182     /* Remove EOS from the old list, and insert into the new. */
1183     APR_BUCKET_REMOVE(e);
1184     APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
1185    
1186     /*
1187     * Okay, we've seen the EOS.
1188     * Time to pass it along down the chain.
1189     */
1190     return ap_pass_brigade(f->next, ctx->bb);
1191 ianh 103405 }
1192    
1193 rpluem 426799 if (APR_BUCKET_IS_FLUSH(e)) {
1194     apr_status_t rv;
1195    
1196     /* flush the remaining data from the zlib buffers */
1197     zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, inflate,
1198     Z_SYNC_FLUSH, UPDATE_CRC);
1199     if (zRC != Z_OK) {
1200     return APR_EGENERAL;
1201     }
1202    
1203     /* Remove flush bucket from old brigade anf insert into the new. */
1204     APR_BUCKET_REMOVE(e);
1205     APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
1206     rv = ap_pass_brigade(f->next, ctx->bb);
1207     if (rv != APR_SUCCESS) {
1208     return rv;
1209     }
1210 niq 416165 continue;
1211 ianh 103405 }
1212    
1213 gregames 556028 if (APR_BUCKET_IS_METADATA(e)) {
1214     /*
1215     * Remove meta data bucket from old brigade and insert into the
1216     * new.
1217     */
1218     APR_BUCKET_REMOVE(e);
1219     APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
1220     continue;
1221     }
1222    
1223 ianh 103405 /* read */
1224 rpluem 426799 apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
1225 ianh 103405
1226     /* first bucket contains zlib header */
1227 niq 580598 if (!ctx->inflate_init++) {
1228 nd 104166 if (len < 10) {
1229 ianh 103405 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1230     "Insufficient data for inflate");
1231 nd 104166 return APR_EGENERAL;
1232 jim 332306 }
1233 ianh 103405 else {
1234 nd 104166 zlib_method = data[2];
1235     zlib_flags = data[3];
1236     if (zlib_method != Z_DEFLATED) {
1237 nd 104155 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1238 nd 104166 "inflate: data not deflated!");
1239     ap_remove_output_filter(f);
1240     return ap_pass_brigade(f->next, bb);
1241 niq 104034 }
1242 ianh 103405 if (data[0] != deflate_magic[0] ||
1243 niq 104034 data[1] != deflate_magic[1] ||
1244 nd 104166 (zlib_flags & RESERVED) != 0) {
1245 ianh 103405 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1246 nd 104166 "inflate: bad header");
1247 ianh 103405 return APR_EGENERAL ;
1248     }
1249     data += 10 ;
1250     len -= 10 ;
1251     }
1252 nd 104166 if (zlib_flags & EXTRA_FIELD) {
1253     unsigned int bytes = (unsigned int)(data[0]);
1254     bytes += ((unsigned int)(data[1])) << 8;
1255     bytes += 2;
1256     if (len < bytes) {
1257 niq 104034 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1258 nd 104166 "inflate: extra field too big (not "
1259     "supported)");
1260     return APR_EGENERAL;
1261 niq 104034 }
1262 nd 104166 data += bytes;
1263     len -= bytes;
1264 niq 104034 }
1265 nd 104166 if (zlib_flags & ORIG_NAME) {
1266     while (len-- && *data++);
1267 niq 104034 }
1268 nd 104166 if (zlib_flags & COMMENT) {
1269     while (len-- && *data++);
1270 niq 104034 }
1271 nd 104166 if (zlib_flags & HEAD_CRC) {
1272     len -= 2;
1273     data += 2;
1274 niq 104034 }
1275 ianh 103405 }
1276    
1277     /* pass through zlib inflate. */
1278     ctx->stream.next_in = (unsigned char *)data;
1279     ctx->stream.avail_in = len;
1280    
1281 rpluem 426799 if (ctx->validation_buffer) {
1282     if (ctx->validation_buffer_length < VALIDATION_SIZE) {
1283     apr_size_t copy_size;
1284    
1285     copy_size = VALIDATION_SIZE - ctx->validation_buffer_length;
1286     if (copy_size > ctx->stream.avail_in)
1287     copy_size = ctx->stream.avail_in;
1288 rpluem 475915 memcpy(ctx->validation_buffer + ctx->validation_buffer_length,
1289     ctx->stream.next_in, copy_size);
1290     /* Saved copy_size bytes */
1291     ctx->stream.avail_in -= copy_size;
1292 niq 476600 ctx->validation_buffer_length += copy_size;
1293 rpluem 475915 }
1294     if (ctx->stream.avail_in) {
1295 rpluem 426799 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1296     "Zlib: %d bytes of garbage at the end of "
1297     "compressed stream.", ctx->stream.avail_in);
1298 rpluem 475915 /*
1299     * There is nothing worth consuming for zlib left, because it is
1300     * either garbage data or the data has been copied to the
1301     * validation buffer (processing validation data is no business
1302     * for zlib). So set ctx->stream.avail_in to zero to indicate
1303     * this to the following while loop.
1304     */
1305     ctx->stream.avail_in = 0;
1306 rpluem 426799 }
1307     }
1308    
1309 ianh 103405 zRC = Z_OK;
1310    
1311     while (ctx->stream.avail_in != 0) {
1312     if (ctx->stream.avail_out == 0) {
1313 rpluem 426799
1314 ianh 103405 ctx->stream.next_out = ctx->buffer;
1315     len = c->bufferSize - ctx->stream.avail_out;
1316    
1317     ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1318 rpluem 426799 b = apr_bucket_heap_create((char *)ctx->buffer, len,
1319     NULL, f->c->bucket_alloc);
1320     APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
1321 ianh 103405 ctx->stream.avail_out = c->bufferSize;
1322 rpluem 426799 /* Send what we have right now to the next filter. */
1323     rv = ap_pass_brigade(f->next, ctx->bb);
1324     if (rv != APR_SUCCESS) {
1325     return rv;
1326     }
1327 ianh 103405 }
1328    
1329     zRC = inflate(&ctx->stream, Z_NO_FLUSH);
1330    
1331     if (zRC == Z_STREAM_END) {
1332 rpluem 426799 /*
1333     * We have inflated all data. Now try to capture the
1334     * validation bytes. We may not have them all available
1335     * right now, but capture what is there.
1336     */
1337     ctx->validation_buffer = apr_pcalloc(f->r->pool,
1338     VALIDATION_SIZE);
1339     if (ctx->stream.avail_in > VALIDATION_SIZE) {
1340     ctx->validation_buffer_length = VALIDATION_SIZE;
1341 rpluem 475920 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1342     "Zlib: %d bytes of garbage at the end of "
1343     "compressed stream.",
1344     ctx->stream.avail_in - VALIDATION_SIZE);
1345 rpluem 426799 } else if (ctx->stream.avail_in > 0) {
1346     ctx->validation_buffer_length = ctx->stream.avail_in;
1347     }
1348     if (ctx->validation_buffer_length)
1349     memcpy(ctx->validation_buffer, ctx->stream.next_in,
1350     ctx->validation_buffer_length);
1351 ianh 103405 break;
1352     }
1353    
1354     if (zRC != Z_OK) {
1355     return APR_EGENERAL;
1356     }
1357     }
1358    
1359 rpluem 426799 apr_bucket_delete(e);
1360 ianh 103405 }
1361    
1362 rpluem 426799 apr_brigade_cleanup(bb);
1363     return APR_SUCCESS;
1364 ianh 103405 }
1365    
1366 niq 416165 #define PROTO_FLAGS AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH
1367 jerenkrantz 94979 static void register_hooks(apr_pool_t *p)
1368     {
1369 jerenkrantz 95906 ap_register_output_filter(deflateFilterName, deflate_out_filter, NULL,
1370 jerenkrantz 94979 AP_FTYPE_CONTENT_SET);
1371 ianh 103405 ap_register_output_filter("INFLATE", inflate_out_filter, NULL,
1372     AP_FTYPE_RESOURCE-1);
1373 jerenkrantz 95906 ap_register_input_filter(deflateFilterName, deflate_in_filter, NULL,
1374 jerenkrantz 95345 AP_FTYPE_CONTENT_SET);
1375 jerenkrantz 94979 }
1376    
1377     static const command_rec deflate_filter_cmds[] = {
1378 nd 98149 AP_INIT_TAKE12("DeflateFilterNote", deflate_set_note, NULL, RSRC_CONF,
1379 jerenkrantz 94979 "Set a note to report on compression ratio"),
1380     AP_INIT_TAKE1("DeflateWindowSize", deflate_set_window_size, NULL,
1381     RSRC_CONF, "Set the Deflate window size (1-15)"),
1382 jerenkrantz 94987 AP_INIT_TAKE1("DeflateBufferSize", deflate_set_buffer_size, NULL, RSRC_CONF,
1383     "Set the Deflate Buffer Size"),
1384 jerenkrantz 94979 AP_INIT_TAKE1("DeflateMemLevel", deflate_set_memlevel, NULL, RSRC_CONF,
1385     "Set the Deflate Memory Level (1-9)"),
1386 ianh 98982 AP_INIT_TAKE1("DeflateCompressionLevel", deflate_set_compressionlevel, NULL, RSRC_CONF,
1387 ianh 98895 "Set the Deflate Compression Level (1-9)"),
1388 jerenkrantz 94979 {NULL}
1389     };
1390    
1391     module AP_MODULE_DECLARE_DATA deflate_module = {
1392     STANDARD20_MODULE_STUFF,
1393     NULL, /* dir config creater */
1394     NULL, /* dir merger --- default is to override */
1395     create_deflate_server_config, /* server config */
1396     NULL, /* merge server config */
1397     deflate_filter_cmds, /* command table */
1398     register_hooks /* register hooks */
1399     };

Properties

Name Value
svn:eol-style native

apache@apache.org
ViewVC Help
Powered by ViewVC 1.1.2