| >| PURGE http://cachehost/someuri HTTP/1.1
| >| ....
| >
| >Isn't it better to do it as a uri - say - /cache-control - hosted on the
| >proxy?
| >so the above would look like
| >
| >POST /cache-control?purge
| >
| >http://cachehost/someuri1
| >http://cachehost/someuri2
| >http://cachehost/someuri3
| >
| >
| >the advantage is that standard http clients like wget can be used to purge
| >a
| >number of URLs (or based on wild cards) and it does not use any non-rfc
| >methods.
|
| If implemented as a handler it would also give you ACL/auth for free. OTOH
| it gets more difficult to implement the actual deleting from the cache.
| Furthermore you cannot delete specific variants.
A simple minded cache purge (POC) is attached.
1) does not understand variants.
2) takes input as a post request with a number of URLs one per line
3) generates our own request, so should be possible to add vary &
headers
configuration
-------------
<Location /cache>
SetHandler meta_cache
</Location>
invoke e.g
$cat > url.file
/index.html
http://webproxy.india.sun.com/index.html
^D
$wget --post-file url.file 'http://agneyam.india.sun.com:8080/cache?purge'
do let me know how I can improve this.
rahul
/*
** mod_meta_cache.c -- Apache sample meta_cache module
** A simple minded module to purge URLs from cache.
** conf:
** <Location /cache>
** SetHandler meta_cache
** </Location>
**
** Usage:
** $cat > url.file
** /index.html
** http://webproxy.india.sun.com/index.html
** ^D
** $wget --post-file url.file 'http://agneyam.india.sun.com:8080/cache?purge'
**
** License : Apache V2
*/
#include "httpd.h"
#include "http_config.h"
#include "http_request.h"
#include "http_protocol.h"
#include "apr_tables.h"
#include "ap_config.h"
#include "mod_cache.h"
#include "mod_proxy.h"
static const char s_metacache[] = "meta-cache";
extern module AP_MODULE_DECLARE_DATA cache_module;
typedef int (apply_fn)(const char *url, request_rec *r);
static int process_post(request_rec* r,apply_fn url_fn)
{
apr_status_t rv;
apr_bucket_brigade *bb_in;
apr_bucket_brigade *temp_brigade;
bb_in = apr_brigade_create(r->pool, r->connection->bucket_alloc);
rv = ap_get_brigade(r->input_filters, bb_in, AP_MODE_READBYTES,
APR_BLOCK_READ, HUGE_STRING_LEN);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
"Error reading request entity data");
return HTTP_INTERNAL_SERVER_ERROR;
}
temp_brigade = apr_brigade_create(r->pool, r->connection->bucket_alloc);
while(!APR_BRIGADE_EMPTY(bb_in)) {
apr_bucket *bkt_in = APR_BRIGADE_FIRST(bb_in);
apr_bucket *bkt_out;
char line[AP_IOBUFSIZE];
apr_size_t line_len = sizeof(line) - 1;
if(APR_BUCKET_IS_EOS(bkt_in)) {
APR_BUCKET_REMOVE(bkt_in);
break;
}
rv = apr_brigade_split_line(temp_brigade, bb_in,
APR_BLOCK_READ, AP_IOBUFSIZE);
if (rv != APR_SUCCESS) return rv;
rv = apr_brigade_flatten(temp_brigade, line, &line_len);
if (rv != APR_SUCCESS) return rv;
line[line_len] = 0;
if(line[line_len-1] == '\n')
line[line_len-1] = 0;
if (strlen(line)) {
rv = url_fn(line, r);
ap_rputs(line, r);
if (rv != APR_SUCCESS) {
ap_rputs(" : notfound\n", r);
} else {
ap_rputs(" : purged\n", r);
}
}
apr_brigade_cleanup(temp_brigade);
}
apr_brigade_destroy(temp_brigade);
apr_brigade_cleanup(bb_in);
}
int remove_uri(const char *url, request_rec *r);
static int meta_cache_handler(request_rec *r)
{
if (strcmp(r->handler, "meta_cache")) return DECLINED;
r->content_type = "text/html";
if(r->args) {
if (!strncmp(r->args, "purge", sizeof("purge"))) {
process_post(r, remove_uri);
}
}
ap_rputs("meta_cache executed successfully. \n", r);
return OK;
}
/* All this does is to copy over relevant fields of our original reques_rec
* structure to new one, and stick a new URI
* Required as a request_rec is used as a key in the cache interface.
*/
static request_rec *fake_request(const char *new_uri, request_rec *r)
{
request_rec *new = (request_rec *) apr_pcalloc(r->pool, sizeof(request_rec));
new->connection = r->connection;
new->server = r->server;
new->pool = r->pool;
new->method = r->method;
new->method_number = r->method_number;
new->allowed_methods = ap_make_method_list(new->pool, 2);
ap_parse_uri(new, new_uri);
new->request_config = ap_create_request_config(r->pool);
new->per_dir_config = r->server->lookup_defaults;
new->the_request = r->the_request;
new->allowed = r->allowed;
new->status = r->status;
new->assbackwards = r->assbackwards;
new->header_only = r->header_only;
new->protocol = r->protocol;
new->proto_num = r->proto_num;
new->hostname = r->hostname;
new->request_time = r->request_time;
new->main = r->main;
new->headers_in = r->headers_in;
new->headers_out = apr_table_make(r->pool, 12);
new->err_headers_out = r->err_headers_out;
new->subprocess_env = r->subprocess_env;
new->notes = apr_table_make(r->pool, 5);
new->allowed_methods = ap_make_method_list(new->pool, 2);
new->htaccess = r->htaccess;
new->no_cache = r->no_cache;
new->expecting_100 = r->expecting_100;
new->no_local_copy = r->no_local_copy;
new->read_length = r->read_length;
new->vlist_validator = r->vlist_validator;
new->proto_output_filters = r->proto_output_filters;
new->proto_input_filters = r->proto_input_filters;
new->output_filters = new->proto_output_filters;
new->input_filters = new->proto_input_filters;
/* cache_select uses parsed_uri.hostname if it is proxyreq */
if (new->parsed_uri.hostname)
new->proxyreq = 1;
return new;
}
static int remove_uri(const char *url, request_rec *r)
{
apr_status_t rv;
request_rec *preq = fake_request(url, r);
/* make space for the per request config */
cache_provider_list *providers;
cache_server_conf *conf;
cache_request_rec *cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
ap_set_module_config(preq->request_config, &cache_module, cache);
conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
&cache_module);
if (!(providers = ap_cache_get_providers(preq, conf, preq->parsed_uri)))
return DECLINED;
cache->providers = providers;
/* Select one version of URI in the db. the version selected depends on the
* pseudo request that we create. this function updates the request_config with
* required cache data.
* */
rv = cache_select(preq);
if (rv == APR_SUCCESS)
cache_remove_url(cache, r->pool);
return rv;
}
static void meta_cache_register_hooks(apr_pool_t *p)
{
ap_hook_handler(meta_cache_handler, NULL, NULL, APR_HOOK_MIDDLE);
}
/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA meta_cache_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-dir config structures */
NULL, /* merge per-dir config structures */
NULL, /* create per-server config structures */
NULL, /* merge per-server config structures */
NULL, /* table of config file commands */
meta_cache_register_hooks /* register hooks */
};