00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "httpd.h"
00030 #include "http_config.h"
00031 #include "http_log.h"
00032 #include "apr_strings.h"
00033 #include "apr_general.h"
00034 #include "util_filter.h"
00035 #include "apr_buckets.h"
00036 #include "http_request.h"
00037 #define APR_WANT_STRFUNC
00038 #include "apr_want.h"
00039
00040 #include "zlib.h"
00041
00042 #ifdef HAVE_ZUTIL_H
00043 #include "zutil.h"
00044 #else
00045
00046
00047
00048
00049
00050
00051 #ifdef OS2
00052 #define OS_CODE 0x06
00053 #endif
00054
00055 #ifdef WIN32
00056 #define OS_CODE 0x0b
00057 #endif
00058
00059 #if defined(VAXC) || defined(VMS)
00060 #define OS_CODE 0x02
00061 #endif
00062
00063 #ifdef AMIGA
00064 #define OS_CODE 0x01
00065 #endif
00066
00067 #if defined(ATARI) || defined(atarist)
00068 #define OS_CODE 0x05
00069 #endif
00070
00071 #if defined(MACOS) || defined(TARGET_OS_MAC)
00072 #define OS_CODE 0x07
00073 #endif
00074
00075 #ifdef __50SERIES
00076 #define OS_CODE 0x0F
00077 #endif
00078
00079 #ifdef TOPS20
00080 #define OS_CODE 0x0a
00081 #endif
00082
00083 #ifndef OS_CODE
00084 #define OS_CODE 0x03
00085 #endif
00086 #endif
00087
00088 static const char deflateFilterName[] = "DEFLATE";
00089 module AP_MODULE_DECLARE_DATA deflate_module;
00090
00091 typedef struct deflate_filter_config_t
00092 {
00093 int windowSize;
00094 int memlevel;
00095 int compressionlevel;
00096 apr_size_t bufferSize;
00097 char *note_ratio_name;
00098 char *note_input_name;
00099 char *note_output_name;
00100 } deflate_filter_config;
00101
00102
00103 #define DEFAULT_COMPRESSION Z_DEFAULT_COMPRESSION
00104 #define DEFAULT_WINDOWSIZE -15
00105 #define DEFAULT_MEMLEVEL 9
00106 #define DEFAULT_BUFFERSIZE 8096
00107
00108
00109
00110
00111 static void putLong(unsigned char *string, unsigned long x)
00112 {
00113 string[0] = (unsigned char)(x & 0xff);
00114 string[1] = (unsigned char)((x & 0xff00) >> 8);
00115 string[2] = (unsigned char)((x & 0xff0000) >> 16);
00116 string[3] = (unsigned char)((x & 0xff000000) >> 24);
00117 }
00118
00119
00120
00121 static unsigned long getLong(unsigned char *string)
00122 {
00123 return ((unsigned long)string[0])
00124 | (((unsigned long)string[1]) << 8)
00125 | (((unsigned long)string[2]) << 16)
00126 | (((unsigned long)string[3]) << 24);
00127 }
00128
00129 static void *create_deflate_server_config(apr_pool_t *p, server_rec *s)
00130 {
00131 deflate_filter_config *c = apr_pcalloc(p, sizeof *c);
00132
00133 c->memlevel = DEFAULT_MEMLEVEL;
00134 c->windowSize = DEFAULT_WINDOWSIZE;
00135 c->bufferSize = DEFAULT_BUFFERSIZE;
00136 c->compressionlevel = DEFAULT_COMPRESSION;
00137
00138 return c;
00139 }
00140
00141 static const char *deflate_set_window_size(cmd_parms *cmd, void *dummy,
00142 const char *arg)
00143 {
00144 deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
00145 &deflate_module);
00146 int i;
00147
00148 i = atoi(arg);
00149
00150 if (i < 1 || i > 15)
00151 return "DeflateWindowSize must be between 1 and 15";
00152
00153 c->windowSize = i * -1;
00154
00155 return NULL;
00156 }
00157
00158 static const char *deflate_set_buffer_size(cmd_parms *cmd, void *dummy,
00159 const char *arg)
00160 {
00161 deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
00162 &deflate_module);
00163 int n = atoi(arg);
00164
00165 if (n <= 0) {
00166 return "DeflateBufferSize should be positive";
00167 }
00168
00169 c->bufferSize = (apr_size_t)n;
00170
00171 return NULL;
00172 }
00173 static const char *deflate_set_note(cmd_parms *cmd, void *dummy,
00174 const char *arg1, const char *arg2)
00175 {
00176 deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
00177 &deflate_module);
00178
00179 if (arg2 == NULL) {
00180 c->note_ratio_name = apr_pstrdup(cmd->pool, arg1);
00181 }
00182 else if (!strcasecmp(arg1, "ratio")) {
00183 c->note_ratio_name = apr_pstrdup(cmd->pool, arg2);
00184 }
00185 else if (!strcasecmp(arg1, "input")) {
00186 c->note_input_name = apr_pstrdup(cmd->pool, arg2);
00187 }
00188 else if (!strcasecmp(arg1, "output")) {
00189 c->note_output_name = apr_pstrdup(cmd->pool, arg2);
00190 }
00191 else {
00192 return apr_psprintf(cmd->pool, "Unknown note type %s", arg1);
00193 }
00194
00195 return NULL;
00196 }
00197
00198 static const char *deflate_set_memlevel(cmd_parms *cmd, void *dummy,
00199 const char *arg)
00200 {
00201 deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
00202 &deflate_module);
00203 int i;
00204
00205 i = atoi(arg);
00206
00207 if (i < 1 || i > 9)
00208 return "DeflateMemLevel must be between 1 and 9";
00209
00210 c->memlevel = i;
00211
00212 return NULL;
00213 }
00214
00215 static const char *deflate_set_compressionlevel(cmd_parms *cmd, void *dummy,
00216 const char *arg)
00217 {
00218 deflate_filter_config *c = ap_get_module_config(cmd->server->module_config,
00219 &deflate_module);
00220 int i;
00221
00222 i = atoi(arg);
00223
00224 if (i < 1 || i > 9)
00225 return "Compression Level must be between 1 and 9";
00226
00227 c->compressionlevel = i;
00228
00229 return NULL;
00230 }
00231
00232
00233 static char deflate_magic[2] = { '\037', '\213' };
00234
00235 typedef struct deflate_ctx_t
00236 {
00237 z_stream stream;
00238 unsigned char *buffer;
00239 unsigned long crc;
00240 apr_bucket_brigade *bb, *proc_bb;
00241 } deflate_ctx;
00242
00243 static apr_status_t deflate_out_filter(ap_filter_t *f,
00244 apr_bucket_brigade *bb)
00245 {
00246 apr_bucket *e;
00247 request_rec *r = f->r;
00248 deflate_ctx *ctx = f->ctx;
00249 int zRC;
00250 deflate_filter_config *c = ap_get_module_config(r->server->module_config,
00251 &deflate_module);
00252
00253
00254
00255
00256
00257
00258
00259 if (!ctx) {
00260 char *buf, *token;
00261 const char *encoding, *accepts;
00262
00263
00264 if (r->main) {
00265 ap_remove_output_filter(f);
00266 return ap_pass_brigade(f->next, bb);
00267 }
00268
00269
00270
00271
00272 if (apr_table_get(r->subprocess_env, "no-gzip")) {
00273 ap_remove_output_filter(f);
00274 return ap_pass_brigade(f->next, bb);
00275 }
00276
00277
00278
00279
00280
00281 if (r->content_type == NULL
00282 || strncmp(r->content_type, "text/html", 9)) {
00283 const char *env_value = apr_table_get(r->subprocess_env,
00284 "gzip-only-text/html");
00285 if ( env_value && (strcmp(env_value,"1") == 0) ) {
00286 ap_remove_output_filter(f);
00287 return ap_pass_brigade(f->next, bb);
00288 }
00289 }
00290
00291
00292
00293
00294
00295 encoding = apr_table_get(r->headers_out, "Content-Encoding");
00296 if (encoding) {
00297 const char *err_enc;
00298
00299 err_enc = apr_table_get(r->err_headers_out, "Content-Encoding");
00300 if (err_enc) {
00301 encoding = apr_pstrcat(r->pool, encoding, ",", err_enc, NULL);
00302 }
00303 }
00304 else {
00305 encoding = apr_table_get(r->err_headers_out, "Content-Encoding");
00306 }
00307
00308 if (r->content_encoding) {
00309 encoding = encoding ? apr_pstrcat(r->pool, encoding, ",",
00310 r->content_encoding, NULL)
00311 : r->content_encoding;
00312 }
00313
00314 if (encoding) {
00315 const char *tmp = encoding;
00316
00317 token = ap_get_token(r->pool, &tmp, 0);
00318 while (token && *token) {
00319
00320 if (strcmp(token, "identity") && strcmp(token, "7bit") &&
00321 strcmp(token, "8bit") && strcmp(token, "binary")) {
00322
00323 ap_remove_output_filter(f);
00324 return ap_pass_brigade(f->next, bb);
00325 }
00326
00327
00328 if (*tmp) {
00329 ++tmp;
00330 }
00331 token = (*tmp) ? ap_get_token(r->pool, &tmp, 0) : NULL;
00332 }
00333 }
00334
00335
00336
00337
00338
00339 apr_table_setn(r->headers_out, "Vary", "Accept-Encoding");
00340
00341
00342 accepts = apr_table_get(r->headers_in, "Accept-Encoding");
00343 if (accepts == NULL) {
00344 ap_remove_output_filter(f);
00345 return ap_pass_brigade(f->next, bb);
00346 }
00347
00348 token = ap_get_token(r->pool, &accepts, 0);
00349 while (token && token[0] && strcasecmp(token, "gzip")) {
00350
00351 while (*accepts == ';') {
00352 ++accepts;
00353 token = ap_get_token(r->pool, &accepts, 1);
00354 }
00355
00356
00357 if (*accepts == ',') {
00358 ++accepts;
00359 }
00360 token = (*accepts) ? ap_get_token(r->pool, &accepts, 0) : NULL;
00361 }
00362
00363
00364 if (token == NULL || token[0] == '\0') {
00365 ap_remove_output_filter(f);
00366 return ap_pass_brigade(f->next, bb);
00367 }
00368
00369
00370 ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx));
00371 ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
00372 ctx->buffer = apr_palloc(r->pool, c->bufferSize);
00373
00374 zRC = deflateInit2(&ctx->stream, c->compressionlevel, Z_DEFLATED,
00375 c->windowSize, c->memlevel,
00376 Z_DEFAULT_STRATEGY);
00377
00378 if (zRC != Z_OK) {
00379 f->ctx = NULL;
00380 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
00381 "unable to init Zlib: "
00382 "deflateInit2 returned %d: URL %s",
00383 zRC, r->uri);
00384 return ap_pass_brigade(f->next, bb);
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398 buf = apr_psprintf(r->pool, "%c%c%c%c%c%c%c%c%c%c", deflate_magic[0],
00399 deflate_magic[1], Z_DEFLATED, 0 ,
00400 0, 0, 0, 0 ,
00401 0 , OS_CODE);
00402 e = apr_bucket_pool_create(buf, 10, r->pool, f->c->bucket_alloc);
00403 APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
00404
00405
00406 if (!encoding || !strcasecmp(encoding, "identity")) {
00407 apr_table_setn(r->headers_out, "Content-Encoding", "gzip");
00408 }
00409 else {
00410 apr_table_mergen(r->headers_out, "Content-Encoding", "gzip");
00411 }
00412 apr_table_unset(r->headers_out, "Content-Length");
00413
00414
00415 ctx->stream.next_out = ctx->buffer;
00416 ctx->stream.avail_out = c->bufferSize;
00417 }
00418
00419 while (!APR_BRIGADE_EMPTY(bb))
00420 {
00421 const char *data;
00422 apr_bucket *b;
00423 apr_size_t len;
00424 int done = 0;
00425
00426 e = APR_BRIGADE_FIRST(bb);
00427
00428 if (APR_BUCKET_IS_EOS(e)) {
00429 char *buf;
00430 unsigned int deflate_len;
00431
00432 ctx->stream.avail_in = 0;
00433 for (;;) {
00434 deflate_len = c->bufferSize - ctx->stream.avail_out;
00435
00436 if (deflate_len != 0) {
00437 b = apr_bucket_heap_create((char *)ctx->buffer,
00438 deflate_len, NULL,
00439 f->c->bucket_alloc);
00440 APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
00441 ctx->stream.next_out = ctx->buffer;
00442 ctx->stream.avail_out = c->bufferSize;
00443 }
00444
00445 if (done) {
00446 break;
00447 }
00448
00449 zRC = deflate(&ctx->stream, Z_FINISH);
00450
00451 if (deflate_len == 0 && zRC == Z_BUF_ERROR) {
00452 zRC = Z_OK;
00453 }
00454
00455 done = (ctx->stream.avail_out != 0 || zRC == Z_STREAM_END);
00456
00457 if (zRC != Z_OK && zRC != Z_STREAM_END) {
00458 break;
00459 }
00460 }
00461
00462 buf = apr_palloc(r->pool, 8);
00463 putLong((unsigned char *)&buf[0], ctx->crc);
00464 putLong((unsigned char *)&buf[4], ctx->stream.total_in);
00465
00466 b = apr_bucket_pool_create(buf, 8, r->pool, f->c->bucket_alloc);
00467 APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
00468 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
00469 "Zlib: Compressed %ld to %ld : URL %s",
00470 ctx->stream.total_in, ctx->stream.total_out, r->uri);
00471
00472
00473 if (c->note_input_name) {
00474 apr_table_setn(r->notes, c->note_input_name,
00475 (ctx->stream.total_in > 0)
00476 ? apr_off_t_toa(r->pool,
00477 ctx->stream.total_in)
00478 : "-");
00479 }
00480
00481 if (c->note_output_name) {
00482 apr_table_setn(r->notes, c->note_output_name,
00483 (ctx->stream.total_in > 0)
00484 ? apr_off_t_toa(r->pool,
00485 ctx->stream.total_out)
00486 : "-");
00487 }
00488
00489 if (c->note_ratio_name) {
00490 apr_table_setn(r->notes, c->note_ratio_name,
00491 (ctx->stream.total_in > 0)
00492 ? apr_itoa(r->pool,
00493 (int)(ctx->stream.total_out
00494 * 100
00495 / ctx->stream.total_in))
00496 : "-");
00497 }
00498
00499 deflateEnd(&ctx->stream);
00500
00501
00502 APR_BUCKET_REMOVE(e);
00503 APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
00504
00505
00506
00507
00508 return ap_pass_brigade(f->next, ctx->bb);
00509 }
00510
00511 if (APR_BUCKET_IS_FLUSH(e)) {
00512 apr_bucket *bkt;
00513 apr_status_t rv;
00514
00515 apr_bucket_delete(e);
00516
00517 if (ctx->stream.avail_in > 0) {
00518 zRC = deflate(&(ctx->stream), Z_SYNC_FLUSH);
00519 if (zRC != Z_OK) {
00520 return APR_EGENERAL;
00521 }
00522 }
00523
00524 ctx->stream.next_out = ctx->buffer;
00525 len = c->bufferSize - ctx->stream.avail_out;
00526
00527 b = apr_bucket_heap_create((char *)ctx->buffer, len,
00528 NULL, f->c->bucket_alloc);
00529 APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
00530 ctx->stream.avail_out = c->bufferSize;
00531
00532 bkt = apr_bucket_flush_create(f->c->bucket_alloc);
00533 APR_BRIGADE_INSERT_TAIL(ctx->bb, bkt);
00534 rv = ap_pass_brigade(f->next, ctx->bb);
00535 if (rv != APR_SUCCESS) {
00536 return rv;
00537 }
00538 continue;
00539 }
00540
00541
00542 apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
00543
00544
00545 ctx->crc = crc32(ctx->crc, (const Bytef *)data, len);
00546
00547
00548 ctx->stream.next_in = (unsigned char *)data;
00549
00550
00551 ctx->stream.avail_in = len;
00552
00553 while (ctx->stream.avail_in != 0) {
00554 if (ctx->stream.avail_out == 0) {
00555 apr_status_t rv;
00556
00557 ctx->stream.next_out = ctx->buffer;
00558 len = c->bufferSize - ctx->stream.avail_out;
00559
00560 b = apr_bucket_heap_create((char *)ctx->buffer, len,
00561 NULL, f->c->bucket_alloc);
00562 APR_BRIGADE_INSERT_TAIL(ctx->bb, b);
00563 ctx->stream.avail_out = c->bufferSize;
00564
00565 rv = ap_pass_brigade(f->next, ctx->bb);
00566 if (rv != APR_SUCCESS) {
00567 return rv;
00568 }
00569 }
00570
00571 zRC = deflate(&(ctx->stream), Z_NO_FLUSH);
00572
00573 if (zRC != Z_OK)
00574 return APR_EGENERAL;
00575 }
00576
00577 apr_bucket_delete(e);
00578 }
00579
00580 apr_brigade_cleanup(bb);
00581 return APR_SUCCESS;
00582 }
00583
00584
00585 static apr_status_t deflate_in_filter(ap_filter_t *f,
00586 apr_bucket_brigade *bb,
00587 ap_input_mode_t mode,
00588 apr_read_type_e block,
00589 apr_off_t readbytes)
00590 {
00591 apr_bucket *bkt;
00592 request_rec *r = f->r;
00593 deflate_ctx *ctx = f->ctx;
00594 int zRC;
00595 apr_status_t rv;
00596 deflate_filter_config *c;
00597
00598
00599 if (mode != AP_MODE_READBYTES) {
00600 return ap_get_brigade(f->next, bb, mode, block, readbytes);
00601 }
00602
00603 c = ap_get_module_config(r->server->module_config, &deflate_module);
00604
00605 if (!ctx) {
00606 int found = 0;
00607 char *token, deflate_hdr[10];
00608 const char *encoding;
00609 apr_size_t len;
00610
00611
00612 if (r->main) {
00613 ap_remove_input_filter(f);
00614 return ap_get_brigade(f->next, bb, mode, block, readbytes);
00615 }
00616
00617
00618
00619
00620 encoding = apr_table_get(r->headers_in, "Content-Encoding");
00621 if (encoding) {
00622 const char *tmp = encoding;
00623
00624 token = ap_get_token(r->pool, &tmp, 0);
00625 while (token && token[0]) {
00626 if (!strcasecmp(token, "gzip")) {
00627 found = 1;
00628 break;
00629 }
00630
00631 tmp++;
00632 token = ap_get_token(r->pool, &tmp, 0);
00633 }
00634 }
00635
00636 if (found == 0) {
00637 ap_remove_input_filter(f);
00638 return ap_get_brigade(f->next, bb, mode, block, readbytes);
00639 }
00640
00641 f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
00642 ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
00643 ctx->proc_bb = apr_brigade_create(r->pool, f->c->bucket_alloc);
00644 ctx->buffer = apr_palloc(r->pool, c->bufferSize);
00645
00646 rv = ap_get_brigade(f->next, ctx->bb, AP_MODE_READBYTES, block, 10);
00647 if (rv != APR_SUCCESS) {
00648 return rv;
00649 }
00650
00651 len = 10;
00652 rv = apr_brigade_flatten(ctx->bb, deflate_hdr, &len);
00653 if (rv != APR_SUCCESS) {
00654 return rv;
00655 }
00656
00657
00658 if (len != 10 ||
00659 deflate_hdr[0] != deflate_magic[0] ||
00660 deflate_hdr[1] != deflate_magic[1]) {
00661 return APR_EGENERAL;
00662 }
00663
00664
00665 if (deflate_hdr[3] != 0) {
00666 return APR_EGENERAL;
00667 }
00668
00669 zRC = inflateInit2(&ctx->stream, c->windowSize);
00670
00671 if (zRC != Z_OK) {
00672 f->ctx = NULL;
00673 inflateEnd(&ctx->stream);
00674 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
00675 "unable to init Zlib: "
00676 "inflateInit2 returned %d: URL %s",
00677 zRC, r->uri);
00678 ap_remove_input_filter(f);
00679 return ap_get_brigade(f->next, bb, mode, block, readbytes);
00680 }
00681
00682
00683 ctx->stream.next_out = ctx->buffer;
00684 ctx->stream.avail_out = c->bufferSize;
00685
00686 apr_brigade_cleanup(ctx->bb);
00687 }
00688
00689 if (APR_BRIGADE_EMPTY(ctx->proc_bb)) {
00690 rv = ap_get_brigade(f->next, ctx->bb, mode, block, readbytes);
00691
00692 if (rv != APR_SUCCESS) {
00693
00694 inflateEnd(&ctx->stream);
00695 return rv;
00696 }
00697
00698 APR_BRIGADE_FOREACH(bkt, ctx->bb) {
00699 const char *data;
00700 apr_size_t len;
00701
00702
00703 if (APR_BUCKET_IS_EOS(bkt)) {
00704 inflateEnd(&ctx->stream);
00705 return APR_EGENERAL;
00706 }
00707
00708 if (APR_BUCKET_IS_FLUSH(bkt)) {
00709 apr_bucket *tmp_heap;
00710 zRC = inflate(&(ctx->stream), Z_SYNC_FLUSH);
00711 if (zRC != Z_OK) {
00712 inflateEnd(&ctx->stream);
00713 return APR_EGENERAL;
00714 }
00715
00716 ctx->stream.next_out = ctx->buffer;
00717 len = c->bufferSize - ctx->stream.avail_out;
00718
00719 ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
00720 tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
00721 NULL, f->c->bucket_alloc);
00722 APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
00723 ctx->stream.avail_out = c->bufferSize;
00724
00725
00726 APR_BUCKET_REMOVE(bkt);
00727 APR_BRIGADE_CONCAT(bb, ctx->bb);
00728 break;
00729 }
00730
00731
00732 apr_bucket_read(bkt, &data, &len, APR_BLOCK_READ);
00733
00734
00735 ctx->stream.next_in = (unsigned char *)data;
00736 ctx->stream.avail_in = len;
00737
00738 zRC = Z_OK;
00739
00740 while (ctx->stream.avail_in != 0) {
00741 if (ctx->stream.avail_out == 0) {
00742 apr_bucket *tmp_heap;
00743 ctx->stream.next_out = ctx->buffer;
00744 len = c->bufferSize - ctx->stream.avail_out;
00745
00746 ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
00747 tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
00748 NULL, f->c->bucket_alloc);
00749 APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
00750 ctx->stream.avail_out = c->bufferSize;
00751 }
00752
00753 zRC = inflate(&ctx->stream, Z_NO_FLUSH);
00754
00755 if (zRC == Z_STREAM_END) {
00756 break;
00757 }
00758
00759 if (zRC != Z_OK) {
00760 inflateEnd(&ctx->stream);
00761 return APR_EGENERAL;
00762 }
00763 }
00764 if (zRC == Z_STREAM_END) {
00765 apr_bucket *tmp_heap, *eos;
00766
00767 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
00768 "Zlib: Inflated %ld to %ld : URL %s",
00769 ctx->stream.total_in, ctx->stream.total_out,
00770 r->uri);
00771
00772 len = c->bufferSize - ctx->stream.avail_out;
00773
00774 ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
00775 tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
00776 NULL, f->c->bucket_alloc);
00777 APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
00778 ctx->stream.avail_out = c->bufferSize;
00779
00780
00781 if (ctx->stream.avail_in >= 8) {
00782 unsigned long compCRC, compLen;
00783 compCRC = getLong(ctx->stream.next_in);
00784 if (ctx->crc != compCRC) {
00785 inflateEnd(&ctx->stream);
00786 return APR_EGENERAL;
00787 }
00788 ctx->stream.next_in += 4;
00789 compLen = getLong(ctx->stream.next_in);
00790 if (ctx->stream.total_out != compLen) {
00791 inflateEnd(&ctx->stream);
00792 return APR_EGENERAL;
00793 }
00794 }
00795 else {
00796
00797
00798 inflateEnd(&ctx->stream);
00799 return APR_EGENERAL;
00800 }
00801
00802 inflateEnd(&ctx->stream);
00803
00804 eos = apr_bucket_eos_create(f->c->bucket_alloc);
00805 APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, eos);
00806 break;
00807 }
00808
00809 }
00810 apr_brigade_cleanup(ctx->bb);
00811 }
00812
00813
00814
00815
00816 if (block == APR_BLOCK_READ &&
00817 APR_BRIGADE_EMPTY(ctx->proc_bb) &&
00818 ctx->stream.avail_out < c->bufferSize) {
00819 apr_bucket *tmp_heap;
00820 apr_size_t len;
00821 ctx->stream.next_out = ctx->buffer;
00822 len = c->bufferSize - ctx->stream.avail_out;
00823
00824 ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len);
00825 tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len,
00826 NULL, f->c->bucket_alloc);
00827 APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap);
00828 ctx->stream.avail_out = c->bufferSize;
00829 }
00830
00831 if (!APR_BRIGADE_EMPTY(ctx->proc_bb)) {
00832 apr_bucket_brigade *newbb;
00833
00834
00835 apr_brigade_partition(ctx->proc_bb, readbytes, &bkt);
00836
00837 newbb = apr_brigade_split(ctx->proc_bb, bkt);
00838 APR_BRIGADE_CONCAT(bb, ctx->proc_bb);
00839 APR_BRIGADE_CONCAT(ctx->proc_bb, newbb);
00840 }
00841
00842 return APR_SUCCESS;
00843 }
00844
00845 static void register_hooks(apr_pool_t *p)
00846 {
00847 ap_register_output_filter(deflateFilterName, deflate_out_filter, NULL,
00848 AP_FTYPE_CONTENT_SET);
00849 ap_register_input_filter(deflateFilterName, deflate_in_filter, NULL,
00850 AP_FTYPE_CONTENT_SET);
00851 }
00852
00853 static const command_rec deflate_filter_cmds[] = {
00854 AP_INIT_TAKE12("DeflateFilterNote", deflate_set_note, NULL, RSRC_CONF,
00855 "Set a note to report on compression ratio"),
00856 AP_INIT_TAKE1("DeflateWindowSize", deflate_set_window_size, NULL,
00857 RSRC_CONF, "Set the Deflate window size (1-15)"),
00858 AP_INIT_TAKE1("DeflateBufferSize", deflate_set_buffer_size, NULL, RSRC_CONF,
00859 "Set the Deflate Buffer Size"),
00860 AP_INIT_TAKE1("DeflateMemLevel", deflate_set_memlevel, NULL, RSRC_CONF,
00861 "Set the Deflate Memory Level (1-9)"),
00862 AP_INIT_TAKE1("DeflateCompressionLevel", deflate_set_compressionlevel, NULL, RSRC_CONF,
00863 "Set the Deflate Compression Level (1-9)"),
00864 {NULL}
00865 };
00866
00867 module AP_MODULE_DECLARE_DATA deflate_module = {
00868 STANDARD20_MODULE_STUFF,
00869 NULL,
00870 NULL,
00871 create_deflate_server_config,
00872 NULL,
00873 deflate_filter_cmds,
00874 register_hooks
00875 };