]> granicus.if.org Git - apache/commitdiff
mod_cache: We must ignore quoted-string values that appear in a
authorGraham Leggett <minfrin@apache.org>
Sat, 12 Feb 2011 13:08:57 +0000 (13:08 +0000)
committerGraham Leggett <minfrin@apache.org>
Sat, 12 Feb 2011 13:08:57 +0000 (13:08 +0000)
Cache-Control header. PR 50199.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1070075 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
modules/cache/cache_util.c

diff --git a/CHANGES b/CHANGES
index e20d33c7fabff0e2709a0098aa64f43932f9e75f..103725ed87fc0c631c4ce1583e24112cb45421fe 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,9 @@
 
 Changes with Apache 2.3.11
 
+  *) mod_cache: We must ignore quoted-string values that appear in a
+     Cache-Control header. PR 50199. [Graham Leggett]
+
   *) mod_dav: Revert change to send 501 error if unknown Content-* header is
     received for a PUT request. PR 42978. [Stefan Fritsch]
 
index 7a3cbd6142712f2f4ab54d35ec329e28d2ab00bd..7a85d249e362ed73279e0932084b77b813cf6db8 100644 (file)
@@ -27,6 +27,8 @@ extern APR_OPTIONAL_FN_TYPE(ap_cache_generate_key) *cache_generate_key;
 
 extern module AP_MODULE_DECLARE_DATA cache_module;
 
+#define CACHE_SEPARATOR ",   "
+
 /* Determine if "url" matches the hostname, scheme and port and path
  * in "filter". All but the path comparisons are case-insensitive.
  */
@@ -1021,6 +1023,74 @@ CACHE_DECLARE(apr_table_t *)ap_cache_cacheable_headers_out(request_rec *r)
     return headers_out;
 }
 
+/**
+ * String tokenizer that ignores separator characters within quoted strings
+ * and escaped characters, as per RFC2616 section 2.2.
+ */
+static char *cache_strqtok(char *str, const char *sep, char **last)
+{
+    char *token;
+    int quoted = 0;
+
+    if (!str) {         /* subsequent call */
+        str = *last;    /* start where we left off */
+    }
+
+    /* skip characters in sep (will terminate at '\0') */
+    while (*str && strchr(sep, *str)) {
+        ++str;
+    }
+
+    if (!*str) {        /* no more tokens */
+        return NULL;
+    }
+
+    token = str;
+
+    /* skip valid token characters to terminate token and
+     * prepare for the next call (will terminate at '\0)
+     * on the way, ignore all quoted strings, and within
+     * quoted strings, escaped characters.
+     */
+    *last = token + 1;
+    while (**last) {
+        if (!quoted) {
+            if (**last == '\"') {
+                quoted = 1;
+                ++*last;
+            }
+            else if (!strchr(sep, **last)) {
+                ++*last;
+            }
+            else {
+                break;
+            }
+        }
+        else {
+            if (**last == '\"') {
+                quoted = 0;
+                ++*last;
+            }
+            else if (**last == '\\') {
+                ++*last;
+                if (**last) {
+                    ++*last;
+                }
+            }
+            else {
+                ++*last;
+            }
+        }
+    }
+
+    if (**last) {
+        **last = '\0';
+        ++*last;
+    }
+
+    return token;
+}
+
 /**
  * Parse the Cache-Control and Pragma headers in one go, marking
  * which tokens appear within the header. Populate the structure
@@ -1043,7 +1113,7 @@ int ap_cache_control(request_rec *r, cache_control_t *cc,
 
     if (pragma_header) {
         char *header = apr_pstrdup(r->pool, pragma_header);
-        const char *token = apr_strtok(header, ", ", &last);
+        const char *token = cache_strqtok(header, CACHE_SEPARATOR, &last);
         while (token) {
             /* handle most common quickest case... */
             if (!strcmp(token, "no-cache")) {
@@ -1053,14 +1123,14 @@ int ap_cache_control(request_rec *r, cache_control_t *cc,
             else if (!strcasecmp(token, "no-cache")) {
                 cc->no_cache = 1;
             }
-            token = apr_strtok(NULL, ", ", &last);
+            token = cache_strqtok(NULL, CACHE_SEPARATOR, &last);
         }
         cc->pragma = 1;
     }
 
     if (cc_header) {
         char *header = apr_pstrdup(r->pool, cc_header);
-        const char *token = apr_strtok(header, ", ", &last);
+        const char *token = cache_strqtok(header, CACHE_SEPARATOR, &last);
         while (token) {
             switch (token[0]) {
             case 'n':
@@ -1178,7 +1248,7 @@ int ap_cache_control(request_rec *r, cache_control_t *cc,
                 break;
             }
             }
-            token = apr_strtok(NULL, ", ", &last);
+            token = cache_strqtok(NULL, CACHE_SEPARATOR, &last);
         }
         cc->cache_control = 1;
     }