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"