1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "mod_cache.h"
19 #include "cache_storage.h"
20 #include "cache_util.h"
22 module AP_MODULE_DECLARE_DATA cache_module;
23 APR_OPTIONAL_FN_TYPE(ap_cache_generate_key) *cache_generate_key;
25 /* -------------------------------------------------------------- */
28 /* Handles for cache filters, resolved at startup to eliminate
29 * a name-to-function mapping on each request
31 static ap_filter_rec_t *cache_filter_handle;
32 static ap_filter_rec_t *cache_save_filter_handle;
33 static ap_filter_rec_t *cache_save_subreq_filter_handle;
34 static ap_filter_rec_t *cache_out_filter_handle;
35 static ap_filter_rec_t *cache_out_subreq_filter_handle;
36 static ap_filter_rec_t *cache_remove_url_filter_handle;
37 static ap_filter_rec_t *cache_invalidate_filter_handle;
40 * Entity headers' names
42 static const char *MOD_CACHE_ENTITY_HEADERS[] = {
59 * Can we deliver this request from the cache?
61 * deliver the content by installing the CACHE_OUT filter.
63 * check whether we're allowed to try cache it
65 * add CACHE_SAVE filter
69 * By default, the cache handler runs in the quick handler, bypassing
70 * virtually all server processing and offering the cache its optimal
71 * performance. In this mode, the cache bolts onto the front of the
72 * server, and behaves as a discrete RFC2616 caching proxy
75 * Under certain circumstances, an admin might want to run the cache as
76 * a normal handler instead of a quick handler, allowing the cache to
77 * run after the authorisation hooks, or by allowing fine control over
78 * the placement of the cache in the filter chain. This option comes at
79 * a performance penalty, and should only be used to achieve specific
80 * caching goals where the admin understands what they are doing.
83 static int cache_quick_handler(request_rec *r, int lookup)
87 cache_provider_list *providers;
88 cache_request_rec *cache;
89 apr_bucket_brigade *out;
92 ap_filter_rec_t *cache_out_handle;
93 cache_server_conf *conf;
95 conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
98 /* only run if the quick handler is enabled */
104 * Which cache module (if any) should handle this request?
106 if (!(providers = cache_get_providers(r, conf))) {
110 /* make space for the per request config */
111 cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
113 cache->out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
115 /* save away the possible providers */
116 cache->providers = providers;
119 * Are we allowed to serve cached info at all?
121 if (!ap_cache_check_no_store(cache, r)) {
125 /* find certain cache controlling headers */
126 auth = apr_table_get(r->headers_in, "Authorization");
128 /* First things first - does the request allow us to return
129 * cached information at all? If not, just decline the request.
135 /* Are we PUT/POST/DELETE? If so, prepare to invalidate the cached entities.
137 switch (r->method_number) {
143 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02461)
144 "PUT/POST/DELETE: Adding CACHE_INVALIDATE filter for %s",
147 /* Add cache_invalidate filter to this request to force a
148 * cache entry to be invalidated if the response is
149 * ultimately successful (2xx).
151 ap_add_output_filter_handle(
152 cache_invalidate_filter_handle, cache, r,
163 APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02462) "cache: Method '%s' not cacheable by mod_cache, ignoring: %s", r->method, r->uri);
170 * Try to serve this request from the cache.
172 * If no existing cache file (DECLINED)
173 * add cache_save filter
174 * If cached file (OK)
176 * add cache_out filter
179 rv = cache_select(cache, r);
181 if (rv == DECLINED) {
184 /* try to obtain a cache lock at this point. if we succeed,
185 * we are the first to try and cache this url. if we fail,
186 * it means someone else is already trying to cache this
187 * url, and we should just let the request through to the
188 * backend without any attempt to cache. this stops
189 * duplicated simultaneous attempts to cache an entity.
191 rv = cache_try_lock(conf, cache, r);
192 if (APR_SUCCESS == rv) {
195 * Add cache_save filter to cache this request. Choose
196 * the correct filter by checking if we are a subrequest
200 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
201 r, APLOGNO(00749) "Adding CACHE_SAVE_SUBREQ filter for %s",
203 cache->save_filter = ap_add_output_filter_handle(
204 cache_save_subreq_filter_handle, cache, r,
208 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
209 r, APLOGNO(00750) "Adding CACHE_SAVE filter for %s",
211 cache->save_filter = ap_add_output_filter_handle(
212 cache_save_filter_handle, cache, r,
216 apr_pool_userdata_setn(cache, CACHE_CTX_KEY, NULL, r->pool);
218 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00751)
219 "Adding CACHE_REMOVE_URL filter for %s",
222 /* Add cache_remove_url filter to this request to remove a
223 * stale cache entry if needed. Also put the current cache
224 * request rec in the filter context, as the request that
225 * is available later during running the filter may be
226 * different due to an internal redirect.
228 cache->remove_url_filter = ap_add_output_filter_handle(
229 cache_remove_url_filter_handle, cache, r,
234 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv,
235 r, APLOGNO(00752) "Cache locked for url, not caching "
236 "response: %s", r->uri);
237 /* cache_select() may have added conditional headers */
238 if (cache->stale_headers) {
239 r->headers_in = cache->stale_headers;
245 if (cache->stale_headers) {
246 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
247 r, APLOGNO(00753) "Restoring request headers for %s",
250 r->headers_in = cache->stale_headers;
261 /* we've got a cache hit! tell everyone who cares */
262 cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_HIT,
265 /* if we are a lookup, we are exiting soon one way or another; Restore
268 if (cache->stale_headers) {
269 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00754)
270 "Restoring request headers.");
271 r->headers_in = cache->stale_headers;
275 rv = ap_meets_conditions(r);
277 /* If we are a lookup, we have to return DECLINED as we have no
278 * way of knowing if we will be able to serve the content.
284 /* Return cached status. */
288 /* If we're a lookup, we can exit now instead of serving the content. */
293 /* Serve up the content */
295 /* We are in the quick handler hook, which means that no output
296 * filters have been set. So lets run the insert_filter hook.
298 ap_run_insert_filter(r);
301 * Add cache_out filter to serve this request. Choose
302 * the correct filter by checking if we are a subrequest
306 cache_out_handle = cache_out_subreq_filter_handle;
309 cache_out_handle = cache_out_filter_handle;
311 ap_add_output_filter_handle(cache_out_handle, cache, r, r->connection);
314 * Remove all filters that are before the cache_out filter. This ensures
315 * that we kick off the filter stack with our cache_out filter being the
316 * first in the chain. This make sense because we want to restore things
317 * in the same manner as we saved them.
318 * There may be filters before our cache_out filter, because
320 * 1. We call ap_set_content_type during cache_select. This causes
321 * Content-Type specific filters to be added.
322 * 2. We call the insert_filter hook. This causes filters e.g. like
323 * the ones set with SetOutputFilter to be added.
325 next = r->output_filters;
326 while (next && (next->frec != cache_out_handle)) {
327 ap_remove_output_filter(next);
331 /* kick off the filter stack */
332 out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
333 e = apr_bucket_eos_create(out->bucket_alloc);
334 APR_BRIGADE_INSERT_TAIL(out, e);
336 return ap_pass_brigade_fchk(r, out,
337 "cache_quick_handler(%s): ap_pass_brigade returned",
338 cache->provider_name);
342 * If the two filter handles are present within the filter chain, replace
343 * the last instance of the first filter with the last instance of the
344 * second filter, and return true. If the second filter is not present at
345 * all, the first filter is removed, and false is returned. If neither
346 * filter is present, false is returned and this function does nothing.
347 * If a stop filter is specified, processing will stop once this filter is
350 static int cache_replace_filter(ap_filter_t *next, ap_filter_rec_t *from,
351 ap_filter_rec_t *to, ap_filter_rec_t *stop) {
352 ap_filter_t *ffrom = NULL, *fto = NULL;
353 while (next && next->frec != stop) {
354 if (next->frec == from) {
357 if (next->frec == to) {
363 ffrom->frec = fto->frec;
364 ffrom->ctx = fto->ctx;
365 ap_remove_output_filter(fto);
369 ap_remove_output_filter(ffrom);
375 * Find the given filter, and return it if found, or NULL otherwise.
377 static ap_filter_t *cache_get_filter(ap_filter_t *next, ap_filter_rec_t *rec) {
379 if (next->frec == rec && next->ctx) {
388 * The cache handler is functionally similar to the cache_quick_hander,
389 * however a number of steps that are required by the quick handler are
390 * not required here, as the normal httpd processing has already handled
393 static int cache_handler(request_rec *r)
396 cache_provider_list *providers;
397 cache_request_rec *cache;
398 apr_bucket_brigade *out;
401 ap_filter_rec_t *cache_out_handle;
402 ap_filter_rec_t *cache_save_handle;
403 cache_server_conf *conf;
405 conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
408 /* only run if the quick handler is disabled */
414 * Which cache module (if any) should handle this request?
416 if (!(providers = cache_get_providers(r, conf))) {
420 /* make space for the per request config */
421 cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
423 cache->out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
425 /* save away the possible providers */
426 cache->providers = providers;
429 * Are we allowed to serve cached info at all?
431 if (!ap_cache_check_no_store(cache, r)) {
435 /* Are we PUT/POST/DELETE? If so, prepare to invalidate the cached entities.
437 switch (r->method_number) {
443 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02463)
444 "PUT/POST/DELETE: Adding CACHE_INVALIDATE filter for %s",
447 /* Add cache_invalidate filter to this request to force a
448 * cache entry to be invalidated if the response is
449 * ultimately successful (2xx).
451 ap_add_output_filter_handle(
452 cache_invalidate_filter_handle, cache, r,
463 APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02464) "cache: Method '%s' not cacheable by mod_cache, ignoring: %s", r->method, r->uri);
470 * Try to serve this request from the cache.
472 * If no existing cache file (DECLINED)
473 * add cache_save filter
474 * If cached file (OK)
476 * add cache_out filter
479 rv = cache_select(cache, r);
481 if (rv == DECLINED) {
483 /* try to obtain a cache lock at this point. if we succeed,
484 * we are the first to try and cache this url. if we fail,
485 * it means someone else is already trying to cache this
486 * url, and we should just let the request through to the
487 * backend without any attempt to cache. this stops
488 * duplicated simultaneous attempts to cache an entity.
490 rv = cache_try_lock(conf, cache, r);
491 if (APR_SUCCESS == rv) {
494 * Add cache_save filter to cache this request. Choose
495 * the correct filter by checking if we are a subrequest
499 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
500 r, APLOGNO(00756) "Adding CACHE_SAVE_SUBREQ filter for %s",
502 cache_save_handle = cache_save_subreq_filter_handle;
505 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
506 r, APLOGNO(00757) "Adding CACHE_SAVE filter for %s",
508 cache_save_handle = cache_save_filter_handle;
510 ap_add_output_filter_handle(cache_save_handle, cache, r,
514 * Did the user indicate the precise location of the
515 * CACHE_SAVE filter by inserting the CACHE filter as a
518 * If so, we get cunning and replace CACHE with the
519 * CACHE_SAVE filter. This has the effect of inserting
520 * the CACHE_SAVE filter at the precise location where
521 * the admin wants to cache the content. All filters that
522 * lie before and after the original location of the CACHE
523 * filter will remain in place.
525 if (cache_replace_filter(r->output_filters,
526 cache_filter_handle, cache_save_handle,
527 ap_get_input_filter_handle("SUBREQ_CORE"))) {
528 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
529 r, APLOGNO(00758) "Replacing CACHE with CACHE_SAVE "
530 "filter for %s", r->uri);
533 /* save away the save filter stack */
534 cache->save_filter = cache_get_filter(r->output_filters,
535 cache_save_filter_handle);
537 apr_pool_userdata_setn(cache, CACHE_CTX_KEY, NULL, r->pool);
539 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00759)
540 "Adding CACHE_REMOVE_URL filter for %s",
543 /* Add cache_remove_url filter to this request to remove a
544 * stale cache entry if needed. Also put the current cache
545 * request rec in the filter context, as the request that
546 * is available later during running the filter may be
547 * different due to an internal redirect.
549 cache->remove_url_filter
550 = ap_add_output_filter_handle(
551 cache_remove_url_filter_handle, cache, r,
556 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv,
557 r, APLOGNO(00760) "Cache locked for url, not caching "
558 "response: %s", r->uri);
568 /* we've got a cache hit! tell everyone who cares */
569 cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_HIT,
572 rv = ap_meets_conditions(r);
577 /* Serve up the content */
580 * Add cache_out filter to serve this request. Choose
581 * the correct filter by checking if we are a subrequest
585 cache_out_handle = cache_out_subreq_filter_handle;
588 cache_out_handle = cache_out_filter_handle;
590 ap_add_output_filter_handle(cache_out_handle, cache, r, r->connection);
593 * Did the user indicate the precise location of the CACHE_OUT filter by
594 * inserting the CACHE filter as a marker?
596 * If so, we get cunning and replace CACHE with the CACHE_OUT filters.
597 * This has the effect of inserting the CACHE_OUT filter at the precise
598 * location where the admin wants to cache the content. All filters that
599 * lie *after* the original location of the CACHE filter will remain in
602 if (cache_replace_filter(r->output_filters, cache_filter_handle,
603 cache_out_handle, ap_get_input_filter_handle("SUBREQ_CORE"))) {
604 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
605 r, APLOGNO(00761) "Replacing CACHE with CACHE_OUT filter for %s",
610 * Remove all filters that are before the cache_out filter. This ensures
611 * that we kick off the filter stack with our cache_out filter being the
612 * first in the chain. This make sense because we want to restore things
613 * in the same manner as we saved them.
614 * There may be filters before our cache_out filter, because
616 * 1. We call ap_set_content_type during cache_select. This causes
617 * Content-Type specific filters to be added.
618 * 2. We call the insert_filter hook. This causes filters e.g. like
619 * the ones set with SetOutputFilter to be added.
621 next = r->output_filters;
622 while (next && (next->frec != cache_out_handle)) {
623 ap_remove_output_filter(next);
627 /* kick off the filter stack */
628 out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
629 e = apr_bucket_eos_create(out->bucket_alloc);
630 APR_BRIGADE_INSERT_TAIL(out, e);
631 return ap_pass_brigade_fchk(r, out, "cache(%s): ap_pass_brigade returned",
632 cache->provider_name);
639 * Deliver cached content (headers and body) up the stack.
641 static apr_status_t cache_out_filter(ap_filter_t *f, apr_bucket_brigade *in)
643 request_rec *r = f->r;
644 cache_request_rec *cache = (cache_request_rec *)f->ctx;
647 /* user likely configured CACHE_OUT manually; they should use mod_cache
648 * configuration to do that */
649 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00762)
650 "CACHE/CACHE_OUT filter enabled while caching is disabled, ignoring");
651 ap_remove_output_filter(f);
652 return ap_pass_brigade(f->next, in);
655 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00763)
656 "cache: running CACHE_OUT filter");
658 /* clean out any previous response up to EOS, if any */
659 while (!APR_BRIGADE_EMPTY(in)) {
660 apr_bucket *e = APR_BRIGADE_FIRST(in);
661 if (APR_BUCKET_IS_EOS(e)) {
662 apr_bucket_brigade *bb = apr_brigade_create(r->pool,
663 r->connection->bucket_alloc);
665 /* restore content type of cached response if available */
666 /* Needed especially when stale content gets served. */
667 const char *ct = apr_table_get(cache->handle->resp_hdrs, "Content-Type");
669 ap_set_content_type(r, ct);
672 /* restore status of cached response */
673 r->status = cache->handle->cache_obj->info.status;
675 /* recall_headers() was called in cache_select() */
676 cache->provider->recall_body(cache->handle, r->pool, bb);
677 APR_BRIGADE_PREPEND(in, bb);
679 /* This filter is done once it has served up its content */
680 ap_remove_output_filter(f);
682 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00764)
683 "cache: serving %s", r->uri);
684 return ap_pass_brigade(f->next, in);
687 apr_bucket_delete(e);
694 * Having jumped through all the hoops and decided to cache the
695 * response, call store_body() for each brigade, handling the
696 * case where the provider can't swallow the full brigade. In this
697 * case, we write the brigade we were passed out downstream, and
698 * loop around to try and cache some more until the in brigade is
699 * completely empty. As soon as the out brigade contains eos, call
700 * commit_entity() to finalise the cached element.
702 static int cache_save_store(ap_filter_t *f, apr_bucket_brigade *in,
703 cache_server_conf *conf, cache_request_rec *cache)
705 int rv = APR_SUCCESS;
708 /* pass the brigade in into the cache provider, which is then
709 * expected to move cached buckets to the out brigade, for us
710 * to pass up the filter stack. repeat until in is empty, or
713 while (APR_SUCCESS == rv && !APR_BRIGADE_EMPTY(in)) {
715 rv = cache->provider->store_body(cache->handle, f->r, in, cache->out);
716 if (rv != APR_SUCCESS) {
717 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, f->r, APLOGNO(00765)
718 "cache: Cache provider's store_body failed for URI %s", f->r->uri);
719 ap_remove_output_filter(f);
721 /* give someone else the chance to cache the file */
722 cache_remove_lock(conf, cache, f->r, NULL);
724 /* give up trying to cache, just step out the way */
725 APR_BRIGADE_PREPEND(in, cache->out);
726 return ap_pass_brigade(f->next, in);
730 /* does the out brigade contain eos? if so, we're done, commit! */
731 for (e = APR_BRIGADE_FIRST(cache->out);
732 e != APR_BRIGADE_SENTINEL(cache->out);
733 e = APR_BUCKET_NEXT(e))
735 if (APR_BUCKET_IS_EOS(e)) {
736 rv = cache->provider->commit_entity(cache->handle, f->r);
741 /* conditionally remove the lock as soon as we see the eos bucket */
742 cache_remove_lock(conf, cache, f->r, cache->out);
744 if (APR_BRIGADE_EMPTY(cache->out)) {
745 if (APR_BRIGADE_EMPTY(in)) {
746 /* cache provider wants more data before passing the brigade
747 * upstream, oblige the provider by leaving to fetch more.
752 /* oops, no data out, but not all data read in either, be
753 * safe and stand down to prevent a spin.
755 ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, f->r, APLOGNO(00766)
756 "cache: Cache provider's store_body returned an "
757 "empty brigade, but didn't consume all of the "
758 "input brigade, standing down to prevent a spin");
759 ap_remove_output_filter(f);
761 /* give someone else the chance to cache the file */
762 cache_remove_lock(conf, cache, f->r, NULL);
764 return ap_pass_brigade(f->next, in);
768 rv = ap_pass_brigade(f->next, cache->out);
775 * Sanity check for 304 Not Modified responses, as per RFC2616 Section 10.3.5.
777 static int cache_header_cmp(apr_pool_t *pool, apr_table_t *left,
778 apr_table_t *right, const char *key)
782 if ((h1 = cache_table_getm(pool, left, key))
783 && (h2 = cache_table_getm(pool, right, key)) && (strcmp(h1, h2))) {
793 * Decide whether or not this content should be cached.
794 * If we decide no it should not:
795 * remove the filter from the chain
796 * If we decide yes it should:
797 * Have we already started saving the response?
798 * If we have started, pass the data to the storage manager via store_body
800 * Check to see if we *can* save this particular response.
801 * If we can, call cache_create_entity() and save the headers and body
802 * Finally, pass the data to the next filter (the network or whatever)
804 * After the various failure cases, the cache lock is proactively removed, so
805 * that another request is given the opportunity to attempt to cache without
806 * waiting for a potentially slow client to acknowledge the failure.
809 static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
812 request_rec *r = f->r;
813 cache_request_rec *cache = (cache_request_rec *)f->ctx;
814 cache_server_conf *conf;
815 cache_dir_conf *dconf;
816 cache_control_t control;
817 const char *cc_out, *cl, *pragma;
818 const char *exps, *lastmods, *dates, *etag;
819 apr_time_t exp, date, lastmod, now;
821 cache_info *info = NULL;
822 const char *reason, **eh;
825 apr_table_t *headers;
828 conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
831 /* Setup cache_request_rec */
833 /* user likely configured CACHE_SAVE manually; they should really use
834 * mod_cache configuration to do that
836 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00767)
837 "CACHE/CACHE_SAVE filter enabled while caching is disabled, ignoring");
838 ap_remove_output_filter(f);
839 return ap_pass_brigade(f->next, in);
847 * This section passes the brigades into the cache modules, but only
848 * if the setup section (see below) is complete.
850 if (cache->block_response) {
851 /* We've already sent down the response and EOS. So, ignore
852 * whatever comes now.
857 /* have we already run the cacheability check and set up the
858 * cached file handle?
860 if (cache->in_checked) {
861 return cache_save_store(f, in, conf, cache);
865 * Setup Data in Cache
866 * -------------------
867 * This section opens the cache entity and sets various caching
868 * parameters, and decides whether this URL should be cached at
869 * all. This section is* run before the above section.
872 dconf = ap_get_module_config(r->per_dir_config, &cache_module);
874 /* RFC2616 13.8 Errors or Incomplete Response Cache Behavior:
875 * If a cache receives a 5xx response while attempting to revalidate an
876 * entry, it MAY either forward this response to the requesting client,
877 * or act as if the server failed to respond. In the latter case, it MAY
878 * return a previously received response unless the cached entry
879 * includes the "must-revalidate" cache-control directive (see section
882 * This covers the case where an error was generated behind us, for example
883 * by a backend server via mod_proxy.
885 if (dconf->stale_on_error && r->status >= HTTP_INTERNAL_SERVER_ERROR) {
887 ap_remove_output_filter(cache->remove_url_filter);
889 if (cache->stale_handle
890 && !cache->stale_handle->cache_obj->info.control.must_revalidate
891 && !cache->stale_handle->cache_obj->info.control.proxy_revalidate) {
892 const char *warn_head;
894 /* morph the current save filter into the out filter, and serve from
897 cache->handle = cache->stale_handle;
899 f->frec = cache_out_subreq_filter_handle;
902 f->frec = cache_out_filter_handle;
905 r->headers_out = cache->stale_handle->resp_hdrs;
907 ap_set_content_type(r, apr_table_get(
908 cache->stale_handle->resp_hdrs, "Content-Type"));
910 /* add a revalidation warning */
911 warn_head = apr_table_get(r->err_headers_out, "Warning");
912 if ((warn_head == NULL) ||
913 (ap_strstr_c(warn_head, "111") == NULL)) {
914 apr_table_mergen(r->err_headers_out, "Warning",
915 "111 Revalidation failed");
918 cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_HIT,
919 apr_psprintf(r->pool,
920 "cache hit: %d status; stale content returned",
923 /* give someone else the chance to cache the file */
924 cache_remove_lock(conf, cache, f->r, NULL);
926 /* pass brigade to our morphed out filter */
927 return ap_pass_brigade(f, in);
931 query = cache_use_early_url(r) ? r->parsed_uri.query : r->args;
933 /* read expiry date; if a bad date, then leave it so the client can
936 exps = apr_table_get(r->err_headers_out, "Expires");
938 exps = apr_table_get(r->headers_out, "Expires");
941 exp = apr_date_parse_http(exps);
947 /* read the last-modified date; if the date is bad, then delete it */
948 lastmods = apr_table_get(r->err_headers_out, "Last-Modified");
949 if (lastmods == NULL) {
950 lastmods = apr_table_get(r->headers_out, "Last-Modified");
952 if (lastmods != NULL) {
953 lastmod = apr_date_parse_http(lastmods);
954 if (lastmod == APR_DATE_BAD) {
959 lastmod = APR_DATE_BAD;
962 /* read the etag and cache-control from the entity */
963 etag = apr_table_get(r->err_headers_out, "Etag");
965 etag = apr_table_get(r->headers_out, "Etag");
967 cc_out = cache_table_getm(r->pool, r->err_headers_out, "Cache-Control");
968 pragma = cache_table_getm(r->pool, r->err_headers_out, "Pragma");
969 headers = r->err_headers_out;
970 if (!cc_out && !pragma) {
971 cc_out = cache_table_getm(r->pool, r->headers_out, "Cache-Control");
972 pragma = cache_table_getm(r->pool, r->headers_out, "Pragma");
973 headers = r->headers_out;
976 /* Have we received a 304 response without any headers at all? Fall back to
977 * the original headers in the original cached request.
979 if (r->status == HTTP_NOT_MODIFIED && cache->stale_handle) {
980 if (!cc_out && !pragma) {
981 cc_out = cache_table_getm(r->pool, cache->stale_handle->resp_hdrs,
983 pragma = cache_table_getm(r->pool, cache->stale_handle->resp_hdrs,
987 /* 304 does not contain Content-Type and mod_mime regenerates the
988 * Content-Type based on the r->filename. This would lead to original
989 * Content-Type to be lost (overwriten by whatever mod_mime generates).
990 * We preserves the original Content-Type here. */
991 ap_set_content_type(r, apr_table_get(
992 cache->stale_handle->resp_hdrs, "Content-Type"));
995 /* Parse the cache control header */
996 memset(&control, 0, sizeof(cache_control_t));
997 ap_cache_control(r, &control, cc_out, pragma, headers);
1000 * what responses should we not cache?
1002 * At this point we decide based on the response headers whether it
1003 * is appropriate _NOT_ to cache the data from the server. There are
1004 * a whole lot of conditions that prevent us from caching this data.
1005 * They are tested here one by one to be clear and unambiguous.
1007 if (r->status != HTTP_OK && r->status != HTTP_NON_AUTHORITATIVE
1008 && r->status != HTTP_PARTIAL_CONTENT
1009 && r->status != HTTP_MULTIPLE_CHOICES
1010 && r->status != HTTP_MOVED_PERMANENTLY
1011 && r->status != HTTP_NOT_MODIFIED) {
1012 /* RFC2616 13.4 we are allowed to cache 200, 203, 206, 300, 301 or 410
1013 * We allow the caching of 206, but a cache implementation might choose
1014 * to decline to cache a 206 if it doesn't know how to.
1015 * We include 304 Not Modified here too as this is the origin server
1016 * telling us to serve the cached copy.
1018 if (exps != NULL || cc_out != NULL) {
1019 /* We are also allowed to cache any response given that it has a
1020 * valid Expires or Cache Control header. If we find a either of
1021 * those here, we pass request through the rest of the tests. From
1024 * A response received with any other status code (e.g. status
1025 * codes 302 and 307) MUST NOT be returned in a reply to a
1026 * subsequent request unless there are cache-control directives or
1027 * another header(s) that explicitly allow it. For example, these
1028 * include the following: an Expires header (section 14.21); a
1029 * "max-age", "s-maxage", "must-revalidate", "proxy-revalidate",
1030 * "public" or "private" cache-control directive (section 14.9).
1032 * FIXME: Wrong if cc_out has just an extension we don't know about
1036 reason = apr_psprintf(p, "Response status %d", r->status);
1043 else if (!control.s_maxage && !control.max_age && !dconf->store_expired
1044 && exps != NULL && exp == APR_DATE_BAD) {
1045 /* if a broken Expires header is present, don't cache it
1046 * Unless CC: s-maxage or max-age is present
1048 reason = apr_pstrcat(p, "Broken expires header: ", exps, NULL);
1050 else if (!control.s_maxage && !control.max_age
1051 && !dconf->store_expired && exp != APR_DATE_BAD
1052 && exp < r->request_time) {
1053 /* if a Expires header is in the past, don't cache it
1054 * Unless CC: s-maxage or max-age is present
1056 reason = "Expires header already expired; not cacheable";
1058 else if (!dconf->store_expired && (control.must_revalidate
1059 || control.proxy_revalidate) && (!control.s_maxage_value
1060 || (!control.s_maxage && !control.max_age_value)) && lastmods
1061 == NULL && etag == NULL) {
1062 /* if we're already stale, but can never revalidate, don't cache it */
1064 = "s-maxage or max-age zero and no Last-Modified or Etag; not cacheable";
1066 else if (!conf->ignorequerystring && query && exps == NULL
1067 && !control.max_age && !control.s_maxage) {
1068 /* if a query string is present but no explicit expiration time,
1069 * don't cache it (RFC 2616/13.9 & 13.2.1)
1071 reason = "Query string present but no explicit expiration time";
1073 else if (r->status == HTTP_NOT_MODIFIED &&
1074 !cache->handle && !cache->stale_handle) {
1075 /* if the server said 304 Not Modified but we have no cache
1076 * file - pass this untouched to the user agent, it's not for us.
1078 reason = "HTTP Status 304 Not Modified";
1080 else if (r->status == HTTP_OK && lastmods == NULL && etag == NULL && (exps
1081 == NULL) && (dconf->no_last_mod_ignore == 0) && !control.max_age
1082 && !control.s_maxage) {
1083 /* 200 OK response from HTTP/1.0 and up without Last-Modified,
1084 * Etag, Expires, Cache-Control:max-age, or Cache-Control:s-maxage
1087 /* Note: mod-include clears last_modified/expires/etags - this
1088 * is why we have an optional function for a key-gen ;-)
1090 reason = "No Last-Modified; Etag; Expires; Cache-Control:max-age or Cache-Control:s-maxage headers";
1092 else if (!dconf->store_nostore && control.no_store) {
1093 /* RFC2616 14.9.2 Cache-Control: no-store response
1094 * indicating do not cache, or stop now if you are
1095 * trying to cache it.
1097 reason = "Cache-Control: no-store present";
1099 else if (!dconf->store_private && control.private) {
1100 /* RFC2616 14.9.1 Cache-Control: private response
1101 * this object is marked for this user's eyes only. Behave
1104 reason = "Cache-Control: private present";
1106 else if (apr_table_get(r->headers_in, "Authorization")
1107 && !(control.s_maxage || control.must_revalidate
1108 || control.proxy_revalidate || control.public)) {
1109 /* RFC2616 14.8 Authorisation:
1110 * if authorisation is included in the request, we don't cache,
1111 * but we can cache if the following exceptions are true:
1112 * 1) If Cache-Control: s-maxage is included
1113 * 2) If Cache-Control: must-revalidate is included
1114 * 3) If Cache-Control: public is included
1116 reason = "Authorization required";
1118 else if (ap_find_token(NULL, apr_table_get(r->headers_out, "Vary"), "*")) {
1119 reason = "Vary header contains '*'";
1121 else if (apr_table_get(r->subprocess_env, "no-cache") != NULL) {
1122 reason = "environment variable 'no-cache' is set";
1124 else if (r->no_cache) {
1125 /* or we've been asked not to cache it above */
1126 reason = "r->no_cache present";
1128 else if (cache->stale_handle
1130 != (date = apr_date_parse_http(
1131 apr_table_get(r->headers_out, "Date")))
1132 && date < cache->stale_handle->cache_obj->info.date) {
1135 * 13.12 Cache Replacement:
1137 * Note: a new response that has an older Date header value than
1138 * existing cached responses is not cacheable.
1140 reason = "updated entity is older than cached entity";
1142 /* while this response is not cacheable, the previous response still is */
1143 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02474)
1144 "cache: Removing CACHE_REMOVE_URL filter.");
1145 ap_remove_output_filter(cache->remove_url_filter);
1147 else if (r->status == HTTP_NOT_MODIFIED && cache->stale_handle) {
1148 apr_table_t *left = cache->stale_handle->resp_hdrs;
1149 apr_table_t *right = r->headers_out;
1150 const char *ehs = NULL;
1152 /* and lastly, contradiction checks for revalidated responses
1153 * as per RFC2616 Section 10.3.5
1155 if (cache_header_cmp(r->pool, left, right, "ETag")) {
1158 for (eh = MOD_CACHE_ENTITY_HEADERS; *eh; ++eh) {
1159 if (cache_header_cmp(r->pool, left, right, *eh)) {
1160 ehs = (ehs) ? apr_pstrcat(r->pool, ehs, ", ", *eh, NULL) : *eh;
1164 reason = apr_pstrcat(r->pool, "contradiction: 304 Not Modified; "
1165 "but ", ehs, " modified", NULL);
1170 * Enforce RFC2616 Section 10.3.5, just in case. We caught any
1171 * inconsistencies above.
1173 * If the conditional GET used a strong cache validator (see section
1174 * 13.3.3), the response SHOULD NOT include other entity-headers.
1175 * Otherwise (i.e., the conditional GET used a weak validator), the
1176 * response MUST NOT include other entity-headers; this prevents
1177 * inconsistencies between cached entity-bodies and updated headers.
1179 if (r->status == HTTP_NOT_MODIFIED) {
1180 for (eh = MOD_CACHE_ENTITY_HEADERS; *eh; ++eh) {
1181 apr_table_unset(r->headers_out, *eh);
1185 /* Hold the phone. Some servers might allow us to cache a 2xx, but
1186 * then make their 304 responses non cacheable. RFC2616 says this:
1188 * If a 304 response indicates an entity not currently cached, then
1189 * the cache MUST disregard the response and repeat the request
1190 * without the conditional.
1192 * A 304 response with contradictory headers is technically a
1193 * different entity, to be safe, we remove the entity from the cache.
1195 if (reason && r->status == HTTP_NOT_MODIFIED && cache->stale_handle) {
1197 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02473)
1198 "cache: %s responded with an uncacheable 304, "
1199 "retrying the request %s. Reason: %s",
1200 cache->key, r->unparsed_uri, reason);
1202 /* we've got a cache conditional miss! tell anyone who cares */
1203 cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_MISS,
1204 apr_psprintf(r->pool,
1205 "conditional cache miss: 304 was uncacheable, entity removed: %s",
1208 /* remove the cached entity immediately, we might cache it again */
1209 ap_remove_output_filter(cache->remove_url_filter);
1210 cache_remove_url(cache, r);
1212 /* let someone else attempt to cache */
1213 cache_remove_lock(conf, cache, r, NULL);
1215 /* remove this filter from the chain */
1216 ap_remove_output_filter(f);
1218 /* retry without the conditionals */
1219 apr_table_unset(r->headers_in, "If-Match");
1220 apr_table_unset(r->headers_in, "If-Modified-Since");
1221 apr_table_unset(r->headers_in, "If-None-Match");
1222 apr_table_unset(r->headers_in, "If-Range");
1223 apr_table_unset(r->headers_in, "If-Unmodified-Since");
1225 /* Currently HTTP_NOT_MODIFIED, and after the redirect, handlers won't think to set status to HTTP_OK */
1226 r->status = HTTP_OK;
1227 ap_internal_redirect(r->unparsed_uri, r);
1233 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00768)
1234 "cache: %s not cached for request %s. Reason: %s",
1235 cache->key, r->unparsed_uri, reason);
1237 /* we've got a cache miss! tell anyone who cares */
1238 cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_MISS,
1241 /* remove this filter from the chain */
1242 ap_remove_output_filter(f);
1244 /* remove the lock file unconditionally */
1245 cache_remove_lock(conf, cache, r, NULL);
1247 /* ship the data up the stack */
1248 return ap_pass_brigade(f->next, in);
1251 /* Make it so that we don't execute this path again. */
1252 cache->in_checked = 1;
1254 /* Set the content length if known.
1256 cl = apr_table_get(r->err_headers_out, "Content-Length");
1258 cl = apr_table_get(r->headers_out, "Content-Length");
1262 if (apr_strtoff(&size, cl, &errp, 10) || *errp || size < 0) {
1263 cl = NULL; /* parse error, see next 'if' block */
1268 /* if we don't get the content-length, see if we have all the
1269 * buckets and use their length to calculate the size
1271 int all_buckets_here=0;
1273 for (e = APR_BRIGADE_FIRST(in);
1274 e != APR_BRIGADE_SENTINEL(in);
1275 e = APR_BUCKET_NEXT(e))
1277 if (APR_BUCKET_IS_EOS(e)) {
1281 if (APR_BUCKET_IS_FLUSH(e)) {
1284 if (e->length == (apr_size_t)-1) {
1289 if (!all_buckets_here) {
1294 /* remember content length to check response size against later */
1297 /* It's safe to cache the response.
1299 * There are two possibilities at this point:
1300 * - cache->handle == NULL. In this case there is no previously
1301 * cached entity anywhere on the system. We must create a brand
1302 * new entity and store the response in it.
1303 * - cache->stale_handle != NULL. In this case there is a stale
1304 * entity in the system which needs to be replaced by new
1305 * content (unless the result was 304 Not Modified, which means
1306 * the cached entity is actually fresh, and we should update
1310 /* Did we have a stale cache entry that really is stale?
1312 if (cache->stale_handle) {
1313 if (r->status == HTTP_NOT_MODIFIED) {
1314 /* Oh, hey. It isn't that stale! Yay! */
1315 cache->handle = cache->stale_handle;
1316 info = &cache->handle->cache_obj->info;
1320 /* Oh, well. Toss it. */
1321 cache->provider->remove_entity(cache->stale_handle);
1322 /* Treat the request as if it wasn't conditional. */
1323 cache->stale_handle = NULL;
1325 * Restore the original request headers as they may be needed
1326 * by further output filters like the byterange filter to make
1327 * the correct decisions.
1329 r->headers_in = cache->stale_headers;
1333 /* no cache handle, create a new entity */
1334 if (!cache->handle) {
1335 rv = cache_create_entity(cache, r, size, in);
1336 info = apr_pcalloc(r->pool, sizeof(cache_info));
1337 /* We only set info->status upon the initial creation. */
1338 info->status = r->status;
1342 /* we've got a cache miss! tell anyone who cares */
1343 cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_MISS,
1344 "cache miss: cache unwilling to store response");
1346 /* Caching layer declined the opportunity to cache the response */
1347 ap_remove_output_filter(f);
1348 cache_remove_lock(conf, cache, r, NULL);
1349 return ap_pass_brigade(f->next, in);
1352 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00769)
1353 "cache: Caching url %s for request %s",
1354 cache->key, r->unparsed_uri);
1356 /* We are actually caching this response. So it does not
1357 * make sense to remove this entity any more.
1359 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00770)
1360 "cache: Removing CACHE_REMOVE_URL filter.");
1361 ap_remove_output_filter(cache->remove_url_filter);
1364 * We now want to update the cache file header information with
1365 * the new date, last modified, expire and content length and write
1366 * it away to our cache file. First, we determine these values from
1367 * the response, using heuristics if appropriate.
1369 * In addition, we make HTTP/1.1 age calculations and write them away
1373 /* store away the previously parsed cache control headers */
1374 memcpy(&info->control, &control, sizeof(cache_control_t));
1376 /* Read the date. Generate one if one is not supplied */
1377 dates = apr_table_get(r->err_headers_out, "Date");
1378 if (dates == NULL) {
1379 dates = apr_table_get(r->headers_out, "Date");
1381 if (dates != NULL) {
1382 info->date = apr_date_parse_http(dates);
1385 info->date = APR_DATE_BAD;
1388 now = apr_time_now();
1389 if (info->date == APR_DATE_BAD) { /* No, or bad date */
1390 /* no date header (or bad header)! */
1395 /* set response_time for HTTP/1.1 age calculations */
1396 info->response_time = now;
1398 /* get the request time */
1399 info->request_time = r->request_time;
1401 /* check last-modified date */
1402 if (lastmod != APR_DATE_BAD && lastmod > date) {
1403 /* if it's in the future, then replace by date */
1405 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0,
1406 r, APLOGNO(00771) "cache: Last modified is in the future, "
1407 "replacing with now");
1411 /* CC has priority over Expires. */
1412 if (control.s_maxage || control.max_age) {
1415 x = control.s_maxage ? control.s_maxage_value : control.max_age_value;
1416 x = x * MSEC_ONE_SEC;
1418 if (x < dconf->minex) {
1421 if (x > dconf->maxex) {
1427 /* if no expiry date then
1428 * if Cache-Control: s-maxage
1429 * expiry date = date + smaxage
1430 * if Cache-Control: max-age
1431 * expiry date = date + max-age
1433 * expiry date = date + min((date - lastmod) * factor, maxexpire)
1435 * expire date = date + defaultexpire
1438 if (exp == APR_DATE_BAD) {
1439 if ((lastmod != APR_DATE_BAD) && (lastmod < date)) {
1440 /* if lastmod == date then you get 0*conf->factor which results in
1441 * an expiration time of now. This causes some problems with
1442 * freshness calculations, so we choose the else path...
1444 apr_time_t x = (apr_time_t) ((date - lastmod) * dconf->factor);
1446 if (x < dconf->minex) {
1449 if (x > dconf->maxex) {
1455 exp = date + dconf->defex;
1460 /* We found a stale entry which wasn't really stale. */
1461 if (cache->stale_handle) {
1463 /* RFC 2616 10.3.5 states that entity headers are not supposed
1464 * to be in the 304 response. Therefore, we need to combine the
1465 * response headers with the cached headers *before* we update
1466 * the cached headers.
1468 * However, before doing that, we need to first merge in
1469 * err_headers_out (note that store_headers() below already selects
1470 * the cacheable only headers using ap_cache_cacheable_headers_out(),
1471 * here we want to keep the original headers in r->headers_out and
1472 * forward all of them to the client, including non-cacheable ones).
1474 r->headers_out = cache_merge_headers_out(r);
1475 apr_table_clear(r->err_headers_out);
1477 /* Merge in our cached headers. However, keep any updated values. */
1478 /* take output, overlay on top of cached */
1479 cache_accept_headers(cache->handle, r, r->headers_out,
1480 cache->handle->resp_hdrs, 1);
1483 /* Write away header information to cache. It is possible that we are
1484 * trying to update headers for an entity which has already been cached.
1486 * This may fail, due to an unwritable cache area. E.g. filesystem full,
1487 * permissions problems or a read-only (re)mount. This must be handled
1490 rv = cache->provider->store_headers(cache->handle, r, info);
1492 /* Did we just update the cached headers on a revalidated response?
1494 * If so, we can now decide what to serve to the client. This is done in
1495 * the same way as with a regular response, but conditions are now checked
1496 * against the cached or merged response headers.
1498 if (cache->stale_handle) {
1499 apr_bucket_brigade *bb;
1503 /* Load in the saved status and clear the status line. */
1504 r->status = info->status;
1505 r->status_line = NULL;
1507 /* We're just saving response headers, so we are done. Commit
1508 * the response at this point, unless there was a previous error.
1510 if (rv == APR_SUCCESS) {
1511 rv = cache->provider->commit_entity(cache->handle, r);
1514 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
1516 /* Restore the original request headers and see if we need to
1517 * return anything else than the cached response (ie. the original
1518 * request was conditional).
1520 r->headers_in = cache->stale_headers;
1521 status = ap_meets_conditions(r);
1525 /* Strip the entity headers merged from the cached headers before
1526 * updating the entry (see cache_accept_headers() above).
1528 for (eh = MOD_CACHE_ENTITY_HEADERS; *eh; ++eh) {
1529 apr_table_unset(r->headers_out, *eh);
1532 bkt = apr_bucket_flush_create(bb->bucket_alloc);
1533 APR_BRIGADE_INSERT_TAIL(bb, bkt);
1536 cache->provider->recall_body(cache->handle, r->pool, bb);
1538 bkt = apr_bucket_eos_create(bb->bucket_alloc);
1539 APR_BRIGADE_INSERT_TAIL(bb, bkt);
1542 cache->block_response = 1;
1544 /* Before returning we need to handle the possible case of an
1545 * unwritable cache. Rather than leaving the entity in the cache
1546 * and having it constantly re-validated, now that we have recalled
1547 * the body it is safe to try and remove the url from the cache.
1549 if (rv != APR_SUCCESS) {
1550 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(00772)
1551 "cache: updating headers with store_headers failed. "
1552 "Removing cached url.");
1554 rv = cache->provider->remove_url(cache->stale_handle, r);
1556 /* Probably a mod_cache_disk cache area has been (re)mounted
1557 * read-only, or that there is a permissions problem.
1559 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(00773)
1560 "cache: attempt to remove url from cache unsuccessful.");
1563 /* we've got a cache conditional hit! tell anyone who cares */
1564 cache_run_cache_status(cache->handle, r, r->headers_out,
1565 AP_CACHE_REVALIDATE,
1566 "conditional cache hit: entity refresh failed");
1571 /* we've got a cache conditional hit! tell anyone who cares */
1572 cache_run_cache_status(cache->handle, r, r->headers_out,
1573 AP_CACHE_REVALIDATE,
1574 "conditional cache hit: entity refreshed");
1578 /* let someone else attempt to cache */
1579 cache_remove_lock(conf, cache, r, NULL);
1581 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02971)
1582 "cache: serving %s (revalidated)", r->uri);
1584 return ap_pass_brigade(f->next, bb);
1587 if (rv != APR_SUCCESS) {
1588 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(00774)
1589 "cache: store_headers failed");
1591 /* we've got a cache miss! tell anyone who cares */
1592 cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_MISS,
1593 "cache miss: store_headers failed");
1595 ap_remove_output_filter(f);
1596 cache_remove_lock(conf, cache, r, NULL);
1597 return ap_pass_brigade(f->next, in);
1600 /* we've got a cache miss! tell anyone who cares */
1601 cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_MISS,
1602 "cache miss: attempting entity save");
1604 return cache_save_store(f, in, conf, cache);
1608 * CACHE_REMOVE_URL filter
1609 * -----------------------
1611 * This filter gets added in the quick handler every time the CACHE_SAVE filter
1612 * gets inserted. Its purpose is to remove a confirmed stale cache entry from
1615 * CACHE_REMOVE_URL has to be a protocol filter to ensure that is run even if
1616 * the response is a canned error message, which removes the content filters
1617 * and thus the CACHE_SAVE filter from the chain.
1619 * CACHE_REMOVE_URL expects cache request rec within its context because the
1620 * request this filter runs on can be different from the one whose cache entry
1621 * should be removed, due to internal redirects.
1623 * Note that CACHE_SAVE_URL (as a content-set filter, hence run before the
1624 * protocol filters) will remove this filter if it decides to cache the file.
1625 * Therefore, if this filter is left in, it must mean we need to toss any
1628 static apr_status_t cache_remove_url_filter(ap_filter_t *f,
1629 apr_bucket_brigade *in)
1631 request_rec *r = f->r;
1632 cache_request_rec *cache;
1634 /* Setup cache_request_rec */
1635 cache = (cache_request_rec *) f->ctx;
1638 /* user likely configured CACHE_REMOVE_URL manually; they should really
1639 * use mod_cache configuration to do that. So:
1640 * 1. Remove ourselves
1641 * 2. Do nothing and bail out
1643 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00775)
1644 "cache: CACHE_REMOVE_URL enabled unexpectedly");
1645 ap_remove_output_filter(f);
1646 return ap_pass_brigade(f->next, in);
1649 /* Now remove this cache entry from the cache */
1650 cache_remove_url(cache, r);
1652 /* remove ourselves */
1653 ap_remove_output_filter(f);
1654 return ap_pass_brigade(f->next, in);
1658 * CACHE_INVALIDATE filter
1659 * -----------------------
1661 * This filter gets added in the quick handler should a PUT, POST or DELETE
1662 * method be detected. If the response is successful, we must invalidate any
1663 * cached entity as per RFC2616 section 13.10.
1665 * CACHE_INVALIDATE has to be a protocol filter to ensure that is run even if
1666 * the response is a canned error message, which removes the content filters
1669 * CACHE_INVALIDATE expects cache request rec within its context because the
1670 * request this filter runs on can be different from the one whose cache entry
1671 * should be removed, due to internal redirects.
1673 static apr_status_t cache_invalidate_filter(ap_filter_t *f,
1674 apr_bucket_brigade *in)
1676 request_rec *r = f->r;
1677 cache_request_rec *cache;
1679 /* Setup cache_request_rec */
1680 cache = (cache_request_rec *) f->ctx;
1683 /* user likely configured CACHE_INVALIDATE manually; they should really
1684 * use mod_cache configuration to do that. So:
1685 * 1. Remove ourselves
1686 * 2. Do nothing and bail out
1688 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02465)
1689 "cache: CACHE_INVALIDATE enabled unexpectedly: %s", r->uri);
1693 if (r->status > 299) {
1695 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02466)
1696 "cache: response status to '%s' method is %d (>299), not invalidating cached entity: %s", r->method, r->status, r->uri);
1701 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02467)
1702 "cache: Invalidating all cached entities in response to '%s' request for %s",
1705 cache_invalidate(cache, r);
1707 /* we've got a cache invalidate! tell everyone who cares */
1708 cache_run_cache_status(cache->handle, r, r->headers_out,
1709 AP_CACHE_INVALIDATE, apr_psprintf(r->pool,
1710 "cache invalidated by %s", r->method));
1716 /* remove ourselves */
1717 ap_remove_output_filter(f);
1718 return ap_pass_brigade(f->next, in);
1725 * This filter can be optionally inserted into the filter chain by the admin as
1726 * a marker representing the precise location within the filter chain where
1727 * caching is to be performed.
1729 * When the filter chain is set up in the non-quick version of the URL handler,
1730 * the CACHE filter is replaced by the CACHE_OUT or CACHE_SAVE filter,
1731 * effectively inserting the caching filters at the point indicated by the
1732 * admin. The CACHE filter is then removed.
1734 * This allows caching to be performed before the content is passed to the
1735 * INCLUDES filter, or to a filter that might perform transformations unique
1736 * to the specific request and that would otherwise be non-cacheable.
1738 static apr_status_t cache_filter(ap_filter_t *f, apr_bucket_brigade *in)
1743 (cache_server_conf *) ap_get_module_config(f->r->server->module_config,
1746 /* was the quick handler enabled */
1748 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, APLOGNO(00776)
1749 "cache: CACHE filter was added in quick handler mode and "
1750 "will be ignored: %s", f->r->unparsed_uri);
1752 /* otherwise we may have been bypassed, nothing to see here */
1754 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, APLOGNO(00777)
1755 "cache: CACHE filter was added twice, or was added where "
1756 "the cache has been bypassed and will be ignored: %s",
1757 f->r->unparsed_uri);
1760 /* we are just a marker, so let's just remove ourselves */
1761 ap_remove_output_filter(f);
1762 return ap_pass_brigade(f->next, in);
1766 * If configured, add the status of the caching attempt to the subprocess
1767 * environment, and if configured, to headers in the response.
1769 * The status is saved below the broad category of the status (hit, miss,
1770 * revalidate), as well as a single cache-status key. This can be used for
1771 * conditional logging.
1773 * The status is optionally saved to an X-Cache header, and the detail of
1774 * why a particular cache entry was cached (or not cached) is optionally
1775 * saved to an X-Cache-Detail header. This extra detail is useful for
1776 * service developers who may need to know whether their Cache-Control headers
1777 * are working correctly.
1779 static int cache_status(cache_handle_t *h, request_rec *r,
1780 apr_table_t *headers, ap_cache_status_e status, const char *reason)
1784 (cache_server_conf *) ap_get_module_config(r->server->module_config,
1787 cache_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &cache_module);
1788 int x_cache = 0, x_cache_detail = 0;
1791 case AP_CACHE_HIT: {
1792 apr_table_setn(r->subprocess_env, AP_CACHE_HIT_ENV, reason);
1795 case AP_CACHE_REVALIDATE: {
1796 apr_table_setn(r->subprocess_env, AP_CACHE_REVALIDATE_ENV, reason);
1799 case AP_CACHE_MISS: {
1800 apr_table_setn(r->subprocess_env, AP_CACHE_MISS_ENV, reason);
1803 case AP_CACHE_INVALIDATE: {
1804 apr_table_setn(r->subprocess_env, AP_CACHE_INVALIDATE_ENV, reason);
1809 apr_table_setn(r->subprocess_env, AP_CACHE_STATUS_ENV, reason);
1811 if (dconf && dconf->x_cache_set) {
1812 x_cache = dconf->x_cache;
1815 x_cache = conf->x_cache;
1818 apr_table_setn(headers, "X-Cache", apr_psprintf(r->pool, "%s from %s",
1819 status == AP_CACHE_HIT ? "HIT"
1820 : status == AP_CACHE_REVALIDATE ? "REVALIDATE" : status
1821 == AP_CACHE_INVALIDATE ? "INVALIDATE" : "MISS",
1822 r->server->server_hostname));
1825 if (dconf && dconf->x_cache_detail_set) {
1826 x_cache_detail = dconf->x_cache_detail;
1829 x_cache_detail = conf->x_cache_detail;
1831 if (x_cache_detail) {
1832 apr_table_setn(headers, "X-Cache-Detail", apr_psprintf(r->pool,
1833 "\"%s\" from %s", reason, r->server->server_hostname));
1840 * If an error has occurred, but we have a stale cached entry, restore the
1841 * filter stack from the save filter onwards. The canned error message will
1842 * be discarded in the process, and replaced with the cached response.
1844 static void cache_insert_error_filter(request_rec *r)
1847 cache_dir_conf *dconf;
1849 /* ignore everything except for 5xx errors */
1850 if (r->status < HTTP_INTERNAL_SERVER_ERROR) {
1854 dconf = ap_get_module_config(r->per_dir_config, &cache_module);
1856 if (!dconf->stale_on_error) {
1860 /* RFC2616 13.8 Errors or Incomplete Response Cache Behavior:
1861 * If a cache receives a 5xx response while attempting to revalidate an
1862 * entry, it MAY either forward this response to the requesting client,
1863 * or act as if the server failed to respond. In the latter case, it MAY
1864 * return a previously received response unless the cached entry
1865 * includes the "must-revalidate" cache-control directive (see section
1868 * This covers the case where the error was generated by our server via
1871 apr_pool_userdata_get(&dummy, CACHE_CTX_KEY, r->pool);
1873 cache_request_rec *cache = (cache_request_rec *) dummy;
1875 ap_remove_output_filter(cache->remove_url_filter);
1877 if (cache->stale_handle && cache->save_filter
1878 && !cache->stale_handle->cache_obj->info.control.must_revalidate
1879 && !cache->stale_handle->cache_obj->info.control.proxy_revalidate
1880 && !cache->stale_handle->cache_obj->info.control.s_maxage) {
1881 const char *warn_head;
1884 (cache_server_conf *) ap_get_module_config(r->server->module_config,
1887 /* morph the current save filter into the out filter, and serve from
1890 cache->handle = cache->stale_handle;
1892 cache->save_filter->frec = cache_out_subreq_filter_handle;
1895 cache->save_filter->frec = cache_out_filter_handle;
1898 r->output_filters = cache->save_filter;
1900 r->err_headers_out = cache->stale_handle->resp_hdrs;
1902 /* add a revalidation warning */
1903 warn_head = apr_table_get(r->err_headers_out, "Warning");
1904 if ((warn_head == NULL)
1905 || ap_strstr_c(warn_head, "111") == NULL) {
1906 apr_table_mergen(r->err_headers_out, "Warning",
1907 "111 Revalidation failed");
1910 cache_run_cache_status(
1917 "cache hit: %d status; stale content returned",
1920 /* give someone else the chance to cache the file */
1921 cache_remove_lock(conf, cache, r, NULL);
1929 /* -------------------------------------------------------------- */
1930 /* Setup configurable data */
1932 static void *create_dir_config(apr_pool_t *p, char *dummy)
1934 cache_dir_conf *dconf = apr_pcalloc(p, sizeof(cache_dir_conf));
1936 dconf->no_last_mod_ignore = 0;
1937 dconf->store_expired = 0;
1938 dconf->store_private = 0;
1939 dconf->store_nostore = 0;
1941 /* maximum time to cache a document */
1942 dconf->maxex = DEFAULT_CACHE_MAXEXPIRE;
1943 dconf->minex = DEFAULT_CACHE_MINEXPIRE;
1944 /* default time to cache a document */
1945 dconf->defex = DEFAULT_CACHE_EXPIRE;
1947 /* factor used to estimate Expires date from LastModified date */
1948 dconf->factor = DEFAULT_CACHE_LMFACTOR;
1950 dconf->x_cache = DEFAULT_X_CACHE;
1951 dconf->x_cache_detail = DEFAULT_X_CACHE_DETAIL;
1953 dconf->stale_on_error = DEFAULT_CACHE_STALE_ON_ERROR;
1955 /* array of providers for this URL space */
1956 dconf->cacheenable = apr_array_make(p, 10, sizeof(struct cache_enable));
1961 static void *merge_dir_config(apr_pool_t *p, void *basev, void *addv) {
1962 cache_dir_conf *new = (cache_dir_conf *) apr_pcalloc(p, sizeof(cache_dir_conf));
1963 cache_dir_conf *add = (cache_dir_conf *) addv;
1964 cache_dir_conf *base = (cache_dir_conf *) basev;
1966 new->no_last_mod_ignore = (add->no_last_mod_ignore_set == 0) ? base->no_last_mod_ignore : add->no_last_mod_ignore;
1967 new->no_last_mod_ignore_set = add->no_last_mod_ignore_set || base->no_last_mod_ignore_set;
1969 new->store_expired = (add->store_expired_set == 0) ? base->store_expired : add->store_expired;
1970 new->store_expired_set = add->store_expired_set || base->store_expired_set;
1971 new->store_private = (add->store_private_set == 0) ? base->store_private : add->store_private;
1972 new->store_private_set = add->store_private_set || base->store_private_set;
1973 new->store_nostore = (add->store_nostore_set == 0) ? base->store_nostore : add->store_nostore;
1974 new->store_nostore_set = add->store_nostore_set || base->store_nostore_set;
1976 /* maximum time to cache a document */
1977 new->maxex = (add->maxex_set == 0) ? base->maxex : add->maxex;
1978 new->maxex_set = add->maxex_set || base->maxex_set;
1979 new->minex = (add->minex_set == 0) ? base->minex : add->minex;
1980 new->minex_set = add->minex_set || base->minex_set;
1982 /* default time to cache a document */
1983 new->defex = (add->defex_set == 0) ? base->defex : add->defex;
1984 new->defex_set = add->defex_set || base->defex_set;
1986 /* factor used to estimate Expires date from LastModified date */
1987 new->factor = (add->factor_set == 0) ? base->factor : add->factor;
1988 new->factor_set = add->factor_set || base->factor_set;
1990 new->x_cache = (add->x_cache_set == 0) ? base->x_cache : add->x_cache;
1991 new->x_cache_set = add->x_cache_set || base->x_cache_set;
1992 new->x_cache_detail = (add->x_cache_detail_set == 0) ? base->x_cache_detail
1993 : add->x_cache_detail;
1994 new->x_cache_detail_set = add->x_cache_detail_set
1995 || base->x_cache_detail_set;
1997 new->stale_on_error = (add->stale_on_error_set == 0) ? base->stale_on_error
1998 : add->stale_on_error;
1999 new->stale_on_error_set = add->stale_on_error_set
2000 || base->stale_on_error_set;
2002 new->cacheenable = add->enable_set ? apr_array_append(p, base->cacheenable,
2003 add->cacheenable) : base->cacheenable;
2004 new->enable_set = add->enable_set || base->enable_set;
2005 new->disable = (add->disable_set == 0) ? base->disable : add->disable;
2006 new->disable_set = add->disable_set || base->disable_set;
2011 static void * create_cache_config(apr_pool_t *p, server_rec *s)
2013 cache_server_conf *ps = apr_pcalloc(p, sizeof(cache_server_conf));
2015 /* array of URL prefixes for which caching is enabled */
2016 ps->cacheenable = apr_array_make(p, 10, sizeof(struct cache_enable));
2017 /* array of URL prefixes for which caching is disabled */
2018 ps->cachedisable = apr_array_make(p, 10, sizeof(struct cache_disable));
2019 ps->ignorecachecontrol = 0;
2020 ps->ignorecachecontrol_set = 0;
2021 /* array of headers that should not be stored in cache */
2022 ps->ignore_headers = apr_array_make(p, 10, sizeof(char *));
2023 ps->ignore_headers_set = CACHE_IGNORE_HEADERS_UNSET;
2024 /* flag indicating that query-string should be ignored when caching */
2025 ps->ignorequerystring = 0;
2026 ps->ignorequerystring_set = 0;
2027 /* by default, run in the quick handler */
2030 /* array of identifiers that should not be used for key calculation */
2031 ps->ignore_session_id = apr_array_make(p, 10, sizeof(char *));
2032 ps->ignore_session_id_set = CACHE_IGNORE_SESSION_ID_UNSET;
2033 ps->lock = 0; /* thundering herd lock defaults to off */
2035 ps->lockpath = ap_runtime_dir_relative(p, DEFAULT_CACHE_LOCKPATH);
2036 ps->lockmaxage = apr_time_from_sec(DEFAULT_CACHE_MAXAGE);
2037 ps->x_cache = DEFAULT_X_CACHE;
2038 ps->x_cache_detail = DEFAULT_X_CACHE_DETAIL;
2042 static void * merge_cache_config(apr_pool_t *p, void *basev, void *overridesv)
2044 cache_server_conf *ps = apr_pcalloc(p, sizeof(cache_server_conf));
2045 cache_server_conf *base = (cache_server_conf *) basev;
2046 cache_server_conf *overrides = (cache_server_conf *) overridesv;
2048 /* array of URL prefixes for which caching is disabled */
2049 ps->cachedisable = apr_array_append(p,
2051 overrides->cachedisable);
2052 /* array of URL prefixes for which caching is enabled */
2053 ps->cacheenable = apr_array_append(p,
2055 overrides->cacheenable);
2057 ps->ignorecachecontrol =
2058 (overrides->ignorecachecontrol_set == 0)
2059 ? base->ignorecachecontrol
2060 : overrides->ignorecachecontrol;
2061 ps->ignore_headers =
2062 (overrides->ignore_headers_set == CACHE_IGNORE_HEADERS_UNSET)
2063 ? base->ignore_headers
2064 : overrides->ignore_headers;
2065 ps->ignorequerystring =
2066 (overrides->ignorequerystring_set == 0)
2067 ? base->ignorequerystring
2068 : overrides->ignorequerystring;
2069 ps->ignore_session_id =
2070 (overrides->ignore_session_id_set == CACHE_IGNORE_SESSION_ID_UNSET)
2071 ? base->ignore_session_id
2072 : overrides->ignore_session_id;
2074 (overrides->lock_set == 0)
2078 (overrides->lockpath_set == 0)
2080 : overrides->lockpath;
2082 (overrides->lockmaxage_set == 0)
2084 : overrides->lockmaxage;
2086 (overrides->quick_set == 0)
2090 (overrides->x_cache_set == 0)
2092 : overrides->x_cache;
2093 ps->x_cache_detail =
2094 (overrides->x_cache_detail_set == 0)
2095 ? base->x_cache_detail
2096 : overrides->x_cache_detail;
2098 (overrides->base_uri_set == 0)
2100 : overrides->base_uri;
2104 static const char *set_cache_quick_handler(cmd_parms *parms, void *dummy,
2107 cache_server_conf *conf;
2110 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2113 conf->quick_set = 1;
2118 static const char *set_cache_ignore_no_last_mod(cmd_parms *parms, void *dummy,
2121 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2123 dconf->no_last_mod_ignore = flag;
2124 dconf->no_last_mod_ignore_set = 1;
2129 static const char *set_cache_ignore_cachecontrol(cmd_parms *parms,
2130 void *dummy, int flag)
2132 cache_server_conf *conf;
2135 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2137 conf->ignorecachecontrol = flag;
2138 conf->ignorecachecontrol_set = 1;
2142 static const char *set_cache_store_expired(cmd_parms *parms, void *dummy,
2145 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2147 dconf->store_expired = flag;
2148 dconf->store_expired_set = 1;
2152 static const char *set_cache_store_private(cmd_parms *parms, void *dummy,
2155 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2157 dconf->store_private = flag;
2158 dconf->store_private_set = 1;
2162 static const char *set_cache_store_nostore(cmd_parms *parms, void *dummy,
2165 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2167 dconf->store_nostore = flag;
2168 dconf->store_nostore_set = 1;
2172 static const char *add_ignore_header(cmd_parms *parms, void *dummy,
2175 cache_server_conf *conf;
2179 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2181 if (!strcasecmp(header, "None")) {
2182 /* if header None is listed clear array */
2183 conf->ignore_headers->nelts = 0;
2186 if ((conf->ignore_headers_set == CACHE_IGNORE_HEADERS_UNSET) ||
2187 (conf->ignore_headers->nelts)) {
2188 /* Only add header if no "None" has been found in header list
2190 * (When 'None' is passed, IGNORE_HEADERS_SET && nelts == 0.)
2192 new = (char **)apr_array_push(conf->ignore_headers);
2193 (*new) = (char *)header;
2196 conf->ignore_headers_set = CACHE_IGNORE_HEADERS_SET;
2200 static const char *add_ignore_session_id(cmd_parms *parms, void *dummy,
2201 const char *identifier)
2203 cache_server_conf *conf;
2207 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2209 if (!strcasecmp(identifier, "None")) {
2210 /* if identifier None is listed clear array */
2211 conf->ignore_session_id->nelts = 0;
2214 if ((conf->ignore_session_id_set == CACHE_IGNORE_SESSION_ID_UNSET) ||
2215 (conf->ignore_session_id->nelts)) {
2217 * Only add identifier if no "None" has been found in identifier
2220 new = (char **)apr_array_push(conf->ignore_session_id);
2221 (*new) = (char *)identifier;
2224 conf->ignore_session_id_set = CACHE_IGNORE_SESSION_ID_SET;
2228 static const char *add_cache_enable(cmd_parms *parms, void *dummy,
2232 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2233 cache_server_conf *conf;
2234 struct cache_enable *new;
2236 const char *err = ap_check_cmd_context(parms,
2237 NOT_IN_DIRECTORY|NOT_IN_LIMIT|NOT_IN_FILES);
2243 return apr_psprintf(parms->pool,
2244 "provider (%s) starts with a '/'. Are url and provider switched?",
2252 return apr_psprintf(parms->pool,
2253 "CacheEnable provider (%s) is missing an URL.", type);
2255 if (parms->path && strncmp(parms->path, url, strlen(parms->path))) {
2256 return "When in a Location, CacheEnable must specify a path or an URL below "
2261 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2265 new = apr_array_push(dconf->cacheenable);
2266 dconf->enable_set = 1;
2269 new = apr_array_push(conf->cacheenable);
2273 if (apr_uri_parse(parms->pool, url, &(new->url))) {
2276 if (new->url.path) {
2277 new->pathlen = strlen(new->url.path);
2280 new->url.path = "/";
2285 static const char *add_cache_disable(cmd_parms *parms, void *dummy,
2288 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2289 cache_server_conf *conf;
2290 struct cache_disable *new;
2292 const char *err = ap_check_cmd_context(parms,
2293 NOT_IN_DIRECTORY|NOT_IN_LIMIT|NOT_IN_FILES);
2299 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2303 if (!strcasecmp(url, "on")) {
2305 dconf->disable_set = 1;
2309 return "CacheDisable must be followed by the word 'on' when in a Location.";
2313 if (!url || (url[0] != '/' && !ap_strchr_c(url, ':'))) {
2314 return "CacheDisable must specify a path or an URL.";
2317 new = apr_array_push(conf->cachedisable);
2318 if (apr_uri_parse(parms->pool, url, &(new->url))) {
2321 if (new->url.path) {
2322 new->pathlen = strlen(new->url.path);
2325 new->url.path = "/";
2330 static const char *set_cache_maxex(cmd_parms *parms, void *dummy,
2333 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2335 dconf->maxex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
2336 dconf->maxex_set = 1;
2340 static const char *set_cache_minex(cmd_parms *parms, void *dummy,
2343 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2345 dconf->minex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
2346 dconf->minex_set = 1;
2350 static const char *set_cache_defex(cmd_parms *parms, void *dummy,
2353 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2355 dconf->defex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
2356 dconf->defex_set = 1;
2360 static const char *set_cache_factor(cmd_parms *parms, void *dummy,
2363 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2366 if (sscanf(arg, "%lg", &val) != 1) {
2367 return "CacheLastModifiedFactor value must be a float";
2369 dconf->factor = val;
2370 dconf->factor_set = 1;
2374 static const char *set_cache_ignore_querystring(cmd_parms *parms, void *dummy,
2377 cache_server_conf *conf;
2380 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2382 conf->ignorequerystring = flag;
2383 conf->ignorequerystring_set = 1;
2387 static const char *set_cache_lock(cmd_parms *parms, void *dummy,
2390 cache_server_conf *conf;
2393 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2400 static const char *set_cache_lock_path(cmd_parms *parms, void *dummy,
2403 cache_server_conf *conf;
2406 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2409 conf->lockpath = ap_runtime_dir_relative(parms->pool, arg);
2410 if (!conf->lockpath) {
2411 return apr_pstrcat(parms->pool, "Invalid CacheLockPath path ",
2414 conf->lockpath_set = 1;
2418 static const char *set_cache_lock_maxage(cmd_parms *parms, void *dummy,
2421 cache_server_conf *conf;
2422 apr_int64_t seconds;
2425 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2427 seconds = apr_atoi64(arg);
2429 return "CacheLockMaxAge value must be a non-zero positive integer";
2431 conf->lockmaxage = apr_time_from_sec(seconds);
2432 conf->lockmaxage_set = 1;
2436 static const char *set_cache_x_cache(cmd_parms *parms, void *dummy, int flag)
2440 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2442 dconf->x_cache = flag;
2443 dconf->x_cache_set = 1;
2447 cache_server_conf *conf =
2448 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2451 conf->x_cache = flag;
2452 conf->x_cache_set = 1;
2459 static const char *set_cache_x_cache_detail(cmd_parms *parms, void *dummy, int flag)
2463 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2465 dconf->x_cache_detail = flag;
2466 dconf->x_cache_detail_set = 1;
2470 cache_server_conf *conf =
2471 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2474 conf->x_cache_detail = flag;
2475 conf->x_cache_detail_set = 1;
2482 static const char *set_cache_key_base_url(cmd_parms *parms, void *dummy,
2485 cache_server_conf *conf;
2489 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2491 conf->base_uri = apr_pcalloc(parms->pool, sizeof(apr_uri_t));
2492 rv = apr_uri_parse(parms->pool, arg, conf->base_uri);
2493 if (rv != APR_SUCCESS) {
2494 return apr_psprintf(parms->pool, "Could not parse '%s' as an URL.", arg);
2496 else if (!conf->base_uri->scheme && !conf->base_uri->hostname &&
2497 !conf->base_uri->port_str) {
2498 return apr_psprintf(parms->pool, "URL '%s' must contain at least one of a scheme, a hostname or a port.", arg);
2500 conf->base_uri_set = 1;
2504 static const char *set_cache_stale_on_error(cmd_parms *parms, void *dummy,
2507 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2509 dconf->stale_on_error = flag;
2510 dconf->stale_on_error_set = 1;
2514 static int cache_post_config(apr_pool_t *p, apr_pool_t *plog,
2515 apr_pool_t *ptemp, server_rec *s)
2517 /* This is the means by which unusual (non-unix) os's may find alternate
2518 * means to run a given command (e.g. shebang/registry parsing on Win32)
2520 cache_generate_key = APR_RETRIEVE_OPTIONAL_FN(ap_cache_generate_key);
2521 if (!cache_generate_key) {
2522 cache_generate_key = cache_generate_key_default;
2528 static const command_rec cache_cmds[] =
2531 * Consider a new config directive that enables loading specific cache
2532 * implememtations (like mod_cache_mem, mod_cache_file, etc.).
2533 * Rather than using a LoadModule directive, admin would use something
2534 * like CacheModule mem_cache_module | file_cache_module, etc,
2535 * which would cause the approprpriate cache module to be loaded.
2536 * This is more intuitive that requiring a LoadModule directive.
2539 AP_INIT_TAKE12("CacheEnable", add_cache_enable, NULL, RSRC_CONF|ACCESS_CONF,
2540 "A cache type and partial URL prefix below which "
2541 "caching is enabled"),
2542 AP_INIT_TAKE1("CacheDisable", add_cache_disable, NULL, RSRC_CONF|ACCESS_CONF,
2543 "A partial URL prefix below which caching is disabled"),
2544 AP_INIT_TAKE1("CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF|ACCESS_CONF,
2545 "The maximum time in seconds to cache a document"),
2546 AP_INIT_TAKE1("CacheMinExpire", set_cache_minex, NULL, RSRC_CONF|ACCESS_CONF,
2547 "The minimum time in seconds to cache a document"),
2548 AP_INIT_TAKE1("CacheDefaultExpire", set_cache_defex, NULL, RSRC_CONF|ACCESS_CONF,
2549 "The default time in seconds to cache a document"),
2550 AP_INIT_FLAG("CacheQuickHandler", set_cache_quick_handler, NULL,
2552 "Run the cache in the quick handler, default on"),
2553 AP_INIT_FLAG("CacheIgnoreNoLastMod", set_cache_ignore_no_last_mod, NULL,
2554 RSRC_CONF|ACCESS_CONF,
2555 "Ignore Responses where there is no Last Modified Header"),
2556 AP_INIT_FLAG("CacheIgnoreCacheControl", set_cache_ignore_cachecontrol,
2558 "Ignore requests from the client for uncached content"),
2559 AP_INIT_FLAG("CacheStoreExpired", set_cache_store_expired,
2560 NULL, RSRC_CONF|ACCESS_CONF,
2561 "Ignore expiration dates when populating cache, resulting in "
2562 "an If-Modified-Since request to the backend on retrieval"),
2563 AP_INIT_FLAG("CacheStorePrivate", set_cache_store_private,
2564 NULL, RSRC_CONF|ACCESS_CONF,
2565 "Ignore 'Cache-Control: private' and store private content"),
2566 AP_INIT_FLAG("CacheStoreNoStore", set_cache_store_nostore,
2567 NULL, RSRC_CONF|ACCESS_CONF,
2568 "Ignore 'Cache-Control: no-store' and store sensitive content"),
2569 AP_INIT_ITERATE("CacheIgnoreHeaders", add_ignore_header, NULL, RSRC_CONF,
2570 "A space separated list of headers that should not be "
2571 "stored by the cache"),
2572 AP_INIT_FLAG("CacheIgnoreQueryString", set_cache_ignore_querystring,
2574 "Ignore query-string when caching"),
2575 AP_INIT_ITERATE("CacheIgnoreURLSessionIdentifiers", add_ignore_session_id,
2576 NULL, RSRC_CONF, "A space separated list of session "
2577 "identifiers that should be ignored for creating the key "
2578 "of the cached entity."),
2579 AP_INIT_TAKE1("CacheLastModifiedFactor", set_cache_factor, NULL, RSRC_CONF|ACCESS_CONF,
2580 "The factor used to estimate Expires date from "
2581 "LastModified date"),
2582 AP_INIT_FLAG("CacheLock", set_cache_lock,
2584 "Enable or disable the thundering herd lock."),
2585 AP_INIT_TAKE1("CacheLockPath", set_cache_lock_path, NULL, RSRC_CONF,
2586 "The thundering herd lock path. Defaults to the '"
2587 DEFAULT_CACHE_LOCKPATH "' directory relative to the "
2588 "DefaultRuntimeDir setting."),
2589 AP_INIT_TAKE1("CacheLockMaxAge", set_cache_lock_maxage, NULL, RSRC_CONF,
2590 "Maximum age of any thundering herd lock."),
2591 AP_INIT_FLAG("CacheHeader", set_cache_x_cache, NULL, RSRC_CONF | ACCESS_CONF,
2592 "Add a X-Cache header to responses. Default is off."),
2593 AP_INIT_FLAG("CacheDetailHeader", set_cache_x_cache_detail, NULL,
2594 RSRC_CONF | ACCESS_CONF,
2595 "Add a X-Cache-Detail header to responses. Default is off."),
2596 AP_INIT_TAKE1("CacheKeyBaseURL", set_cache_key_base_url, NULL, RSRC_CONF,
2597 "Override the base URL of reverse proxied cache keys."),
2598 AP_INIT_FLAG("CacheStaleOnError", set_cache_stale_on_error,
2599 NULL, RSRC_CONF|ACCESS_CONF,
2600 "Serve stale content on 5xx errors if present. Defaults to on."),
2604 static void register_hooks(apr_pool_t *p)
2606 /* cache initializer */
2607 /* cache quick handler */
2608 ap_hook_quick_handler(cache_quick_handler, NULL, NULL, APR_HOOK_FIRST);
2610 ap_hook_handler(cache_handler, NULL, NULL, APR_HOOK_REALLY_FIRST);
2612 cache_hook_cache_status(cache_status, NULL, NULL, APR_HOOK_MIDDLE);
2613 /* cache error handler */
2614 ap_hook_insert_error_filter(cache_insert_error_filter, NULL, NULL, APR_HOOK_MIDDLE);
2616 * XXX The cache filters need to run right after the handlers and before
2617 * any other filters. Consider creating AP_FTYPE_CACHE for this purpose.
2619 * Depending on the type of request (subrequest / main request) they
2620 * need to be run before AP_FTYPE_CONTENT_SET / after AP_FTYPE_CONTENT_SET
2621 * filters. Thus create two filter handles for each type:
2622 * cache_save_filter_handle / cache_out_filter_handle to be used by
2624 * cache_save_subreq_filter_handle / cache_out_subreq_filter_handle
2625 * to be run by subrequest
2628 * CACHE is placed into the filter chain at an admin specified location,
2629 * and when the cache_handler is run, the CACHE filter is swapped with
2630 * the CACHE_OUT filter, or CACHE_SAVE filter as appropriate. This has
2631 * the effect of offering optional fine control of where the cache is
2632 * inserted into the filter chain.
2634 cache_filter_handle =
2635 ap_register_output_filter("CACHE",
2640 * CACHE_SAVE must go into the filter chain after a possible DEFLATE
2641 * filter to ensure that the compressed content is stored.
2642 * Incrementing filter type by 1 ensures this happens.
2644 cache_save_filter_handle =
2645 ap_register_output_filter("CACHE_SAVE",
2648 AP_FTYPE_CONTENT_SET+1);
2650 * CACHE_SAVE_SUBREQ must go into the filter chain before SUBREQ_CORE to
2651 * handle subrequsts. Decrementing filter type by 1 ensures this
2654 cache_save_subreq_filter_handle =
2655 ap_register_output_filter("CACHE_SAVE_SUBREQ",
2658 AP_FTYPE_CONTENT_SET-1);
2660 * CACHE_OUT must go into the filter chain after a possible DEFLATE
2661 * filter to ensure that already compressed cache objects do not
2662 * get compressed again. Incrementing filter type by 1 ensures
2665 cache_out_filter_handle =
2666 ap_register_output_filter("CACHE_OUT",
2669 AP_FTYPE_CONTENT_SET+1);
2671 * CACHE_OUT_SUBREQ must go into the filter chain before SUBREQ_CORE to
2672 * handle subrequsts. Decrementing filter type by 1 ensures this
2675 cache_out_subreq_filter_handle =
2676 ap_register_output_filter("CACHE_OUT_SUBREQ",
2679 AP_FTYPE_CONTENT_SET-1);
2680 /* CACHE_REMOVE_URL has to be a protocol filter to ensure that is
2681 * run even if the response is a canned error message, which
2682 * removes the content filters.
2684 cache_remove_url_filter_handle =
2685 ap_register_output_filter("CACHE_REMOVE_URL",
2686 cache_remove_url_filter,
2689 cache_invalidate_filter_handle =
2690 ap_register_output_filter("CACHE_INVALIDATE",
2691 cache_invalidate_filter,
2694 ap_hook_post_config(cache_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
2697 AP_DECLARE_MODULE(cache) =
2699 STANDARD20_MODULE_STUFF,
2700 create_dir_config, /* create per-directory config structure */
2701 merge_dir_config, /* merge per-directory config structures */
2702 create_cache_config, /* create per-server config structure */
2703 merge_cache_config, /* merge per-server config structures */
2704 cache_cmds, /* command apr_table_t */
2709 APR_HOOK_LINK(cache_status)
2712 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(cache, CACHE, int, cache_status,
2713 (cache_handle_t *h, request_rec *r,
2714 apr_table_t *headers, ap_cache_status_e status,
2715 const char *reason), (h, r, headers, status, reason),