]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
mod_cache: When a request other than GET or HEAD arrives, we must
authorGraham Leggett <minfrin@apache.org>
Sun, 13 Feb 2011 02:03:29 +0000 (02:03 +0000)
committerGraham Leggett <minfrin@apache.org>
Sun, 13 Feb 2011 02:03:29 +0000 (02:03 +0000)
invalidate existing cache entities as per RFC2616 13.10. PR 15868.

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

CHANGES
docs/manual/mod/mod_cache.xml
modules/cache/cache_storage.c
modules/cache/cache_storage.h
modules/cache/mod_cache.c
modules/cache/mod_cache.h

diff --git a/CHANGES b/CHANGES
index 2c9fb190565b39ff9dfdea40b493c01774eddc30..98ebb8e7b0aa45031a992653cb0fdf0873b67fd9 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,10 @@
 
 Changes with Apache 2.3.11
 
+  *) mod_cache: When a request other than GET or HEAD arrives, we must
+     invalidate existing cache entities as per RFC2616 13.10. PR 15868.
+     [Graham Leggett]
+
   *) modules: Fix many modules that were not correctly initializing if they
      were not active during server startup but got enabled later during a
      graceful restart. [Stefan Fritsch]
index e73e2d93ee56ab7177eae00d6f6f242decdd3719..97d7c11760241fbb38a4239946b758aecbf74d3f 100644 (file)
   </example>
 
   <p>Based on the caching decision made, the reason is also written to the
-  subprocess environment under one the following three keys, as appropriate:</p>
+  subprocess environment under one the following four keys, as appropriate:</p>
 
   <dl>
     <dt>cache-hit</dt><dd>The response was served from cache.</dd>
     <dt>cache-revalidate</dt><dd>The response was stale and was successfully
       revalidated, then served from cache.</dd>
     <dt>cache-miss</dt><dd>The response was served from the upstream server.</dd>
+    <dt>cache-invalidate</dt><dd>The cached entity was invalidated by a request
+      method other than GET or HEAD.</dd>
   </dl>
 
   <p>This makes it possible to support conditional logging of cached requests
     CustomLog cached-requests.log common env=cache-hit<br />
     CustomLog uncached-requests.log common env=cache-miss<br />
     CustomLog revalidated-requests.log common env=cache-revalidate<br />
+    CustomLog invalidated-requests.log common env=cache-invalidate<br />
   </example>
 
+  <p>For module authors, a hook called <var>cache_status</var> is available,
+  allowing modules to respond to the caching outcomes above in customised
+  ways.</p>
 </section>
-    
+
 <directivesynopsis>
 <name>CacheEnable</name>
 <description>Enable caching of specified URLs using a specified storage
index 66a965c5e0dcdacd72ff4ff0a722459f96c07e04..dd0433e1d3b2279618853b94bfbda9e468cc077f 100644 (file)
@@ -389,6 +389,53 @@ int cache_select(cache_request_rec *cache, request_rec *r)
     return DECLINED;
 }
 
+/*
+ * invalidate a specific URL entity in all caches
+ *
+ * All cached entities for this URL are removed, usually in
+ * response to a POST/PUT or DELETE.
+ *
+ * This function returns OK if at least one entity was found and
+ * removed, and DECLINED if no cached entities were removed.
+ */
+int cache_invalidate(cache_request_rec *cache, request_rec *r)
+{
+    cache_provider_list *list;
+    apr_status_t rv, status = DECLINED;
+    cache_handle_t *h;
+
+    if (!cache) {
+        /* This should never happen */
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r,
+                "cache: No cache request information available for key"
+                " generation");
+        return DECLINED;
+    }
+
+    if (!cache->key) {
+        rv = cache_generate_key(r, r->pool, &cache->key);
+        if (rv != APR_SUCCESS) {
+            return DECLINED;
+        }
+    }
+
+    /* go through the cache types */
+    h = apr_palloc(r->pool, sizeof(cache_handle_t));
+
+    list = cache->providers;
+
+    while (list) {
+        rv = list->provider->open_entity(h, r, cache->key);
+        if (OK == rv) {
+            list->provider->remove_url(h, r);
+            status = OK;
+        }
+        list = list->next;
+    }
+
+    return status;
+}
+
 apr_status_t cache_generate_key_default(request_rec *r, apr_pool_t* p,
         const char **key)
 {
index 2b67970e1ef5fd4f89dbc013925f02a451ea3be1..90445f06551020d0477578cc47d6a255d5eae03b 100644 (file)
@@ -40,6 +40,20 @@ int cache_remove_url(cache_request_rec *cache, request_rec *r);
 int cache_create_entity(cache_request_rec *cache, request_rec *r,
                         apr_off_t size, apr_bucket_brigade *in);
 int cache_select(cache_request_rec *cache, request_rec *r);
+
+/**
+ * invalidate a specific URL entity in all caches
+ *
+ * All cached entities for this URL are removed, usually in
+ * response to a POST/PUT or DELETE.
+ *
+ * This function returns OK if at least one entity was found and
+ * removed, and DECLINED if no cached entities were removed.
+ * @param h cache_handle_t
+ * @param r request_rec
+ */
+int cache_invalidate(cache_request_rec *cache, request_rec *r);
+
 apr_status_t cache_generate_key_default(request_rec *r, apr_pool_t* p,
         const char **key);
 
index f02922d563633b3379ac57c1f918784972dc0916..afaaf997ee7fad7d1ca1b3a0f9beb338620d14f0 100644 (file)
@@ -75,11 +75,6 @@ static int cache_quick_handler(request_rec *r, int lookup)
     ap_filter_rec_t *cache_out_handle;
     cache_server_conf *conf;
 
-    /* Delay initialization until we know we are handling a GET */
-    if (r->method_number != M_GET) {
-        return DECLINED;
-    }
-
     conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
                                                       &cache_module);
 
@@ -117,6 +112,25 @@ static int cache_quick_handler(request_rec *r, int lookup)
         return DECLINED;
     }
 
+    /* Are we something other than GET or HEAD? If so, invalidate
+     * the cached entities.
+     */
+    if (r->method_number != M_GET) {
+
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
+                "Invalidating all cached entities in response to '%s' request for %s",
+                r->method, r->uri);
+
+        cache_invalidate(cache, r);
+
+        /* we've got a cache invalidate! tell everyone who cares */
+        cache_run_cache_status(cache->handle, r, r->headers_out,
+                AP_CACHE_INVALIDATE, apr_psprintf(r->pool,
+                        "cache invalidated by %s", r->method));
+
+        return DECLINED;
+    }
+
     /*
      * Try to serve this request from the cache.
      *
@@ -176,9 +190,10 @@ static int cache_quick_handler(request_rec *r, int lookup)
                      * is available later during running the filter may be
                      * different due to an internal redirect.
                      */
-                    cache->remove_url_filter =
-                        ap_add_output_filter_handle(cache_remove_url_filter_handle,
-                                cache, r, r->connection);
+                    cache->remove_url_filter = ap_add_output_filter_handle(
+                            cache_remove_url_filter_handle, cache, r,
+                            r->connection);
+
                 }
                 else {
                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv,
@@ -356,11 +371,6 @@ static int cache_handler(request_rec *r)
     ap_filter_rec_t *cache_save_handle;
     cache_server_conf *conf;
 
-    /* Delay initialization until we know we are handling a GET */
-    if (r->method_number != M_GET) {
-        return DECLINED;
-    }
-
     conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
                                                       &cache_module);
 
@@ -384,6 +394,26 @@ static int cache_handler(request_rec *r)
     /* save away the possible providers */
     cache->providers = providers;
 
+    /* Are we something other than GET or HEAD? If so, invalidate
+     * the cached entities.
+     */
+    if (r->method_number != M_GET) {
+
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
+                "Invalidating all cached entities in response to '%s' request for %s",
+                r->method, r->uri);
+
+        cache_invalidate(cache, r);
+
+        /* we've got a cache invalidate! tell everyone who cares */
+        cache_run_cache_status(cache->handle, r, r->headers_out,
+                AP_CACHE_INVALIDATE, apr_psprintf(r->pool,
+                        "cache invalidated by %s", r->method));
+
+        return DECLINED;
+
+    }
+
     /*
      * Try to serve this request from the cache.
      *
@@ -464,9 +494,10 @@ static int cache_handler(request_rec *r)
                  * is available later during running the filter may be
                  * different due to an internal redirect.
                  */
-                cache->remove_url_filter =
-                    ap_add_output_filter_handle(cache_remove_url_filter_handle,
-                            cache, r, r->connection);
+                cache->remove_url_filter
+                        = ap_add_output_filter_handle(
+                                cache_remove_url_filter_handle, cache, r,
+                                r->connection);
 
             }
             else {
@@ -1538,6 +1569,10 @@ static int cache_status(cache_handle_t *h, request_rec *r,
         apr_table_setn(r->subprocess_env, AP_CACHE_MISS_ENV, reason);
         break;
     }
+    case AP_CACHE_INVALIDATE: {
+        apr_table_setn(r->subprocess_env, AP_CACHE_INVALIDATE_ENV, reason);
+        break;
+    }
     }
 
     apr_table_setn(r->subprocess_env, AP_CACHE_STATUS_ENV, reason);
@@ -1549,11 +1584,11 @@ static int cache_status(cache_handle_t *h, request_rec *r,
         x_cache = conf->x_cache;
     }
     if (x_cache) {
-        apr_table_setn(headers, "X-Cache",
-                apr_psprintf(r->pool, "%s from %s",
-                        status == AP_CACHE_HIT ? "HIT" : status
-                                == AP_CACHE_REVALIDATE ? "REVALIDATE" : "MISS",
-                        r->server->server_hostname));
+        apr_table_setn(headers, "X-Cache", apr_psprintf(r->pool, "%s from %s",
+                status == AP_CACHE_HIT ? "HIT"
+                        : status == AP_CACHE_REVALIDATE ? "REVALIDATE" : status
+                                == AP_CACHE_INVALIDATE ? "INVALIDATE" : "MISS",
+                r->server->server_hostname));
     }
 
     if (dconf && dconf->x_cache_detail_set) {
index b65e56a948192f64664f130ef118ef8a8e4439f7..70c4bc43ccd4042760aac7a8175dbabcb13ebdae 100644 (file)
@@ -114,12 +114,14 @@ typedef struct {
 typedef enum {
     AP_CACHE_HIT,
     AP_CACHE_REVALIDATE,
-    AP_CACHE_MISS
+    AP_CACHE_MISS,
+    AP_CACHE_INVALIDATE
 } ap_cache_status_e;
 
 #define AP_CACHE_HIT_ENV "cache-hit"
 #define AP_CACHE_REVALIDATE_ENV "cache-revalidate"
 #define AP_CACHE_MISS_ENV "cache-miss"
+#define AP_CACHE_INVALIDATE_ENV "cache-invalidate"
 #define AP_CACHE_STATUS_ENV "cache-status"