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 module AP_MODULE_DECLARE_DATA cache_module;
20 APR_OPTIONAL_FN_TYPE(ap_cache_generate_key) *cache_generate_key;
22 /* -------------------------------------------------------------- */
25 /* Handles for cache filters, resolved at startup to eliminate
26 * a name-to-function mapping on each request
28 static ap_filter_rec_t *cache_filter_handle;
29 static ap_filter_rec_t *cache_save_filter_handle;
30 static ap_filter_rec_t *cache_save_subreq_filter_handle;
31 static ap_filter_rec_t *cache_out_filter_handle;
32 static ap_filter_rec_t *cache_out_subreq_filter_handle;
33 static ap_filter_rec_t *cache_remove_url_filter_handle;
39 * Can we deliver this request from the cache?
41 * deliver the content by installing the CACHE_OUT filter.
43 * check whether we're allowed to try cache it
45 * add CACHE_SAVE filter
49 * By default, the cache handler runs in the quick handler, bypassing
50 * virtually all server processing and offering the cache its optimal
51 * performance. In this mode, the cache bolts onto the front of the
52 * server, and behaves as a discrete RFC2616 caching proxy
55 * Under certain circumstances, an admin might want to run the cache as
56 * a normal handler instead of a quick handler, allowing the cache to
57 * run after the authorisation hooks, or by allowing fine control over
58 * the placement of the cache in the filter chain. This option comes at
59 * a performance penalty, and should only be used to achieve specific
60 * caching goals where the admin understands what they are doing.
63 static int cache_quick_handler(request_rec *r, int lookup)
67 cache_provider_list *providers;
68 cache_request_rec *cache;
69 apr_bucket_brigade *out;
71 ap_filter_rec_t *cache_out_handle;
72 cache_server_conf *conf;
74 /* Delay initialization until we know we are handling a GET */
75 if (r->method_number != M_GET) {
79 conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
82 /* only run if the quick handler is enabled */
88 * Which cache module (if any) should handle this request?
90 if (!(providers = ap_cache_get_providers(r, conf, r->parsed_uri))) {
94 /* make space for the per request config */
95 cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
98 /* store away the per request config where the API can find it */
99 apr_pool_userdata_setn(cache, MOD_CACHE_REQUEST_REC, NULL, r->pool);
101 /* save away the possible providers */
102 cache->providers = providers;
105 * Are we allowed to serve cached info at all?
108 /* find certain cache controlling headers */
109 auth = apr_table_get(r->headers_in, "Authorization");
111 /* First things first - does the request allow us to return
112 * cached information at all? If not, just decline the request.
119 * Try to serve this request from the cache.
121 * If no existing cache file (DECLINED)
122 * add cache_save filter
123 * If cached file (OK)
125 * add cache_out filter
128 rv = cache_select(r);
130 if (rv == DECLINED) {
133 /* try to obtain a cache lock at this point. if we succeed,
134 * we are the first to try and cache this url. if we fail,
135 * it means someone else is already trying to cache this
136 * url, and we should just let the request through to the
137 * backend without any attempt to cache. this stops
138 * duplicated simultaneous attempts to cache an entity.
140 rv = ap_cache_try_lock(conf, r, NULL);
141 if (APR_SUCCESS == rv) {
144 * Add cache_save filter to cache this request. Choose
145 * the correct filter by checking if we are a subrequest
149 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
151 "Adding CACHE_SAVE_SUBREQ filter for %s",
153 ap_add_output_filter_handle(cache_save_subreq_filter_handle,
154 cache, r, r->connection);
157 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
158 r->server, "Adding CACHE_SAVE filter for %s",
160 ap_add_output_filter_handle(cache_save_filter_handle,
161 cache, r, r->connection);
164 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
165 "Adding CACHE_REMOVE_URL filter for %s",
168 /* Add cache_remove_url filter to this request to remove a
169 * stale cache entry if needed. Also put the current cache
170 * request rec in the filter context, as the request that
171 * is available later during running the filter may be
172 * different due to an internal redirect.
174 cache->remove_url_filter =
175 ap_add_output_filter_handle(cache_remove_url_filter_handle,
176 cache, r, r->connection);
179 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
180 r->server, "Cache locked for url, not caching "
181 "response: %s", r->uri);
185 if (cache->stale_headers) {
186 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
187 r->server, "Restoring request headers for %s",
190 r->headers_in = cache->stale_headers;
196 ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
197 "cache: error returned while checking for cached "
198 "file by '%s' cache", cache->provider_name);
203 /* if we are a lookup, we are exiting soon one way or another; Restore
206 if (cache->stale_headers) {
207 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
208 "Restoring request headers.");
209 r->headers_in = cache->stale_headers;
213 rv = ap_meets_conditions(r);
215 /* If we are a lookup, we have to return DECLINED as we have no
216 * way of knowing if we will be able to serve the content.
222 /* Return cached status. */
226 /* If we're a lookup, we can exit now instead of serving the content. */
231 /* Serve up the content */
233 /* We are in the quick handler hook, which means that no output
234 * filters have been set. So lets run the insert_filter hook.
236 ap_run_insert_filter(r);
239 * Add cache_out filter to serve this request. Choose
240 * the correct filter by checking if we are a subrequest
244 cache_out_handle = cache_out_subreq_filter_handle;
247 cache_out_handle = cache_out_filter_handle;
249 ap_add_output_filter_handle(cache_out_handle, cache, r, r->connection);
252 * Remove all filters that are before the cache_out filter. This ensures
253 * that we kick off the filter stack with our cache_out filter being the
254 * first in the chain. This make sense because we want to restore things
255 * in the same manner as we saved them.
256 * There may be filters before our cache_out filter, because
258 * 1. We call ap_set_content_type during cache_select. This causes
259 * Content-Type specific filters to be added.
260 * 2. We call the insert_filter hook. This causes filters e.g. like
261 * the ones set with SetOutputFilter to be added.
263 next = r->output_filters;
264 while (next && (next->frec != cache_out_handle)) {
265 ap_remove_output_filter(next);
269 /* kick off the filter stack */
270 out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
271 rv = ap_pass_brigade(r->output_filters, out);
272 if (rv != APR_SUCCESS) {
273 if (rv != AP_FILTER_ERROR) {
274 ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
275 "cache: error returned while trying to return %s "
277 cache->provider_name);
286 * If the two filter handles are present within the filter chain, replace
287 * the last instance of the first filter with the last instance of the
288 * second filter, and return true. If the second filter is not present at
289 * all, the first filter is removed, and false is returned. If neither
290 * filter is present, false is returned and this function does nothing.
292 static int cache_replace_filter(ap_filter_t *next, ap_filter_rec_t *from,
293 ap_filter_rec_t *to) {
294 ap_filter_t *ffrom = NULL, *fto = NULL;
296 if (next->frec == from && !next->ctx) {
299 if (next->frec == to && !next->ctx) {
305 ffrom->frec = fto->frec;
306 ffrom->ctx = fto->ctx;
307 ap_remove_output_filter(fto);
311 ap_remove_output_filter(ffrom);
317 * The cache handler is functionally similar to the cache_quick_hander,
318 * however a number of steps that are required by the quick handler are
319 * not required here, as the normal httpd processing has already handled
322 static int cache_handler(request_rec *r)
325 cache_provider_list *providers;
326 cache_request_rec *cache;
327 apr_bucket_brigade *out;
329 ap_filter_rec_t *cache_out_handle;
330 ap_filter_rec_t *cache_save_handle;
331 cache_server_conf *conf;
333 /* Delay initialization until we know we are handling a GET */
334 if (r->method_number != M_GET) {
338 conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
341 /* only run if the quick handler is disabled */
347 * Which cache module (if any) should handle this request?
349 if (!(providers = ap_cache_get_providers(r, conf, r->parsed_uri))) {
353 /* make space for the per request config */
354 cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
357 /* store away the per request config where the API can find it */
358 apr_pool_userdata_setn(cache, MOD_CACHE_REQUEST_REC, NULL, r->pool);
360 /* save away the possible providers */
361 cache->providers = providers;
364 * Try to serve this request from the cache.
366 * If no existing cache file (DECLINED)
367 * add cache_save filter
368 * If cached file (OK)
370 * add cache_out filter
373 rv = cache_select(r);
375 if (rv == DECLINED) {
377 /* try to obtain a cache lock at this point. if we succeed,
378 * we are the first to try and cache this url. if we fail,
379 * it means someone else is already trying to cache this
380 * url, and we should just let the request through to the
381 * backend without any attempt to cache. this stops
382 * duplicated simultaneous attempts to cache an entity.
384 rv = ap_cache_try_lock(conf, r, NULL);
385 if (APR_SUCCESS == rv) {
388 * Add cache_save filter to cache this request. Choose
389 * the correct filter by checking if we are a subrequest
393 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
395 "Adding CACHE_SAVE_SUBREQ filter for %s",
397 cache_save_handle = cache_save_subreq_filter_handle;
400 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
401 r->server, "Adding CACHE_SAVE filter for %s",
403 cache_save_handle = cache_save_filter_handle;
405 ap_add_output_filter_handle(cache_save_handle,
406 cache, r, r->connection);
409 * Did the user indicate the precise location of the
410 * CACHE_SAVE filter by inserting the CACHE filter as a
413 * If so, we get cunning and replace CACHE with the
414 * CACHE_SAVE filter. This has the effect of inserting
415 * the CACHE_SAVE filter at the precise location where
416 * the admin wants to cache the content. All filters that
417 * lie before and after the original location of the CACHE
418 * filter will remain in place.
420 if (cache_replace_filter(r->output_filters,
421 cache_filter_handle, cache_save_handle)) {
422 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
423 r->server, "Replacing CACHE with CACHE_SAVE "
424 "filter for %s", r->uri);
427 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
428 "Adding CACHE_REMOVE_URL filter for %s",
431 /* Add cache_remove_url filter to this request to remove a
432 * stale cache entry if needed. Also put the current cache
433 * request rec in the filter context, as the request that
434 * is available later during running the filter may be
435 * different due to an internal redirect.
437 cache->remove_url_filter =
438 ap_add_output_filter_handle(cache_remove_url_filter_handle,
439 cache, r, r->connection);
443 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
444 r->server, "Cache locked for url, not caching "
445 "response: %s", r->uri);
450 ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
451 "cache: error returned while checking for cached "
452 "file by %s cache", cache->provider_name);
457 rv = ap_meets_conditions(r);
462 /* Serve up the content */
465 * Add cache_out filter to serve this request. Choose
466 * the correct filter by checking if we are a subrequest
470 cache_out_handle = cache_out_subreq_filter_handle;
473 cache_out_handle = cache_out_filter_handle;
475 ap_add_output_filter_handle(cache_out_handle, cache, r, r->connection);
478 * Did the user indicate the precise location of the CACHE_OUT filter by
479 * inserting the CACHE filter as a marker?
481 * If so, we get cunning and replace CACHE with the CACHE_OUT filters.
482 * This has the effect of inserting the CACHE_OUT filter at the precise
483 * location where the admin wants to cache the content. All filters that
484 * lie *after* the original location of the CACHE filter will remain in
487 if (cache_replace_filter(r->output_filters, cache_filter_handle, cache_out_handle)) {
488 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
489 r->server, "Replacing CACHE with CACHE_OUT filter for %s",
494 * Remove all filters that are before the cache_out filter. This ensures
495 * that we kick off the filter stack with our cache_out filter being the
496 * first in the chain. This make sense because we want to restore things
497 * in the same manner as we saved them.
498 * There may be filters before our cache_out filter, because
500 * 1. We call ap_set_content_type during cache_select. This causes
501 * Content-Type specific filters to be added.
502 * 2. We call the insert_filter hook. This causes filters e.g. like
503 * the ones set with SetOutputFilter to be added.
505 next = r->output_filters;
506 while (next && (next->frec != cache_out_handle)) {
507 ap_remove_output_filter(next);
511 /* kick off the filter stack */
512 out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
513 rv = ap_pass_brigade(r->output_filters, out);
514 if (rv != APR_SUCCESS) {
515 if (rv != AP_FILTER_ERROR) {
516 ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
517 "cache: error returned while trying to return %s "
519 cache->provider_name);
531 * Deliver cached content (headers and body) up the stack.
533 static int cache_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
535 request_rec *r = f->r;
536 cache_request_rec *cache = (cache_request_rec *)f->ctx;
539 /* user likely configured CACHE_OUT manually; they should use mod_cache
540 * configuration to do that */
541 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
542 "CACHE/CACHE_OUT filter enabled while caching is disabled, ignoring");
543 ap_remove_output_filter(f);
544 return ap_pass_brigade(f->next, bb);
547 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
548 "cache: running CACHE_OUT filter");
550 /* restore status of cached response */
551 /* XXX: This exposes a bug in mem_cache, since it does not
552 * restore the status into it's handle. */
553 r->status = cache->handle->cache_obj->info.status;
555 /* recall_headers() was called in cache_select() */
556 cache->provider->recall_body(cache->handle, r->pool, bb);
558 /* This filter is done once it has served up its content */
559 ap_remove_output_filter(f);
561 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server,
562 "cache: serving %s", r->uri);
563 return ap_pass_brigade(f->next, bb);
570 * Decide whether or not this content should be cached.
571 * If we decide no it should not:
572 * remove the filter from the chain
573 * If we decide yes it should:
574 * Have we already started saving the response?
575 * If we have started, pass the data to the storage manager via store_body
577 * Check to see if we *can* save this particular response.
578 * If we can, call cache_create_entity() and save the headers and body
579 * Finally, pass the data to the next filter (the network or whatever)
581 * After the various failure cases, the cache lock is proactively removed, so
582 * that another request is given the opportunity to attempt to cache without
583 * waiting for a potentially slow client to acknowledge the failure.
586 static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
589 request_rec *r = f->r;
590 cache_request_rec *cache = (cache_request_rec *)f->ctx;
591 cache_server_conf *conf;
592 const char *cc_out, *cl;
593 const char *exps, *lastmods, *dates, *etag;
594 apr_time_t exp, date, lastmod, now;
596 cache_info *info = NULL;
602 conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
605 /* Setup cache_request_rec */
607 /* user likely configured CACHE_SAVE manually; they should really use
608 * mod_cache configuration to do that
610 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
611 "CACHE/CACHE_SAVE filter enabled while caching is disabled, ignoring");
612 ap_remove_output_filter(f);
613 return ap_pass_brigade(f->next, in);
621 * This section passes the brigades into the cache modules, but only
622 * if the setup section (see below) is complete.
624 if (cache->block_response) {
625 /* We've already sent down the response and EOS. So, ignore
626 * whatever comes now.
631 /* have we already run the cachability check and set up the
632 * cached file handle?
634 if (cache->in_checked) {
635 /* pass the brigades into the cache, then pass them
636 * up the filter stack
638 rv = cache->provider->store_body(cache->handle, r, in);
639 if (rv != APR_SUCCESS) {
640 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
641 "cache: Cache provider's store_body failed!");
642 ap_remove_output_filter(f);
644 /* give someone else the chance to cache the file */
645 ap_cache_remove_lock(conf, r, cache->handle ?
646 (char *)cache->handle->cache_obj->key : NULL, NULL);
650 /* proactively remove the lock as soon as we see the eos bucket */
651 ap_cache_remove_lock(conf, r, cache->handle ?
652 (char *)cache->handle->cache_obj->key : NULL, in);
656 return ap_pass_brigade(f->next, in);
660 * Setup Data in Cache
661 * -------------------
662 * This section opens the cache entity and sets various caching
663 * parameters, and decides whether this URL should be cached at
664 * all. This section is* run before the above section.
667 /* read expiry date; if a bad date, then leave it so the client can
670 exps = apr_table_get(r->err_headers_out, "Expires");
672 exps = apr_table_get(r->headers_out, "Expires");
675 if (APR_DATE_BAD == (exp = apr_date_parse_http(exps))) {
683 /* read the last-modified date; if the date is bad, then delete it */
684 lastmods = apr_table_get(r->err_headers_out, "Last-Modified");
685 if (lastmods == NULL) {
686 lastmods = apr_table_get(r->headers_out, "Last-Modified");
688 if (lastmods != NULL) {
689 lastmod = apr_date_parse_http(lastmods);
690 if (lastmod == APR_DATE_BAD) {
695 lastmod = APR_DATE_BAD;
698 /* read the etag and cache-control from the entity */
699 etag = apr_table_get(r->err_headers_out, "Etag");
701 etag = apr_table_get(r->headers_out, "Etag");
703 cc_out = apr_table_get(r->err_headers_out, "Cache-Control");
704 if (cc_out == NULL) {
705 cc_out = apr_table_get(r->headers_out, "Cache-Control");
709 * what responses should we not cache?
711 * At this point we decide based on the response headers whether it
712 * is appropriate _NOT_ to cache the data from the server. There are
713 * a whole lot of conditions that prevent us from caching this data.
714 * They are tested here one by one to be clear and unambiguous.
716 if (r->status != HTTP_OK && r->status != HTTP_NON_AUTHORITATIVE
717 && r->status != HTTP_PARTIAL_CONTENT
718 && r->status != HTTP_MULTIPLE_CHOICES
719 && r->status != HTTP_MOVED_PERMANENTLY
720 && r->status != HTTP_NOT_MODIFIED) {
721 /* RFC2616 13.4 we are allowed to cache 200, 203, 206, 300, 301 or 410
722 * We allow the caching of 206, but a cache implementation might choose
723 * to decline to cache a 206 if it doesn't know how to.
724 * We include 304 Not Modified here too as this is the origin server
725 * telling us to serve the cached copy.
727 if (exps != NULL || cc_out != NULL) {
728 /* We are also allowed to cache any response given that it has a
729 * valid Expires or Cache Control header. If we find a either of
730 * those here, we pass request through the rest of the tests. From
733 * A response received with any other status code (e.g. status
734 * codes 302 and 307) MUST NOT be returned in a reply to a
735 * subsequent request unless there are cache-control directives or
736 * another header(s) that explicitly allow it. For example, these
737 * include the following: an Expires header (section 14.21); a
738 * "max-age", "s-maxage", "must-revalidate", "proxy-revalidate",
739 * "public" or "private" cache-control directive (section 14.9).
743 reason = apr_psprintf(p, "Response status %d", r->status);
750 else if (exps != NULL && exp == APR_DATE_BAD) {
751 /* if a broken Expires header is present, don't cache it */
752 reason = apr_pstrcat(p, "Broken expires header: ", exps, NULL);
754 else if (exp != APR_DATE_BAD && exp < r->request_time)
756 /* if a Expires header is in the past, don't cache it */
757 reason = "Expires header already expired, not cacheable";
759 else if (!conf->ignorequerystring && r->parsed_uri.query && exps == NULL &&
760 !ap_cache_liststr(NULL, cc_out, "max-age", NULL) &&
761 !ap_cache_liststr(NULL, cc_out, "s-maxage", NULL)) {
762 /* if a query string is present but no explicit expiration time,
763 * don't cache it (RFC 2616/13.9 & 13.2.1)
765 reason = "Query string present but no explicit expiration time";
767 else if (r->status == HTTP_NOT_MODIFIED &&
768 !cache->handle && !cache->stale_handle) {
769 /* if the server said 304 Not Modified but we have no cache
770 * file - pass this untouched to the user agent, it's not for us.
772 reason = "HTTP Status 304 Not Modified";
774 else if (r->status == HTTP_OK && lastmods == NULL && etag == NULL
775 && (exps == NULL) && (conf->no_last_mod_ignore ==0) &&
776 !ap_cache_liststr(NULL, cc_out, "max-age", NULL) &&
777 !ap_cache_liststr(NULL, cc_out, "s-maxage", NULL)) {
778 /* 200 OK response from HTTP/1.0 and up without Last-Modified,
779 * Etag, Expires, Cache-Control:max-age, or Cache-Control:s-maxage
782 /* Note: mod-include clears last_modified/expires/etags - this
783 * is why we have an optional function for a key-gen ;-)
785 reason = "No Last-Modified, Etag, Expires, Cache-Control:max-age or Cache-Control:s-maxage headers";
787 else if (r->header_only && !cache->stale_handle) {
788 /* Forbid HEAD requests unless we have it cached already */
789 reason = "HTTP HEAD request";
791 else if (!conf->store_nostore &&
792 ap_cache_liststr(NULL, cc_out, "no-store", NULL)) {
793 /* RFC2616 14.9.2 Cache-Control: no-store response
794 * indicating do not cache, or stop now if you are
795 * trying to cache it.
797 /* FIXME: The Cache-Control: no-store could have come in on a 304,
798 * FIXME: while the original request wasn't conditional. IOW, we
799 * FIXME: made the the request conditional earlier to revalidate
800 * FIXME: our cached response.
802 reason = "Cache-Control: no-store present";
804 else if (!conf->store_private &&
805 ap_cache_liststr(NULL, cc_out, "private", NULL)) {
806 /* RFC2616 14.9.1 Cache-Control: private response
807 * this object is marked for this user's eyes only. Behave
810 /* FIXME: See above (no-store) */
811 reason = "Cache-Control: private present";
813 else if (apr_table_get(r->headers_in, "Authorization") != NULL
814 && !(ap_cache_liststr(NULL, cc_out, "s-maxage", NULL)
815 || ap_cache_liststr(NULL, cc_out, "must-revalidate", NULL)
816 || ap_cache_liststr(NULL, cc_out, "public", NULL))) {
817 /* RFC2616 14.8 Authorisation:
818 * if authorisation is included in the request, we don't cache,
819 * but we can cache if the following exceptions are true:
820 * 1) If Cache-Control: s-maxage is included
821 * 2) If Cache-Control: must-revalidate is included
822 * 3) If Cache-Control: public is included
824 reason = "Authorization required";
826 else if (ap_cache_liststr(NULL,
827 apr_table_get(r->headers_out, "Vary"),
829 reason = "Vary header contains '*'";
831 else if (apr_table_get(r->subprocess_env, "no-cache") != NULL) {
832 reason = "environment variable 'no-cache' is set";
834 else if (r->no_cache) {
835 /* or we've been asked not to cache it above */
836 reason = "r->no_cache present";
840 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
841 "cache: %s not cached. Reason: %s", r->unparsed_uri,
844 /* remove this filter from the chain */
845 ap_remove_output_filter(f);
847 /* remove the lock file unconditionally */
848 ap_cache_remove_lock(conf, r, cache->handle ?
849 (char *)cache->handle->cache_obj->key : NULL, NULL);
851 /* ship the data up the stack */
852 return ap_pass_brigade(f->next, in);
855 /* Make it so that we don't execute this path again. */
856 cache->in_checked = 1;
858 /* Set the content length if known.
860 cl = apr_table_get(r->err_headers_out, "Content-Length");
862 cl = apr_table_get(r->headers_out, "Content-Length");
866 if (apr_strtoff(&size, cl, &errp, 10) || *errp || size < 0) {
867 cl = NULL; /* parse error, see next 'if' block */
872 /* if we don't get the content-length, see if we have all the
873 * buckets and use their length to calculate the size
875 int all_buckets_here=0;
877 for (e = APR_BRIGADE_FIRST(in);
878 e != APR_BRIGADE_SENTINEL(in);
879 e = APR_BUCKET_NEXT(e))
881 if (APR_BUCKET_IS_EOS(e)) {
885 if (APR_BUCKET_IS_FLUSH(e)) {
888 if (e->length == (apr_size_t)-1) {
893 if (!all_buckets_here) {
898 /* remember content length to check response size against later */
901 /* It's safe to cache the response.
903 * There are two possiblities at this point:
904 * - cache->handle == NULL. In this case there is no previously
905 * cached entity anywhere on the system. We must create a brand
906 * new entity and store the response in it.
907 * - cache->stale_handle != NULL. In this case there is a stale
908 * entity in the system which needs to be replaced by new
909 * content (unless the result was 304 Not Modified, which means
910 * the cached entity is actually fresh, and we should update
914 /* Did we have a stale cache entry that really is stale?
916 * Note that for HEAD requests, we won't get the body, so for a stale
917 * HEAD request, we don't remove the entity - instead we let the
918 * CACHE_REMOVE_URL filter remove the stale item from the cache.
920 if (cache->stale_handle) {
921 if (r->status == HTTP_NOT_MODIFIED) {
922 /* Oh, hey. It isn't that stale! Yay! */
923 cache->handle = cache->stale_handle;
924 info = &cache->handle->cache_obj->info;
927 else if (!r->header_only) {
928 /* Oh, well. Toss it. */
929 cache->provider->remove_entity(cache->stale_handle);
930 /* Treat the request as if it wasn't conditional. */
931 cache->stale_handle = NULL;
933 * Restore the original request headers as they may be needed
934 * by further output filters like the byterange filter to make
935 * the correct decisions.
937 r->headers_in = cache->stale_headers;
941 /* no cache handle, create a new entity only for non-HEAD requests */
942 if (!cache->handle && !r->header_only) {
943 rv = cache_create_entity(r, size);
944 info = apr_pcalloc(r->pool, sizeof(cache_info));
945 /* We only set info->status upon the initial creation. */
946 info->status = r->status;
950 /* Caching layer declined the opportunity to cache the response */
951 ap_remove_output_filter(f);
952 ap_cache_remove_lock(conf, r, cache->handle ?
953 (char *)cache->handle->cache_obj->key : NULL, NULL);
954 return ap_pass_brigade(f->next, in);
957 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
958 "cache: Caching url: %s", r->unparsed_uri);
960 /* We are actually caching this response. So it does not
961 * make sense to remove this entity any more.
963 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
964 "cache: Removing CACHE_REMOVE_URL filter.");
965 ap_remove_output_filter(cache->remove_url_filter);
968 * We now want to update the cache file header information with
969 * the new date, last modified, expire and content length and write
970 * it away to our cache file. First, we determine these values from
971 * the response, using heuristics if appropriate.
973 * In addition, we make HTTP/1.1 age calculations and write them away
977 /* Read the date. Generate one if one is not supplied */
978 dates = apr_table_get(r->err_headers_out, "Date");
980 dates = apr_table_get(r->headers_out, "Date");
983 info->date = apr_date_parse_http(dates);
986 info->date = APR_DATE_BAD;
989 now = apr_time_now();
990 if (info->date == APR_DATE_BAD) { /* No, or bad date */
991 /* no date header (or bad header)! */
996 /* set response_time for HTTP/1.1 age calculations */
997 info->response_time = now;
999 /* get the request time */
1000 info->request_time = r->request_time;
1002 /* check last-modified date */
1003 if (lastmod != APR_DATE_BAD && lastmod > date) {
1004 /* if it's in the future, then replace by date */
1007 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
1009 "cache: Last modified is in the future, "
1010 "replacing with now");
1013 /* if no expiry date then
1014 * if Cache-Control: max-age
1015 * expiry date = date + max-age
1017 * expiry date = date + min((date - lastmod) * factor, maxexpire)
1019 * expire date = date + defaultexpire
1021 if (exp == APR_DATE_BAD) {
1024 if (ap_cache_liststr(r->pool, cc_out, "max-age", &max_age_val) &&
1025 max_age_val != NULL) {
1029 x = apr_atoi64(max_age_val);
1034 x = x * MSEC_ONE_SEC;
1036 if (x < conf->minex) {
1039 if (x > conf->maxex) {
1044 else if ((lastmod != APR_DATE_BAD) && (lastmod < date)) {
1045 /* if lastmod == date then you get 0*conf->factor which results in
1046 * an expiration time of now. This causes some problems with
1047 * freshness calculations, so we choose the else path...
1049 apr_time_t x = (apr_time_t) ((date - lastmod) * conf->factor);
1051 if (x < conf->minex) {
1054 if (x > conf->maxex) {
1060 exp = date + conf->defex;
1065 /* We found a stale entry which wasn't really stale. */
1066 if (cache->stale_handle) {
1067 /* Load in the saved status and clear the status line. */
1068 r->status = info->status;
1069 r->status_line = NULL;
1071 /* RFC 2616 10.3.5 states that entity headers are not supposed
1072 * to be in the 304 response. Therefore, we need to combine the
1073 * response headers with the cached headers *before* we update
1074 * the cached headers.
1076 * However, before doing that, we need to first merge in
1077 * err_headers_out and we also need to strip any hop-by-hop
1078 * headers that might have snuck in.
1080 r->headers_out = ap_cache_cacheable_headers_out(r);
1082 /* Merge in our cached headers. However, keep any updated values. */
1083 ap_cache_accept_headers(cache->handle, r, 1);
1086 /* Write away header information to cache. It is possible that we are
1087 * trying to update headers for an entity which has already been cached.
1089 * This may fail, due to an unwritable cache area. E.g. filesystem full,
1090 * permissions problems or a read-only (re)mount. This must be handled
1093 rv = cache->provider->store_headers(cache->handle, r, info);
1095 /* Did we just update the cached headers on a revalidated response?
1097 * If so, we can now decide what to serve to the client. This is done in
1098 * the same way as with a regular response, but conditions are now checked
1099 * against the cached or merged response headers.
1101 if (cache->stale_handle) {
1102 apr_bucket_brigade *bb;
1106 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
1108 /* Restore the original request headers and see if we need to
1109 * return anything else than the cached response (ie. the original
1110 * request was conditional).
1112 r->headers_in = cache->stale_headers;
1113 status = ap_meets_conditions(r);
1117 bkt = apr_bucket_flush_create(bb->bucket_alloc);
1118 APR_BRIGADE_INSERT_TAIL(bb, bkt);
1121 cache->provider->recall_body(cache->handle, r->pool, bb);
1124 cache->block_response = 1;
1126 /* Before returning we need to handle the possible case of an
1127 * unwritable cache. Rather than leaving the entity in the cache
1128 * and having it constantly re-validated, now that we have recalled
1129 * the body it is safe to try and remove the url from the cache.
1131 if (rv != APR_SUCCESS) {
1132 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
1133 "cache: updating headers with store_headers failed. "
1134 "Removing cached url.");
1136 rv = cache->provider->remove_url(cache->stale_handle, r->pool);
1138 /* Probably a mod_disk_cache cache area has been (re)mounted
1139 * read-only, or that there is a permissions problem.
1141 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
1142 "cache: attempt to remove url from cache unsuccessful.");
1147 /* let someone else attempt to cache */
1148 ap_cache_remove_lock(conf, r, cache->handle ?
1149 (char *)cache->handle->cache_obj->key : NULL, NULL);
1151 return ap_pass_brigade(f->next, bb);
1154 if (rv != APR_SUCCESS) {
1155 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
1156 "cache: store_headers failed");
1158 ap_remove_output_filter(f);
1159 ap_cache_remove_lock(conf, r, cache->handle ?
1160 (char *)cache->handle->cache_obj->key : NULL, NULL);
1161 return ap_pass_brigade(f->next, in);
1164 rv = cache->provider->store_body(cache->handle, r, in);
1165 if (rv != APR_SUCCESS) {
1166 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
1167 "cache: store_body failed");
1168 ap_remove_output_filter(f);
1169 ap_cache_remove_lock(conf, r, cache->handle ?
1170 (char *)cache->handle->cache_obj->key : NULL, NULL);
1171 return ap_pass_brigade(f->next, in);
1174 /* proactively remove the lock as soon as we see the eos bucket */
1175 ap_cache_remove_lock(conf, r, cache->handle ?
1176 (char *)cache->handle->cache_obj->key : NULL, in);
1178 return ap_pass_brigade(f->next, in);
1182 * CACHE_REMOVE_URL filter
1183 * -----------------------
1185 * This filter gets added in the quick handler every time the CACHE_SAVE filter
1186 * gets inserted. Its purpose is to remove a confirmed stale cache entry from
1189 * CACHE_REMOVE_URL has to be a protocol filter to ensure that is run even if
1190 * the response is a canned error message, which removes the content filters
1191 * and thus the CACHE_SAVE filter from the chain.
1193 * CACHE_REMOVE_URL expects cache request rec within its context because the
1194 * request this filter runs on can be different from the one whose cache entry
1195 * should be removed, due to internal redirects.
1197 * Note that CACHE_SAVE_URL (as a content-set filter, hence run before the
1198 * protocol filters) will remove this filter if it decides to cache the file.
1199 * Therefore, if this filter is left in, it must mean we need to toss any
1202 static int cache_remove_url_filter(ap_filter_t *f, apr_bucket_brigade *in)
1204 request_rec *r = f->r;
1205 cache_request_rec *cache;
1207 /* Setup cache_request_rec */
1208 cache = (cache_request_rec *) f->ctx;
1211 /* user likely configured CACHE_REMOVE_URL manually; they should really
1212 * use mod_cache configuration to do that. So:
1213 * 1. Remove ourselves
1214 * 2. Do nothing and bail out
1216 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1217 "cache: CACHE_REMOVE_URL enabled unexpectedly");
1218 ap_remove_output_filter(f);
1219 return ap_pass_brigade(f->next, in);
1222 /* Now remove this cache entry from the cache */
1223 cache_remove_url(cache, r->pool);
1225 /* remove ourselves */
1226 ap_remove_output_filter(f);
1227 return ap_pass_brigade(f->next, in);
1234 * This filter can be optionally inserted into the filter chain by the admin as
1235 * a marker representing the precise location within the filter chain where
1236 * caching is to be performed.
1238 * When the filter chain is set up in the non-quick version of the URL handler,
1239 * the CACHE filter is replaced by the CACHE_OUT or CACHE_SAVE filter,
1240 * effectively inserting the caching filters at the point indicated by the
1241 * admin. The CACHE filter is then removed.
1243 * This allows caching to be performed before the content is passed to the
1244 * INCLUDES filter, or to a filter that might perform transformations unique
1245 * to the specific request and that would otherwise be non-cacheable.
1247 static int cache_filter(ap_filter_t *f, apr_bucket_brigade *in)
1249 /* we are just a marker, so let's just remove ourselves */
1250 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, f->r->server,
1251 "cache: CACHE filter was added twice, or was added in quick "
1252 "handler mode and will be ignored.");
1253 ap_remove_output_filter(f);
1254 return ap_pass_brigade(f->next, in);
1257 /* -------------------------------------------------------------- */
1258 /* Setup configurable data */
1260 static void * create_cache_config(apr_pool_t *p, server_rec *s)
1262 const char *tmppath;
1263 cache_server_conf *ps = apr_pcalloc(p, sizeof(cache_server_conf));
1265 /* array of URL prefixes for which caching is enabled */
1266 ps->cacheenable = apr_array_make(p, 10, sizeof(struct cache_enable));
1267 /* array of URL prefixes for which caching is disabled */
1268 ps->cachedisable = apr_array_make(p, 10, sizeof(struct cache_disable));
1269 /* maximum time to cache a document */
1270 ps->maxex = DEFAULT_CACHE_MAXEXPIRE;
1272 ps->minex = DEFAULT_CACHE_MINEXPIRE;
1274 /* default time to cache a document */
1275 ps->defex = DEFAULT_CACHE_EXPIRE;
1277 /* factor used to estimate Expires date from LastModified date */
1278 ps->factor = DEFAULT_CACHE_LMFACTOR;
1280 ps->no_last_mod_ignore_set = 0;
1281 ps->no_last_mod_ignore = 0;
1282 ps->ignorecachecontrol = 0;
1283 ps->ignorecachecontrol_set = 0;
1284 ps->store_private = 0;
1285 ps->store_private_set = 0;
1286 ps->store_nostore = 0;
1287 ps->store_nostore_set = 0;
1288 /* array of headers that should not be stored in cache */
1289 ps->ignore_headers = apr_array_make(p, 10, sizeof(char *));
1290 ps->ignore_headers_set = CACHE_IGNORE_HEADERS_UNSET;
1291 /* flag indicating that query-string should be ignored when caching */
1292 ps->ignorequerystring = 0;
1293 ps->ignorequerystring_set = 0;
1294 /* by default, run in the quick handler */
1297 /* array of identifiers that should not be used for key calculation */
1298 ps->ignore_session_id = apr_array_make(p, 10, sizeof(char *));
1299 ps->ignore_session_id_set = CACHE_IGNORE_SESSION_ID_UNSET;
1300 ps->lock = 0; /* thundering herd lock defaults to off */
1302 apr_temp_dir_get(&tmppath, p);
1304 ps->lockpath = apr_pstrcat(p, tmppath, DEFAULT_CACHE_LOCKPATH, NULL);
1306 ps->lockmaxage = apr_time_from_sec(DEFAULT_CACHE_MAXAGE);
1310 static void * merge_cache_config(apr_pool_t *p, void *basev, void *overridesv)
1312 cache_server_conf *ps = apr_pcalloc(p, sizeof(cache_server_conf));
1313 cache_server_conf *base = (cache_server_conf *) basev;
1314 cache_server_conf *overrides = (cache_server_conf *) overridesv;
1316 /* array of URL prefixes for which caching is disabled */
1317 ps->cachedisable = apr_array_append(p,
1319 overrides->cachedisable);
1320 /* array of URL prefixes for which caching is enabled */
1321 ps->cacheenable = apr_array_append(p,
1323 overrides->cacheenable);
1324 /* maximum time to cache a document */
1325 ps->maxex = (overrides->maxex_set == 0) ? base->maxex : overrides->maxex;
1326 ps->minex = (overrides->minex_set == 0) ? base->minex : overrides->minex;
1327 /* default time to cache a document */
1328 ps->defex = (overrides->defex_set == 0) ? base->defex : overrides->defex;
1329 /* factor used to estimate Expires date from LastModified date */
1331 (overrides->factor_set == 0) ? base->factor : overrides->factor;
1333 ps->no_last_mod_ignore =
1334 (overrides->no_last_mod_ignore_set == 0)
1335 ? base->no_last_mod_ignore
1336 : overrides->no_last_mod_ignore;
1337 ps->ignorecachecontrol =
1338 (overrides->ignorecachecontrol_set == 0)
1339 ? base->ignorecachecontrol
1340 : overrides->ignorecachecontrol;
1342 (overrides->store_private_set == 0)
1343 ? base->store_private
1344 : overrides->store_private;
1346 (overrides->store_nostore_set == 0)
1347 ? base->store_nostore
1348 : overrides->store_nostore;
1349 ps->ignore_headers =
1350 (overrides->ignore_headers_set == CACHE_IGNORE_HEADERS_UNSET)
1351 ? base->ignore_headers
1352 : overrides->ignore_headers;
1353 ps->ignorequerystring =
1354 (overrides->ignorequerystring_set == 0)
1355 ? base->ignorequerystring
1356 : overrides->ignorequerystring;
1357 ps->ignore_session_id =
1358 (overrides->ignore_session_id_set == CACHE_IGNORE_SESSION_ID_UNSET)
1359 ? base->ignore_session_id
1360 : overrides->ignore_session_id;
1362 (overrides->lock_set == 0)
1366 (overrides->lockpath_set == 0)
1368 : overrides->lockpath;
1370 (overrides->lockmaxage_set == 0)
1372 : overrides->lockmaxage;
1374 (overrides->quick_set == 0)
1380 static const char *set_cache_quick_handler(cmd_parms *parms, void *dummy,
1383 cache_server_conf *conf;
1386 (cache_server_conf *)ap_get_module_config(parms->server->module_config
1390 conf->quick_set = 1;
1395 static const char *set_cache_ignore_no_last_mod(cmd_parms *parms, void *dummy,
1398 cache_server_conf *conf;
1401 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1403 conf->no_last_mod_ignore = flag;
1404 conf->no_last_mod_ignore_set = 1;
1409 static const char *set_cache_ignore_cachecontrol(cmd_parms *parms,
1410 void *dummy, int flag)
1412 cache_server_conf *conf;
1415 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1417 conf->ignorecachecontrol = flag;
1418 conf->ignorecachecontrol_set = 1;
1422 static const char *set_cache_store_private(cmd_parms *parms, void *dummy,
1425 cache_server_conf *conf;
1428 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1430 conf->store_private = flag;
1431 conf->store_private_set = 1;
1435 static const char *set_cache_store_nostore(cmd_parms *parms, void *dummy,
1438 cache_server_conf *conf;
1441 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1443 conf->store_nostore = flag;
1444 conf->store_nostore_set = 1;
1448 static const char *add_ignore_header(cmd_parms *parms, void *dummy,
1451 cache_server_conf *conf;
1455 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1457 if (!strcasecmp(header, "None")) {
1458 /* if header None is listed clear array */
1459 conf->ignore_headers->nelts = 0;
1462 if ((conf->ignore_headers_set == CACHE_IGNORE_HEADERS_UNSET) ||
1463 (conf->ignore_headers->nelts)) {
1464 /* Only add header if no "None" has been found in header list
1466 * (When 'None' is passed, IGNORE_HEADERS_SET && nelts == 0.)
1468 new = (char **)apr_array_push(conf->ignore_headers);
1469 (*new) = (char *)header;
1472 conf->ignore_headers_set = CACHE_IGNORE_HEADERS_SET;
1476 static const char *add_ignore_session_id(cmd_parms *parms, void *dummy,
1477 const char *identifier)
1479 cache_server_conf *conf;
1483 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1485 if (!strcasecmp(identifier, "None")) {
1486 /* if identifier None is listed clear array */
1487 conf->ignore_session_id->nelts = 0;
1490 if ((conf->ignore_session_id_set == CACHE_IGNORE_SESSION_ID_UNSET) ||
1491 (conf->ignore_session_id->nelts)) {
1493 * Only add identifier if no "None" has been found in identifier
1496 new = (char **)apr_array_push(conf->ignore_session_id);
1497 (*new) = (char *)identifier;
1500 conf->ignore_session_id_set = CACHE_IGNORE_SESSION_ID_SET;
1504 static const char *add_cache_enable(cmd_parms *parms, void *dummy,
1508 cache_server_conf *conf;
1509 struct cache_enable *new;
1511 const char *err = ap_check_cmd_context(parms,
1512 NOT_IN_DIRECTORY|NOT_IN_LIMIT|NOT_IN_FILES);
1518 return apr_psprintf(parms->pool,
1519 "provider (%s) starts with a '/'. Are url and provider switched?",
1527 return apr_psprintf(parms->pool,
1528 "CacheEnable provider (%s) is missing an URL.", type);
1530 if (parms->path && strncmp(parms->path, url, strlen(parms->path))) {
1531 return "When in a Location, CacheEnable must specify a path or an URL below "
1536 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1538 new = apr_array_push(conf->cacheenable);
1540 if (apr_uri_parse(parms->pool, url, &(new->url))) {
1543 if (new->url.path) {
1544 new->pathlen = strlen(new->url.path);
1547 new->url.path = "/";
1552 static const char *add_cache_disable(cmd_parms *parms, void *dummy,
1555 cache_server_conf *conf;
1556 struct cache_disable *new;
1558 const char *err = ap_check_cmd_context(parms,
1559 NOT_IN_DIRECTORY|NOT_IN_LIMIT|NOT_IN_FILES);
1564 if (parms->path && !strcmp(url, "on")) {
1567 if (url[0] != '/' && !ap_strchr_c(url, ':')) {
1568 return "CacheDisable must specify a path or an URL, or when in a Location, "
1572 if (parms->path && strncmp(parms->path, url, strlen(parms->path))) {
1573 return "When in a Location, CacheDisable must specify a path or an URL below "
1578 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1580 new = apr_array_push(conf->cachedisable);
1581 if (apr_uri_parse(parms->pool, url, &(new->url))) {
1584 if (new->url.path) {
1585 new->pathlen = strlen(new->url.path);
1588 new->url.path = "/";
1593 static const char *set_cache_maxex(cmd_parms *parms, void *dummy,
1596 cache_server_conf *conf;
1599 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1601 conf->maxex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
1602 conf->maxex_set = 1;
1606 static const char *set_cache_minex(cmd_parms *parms, void *dummy,
1609 cache_server_conf *conf;
1612 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1614 conf->minex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
1615 conf->minex_set = 1;
1619 static const char *set_cache_defex(cmd_parms *parms, void *dummy,
1622 cache_server_conf *conf;
1625 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1627 conf->defex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
1628 conf->defex_set = 1;
1632 static const char *set_cache_factor(cmd_parms *parms, void *dummy,
1635 cache_server_conf *conf;
1639 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1641 if (sscanf(arg, "%lg", &val) != 1) {
1642 return "CacheLastModifiedFactor value must be a float";
1645 conf->factor_set = 1;
1649 static const char *set_cache_ignore_querystring(cmd_parms *parms, void *dummy,
1652 cache_server_conf *conf;
1655 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1657 conf->ignorequerystring = flag;
1658 conf->ignorequerystring_set = 1;
1662 static const char *set_cache_lock(cmd_parms *parms, void *dummy,
1665 cache_server_conf *conf;
1668 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1675 static const char *set_cache_lock_path(cmd_parms *parms, void *dummy,
1678 cache_server_conf *conf;
1681 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1684 conf->lockpath = ap_server_root_relative(parms->pool, arg);
1685 if (!conf->lockpath) {
1686 return apr_pstrcat(parms->pool, "Invalid CacheLockPath path ",
1689 conf->lockpath_set = 1;
1693 static const char *set_cache_lock_maxage(cmd_parms *parms, void *dummy,
1696 cache_server_conf *conf;
1697 apr_int64_t seconds;
1700 (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1702 seconds = apr_atoi64(arg);
1704 return "CacheLockMaxAge value must be a non-zero positive integer";
1706 conf->lockmaxage = apr_time_from_sec(seconds);
1707 conf->lockmaxage_set = 1;
1711 static int cache_post_config(apr_pool_t *p, apr_pool_t *plog,
1712 apr_pool_t *ptemp, server_rec *s)
1714 /* This is the means by which unusual (non-unix) os's may find alternate
1715 * means to run a given command (e.g. shebang/registry parsing on Win32)
1717 cache_generate_key = APR_RETRIEVE_OPTIONAL_FN(ap_cache_generate_key);
1718 if (!cache_generate_key) {
1719 cache_generate_key = cache_generate_key_default;
1725 static const command_rec cache_cmds[] =
1728 * Consider a new config directive that enables loading specific cache
1729 * implememtations (like mod_cache_mem, mod_cache_file, etc.).
1730 * Rather than using a LoadModule directive, admin would use something
1731 * like CacheModule mem_cache_module | file_cache_module, etc,
1732 * which would cause the approprpriate cache module to be loaded.
1733 * This is more intuitive that requiring a LoadModule directive.
1736 AP_INIT_TAKE12("CacheEnable", add_cache_enable, NULL, RSRC_CONF|ACCESS_CONF,
1737 "A cache type and partial URL prefix below which "
1738 "caching is enabled"),
1739 AP_INIT_TAKE1("CacheDisable", add_cache_disable, NULL, RSRC_CONF|ACCESS_CONF,
1740 "A partial URL prefix below which caching is disabled"),
1741 AP_INIT_TAKE1("CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF,
1742 "The maximum time in seconds to cache a document"),
1743 AP_INIT_TAKE1("CacheMinExpire", set_cache_minex, NULL, RSRC_CONF,
1744 "The minimum time in seconds to cache a document"),
1745 AP_INIT_TAKE1("CacheDefaultExpire", set_cache_defex, NULL, RSRC_CONF,
1746 "The default time in seconds to cache a document"),
1747 AP_INIT_FLAG("CacheQuickHandler", set_cache_quick_handler, NULL,
1749 "Run the cache in the quick handler, default on"),
1750 AP_INIT_FLAG("CacheIgnoreNoLastMod", set_cache_ignore_no_last_mod, NULL,
1752 "Ignore Responses where there is no Last Modified Header"),
1753 AP_INIT_FLAG("CacheIgnoreCacheControl", set_cache_ignore_cachecontrol,
1755 "Ignore requests from the client for uncached content"),
1756 AP_INIT_FLAG("CacheStorePrivate", set_cache_store_private,
1758 "Ignore 'Cache-Control: private' and store private content"),
1759 AP_INIT_FLAG("CacheStoreNoStore", set_cache_store_nostore,
1761 "Ignore 'Cache-Control: no-store' and store sensitive content"),
1762 AP_INIT_ITERATE("CacheIgnoreHeaders", add_ignore_header, NULL, RSRC_CONF,
1763 "A space separated list of headers that should not be "
1764 "stored by the cache"),
1765 AP_INIT_FLAG("CacheIgnoreQueryString", set_cache_ignore_querystring,
1767 "Ignore query-string when caching"),
1768 AP_INIT_ITERATE("CacheIgnoreURLSessionIdentifiers", add_ignore_session_id,
1769 NULL, RSRC_CONF, "A space separated list of session "
1770 "identifiers that should be ignored for creating the key "
1771 "of the cached entity."),
1772 AP_INIT_TAKE1("CacheLastModifiedFactor", set_cache_factor, NULL, RSRC_CONF,
1773 "The factor used to estimate Expires date from "
1774 "LastModified date"),
1775 AP_INIT_FLAG("CacheLock", set_cache_lock,
1777 "Enable or disable the thundering herd lock."),
1778 AP_INIT_TAKE1("CacheLockPath", set_cache_lock_path, NULL, RSRC_CONF,
1779 "The thundering herd lock path. Defaults to the '"
1780 DEFAULT_CACHE_LOCKPATH "' directory in the system "
1782 AP_INIT_TAKE1("CacheLockMaxAge", set_cache_lock_maxage, NULL, RSRC_CONF,
1783 "Maximum age of any thundering herd lock."),
1787 static void register_hooks(apr_pool_t *p)
1789 /* cache initializer */
1790 /* cache quick handler */
1791 ap_hook_quick_handler(cache_quick_handler, NULL, NULL, APR_HOOK_FIRST);
1793 ap_hook_handler(cache_handler, NULL, NULL, APR_HOOK_REALLY_FIRST);
1795 * XXX The cache filters need to run right after the handlers and before
1796 * any other filters. Consider creating AP_FTYPE_CACHE for this purpose.
1798 * Depending on the type of request (subrequest / main request) they
1799 * need to be run before AP_FTYPE_CONTENT_SET / after AP_FTYPE_CONTENT_SET
1800 * filters. Thus create two filter handles for each type:
1801 * cache_save_filter_handle / cache_out_filter_handle to be used by
1803 * cache_save_subreq_filter_handle / cache_out_subreq_filter_handle
1804 * to be run by subrequest
1807 * CACHE is placed into the filter chain at an admin specified location,
1808 * and when the cache_handler is run, the CACHE filter is swapped with
1809 * the CACHE_OUT filter, or CACHE_SAVE filter as appropriate. This has
1810 * the effect of offering optional fine control of where the cache is
1811 * inserted into the filter chain.
1813 cache_filter_handle =
1814 ap_register_output_filter("CACHE",
1819 * CACHE_SAVE must go into the filter chain after a possible DEFLATE
1820 * filter to ensure that the compressed content is stored.
1821 * Incrementing filter type by 1 ensures his happens.
1823 cache_save_filter_handle =
1824 ap_register_output_filter("CACHE_SAVE",
1827 AP_FTYPE_CONTENT_SET+1);
1829 * CACHE_SAVE_SUBREQ must go into the filter chain before SUBREQ_CORE to
1830 * handle subrequsts. Decrementing filter type by 1 ensures this
1833 cache_save_subreq_filter_handle =
1834 ap_register_output_filter("CACHE_SAVE_SUBREQ",
1837 AP_FTYPE_CONTENT_SET-1);
1839 * CACHE_OUT must go into the filter chain after a possible DEFLATE
1840 * filter to ensure that already compressed cache objects do not
1841 * get compressed again. Incrementing filter type by 1 ensures
1844 cache_out_filter_handle =
1845 ap_register_output_filter("CACHE_OUT",
1848 AP_FTYPE_CONTENT_SET+1);
1850 * CACHE_OUT_SUBREQ must go into the filter chain before SUBREQ_CORE to
1851 * handle subrequsts. Decrementing filter type by 1 ensures this
1854 cache_out_subreq_filter_handle =
1855 ap_register_output_filter("CACHE_OUT_SUBREQ",
1858 AP_FTYPE_CONTENT_SET-1);
1859 /* CACHE_REMOVE_URL has to be a protocol filter to ensure that is
1860 * run even if the response is a canned error message, which
1861 * removes the content filters.
1863 cache_remove_url_filter_handle =
1864 ap_register_output_filter("CACHE_REMOVE_URL",
1865 cache_remove_url_filter,
1868 ap_hook_post_config(cache_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
1871 AP_DECLARE_MODULE(cache) =
1873 STANDARD20_MODULE_STUFF,
1874 NULL, /* create per-directory config structure */
1875 NULL, /* merge per-directory config structures */
1876 create_cache_config, /* create per-server config structure */
1877 merge_cache_config, /* merge per-server config structures */
1878 cache_cmds, /* command apr_table_t */