</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
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)
{
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);
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.
*
* 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,
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);
/* 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.
*
* 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 {
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);
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) {