From: Graham Leggett
Date: Sun, 13 Feb 2011 02:03:29 +0000 (+0000)
Subject: mod_cache: When a request other than GET or HEAD arrives, we must
X-Git-Tag: 2.3.11~64
X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=43fc2d47c7ec261abefc5bafecfdb9e66c48fd30;p=thirdparty%2Fapache%2Fhttpd.git
mod_cache: When a request other than GET or HEAD arrives, we must
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
---
diff --git a/CHANGES b/CHANGES
index 2c9fb190565..98ebb8e7b0a 100644
--- 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]
diff --git a/docs/manual/mod/mod_cache.xml b/docs/manual/mod/mod_cache.xml
index e73e2d93ee5..97d7c117602 100644
--- a/docs/manual/mod/mod_cache.xml
+++ b/docs/manual/mod/mod_cache.xml
@@ -302,13 +302,15 @@
Based on the caching decision made, the reason is also written to the
- subprocess environment under one the following three keys, as appropriate:
+ subprocess environment under one the following four keys, as appropriate:
- cache-hit
- The response was served from cache.
- cache-revalidate
- The response was stale and was successfully
revalidated, then served from cache.
- cache-miss
- The response was served from the upstream server.
+ - cache-invalidate
- The cached entity was invalidated by a request
+ method other than GET or HEAD.
This makes it possible to support conditional logging of cached requests
@@ -318,10 +320,14 @@
CustomLog cached-requests.log common env=cache-hit
CustomLog uncached-requests.log common env=cache-miss
CustomLog revalidated-requests.log common env=cache-revalidate
+ CustomLog invalidated-requests.log common env=cache-invalidate
+
For module authors, a hook called cache_status is available,
+ allowing modules to respond to the caching outcomes above in customised
+ ways.
-
+
CacheEnable
Enable caching of specified URLs using a specified storage
diff --git a/modules/cache/cache_storage.c b/modules/cache/cache_storage.c
index 66a965c5e0d..dd0433e1d3b 100644
--- a/modules/cache/cache_storage.c
+++ b/modules/cache/cache_storage.c
@@ -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)
{
diff --git a/modules/cache/cache_storage.h b/modules/cache/cache_storage.h
index 2b67970e1ef..90445f06551 100644
--- a/modules/cache/cache_storage.h
+++ b/modules/cache/cache_storage.h
@@ -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);
diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c
index f02922d5636..afaaf997ee7 100644
--- a/modules/cache/mod_cache.c
+++ b/modules/cache/mod_cache.c
@@ -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) {
diff --git a/modules/cache/mod_cache.h b/modules/cache/mod_cache.h
index b65e56a9481..70c4bc43ccd 100644
--- a/modules/cache/mod_cache.h
+++ b/modules/cache/mod_cache.h
@@ -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"