| 37 |
#include "httpd.h" |
#include "httpd.h" |
| 38 |
#include "http_config.h" |
#include "http_config.h" |
| 39 |
#include "http_log.h" |
#include "http_log.h" |
| 40 |
|
#include "http_core.h" |
| 41 |
#include "apr_lib.h" |
#include "apr_lib.h" |
| 42 |
#include "apr_strings.h" |
#include "apr_strings.h" |
| 43 |
#include "apr_general.h" |
#include "apr_general.h" |
| 59 |
#define AP_DEFLATE_ETAG_NOCHANGE 1 |
#define AP_DEFLATE_ETAG_NOCHANGE 1 |
| 60 |
#define AP_DEFLATE_ETAG_REMOVE 2 |
#define AP_DEFLATE_ETAG_REMOVE 2 |
| 61 |
|
|
| 62 |
|
#define AP_INFLATE_RATIO_LIMIT 200 |
| 63 |
|
#define AP_INFLATE_RATIO_BURST 3 |
| 64 |
|
|
| 65 |
typedef struct deflate_filter_config_t |
typedef struct deflate_filter_config_t |
| 66 |
{ |
{ |
| 67 |
int windowSize; |
int windowSize; |
| 74 |
int etag_opt; |
int etag_opt; |
| 75 |
} deflate_filter_config; |
} deflate_filter_config; |
| 76 |
|
|
| 77 |
|
typedef struct deflate_dirconf_t { |
| 78 |
|
apr_off_t inflate_limit; |
| 79 |
|
int ratio_limit, |
| 80 |
|
ratio_burst; |
| 81 |
|
} deflate_dirconf_t; |
| 82 |
|
|
| 83 |
/* RFC 1952 Section 2.3 defines the gzip header: |
/* RFC 1952 Section 2.3 defines the gzip header: |
| 84 |
* |
* |
| 85 |
* +---+---+---+---+---+---+---+---+---+---+ |
* +---+---+---+---+---+---+---+---+---+---+ |
| 222 |
return c; |
return c; |
| 223 |
} |
} |
| 224 |
|
|
| 225 |
|
static void *create_deflate_dirconf(apr_pool_t *p, char *dummy) |
| 226 |
|
{ |
| 227 |
|
deflate_dirconf_t *dc = apr_pcalloc(p, sizeof(*dc)); |
| 228 |
|
dc->ratio_limit = AP_INFLATE_RATIO_LIMIT; |
| 229 |
|
dc->ratio_burst = AP_INFLATE_RATIO_BURST; |
| 230 |
|
return dc; |
| 231 |
|
} |
| 232 |
|
|
| 233 |
static const char *deflate_set_window_size(cmd_parms *cmd, void *dummy, |
static const char *deflate_set_window_size(cmd_parms *cmd, void *dummy, |
| 234 |
const char *arg) |
const char *arg) |
| 235 |
{ |
{ |
| 344 |
return NULL; |
return NULL; |
| 345 |
} |
} |
| 346 |
|
|
| 347 |
|
|
| 348 |
|
static const char *deflate_set_inflate_limit(cmd_parms *cmd, void *dirconf, |
| 349 |
|
const char *arg) |
| 350 |
|
{ |
| 351 |
|
deflate_dirconf_t *dc = (deflate_dirconf_t*) dirconf; |
| 352 |
|
char *errp; |
| 353 |
|
|
| 354 |
|
if (APR_SUCCESS != apr_strtoff(&dc->inflate_limit, arg, &errp, 10)) { |
| 355 |
|
return "DeflateInflateLimitRequestBody is not parsable."; |
| 356 |
|
} |
| 357 |
|
if (*errp || dc->inflate_limit < 0) { |
| 358 |
|
return "DeflateInflateLimitRequestBody requires a non-negative integer."; |
| 359 |
|
} |
| 360 |
|
|
| 361 |
|
return NULL; |
| 362 |
|
} |
| 363 |
|
|
| 364 |
|
static const char *deflate_set_inflate_ratio_limit(cmd_parms *cmd, |
| 365 |
|
void *dirconf, |
| 366 |
|
const char *arg) |
| 367 |
|
{ |
| 368 |
|
deflate_dirconf_t *dc = (deflate_dirconf_t*) dirconf; |
| 369 |
|
int i; |
| 370 |
|
|
| 371 |
|
i = atoi(arg); |
| 372 |
|
if (i <= 0) |
| 373 |
|
return "DeflateInflateRatioLimit must be positive"; |
| 374 |
|
|
| 375 |
|
dc->ratio_limit = i; |
| 376 |
|
|
| 377 |
|
return NULL; |
| 378 |
|
} |
| 379 |
|
|
| 380 |
|
static const char *deflate_set_inflate_ratio_burst(cmd_parms *cmd, |
| 381 |
|
void *dirconf, |
| 382 |
|
const char *arg) |
| 383 |
|
{ |
| 384 |
|
deflate_dirconf_t *dc = (deflate_dirconf_t*) dirconf; |
| 385 |
|
int i; |
| 386 |
|
|
| 387 |
|
i = atoi(arg); |
| 388 |
|
if (i <= 0) |
| 389 |
|
return "DeflateInflateRatioBurst must be positive"; |
| 390 |
|
|
| 391 |
|
dc->ratio_burst = i; |
| 392 |
|
|
| 393 |
|
return NULL; |
| 394 |
|
} |
| 395 |
|
|
| 396 |
typedef struct deflate_ctx_t |
typedef struct deflate_ctx_t |
| 397 |
{ |
{ |
| 398 |
z_stream stream; |
z_stream stream; |
| 405 |
char header[10]; /* sizeof(gzip_header) */ |
char header[10]; /* sizeof(gzip_header) */ |
| 406 |
apr_size_t header_len; |
apr_size_t header_len; |
| 407 |
int zlib_flags; |
int zlib_flags; |
| 408 |
|
int ratio_hits; |
| 409 |
|
apr_off_t inflate_total; |
| 410 |
unsigned int consume_pos, |
unsigned int consume_pos, |
| 411 |
consume_len; |
consume_len; |
| 412 |
unsigned int filter_init:1; |
unsigned int filter_init:1; |
| 531 |
} |
} |
| 532 |
} |
} |
| 533 |
|
|
| 534 |
|
/* Check whether the (inflate) ratio exceeds the configured limit/burst. */ |
| 535 |
|
static int check_ratio(request_rec *r, deflate_ctx *ctx, |
| 536 |
|
const deflate_dirconf_t *dc) |
| 537 |
|
{ |
| 538 |
|
if (ctx->stream.total_in) { |
| 539 |
|
int ratio = ctx->stream.total_out / ctx->stream.total_in; |
| 540 |
|
if (ratio < dc->ratio_limit) { |
| 541 |
|
ctx->ratio_hits = 0; |
| 542 |
|
} |
| 543 |
|
else if (++ctx->ratio_hits > dc->ratio_burst) { |
| 544 |
|
return 0; |
| 545 |
|
} |
| 546 |
|
} |
| 547 |
|
return 1; |
| 548 |
|
} |
| 549 |
|
|
| 550 |
static int have_ssl_compression(request_rec *r) |
static int have_ssl_compression(request_rec *r) |
| 551 |
{ |
{ |
| 552 |
const char *comp; |
const char *comp; |
| 1121 |
int zRC; |
int zRC; |
| 1122 |
apr_status_t rv; |
apr_status_t rv; |
| 1123 |
deflate_filter_config *c; |
deflate_filter_config *c; |
| 1124 |
|
deflate_dirconf_t *dc; |
| 1125 |
|
apr_off_t inflate_limit; |
| 1126 |
|
|
| 1127 |
/* just get out of the way of things we don't want. */ |
/* just get out of the way of things we don't want. */ |
| 1128 |
if (mode != AP_MODE_READBYTES) { |
if (mode != AP_MODE_READBYTES) { |
| 1130 |
} |
} |
| 1131 |
|
|
| 1132 |
c = ap_get_module_config(r->server->module_config, &deflate_module); |
c = ap_get_module_config(r->server->module_config, &deflate_module); |
| 1133 |
|
dc = ap_get_module_config(r->per_dir_config, &deflate_module); |
| 1134 |
|
|
| 1135 |
if (!ctx || ctx->header_len < sizeof(ctx->header)) { |
if (!ctx || ctx->header_len < sizeof(ctx->header)) { |
| 1136 |
apr_size_t len; |
apr_size_t len; |
| 1247 |
apr_brigade_cleanup(ctx->bb); |
apr_brigade_cleanup(ctx->bb); |
| 1248 |
} |
} |
| 1249 |
|
|
| 1250 |
|
inflate_limit = dc->inflate_limit; |
| 1251 |
|
if (inflate_limit == 0) { |
| 1252 |
|
/* The core is checking the deflated body, we'll check the inflated */ |
| 1253 |
|
inflate_limit = ap_get_limit_req_body(f->r); |
| 1254 |
|
} |
| 1255 |
|
|
| 1256 |
if (APR_BRIGADE_EMPTY(ctx->proc_bb)) { |
if (APR_BRIGADE_EMPTY(ctx->proc_bb)) { |
| 1257 |
rv = ap_get_brigade(f->next, ctx->bb, mode, block, readbytes); |
rv = ap_get_brigade(f->next, ctx->bb, mode, block, readbytes); |
| 1258 |
|
|
| 1304 |
ctx->stream.next_out = ctx->buffer; |
ctx->stream.next_out = ctx->buffer; |
| 1305 |
len = c->bufferSize - ctx->stream.avail_out; |
len = c->bufferSize - ctx->stream.avail_out; |
| 1306 |
|
|
| 1307 |
|
ctx->inflate_total += len; |
| 1308 |
|
if (inflate_limit && ctx->inflate_total > inflate_limit) { |
| 1309 |
|
inflateEnd(&ctx->stream); |
| 1310 |
|
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO() |
| 1311 |
|
"Inflated content length of %" APR_OFF_T_FMT |
| 1312 |
|
" is larger than the configured limit" |
| 1313 |
|
" of %" APR_OFF_T_FMT, |
| 1314 |
|
ctx->inflate_total, inflate_limit); |
| 1315 |
|
return APR_ENOSPC; |
| 1316 |
|
} |
| 1317 |
|
|
| 1318 |
ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len); |
ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len); |
| 1319 |
tmp_b = apr_bucket_heap_create((char *)ctx->buffer, len, |
tmp_b = apr_bucket_heap_create((char *)ctx->buffer, len, |
| 1320 |
NULL, f->c->bucket_alloc); |
NULL, f->c->bucket_alloc); |
| 1368 |
while (ctx->stream.avail_in != 0) { |
while (ctx->stream.avail_in != 0) { |
| 1369 |
if (ctx->stream.avail_out == 0) { |
if (ctx->stream.avail_out == 0) { |
| 1370 |
apr_bucket *tmp_heap; |
apr_bucket *tmp_heap; |
| 1371 |
|
|
| 1372 |
ctx->stream.next_out = ctx->buffer; |
ctx->stream.next_out = ctx->buffer; |
| 1373 |
len = c->bufferSize - ctx->stream.avail_out; |
len = c->bufferSize - ctx->stream.avail_out; |
| 1374 |
|
|
| 1375 |
|
ctx->inflate_total += len; |
| 1376 |
|
if (inflate_limit && ctx->inflate_total > inflate_limit) { |
| 1377 |
|
inflateEnd(&ctx->stream); |
| 1378 |
|
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO() |
| 1379 |
|
"Inflated content length of %" APR_OFF_T_FMT |
| 1380 |
|
" is larger than the configured limit" |
| 1381 |
|
" of %" APR_OFF_T_FMT, |
| 1382 |
|
ctx->inflate_total, inflate_limit); |
| 1383 |
|
return APR_ENOSPC; |
| 1384 |
|
} |
| 1385 |
|
|
| 1386 |
|
if (!check_ratio(r, ctx, dc)) { |
| 1387 |
|
inflateEnd(&ctx->stream); |
| 1388 |
|
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO() |
| 1389 |
|
"Inflated content ratio is larger than the " |
| 1390 |
|
"configured limit %i by %i time(s)", |
| 1391 |
|
dc->ratio_limit, dc->ratio_burst); |
| 1392 |
|
return APR_EINVAL; |
| 1393 |
|
} |
| 1394 |
|
|
| 1395 |
ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len); |
ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len); |
| 1396 |
tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len, |
tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len, |
| 1397 |
NULL, f->c->bucket_alloc); |
NULL, f->c->bucket_alloc); |
| 1537 |
int zRC; |
int zRC; |
| 1538 |
apr_status_t rv; |
apr_status_t rv; |
| 1539 |
deflate_filter_config *c; |
deflate_filter_config *c; |
| 1540 |
|
deflate_dirconf_t *dc; |
| 1541 |
|
|
| 1542 |
/* Do nothing if asked to filter nothing. */ |
/* Do nothing if asked to filter nothing. */ |
| 1543 |
if (APR_BRIGADE_EMPTY(bb)) { |
if (APR_BRIGADE_EMPTY(bb)) { |
| 1545 |
} |
} |
| 1546 |
|
|
| 1547 |
c = ap_get_module_config(r->server->module_config, &deflate_module); |
c = ap_get_module_config(r->server->module_config, &deflate_module); |
| 1548 |
|
dc = ap_get_module_config(r->per_dir_config, &deflate_module); |
| 1549 |
|
|
| 1550 |
if (!ctx) { |
if (!ctx) { |
| 1551 |
|
|
| 1826 |
while (ctx->stream.avail_in != 0) { |
while (ctx->stream.avail_in != 0) { |
| 1827 |
if (ctx->stream.avail_out == 0) { |
if (ctx->stream.avail_out == 0) { |
| 1828 |
|
|
| 1829 |
|
if (!check_ratio(r, ctx, dc)) { |
| 1830 |
|
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO() |
| 1831 |
|
"Inflated content ratio is larger than the " |
| 1832 |
|
"configured limit %i by %i time(s)", |
| 1833 |
|
dc->ratio_limit, dc->ratio_burst); |
| 1834 |
|
return APR_EINVAL; |
| 1835 |
|
} |
| 1836 |
|
|
| 1837 |
ctx->stream.next_out = ctx->buffer; |
ctx->stream.next_out = ctx->buffer; |
| 1838 |
len = c->bufferSize - ctx->stream.avail_out; |
len = c->bufferSize - ctx->stream.avail_out; |
| 1839 |
|
|
| 1921 |
"Set the Deflate Compression Level (1-9)"), |
"Set the Deflate Compression Level (1-9)"), |
| 1922 |
AP_INIT_TAKE1("DeflateAlterEtag", deflate_set_etag, NULL, RSRC_CONF, |
AP_INIT_TAKE1("DeflateAlterEtag", deflate_set_etag, NULL, RSRC_CONF, |
| 1923 |
"Set how mod_deflate should modify ETAG response headers: 'AddSuffix' (default), 'NoChange' (2.2.x behavior), 'Remove'"), |
"Set how mod_deflate should modify ETAG response headers: 'AddSuffix' (default), 'NoChange' (2.2.x behavior), 'Remove'"), |
| 1924 |
|
AP_INIT_TAKE1("DeflateInflateLimitRequestBody", deflate_set_inflate_limit, NULL, OR_ALL, |
| 1925 |
|
"Set a limit on size of inflated input"), |
| 1926 |
|
AP_INIT_TAKE1("DeflateInflateRatioLimit", deflate_set_inflate_ratio_limit, NULL, OR_ALL, |
| 1927 |
|
"Set the inflate ratio limit above which inflation is " |
| 1928 |
|
"aborted (default: " APR_STRINGIFY(AP_INFLATE_RATIO_LIMIT) ")"), |
| 1929 |
|
AP_INIT_TAKE1("DeflateInflateRatioBurst", deflate_set_inflate_ratio_burst, NULL, OR_ALL, |
| 1930 |
|
"Set the maximum number of following inflate ratios above limit " |
| 1931 |
|
"(default: " APR_STRINGIFY(AP_INFLATE_RATIO_BURST) ")"), |
| 1932 |
{NULL} |
{NULL} |
| 1933 |
}; |
}; |
| 1934 |
|
|
| 1938 |
#endif |
#endif |
| 1939 |
AP_DECLARE_MODULE(deflate) = { |
AP_DECLARE_MODULE(deflate) = { |
| 1940 |
STANDARD20_MODULE_STUFF, |
STANDARD20_MODULE_STUFF, |
| 1941 |
NULL, /* dir config creater */ |
create_deflate_dirconf, /* dir config creater */ |
| 1942 |
NULL, /* dir merger --- default is to override */ |
NULL, /* dir merger --- default is to override */ |
| 1943 |
create_deflate_server_config, /* server config */ |
create_deflate_server_config, /* server config */ |
| 1944 |
NULL, /* merge server config */ |
NULL, /* merge server config */ |