summaryrefslogtreecommitdiffstats
path: root/modules/cache
diff options
context:
space:
mode:
authorGraham Leggett <minfrin@apache.org>2011-02-12 14:08:57 +0100
committerGraham Leggett <minfrin@apache.org>2011-02-12 14:08:57 +0100
commitbd9b56da19a02c6ec7afc380804c67605f07f5a1 (patch)
tree75002e315bb7f09b837d431622e54d9b2ca36693 /modules/cache
parentrevert r1026746: (diff)
downloadapache2-bd9b56da19a02c6ec7afc380804c67605f07f5a1.tar.xz
apache2-bd9b56da19a02c6ec7afc380804c67605f07f5a1.zip
mod_cache: We must ignore quoted-string values that appear in a
Cache-Control header. PR 50199. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1070075 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/cache')
-rw-r--r--modules/cache/cache_util.c78
1 files changed, 74 insertions, 4 deletions
diff --git a/modules/cache/cache_util.c b/modules/cache/cache_util.c
index 7a3cbd6142..7a85d249e3 100644
--- a/modules/cache/cache_util.c
+++ b/modules/cache/cache_util.c
@@ -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.
*/
@@ -1022,6 +1024,74 @@ CACHE_DECLARE(apr_table_t *)ap_cache_cacheable_headers_out(request_rec *r)
}
/**
+ * 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
* passed in.
@@ -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;
}