File httpd-cache-forward-http-proxy.patch of Package apache2

https://bz.apache.org/bugzilla/show_bug.cgi?id=60577 comment 5
--- modules/cache/cache_storage.c	(revision 1783795)
+++ modules/cache/cache_storage.c	(working copy)
@@ -427,7 +427,7 @@ int cache_select(cache_request_rec *cache, request
 }
 
 static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
-                                           const char *uri, const char *query,
+                                           const char *path, const char *query,
                                            apr_uri_t *parsed_uri,
                                            const char **key)
 {
@@ -435,8 +435,8 @@ static apr_status_t cache_canonicalise_key(request
     char *port_str, *hn, *lcs;
     const char *hostname, *scheme;
     int i;
-    const char *path;
-    char *querystring;
+    const char *kpath;
+    const char *kquery;
 
     if (*key) {
         /*
@@ -564,8 +564,8 @@ static apr_status_t cache_canonicalise_key(request
      * Check if we need to ignore session identifiers in the URL and do so
      * if needed.
      */
-    path = uri;
-    querystring = apr_pstrdup(p, query ? query : parsed_uri->query);
+    kpath = path;
+    kquery = conf->ignorequerystring ? NULL : query;
     if (conf->ignore_session_id->nelts) {
         int i;
         char **identifier;
@@ -580,24 +580,23 @@ static apr_status_t cache_canonicalise_key(request
              * Check that we have a parameter separator in the last segment
              * of the path and that the parameter matches our identifier
              */
-            if ((param = ap_strrchr_c(path, ';'))
+            if ((param = ap_strrchr_c(kpath, ';'))
                     && !strncmp(param + 1, *identifier, len)
                     && (*(param + len + 1) == '=')
                     && !ap_strchr_c(param + len + 2, '/')) {
-                path = apr_pstrmemdup(p, path, param - path);
+                kpath = apr_pstrmemdup(p, kpath, param - kpath);
                 continue;
             }
             /*
-             * Check if the identifier is in the querystring and cut it out.
+             * Check if the identifier is in the query string and cut it out.
              */
-            if (querystring && *querystring) {
+            if (kquery && *kquery) {
                 /*
                  * First check if the identifier is at the beginning of the
-                 * querystring and followed by a '='
+                 * query string and followed by a '='
                  */
-                if (!strncmp(querystring, *identifier, len)
-                        && (*(querystring + len) == '=')) {
-                    param = querystring;
+                if (!strncmp(kquery, *identifier, len) && kquery[len] == '=') {
+                    param = kquery;
                 }
                 else {
                     char *complete;
@@ -607,7 +606,7 @@ static apr_status_t cache_canonicalise_key(request
                      * identifier with a '&' and append a '='
                      */
                     complete = apr_pstrcat(p, "&", *identifier, "=", NULL);
-                    param = ap_strstr_c(querystring, complete);
+                    param = ap_strstr_c(kquery, complete);
                     /* If we found something we are sitting on the '&' */
                     if (param) {
                         param++;
@@ -615,28 +614,28 @@ static apr_status_t cache_canonicalise_key(request
                 }
                 if (param) {
                     const char *amp;
+                    char *dup = NULL;
 
-                    if (querystring != param) {
-                        querystring = apr_pstrndup(p, querystring,
-                                param - querystring);
+                    if (kquery != param) {
+                        dup = apr_pstrmemdup(p, kquery, param - kquery);
+                        kquery = dup;
                     }
                     else {
-                        querystring = "";
+                        kquery = "";
                     }
 
                     if ((amp = ap_strchr_c(param + len + 1, '&'))) {
-                        querystring = apr_pstrcat(p, querystring, amp + 1,
-                                NULL);
+                        kquery = apr_pstrcat(p, kquery, amp + 1, NULL);
                     }
                     else {
                         /*
-                         * If querystring is not "", then we have the case
+                         * If query string is not "", then we have the case
                          * that the identifier parameter we removed was the
-                         * last one in the original querystring. Hence we have
+                         * last one in the original query string. Hence we have
                          * a trailing '&' which needs to be removed.
                          */
-                        if (*querystring) {
-                            querystring[strlen(querystring) - 1] = '\0';
+                        if (dup) {
+                            dup[strlen(dup) - 1] = '\0';
                         }
                     }
                 }
@@ -644,15 +643,11 @@ static apr_status_t cache_canonicalise_key(request
         }
     }
 
-    /* Key format is a URI, optionally without the query-string */
-    if (conf->ignorequerystring) {
-        *key = apr_pstrcat(p, scheme, "://", hostname, port_str, path, "?",
-                NULL);
-    }
-    else {
-        *key = apr_pstrcat(p, scheme, "://", hostname, port_str, path, "?",
-                querystring, NULL);
-    }
+    /* Key format is a URI, optionally without the query-string (NULL
+     * per above if conf->ignorequerystring)
+     */
+    *key = apr_pstrcat(p, scheme, "://", hostname, port_str,
+                       kpath, "?", kquery, NULL);
 
     /*
      * Store the key in the request_config for the cache as r->parsed_uri
@@ -662,20 +657,26 @@ static apr_status_t cache_canonicalise_key(request
      * resource in the cache under a key where it is never found by the quick
      * handler during following requests.
      */
-    ap_log_rerror(
-            APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00698) "cache: Key for entity %s?%s is %s", uri, parsed_uri->query, *key);
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00698)
+                  "cache: Key for entity %s?%s is %s", path, query, *key);
 
     return APR_SUCCESS;
 }
 
 apr_status_t cache_generate_key_default(request_rec *r, apr_pool_t* p,
-        const char **key)
+                                        const char **key)
 {
-    /* We want the actual query-string, which may differ from
-     * r->parsed_uri.query (immutable), so use "" (not NULL).
+    /* In early processing (quick-handler, forward proxy), we want the initial
+     * query-string from r->parsed_uri, since any change before CACHE_SAVE
+     * shouldn't modify the key. Otherwise we want the actual query-string.
      */
-    const char *args = r->args ? r->args : "";
-    return cache_canonicalise_key(r, p, r->uri, args, &r->parsed_uri, key);
+    const char *path = r->uri;
+    const char *query = r->args;
+    if (cache_use_early_url(r)) {
+        path = r->parsed_uri.path;
+        query = r->parsed_uri.query;
+    }
+    return cache_canonicalise_key(r, p, path, query, &r->parsed_uri, key);
 }
 
 /*
@@ -717,7 +718,8 @@ int cache_invalidate(cache_request_rec *cache, req
     if (location) {
         if (apr_uri_parse(r->pool, location, &location_uri)
                 || cache_canonicalise_key(r, r->pool,
-                                          location, NULL,
+                                          location_uri.path,
+                                          location_uri.query,
                                           &location_uri, &location_key)
                 || !(r->parsed_uri.hostname
                      && location_uri.hostname
@@ -732,7 +734,8 @@ int cache_invalidate(cache_request_rec *cache, req
         if (apr_uri_parse(r->pool, content_location,
                           &content_location_uri)
                 || cache_canonicalise_key(r, r->pool,
-                                          content_location, NULL,
+                                          content_location_uri.path,
+                                          content_location_uri.query,
                                           &content_location_uri,
                                           &content_location_key)
                 || !(r->parsed_uri.hostname
--- modules/cache/cache_util.c	(revision 1783795)
+++ modules/cache/cache_util.c	(working copy)
@@ -31,10 +31,8 @@ extern module AP_MODULE_DECLARE_DATA cache_module;
  * in "filter". All but the path comparisons are case-insensitive.
  */
 static int uri_meets_conditions(const apr_uri_t *filter, const int pathlen,
-                                request_rec *r)
+                                const apr_uri_t *url, const char *path)
 {
-    const apr_uri_t *url = &r->parsed_uri;
-
     /* Scheme, hostname port and local part. The filter URI and the
      * URI we test may have the following shapes:
      *   /<path>
@@ -114,7 +112,7 @@ static int uri_meets_conditions(const apr_uri_t *f
     /* For HTTP caching purposes, an empty (NULL) path is equivalent to
      * a single "/" path. RFCs 3986/2396
      */
-    if (!r->uri) {
+    if (!path) {
         if (*filter->path == '/' && pathlen == 1) {
             return 1;
         }
@@ -126,9 +124,25 @@ static int uri_meets_conditions(const apr_uri_t *f
     /* Url has met all of the filter conditions so far, determine
      * if the paths match.
      */
-    return !strncmp(filter->path, r->uri, pathlen);
+    return !strncmp(filter->path, path, pathlen);
 }
 
+int cache_use_early_url(request_rec *r)
+{
+    cache_server_conf *conf;
+
+    if (r->proxyreq == PROXYREQ_PROXY) {
+        return 1;
+    }
+
+    conf = ap_get_module_config(r->server->module_config, &cache_module);
+    if (conf->quick) {
+        return 1;
+    }
+
+    return 0;
+}
+
 static cache_provider_list *get_provider(request_rec *r, struct cache_enable *ent,
         cache_provider_list *providers)
 {
@@ -172,6 +186,7 @@ cache_provider_list *cache_get_providers(request_r
 {
     cache_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &cache_module);
     cache_provider_list *providers = NULL;
+    const char *path;
     int i;
 
     /* per directory cache disable */
@@ -179,11 +194,14 @@ cache_provider_list *cache_get_providers(request_r
         return NULL;
     }
 
+    path = cache_use_early_url(r) ? r->parsed_uri.path : r->uri;
+
     /* global cache disable */
     for (i = 0; i < conf->cachedisable->nelts; i++) {
         struct cache_disable *ent =
                                (struct cache_disable *)conf->cachedisable->elts;
-        if (uri_meets_conditions(&ent[i].url, ent[i].pathlen, r)) {
+        if (uri_meets_conditions(&ent[i].url, ent[i].pathlen,
+                                 &r->parsed_uri, path)) {
             /* Stop searching now. */
             return NULL;
         }
@@ -200,7 +218,8 @@ cache_provider_list *cache_get_providers(request_r
     for (i = 0; i < conf->cacheenable->nelts; i++) {
         struct cache_enable *ent =
                                 (struct cache_enable *)conf->cacheenable->elts;
-        if (uri_meets_conditions(&ent[i].url, ent[i].pathlen, r)) {
+        if (uri_meets_conditions(&ent[i].url, ent[i].pathlen,
+                                 &r->parsed_uri, path)) {
             providers = get_provider(r, &ent[i], providers);
         }
     }
--- modules/cache/cache_util.h	(revision 1783795)
+++ modules/cache/cache_util.h	(working copy)
@@ -327,6 +327,12 @@ char *cache_strqtok(char *str, const char *sep, ch
  */
 apr_table_t *cache_merge_headers_out(request_rec *r);
 
+/**
+ * Return whether to use request's path/query from early stage (r->parsed_uri)
+ * or the current/rewritable ones (r->uri/r->args).
+ */
+int cache_use_early_url(request_rec *r);
+
 #ifdef __cplusplus
 }
 #endif
--- modules/cache/mod_cache.c	(revision 1783795)
+++ modules/cache/mod_cache.c	(working copy)
@@ -823,6 +823,7 @@ static apr_status_t cache_save_filter(ap_filter_t
     apr_pool_t *p;
     apr_bucket *e;
     apr_table_t *headers;
+    const char *query;
 
     conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
                                                       &cache_module);
@@ -927,6 +928,8 @@ static apr_status_t cache_save_filter(ap_filter_t
         }
     }
 
+    query = cache_use_early_url(r) ? r->parsed_uri.query : r->args;
+
     /* read expiry date; if a bad date, then leave it so the client can
      * read it
      */
@@ -1057,7 +1060,7 @@ static apr_status_t cache_save_filter(ap_filter_t
         reason
                 = "s-maxage or max-age zero and no Last-Modified or Etag; not cacheable";
     }
-    else if (!conf->ignorequerystring && r->parsed_uri.query && exps == NULL
+    else if (!conf->ignorequerystring && query && exps == NULL
             && !control.max_age && !control.s_maxage) {
         /* if a query string is present but no explicit expiration time,
          * don't cache it (RFC 2616/13.9 & 13.2.1)

openSUSE Build Service is sponsored by