Index: docs/manual/mod/mod_cache.xml =================================================================== RCS file: /home/cvspublic/httpd-2.0/docs/manual/mod/mod_cache.xml,v --- docs/manual/mod/mod_cache.xml 15 Apr 2003 22:56:37 -0000 1.12.2.2 +++ docs/manual/mod/mod_cache.xml 4 Dec 2003 13:54:10 -0000 @@ -314,4 +314,42 @@ + +CachePurgeMethod +Name of HTTP method used which may be used to remove +single entries in the cache. +CachePurgeMethod MethodName +CachePurgeMethod PURGE +server configvirtual host + + + +

Generally a resource which has been stored in the cache will be + removed and replaced by new resource data whenever the cache decides + to do so. There are on the other situations, where some process, for + example a web server in fron of which a caching reverse proxy is placed, + knows before hand that some resource has changed. In such situations + that other process might wish to inform the caching proxy to remove + the stale data from the cache regardless of any other information.

+ +

This kind of administration of the cache contents is made possible + through the use of cache purge method. The cache handler will intercept + a request with the hereby configured method and try to remove the + cache entry indicated by the request. In case of success, that is the + cache entry was present and has been removed, the server response + with a OK status (200). If the no cache entry was present for the + indicated resource, the cache handler sends a Not Found (404) + response.

+ +

The cache handler completely ignores any incoming request body and + does not send back a response body. Request headers are only respected + as far as they are needed to identify the cache entry for the + resource.

+ + + CachePurgeMethod PURGE_CACHE + +
+
+ Index: modules/experimental/cache_storage.c =================================================================== RCS file: /home/cvspublic/httpd-2.0/modules/experimental/cache_storage.c,v --- modules/experimental/cache_storage.c 3 Feb 2003 17:31:36 -0000 1.27.2.1 +++ modules/experimental/cache_storage.c 4 Dec 2003 13:54:33 -0000 @@ -76,7 +76,7 @@ * delete all URL entities from the cache * */ -int cache_remove_url(request_rec *r, const char *types, char *url) +int cache_remove_url(cache_handle_t *h, request_rec *r, const char *types, char *url) { const char *next = types; const char *type; @@ -91,7 +91,7 @@ /* for each specified cache type, delete the URL */ while(next) { type = ap_cache_tokstr(r->pool, next, &next); - cache_run_remove_url(type, key); + cache_run_remove_url(h, r, type, key); } return OK; } @@ -312,7 +312,7 @@ const char *urlkey),(h,r,type,urlkey), DECLINED) APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(cache, CACHE, int, remove_url, - (const char *type, const char *urlkey), - (type,urlkey),OK,DECLINED) + (cache_handle_t *h, request_rec *r, const char *type, const char *urlkey), + (h,r,type,urlkey),OK,DECLINED) Index: modules/experimental/mod_cache.c =================================================================== RCS file: /home/cvspublic/httpd-2.0/modules/experimental/mod_cache.c,v --- modules/experimental/mod_cache.c 27 Sep 2003 18:17:10 -0000 1.64.2.7 +++ modules/experimental/mod_cache.c 4 Dec 2003 13:54:33 -0000 @@ -71,8 +71,12 @@ */ static ap_filter_rec_t *cache_in_filter_handle; static ap_filter_rec_t *cache_out_filter_handle; +static ap_filter_rec_t *cache_out_purge_handle; static ap_filter_rec_t *cache_conditional_filter_handle; +/* Forward declarations */ +static int cache_purge(request_rec *r, cache_server_conf *conf, cache_request_rec *cache, char *url); + /* * CACHE handler * ------------- @@ -104,8 +108,8 @@ conf = (cache_server_conf *) ap_get_module_config(r->server->module_config, &cache_module); - /* we don't handle anything but GET */ - if (r->method_number != M_GET) { + /* we don't handle anything but GET and cache purge method */ + if (r->method_number != M_GET && r->method_number != conf->method) { return DECLINED; } @@ -169,7 +173,7 @@ if (ap_cache_liststr(NULL, cc_in, "no-store", NULL) || ap_cache_liststr(NULL, pragma, "no-cache", NULL) || (auth != NULL)) { /* delete the previously cached file */ - cache_remove_url(r, cache->types, url); + cache_remove_url(cache->handle, r, cache->types, url); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "cache: no-store forbids caching of %s", url); @@ -180,6 +184,8 @@ /* * Try to serve this request from the cache. * + * If cache purge method + * purge cache entry * If no existing cache file * add cache_in filter * If stale cache file @@ -194,7 +200,11 @@ */ rv = cache_select_url(r, cache->types, url); - if (DECLINED == rv) { + if (r->method_number == conf->method && (DECLINED == rv || OK == rv)) { + cache_request_rec *purge_cache = (OK == rv) ? cache : NULL; + return cache_purge(r, conf, purge_cache, url); + } + else if (DECLINED == rv) { if (!lookup) { /* no existing cache file */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, @@ -591,7 +601,7 @@ * BillS Asks.. Why do we need to make this call to remove_url? * leave it in for now.. */ - cache_remove_url(r, cache->types, url); + cache_remove_url(cache->handle, r, cache->types, url); /* remove this filter from the chain */ ap_remove_output_filter(f); @@ -775,6 +785,110 @@ return ap_pass_brigade(f->next, in); } +/* + * CACHE_PURGE filter + * ------------------ + * + * Deliver cache purge response up the stack. + */ +static int cache_out_purge(ap_filter_t *f, apr_bucket_brigade *bb) +{ + request_rec *r = f->r; + cache_request_rec *cache; + + cache = (cache_request_rec *) ap_get_module_config(r->request_config, + &cache_module); + + if (!cache) { + /* user likely configured CACHE_PURGE manually; they should use mod_cache + * configuration to do that */ + ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, + "CACHE_PURGE enabled unexpectedly"); + ap_remove_output_filter(f); + return ap_pass_brigade(f->next, bb); + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server, + "cache_out_purge: running CACHE_PURGE filter"); + + /* Would set status code, but has already been done in cache_purge */ + + /* Remove as many headers as possible .... */ + apr_table_clear(r->headers_out); + apr_table_clear(r->err_headers_out); + + /* at least force Content-Length to be zero, we do not have anything */ + apr_table_set(r->headers_out, "Content-Length", "0"); + + /* This filter is done once it has served up its content */ + ap_remove_output_filter(f); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server, + "cache: sending reply to purging %s from cache", + r->uri); + return ap_pass_brigade(f->next, bb); +} + +/* + * Helper method to remove the cache entry from the storage + * and redirect request handling to the cache_out_purge method. + * + * If cache + * cache contains data, which is removed + * set HTTP response status OK/200 + * Else + * cache does not contain data + * set HTTP response status NOT_FOUND/404 + */ +static int cache_purge(request_rec *r, cache_server_conf *conf, cache_request_rec *cache, char *url) +{ + conn_rec *c = r->connection; + apr_bucket_brigade *out; + int rv; + + if (cache) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "cache: Remove entity url=%s for types=%s", + url, cache->types); + + rv = cache_remove_url(cache->handle, r, cache->types, url); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "cache: cache_remove_url rv=%d", + rv); + r->status = HTTP_OK; + } + else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "cache: Entity url=%s not in cache", + url); + r->status = HTTP_NOT_FOUND; + } + + + /* the following is duplicate from cache_url_handler, I assume + * this code is correct... + */ + + /* We are in the quick handler hook, which means that no output + * filters have been set. So lets run the insert_filter hook. + */ + ap_run_insert_filter(r); + ap_add_output_filter_handle(cache_out_purge_handle, NULL, + r, r->connection); + + /* kick off the filter stack */ + out = apr_brigade_create(r->pool, c->bucket_alloc); + if (APR_SUCCESS != (rv = ap_pass_brigade(r->output_filters, out))) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, + "cache: error returned while trying to purge cache entry " + "for url=%s", + url); + return rv; + } + + return OK; +} + /* -------------------------------------------------------------- */ /* Setup configurable data */ @@ -798,6 +912,9 @@ /* default percentage to force cache completion */ ps->complete = DEFAULT_CACHE_COMPLETION; ps->complete_set = 0; + /* default purge method name to remove cache entry */ + ps->method = ap_method_register(p, DEFAULT_PURGE_METHOD); + ps->method_set = 0; ps->no_last_mod_ignore_set = 0; ps->no_last_mod_ignore = 0; ps->ignorecachecontrol = 0; @@ -829,6 +946,9 @@ /* default percentage to force cache completion */ ps->complete = (overrides->complete_set == 0) ? base->complete : overrides->complete; + /* default purge method name to remove cache entry */ + ps->method = + (overrides->method_set == 0) ? base->method : overrides->method; ps->no_last_mod_ignore = (overrides->no_last_mod_ignore_set == 0) @@ -957,6 +1077,24 @@ return NULL; } +static const char *set_cache_purge_method(cmd_parms *parms, void *dummy, + const char *arg) +{ + cache_server_conf *conf; + int val; + + conf = + (cache_server_conf *)ap_get_module_config(parms->server->module_config, + &cache_module); + int method = ap_method_register(parms->pool, arg); + if (method == M_INVALID) { + return "CachePurgeMethod cannot be registered and used"; + } + conf->method = method; + conf->method_set = 1; + return NULL; +} + static int cache_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { @@ -1003,6 +1141,8 @@ AP_INIT_TAKE1("CacheForceCompletion", set_cache_complete, NULL, RSRC_CONF, "Percentage of download to arrive for the cache to force " "complete transfer"), + AP_INIT_TAKE1("CachePurgeMethod", set_cache_purge_method, NULL, RSRC_CONF, + "Name of HTTP method used to purge a cache entry"), {NULL} }; @@ -1036,6 +1176,11 @@ cache_conditional_filter, NULL, AP_FTYPE_CONTENT_SET); + cache_out_purge_handle = + ap_register_output_filter("CACHE_PURGE", + cache_out_purge, + NULL, + AP_FTYPE_CONTENT_SET-1); ap_hook_post_config(cache_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST); } Index: modules/experimental/mod_cache.h =================================================================== RCS file: /home/cvspublic/httpd-2.0/modules/experimental/mod_cache.h,v --- modules/experimental/mod_cache.h 3 Feb 2003 17:31:36 -0000 1.36.2.2 +++ modules/experimental/mod_cache.h 4 Dec 2003 13:54:33 -0000 @@ -130,6 +130,7 @@ #define DEFAULT_CACHE_MAXEXPIRE MSEC_ONE_DAY #define DEFAULT_CACHE_EXPIRE MSEC_ONE_HR #define DEFAULT_CACHE_LMFACTOR (0.1) +#define DEFAULT_PURGE_METHOD ("PURGE") /* Create a set of PROXY_DECLARE(type), PROXY_DECLARE_NONSTD(type) and * PROXY_DECLARE_DATA with appropriate export and import tags for the platform @@ -179,6 +180,9 @@ /** ignore client's requests for uncached responses */ int ignorecachecontrol; int ignorecachecontrol_set; + /* purge method */ + int method; + int method_set; } cache_server_conf; /* cache info information */ @@ -284,7 +288,7 @@ /** * cache_storage.c */ -int cache_remove_url(request_rec *r, const char *types, char *url); +int cache_remove_url(cache_handle_t *h, request_rec *r, const char *types, char *url); int cache_create_entity(request_rec *r, const char *types, char *url, apr_off_t size); int cache_remove_entity(request_rec *r, const char *types, cache_handle_t *h); int cache_select_url(request_rec *r, const char *types, char *url); @@ -332,7 +336,7 @@ (cache_handle_t *h, request_rec *r, const char *type, const char *urlkey)) APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, remove_url, - (const char *type, const char *urlkey)) + (cache_handle_t *h, request_rec *r, const char *type, const char *urlkey)) Index: modules/experimental/mod_disk_cache.c =================================================================== RCS file: /home/cvspublic/httpd-2.0/modules/experimental/mod_disk_cache.c,v --- modules/experimental/mod_disk_cache.c 3 Feb 2003 17:31:36 -0000 1.45.2.1 +++ modules/experimental/mod_disk_cache.c 4 Dec 2003 13:54:33 -0000 @@ -469,6 +469,65 @@ return OK; } +/* + * Removes the cache data addressed by the cache handle + */ +static int remove_url(cache_handle_t *h, request_rec *r, const char *type, const char *key) +{ + cache_object_t *obj; + disk_cache_object_t *dobj; + + /* Look up entity keyed to 'url' */ + if (strcasecmp(type, "disk")) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "disk_cache: Incorrect cache type for key=%s", + key); + return DECLINED; + } + + /* Check whether we have a cache handle at all */ + if (!h) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "disk_cache: No cache handle for key=%s", + key); + return DECLINED; + } + + /* Need the cache object, fail if not present */ + obj = h->cache_obj; + if (!obj) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "disk_cache: No cache object in cache handle " + "for key=%s", + key); + return DECLINED; + } + + /* Now I need the disk cache object, fail if not present */ + dobj = (disk_cache_object_t *) obj->vobj; + if (!dobj) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "disk_cache: No disk cache object in cache " + "handle for key=%s", + key); + return DECLINED; + } + + /* So we continue to remove the header and data files */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "disk_cache: Removing files data=%s, headers=%s", + dobj->datafile, dobj->hdrsfile); + + /* simply remove the files, + * should probably check and guard ??? + */ + apr_file_remove(dobj->datafile, r->pool); + apr_file_remove(dobj->hdrsfile, r->pool); + + /*assume everything is just fine */ + return OK; +} + static int remove_entity(cache_handle_t *h) { /* Null out the cache object pointer so next time we start from scratch */ @@ -884,7 +943,7 @@ /* cache initializer */ cache_hook_create_entity(create_entity, NULL, NULL, APR_HOOK_MIDDLE); cache_hook_open_entity(open_entity, NULL, NULL, APR_HOOK_MIDDLE); -/* cache_hook_remove_entity(remove_entity, NULL, NULL, APR_HOOK_MIDDLE); */ + cache_hook_remove_url(remove_url, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA disk_cache_module = { Index: modules/experimental/mod_mem_cache.c =================================================================== RCS file: /home/cvspublic/httpd-2.0/modules/experimental/mod_mem_cache.c,v --- modules/experimental/mod_mem_cache.c 3 Feb 2003 17:31:37 -0000 1.88.2.2 +++ modules/experimental/mod_mem_cache.c 4 Dec 2003 13:54:34 -0000 @@ -719,7 +719,7 @@ return APR_SUCCESS; } /* Define request processing hook handlers */ -static int remove_url(const char *type, const char *key) +static int remove_url(cache_handle_t *h, request_rec *r, const char *type, const char *key) { cache_object_t *obj;