@@ -29,6 +29,7 @@ APR_OPTIONAL_FN_TYPE(ap_cache_generate_key) *cache_generate_key;
2929 */
3030static ap_filter_rec_t * cache_save_filter_handle ;
3131static ap_filter_rec_t * cache_out_filter_handle ;
32+ static ap_filter_rec_t * cache_remove_url_filter_handle ;
3233
3334/*
3435 * CACHE handler
@@ -123,6 +124,19 @@ static int cache_url_handler(request_rec *r, int lookup)
123124 /* add cache_save filter to cache this request */
124125 ap_add_output_filter_handle (cache_save_filter_handle , NULL , r ,
125126 r -> connection );
127+
128+ ap_log_error (APLOG_MARK , APLOG_DEBUG , APR_SUCCESS , r -> server ,
129+ "Adding CACHE_REMOVE_URL filter." );
130+
131+ /* Add cache_remove_url filter to this request to remove a
132+ * stale cache entry if needed. Also put the current cache
133+ * request rec in the filter context, as the request that
134+ * is available later during running the filter maybe
135+ * different due to an internal redirect.
136+ */
137+ cache -> remove_url_filter =
138+ ap_add_output_filter_handle (cache_remove_url_filter_handle ,
139+ cache , r , r -> connection );
126140 }
127141 else if (cache -> stale_headers ) {
128142 ap_log_error (APLOG_MARK , APLOG_DEBUG , APR_SUCCESS , r -> server ,
@@ -441,11 +455,6 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
441455 if (reason ) {
442456 ap_log_error (APLOG_MARK , APLOG_DEBUG , 0 , r -> server ,
443457 "cache: %s not cached. Reason: %s" , url , reason );
444- /* remove this object from the cache
445- * BillS Asks.. Why do we need to make this call to remove_url?
446- * leave it in for now..
447- */
448- cache_remove_url (r , url );
449458
450459 /* remove this filter from the chain */
451460 ap_remove_output_filter (f );
@@ -546,6 +555,13 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
546555 ap_log_error (APLOG_MARK , APLOG_DEBUG , 0 , r -> server ,
547556 "cache: Caching url: %s" , url );
548557
558+ /* We are actually caching this response. So it does not
559+ * make sense to remove this entity any more.
560+ */
561+ ap_log_error (APLOG_MARK , APLOG_DEBUG , 0 , r -> server ,
562+ "cache: Removing CACHE_REMOVE_URL filter." );
563+ ap_remove_output_filter (cache -> remove_url_filter );
564+
549565 /*
550566 * We now want to update the cache file header information with
551567 * the new date, last modified, expire and content length and write
@@ -714,6 +730,57 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
714730 return ap_pass_brigade (f -> next , in );
715731}
716732
733+ /*
734+ * CACHE_REMOVE_URL filter
735+ * ---------------
736+ *
737+ * This filter gets added in the quick handler every time the CACHE_SAVE filter
738+ * gets inserted. Its purpose is to remove a confirmed stale cache entry from
739+ * the cache.
740+ *
741+ * CACHE_REMOVE_URL has to be a protocol filter to ensure that is run even if
742+ * the response is a canned error message, which removes the content filters
743+ * and thus the CACHE_SAVE filter from the chain.
744+ *
745+ * CACHE_REMOVE_URL expects cache request rec within its context because the
746+ * request this filter runs on can be different from the one whose cache entry
747+ * should be removed, due to internal redirects.
748+ *
749+ * Note that CACHE_SAVE_URL (as a content-set filter, hence run before the
750+ * protocol filters) will remove this filter if it decides to cache the file.
751+ * Therefore, if this filter is left in, it must mean we need to toss any
752+ * existing files.
753+ */
754+ static int cache_remove_url_filter (ap_filter_t * f , apr_bucket_brigade * in )
755+ {
756+ request_rec * r = f -> r ;
757+ cache_request_rec * cache ;
758+
759+ /* Setup cache_request_rec */
760+ cache = (cache_request_rec * ) f -> ctx ;
761+
762+ if (!cache ) {
763+ /* user likely configured CACHE_REMOVE_URL manually; they should really
764+ * use mod_cache configuration to do that. So:
765+ * 1. Remove ourselves
766+ * 2. Do nothing and bail out
767+ */
768+ ap_log_error (APLOG_MARK , APLOG_DEBUG , 0 , r -> server ,
769+ "cache: CACHE_REMOVE_URL enabled unexpectedly" );
770+ ap_remove_output_filter (f );
771+ return ap_pass_brigade (f -> next , in );
772+ }
773+ /*
774+ * Now remove this cache entry from the cache
775+ */
776+ ap_log_error (APLOG_MARK , APLOG_DEBUG , 0 , r -> server ,
777+ "cache: Removing url %s from the cache" , f -> r -> unparsed_uri );
778+ cache_remove_url (cache , r -> pool );
779+ /* remove ourselves */
780+ ap_remove_output_filter (f );
781+ return ap_pass_brigade (f -> next , in );
782+ }
783+
717784/* -------------------------------------------------------------- */
718785/* Setup configurable data */
719786
@@ -967,6 +1034,7 @@ static int cache_post_config(apr_pool_t *p, apr_pool_t *plog,
9671034 return OK ;
9681035}
9691036
1037+
9701038static const command_rec cache_cmds [] =
9711039{
9721040 /* XXX
@@ -1033,6 +1101,15 @@ static void register_hooks(apr_pool_t *p)
10331101 cache_out_filter ,
10341102 NULL ,
10351103 AP_FTYPE_CONTENT_SET + 1 );
1104+ /* CACHE_REMOVE_URL has to be a protocol filter to ensure that is
1105+ * run even if the response is a canned error message, which
1106+ * removes the content filters.
1107+ */
1108+ cache_remove_url_filter_handle =
1109+ ap_register_output_filter ("CACHE_REMOVE_URL" ,
1110+ cache_remove_url_filter ,
1111+ NULL ,
1112+ AP_FTYPE_PROTOCOL );
10361113 ap_hook_post_config (cache_post_config , NULL , NULL , APR_HOOK_REALLY_FIRST );
10371114}
10381115
0 commit comments