Index: modules/cache/mod_cache.c =================================================================== --- modules/cache/mod_cache.c (revision 687709) +++ modules/cache/mod_cache.c (working copy) @@ -44,22 +44,46 @@ * add CACHE_SAVE filter * If No: * oh well. + * Does this request invalidate our Cache? (PUT|POST|DELETE) + * attach cache_remove_url_filter and exit. */ static int cache_url_handler(request_rec *r, int lookup) { apr_status_t rv; - const char *auth; cache_provider_list *providers; cache_request_rec *cache; cache_server_conf *conf; apr_bucket_brigade *out; ap_filter_t *next; ap_filter_rec_t *cache_out_handle; + int remove_due_to_method = 0; - /* Delay initialization until we know we are handling a GET */ - if (r->method_number != M_GET) { - return DECLINED; + switch (r->method_number) { + case M_POST: + case M_PUT: + case M_DELETE: + /* If remove_due_to_method is set we have a POST, DELETE or PUT + * request on the resource which according to RFC2616 13.1 causes + * a possible existing cached resource to be invalided and + * ejected from the cache. It is perfectly possible that POST, DELETE or + * PUT on this resource is protected while a GET on this resource that + * caused the resource to be cached is not. So we need not check for + * auth here. + * If remove_due_to_method is set it is guaranteed anyway that we DECLINE + * later, but we need to have cache_select run before to be able to + * eject the cached resource from the cache. + */ + remove_due_to_method = 1; + break; + case M_GET: + /* Are we allowed to serve cached info at all? Check Auth headers + * and get out if we they are set. + */ + if(!apr_table_get(r->headers_in, "Authorization")) + break; + default: + return DECLINED; } conf = (cache_server_conf *) ap_get_module_config(r->server->module_config, @@ -84,21 +108,8 @@ cache->providers = providers; /* - * Are we allowed to serve cached info at all? - */ - - /* find certain cache controlling headers */ - auth = apr_table_get(r->headers_in, "Authorization"); - - /* First things first - does the request allow us to return - * cached information at all? If not, just decline the request. - */ - if (auth) { - return DECLINED; - } - - /* - * Try to serve this request from the cache. + * Try to select and serve this request from the cache. + * If it is an invalidating method, add the remove_url_filter and exit * * If no existing cache file (DECLINED) * add cache_save filter @@ -108,6 +119,18 @@ * return OK */ rv = cache_select(r); + /* + * Eject a possible cached resource from cache if handle a POST, DELETE or PUT + * on this resource. + * Note: cache_remove_url can handle the case when no cached resource + * was found by cache_select. + */ + if (remove_due_to_method) { + cache->remove_url_filter = + ap_add_output_filter_handle(cache_remove_url_filter_handle, + cache, r, r->connection); + return DECLINED; + } if (rv != OK) { if (rv == DECLINED) { if (!lookup) { @@ -884,9 +907,23 @@ ap_remove_output_filter(f); return ap_pass_brigade(f->next, in); } - /* Now remove this cache entry from the cache */ - cache_remove_url(cache, r->pool); + switch(r->method_number) { + case M_POST: + case M_PUT: + case M_DELETE: + /* If it was invalid in some way, cache does not want to notice it. + * This is not specified in RFC, but it is slightly nicer + * and protects against accidental cache evicion. (A user can still force + * it with GET | [Cache-control: max-age=0] ) + */ + if (r->status > 400) break; + case M_GET: + /* Nothing to check remove it from cache.*/ + cache_remove_url(cache, r->pool); + default: + break; + } /* remove ourselves */ ap_remove_output_filter(f); return ap_pass_brigade(f->next, in);