From: Jim Jagielski Date: Tue, 7 Aug 2007 12:09:26 +0000 (+0000) Subject: *) mod_deflate: fix protocol handling in deflate input filter X-Git-Tag: 2.2.5~24 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f36196a1a312dbcd000491026b68d485866d5d56;p=thirdparty%2Fapache%2Fhttpd.git *) mod_deflate: fix protocol handling in deflate input filter PR 23287 [Nick Kew] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@563464 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index b128c086ec1..cdee2357d49 100644 --- a/CHANGES +++ b/CHANGES @@ -26,6 +26,9 @@ Changes with Apache 2.2.5 values could previously point to cleaned up storage. PR 41551. [Davi Arnaut ] + *) mod_deflate: fix protocol handling in deflate input filter + PR 23287 [Nick Kew] + *) mime.types: add Registered Javascript/ECMAScript MIME types (RFC4329) PR 40299 [Dave Hodder ] diff --git a/STATUS b/STATUS index b5569c582f9..acecd38cc3d 100644 --- a/STATUS +++ b/STATUS @@ -78,11 +78,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - * mod_deflate: fix protocol handling in input filter - PR: 23287 - http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/filters/mod_deflate.c?r1=556113&r2=563133 - +1: niq, rpluem, jim - * mod_deflate: don't try to operate on a Content-Range trunk: http://svn.apache.org/viewvc?view=rev&revision=563154 http://svn.apache.org/viewvc?view=rev&revision=563229 diff --git a/modules/filters/mod_deflate.c b/modules/filters/mod_deflate.c index 2cbb993da7a..365a8378fec 100644 --- a/modules/filters/mod_deflate.c +++ b/modules/filters/mod_deflate.c @@ -37,6 +37,7 @@ #include "httpd.h" #include "http_config.h" #include "http_log.h" +#include "apr_lib.h" #include "apr_strings.h" #include "apr_general.h" #include "util_filter.h" @@ -82,6 +83,57 @@ static const char deflate_magic[2] = { '\037', '\213' }; #define DEFAULT_MEMLEVEL 9 #define DEFAULT_BUFFERSIZE 8096 + +/* Check whether a request is gzipped, so we can un-gzip it. + * If a request has multiple encodings, we need the gzip + * to be the outermost non-identity encoding. + */ +static int check_gzip(apr_pool_t *pool, apr_table_t *hdrs) +{ + int found = 0; + const char *encoding = apr_table_get(hdrs, "Content-Encoding"); + if (encoding && *encoding) { + + /* check the usual/simple case first */ + if (!strcasecmp(encoding, "gzip") + || !strcasecmp(encoding, "x-gzip")) { + found = 1; + apr_table_unset(hdrs, "Content-Encoding"); + } + else if (ap_strchr_c(encoding, ',') != NULL) { + /* If the outermost encoding isn't gzip, there's nowt + * we can do. So only check the last non-identity token + */ + char *new_encoding = apr_pstrdup(pool, encoding); + char *ptr; + for(;;) { + char *token = ap_strrchr(new_encoding, ','); + if (!token) { /* gzip:identity or other:identity */ + if (!strcasecmp(new_encoding, "gzip") + || !strcasecmp(new_encoding, "x-gzip")) { + apr_table_unset(hdrs, "Content-Encoding"); + found = 1; + } + break; /* seen all tokens */ + } + for (ptr=token+1; apr_isspace(*ptr); ++ptr); + if (!strcasecmp(ptr, "gzip") + || !strcasecmp(ptr, "x-gzip")) { + *token = '\0'; + apr_table_setn(hdrs, "Content-Encoding", new_encoding); + found = 1; + } + else if (!ptr[0] || !strcasecmp(ptr, "identity")) { + *token = '\0'; + continue; /* strip the token and find the next one */ + } + break; /* found a non-identity token */ + } + } + } + return found; +} + /* Outputs a long in LSB order to the given file * only the bottom 4 bits are required for the deflate file format. */ @@ -654,9 +706,7 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, c = ap_get_module_config(r->server->module_config, &deflate_module); if (!ctx) { - int found = 0; - char *token, deflate_hdr[10]; - const char *encoding; + char deflate_hdr[10]; apr_size_t len; /* only work on main request/no subrequests */ @@ -665,26 +715,14 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, return ap_get_brigade(f->next, bb, mode, block, readbytes); } - /* Let's see what our current Content-Encoding is. - * If gzip is present, don't gzip again. (We could, but let's not.) + /* Check whether request body is gzipped. + * + * If it is, we're transforming the contents, invalidating + * some request headers including Content-Encoding. + * + * If not, we just remove ourself. */ - encoding = apr_table_get(r->headers_in, "Content-Encoding"); - if (encoding) { - const char *tmp = encoding; - - token = ap_get_token(r->pool, &tmp, 0); - while (token && token[0]) { - if (!strcasecmp(token, "gzip")) { - found = 1; - break; - } - /* Otherwise, skip token */ - tmp++; - token = ap_get_token(r->pool, &tmp, 0); - } - } - - if (found == 0) { + if (check_gzip(r->pool, r->headers_in) == 0) { ap_remove_input_filter(f); return ap_get_brigade(f->next, bb, mode, block, readbytes); } @@ -699,6 +737,10 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, return rv; } + apr_table_unset(r->headers_in, "Content-Length"); + apr_table_unset(r->headers_in, "Content-MD5"); + apr_table_unset(r->headers_in, "Content-Range"); + len = 10; rv = apr_brigade_flatten(ctx->bb, deflate_hdr, &len); if (rv != APR_SUCCESS) { @@ -919,9 +961,6 @@ static apr_status_t inflate_out_filter(ap_filter_t *f, c = ap_get_module_config(r->server->module_config, &deflate_module); if (!ctx) { - int found = 0; - char *token; - const char *encoding; /* only work on main request/no subrequests */ if (!ap_is_initial_req(r)) { @@ -931,29 +970,12 @@ static apr_status_t inflate_out_filter(ap_filter_t *f, /* * Let's see what our current Content-Encoding is. - * Only inflate if gzip is present. + * Only inflate if gzipped. */ - encoding = apr_table_get(r->headers_out, "Content-Encoding"); - if (encoding) { - const char *tmp = encoding; - - token = ap_get_token(r->pool, &tmp, 0); - while (token && token[0]) { - if (!strcasecmp(token, "gzip")) { - found = 1; - break; - } - /* Otherwise, skip token */ - tmp++; - token = ap_get_token(r->pool, &tmp, 0); - } - } - - if (found == 0) { + if (check_gzip(r->pool, r->headers_out) == 0) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } - apr_table_unset(r->headers_out, "Content-Encoding"); /* No need to inflate HEAD or 204/304 */ if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(bb))) { @@ -961,6 +983,10 @@ static apr_status_t inflate_out_filter(ap_filter_t *f, return ap_pass_brigade(f->next, bb); } + /* these are unlikely to be set anyway, but ... */ + apr_table_unset(r->headers_out, "Content-Length"); + apr_table_unset(r->headers_out, "Content-MD5"); + apr_table_unset(r->headers_out, "Content-Range"); f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx)); ctx->bb = apr_brigade_create(r->pool, f->c->bucket_alloc);