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;
42 * Can we deliver this request from the cache?
44 * deliver the content by installing the CACHE_OUT filter.
46 * check whether we're allowed to try cache it
48 * add CACHE_SAVE filter
52 * By default, the cache handler runs in the quick handler, bypassing
53 * virtually all server processing and offering the cache its optimal
54 * performance. In this mode, the cache bolts onto the front of the
55 * server, and behaves as a discrete RFC2616 caching proxy
58 * Under certain circumstances, an admin might want to run the cache as
59 * a normal handler instead of a quick handler, allowing the cache to
60 * run after the authorisation hooks, or by allowing fine control over
61 * the placement of the cache in the filter chain. This option comes at
62 * a performance penalty, and should only be used to achieve specific
63 * caching goals where the admin understands what they are doing.
66 static int cache_quick_handler(request_rec *r, int lookup)
70 cache_provider_list *providers;
71 cache_request_rec *cache;
72 apr_bucket_brigade *out;
74 ap_filter_rec_t *cache_out_handle;
75 cache_server_conf *conf;
77 /* Delay initialization until we know we are handling a GET */
78 if (r->method_number != M_GET) {
82 conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
85 /* only run if the quick handler is enabled */
91 * Which cache module (if any) should handle this request?
93 if (!(providers = cache_get_providers(r, conf, r->parsed_uri))) {
97 /* make space for the per request config */
98 cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
100 cache->out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
102 /* save away the possible providers */
103 cache->providers = providers;
106 * Are we allowed to serve cached info at all?
109 /* find certain cache controlling headers */
110 auth = apr_table_get(r->headers_in, "Authorization");
112 /* First things first - does the request allow us to return
113 * cached information at all? If not, just decline the request.
120 * Try to serve this request from the cache.
122 * If no existing cache file (DECLINED)
123 * add cache_save filter
124 * If cached file (OK)
126 * add cache_out filter
129 rv = cache_select(cache, r);
131 if (rv == DECLINED) {
134 /* try to obtain a cache lock at this point. if we succeed,
135 * we are the first to try and cache this url. if we fail,
136 * it means someone else is already trying to cache this
137 * url, and we should just let the request through to the
138 * backend without any attempt to cache. this stops
139 * duplicated simultaneous attempts to cache an entity.
141 rv = cache_try_lock(conf, cache, r, NULL);
142 if (APR_SUCCESS == rv) {
145 * Add cache_save filter to cache this request. Choose
146 * the correct filter by checking if we are a subrequest
150 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
152 "Adding CACHE_SAVE_SUBREQ filter for %s",
154 ap_add_output_filter_handle(cache_save_subreq_filter_handle,
155 cache, r, r->connection);
158 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
159 r->server, "Adding CACHE_SAVE filter for %s",
161 ap_add_output_filter_handle(cache_save_filter_handle,
162 cache, r, r->connection);
165 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
166 "Adding CACHE_REMOVE_URL filter for %s",
169 /* Add cache_remove_url filter to this request to remove a
170 * stale cache entry if needed. Also put the current cache
171 * request rec in the filter context, as the request that
172 * is available later during running the filter may be
173 * different due to an internal redirect.
175 cache->remove_url_filter =
176 ap_add_output_filter_handle(cache_remove_url_filter_handle,
177 cache, r, r->connection);
180 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
181 r->server, "Cache locked for url, not caching "
182 "response: %s", r->uri);
186 if (cache->stale_headers) {
187 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
188 r->server, "Restoring request headers for %s",
191 r->headers_in = cache->stale_headers;
197 ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
198 "cache: error returned while checking for cached "
199 "file by '%s' cache", cache->provider_name);
204 /* we've got a cache hit! tell everyone who cares */
205 cache_run_cache_status(cache->handle, r, AP_CACHE_HIT, "cache hit");
207 /* if we are a lookup, we are exiting soon one way or another; Restore
210 if (cache->stale_headers) {
211 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
212 "Restoring request headers.");
213 r->headers_in = cache->stale_headers;
217 rv = ap_meets_conditions(r);
219 /* If we are a lookup, we have to return DECLINED as we have no
220 * way of knowing if we will be able to serve the content.
226 /* Return cached status. */
230 /* If we're a lookup, we can exit now instead of serving the content. */
235 /* Serve up the content */
237 /* We are in the quick handler hook, which means that no output
238 * filters have been set. So lets run the insert_filter hook.
240 ap_run_insert_filter(r);
243 * Add cache_out filter to serve this request. Choose
244 * the correct filter by checking if we are a subrequest
248 cache_out_handle = cache_out_subreq_filter_handle;
251 cache_out_handle = cache_out_filter_handle;
253 ap_add_output_filter_handle(cache_out_handle, cache, r, r->connection);
256 * Remove all filters that are before the cache_out filter. This ensures
257 * that we kick off the filter stack with our cache_out filter being the
258 * first in the chain. This make sense because we want to restore things
259 * in the same manner as we saved them.
260 * There may be filters before our cache_out filter, because
262 * 1. We call ap_set_content_type during cache_select. This causes
263 * Content-Type specific filters to be added.
264 * 2. We call the insert_filter hook. This causes filters e.g. like
265 * the ones set with SetOutputFilter to be added.
267 next = r->output_filters;
268 while (next && (next->frec != cache_out_handle)) {
269 ap_remove_output_filter(next);
273 /* kick off the filter stack */
274 out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
275 rv = ap_pass_brigade(r->output_filters, out);
276 if (rv != APR_SUCCESS) {
277 if (rv != AP_FILTER_ERROR) {
278 ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
279 "cache: error returned while trying to return %s "
281 cache->provider_name);
290 * If the two filter handles are present within the filter chain, replace
291 * the last instance of the first filter with the last instance of the
292 * second filter, and return true. If the second filter is not present at
293 * all, the first filter is removed, and false is returned. If neither
294 * filter is present, false is returned and this function does nothing.
296 static int cache_replace_filter(ap_filter_t *next, ap_filter_rec_t *from,
297 ap_filter_rec_t *to) {
298 ap_filter_t *ffrom = NULL, *fto = NULL;
300 if (next->frec == from && !next->ctx) {
303 if (next->frec == to && !next->ctx) {
309 ffrom->frec = fto->frec;
310 ffrom->ctx = fto->ctx;
311 ap_remove_output_filter(fto);
315 ap_remove_output_filter(ffrom);
321 * The cache handler is functionally similar to the cache_quick_hander,
322 * however a number of steps that are required by the quick handler are
323 * not required here, as the normal httpd processing has already handled
326 static int cache_handler(request_rec *r)
329 cache_provider_list *providers;
330 cache_request_rec *cache;
331 apr_bucket_brigade *out;
333 ap_filter_rec_t *cache_out_handle;
334 ap_filter_rec_t *cache_save_handle;
335 cache_server_conf *conf;
337 /* Delay initialization until we know we are handling a GET */
338 if (r->method_number != M_GET) {
342 conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
345 /* only run if the quick handler is disabled */
351 * Which cache module (if any) should handle this request?
353 if (!(providers = cache_get_providers(r, conf, r->parsed_uri))) {
357 /* make space for the per request config */
358 cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
360 cache->out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
362 /* save away the possible providers */
363 cache->providers = providers;
366 * Try to serve this request from the cache.
368 * If no existing cache file (DECLINED)
369 * add cache_save filter
370 * If cached file (OK)
372 * add cache_out filter
375 rv = cache_select(cache, r);
377 if (rv == DECLINED) {
379 /* try to obtain a cache lock at this point. if we succeed,
380 * we are the first to try and cache this url. if we fail,
381 * it means someone else is already trying to cache this
382 * url, and we should just let the request through to the
383 * backend without any attempt to cache. this stops
384 * duplicated simultaneous attempts to cache an entity.
386 rv = cache_try_lock(conf, cache, r, NULL);
387 if (APR_SUCCESS == rv) {
390 * Add cache_save filter to cache this request. Choose
391 * the correct filter by checking if we are a subrequest
395 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
397 "Adding CACHE_SAVE_SUBREQ filter for %s",
399 cache_save_handle = cache_save_subreq_filter_handle;
402 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
403 r->server, "Adding CACHE_SAVE filter for %s",
405 cache_save_handle = cache_save_filter_handle;
407 ap_add_output_filter_handle(cache_save_handle,
408 cache, r, r->connection);
411 * Did the user indicate the precise location of the
412 * CACHE_SAVE filter by inserting the CACHE filter as a
415 * If so, we get cunning and replace CACHE with the
416 * CACHE_SAVE filter. This has the effect of inserting
417 * the CACHE_SAVE filter at the precise location where
418 * the admin wants to cache the content. All filters that
419 * lie before and after the original location of the CACHE
420 * filter will remain in place.
422 if (cache_replace_filter(r->output_filters,
423 cache_filter_handle, cache_save_handle)) {
424 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
425 r->server, "Replacing CACHE with CACHE_SAVE "
426 "filter for %s", r->uri);
429 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
430 "Adding CACHE_REMOVE_URL filter for %s",
433 /* Add cache_remove_url filter to this request to remove a
434 * stale cache entry if needed. Also put the current cache
435 * request rec in the filter context, as the request that
436 * is available later during running the filter may be
437 * different due to an internal redirect.
439 cache->remove_url_filter =
440 ap_add_output_filter_handle(cache_remove_url_filter_handle,
441 cache, r, r->connection);
445 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
446 r->server, "Cache locked for url, not caching "
447 "response: %s", r->uri);
452 ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
453 "cache: error returned while checking for cached "
454 "file by %s cache", cache->provider_name);
459 /* we've got a cache hit! tell everyone who cares */
460 cache_run_cache_status(cache->handle, r, AP_CACHE_HIT, "cache hit");
462 rv = ap_meets_conditions(r);
467 /* Serve up the content */
470 * Add cache_out filter to serve this request. Choose
471 * the correct filter by checking if we are a subrequest
475 cache_out_handle = cache_out_subreq_filter_handle;
478 cache_out_handle = cache_out_filter_handle;
480 ap_add_output_filter_handle(cache_out_handle, cache, r, r->connection);
483 * Did the user indicate the precise location of the CACHE_OUT filter by
484 * inserting the CACHE filter as a marker?
486 * If so, we get cunning and replace CACHE with the CACHE_OUT filters.
487 * This has the effect of inserting the CACHE_OUT filter at the precise
488 * location where the admin wants to cache the content. All filters that
489 * lie *after* the original location of the CACHE filter will remain in
492 if (cache_replace_filter(r->output_filters, cache_filter_handle, cache_out_handle)) {
493 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
494 r->server, "Replacing CACHE with CACHE_OUT filter for %s",
499 * Remove all filters that are before the cache_out filter. This ensures
500 * that we kick off the filter stack with our cache_out filter being the
501 * first in the chain. This make sense because we want to restore things
502 * in the same manner as we saved them.
503 * There may be filters before our cache_out filter, because
505 * 1. We call ap_set_content_type during cache_select. This causes
506 * Content-Type specific filters to be added.
507 * 2. We call the insert_filter hook. This causes filters e.g. like
508 * the ones set with SetOutputFilter to be added.
510 next = r->output_filters;
511 while (next && (next->frec != cache_out_handle)) {
512 ap_remove_output_filter(next);
516 /* kick off the filter stack */
517 out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
518 rv = ap_pass_brigade(r->output_filters, out);
519 if (rv != APR_SUCCESS) {
520 if (rv != AP_FILTER_ERROR) {
521 ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
522 "cache: error returned while trying to return %s "
524 cache->provider_name);
536 * Deliver cached content (headers and body) up the stack.
538 static int cache_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
540 request_rec *r = f->r;
541 cache_request_rec *cache = (cache_request_rec *)f->ctx;
544 /* user likely configured CACHE_OUT manually; they should use mod_cache
545 * configuration to do that */
546 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
547 "CACHE/CACHE_OUT filter enabled while caching is disabled, ignoring");
548 ap_remove_output_filter(f);
549 return ap_pass_brigade(f->next, bb);
552 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
553 "cache: running CACHE_OUT filter");
555 /* restore status of cached response */
556 /* XXX: This exposes a bug in mem_cache, since it does not
557 * restore the status into it's handle. */
558 r->status = cache->handle->cache_obj->info.status;
560 /* recall_headers() was called in cache_select() */
561 cache->provider->recall_body(cache->handle, r->pool, bb);
563 /* This filter is done once it has served up its content */
564 ap_remove_output_filter(f);
566 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
567 "cache: serving %s", r->uri);
568 return ap_pass_brigade(f->next, bb);
572 * Having jumped through all the hoops and decided to cache the
573 * response, call store_body() for each brigade, handling the
574 * case where the provider can't swallow the full brigade. In this
575 * case, we write the brigade we were passed out downstream, and
576 * loop around to try and cache some more until the in brigade is
577 * completely empty. As soon as the out brigade contains eos, call
578 * commit_entity() to finalise the cached element.
580 static int cache_save_store(ap_filter_t *f, apr_bucket_brigade *in,
581 cache_server_conf *conf, cache_request_rec *cache)
583 int rv = APR_SUCCESS;
586 /* pass the brigade in into the cache provider, which is then
587 * expected to move cached buckets to the out brigade, for us
588 * to pass up the filter stack. repeat until in is empty, or
591 while (APR_SUCCESS == rv && !APR_BRIGADE_EMPTY(in)) {
593 rv = cache->provider->store_body(cache->handle, f->r, in, cache->out);
594 if (rv != APR_SUCCESS) {
595 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, f->r->server,
596 "cache: Cache provider's store_body failed!");
597 ap_remove_output_filter(f);
599 /* give someone else the chance to cache the file */
600 cache_remove_lock(conf, cache, f->r, cache->handle ?
601 (char *)cache->handle->cache_obj->key : NULL, NULL);
603 /* give up trying to cache, just step out the way */
604 APR_BRIGADE_PREPEND(in, cache->out);
605 return ap_pass_brigade(f->next, in);
609 /* does the out brigade contain eos? if so, we're done, commit! */
610 for (e = APR_BRIGADE_FIRST(cache->out);
611 e != APR_BRIGADE_SENTINEL(cache->out);
612 e = APR_BUCKET_NEXT(e))
614 if (APR_BUCKET_IS_EOS(e)) {
615 rv = cache->provider->commit_entity(cache->handle, f->r);
620 /* conditionally remove the lock as soon as we see the eos bucket */
621 cache_remove_lock(conf, cache, f->r, cache->handle ?
622 (char *)cache->handle->cache_obj->key : NULL, cache->out);
624 if (APR_BRIGADE_EMPTY(cache->out)) {
625 if (APR_BRIGADE_EMPTY(in)) {
626 /* cache provider wants more data before passing the brigade
627 * upstream, oblige the provider by leaving to fetch more.
632 /* oops, no data out, but not all data read in either, be
633 * safe and stand down to prevent a spin.
635 ap_log_error(APLOG_MARK, APLOG_WARNING, rv, f->r->server,
636 "cache: Cache provider's store_body returned an "
637 "empty brigade, but didn't consume all of the"
638 "input brigade, standing down to prevent a spin");
639 ap_remove_output_filter(f);
641 /* give someone else the chance to cache the file */
642 cache_remove_lock(conf, cache, f->r, cache->handle ?
643 (char *)cache->handle->cache_obj->key : NULL, NULL);
645 return ap_pass_brigade(f->next, in);
649 rv = ap_pass_brigade(f->next, cache->out);
659 * Decide whether or not this content should be cached.
660 * If we decide no it should not:
661 * remove the filter from the chain
662 * If we decide yes it should:
663 * Have we already started saving the response?
664 * If we have started, pass the data to the storage manager via store_body
666 * Check to see if we *can* save this particular response.
667 * If we can, call cache_create_entity() and save the headers and body
668 * Finally, pass the data to the next filter (the network or whatever)
670 * After the various failure cases, the cache lock is proactively removed, so
671 * that another request is given the opportunity to attempt to cache without
672 * waiting for a potentially slow client to acknowledge the failure.
675 static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
678 request_rec *r = f->r;
679 cache_request_rec *cache = (cache_request_rec *)f->ctx;
680 cache_server_conf *conf;
681 const char *cc_out, *cl;
682 const char *exps, *lastmods, *dates, *etag;
683 apr_time_t exp, date, lastmod, now;
685 cache_info *info = NULL;
690 conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
693 /* Setup cache_request_rec */
695 /* user likely configured CACHE_SAVE manually; they should really use
696 * mod_cache configuration to do that
698 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
699 "CACHE/CACHE_SAVE filter enabled while caching is disabled, ignoring");
700 ap_remove_output_filter(f);
701 return ap_pass_brigade(f->next, in);
709 * This section passes the brigades into the cache modules, but only
710 * if the setup section (see below) is complete.
712 if (cache->block_response) {
713 /* We've already sent down the response and EOS. So, ignore
714 * whatever comes now.
719 /* have we already run the cachability check and set up the
720 * cached file handle?
722 if (cache->in_checked) {
723 return cache_save_store(f, in, conf, cache);
727 * Setup Data in Cache
728 * -------------------
729 * This section opens the cache entity and sets various caching
730 * parameters, and decides whether this URL should be cached at
731 * all. This section is* run before the above section.
734 /* read expiry date; if a bad date, then leave it so the client can
737 exps = apr_table_get(r->err_headers_out, "Expires");
739 exps = apr_table_get(r->headers_out, "Expires");
742 if (APR_DATE_BAD == (exp = apr_date_parse_http(exps))) {
750 /* read the last-modified date; if the date is bad, then delete it */
751 lastmods = apr_table_get(r->err_headers_out, "Last-Modified");
752 if (lastmods == NULL) {
753 lastmods = apr_table_get(r->headers_out, "Last-Modified");
755 if (lastmods != NULL) {
756 lastmod = apr_date_parse_http(lastmods);
757 if (lastmod == APR_DATE_BAD) {
762 lastmod = APR_DATE_BAD;
765 /* read the etag and cache-control from the entity */
766 etag = apr_table_get(r->err_headers_out, "Etag");
768 etag = apr_table_get(r->headers_out, "Etag");
770 cc_out = apr_table_get(r->err_headers_out, "Cache-Control");
771 if (cc_out == NULL) {
772 cc_out = apr_table_get(r->headers_out, "Cache-Control");
776 * what responses should we not cache?
778 * At this point we decide based on the response headers whether it
779 * is appropriate _NOT_ to cache the data from the server. There are
780 * a whole lot of conditions that prevent us from caching this data.
781 * They are tested here one by one to be clear and unambiguous.
783 if (r->status != HTTP_OK && r->status != HTTP_NON_AUTHORITATIVE
784 && r->status != HTTP_PARTIAL_CONTENT
785 && r->status != HTTP_MULTIPLE_CHOICES
786 && r->status != HTTP_MOVED_PERMANENTLY
787 && r->status != HTTP_NOT_MODIFIED) {
788 /* RFC2616 13.4 we are allowed to cache 200, 203, 206, 300, 301 or 410
789 * We allow the caching of 206, but a cache implementation might choose
790 * to decline to cache a 206 if it doesn't know how to.
791 * We include 304 Not Modified here too as this is the origin server
792 * telling us to serve the cached copy.
794 if (exps != NULL || cc_out != NULL) {
795 /* We are also allowed to cache any response given that it has a
796 * valid Expires or Cache Control header. If we find a either of
797 * those here, we pass request through the rest of the tests. From
800 * A response received with any other status code (e.g. status
801 * codes 302 and 307) MUST NOT be returned in a reply to a
802 * subsequent request unless there are cache-control directives or
803 * another header(s) that explicitly allow it. For example, these
804 * include the following: an Expires header (section 14.21); a
805 * "max-age", "s-maxage", "must-revalidate", "proxy-revalidate",
806 * "public" or "private" cache-control directive (section 14.9).
810 reason = apr_psprintf(p, "Response status %d", r->status);
817 else if (exps != NULL && exp == APR_DATE_BAD) {
818 /* if a broken Expires header is present, don't cache it */
819 reason = apr_pstrcat(p, "Broken expires header: ", exps, NULL);
821 else if (!conf->store_expired && exp != APR_DATE_BAD
822 && exp < r->request_time)
824 /* if a Expires header is in the past, don't cache it */
825 reason = "Expires header already expired; not cacheable";
827 else if (!conf->ignorequerystring && r->parsed_uri.query && exps == NULL &&
828 !ap_cache_liststr(NULL, cc_out, "max-age", NULL) &&
829 !ap_cache_liststr(NULL, cc_out, "s-maxage", NULL)) {
830 /* if a query string is present but no explicit expiration time,
831 * don't cache it (RFC 2616/13.9 & 13.2.1)
833 reason = "Query string present but no explicit expiration time";
835 else if (r->status == HTTP_NOT_MODIFIED &&
836 !cache->handle && !cache->stale_handle) {
837 /* if the server said 304 Not Modified but we have no cache
838 * file - pass this untouched to the user agent, it's not for us.
840 reason = "HTTP Status 304 Not Modified";
842 else if (r->status == HTTP_OK && lastmods == NULL && etag == NULL
843 && (exps == NULL) && (conf->no_last_mod_ignore ==0) &&
844 !ap_cache_liststr(NULL, cc_out, "max-age", NULL) &&
845 !ap_cache_liststr(NULL, cc_out, "s-maxage", NULL)) {
846 /* 200 OK response from HTTP/1.0 and up without Last-Modified,
847 * Etag, Expires, Cache-Control:max-age, or Cache-Control:s-maxage
850 /* Note: mod-include clears last_modified/expires/etags - this
851 * is why we have an optional function for a key-gen ;-)
853 reason = "No Last-Modified; Etag; Expires; Cache-Control:max-age or Cache-Control:s-maxage headers";
855 else if (!conf->store_nostore &&
856 ap_cache_liststr(NULL, cc_out, "no-store", NULL)) {
857 /* RFC2616 14.9.2 Cache-Control: no-store response
858 * indicating do not cache, or stop now if you are
859 * trying to cache it.
861 /* FIXME: The Cache-Control: no-store could have come in on a 304,
862 * FIXME: while the original request wasn't conditional. IOW, we
863 * FIXME: made the the request conditional earlier to revalidate
864 * FIXME: our cached response.
866 reason = "Cache-Control: no-store present";
868 else if (!conf->store_private &&
869 ap_cache_liststr(NULL, cc_out, "private", NULL)) {
870 /* RFC2616 14.9.1 Cache-Control: private response
871 * this object is marked for this user's eyes only. Behave
874 /* FIXME: See above (no-store) */
875 reason = "Cache-Control: private present";
877 else if (apr_table_get(r->headers_in, "Authorization") != NULL
878 && !(ap_cache_liststr(NULL, cc_out, "s-maxage", NULL)
879 || ap_cache_liststr(NULL, cc_out, "must-revalidate", NULL)
880 || ap_cache_liststr(NULL, cc_out, "public", NULL))) {
881 /* RFC2616 14.8 Authorisation:
882 * if authorisation is included in the request, we don't cache,
883 * but we can cache if the following exceptions are true:
884 * 1) If Cache-Control: s-maxage is included
885 * 2) If Cache-Control: must-revalidate is included
886 * 3) If Cache-Control: public is included
888 reason = "Authorization required";
890 else if (ap_cache_liststr(NULL,
891 apr_table_get(r->headers_out, "Vary"),
893 reason = "Vary header contains '*'";
895 else if (apr_table_get(r->subprocess_env, "no-cache") != NULL) {
896 reason = "environment variable 'no-cache' is set";
898 else if (r->no_cache) {
899 /* or we've been asked not to cache it above */
900 reason = "r->no_cache present";
903 /* Hold the phone. Some servers might allow us to cache a 2xx, but
904 * then make their 304 responses non cacheable. This leaves us in a
905 * sticky position. If the 304 is in answer to our own conditional
906 * request, we cannot send this 304 back to the client because the
907 * client isn't expecting it. Instead, our only option is to respect
908 * the answer to the question we asked (has it changed, answer was
909 * no) and return the cached item to the client, and then respect
910 * the uncacheable nature of this 304 by allowing the remove_url
911 * filter to kick in and remove the cached entity.
913 if (reason && r->status == HTTP_NOT_MODIFIED &&
914 cache->stale_handle) {
915 apr_bucket_brigade *bb;
919 cache->handle = cache->stale_handle;
920 info = &cache->handle->cache_obj->info;
922 /* Load in the saved status and clear the status line. */
923 r->status = info->status;
924 r->status_line = NULL;
926 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
928 r->headers_in = cache->stale_headers;
929 status = ap_meets_conditions(r);
933 bkt = apr_bucket_flush_create(bb->bucket_alloc);
934 APR_BRIGADE_INSERT_TAIL(bb, bkt);
937 cache->provider->recall_body(cache->handle, r->pool, bb);
940 cache->block_response = 1;
942 /* we've got a cache conditional hit! tell anyone who cares */
943 cache_run_cache_status(
949 "conditional cache hit: 304 was uncacheable though (%s); entity removed",
952 /* let someone else attempt to cache */
953 cache_remove_lock(conf, cache, r, cache->handle ?
954 (char *)cache->handle->cache_obj->key : NULL, NULL);
956 return ap_pass_brigade(f->next, bb);
960 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
961 "cache: %s not cached. Reason: %s", r->unparsed_uri,
964 /* we've got a cache miss! tell anyone who cares */
965 cache_run_cache_status(cache->handle, r, AP_CACHE_MISS, reason);
967 /* remove this filter from the chain */
968 ap_remove_output_filter(f);
970 /* remove the lock file unconditionally */
971 cache_remove_lock(conf, cache, r, cache->handle ?
972 (char *)cache->handle->cache_obj->key : NULL, NULL);
974 /* ship the data up the stack */
975 return ap_pass_brigade(f->next, in);
978 /* Make it so that we don't execute this path again. */
979 cache->in_checked = 1;
981 /* Set the content length if known.
983 cl = apr_table_get(r->err_headers_out, "Content-Length");
985 cl = apr_table_get(r->headers_out, "Content-Length");
989 if (apr_strtoff(&size, cl, &errp, 10) || *errp || size < 0) {
990 cl = NULL; /* parse error, see next 'if' block */
995 /* if we don't get the content-length, see if we have all the
996 * buckets and use their length to calculate the size
998 int all_buckets_here=0;
1000 for (e = APR_BRIGADE_FIRST(in);
1001 e != APR_BRIGADE_SENTINEL(in);
1002 e = APR_BUCKET_NEXT(e))
1004 if (APR_BUCKET_IS_EOS(e)) {
1008 if (APR_BUCKET_IS_FLUSH(e)) {
1011 if (e->length == (apr_size_t)-1) {
1016 if (!all_buckets_here) {
1021 /* remember content length to check response size against later */
1024 /* It's safe to cache the response.
1026 * There are two possiblities at this point:
1027 * - cache->handle == NULL. In this case there is no previously
1028 * cached entity anywhere on the system. We must create a brand
1029 * new entity and store the response in it.
1030 * - cache->stale_handle != NULL. In this case there is a stale
1031 * entity in the system which needs to be replaced by new
1032 * content (unless the result was 304 Not Modified, which means
1033 * the cached entity is actually fresh, and we should update
1037 /* Did we have a stale cache entry that really is stale?
1039 if (cache->stale_handle) {
1040 if (r->status == HTTP_NOT_MODIFIED) {
1041 /* Oh, hey. It isn't that stale! Yay! */
1042 cache->handle = cache->stale_handle;
1043 info = &cache->handle->cache_obj->info;
1047 /* Oh, well. Toss it. */
1048 cache->provider->remove_entity(cache->stale_handle);
1049 /* Treat the request as if it wasn't conditional. */
1050 cache->stale_handle = NULL;
1052 * Restore the original request headers as they may be needed
1053 * by further output filters like the byterange filter to make
1054 * the correct decisions.
1056 r->headers_in = cache->stale_headers;
1060 /* no cache handle, create a new entity */
1061 if (!cache->handle) {
1062 rv = cache_create_entity(cache, r, size, in);
1063 info = apr_pcalloc(r->pool, sizeof(cache_info));
1064 /* We only set info->status upon the initial creation. */
1065 info->status = r->status;
1069 /* we've got a cache miss! tell anyone who cares */
1070 cache_run_cache_status(cache->handle, r, AP_CACHE_MISS,
1071 "cache miss: create_entity failed");
1073 /* Caching layer declined the opportunity to cache the response */
1074 ap_remove_output_filter(f);
1075 cache_remove_lock(conf, cache, r, cache->handle ?
1076 (char *)cache->handle->cache_obj->key : NULL, NULL);
1077 return ap_pass_brigade(f->next, in);
1080 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1081 "cache: Caching url: %s", r->unparsed_uri);
1083 /* We are actually caching this response. So it does not
1084 * make sense to remove this entity any more.
1086 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1087 "cache: Removing CACHE_REMOVE_URL filter.");
1088 ap_remove_output_filter(cache->remove_url_filter);
1091 * We now want to update the cache file header information with
1092 * the new date, last modified, expire and content length and write
1093 * it away to our cache file. First, we determine these values from
1094 * the response, using heuristics if appropriate.
1096 * In addition, we make HTTP/1.1 age calculations and write them away
1100 /* Read the date. Generate one if one is not supplied */
1101 dates = apr_table_get(r->err_headers_out, "Date");
1102 if (dates == NULL) {
1103 dates = apr_table_get(r->headers_out, "Date");
1105 if (dates != NULL) {
1106 info->date = apr_date_parse_http(dates);
1109 info->date = APR_DATE_BAD;
1112 now = apr_time_now();
1113 if (info->date == APR_DATE_BAD) { /* No, or bad date */
1114 /* no date header (or bad header)! */
1119 /* set response_time for HTTP/1.1 age calculations */
1120 info->response_time = now;
1122 /* get the request time */
1123 info->request_time = r->request_time;
1125 /* check last-modified date */
1126 if (lastmod != APR_DATE_BAD && lastmod > date) {
1127 /* if it's in the future, then replace by date */
1130 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
1132 "cache: Last modified is in the future, "
1133 "replacing with now");
1136 /* if no expiry date then
1137 * if Cache-Control: max-age
1138 * expiry date = date + max-age
1140 * expiry date = date + min((date - lastmod) * factor, maxexpire)
1142 * expire date = date + defaultexpire
1144 if (exp == APR_DATE_BAD) {
1147 if (ap_cache_liststr(r->pool, cc_out, "max-age", &max_age_val) &&
1148 max_age_val != NULL) {
1152 x = apr_atoi64(max_age_val);
1157 x = x * MSEC_ONE_SEC;
1159 if (x < conf->minex) {
1162 if (x > conf->maxex) {
1167 else if ((lastmod != APR_DATE_BAD) && (lastmod < date)) {
1168 /* if lastmod == date then you get 0*conf->factor which results in
1169 * an expiration time of now. This causes some problems with
1170 * freshness calculations, so we choose the else path...
1172 apr_time_t x = (apr_time_t) ((date - lastmod) * conf->factor);
1174 if (x < conf->minex) {
1177 if (x > conf->maxex) {
1183 exp = date + conf->defex;
1188 /* We found a stale entry which wasn't really stale. */
1189 if (cache->stale_handle) {
1190 /* Load in the saved status and clear the status line. */
1191 r->status = info->status;
1192 r->status_line = NULL;
1194 /* RFC 2616 10.3.5 states that entity headers are not supposed
1195 * to be in the 304 response. Therefore, we need to combine the
1196 * response headers with the cached headers *before* we update
1197 * the cached headers.
1199 * However, before doing that, we need to first merge in
1200 * err_headers_out and we also need to strip any hop-by-hop
1201 * headers that might have snuck in.
1203 r->headers_out = ap_cache_cacheable_headers_out(r);
1205 /* Merge in our cached headers. However, keep any updated values. */
1206 cache_accept_headers(cache->handle, r, 1);
1209 /* Write away header information to cache. It is possible that we are
1210 * trying to update headers for an entity which has already been cached.
1212 * This may fail, due to an unwritable cache area. E.g. filesystem full,
1213 * permissions problems or a read-only (re)mount. This must be handled
1216 rv = cache->provider->store_headers(cache->handle, r, info);
1218 /* Did we just update the cached headers on a revalidated response?
1220 * If so, we can now decide what to serve to the client. This is done in
1221 * the same way as with a regular response, but conditions are now checked
1222 * against the cached or merged response headers.
1224 if (cache->stale_handle) {
1225 apr_bucket_brigade *bb;
1229 /* We're just saving response headers, so we are done. Commit
1230 * the response at this point, unless there was a previous error.
1232 if (rv == APR_SUCCESS) {
1233 rv = cache->provider->commit_entity(cache->handle, r);
1236 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
1238 /* Restore the original request headers and see if we need to
1239 * return anything else than the cached response (ie. the original
1240 * request was conditional).
1242 r->headers_in = cache->stale_headers;
1243 status = ap_meets_conditions(r);
1247 bkt = apr_bucket_flush_create(bb->bucket_alloc);
1248 APR_BRIGADE_INSERT_TAIL(bb, bkt);
1251 cache->provider->recall_body(cache->handle, r->pool, bb);
1254 cache->block_response = 1;
1256 /* Before returning we need to handle the possible case of an
1257 * unwritable cache. Rather than leaving the entity in the cache
1258 * and having it constantly re-validated, now that we have recalled
1259 * the body it is safe to try and remove the url from the cache.
1261 if (rv != APR_SUCCESS) {
1262 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
1263 "cache: updating headers with store_headers failed. "
1264 "Removing cached url.");
1266 rv = cache->provider->remove_url(cache->stale_handle, r->pool);
1268 /* Probably a mod_disk_cache cache area has been (re)mounted
1269 * read-only, or that there is a permissions problem.
1271 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
1272 "cache: attempt to remove url from cache unsuccessful.");
1275 /* we've got a cache conditional hit! tell anyone who cares */
1276 cache_run_cache_status(cache->handle, r, AP_CACHE_REVALIDATE,
1277 "conditional cache hit: entity refresh failed");
1282 /* we've got a cache conditional hit! tell anyone who cares */
1283 cache_run_cache_status(cache->handle, r, AP_CACHE_REVALIDATE,
1284 "conditional cache hit: entity refreshed");
1288 /* let someone else attempt to cache */
1289 cache_remove_lock(conf, cache, r, cache->handle ?
1290 (char *)cache->handle->cache_obj->key : NULL, NULL);
1292 return ap_pass_brigade(f->next, bb);
1295 if (rv != APR_SUCCESS) {
1296 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
1297 "cache: store_headers failed");
1299 /* we've got a cache miss! tell anyone who cares */
1300 cache_run_cache_status(cache->handle, r, AP_CACHE_MISS,
1301 "cache miss: store_headers failed");
1303 ap_remove_output_filter(f);
1304 cache_remove_lock(conf, cache, r, cache->handle ?
1305 (char *)cache->handle->cache_obj->key : NULL, NULL);
1306 return ap_pass_brigade(f->next, in);
1309 /* we've got a cache miss! tell anyone who cares */
1310 cache_run_cache_status(cache->handle, r, AP_CACHE_MISS,
1311 "cache miss: attempting entity save");
1313 return cache_save_store(f, in, conf, cache);
1317 * CACHE_REMOVE_URL filter
1318 * -----------------------
1320 * This filter gets added in the quick handler every time the CACHE_SAVE filter
1321 * gets inserted. Its purpose is to remove a confirmed stale cache entry from
1324 * CACHE_REMOVE_URL has to be a protocol filter to ensure that is run even if
1325 * the response is a canned error message, which removes the content filters
1326 * and thus the CACHE_SAVE filter from the chain.
1328 * CACHE_REMOVE_URL expects cache request rec within its context because the
1329 * request this filter runs on can be different from the one whose cache entry
1330 * should be removed, due to internal redirects.
1332 * Note that CACHE_SAVE_URL (as a content-set filter, hence run before the
1333 * protocol filters) will remove this filter if it decides to cache the file.
1334 * Therefore, if this filter is left in, it must mean we need to toss any
1337 static int cache_remove_url_filter(ap_filter_t *f, apr_bucket_brigade *in)
1339 request_rec *r = f->r;
1340 cache_request_rec *cache;
1342 /* Setup cache_request_rec */
1343 cache = (cache_request_rec *) f->ctx;
1346 /* user likely configured CACHE_REMOVE_URL manually; they should really
1347 * use mod_cache configuration to do that. So:
1348 * 1. Remove ourselves
1349 * 2. Do nothing and bail out
1351 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1352 "cache: CACHE_REMOVE_URL enabled unexpectedly");
1353 ap_remove_output_filter(f);
1354 return ap_pass_brigade(f->next, in);
1357 /* Now remove this cache entry from the cache */
1358 cache_remove_url(cache, r->pool);
1360 /* remove ourselves */
1361 ap_remove_output_filter(f);
1362 return ap_pass_brigade(f->next, in);
1369 * This filter can be optionally inserted into the filter chain by the admin as
1370 * a marker representing the precise location within the filter chain where
1371 * caching is to be performed.
1373 * When the filter chain is set up in the non-quick version of the URL handler,
1374 * the CACHE filter is replaced by the CACHE_OUT or CACHE_SAVE filter,
1375 * effectively inserting the caching filters at the point indicated by the
1376 * admin. The CACHE filter is then removed.
1378 * This allows caching to be performed before the content is passed to the
1379 * INCLUDES filter, or to a filter that might perform transformations unique
1380 * to the specific request and that would otherwise be non-cacheable.
1382 static int cache_filter(ap_filter_t *f, apr_bucket_brigade *in)
1384 /* we are just a marker, so let's just remove ourselves */
1385 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, f->r->server,
1386 "cache: CACHE filter was added twice, or was added in quick "
1387 "handler mode and will be ignored.");
1388 ap_remove_output_filter(f);
1389 return ap_pass_brigade(f->next, in);
1393 * If configured, add the status of the caching attempt to the subprocess
1394 * environment, and if configured, to headers in the response.
1396 * The status is saved below the broad category of the status (hit, miss,
1397 * revalidate), as well as a single cache-status key. This can be used for
1398 * conditional logging.
1400 * The status is optionally saved to an X-Cache header, and the detail of
1401 * why a particular cache entry was cached (or not cached) is optionally
1402 * saved to an X-Cache-Detail header. This extra detail is useful for
1403 * service developers who may need to know whether their Cache-Control headers
1404 * are working correctly.
1406 static int cache_status(cache_handle_t *h, request_rec *r, ap_cache_status_e status,
1411 (cache_server_conf *) ap_get_module_config(r->server->module_config,
1414 cache_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &cache_module);
1415 int x_cache = 0, x_cache_detail = 0;
1418 case AP_CACHE_HIT: {
1419 apr_table_setn(r->subprocess_env, AP_CACHE_HIT_ENV, reason);
1422 case AP_CACHE_REVALIDATE: {
1423 apr_table_setn(r->subprocess_env, AP_CACHE_REVALIDATE_ENV, reason);
1426 case AP_CACHE_MISS: {
1427 apr_table_setn(r->subprocess_env, AP_CACHE_MISS_ENV, reason);
1432 apr_table_setn(r->subprocess_env, AP_CACHE_STATUS_ENV, reason);
1434 if (dconf && dconf->x_cache_set) {
1435 x_cache = dconf->x_cache;
1438 x_cache = conf->x_cache;
1441 apr_table_setn(r->headers_out, "X-Cache", apr_psprintf(r->pool, "%s from %s",
1442 status == AP_CACHE_HIT ? "HIT" : status == AP_CACHE_REVALIDATE ?
1443 "REVALIDATE" : "MISS", r->server->server_hostname));
1446 if (dconf && dconf->x_cache_detail_set) {
1447 x_cache_detail = dconf->x_cache_detail;
1450 x_cache_detail = conf->x_cache_detail;
1452 if (x_cache_detail) {
1453 apr_table_setn(r->headers_out, "X-Cache-Detail", apr_psprintf(r->pool,
1454 "\"%s\" from %s", reason, r->server->server_hostname));
1460 /* -------------------------------------------------------------- */
1461 /* Setup configurable data */
1463 static void *create_dir_config(apr_pool_t *p, char *dummy)
1465 cache_dir_conf *dconf = apr_pcalloc(p, sizeof(cache_dir_conf));
1467 dconf->x_cache = DEFAULT_X_CACHE;
1468 dconf->x_cache_detail = DEFAULT_X_CACHE_DETAIL;
1473 static void *merge_dir_config(apr_pool_t *p, void *basev, void *addv) {
1474 cache_dir_conf *new = (cache_dir_conf *) apr_pcalloc(p, sizeof(cache_dir_conf));
1475 cache_dir_conf *add = (cache_dir_conf *) addv;
1476 cache_dir_conf *base = (cache_dir_conf *) basev;
1478 new->x_cache = (add->x_cache_set == 0) ? base->x_cache : add->x_cache;
1479 new->x_cache_set = add->x_cache_set || base->x_cache_set;
1480 new->x_cache_detail = (add->x_cache_detail_set == 0) ? base->x_cache_detail
1481 : add->x_cache_detail;
1482 new->x_cache_detail_set = add->x_cache_detail_set
1483 || base->x_cache_detail_set;
1488 static void * create_cache_config(apr_pool_t *p, server_rec *s)
1490 const char *tmppath;
1491 cache_server_conf *ps = apr_pcalloc(p, sizeof(cache_server_conf));
1493 /* array of URL prefixes for which caching is enabled */
1494 ps->cacheenable = apr_array_make(p, 10, sizeof(struct cache_enable));
1495 /* array of URL prefixes for which caching is disabled */
1496 ps->cachedisable = apr_array_make(p, 10, sizeof(struct cache_disable));
1497 /* maximum time to cache a document */
1498 ps->maxex = DEFAULT_CACHE_MAXEXPIRE;
1500 ps->minex = DEFAULT_CACHE_MINEXPIRE;
1502 /* default time to cache a document */
1503 ps->defex = DEFAULT_CACHE_EXPIRE;
1505 /* factor used to estimate Expires date from LastModified date */
1506 ps->factor = DEFAULT_CACHE_LMFACTOR;
1508 ps->no_last_mod_ignore_set = 0;
1509 ps->no_last_mod_ignore = 0;
1510 ps->ignorecachecontrol = 0;
1511 ps->ignorecachecontrol_set = 0;
1512 ps->store_expired = 0;
1513 ps->store_expired_set = 0;
1514 ps->store_private = 0;
1515 ps->store_private_set = 0;
1516 ps->store_nostore = 0;
1517 ps->store_nostore_set = 0;
1518 /* array of headers that should not be stored in cache */
1519 ps->ignore_headers = apr_array_make(p, 10, sizeof(char *));
1520 ps->ignore_headers_set = CACHE_IGNORE_HEADERS_UNSET;
1521 /* flag indicating that query-string should be ignored when caching */
1522 ps->ignorequerystring = 0;
1523 ps->ignorequerystring_set = 0;
1524 /* by default, run in the quick handler */
1527 /* array of identifiers that should not be used for key calculation */
1528 ps->ignore_session_id = apr_array_make(p, 10, sizeof(char *));
1529 ps->ignore_session_id_set = CACHE_IGNORE_SESSION_ID_UNSET;
1530 ps->lock = 0; /* thundering herd lock defaults to off */
1532 apr_temp_dir_get(&tmppath, p);
1534 ps->lockpath = apr_pstrcat(p, tmppath, DEFAULT_CACHE_LOCKPATH, NULL);
1536 ps->lockmaxage = apr_time_from_sec(DEFAULT_CACHE_MAXAGE);
1537 ps->x_cache = DEFAULT_X_CACHE;
1538 ps->x_cache_detail = DEFAULT_X_CACHE_DETAIL;
1542 static void * merge_cache_config(apr_pool_t *p, void *basev, void *overridesv)
1544 cache_server_conf *ps = apr_pcalloc(p, sizeof(cache_server_conf));
1545 cache_server_conf *base = (cache_server_conf *) basev;
1546 cache_server_conf *overrides = (cache_server_conf *) overridesv;
1548 /* array of URL prefixes for which caching is disabled */
1549 ps->cachedisable = apr_array_append(p,
1551 overrides->cachedisable);
1552 /* array of URL prefixes for which caching is enabled */
1553 ps->cacheenable = apr_array_append(p,
1555 overrides->cacheenable);
1556 /* maximum time to cache a document */
1557 ps->maxex = (overrides->maxex_set == 0) ? base->maxex : overrides->maxex;
1558 ps->minex = (overrides->minex_set == 0) ? base->minex : overrides->minex;
1559 /* default time to cache a document */
1560 ps->defex = (overrides->defex_set == 0) ? base->defex : overrides->defex;
1561 /* factor used to estimate Expires date from LastModified date */
1563 (overrides->factor_set == 0) ? base->factor : overrides->factor;
1565 ps->no_last_mod_ignore =
1566 (overrides->no_last_mod_ignore_set == 0)
1567 ? base->no_last_mod_ignore
1568 : overrides->no_last_mod_ignore;
1569 ps->ignorecachecontrol =
1570 (overrides->ignorecachecontrol_set == 0)
1571 ? base->ignorecachecontrol
1572 : overrides->ignorecachecontrol;
1574 (overrides->store_expired_set == 0)
1575 ? base->store_expired
1576 : overrides->store_expired;
1578 (overrides->store_private_set == 0)
1579 ? base->store_private
1580 : overrides->store_private;
1582 (overrides->store_nostore_set == 0)
1583 ? base->store_nostore
1584 : overrides->store_nostore;
1585 ps->ignore_headers =
1586 (overrides->ignore_headers_set == CACHE_IGNORE_HEADERS_UNSET)
1587 ? base->ignore_headers
1588 : overrides->ignore_headers;
1589 ps->ignorequerystring =
1590 (overrides->ignorequerystring_set == 0)
1591 ? base->ignorequerystring
1592 : overrides->ignorequerystring;
1593 ps->ignore_session_id =
1594 (overrides->ignore_session_id_set == CACHE_IGNORE_SESSION_ID_UNSET)
1595 ? base->ignore_session_id
1596 : overrides->ignore_session_id;
1598 (overrides->lock_set == 0)
1602 (overrides->lockpath_set == 0)
1604 : overrides->lockpath;
1606 (overrides->lockmaxage_set == 0)
1608 : overrides->lockmaxage;
1610 (overrides->quick_set == 0)
1614 (overrides->x_cache_set == 0)
1616 : overrides->x_cache;
1617 ps->x_cache_detail =
1618 (overrides->x_cache_detail_set == 0)
1619 ? base->x_cache_detail
1620 : overrides->x_cache_detail;
1624 static const char *set_cache_quick_handler(cmd_parms *parms, void *dummy,
1627 cache_server_conf *conf;
1630 (cache_server_conf *)ap_get_module_config(parms->server->module_config
1634 conf->quick_set = 1;
1639 static const char *set_cache_ignore_no_last_mod(cmd_parms *parms, void *dummy,
1642 cache_server_conf *conf;
1645 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1647 conf->no_last_mod_ignore = flag;
1648 conf->no_last_mod_ignore_set = 1;
1653 static const char *set_cache_ignore_cachecontrol(cmd_parms *parms,
1654 void *dummy, int flag)
1656 cache_server_conf *conf;
1659 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1661 conf->ignorecachecontrol = flag;
1662 conf->ignorecachecontrol_set = 1;
1666 static const char *set_cache_store_expired(cmd_parms *parms, void *dummy,
1669 cache_server_conf *conf;
1672 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1674 conf->store_expired = flag;
1675 conf->store_expired_set = 1;
1679 static const char *set_cache_store_private(cmd_parms *parms, void *dummy,
1682 cache_server_conf *conf;
1685 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1687 conf->store_private = flag;
1688 conf->store_private_set = 1;
1692 static const char *set_cache_store_nostore(cmd_parms *parms, void *dummy,
1695 cache_server_conf *conf;
1698 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1700 conf->store_nostore = flag;
1701 conf->store_nostore_set = 1;
1705 static const char *add_ignore_header(cmd_parms *parms, void *dummy,
1708 cache_server_conf *conf;
1712 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1714 if (!strcasecmp(header, "None")) {
1715 /* if header None is listed clear array */
1716 conf->ignore_headers->nelts = 0;
1719 if ((conf->ignore_headers_set == CACHE_IGNORE_HEADERS_UNSET) ||
1720 (conf->ignore_headers->nelts)) {
1721 /* Only add header if no "None" has been found in header list
1723 * (When 'None' is passed, IGNORE_HEADERS_SET && nelts == 0.)
1725 new = (char **)apr_array_push(conf->ignore_headers);
1726 (*new) = (char *)header;
1729 conf->ignore_headers_set = CACHE_IGNORE_HEADERS_SET;
1733 static const char *add_ignore_session_id(cmd_parms *parms, void *dummy,
1734 const char *identifier)
1736 cache_server_conf *conf;
1740 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1742 if (!strcasecmp(identifier, "None")) {
1743 /* if identifier None is listed clear array */
1744 conf->ignore_session_id->nelts = 0;
1747 if ((conf->ignore_session_id_set == CACHE_IGNORE_SESSION_ID_UNSET) ||
1748 (conf->ignore_session_id->nelts)) {
1750 * Only add identifier if no "None" has been found in identifier
1753 new = (char **)apr_array_push(conf->ignore_session_id);
1754 (*new) = (char *)identifier;
1757 conf->ignore_session_id_set = CACHE_IGNORE_SESSION_ID_SET;
1761 static const char *add_cache_enable(cmd_parms *parms, void *dummy,
1765 cache_server_conf *conf;
1766 struct cache_enable *new;
1768 const char *err = ap_check_cmd_context(parms,
1769 NOT_IN_DIRECTORY|NOT_IN_LIMIT|NOT_IN_FILES);
1775 return apr_psprintf(parms->pool,
1776 "provider (%s) starts with a '/'. Are url and provider switched?",
1784 return apr_psprintf(parms->pool,
1785 "CacheEnable provider (%s) is missing an URL.", type);
1787 if (parms->path && strncmp(parms->path, url, strlen(parms->path))) {
1788 return "When in a Location, CacheEnable must specify a path or an URL below "
1793 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1795 new = apr_array_push(conf->cacheenable);
1797 if (apr_uri_parse(parms->pool, url, &(new->url))) {
1800 if (new->url.path) {
1801 new->pathlen = strlen(new->url.path);
1804 new->url.path = "/";
1809 static const char *add_cache_disable(cmd_parms *parms, void *dummy,
1812 cache_server_conf *conf;
1813 struct cache_disable *new;
1815 const char *err = ap_check_cmd_context(parms,
1816 NOT_IN_DIRECTORY|NOT_IN_LIMIT|NOT_IN_FILES);
1821 if (parms->path && !strcmp(url, "on")) {
1824 if (url[0] != '/' && !ap_strchr_c(url, ':')) {
1825 return "CacheDisable must specify a path or an URL, or when in a Location, "
1829 if (parms->path && strncmp(parms->path, url, strlen(parms->path))) {
1830 return "When in a Location, CacheDisable must specify a path or an URL below "
1835 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1837 new = apr_array_push(conf->cachedisable);
1838 if (apr_uri_parse(parms->pool, url, &(new->url))) {
1841 if (new->url.path) {
1842 new->pathlen = strlen(new->url.path);
1845 new->url.path = "/";
1850 static const char *set_cache_maxex(cmd_parms *parms, void *dummy,
1853 cache_server_conf *conf;
1856 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1858 conf->maxex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
1859 conf->maxex_set = 1;
1863 static const char *set_cache_minex(cmd_parms *parms, void *dummy,
1866 cache_server_conf *conf;
1869 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1871 conf->minex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
1872 conf->minex_set = 1;
1876 static const char *set_cache_defex(cmd_parms *parms, void *dummy,
1879 cache_server_conf *conf;
1882 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1884 conf->defex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
1885 conf->defex_set = 1;
1889 static const char *set_cache_factor(cmd_parms *parms, void *dummy,
1892 cache_server_conf *conf;
1896 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1898 if (sscanf(arg, "%lg", &val) != 1) {
1899 return "CacheLastModifiedFactor value must be a float";
1902 conf->factor_set = 1;
1906 static const char *set_cache_ignore_querystring(cmd_parms *parms, void *dummy,
1909 cache_server_conf *conf;
1912 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1914 conf->ignorequerystring = flag;
1915 conf->ignorequerystring_set = 1;
1919 static const char *set_cache_lock(cmd_parms *parms, void *dummy,
1922 cache_server_conf *conf;
1925 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1932 static const char *set_cache_lock_path(cmd_parms *parms, void *dummy,
1935 cache_server_conf *conf;
1938 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1941 conf->lockpath = ap_server_root_relative(parms->pool, arg);
1942 if (!conf->lockpath) {
1943 return apr_pstrcat(parms->pool, "Invalid CacheLockPath path ",
1946 conf->lockpath_set = 1;
1950 static const char *set_cache_lock_maxage(cmd_parms *parms, void *dummy,
1953 cache_server_conf *conf;
1954 apr_int64_t seconds;
1957 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1959 seconds = apr_atoi64(arg);
1961 return "CacheLockMaxAge value must be a non-zero positive integer";
1963 conf->lockmaxage = apr_time_from_sec(seconds);
1964 conf->lockmaxage_set = 1;
1968 static const char *set_cache_x_cache(cmd_parms *parms, void *dummy, int flag)
1972 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
1974 dconf->x_cache = flag;
1975 dconf->x_cache_set = 1;
1979 cache_server_conf *conf =
1980 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1983 conf->x_cache = flag;
1984 conf->x_cache_set = 1;
1991 static const char *set_cache_x_cache_detail(cmd_parms *parms, void *dummy, int flag)
1995 cache_dir_conf *dconf = (cache_dir_conf *)dummy;
1997 dconf->x_cache_detail = flag;
1998 dconf->x_cache_detail_set = 1;
2002 cache_server_conf *conf =
2003 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2006 conf->x_cache_detail = flag;
2007 conf->x_cache_detail_set = 1;
2014 static int cache_post_config(apr_pool_t *p, apr_pool_t *plog,
2015 apr_pool_t *ptemp, server_rec *s)
2017 /* This is the means by which unusual (non-unix) os's may find alternate
2018 * means to run a given command (e.g. shebang/registry parsing on Win32)
2020 cache_generate_key = APR_RETRIEVE_OPTIONAL_FN(ap_cache_generate_key);
2021 if (!cache_generate_key) {
2022 cache_generate_key = cache_generate_key_default;
2028 static const command_rec cache_cmds[] =
2031 * Consider a new config directive that enables loading specific cache
2032 * implememtations (like mod_cache_mem, mod_cache_file, etc.).
2033 * Rather than using a LoadModule directive, admin would use something
2034 * like CacheModule mem_cache_module | file_cache_module, etc,
2035 * which would cause the approprpriate cache module to be loaded.
2036 * This is more intuitive that requiring a LoadModule directive.
2039 AP_INIT_TAKE12("CacheEnable", add_cache_enable, NULL, RSRC_CONF|ACCESS_CONF,
2040 "A cache type and partial URL prefix below which "
2041 "caching is enabled"),
2042 AP_INIT_TAKE1("CacheDisable", add_cache_disable, NULL, RSRC_CONF|ACCESS_CONF,
2043 "A partial URL prefix below which caching is disabled"),
2044 AP_INIT_TAKE1("CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF,
2045 "The maximum time in seconds to cache a document"),
2046 AP_INIT_TAKE1("CacheMinExpire", set_cache_minex, NULL, RSRC_CONF,
2047 "The minimum time in seconds to cache a document"),
2048 AP_INIT_TAKE1("CacheDefaultExpire", set_cache_defex, NULL, RSRC_CONF,
2049 "The default time in seconds to cache a document"),
2050 AP_INIT_FLAG("CacheQuickHandler", set_cache_quick_handler, NULL,
2052 "Run the cache in the quick handler, default on"),
2053 AP_INIT_FLAG("CacheIgnoreNoLastMod", set_cache_ignore_no_last_mod, NULL,
2055 "Ignore Responses where there is no Last Modified Header"),
2056 AP_INIT_FLAG("CacheIgnoreCacheControl", set_cache_ignore_cachecontrol,
2058 "Ignore requests from the client for uncached content"),
2059 AP_INIT_FLAG("CacheStoreExpired", set_cache_store_expired,
2061 "Ignore expiration dates when populating cache, resulting in "
2062 "an If-Modified-Since request to the backend on retrieval"),
2063 AP_INIT_FLAG("CacheStorePrivate", set_cache_store_private,
2065 "Ignore 'Cache-Control: private' and store private content"),
2066 AP_INIT_FLAG("CacheStoreNoStore", set_cache_store_nostore,
2068 "Ignore 'Cache-Control: no-store' and store sensitive content"),
2069 AP_INIT_ITERATE("CacheIgnoreHeaders", add_ignore_header, NULL, RSRC_CONF,
2070 "A space separated list of headers that should not be "
2071 "stored by the cache"),
2072 AP_INIT_FLAG("CacheIgnoreQueryString", set_cache_ignore_querystring,
2074 "Ignore query-string when caching"),
2075 AP_INIT_ITERATE("CacheIgnoreURLSessionIdentifiers", add_ignore_session_id,
2076 NULL, RSRC_CONF, "A space separated list of session "
2077 "identifiers that should be ignored for creating the key "
2078 "of the cached entity."),
2079 AP_INIT_TAKE1("CacheLastModifiedFactor", set_cache_factor, NULL, RSRC_CONF,
2080 "The factor used to estimate Expires date from "
2081 "LastModified date"),
2082 AP_INIT_FLAG("CacheLock", set_cache_lock,
2084 "Enable or disable the thundering herd lock."),
2085 AP_INIT_TAKE1("CacheLockPath", set_cache_lock_path, NULL, RSRC_CONF,
2086 "The thundering herd lock path. Defaults to the '"
2087 DEFAULT_CACHE_LOCKPATH "' directory in the system "
2089 AP_INIT_TAKE1("CacheLockMaxAge", set_cache_lock_maxage, NULL, RSRC_CONF,
2090 "Maximum age of any thundering herd lock."),
2091 AP_INIT_FLAG("CacheHeader", set_cache_x_cache, NULL, RSRC_CONF | ACCESS_CONF,
2092 "Add a X-Cache header to responses. Default is off."),
2093 AP_INIT_FLAG("CacheDetailHeader", set_cache_x_cache_detail, NULL,
2094 RSRC_CONF | ACCESS_CONF,
2095 "Add a X-Cache-Detail header to responses. Default is off."),
2099 static void register_hooks(apr_pool_t *p)
2101 /* cache initializer */
2102 /* cache quick handler */
2103 ap_hook_quick_handler(cache_quick_handler, NULL, NULL, APR_HOOK_FIRST);
2105 ap_hook_handler(cache_handler, NULL, NULL, APR_HOOK_REALLY_FIRST);
2107 cache_hook_cache_status(cache_status, NULL, NULL, APR_HOOK_MIDDLE);
2109 * XXX The cache filters need to run right after the handlers and before
2110 * any other filters. Consider creating AP_FTYPE_CACHE for this purpose.
2112 * Depending on the type of request (subrequest / main request) they
2113 * need to be run before AP_FTYPE_CONTENT_SET / after AP_FTYPE_CONTENT_SET
2114 * filters. Thus create two filter handles for each type:
2115 * cache_save_filter_handle / cache_out_filter_handle to be used by
2117 * cache_save_subreq_filter_handle / cache_out_subreq_filter_handle
2118 * to be run by subrequest
2121 * CACHE is placed into the filter chain at an admin specified location,
2122 * and when the cache_handler is run, the CACHE filter is swapped with
2123 * the CACHE_OUT filter, or CACHE_SAVE filter as appropriate. This has
2124 * the effect of offering optional fine control of where the cache is
2125 * inserted into the filter chain.
2127 cache_filter_handle =
2128 ap_register_output_filter("CACHE",
2133 * CACHE_SAVE must go into the filter chain after a possible DEFLATE
2134 * filter to ensure that the compressed content is stored.
2135 * Incrementing filter type by 1 ensures his happens.
2137 cache_save_filter_handle =
2138 ap_register_output_filter("CACHE_SAVE",
2141 AP_FTYPE_CONTENT_SET+1);
2143 * CACHE_SAVE_SUBREQ must go into the filter chain before SUBREQ_CORE to
2144 * handle subrequsts. Decrementing filter type by 1 ensures this
2147 cache_save_subreq_filter_handle =
2148 ap_register_output_filter("CACHE_SAVE_SUBREQ",
2151 AP_FTYPE_CONTENT_SET-1);
2153 * CACHE_OUT must go into the filter chain after a possible DEFLATE
2154 * filter to ensure that already compressed cache objects do not
2155 * get compressed again. Incrementing filter type by 1 ensures
2158 cache_out_filter_handle =
2159 ap_register_output_filter("CACHE_OUT",
2162 AP_FTYPE_CONTENT_SET+1);
2164 * CACHE_OUT_SUBREQ must go into the filter chain before SUBREQ_CORE to
2165 * handle subrequsts. Decrementing filter type by 1 ensures this
2168 cache_out_subreq_filter_handle =
2169 ap_register_output_filter("CACHE_OUT_SUBREQ",
2172 AP_FTYPE_CONTENT_SET-1);
2173 /* CACHE_REMOVE_URL has to be a protocol filter to ensure that is
2174 * run even if the response is a canned error message, which
2175 * removes the content filters.
2177 cache_remove_url_filter_handle =
2178 ap_register_output_filter("CACHE_REMOVE_URL",
2179 cache_remove_url_filter,
2182 ap_hook_post_config(cache_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
2185 AP_DECLARE_MODULE(cache) =
2187 STANDARD20_MODULE_STUFF,
2188 create_dir_config, /* create per-directory config structure */
2189 merge_dir_config, /* merge per-directory config structures */
2190 create_cache_config, /* create per-server config structure */
2191 merge_cache_config, /* merge per-server config structures */
2192 cache_cmds, /* command apr_table_t */
2197 APR_HOOK_LINK(cache_status)
2200 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(cache, CACHE, int, cache_status,
2201 (cache_handle_t *h, request_rec *r,
2202 ap_cache_status_e status,
2203 const char *reason), (h, r, status, reason),