| >| 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 */ };