From: Graham Leggett Date: Tue, 28 May 2013 20:55:01 +0000 (+0000) Subject: mod_cache: Make sure Vary processing handles multivalued Vary headers and X-Git-Tag: 2.4.5~201 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=edc19493820e79ad2192f59a428a04fc63882bed;p=apache mod_cache: Make sure Vary processing handles multivalued Vary headers and multivalued headers referred to via Vary. trunk patch: http://svn.apache.org/r1478748 Submitted by: minfrin Reviewed by: jim, wrowe git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1487114 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index d11542af53..9d2ef8dd1c 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,9 @@ Changes with Apache 2.4.5 + *) mod_cache: Make sure Vary processing handles multivalued Vary headers and + multivalued headers referred to via Vary. [Graham Leggett] + *) mod_cache: When serving from cache, only the last header of a multivalued header was taken into account. Fixed. Ensure that Warning headers are correctly handled as per RFC2616. [Graham Leggett] diff --git a/STATUS b/STATUS index 13dd08d412..4b4fbdc96d 100644 --- a/STATUS +++ b/STATUS @@ -90,13 +90,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - * mod_cache: Make sure Vary processing handles multivalued Vary headers and - multivalued headers referred to via Vary. - trunk patch: http://svn.apache.org/r1478748 - 2.4.x patch: trunk patch works (minus CHANGES, on condition above backports are - done first) - +1: minfrin, jim, wrowe - * mod_cache: Make sure that contradictory entity headers present in a 304 Not Modified response are caught and cause the entity to be removed. trunk patch: http://svn.apache.org/r1479117 diff --git a/modules/cache/cache_storage.c b/modules/cache/cache_storage.c index 0fb8792c63..b1968ff258 100644 --- a/modules/cache/cache_storage.c +++ b/modules/cache/cache_storage.c @@ -246,6 +246,7 @@ int cache_select(cache_request_rec *cache, request_rec *r) case OK: { char *vary = NULL; int fresh, mismatch = 0; + char *last = NULL; if (list->provider->recall_headers(h, r) != APR_SUCCESS) { /* try again with next cache type */ @@ -271,25 +272,19 @@ int cache_select(cache_request_rec *cache, request_rec *r) * * RFC2616 13.6 and 14.44 describe the Vary mechanism. */ - vary = apr_pstrdup(r->pool, apr_table_get(h->resp_hdrs, "Vary")); - while (vary && *vary) { - char *name = vary; + vary = cache_strqtok( + apr_pstrdup(r->pool, + cache_table_getm(r->pool, h->resp_hdrs, "Vary")), + CACHE_SEPARATOR, &last); + while (vary) { const char *h1, *h2; - /* isolate header name */ - while (*vary && !apr_isspace(*vary) && (*vary != ',')) - ++vary; - while (apr_isspace(*vary) || (*vary == ',')) { - *vary = '\0'; - ++vary; - } - /* * is this header in the request and the header in the cached * request identical? If not, we give up and do a straight get */ - h1 = apr_table_get(r->headers_in, name); - h2 = apr_table_get(h->req_hdrs, name); + h1 = cache_table_getm(r->pool, r->headers_in, vary); + h2 = cache_table_getm(r->pool, h->req_hdrs, vary); if (h1 == h2) { /* both headers NULL, so a match - do nothing */ } @@ -303,6 +298,7 @@ int cache_select(cache_request_rec *cache, request_rec *r) mismatch = 1; break; } + vary = cache_strqtok(NULL, CACHE_SEPARATOR, &last); } /* no vary match, try next provider */ diff --git a/modules/cache/cache_util.c b/modules/cache/cache_util.c index f82dbdcb21..f85b125423 100644 --- a/modules/cache/cache_util.c +++ b/modules/cache/cache_util.c @@ -27,8 +27,6 @@ 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. */ @@ -862,7 +860,7 @@ CACHE_DECLARE(char *)ap_cache_generate_name(apr_pool_t *p, int dirlevels, * 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 *cache_strqtok(char *str, const char *sep, char **last) { char *token; int quoted = 0; @@ -871,6 +869,10 @@ static char *cache_strqtok(char *str, const char *sep, char **last) str = *last; /* start where we left off */ } + if (!str) { /* no more tokens */ + return NULL; + } + /* skip characters in sep (will terminate at '\0') */ while (*str && ap_strchr_c(sep, *str)) { ++str; diff --git a/modules/cache/cache_util.h b/modules/cache/cache_util.h index 0fc2c1b8c2..65321d1fb8 100644 --- a/modules/cache/cache_util.h +++ b/modules/cache/cache_util.h @@ -99,6 +99,7 @@ extern "C" { #define CACHE_LOCKNAME_KEY "mod_cache-lockname" #define CACHE_LOCKFILE_KEY "mod_cache-lockfile" #define CACHE_CTX_KEY "mod_cache-ctx" +#define CACHE_SEPARATOR ", " /** * cache_util.c @@ -305,6 +306,12 @@ cache_provider_list *cache_get_providers(request_rec *r, const char *cache_table_getm(apr_pool_t *p, const apr_table_t *t, const char *key); +/** + * String tokenizer that ignores separator characters within quoted strings + * and escaped characters, as per RFC2616 section 2.2. + */ +char *cache_strqtok(char *str, const char *sep, char **last); + #ifdef __cplusplus } #endif