/[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 741865 - (hide annotations)
Sat Feb 7 09:25:28 2009 UTC (9 months, 2 weeks ago) by rpluem
File MIME type: text/plain
File size: 49774 byte(s)
* Only drop the last char (the '"') and not the last one of the etag itself.
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 niq 581198 /* PR 39727: we're screwing up our clients if we leave a strong ETag
385 niq 607219 * header while transforming content. Henrik Nordstrom suggests
386     * appending ";gzip".
387 niq 581198 *
388 niq 607219 * Pending a more thorough review of our Etag handling, let's just
389     * implement his suggestion. It fixes the bug, or at least turns it
390     * from a showstopper to an inefficiency. And it breaks nothing that
391     * wasn't already broken.
392 niq 581198 */
393 niq 607219 static void deflate_check_etag(request_rec *r, const char *transform)
394 niq 581198 {
395     const char *etag = apr_table_get(r->headers_out, "ETag");
396 lars 740149 if ((etag && (strlen(etag) > 2))) {
397     if (etag[0] == '"') {
398 rpluem 741865 etag = apr_pstrndup(r->pool, etag, strlen(etag) - 1);
399 lars 740149 apr_table_set(r->headers_out, "ETag",
400     apr_pstrcat(r->pool, etag, "-", transform, "\"", NULL));
401     }
402     }
403 niq 581198 }
404 jerenkrantz 94979 static apr_status_t deflate_out_filter(ap_filter_t *f,
405     apr_bucket_brigade *bb)
406     {
407     apr_bucket *e;
408     request_rec *r = f->r;
409     deflate_ctx *ctx = f->ctx;
410     int zRC;
411 rpluem 426795 deflate_filter_config *c;
412 jerenkrantz 94979
413 niq 104352 /* Do nothing if asked to filter nothing. */
414     if (APR_BRIGADE_EMPTY(bb)) {
415 rpluem 424759 return ap_pass_brigade(f->next, bb);
416 niq 104352 }
417    
418 rpluem 426795 c = ap_get_module_config(r->server->module_config,
419     &deflate_module);
420    
421 jerenkrantz 94979 /* If we don't have a context, we need to ensure that it is okay to send
422     * the deflated content. If we have a context, that means we've done
423     * this before and we liked it.
424     * This could be not so nice if we always fail. But, if we succeed,
425     * we're in better shape.
426     */
427     if (!ctx) {
428 jorton 105410 char *token;
429 niq 104352 const char *encoding;
430 jerenkrantz 94979
431     /* only work on main request/no subrequests */
432 colm 395079 if (r->main != NULL) {
433 jerenkrantz 94982 ap_remove_output_filter(f);
434 jerenkrantz 94979 return ap_pass_brigade(f->next, bb);
435     }
436    
437     /* some browsers might have problems, so set no-gzip
438     * (with browsermatch) for them
439     */
440     if (apr_table_get(r->subprocess_env, "no-gzip")) {
441 jerenkrantz 94982 ap_remove_output_filter(f);
442 jerenkrantz 94979 return ap_pass_brigade(f->next, bb);
443     }
444    
445 niq 563154 /* We can't operate on Content-Ranges */
446     if (apr_table_get(r->headers_out, "Content-Range") != NULL) {
447     ap_remove_output_filter(f);
448     return ap_pass_brigade(f->next, bb);
449     }
450    
451 jerenkrantz 94979 /* Some browsers might have problems with content types
452     * other than text/html, so set gzip-only-text/html
453     * (with browsermatch) for them
454     */
455 ianh 96318 if (r->content_type == NULL
456     || strncmp(r->content_type, "text/html", 9)) {
457     const char *env_value = apr_table_get(r->subprocess_env,
458     "gzip-only-text/html");
459 ianh 96588 if ( env_value && (strcmp(env_value,"1") == 0) ) {
460 ianh 96318 ap_remove_output_filter(f);
461 ianh 96590 return ap_pass_brigade(f->next, bb);
462 jim 332306 }
463 jerenkrantz 94979 }
464    
465 jerenkrantz 95339 /* Let's see what our current Content-Encoding is.
466 nd 101019 * If it's already encoded, don't compress again.
467     * (We could, but let's not.)
468 jerenkrantz 95339 */
469     encoding = apr_table_get(r->headers_out, "Content-Encoding");
470     if (encoding) {
471 nd 98948 const char *err_enc;
472    
473     err_enc = apr_table_get(r->err_headers_out, "Content-Encoding");
474     if (err_enc) {
475     encoding = apr_pstrcat(r->pool, encoding, ",", err_enc, NULL);
476     }
477     }
478     else {
479     encoding = apr_table_get(r->err_headers_out, "Content-Encoding");
480     }
481    
482 nd 99880 if (r->content_encoding) {
483     encoding = encoding ? apr_pstrcat(r->pool, encoding, ",",
484     r->content_encoding, NULL)
485     : r->content_encoding;
486     }
487    
488 nd 98948 if (encoding) {
489 jerenkrantz 95339 const char *tmp = encoding;
490    
491     token = ap_get_token(r->pool, &tmp, 0);
492 nd 101019 while (token && *token) {
493     /* stolen from mod_negotiation: */
494     if (strcmp(token, "identity") && strcmp(token, "7bit") &&
495     strcmp(token, "8bit") && strcmp(token, "binary")) {
496    
497 jerenkrantz 95339 ap_remove_output_filter(f);
498 ianh 103405 return ap_pass_brigade(f->next, bb);
499 jerenkrantz 95339 }
500 nd 101019
501 jerenkrantz 95339 /* Otherwise, skip token */
502 nd 101019 if (*tmp) {
503     ++tmp;
504     }
505     token = (*tmp) ? ap_get_token(r->pool, &tmp, 0) : NULL;
506 jerenkrantz 95339 }
507 ianh 95181 }
508    
509 jerenkrantz 97473 /* Even if we don't accept this request based on it not having
510     * the Accept-Encoding, we need to note that we were looking
511     * for this header and downstream proxies should be aware of that.
512     */
513 pquerna 161691 apr_table_mergen(r->headers_out, "Vary", "Accept-Encoding");
514 jerenkrantz 97473
515 ianh 103405 /* force-gzip will just force it out regardless if the browser
516     * can actually do anything with it.
517     */
518 jerenkrantz 103803 if (!apr_table_get(r->subprocess_env, "force-gzip")) {
519 ianh 103405 const char *accepts;
520     /* if they don't have the line, then they can't play */
521     accepts = apr_table_get(r->headers_in, "Accept-Encoding");
522     if (accepts == NULL) {
523     ap_remove_output_filter(f);
524     return ap_pass_brigade(f->next, bb);
525 nd 101015 }
526    
527 ianh 103405 token = ap_get_token(r->pool, &accepts, 0);
528     while (token && token[0] && strcasecmp(token, "gzip")) {
529     /* skip parameters, XXX: ;q=foo evaluation? */
530 jim 332306 while (*accepts == ';') {
531 ianh 103405 ++accepts;
532     token = ap_get_token(r->pool, &accepts, 1);
533     }
534    
535     /* retrieve next token */
536     if (*accepts == ',') {
537     ++accepts;
538     }
539     token = (*accepts) ? ap_get_token(r->pool, &accepts, 0) : NULL;
540 nd 101015 }
541 jerenkrantz 94979
542 ianh 103405 /* No acceptable token found. */
543     if (token == NULL || token[0] == '\0') {
544     ap_remove_output_filter(f);
545     return ap_pass_brigade(f->next, bb);
546     }
547 jerenkrantz 94979 }
548 ake 103910
549 jorton 109500 /* For a 304 or 204 response there is no entity included in
550     * the response and hence nothing to deflate. */
551     if (r->status == HTTP_NOT_MODIFIED || r->status == HTTP_NO_CONTENT) {
552 niq 104352 ap_remove_output_filter(f);
553 ake 103910 return ap_pass_brigade(f->next, bb);
554     }
555    
556 jerenkrantz 94979 /* We're cool with filtering this. */
557     ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx));
558     ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
559 jerenkrantz 94987 ctx->buffer = apr_palloc(r->pool, c->bufferSize);
560 rpluem 425109 ctx->libz_end_func = deflateEnd;
561 jerenkrantz 95339
562 ianh 98895 zRC = deflateInit2(&ctx->stream, c->compressionlevel, Z_DEFLATED,
563 jerenkrantz 94979 c->windowSize, c->memlevel,
564     Z_DEFAULT_STRATEGY);
565    
566     if (zRC != Z_OK) {
567 rpluem 426795 deflateEnd(&ctx->stream);
568 trawick 95151 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
569 jerenkrantz 94979 "unable to init Zlib: "
570     "deflateInit2 returned %d: URL %s",
571     zRC, r->uri);
572 rpluem 422739 /*
573     * Remove ourselves as it does not make sense to return:
574     * We are not able to init libz and pass data down the chain
575     * uncompressed.
576     */
577     ap_remove_output_filter(f);
578 jerenkrantz 94979 return ap_pass_brigade(f->next, bb);
579     }
580 rpluem 425109 /*
581     * Register a cleanup function to ensure that we cleanup the internal
582     * libz resources.
583     */
584     apr_pool_cleanup_register(r->pool, ctx, deflate_ctx_cleanup,
585     apr_pool_cleanup_null);
586 jerenkrantz 94979
587 jorton 105410 /* add immortal gzip header */
588     e = apr_bucket_immortal_create(gzip_header, sizeof gzip_header,
589     f->c->bucket_alloc);
590 jerenkrantz 94979 APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
591    
592 jerenkrantz 95339 /* If the entire Content-Encoding is "identity", we can replace it. */
593     if (!encoding || !strcasecmp(encoding, "identity")) {
594     apr_table_setn(r->headers_out, "Content-Encoding", "gzip");
595     }
596     else {
597     apr_table_mergen(r->headers_out, "Content-Encoding", "gzip");
598     }
599 rpluem 726791 /* Fix r->content_encoding if it was set before */
600     if (r->content_encoding) {
601     r->content_encoding = apr_table_get(r->headers_out,
602     "Content-Encoding");
603     }
604 jerenkrantz 94979 apr_table_unset(r->headers_out, "Content-Length");
605 rpluem 563230 apr_table_unset(r->headers_out, "Content-MD5");
606 niq 607219 deflate_check_etag(r, "gzip");
607 jerenkrantz 95521
608     /* initialize deflate output buffer */
609     ctx->stream.next_out = ctx->buffer;
610     ctx->stream.avail_out = c->bufferSize;
611 jerenkrantz 94979 }
612 jim 332306
613 jorton 103810 while (!APR_BRIGADE_EMPTY(bb))
614 jwoolley 101788 {
615 jerenkrantz 94979 const char *data;
616     apr_bucket *b;
617     apr_size_t len;
618    
619 jorton 103810 e = APR_BRIGADE_FIRST(bb);
620    
621 jerenkrantz 94979 if (APR_BUCKET_IS_EOS(e)) {
622 jwoolley 95413 char *buf;
623 jerenkrantz 94979
624     ctx->stream.avail_in = 0; /* should be zero already anyway */
625 rpluem 422731 /* flush the remaining data from the zlib buffers */
626 rpluem 426790 flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate, Z_FINISH,
627     NO_UPDATE_CRC);
628 jerenkrantz 94979
629 rpluem 426791 buf = apr_palloc(r->pool, VALIDATION_SIZE);
630 jwoolley 95413 putLong((unsigned char *)&buf[0], ctx->crc);
631     putLong((unsigned char *)&buf[4], ctx->stream.total_in);
632 jerenkrantz 94979
633 rpluem 426791 b = apr_bucket_pool_create(buf, VALIDATION_SIZE, r->pool,
634     f->c->bucket_alloc);
635 jerenkrantz 94979 APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
636 trawick 95151 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
637 jerenkrantz 94979 "Zlib: Compressed %ld to %ld : URL %s",
638     ctx->stream.total_in, ctx->stream.total_out, r->uri);
639    
640 nd 98154 /* leave notes for logging */
641     if (c->note_input_name) {
642     apr_table_setn(r->notes, c->note_input_name,
643     (ctx->stream.total_in > 0)
644     ? apr_off_t_toa(r->pool,
645     ctx->stream.total_in)
646     : "-");
647     }
648 jerenkrantz 94979
649 nd 98154 if (c->note_output_name) {
650     apr_table_setn(r->notes, c->note_output_name,
651     (ctx->stream.total_in > 0)
652     ? apr_off_t_toa(r->pool,
653     ctx->stream.total_out)
654     : "-");
655     }
656    
657     if (c->note_ratio_name) {
658     apr_table_setn(r->notes, c->note_ratio_name,
659     (ctx->stream.total_in > 0)
660     ? apr_itoa(r->pool,
661     (int)(ctx->stream.total_out
662     * 100
663     / ctx->stream.total_in))
664     : "-");
665     }
666    
667 jerenkrantz 94979 deflateEnd(&ctx->stream);
668 rpluem 425109 /* No need for cleanup any longer */
669     apr_pool_cleanup_kill(r->pool, ctx, deflate_ctx_cleanup);
670 jerenkrantz 94979
671     /* Remove EOS from the old list, and insert into the new. */
672     APR_BUCKET_REMOVE(e);
673     APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
674    
675     /* Okay, we've seen the EOS.
676     * Time to pass it along down the chain.
677     */
678     return ap_pass_brigade(f->next, ctx->bb);
679     }
680    
681     if (APR_BUCKET_IS_FLUSH(e)) {
682 jerenkrantz 100730 apr_status_t rv;
683 jorton 103810
684 rpluem 422731 /* flush the remaining data from the zlib buffers */
685 rpluem 423940 zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, deflate,
686 rpluem 426790 Z_SYNC_FLUSH, NO_UPDATE_CRC);
687 rpluem 422731 if (zRC != Z_OK) {
688     return APR_EGENERAL;
689 jerenkrantz 95341 }
690 jerenkrantz 94979
691 rpluem 422731 /* Remove flush bucket from old brigade anf insert into the new. */
692     APR_BUCKET_REMOVE(e);
693     APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
694 jerenkrantz 100730 rv = ap_pass_brigade(f->next, ctx->bb);
695     if (rv != APR_SUCCESS) {
696     return rv;
697     }
698 jerenkrantz 94979 continue;
699     }
700    
701 gregames 556028 if (APR_BUCKET_IS_METADATA(e)) {
702     /*
703     * Remove meta data bucket from old brigade and insert into the
704     * new.
705     */
706     APR_BUCKET_REMOVE(e);
707     APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
708     continue;
709 gregames 554011 }
710    
711 jerenkrantz 94979 /* read */
712     apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
713    
714     /* This crc32 function is from zlib. */
715     ctx->crc = crc32(ctx->crc, (const Bytef *)data, len);
716    
717     /* write */
718     ctx->stream.next_in = (unsigned char *)data; /* We just lost const-ness,
719     * but we'll just have to
720     * trust zlib */
721     ctx->stream.avail_in = len;
722    
723     while (ctx->stream.avail_in != 0) {
724     if (ctx->stream.avail_out == 0) {
725 jerenkrantz 100730 apr_status_t rv;
726    
727 jerenkrantz 94979 ctx->stream.next_out = ctx->buffer;
728 jerenkrantz 94987 len = c->bufferSize - ctx->stream.avail_out;
729 jerenkrantz 94979
730     b = apr_bucket_heap_create((char *)ctx->buffer, len,
731     NULL, f->c->bucket_alloc);
732     APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
733 jerenkrantz 94987 ctx->stream.avail_out = c->bufferSize;
734 jerenkrantz 100730 /* Send what we have right now to the next filter. */
735     rv = ap_pass_brigade(f->next, ctx->bb);
736     if (rv != APR_SUCCESS) {
737     return rv;
738     }
739 jerenkrantz 94979 }
740    
741     zRC = deflate(&(ctx->stream), Z_NO_FLUSH);
742    
743 rpluem 422736 if (zRC != Z_OK) {
744 jerenkrantz 94979 return APR_EGENERAL;
745 rpluem 422736 }
746 jerenkrantz 94979 }
747 jorton 103810
748     apr_bucket_delete(e);
749 jerenkrantz 94979 }
750    
751 jwoolley 97526 apr_brigade_cleanup(bb);
752 jerenkrantz 94979 return APR_SUCCESS;
753     }
754    
755 jerenkrantz 95345 /* This is the deflate input filter (inflates). */
756     static apr_status_t deflate_in_filter(ap_filter_t *f,
757     apr_bucket_brigade *bb,
758     ap_input_mode_t mode,
759     apr_read_type_e block,
760     apr_off_t readbytes)
761     {
762     apr_bucket *bkt;
763     request_rec *r = f->r;
764     deflate_ctx *ctx = f->ctx;
765     int zRC;
766     apr_status_t rv;
767     deflate_filter_config *c;
768    
769     /* just get out of the way of things we don't want. */
770     if (mode != AP_MODE_READBYTES) {
771     return ap_get_brigade(f->next, bb, mode, block, readbytes);
772     }
773    
774     c = ap_get_module_config(r->server->module_config, &deflate_module);
775    
776     if (!ctx) {
777 niq 562507 char deflate_hdr[10];
778 jerenkrantz 95345 apr_size_t len;
779    
780     /* only work on main request/no subrequests */
781 pquerna 105403 if (!ap_is_initial_req(r)) {
782 jerenkrantz 95345 ap_remove_input_filter(f);
783     return ap_get_brigade(f->next, bb, mode, block, readbytes);
784     }
785    
786 niq 563154 /* We can't operate on Content-Ranges */
787     if (apr_table_get(r->headers_in, "Content-Range") != NULL) {
788     ap_remove_input_filter(f);
789     return ap_get_brigade(f->next, bb, mode, block, readbytes);
790     }
791    
792 niq 560689 /* Check whether request body is gzipped.
793     *
794     * If it is, we're transforming the contents, invalidating
795     * some request headers including Content-Encoding.
796     *
797     * If not, we just remove ourself.
798 jerenkrantz 95345 */
799 niq 563803 if (check_gzip(r, r->headers_in, NULL) == 0) {
800 jerenkrantz 95345 ap_remove_input_filter(f);
801     return ap_get_brigade(f->next, bb, mode, block, readbytes);
802     }
803    
804     f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
805     ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
806     ctx->proc_bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
807     ctx->buffer = apr_palloc(r->pool, c->bufferSize);
808    
809     rv = ap_get_brigade(f->next, ctx->bb, AP_MODE_READBYTES, block, 10);
810     if (rv != APR_SUCCESS) {
811     return rv;
812     }
813 jerenkrantz 98689
814 niq 563133 apr_table_unset(r->headers_in, "Content-Length");
815     apr_table_unset(r->headers_in, "Content-MD5");
816    
817 jim 332306 len = 10;
818     rv = apr_brigade_flatten(ctx->bb, deflate_hdr, &len);
819 jerenkrantz 95345 if (rv != APR_SUCCESS) {
820     return rv;
821     }
822    
823     /* We didn't get the magic bytes. */
824     if (len != 10 ||
825     deflate_hdr[0] != deflate_magic[0] ||
826     deflate_hdr[1] != deflate_magic[1]) {
827     return APR_EGENERAL;
828     }
829    
830     /* We can't handle flags for now. */
831     if (deflate_hdr[3] != 0) {
832     return APR_EGENERAL;
833     }
834    
835     zRC = inflateInit2(&ctx->stream, c->windowSize);
836    
837     if (zRC != Z_OK) {
838     f->ctx = NULL;
839 jerenkrantz 98689 inflateEnd(&ctx->stream);
840 jerenkrantz 95345 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
841     "unable to init Zlib: "
842     "inflateInit2 returned %d: URL %s",
843     zRC, r->uri);
844     ap_remove_input_filter(f);
845     return ap_get_brigade(f->next, bb, mode, block, readbytes);
846     }
847    
848     /* initialize deflate output buffer */
849     ctx->stream.next_out = ctx->buffer;
850     ctx->stream.avail_out = c->bufferSize;
851    
852     apr_brigade_cleanup(ctx->bb);
853     }
854    
855     if (APR_BRIGADE_EMPTY(ctx->proc_bb)) {
856     rv = ap_get_brigade(f->next, ctx->bb, mode, block, readbytes);
857    
858     if (rv != APR_SUCCESS) {
859 jerenkrantz 98689 /* What about APR_EAGAIN errors? */
860     inflateEnd(&ctx->stream);
861 jerenkrantz 95345 return rv;
862     }
863    
864 jwoolley 101788 for (bkt = APR_BRIGADE_FIRST(ctx->bb);
865     bkt != APR_BRIGADE_SENTINEL(ctx->bb);
866     bkt = APR_BUCKET_NEXT(bkt))
867     {
868 jerenkrantz 95345 const char *data;
869     apr_size_t len;
870    
871     /* If we actually see the EOS, that means we screwed up! */
872     if (APR_BUCKET_IS_EOS(bkt)) {
873 jerenkrantz 98689 inflateEnd(&ctx->stream);
874 jerenkrantz 95345 return APR_EGENERAL;
875     }
876    
877     if (APR_BUCKET_IS_FLUSH(bkt)) {
878     apr_bucket *tmp_heap;
879     zRC = inflate(&(ctx->stream), Z_SYNC_FLUSH);
880     if (zRC != Z_OK) {
881 jerenkrantz 98689 inflateEnd(&ctx->stream);
882 jerenkrantz 95345 return APR_EGENERAL;
883     }
884    
885     ctx->stream.next_out = ctx->buffer;
886     len = c->bufferSize - ctx->stream.avail_out;
887    
888     ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
889     tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
890     NULL, f->c->bucket_alloc);
891     APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
892     ctx->stream.avail_out = c->bufferSize;
893    
894     /* Move everything to the returning brigade. */
895     APR_BUCKET_REMOVE(bkt);
896     APR_BRIGADE_CONCAT(bb, ctx->bb);
897     break;
898     }
899    
900     /* read */
901     apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ);
902    
903     /* pass through zlib inflate. */
904     ctx->stream.next_in = (unsigned char *)data;
905     ctx->stream.avail_in = len;
906    
907 jerenkrantz 95359 zRC = Z_OK;
908    
909 jerenkrantz 95345 while (ctx->stream.avail_in != 0) {
910     if (ctx->stream.avail_out == 0) {
911     apr_bucket *tmp_heap;
912     ctx->stream.next_out = ctx->buffer;
913     len = c->bufferSize - ctx->stream.avail_out;
914    
915     ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
916     tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
917     NULL, f->c->bucket_alloc);
918     APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
919     ctx->stream.avail_out = c->bufferSize;
920     }
921    
922     zRC = inflate(&ctx->stream, Z_NO_FLUSH);
923    
924     if (zRC == Z_STREAM_END) {
925     break;
926     }
927    
928     if (zRC != Z_OK) {
929 jerenkrantz 98689 inflateEnd(&ctx->stream);
930 jerenkrantz 95345 return APR_EGENERAL;
931     }
932     }
933     if (zRC == Z_STREAM_END) {
934     apr_bucket *tmp_heap, *eos;
935    
936     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
937     "Zlib: Inflated %ld to %ld : URL %s",
938     ctx->stream.total_in, ctx->stream.total_out,
939     r->uri);
940    
941     len = c->bufferSize - ctx->stream.avail_out;
942    
943     ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
944     tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
945     NULL, f->c->bucket_alloc);
946     APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
947     ctx->stream.avail_out = c->bufferSize;
948    
949     /* Is the remaining 8 bytes already in the avail stream? */
950     if (ctx->stream.avail_in >= 8) {
951     unsigned long compCRC, compLen;
952     compCRC = getLong(ctx->stream.next_in);
953     if (ctx->crc != compCRC) {
954 jerenkrantz 98689 inflateEnd(&ctx->stream);
955 jerenkrantz 95345 return APR_EGENERAL;
956     }
957     ctx->stream.next_in += 4;
958     compLen = getLong(ctx->stream.next_in);
959     if (ctx->stream.total_out != compLen) {
960 jerenkrantz 98689 inflateEnd(&ctx->stream);
961 jerenkrantz 95345 return APR_EGENERAL;
962     }
963     }
964     else {
965     /* FIXME: We need to grab the 8 verification bytes
966     * from the wire! */
967 jerenkrantz 98689 inflateEnd(&ctx->stream);
968 jerenkrantz 95345 return APR_EGENERAL;
969     }
970    
971     inflateEnd(&ctx->stream);
972 jerenkrantz 98689
973 jerenkrantz 95345 eos = apr_bucket_eos_create(f->c->bucket_alloc);
974 jim 332306 APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, eos);
975 jerenkrantz 95345 break;
976     }
977 jerenkrantz 95666
978 jerenkrantz 95345 }
979 jerenkrantz 95521 apr_brigade_cleanup(ctx->bb);
980 jerenkrantz 95345 }
981    
982 jerenkrantz 95666 /* If we are about to return nothing for a 'blocking' read and we have
983     * some data in our zlib buffer, flush it out so we can return something.
984     */
985     if (block == APR_BLOCK_READ &&
986     APR_BRIGADE_EMPTY(ctx->proc_bb) &&
987     ctx->stream.avail_out < c->bufferSize) {
988     apr_bucket *tmp_heap;
989     apr_size_t len;
990     ctx->stream.next_out = ctx->buffer;
991     len = c->bufferSize - ctx->stream.avail_out;
992    
993     ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
994     tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
995     NULL, f->c->bucket_alloc);
996     APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
997     ctx->stream.avail_out = c->bufferSize;
998     }
999    
1000 jerenkrantz 95345 if (!APR_BRIGADE_EMPTY(ctx->proc_bb)) {
1001     apr_bucket_brigade *newbb;
1002    
1003     /* May return APR_INCOMPLETE which is fine by us. */
1004     apr_brigade_partition(ctx->proc_bb, readbytes, &bkt);
1005    
1006     newbb = apr_brigade_split(ctx->proc_bb, bkt);
1007     APR_BRIGADE_CONCAT(bb, ctx->proc_bb);
1008     APR_BRIGADE_CONCAT(ctx->proc_bb, newbb);
1009     }
1010    
1011     return APR_SUCCESS;
1012     }
1013    
1014 ianh 103405
1015     /* Filter to inflate for a content-transforming proxy. */
1016     static apr_status_t inflate_out_filter(ap_filter_t *f,
1017     apr_bucket_brigade *bb)
1018     {
1019 nd 104166 int zlib_method;
1020     int zlib_flags;
1021 rpluem 426799 apr_bucket *e;
1022 ianh 103405 request_rec *r = f->r;
1023     deflate_ctx *ctx = f->ctx;
1024     int zRC;
1025     apr_status_t rv;
1026     deflate_filter_config *c;
1027    
1028 niq 104352 /* Do nothing if asked to filter nothing. */
1029     if (APR_BRIGADE_EMPTY(bb)) {
1030 rpluem 424759 return ap_pass_brigade(f->next, bb);
1031 niq 104352 }
1032    
1033 ianh 103405 c = ap_get_module_config(r->server->module_config, &deflate_module);
1034    
1035     if (!ctx) {
1036    
1037     /* only work on main request/no subrequests */
1038 pquerna 105403 if (!ap_is_initial_req(r)) {
1039 ianh 103405 ap_remove_output_filter(f);
1040     return ap_pass_brigade(f->next, bb);
1041     }
1042    
1043 niq 563154 /* We can't operate on Content-Ranges */
1044     if (apr_table_get(r->headers_out, "Content-Range") != NULL) {
1045     ap_remove_output_filter(f);
1046     return ap_pass_brigade(f->next, bb);
1047     }
1048    
1049 rpluem 475922 /*
1050     * Let's see what our current Content-Encoding is.
1051 niq 562507 * Only inflate if gzipped.
1052 ianh 103405 */
1053 niq 563803 if (check_gzip(r, r->headers_out, r->err_headers_out) == 0) {
1054 ianh 103405 ap_remove_output_filter(f);
1055     return ap_pass_brigade(f->next, bb);
1056     }
1057    
1058 niq 104352 /* No need to inflate HEAD or 204/304 */
1059     if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(bb))) {
1060     ap_remove_output_filter(f);
1061     return ap_pass_brigade(f->next, bb);
1062     }
1063    
1064 ianh 103405 f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
1065 rpluem 426799 ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
1066 ianh 103405 ctx->buffer = apr_palloc(r->pool, c->bufferSize);
1067 rpluem 426799 ctx->libz_end_func = inflateEnd;
1068     ctx->validation_buffer = NULL;
1069     ctx->validation_buffer_length = 0;
1070 ianh 103405
1071     zRC = inflateInit2(&ctx->stream, c->windowSize);
1072    
1073     if (zRC != Z_OK) {
1074     f->ctx = NULL;
1075     inflateEnd(&ctx->stream);
1076     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1077     "unable to init Zlib: "
1078     "inflateInit2 returned %d: URL %s",
1079     zRC, r->uri);
1080 rpluem 426799 /*
1081     * Remove ourselves as it does not make sense to return:
1082     * We are not able to init libz and pass data down the chain
1083     * compressed.
1084     */
1085 ianh 103405 ap_remove_output_filter(f);
1086     return ap_pass_brigade(f->next, bb);
1087     }
1088    
1089 rpluem 426799 /*
1090     * Register a cleanup function to ensure that we cleanup the internal
1091     * libz resources.
1092     */
1093     apr_pool_cleanup_register(r->pool, ctx, deflate_ctx_cleanup,
1094     apr_pool_cleanup_null);
1095    
1096 rpluem 563229 /* these are unlikely to be set anyway, but ... */
1097 rpluem 426799 apr_table_unset(r->headers_out, "Content-Length");
1098 rpluem 563229 apr_table_unset(r->headers_out, "Content-MD5");
1099 niq 607219 deflate_check_etag(r, "gunzip");
1100 rpluem 426799
1101     /* initialize inflate output buffer */
1102 ianh 103405 ctx->stream.next_out = ctx->buffer;
1103     ctx->stream.avail_out = c->bufferSize;
1104    
1105 niq 580598 ctx->inflate_init = 0;
1106 ianh 103405 }
1107    
1108 rpluem 426799 while (!APR_BRIGADE_EMPTY(bb))
1109 ianh 103405 {
1110     const char *data;
1111 rpluem 426799 apr_bucket *b;
1112 ianh 103405 apr_size_t len;
1113    
1114 rpluem 426799 e = APR_BRIGADE_FIRST(bb);
1115    
1116     if (APR_BUCKET_IS_EOS(e)) {
1117 rpluem 475406 /*
1118     * We are really done now. Ensure that we never return here, even
1119     * if a second EOS bucket falls down the chain. Thus remove
1120     * ourselves.
1121     */
1122     ap_remove_output_filter(f);
1123 rpluem 475922 /* should be zero already anyway */
1124     ctx->stream.avail_in = 0;
1125 rpluem 426799 /*
1126     * Flush the remaining data from the zlib buffers. It is correct
1127     * to use Z_SYNC_FLUSH in this case and not Z_FINISH as in the
1128     * deflate case. In the inflate case Z_FINISH requires to have a
1129     * large enough output buffer to put ALL data in otherwise it
1130     * fails, whereas in the deflate case you can empty a filled output
1131     * buffer and call it again until no more output can be created.
1132     */
1133     flush_libz_buffer(ctx, c, f->c->bucket_alloc, inflate, Z_SYNC_FLUSH,
1134     UPDATE_CRC);
1135     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1136     "Zlib: Inflated %ld to %ld : URL %s",
1137     ctx->stream.total_in, ctx->stream.total_out, r->uri);
1138    
1139     if (ctx->validation_buffer_length == VALIDATION_SIZE) {
1140     unsigned long compCRC, compLen;
1141     compCRC = getLong(ctx->validation_buffer);
1142     if (ctx->crc != compCRC) {
1143     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1144     "Zlib: Checksum of inflated stream invalid");
1145     return APR_EGENERAL;
1146     }
1147     ctx->validation_buffer += VALIDATION_SIZE / 2;
1148     compLen = getLong(ctx->validation_buffer);
1149     if (ctx->stream.total_out != compLen) {
1150     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1151     "Zlib: Length of inflated stream invalid");
1152     return APR_EGENERAL;
1153     }
1154     }
1155     else {
1156     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1157     "Zlib: Validation bytes not present");
1158     return APR_EGENERAL;
1159     }
1160    
1161 ianh 103405 inflateEnd(&ctx->stream);
1162 rpluem 426799 /* No need for cleanup any longer */
1163     apr_pool_cleanup_kill(r->pool, ctx, deflate_ctx_cleanup);
1164    
1165     /* Remove EOS from the old list, and insert into the new. */
1166     APR_BUCKET_REMOVE(e);
1167     APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
1168    
1169     /*
1170     * Okay, we've seen the EOS.
1171     * Time to pass it along down the chain.
1172     */
1173     return ap_pass_brigade(f->next, ctx->bb);
1174 ianh 103405 }
1175    
1176 rpluem 426799 if (APR_BUCKET_IS_FLUSH(e)) {
1177     apr_status_t rv;
1178    
1179     /* flush the remaining data from the zlib buffers */
1180     zRC = flush_libz_buffer(ctx, c, f->c->bucket_alloc, inflate,
1181     Z_SYNC_FLUSH, UPDATE_CRC);
1182     if (zRC != Z_OK) {
1183     return APR_EGENERAL;
1184     }
1185    
1186     /* Remove flush bucket from old brigade anf insert into the new. */
1187     APR_BUCKET_REMOVE(e);
1188     APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
1189     rv = ap_pass_brigade(f->next, ctx->bb);
1190     if (rv != APR_SUCCESS) {
1191     return rv;
1192     }
1193 niq 416165 continue;
1194 ianh 103405 }
1195    
1196 gregames 556028 if (APR_BUCKET_IS_METADATA(e)) {
1197     /*
1198     * Remove meta data bucket from old brigade and insert into the
1199     * new.
1200     */
1201     APR_BUCKET_REMOVE(e);
1202     APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
1203     continue;
1204     }
1205    
1206 ianh 103405 /* read */
1207 rpluem 426799 apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
1208 ianh 103405
1209     /* first bucket contains zlib header */
1210 niq 580598 if (!ctx->inflate_init++) {
1211 nd 104166 if (len < 10) {
1212 ianh 103405 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1213     "Insufficient data for inflate");
1214 nd 104166 return APR_EGENERAL;
1215 jim 332306 }
1216 ianh 103405 else {
1217 nd 104166 zlib_method = data[2];
1218     zlib_flags = data[3];
1219     if (zlib_method != Z_DEFLATED) {
1220 nd 104155 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1221 nd 104166 "inflate: data not deflated!");
1222     ap_remove_output_filter(f);
1223     return ap_pass_brigade(f->next, bb);
1224 niq 104034 }
1225 ianh 103405 if (data[0] != deflate_magic[0] ||
1226 niq 104034 data[1] != deflate_magic[1] ||
1227 nd 104166 (zlib_flags & RESERVED) != 0) {
1228 ianh 103405 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1229 nd 104166 "inflate: bad header");
1230 ianh 103405 return APR_EGENERAL ;
1231     }
1232     data += 10 ;
1233     len -= 10 ;
1234     }
1235 nd 104166 if (zlib_flags & EXTRA_FIELD) {
1236     unsigned int bytes = (unsigned int)(data[0]);
1237     bytes += ((unsigned int)(data[1])) << 8;
1238     bytes += 2;
1239     if (len < bytes) {
1240 niq 104034 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1241 nd 104166 "inflate: extra field too big (not "
1242     "supported)");
1243     return APR_EGENERAL;
1244 niq 104034 }
1245 nd 104166 data += bytes;
1246     len -= bytes;
1247 niq 104034 }
1248 nd 104166 if (zlib_flags & ORIG_NAME) {
1249     while (len-- && *data++);
1250 niq 104034 }
1251 nd 104166 if (zlib_flags & COMMENT) {
1252     while (len-- && *data++);
1253 niq 104034 }
1254 nd 104166 if (zlib_flags & HEAD_CRC) {
1255     len -= 2;
1256     data += 2;
1257 niq 104034 }
1258 ianh 103405 }
1259    
1260     /* pass through zlib inflate. */
1261     ctx->stream.next_in = (unsigned char *)data;
1262     ctx->stream.avail_in = len;
1263    
1264 rpluem 426799 if (ctx->validation_buffer) {
1265     if (ctx->validation_buffer_length < VALIDATION_SIZE) {
1266     apr_size_t copy_size;
1267    
1268     copy_size = VALIDATION_SIZE - ctx->validation_buffer_length;
1269     if (copy_size > ctx->stream.avail_in)
1270     copy_size = ctx->stream.avail_in;
1271 rpluem 475915 memcpy(ctx->validation_buffer + ctx->validation_buffer_length,
1272     ctx->stream.next_in, copy_size);
1273     /* Saved copy_size bytes */
1274     ctx->stream.avail_in -= copy_size;
1275 niq 476600 ctx->validation_buffer_length += copy_size;
1276 rpluem 475915 }
1277     if (ctx->stream.avail_in) {
1278 rpluem 426799 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1279     "Zlib: %d bytes of garbage at the end of "
1280     "compressed stream.", ctx->stream.avail_in);
1281 rpluem 475915 /*
1282     * There is nothing worth consuming for zlib left, because it is
1283     * either garbage data or the data has been copied to the
1284     * validation buffer (processing validation data is no business
1285     * for zlib). So set ctx->stream.avail_in to zero to indicate
1286     * this to the following while loop.
1287     */
1288     ctx->stream.avail_in = 0;
1289 rpluem 426799 }
1290     }
1291    
1292 ianh 103405 zRC = Z_OK;
1293    
1294     while (ctx->stream.avail_in != 0) {
1295     if (ctx->stream.avail_out == 0) {
1296 rpluem 426799
1297 ianh 103405 ctx->stream.next_out = ctx->buffer;
1298     len = c->bufferSize - ctx->stream.avail_out;
1299    
1300     ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
1301 rpluem 426799 b = apr_bucket_heap_create((char *)ctx->buffer, len,
1302     NULL, f->c->bucket_alloc);
1303     APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
1304 ianh 103405 ctx->stream.avail_out = c->bufferSize;
1305 rpluem 426799 /* Send what we have right now to the next filter. */
1306     rv = ap_pass_brigade(f->next, ctx->bb);
1307     if (rv != APR_SUCCESS) {
1308     return rv;
1309     }
1310 ianh 103405 }
1311    
1312     zRC = inflate(&ctx->stream, Z_NO_FLUSH);
1313    
1314     if (zRC == Z_STREAM_END) {
1315 rpluem 426799 /*
1316     * We have inflated all data. Now try to capture the
1317     * validation bytes. We may not have them all available
1318     * right now, but capture what is there.
1319     */
1320     ctx->validation_buffer = apr_pcalloc(f->r->pool,
1321     VALIDATION_SIZE);
1322     if (ctx->stream.avail_in > VALIDATION_SIZE) {
1323     ctx->validation_buffer_length = VALIDATION_SIZE;
1324 rpluem 475920 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1325     "Zlib: %d bytes of garbage at the end of "
1326     "compressed stream.",
1327     ctx->stream.avail_in - VALIDATION_SIZE);
1328 rpluem 426799 } else if (ctx->stream.avail_in > 0) {
1329     ctx->validation_buffer_length = ctx->stream.avail_in;
1330     }
1331     if (ctx->validation_buffer_length)
1332     memcpy(ctx->validation_buffer, ctx->stream.next_in,
1333     ctx->validation_buffer_length);
1334 ianh 103405 break;
1335     }
1336    
1337     if (zRC != Z_OK) {
1338     return APR_EGENERAL;
1339     }
1340     }
1341    
1342 rpluem 426799 apr_bucket_delete(e);
1343 ianh 103405 }
1344    
1345 rpluem 426799 apr_brigade_cleanup(bb);
1346     return APR_SUCCESS;
1347 ianh 103405 }
1348    
1349 niq 416165 #define PROTO_FLAGS AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH
1350 jerenkrantz 94979 static void register_hooks(apr_pool_t *p)
1351     {
1352 jerenkrantz 95906 ap_register_output_filter(deflateFilterName, deflate_out_filter, NULL,
1353 jerenkrantz 94979 AP_FTYPE_CONTENT_SET);
1354 ianh 103405 ap_register_output_filter("INFLATE", inflate_out_filter, NULL,
1355     AP_FTYPE_RESOURCE-1);
1356 jerenkrantz 95906 ap_register_input_filter(deflateFilterName, deflate_in_filter, NULL,
1357 jerenkrantz 95345 AP_FTYPE_CONTENT_SET);
1358 jerenkrantz 94979 }
1359    
1360     static const command_rec deflate_filter_cmds[] = {
1361 nd 98149 AP_INIT_TAKE12("DeflateFilterNote", deflate_set_note, NULL, RSRC_CONF,
1362 jerenkrantz 94979 "Set a note to report on compression ratio"),
1363     AP_INIT_TAKE1("DeflateWindowSize", deflate_set_window_size, NULL,
1364     RSRC_CONF, "Set the Deflate window size (1-15)"),
1365 jerenkrantz 94987 AP_INIT_TAKE1("DeflateBufferSize", deflate_set_buffer_size, NULL, RSRC_CONF,
1366     "Set the Deflate Buffer Size"),
1367 jerenkrantz 94979 AP_INIT_TAKE1("DeflateMemLevel", deflate_set_memlevel, NULL, RSRC_CONF,
1368     "Set the Deflate Memory Level (1-9)"),
1369 ianh 98982 AP_INIT_TAKE1("DeflateCompressionLevel", deflate_set_compressionlevel, NULL, RSRC_CONF,
1370 ianh 98895 "Set the Deflate Compression Level (1-9)"),
1371 jerenkrantz 94979 {NULL}
1372     };
1373    
1374     module AP_MODULE_DECLARE_DATA deflate_module = {
1375     STANDARD20_MODULE_STUFF,
1376     NULL, /* dir config creater */
1377     NULL, /* dir merger --- default is to override */
1378     create_deflate_server_config, /* server config */
1379     NULL, /* merge server config */
1380     deflate_filter_cmds, /* command table */
1381     register_hooks /* register hooks */
1382     };

Properties

Name Value
svn:eol-style native

apache@apache.org
ViewVC Help
Powered by ViewVC 1.1.2