]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
*) mod_deflate: fix protocol handling in deflate input filter
authorJim Jagielski <jim@apache.org>
Tue, 7 Aug 2007 12:09:26 +0000 (12:09 +0000)
committerJim Jagielski <jim@apache.org>
Tue, 7 Aug 2007 12:09:26 +0000 (12:09 +0000)
     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

CHANGES
STATUS
modules/filters/mod_deflate.c

diff --git a/CHANGES b/CHANGES
index b128c086ec1a32161585fc31c08845d05ede76ab..cdee2357d4977b5c08d972790810d5b4a3b5d71d 100644 (file)
--- 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 <davi haxent.com.br>]
 
+  *) 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 <dmh dmh.org.uk>]
 
diff --git a/STATUS b/STATUS
index b5569c582f976c3d4fc6b99d641024e98d9404c0..acecd38cc3d7cf075c8b34543da7bd430cdf4fd1 100644 (file)
--- 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
index 2cbb993da7a0f915c09002460208e99f7e68dcb6..365a8378fec8a77f0e77fb22eb31c0636bcf7474 100644 (file)
@@ -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);