]> granicus.if.org Git - apache/blob - modules/cache/mod_cache.c
mod_cache: Make CacheEnable and CacheDisable configurable per
[apache] / modules / cache / mod_cache.c
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "mod_cache.h"
18
19 #include "cache_storage.h"
20 #include "cache_util.h"
21
22 module AP_MODULE_DECLARE_DATA cache_module;
23 APR_OPTIONAL_FN_TYPE(ap_cache_generate_key) *cache_generate_key;
24
25 /* -------------------------------------------------------------- */
26
27
28 /* Handles for cache filters, resolved at startup to eliminate
29  * a name-to-function mapping on each request
30  */
31 static ap_filter_rec_t *cache_filter_handle;
32 static ap_filter_rec_t *cache_save_filter_handle;
33 static ap_filter_rec_t *cache_save_subreq_filter_handle;
34 static ap_filter_rec_t *cache_out_filter_handle;
35 static ap_filter_rec_t *cache_out_subreq_filter_handle;
36 static ap_filter_rec_t *cache_remove_url_filter_handle;
37
38 /*
39  * CACHE handler
40  * -------------
41  *
42  * Can we deliver this request from the cache?
43  * If yes:
44  *   deliver the content by installing the CACHE_OUT filter.
45  * If no:
46  *   check whether we're allowed to try cache it
47  *   If yes:
48  *     add CACHE_SAVE filter
49  *   If No:
50  *     oh well.
51  *
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
56  * implementation.
57  *
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.
64  */
65
66 static int cache_quick_handler(request_rec *r, int lookup)
67 {
68     apr_status_t rv;
69     const char *auth;
70     cache_provider_list *providers;
71     cache_request_rec *cache;
72     apr_bucket_brigade *out;
73     apr_bucket *e;
74     ap_filter_t *next;
75     ap_filter_rec_t *cache_out_handle;
76     cache_server_conf *conf;
77
78     conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
79                                                       &cache_module);
80
81     /* only run if the quick handler is enabled */
82     if (!conf->quick) {
83         return DECLINED;
84     }
85
86     /*
87      * Which cache module (if any) should handle this request?
88      */
89     if (!(providers = cache_get_providers(r, conf, r->parsed_uri))) {
90         return DECLINED;
91     }
92
93     /* make space for the per request config */
94     cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
95     cache->size = -1;
96     cache->out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
97
98     /* save away the possible providers */
99     cache->providers = providers;
100
101     /*
102      * Are we allowed to serve cached info at all?
103      */
104
105     /* find certain cache controlling headers */
106     auth = apr_table_get(r->headers_in, "Authorization");
107
108     /* First things first - does the request allow us to return
109      * cached information at all? If not, just decline the request.
110      */
111     if (auth) {
112         return DECLINED;
113     }
114
115     /* Are we something other than GET or HEAD? If so, invalidate
116      * the cached entities.
117      */
118     if (r->method_number != M_GET) {
119
120         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
121                 "Invalidating all cached entities in response to '%s' request for %s",
122                 r->method, r->uri);
123
124         cache_invalidate(cache, r);
125
126         /* we've got a cache invalidate! tell everyone who cares */
127         cache_run_cache_status(cache->handle, r, r->headers_out,
128                 AP_CACHE_INVALIDATE, apr_psprintf(r->pool,
129                         "cache invalidated by %s", r->method));
130
131         return DECLINED;
132     }
133
134     /*
135      * Try to serve this request from the cache.
136      *
137      * If no existing cache file (DECLINED)
138      *   add cache_save filter
139      * If cached file (OK)
140      *   clear filter stack
141      *   add cache_out filter
142      *   return OK
143      */
144     rv = cache_select(cache, r);
145     if (rv != OK) {
146         if (rv == DECLINED) {
147             if (!lookup) {
148
149                 /* try to obtain a cache lock at this point. if we succeed,
150                  * we are the first to try and cache this url. if we fail,
151                  * it means someone else is already trying to cache this
152                  * url, and we should just let the request through to the
153                  * backend without any attempt to cache. this stops
154                  * duplicated simultaneous attempts to cache an entity.
155                  */
156                 rv = cache_try_lock(conf, cache, r);
157                 if (APR_SUCCESS == rv) {
158
159                     /*
160                      * Add cache_save filter to cache this request. Choose
161                      * the correct filter by checking if we are a subrequest
162                      * or not.
163                      */
164                     if (r->main) {
165                         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
166                                 r, "Adding CACHE_SAVE_SUBREQ filter for %s",
167                                 r->uri);
168                         cache->save_filter = ap_add_output_filter_handle(
169                                 cache_save_subreq_filter_handle, cache, r,
170                                 r->connection);
171                     }
172                     else {
173                         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
174                                 r, "Adding CACHE_SAVE filter for %s",
175                                 r->uri);
176                         cache->save_filter = ap_add_output_filter_handle(
177                                 cache_save_filter_handle, cache, r,
178                                 r->connection);
179                     }
180
181                     apr_pool_userdata_setn(cache, CACHE_CTX_KEY, NULL, r->pool);
182
183                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
184                             "Adding CACHE_REMOVE_URL filter for %s",
185                             r->uri);
186
187                     /* Add cache_remove_url filter to this request to remove a
188                      * stale cache entry if needed. Also put the current cache
189                      * request rec in the filter context, as the request that
190                      * is available later during running the filter may be
191                      * different due to an internal redirect.
192                      */
193                     cache->remove_url_filter = ap_add_output_filter_handle(
194                             cache_remove_url_filter_handle, cache, r,
195                             r->connection);
196
197                 }
198                 else {
199                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv,
200                             r, "Cache locked for url, not caching "
201                             "response: %s", r->uri);
202                 }
203             }
204             else {
205                 if (cache->stale_headers) {
206                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
207                             r, "Restoring request headers for %s",
208                             r->uri);
209
210                     r->headers_in = cache->stale_headers;
211                 }
212             }
213         }
214         else {
215             /* error */
216             return rv;
217         }
218         return DECLINED;
219     }
220
221     /* we've got a cache hit! tell everyone who cares */
222     cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_HIT,
223             "cache hit");
224
225     /* if we are a lookup, we are exiting soon one way or another; Restore
226      * the headers. */
227     if (lookup) {
228         if (cache->stale_headers) {
229             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
230                     "Restoring request headers.");
231             r->headers_in = cache->stale_headers;
232         }
233     }
234
235     rv = ap_meets_conditions(r);
236     if (rv != OK) {
237         /* If we are a lookup, we have to return DECLINED as we have no
238          * way of knowing if we will be able to serve the content.
239          */
240         if (lookup) {
241             return DECLINED;
242         }
243
244         /* Return cached status. */
245         return rv;
246     }
247
248     /* If we're a lookup, we can exit now instead of serving the content. */
249     if (lookup) {
250         return OK;
251     }
252
253     /* Serve up the content */
254
255     /* We are in the quick handler hook, which means that no output
256      * filters have been set. So lets run the insert_filter hook.
257      */
258     ap_run_insert_filter(r);
259
260     /*
261      * Add cache_out filter to serve this request. Choose
262      * the correct filter by checking if we are a subrequest
263      * or not.
264      */
265     if (r->main) {
266         cache_out_handle = cache_out_subreq_filter_handle;
267     }
268     else {
269         cache_out_handle = cache_out_filter_handle;
270     }
271     ap_add_output_filter_handle(cache_out_handle, cache, r, r->connection);
272
273     /*
274      * Remove all filters that are before the cache_out filter. This ensures
275      * that we kick off the filter stack with our cache_out filter being the
276      * first in the chain. This make sense because we want to restore things
277      * in the same manner as we saved them.
278      * There may be filters before our cache_out filter, because
279      *
280      * 1. We call ap_set_content_type during cache_select. This causes
281      *    Content-Type specific filters to be added.
282      * 2. We call the insert_filter hook. This causes filters e.g. like
283      *    the ones set with SetOutputFilter to be added.
284      */
285     next = r->output_filters;
286     while (next && (next->frec != cache_out_handle)) {
287         ap_remove_output_filter(next);
288         next = next->next;
289     }
290
291     /* kick off the filter stack */
292     out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
293     e = apr_bucket_eos_create(out->bucket_alloc);
294     APR_BRIGADE_INSERT_TAIL(out, e);
295     rv = ap_pass_brigade(r->output_filters, out);
296     if (rv != APR_SUCCESS) {
297         if (rv != AP_FILTER_ERROR) {
298             /* no way to know what type of error occurred */
299             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,
300                           "cache_quick_handler(%s): ap_pass_brigade returned %i",
301                           cache->provider_name, rv);
302             return HTTP_INTERNAL_SERVER_ERROR;
303         }
304         return rv;
305     }
306
307     return OK;
308 }
309
310 /**
311  * If the two filter handles are present within the filter chain, replace
312  * the last instance of the first filter with the last instance of the
313  * second filter, and return true. If the second filter is not present at
314  * all, the first filter is removed, and false is returned. If neither
315  * filter is present, false is returned and this function does nothing.
316  * If a stop filter is specified, processing will stop once this filter is
317  * reached.
318  */
319 static int cache_replace_filter(ap_filter_t *next, ap_filter_rec_t *from,
320         ap_filter_rec_t *to, ap_filter_rec_t *stop) {
321     ap_filter_t *ffrom = NULL, *fto = NULL;
322     while (next && next->frec != stop) {
323         if (next->frec == from && !next->ctx) {
324             ffrom = next;
325         }
326         if (next->frec == to && !next->ctx) {
327             fto = next;
328         }
329         next = next->next;
330     }
331     if (ffrom && fto) {
332         ffrom->frec = fto->frec;
333         ffrom->ctx = fto->ctx;
334         ap_remove_output_filter(fto);
335         return 1;
336     }
337     if (ffrom) {
338         ap_remove_output_filter(ffrom);
339     }
340     return 0;
341 }
342
343 /**
344  * Find the given filter, and return it if found, or NULL otherwise.
345  */
346 static ap_filter_t *cache_get_filter(ap_filter_t *next, ap_filter_rec_t *rec) {
347     while (next) {
348         if (next->frec == rec && next->ctx) {
349             break;
350         }
351         next = next->next;
352     }
353     return next;
354 }
355
356 /**
357  * The cache handler is functionally similar to the cache_quick_hander,
358  * however a number of steps that are required by the quick handler are
359  * not required here, as the normal httpd processing has already handled
360  * these steps.
361  */
362 static int cache_handler(request_rec *r)
363 {
364     apr_status_t rv;
365     cache_provider_list *providers;
366     cache_request_rec *cache;
367     apr_bucket_brigade *out;
368     apr_bucket *e;
369     ap_filter_t *next;
370     ap_filter_rec_t *cache_out_handle;
371     ap_filter_rec_t *cache_save_handle;
372     cache_server_conf *conf;
373
374     conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
375                                                       &cache_module);
376
377     /* only run if the quick handler is disabled */
378     if (conf->quick) {
379         return DECLINED;
380     }
381
382     /*
383      * Which cache module (if any) should handle this request?
384      */
385     if (!(providers = cache_get_providers(r, conf, r->parsed_uri))) {
386         return DECLINED;
387     }
388
389     /* make space for the per request config */
390     cache = apr_pcalloc(r->pool, sizeof(cache_request_rec));
391     cache->size = -1;
392     cache->out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
393
394     /* save away the possible providers */
395     cache->providers = providers;
396
397     /* Are we something other than GET or HEAD? If so, invalidate
398      * the cached entities.
399      */
400     if (r->method_number != M_GET) {
401
402         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
403                 "Invalidating all cached entities in response to '%s' request for %s",
404                 r->method, r->uri);
405
406         cache_invalidate(cache, r);
407
408         /* we've got a cache invalidate! tell everyone who cares */
409         cache_run_cache_status(cache->handle, r, r->headers_out,
410                 AP_CACHE_INVALIDATE, apr_psprintf(r->pool,
411                         "cache invalidated by %s", r->method));
412
413         return DECLINED;
414
415     }
416
417     /*
418      * Try to serve this request from the cache.
419      *
420      * If no existing cache file (DECLINED)
421      *   add cache_save filter
422      * If cached file (OK)
423      *   clear filter stack
424      *   add cache_out filter
425      *   return OK
426      */
427     rv = cache_select(cache, r);
428     if (rv != OK) {
429         if (rv == DECLINED) {
430
431             /* try to obtain a cache lock at this point. if we succeed,
432              * we are the first to try and cache this url. if we fail,
433              * it means someone else is already trying to cache this
434              * url, and we should just let the request through to the
435              * backend without any attempt to cache. this stops
436              * duplicated simultaneous attempts to cache an entity.
437              */
438             rv = cache_try_lock(conf, cache, r);
439             if (APR_SUCCESS == rv) {
440
441                 /*
442                  * Add cache_save filter to cache this request. Choose
443                  * the correct filter by checking if we are a subrequest
444                  * or not.
445                  */
446                 if (r->main) {
447                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
448                             r, "Adding CACHE_SAVE_SUBREQ filter for %s",
449                             r->uri);
450                     cache_save_handle = cache_save_subreq_filter_handle;
451                 }
452                 else {
453                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
454                             r, "Adding CACHE_SAVE filter for %s",
455                             r->uri);
456                     cache_save_handle = cache_save_filter_handle;
457                 }
458                 ap_add_output_filter_handle(cache_save_handle, cache, r,
459                         r->connection);
460
461                 /*
462                  * Did the user indicate the precise location of the
463                  * CACHE_SAVE filter by inserting the CACHE filter as a
464                  * marker?
465                  *
466                  * If so, we get cunning and replace CACHE with the
467                  * CACHE_SAVE filter. This has the effect of inserting
468                  * the CACHE_SAVE filter at the precise location where
469                  * the admin wants to cache the content. All filters that
470                  * lie before and after the original location of the CACHE
471                  * filter will remain in place.
472                  */
473                 if (cache_replace_filter(r->output_filters,
474                         cache_filter_handle, cache_save_handle,
475                         ap_get_input_filter_handle("SUBREQ_CORE"))) {
476                     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
477                             r, "Replacing CACHE with CACHE_SAVE "
478                             "filter for %s", r->uri);
479                 }
480
481                 /* save away the save filter stack */
482                 cache->save_filter = cache_get_filter(r->output_filters,
483                         cache_save_filter_handle);
484
485                 apr_pool_userdata_setn(cache, CACHE_CTX_KEY, NULL, r->pool);
486
487                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
488                         "Adding CACHE_REMOVE_URL filter for %s",
489                         r->uri);
490
491                 /* Add cache_remove_url filter to this request to remove a
492                  * stale cache entry if needed. Also put the current cache
493                  * request rec in the filter context, as the request that
494                  * is available later during running the filter may be
495                  * different due to an internal redirect.
496                  */
497                 cache->remove_url_filter
498                         = ap_add_output_filter_handle(
499                                 cache_remove_url_filter_handle, cache, r,
500                                 r->connection);
501
502             }
503             else {
504                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv,
505                         r, "Cache locked for url, not caching "
506                         "response: %s", r->uri);
507             }
508         }
509         else {
510             /* error */
511             return rv;
512         }
513         return DECLINED;
514     }
515
516     /* we've got a cache hit! tell everyone who cares */
517     cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_HIT,
518             "cache hit");
519
520     rv = ap_meets_conditions(r);
521     if (rv != OK) {
522         return rv;
523     }
524
525     /* Serve up the content */
526
527     /*
528      * Add cache_out filter to serve this request. Choose
529      * the correct filter by checking if we are a subrequest
530      * or not.
531      */
532     if (r->main) {
533         cache_out_handle = cache_out_subreq_filter_handle;
534     }
535     else {
536         cache_out_handle = cache_out_filter_handle;
537     }
538     ap_add_output_filter_handle(cache_out_handle, cache, r, r->connection);
539
540     /*
541      * Did the user indicate the precise location of the CACHE_OUT filter by
542      * inserting the CACHE filter as a marker?
543      *
544      * If so, we get cunning and replace CACHE with the CACHE_OUT filters.
545      * This has the effect of inserting the CACHE_OUT filter at the precise
546      * location where the admin wants to cache the content. All filters that
547      * lie *after* the original location of the CACHE filter will remain in
548      * place.
549      */
550     if (cache_replace_filter(r->output_filters, cache_filter_handle,
551             cache_out_handle, ap_get_input_filter_handle("SUBREQ_CORE"))) {
552         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS,
553                 r, "Replacing CACHE with CACHE_OUT filter for %s",
554                 r->uri);
555     }
556
557     /*
558      * Remove all filters that are before the cache_out filter. This ensures
559      * that we kick off the filter stack with our cache_out filter being the
560      * first in the chain. This make sense because we want to restore things
561      * in the same manner as we saved them.
562      * There may be filters before our cache_out filter, because
563      *
564      * 1. We call ap_set_content_type during cache_select. This causes
565      *    Content-Type specific filters to be added.
566      * 2. We call the insert_filter hook. This causes filters e.g. like
567      *    the ones set with SetOutputFilter to be added.
568      */
569     next = r->output_filters;
570     while (next && (next->frec != cache_out_handle)) {
571         ap_remove_output_filter(next);
572         next = next->next;
573     }
574
575     /* kick off the filter stack */
576     out = apr_brigade_create(r->pool, r->connection->bucket_alloc);
577     e = apr_bucket_eos_create(out->bucket_alloc);
578     APR_BRIGADE_INSERT_TAIL(out, e);
579     rv = ap_pass_brigade(r->output_filters, out);
580     if (rv != APR_SUCCESS) {
581         if (rv != AP_FILTER_ERROR) {
582             /* no way to know what type of error occurred */
583             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,
584                           "cache_handler(%s): ap_pass_brigade returned %i",
585                           cache->provider_name, rv);
586             return HTTP_INTERNAL_SERVER_ERROR;
587         }
588         return rv;
589     }
590
591     return OK;
592 }
593
594 /*
595  * CACHE_OUT filter
596  * ----------------
597  *
598  * Deliver cached content (headers and body) up the stack.
599  */
600 static int cache_out_filter(ap_filter_t *f, apr_bucket_brigade *in)
601 {
602     request_rec *r = f->r;
603     apr_bucket *e;
604     cache_request_rec *cache = (cache_request_rec *)f->ctx;
605
606     if (!cache) {
607         /* user likely configured CACHE_OUT manually; they should use mod_cache
608          * configuration to do that */
609         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
610                 "CACHE/CACHE_OUT filter enabled while caching is disabled, ignoring");
611         ap_remove_output_filter(f);
612         return ap_pass_brigade(f->next, in);
613     }
614
615     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
616             "cache: running CACHE_OUT filter");
617
618     /* clean out any previous response up to EOS, if any */
619     for (e = APR_BRIGADE_FIRST(in);
620          e != APR_BRIGADE_SENTINEL(in);
621          e = APR_BUCKET_NEXT(e))
622     {
623         if (APR_BUCKET_IS_EOS(e)) {
624             apr_bucket_brigade *bb = apr_brigade_create(r->pool,
625                     r->connection->bucket_alloc);
626
627             /* restore status of cached response */
628             r->status = cache->handle->cache_obj->info.status;
629
630             /* recall_headers() was called in cache_select() */
631             cache->provider->recall_body(cache->handle, r->pool, bb);
632             APR_BRIGADE_PREPEND(in, bb);
633
634             /* This filter is done once it has served up its content */
635             ap_remove_output_filter(f);
636
637             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
638                     "cache: serving %s", r->uri);
639             return ap_pass_brigade(f->next, in);
640
641         }
642         apr_bucket_delete(e);
643     }
644
645     return APR_SUCCESS;
646 }
647
648 /*
649  * Having jumped through all the hoops and decided to cache the
650  * response, call store_body() for each brigade, handling the
651  * case where the provider can't swallow the full brigade. In this
652  * case, we write the brigade we were passed out downstream, and
653  * loop around to try and cache some more until the in brigade is
654  * completely empty. As soon as the out brigade contains eos, call
655  * commit_entity() to finalise the cached element.
656  */
657 static int cache_save_store(ap_filter_t *f, apr_bucket_brigade *in,
658         cache_server_conf *conf, cache_request_rec *cache)
659 {
660     int rv = APR_SUCCESS;
661     apr_bucket *e;
662
663     /* pass the brigade in into the cache provider, which is then
664      * expected to move cached buckets to the out brigade, for us
665      * to pass up the filter stack. repeat until in is empty, or
666      * we fail.
667      */
668     while (APR_SUCCESS == rv && !APR_BRIGADE_EMPTY(in)) {
669
670         rv = cache->provider->store_body(cache->handle, f->r, in, cache->out);
671         if (rv != APR_SUCCESS) {
672             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, f->r,
673                     "cache: Cache provider's store_body failed!");
674             ap_remove_output_filter(f);
675
676             /* give someone else the chance to cache the file */
677             cache_remove_lock(conf, cache, f->r, NULL);
678
679             /* give up trying to cache, just step out the way */
680             APR_BRIGADE_PREPEND(in, cache->out);
681             return ap_pass_brigade(f->next, in);
682
683         }
684
685         /* does the out brigade contain eos? if so, we're done, commit! */
686         for (e = APR_BRIGADE_FIRST(cache->out);
687              e != APR_BRIGADE_SENTINEL(cache->out);
688              e = APR_BUCKET_NEXT(e))
689         {
690             if (APR_BUCKET_IS_EOS(e)) {
691                 rv = cache->provider->commit_entity(cache->handle, f->r);
692                 break;
693             }
694         }
695
696         /* conditionally remove the lock as soon as we see the eos bucket */
697         cache_remove_lock(conf, cache, f->r, cache->out);
698
699         if (APR_BRIGADE_EMPTY(cache->out)) {
700             if (APR_BRIGADE_EMPTY(in)) {
701                 /* cache provider wants more data before passing the brigade
702                  * upstream, oblige the provider by leaving to fetch more.
703                  */
704                 break;
705             }
706             else {
707                 /* oops, no data out, but not all data read in either, be
708                  * safe and stand down to prevent a spin.
709                  */
710                 ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, f->r,
711                         "cache: Cache provider's store_body returned an "
712                         "empty brigade, but didn't consume all of the"
713                         "input brigade, standing down to prevent a spin");
714                 ap_remove_output_filter(f);
715
716                 /* give someone else the chance to cache the file */
717                 cache_remove_lock(conf, cache, f->r, NULL);
718
719                 return ap_pass_brigade(f->next, in);
720             }
721         }
722
723         rv = ap_pass_brigade(f->next, cache->out);
724     }
725
726     return rv;
727 }
728
729 /*
730  * CACHE_SAVE filter
731  * ---------------
732  *
733  * Decide whether or not this content should be cached.
734  * If we decide no it should not:
735  *   remove the filter from the chain
736  * If we decide yes it should:
737  *   Have we already started saving the response?
738  *      If we have started, pass the data to the storage manager via store_body
739  *      Otherwise:
740  *        Check to see if we *can* save this particular response.
741  *        If we can, call cache_create_entity() and save the headers and body
742  *   Finally, pass the data to the next filter (the network or whatever)
743  *
744  * After the various failure cases, the cache lock is proactively removed, so
745  * that another request is given the opportunity to attempt to cache without
746  * waiting for a potentially slow client to acknowledge the failure.
747  */
748
749 static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
750 {
751     int rv = !OK;
752     request_rec *r = f->r;
753     cache_request_rec *cache = (cache_request_rec *)f->ctx;
754     cache_server_conf *conf;
755     cache_dir_conf *dconf;
756     cache_control_t control;
757     const char *cc_out, *cl, *pragma;
758     const char *exps, *lastmods, *dates, *etag;
759     apr_time_t exp, date, lastmod, now;
760     apr_off_t size = -1;
761     cache_info *info = NULL;
762     char *reason;
763     apr_pool_t *p;
764     apr_bucket *e;
765     apr_table_t *headers;
766
767     conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
768                                                       &cache_module);
769
770     /* Setup cache_request_rec */
771     if (!cache) {
772         /* user likely configured CACHE_SAVE manually; they should really use
773          * mod_cache configuration to do that
774          */
775         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
776                 "CACHE/CACHE_SAVE filter enabled while caching is disabled, ignoring");
777         ap_remove_output_filter(f);
778         return ap_pass_brigade(f->next, in);
779     }
780
781     reason = NULL;
782     p = r->pool;
783     /*
784      * Pass Data to Cache
785      * ------------------
786      * This section passes the brigades into the cache modules, but only
787      * if the setup section (see below) is complete.
788      */
789     if (cache->block_response) {
790         /* We've already sent down the response and EOS.  So, ignore
791          * whatever comes now.
792          */
793         return APR_SUCCESS;
794     }
795
796     /* have we already run the cacheability check and set up the
797      * cached file handle?
798      */
799     if (cache->in_checked) {
800         return cache_save_store(f, in, conf, cache);
801     }
802
803     /*
804      * Setup Data in Cache
805      * -------------------
806      * This section opens the cache entity and sets various caching
807      * parameters, and decides whether this URL should be cached at
808      * all. This section is* run before the above section.
809      */
810
811     dconf = ap_get_module_config(r->per_dir_config, &cache_module);
812
813     /* RFC2616 13.8 Errors or Incomplete Response Cache Behavior:
814      * If a cache receives a 5xx response while attempting to revalidate an
815      * entry, it MAY either forward this response to the requesting client,
816      * or act as if the server failed to respond. In the latter case, it MAY
817      * return a previously received response unless the cached entry
818      * includes the "must-revalidate" cache-control directive (see section
819      * 14.9).
820      *
821      * This covers the case where an error was generated behind us, for example
822      * by a backend server via mod_proxy.
823      */
824     if (dconf->stale_on_error && r->status >= HTTP_INTERNAL_SERVER_ERROR) {
825
826         ap_remove_output_filter(cache->remove_url_filter);
827
828         if (cache->stale_handle
829                 && !cache->stale_handle->cache_obj->info.control.must_revalidate
830                 && !cache->stale_handle->cache_obj->info.control.proxy_revalidate) {
831             const char *warn_head;
832
833             /* morph the current save filter into the out filter, and serve from
834              * cache.
835              */
836             cache->handle = cache->stale_handle;
837             if (r->main) {
838                 f->frec = cache_out_subreq_filter_handle;
839             }
840             else {
841                 f->frec = cache_out_filter_handle;
842             }
843
844             r->headers_out = cache->stale_handle->resp_hdrs;
845
846             /* add a revalidation warning */
847             warn_head = apr_table_get(r->err_headers_out, "Warning");
848             if ((warn_head == NULL) || ((warn_head != NULL)
849                     && (ap_strstr_c(warn_head, "111") == NULL))) {
850                 apr_table_mergen(r->err_headers_out, "Warning",
851                         "111 Revalidation failed");
852             }
853
854             cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_HIT,
855                     apr_psprintf(r->pool,
856                             "cache hit: %d status; stale content returned",
857                             r->status));
858
859             /* give someone else the chance to cache the file */
860             cache_remove_lock(conf, cache, f->r, NULL);
861
862             /* pass brigade to our morphed out filter */
863             return ap_pass_brigade(f, in);
864         }
865     }
866
867     /* read expiry date; if a bad date, then leave it so the client can
868      * read it
869      */
870     exps = apr_table_get(r->err_headers_out, "Expires");
871     if (exps == NULL) {
872         exps = apr_table_get(r->headers_out, "Expires");
873     }
874     if (exps != NULL) {
875         exp = apr_date_parse_http(exps);
876     }
877     else {
878         exp = APR_DATE_BAD;
879     }
880
881     /* read the last-modified date; if the date is bad, then delete it */
882     lastmods = apr_table_get(r->err_headers_out, "Last-Modified");
883     if (lastmods == NULL) {
884         lastmods = apr_table_get(r->headers_out, "Last-Modified");
885     }
886     if (lastmods != NULL) {
887         lastmod = apr_date_parse_http(lastmods);
888         if (lastmod == APR_DATE_BAD) {
889             lastmods = NULL;
890         }
891     }
892     else {
893         lastmod = APR_DATE_BAD;
894     }
895
896     /* read the etag and cache-control from the entity */
897     etag = apr_table_get(r->err_headers_out, "Etag");
898     if (etag == NULL) {
899         etag = apr_table_get(r->headers_out, "Etag");
900     }
901     cc_out = apr_table_get(r->err_headers_out, "Cache-Control");
902     pragma = apr_table_get(r->err_headers_out, "Pragma");
903     headers = r->err_headers_out;
904     if (!cc_out && !pragma) {
905         cc_out = apr_table_get(r->headers_out, "Cache-Control");
906         pragma = apr_table_get(r->headers_out, "Pragma");
907         headers = r->headers_out;
908     }
909
910     /* Have we received a 304 response without any headers at all? Fall back to
911      * the original headers in the original cached request.
912      */
913     if (r->status == HTTP_NOT_MODIFIED && cache->stale_handle && !cc_out
914             && !pragma) {
915         cc_out = apr_table_get(cache->stale_handle->resp_hdrs, "Cache-Control");
916         pragma = apr_table_get(cache->stale_handle->resp_hdrs, "Pragma");
917     }
918
919     /* Parse the cache control header */
920     memset(&control, 0, sizeof(cache_control_t));
921     ap_cache_control(r, &control, cc_out, pragma, headers);
922
923     /*
924      * what responses should we not cache?
925      *
926      * At this point we decide based on the response headers whether it
927      * is appropriate _NOT_ to cache the data from the server. There are
928      * a whole lot of conditions that prevent us from caching this data.
929      * They are tested here one by one to be clear and unambiguous.
930      */
931     if (r->status != HTTP_OK && r->status != HTTP_NON_AUTHORITATIVE
932         && r->status != HTTP_PARTIAL_CONTENT
933         && r->status != HTTP_MULTIPLE_CHOICES
934         && r->status != HTTP_MOVED_PERMANENTLY
935         && r->status != HTTP_NOT_MODIFIED) {
936         /* RFC2616 13.4 we are allowed to cache 200, 203, 206, 300, 301 or 410
937          * We allow the caching of 206, but a cache implementation might choose
938          * to decline to cache a 206 if it doesn't know how to.
939          * We include 304 Not Modified here too as this is the origin server
940          * telling us to serve the cached copy.
941          */
942         if (exps != NULL || cc_out != NULL) {
943             /* We are also allowed to cache any response given that it has a
944              * valid Expires or Cache Control header. If we find a either of
945              * those here,  we pass request through the rest of the tests. From
946              * the RFC:
947              *
948              * A response received with any other status code (e.g. status
949              * codes 302 and 307) MUST NOT be returned in a reply to a
950              * subsequent request unless there are cache-control directives or
951              * another header(s) that explicitly allow it. For example, these
952              * include the following: an Expires header (section 14.21); a
953              * "max-age", "s-maxage",  "must-revalidate", "proxy-revalidate",
954              * "public" or "private" cache-control directive (section 14.9).
955              */
956         }
957         else {
958             reason = apr_psprintf(p, "Response status %d", r->status);
959         }
960     }
961
962     if (reason) {
963         /* noop */
964     }
965     else if (exps != NULL && exp == APR_DATE_BAD) {
966         /* if a broken Expires header is present, don't cache it */
967         reason = apr_pstrcat(p, "Broken expires header: ", exps, NULL);
968     }
969     else if (!dconf->store_expired && exp != APR_DATE_BAD
970             && exp < r->request_time)
971     {
972         /* if a Expires header is in the past, don't cache it */
973         reason = "Expires header already expired; not cacheable";
974     }
975     else if (!conf->ignorequerystring && r->parsed_uri.query && exps == NULL
976             && !control.max_age && !control.s_maxage) {
977         /* if a query string is present but no explicit expiration time,
978          * don't cache it (RFC 2616/13.9 & 13.2.1)
979          */
980         reason = "Query string present but no explicit expiration time";
981     }
982     else if (r->status == HTTP_NOT_MODIFIED &&
983              !cache->handle && !cache->stale_handle) {
984         /* if the server said 304 Not Modified but we have no cache
985          * file - pass this untouched to the user agent, it's not for us.
986          */
987         reason = "HTTP Status 304 Not Modified";
988     }
989     else if (r->status == HTTP_OK && lastmods == NULL && etag == NULL && (exps
990             == NULL) && (dconf->no_last_mod_ignore == 0) && !control.max_age
991             && !control.s_maxage) {
992         /* 200 OK response from HTTP/1.0 and up without Last-Modified,
993          * Etag, Expires, Cache-Control:max-age, or Cache-Control:s-maxage
994          * headers.
995          */
996         /* Note: mod-include clears last_modified/expires/etags - this
997          * is why we have an optional function for a key-gen ;-)
998          */
999         reason = "No Last-Modified; Etag; Expires; Cache-Control:max-age or Cache-Control:s-maxage headers";
1000     }
1001     else if (!dconf->store_nostore && control.no_store) {
1002         /* RFC2616 14.9.2 Cache-Control: no-store response
1003          * indicating do not cache, or stop now if you are
1004          * trying to cache it.
1005          */
1006         reason = "Cache-Control: no-store present";
1007     }
1008     else if (!dconf->store_private && control.private) {
1009         /* RFC2616 14.9.1 Cache-Control: private response
1010          * this object is marked for this user's eyes only. Behave
1011          * as a tunnel.
1012          */
1013         reason = "Cache-Control: private present";
1014     }
1015     else if (apr_table_get(r->headers_in, "Authorization")
1016             && !(control.s_maxage || control.must_revalidate
1017                     || control.proxy_revalidate || control.public)) {
1018         /* RFC2616 14.8 Authorisation:
1019          * if authorisation is included in the request, we don't cache,
1020          * but we can cache if the following exceptions are true:
1021          * 1) If Cache-Control: s-maxage is included
1022          * 2) If Cache-Control: must-revalidate is included
1023          * 3) If Cache-Control: public is included
1024          */
1025         reason = "Authorization required";
1026     }
1027     else if (ap_cache_liststr(NULL,
1028                               apr_table_get(r->headers_out, "Vary"),
1029                               "*", NULL)) {
1030         reason = "Vary header contains '*'";
1031     }
1032     else if (apr_table_get(r->subprocess_env, "no-cache") != NULL) {
1033         reason = "environment variable 'no-cache' is set";
1034     }
1035     else if (r->no_cache) {
1036         /* or we've been asked not to cache it above */
1037         reason = "r->no_cache present";
1038     }
1039
1040     /* Hold the phone. Some servers might allow us to cache a 2xx, but
1041      * then make their 304 responses non cacheable. This leaves us in a
1042      * sticky position. If the 304 is in answer to our own conditional
1043      * request, we cannot send this 304 back to the client because the
1044      * client isn't expecting it. Instead, our only option is to respect
1045      * the answer to the question we asked (has it changed, answer was
1046      * no) and return the cached item to the client, and then respect
1047      * the uncacheable nature of this 304 by allowing the remove_url
1048      * filter to kick in and remove the cached entity.
1049      */
1050     if (reason && r->status == HTTP_NOT_MODIFIED &&
1051              cache->stale_handle) {
1052         apr_bucket_brigade *bb;
1053         apr_bucket *bkt;
1054         int status;
1055
1056         cache->handle = cache->stale_handle;
1057         info = &cache->handle->cache_obj->info;
1058
1059         /* Load in the saved status and clear the status line. */
1060         r->status = info->status;
1061         r->status_line = NULL;
1062
1063         bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
1064
1065         r->headers_in = cache->stale_headers;
1066         status = ap_meets_conditions(r);
1067         if (status != OK) {
1068             r->status = status;
1069
1070             bkt = apr_bucket_flush_create(bb->bucket_alloc);
1071             APR_BRIGADE_INSERT_TAIL(bb, bkt);
1072         }
1073         else {
1074             cache->provider->recall_body(cache->handle, r->pool, bb);
1075
1076             bkt = apr_bucket_eos_create(bb->bucket_alloc);
1077             APR_BRIGADE_INSERT_TAIL(bb, bkt);
1078         }
1079
1080         cache->block_response = 1;
1081
1082         /* we've got a cache conditional hit! tell anyone who cares */
1083         cache_run_cache_status(
1084                 cache->handle,
1085                 r,
1086                 r->headers_out,
1087                 AP_CACHE_REVALIDATE,
1088                 apr_psprintf(
1089                         r->pool,
1090                         "conditional cache hit: 304 was uncacheable though (%s); entity removed",
1091                         reason));
1092
1093         /* let someone else attempt to cache */
1094         cache_remove_lock(conf, cache, r, NULL);
1095
1096         return ap_pass_brigade(f->next, bb);
1097     }
1098
1099     if (reason) {
1100         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1101                 "cache: %s not cached. Reason: %s", r->unparsed_uri,
1102                 reason);
1103
1104         /* we've got a cache miss! tell anyone who cares */
1105         cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_MISS,
1106                 reason);
1107
1108         /* remove this filter from the chain */
1109         ap_remove_output_filter(f);
1110
1111         /* remove the lock file unconditionally */
1112         cache_remove_lock(conf, cache, r, NULL);
1113
1114         /* ship the data up the stack */
1115         return ap_pass_brigade(f->next, in);
1116     }
1117
1118     /* Make it so that we don't execute this path again. */
1119     cache->in_checked = 1;
1120
1121     /* Set the content length if known.
1122      */
1123     cl = apr_table_get(r->err_headers_out, "Content-Length");
1124     if (cl == NULL) {
1125         cl = apr_table_get(r->headers_out, "Content-Length");
1126     }
1127     if (cl) {
1128         char *errp;
1129         if (apr_strtoff(&size, cl, &errp, 10) || *errp || size < 0) {
1130             cl = NULL; /* parse error, see next 'if' block */
1131         }
1132     }
1133
1134     if (!cl) {
1135         /* if we don't get the content-length, see if we have all the
1136          * buckets and use their length to calculate the size
1137          */
1138         int all_buckets_here=0;
1139         size=0;
1140         for (e = APR_BRIGADE_FIRST(in);
1141              e != APR_BRIGADE_SENTINEL(in);
1142              e = APR_BUCKET_NEXT(e))
1143         {
1144             if (APR_BUCKET_IS_EOS(e)) {
1145                 all_buckets_here=1;
1146                 break;
1147             }
1148             if (APR_BUCKET_IS_FLUSH(e)) {
1149                 continue;
1150             }
1151             if (e->length == (apr_size_t)-1) {
1152                 break;
1153             }
1154             size += e->length;
1155         }
1156         if (!all_buckets_here) {
1157             size = -1;
1158         }
1159     }
1160
1161     /* remember content length to check response size against later */
1162     cache->size = size;
1163
1164     /* It's safe to cache the response.
1165      *
1166      * There are two possiblities at this point:
1167      * - cache->handle == NULL. In this case there is no previously
1168      * cached entity anywhere on the system. We must create a brand
1169      * new entity and store the response in it.
1170      * - cache->stale_handle != NULL. In this case there is a stale
1171      * entity in the system which needs to be replaced by new
1172      * content (unless the result was 304 Not Modified, which means
1173      * the cached entity is actually fresh, and we should update
1174      * the headers).
1175      */
1176
1177     /* Did we have a stale cache entry that really is stale?
1178      */
1179     if (cache->stale_handle) {
1180         if (r->status == HTTP_NOT_MODIFIED) {
1181             /* Oh, hey.  It isn't that stale!  Yay! */
1182             cache->handle = cache->stale_handle;
1183             info = &cache->handle->cache_obj->info;
1184             rv = OK;
1185         }
1186         else {
1187             /* Oh, well.  Toss it. */
1188             cache->provider->remove_entity(cache->stale_handle);
1189             /* Treat the request as if it wasn't conditional. */
1190             cache->stale_handle = NULL;
1191             /*
1192              * Restore the original request headers as they may be needed
1193              * by further output filters like the byterange filter to make
1194              * the correct decisions.
1195              */
1196             r->headers_in = cache->stale_headers;
1197         }
1198     }
1199
1200     /* no cache handle, create a new entity */
1201     if (!cache->handle) {
1202         rv = cache_create_entity(cache, r, size, in);
1203         info = apr_pcalloc(r->pool, sizeof(cache_info));
1204         /* We only set info->status upon the initial creation. */
1205         info->status = r->status;
1206     }
1207
1208     if (rv != OK) {
1209         /* we've got a cache miss! tell anyone who cares */
1210         cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_MISS,
1211                 "cache miss: create_entity failed");
1212
1213         /* Caching layer declined the opportunity to cache the response */
1214         ap_remove_output_filter(f);
1215         cache_remove_lock(conf, cache, r, NULL);
1216         return ap_pass_brigade(f->next, in);
1217     }
1218
1219     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1220             "cache: Caching url: %s", r->unparsed_uri);
1221
1222     /* We are actually caching this response. So it does not
1223      * make sense to remove this entity any more.
1224      */
1225     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1226             "cache: Removing CACHE_REMOVE_URL filter.");
1227     ap_remove_output_filter(cache->remove_url_filter);
1228
1229     /*
1230      * We now want to update the cache file header information with
1231      * the new date, last modified, expire and content length and write
1232      * it away to our cache file. First, we determine these values from
1233      * the response, using heuristics if appropriate.
1234      *
1235      * In addition, we make HTTP/1.1 age calculations and write them away
1236      * too.
1237      */
1238
1239     /* store away the previously parsed cache control headers */
1240     memcpy(&info->control, &control, sizeof(cache_control_t));
1241
1242     /* Read the date. Generate one if one is not supplied */
1243     dates = apr_table_get(r->err_headers_out, "Date");
1244     if (dates == NULL) {
1245         dates = apr_table_get(r->headers_out, "Date");
1246     }
1247     if (dates != NULL) {
1248         info->date = apr_date_parse_http(dates);
1249     }
1250     else {
1251         info->date = APR_DATE_BAD;
1252     }
1253
1254     now = apr_time_now();
1255     if (info->date == APR_DATE_BAD) {  /* No, or bad date */
1256         /* no date header (or bad header)! */
1257         info->date = now;
1258     }
1259     date = info->date;
1260
1261     /* set response_time for HTTP/1.1 age calculations */
1262     info->response_time = now;
1263
1264     /* get the request time */
1265     info->request_time = r->request_time;
1266
1267     /* check last-modified date */
1268     if (lastmod != APR_DATE_BAD && lastmod > date) {
1269         /* if it's in the future, then replace by date */
1270         lastmod = date;
1271         lastmods = dates;
1272         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0,
1273                 r, "cache: Last modified is in the future, "
1274                 "replacing with now");
1275     }
1276
1277     /* if no expiry date then
1278      *   if Cache-Control: max-age
1279      *      expiry date = date + max-age
1280      *   else if lastmod
1281      *      expiry date = date + min((date - lastmod) * factor, maxexpire)
1282      *   else
1283      *      expire date = date + defaultexpire
1284      */
1285     if (exp == APR_DATE_BAD) {
1286
1287         if (control.max_age) {
1288             apr_int64_t x;
1289
1290             errno = 0;
1291             x = control.max_age_value;
1292             if (errno) {
1293                 x = dconf->defex;
1294             }
1295             else {
1296                 x = x * MSEC_ONE_SEC;
1297             }
1298             if (x < dconf->minex) {
1299                 x = dconf->minex;
1300             }
1301             if (x > dconf->maxex) {
1302                 x = dconf->maxex;
1303             }
1304             exp = date + x;
1305         }
1306         else if ((lastmod != APR_DATE_BAD) && (lastmod < date)) {
1307             /* if lastmod == date then you get 0*conf->factor which results in
1308              * an expiration time of now. This causes some problems with
1309              * freshness calculations, so we choose the else path...
1310              */
1311             apr_time_t x = (apr_time_t) ((date - lastmod) * dconf->factor);
1312
1313             if (x < dconf->minex) {
1314                 x = dconf->minex;
1315             }
1316             if (x > dconf->maxex) {
1317                 x = dconf->maxex;
1318             }
1319             exp = date + x;
1320         }
1321         else {
1322             exp = date + dconf->defex;
1323         }
1324     }
1325     info->expire = exp;
1326
1327     /* We found a stale entry which wasn't really stale. */
1328     if (cache->stale_handle) {
1329         /* Load in the saved status and clear the status line. */
1330         r->status = info->status;
1331         r->status_line = NULL;
1332
1333         /* RFC 2616 10.3.5 states that entity headers are not supposed
1334          * to be in the 304 response.  Therefore, we need to combine the
1335          * response headers with the cached headers *before* we update
1336          * the cached headers.
1337          *
1338          * However, before doing that, we need to first merge in
1339          * err_headers_out and we also need to strip any hop-by-hop
1340          * headers that might have snuck in.
1341          */
1342         r->headers_out = ap_cache_cacheable_headers_out(r);
1343
1344         /* Merge in our cached headers.  However, keep any updated values. */
1345         cache_accept_headers(cache->handle, r, 1);
1346     }
1347
1348     /* Write away header information to cache. It is possible that we are
1349      * trying to update headers for an entity which has already been cached.
1350      *
1351      * This may fail, due to an unwritable cache area. E.g. filesystem full,
1352      * permissions problems or a read-only (re)mount. This must be handled
1353      * later.
1354      */
1355     rv = cache->provider->store_headers(cache->handle, r, info);
1356
1357     /* Did we just update the cached headers on a revalidated response?
1358      *
1359      * If so, we can now decide what to serve to the client.  This is done in
1360      * the same way as with a regular response, but conditions are now checked
1361      * against the cached or merged response headers.
1362      */
1363     if (cache->stale_handle) {
1364         apr_bucket_brigade *bb;
1365         apr_bucket *bkt;
1366         int status;
1367
1368         /* We're just saving response headers, so we are done. Commit
1369          * the response at this point, unless there was a previous error.
1370          */
1371         if (rv == APR_SUCCESS) {
1372             rv = cache->provider->commit_entity(cache->handle, r);
1373         }
1374
1375         bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
1376
1377         /* Restore the original request headers and see if we need to
1378          * return anything else than the cached response (ie. the original
1379          * request was conditional).
1380          */
1381         r->headers_in = cache->stale_headers;
1382         status = ap_meets_conditions(r);
1383         if (status != OK) {
1384             r->status = status;
1385
1386             bkt = apr_bucket_flush_create(bb->bucket_alloc);
1387             APR_BRIGADE_INSERT_TAIL(bb, bkt);
1388         }
1389         else {
1390             cache->provider->recall_body(cache->handle, r->pool, bb);
1391
1392             bkt = apr_bucket_eos_create(bb->bucket_alloc);
1393             APR_BRIGADE_INSERT_TAIL(bb, bkt);
1394         }
1395
1396         cache->block_response = 1;
1397
1398         /* Before returning we need to handle the possible case of an
1399          * unwritable cache. Rather than leaving the entity in the cache
1400          * and having it constantly re-validated, now that we have recalled
1401          * the body it is safe to try and remove the url from the cache.
1402          */
1403         if (rv != APR_SUCCESS) {
1404             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,
1405                     "cache: updating headers with store_headers failed. "
1406                     "Removing cached url.");
1407
1408             rv = cache->provider->remove_url(cache->stale_handle, r);
1409             if (rv != OK) {
1410                 /* Probably a mod_cache_disk cache area has been (re)mounted
1411                  * read-only, or that there is a permissions problem.
1412                  */
1413                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,
1414                         "cache: attempt to remove url from cache unsuccessful.");
1415             }
1416
1417             /* we've got a cache conditional hit! tell anyone who cares */
1418             cache_run_cache_status(cache->handle, r, r->headers_out,
1419                     AP_CACHE_REVALIDATE,
1420                     "conditional cache hit: entity refresh failed");
1421
1422         }
1423         else {
1424
1425             /* we've got a cache conditional hit! tell anyone who cares */
1426             cache_run_cache_status(cache->handle, r, r->headers_out,
1427                     AP_CACHE_REVALIDATE,
1428                     "conditional cache hit: entity refreshed");
1429
1430         }
1431
1432         /* let someone else attempt to cache */
1433         cache_remove_lock(conf, cache, r, NULL);
1434
1435         return ap_pass_brigade(f->next, bb);
1436     }
1437
1438     if (rv != APR_SUCCESS) {
1439         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,
1440                 "cache: store_headers failed");
1441
1442         /* we've got a cache miss! tell anyone who cares */
1443         cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_MISS,
1444                 "cache miss: store_headers failed");
1445
1446         ap_remove_output_filter(f);
1447         cache_remove_lock(conf, cache, r, NULL);
1448         return ap_pass_brigade(f->next, in);
1449     }
1450
1451     /* we've got a cache miss! tell anyone who cares */
1452     cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_MISS,
1453             "cache miss: attempting entity save");
1454
1455     return cache_save_store(f, in, conf, cache);
1456 }
1457
1458 /*
1459  * CACHE_REMOVE_URL filter
1460  * -----------------------
1461  *
1462  * This filter gets added in the quick handler every time the CACHE_SAVE filter
1463  * gets inserted. Its purpose is to remove a confirmed stale cache entry from
1464  * the cache.
1465  *
1466  * CACHE_REMOVE_URL has to be a protocol filter to ensure that is run even if
1467  * the response is a canned error message, which removes the content filters
1468  * and thus the CACHE_SAVE filter from the chain.
1469  *
1470  * CACHE_REMOVE_URL expects cache request rec within its context because the
1471  * request this filter runs on can be different from the one whose cache entry
1472  * should be removed, due to internal redirects.
1473  *
1474  * Note that CACHE_SAVE_URL (as a content-set filter, hence run before the
1475  * protocol filters) will remove this filter if it decides to cache the file.
1476  * Therefore, if this filter is left in, it must mean we need to toss any
1477  * existing files.
1478  */
1479 static int cache_remove_url_filter(ap_filter_t *f, apr_bucket_brigade *in)
1480 {
1481     request_rec *r = f->r;
1482     cache_request_rec *cache;
1483
1484     /* Setup cache_request_rec */
1485     cache = (cache_request_rec *) f->ctx;
1486
1487     if (!cache) {
1488         /* user likely configured CACHE_REMOVE_URL manually; they should really
1489          * use mod_cache configuration to do that. So:
1490          * 1. Remove ourselves
1491          * 2. Do nothing and bail out
1492          */
1493         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1494                 "cache: CACHE_REMOVE_URL enabled unexpectedly");
1495         ap_remove_output_filter(f);
1496         return ap_pass_brigade(f->next, in);
1497     }
1498
1499     /* Now remove this cache entry from the cache */
1500     cache_remove_url(cache, r);
1501
1502     /* remove ourselves */
1503     ap_remove_output_filter(f);
1504     return ap_pass_brigade(f->next, in);
1505 }
1506
1507 /*
1508  * CACHE filter
1509  * ------------
1510  *
1511  * This filter can be optionally inserted into the filter chain by the admin as
1512  * a marker representing the precise location within the filter chain where
1513  * caching is to be performed.
1514  *
1515  * When the filter chain is set up in the non-quick version of the URL handler,
1516  * the CACHE filter is replaced by the CACHE_OUT or CACHE_SAVE filter,
1517  * effectively inserting the caching filters at the point indicated by the
1518  * admin. The CACHE filter is then removed.
1519  *
1520  * This allows caching to be performed before the content is passed to the
1521  * INCLUDES filter, or to a filter that might perform transformations unique
1522  * to the specific request and that would otherwise be non-cacheable.
1523  */
1524 static int cache_filter(ap_filter_t *f, apr_bucket_brigade *in)
1525 {
1526     /* we are just a marker, so let's just remove ourselves */
1527     ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r,
1528             "cache: CACHE filter was added twice, or was added in quick "
1529             "handler mode and will be ignored.");
1530     ap_remove_output_filter(f);
1531     return ap_pass_brigade(f->next, in);
1532 }
1533
1534 /**
1535  * If configured, add the status of the caching attempt to the subprocess
1536  * environment, and if configured, to headers in the response.
1537  *
1538  * The status is saved below the broad category of the status (hit, miss,
1539  * revalidate), as well as a single cache-status key. This can be used for
1540  * conditional logging.
1541  *
1542  * The status is optionally saved to an X-Cache header, and the detail of
1543  * why a particular cache entry was cached (or not cached) is optionally
1544  * saved to an X-Cache-Detail header. This extra detail is useful for
1545  * service developers who may need to know whether their Cache-Control headers
1546  * are working correctly.
1547  */
1548 static int cache_status(cache_handle_t *h, request_rec *r,
1549         apr_table_t *headers, ap_cache_status_e status, const char *reason)
1550 {
1551     cache_server_conf
1552             *conf =
1553                     (cache_server_conf *) ap_get_module_config(r->server->module_config,
1554                             &cache_module);
1555
1556     cache_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &cache_module);
1557     int x_cache = 0, x_cache_detail = 0;
1558
1559     switch (status) {
1560     case AP_CACHE_HIT: {
1561         apr_table_setn(r->subprocess_env, AP_CACHE_HIT_ENV, reason);
1562         break;
1563     }
1564     case AP_CACHE_REVALIDATE: {
1565         apr_table_setn(r->subprocess_env, AP_CACHE_REVALIDATE_ENV, reason);
1566         break;
1567     }
1568     case AP_CACHE_MISS: {
1569         apr_table_setn(r->subprocess_env, AP_CACHE_MISS_ENV, reason);
1570         break;
1571     }
1572     case AP_CACHE_INVALIDATE: {
1573         apr_table_setn(r->subprocess_env, AP_CACHE_INVALIDATE_ENV, reason);
1574         break;
1575     }
1576     }
1577
1578     apr_table_setn(r->subprocess_env, AP_CACHE_STATUS_ENV, reason);
1579
1580     if (dconf && dconf->x_cache_set) {
1581         x_cache = dconf->x_cache;
1582     }
1583     else {
1584         x_cache = conf->x_cache;
1585     }
1586     if (x_cache) {
1587         apr_table_setn(headers, "X-Cache", apr_psprintf(r->pool, "%s from %s",
1588                 status == AP_CACHE_HIT ? "HIT"
1589                         : status == AP_CACHE_REVALIDATE ? "REVALIDATE" : status
1590                                 == AP_CACHE_INVALIDATE ? "INVALIDATE" : "MISS",
1591                 r->server->server_hostname));
1592     }
1593
1594     if (dconf && dconf->x_cache_detail_set) {
1595         x_cache_detail = dconf->x_cache_detail;
1596     }
1597     else {
1598         x_cache_detail = conf->x_cache_detail;
1599     }
1600     if (x_cache_detail) {
1601         apr_table_setn(headers, "X-Cache-Detail", apr_psprintf(r->pool,
1602                 "\"%s\" from %s", reason, r->server->server_hostname));
1603     }
1604
1605     return OK;
1606 }
1607
1608 /**
1609  * If an error has occurred, but we have a stale cached entry, restore the
1610  * filter stack from the save filter onwards. The canned error message will
1611  * be discarded in the process, and replaced with the cached response.
1612  */
1613 static void cache_insert_error_filter(request_rec *r)
1614 {
1615     void *dummy;
1616     cache_dir_conf *dconf;
1617
1618     /* ignore everything except for 5xx errors */
1619     if (r->status < HTTP_INTERNAL_SERVER_ERROR) {
1620         return;
1621     }
1622
1623     dconf = ap_get_module_config(r->per_dir_config, &cache_module);
1624
1625     if (!dconf->stale_on_error) {
1626         return;
1627     }
1628
1629     /* RFC2616 13.8 Errors or Incomplete Response Cache Behavior:
1630      * If a cache receives a 5xx response while attempting to revalidate an
1631      * entry, it MAY either forward this response to the requesting client,
1632      * or act as if the server failed to respond. In the latter case, it MAY
1633      * return a previously received response unless the cached entry
1634      * includes the "must-revalidate" cache-control directive (see section
1635      * 14.9).
1636      *
1637      * This covers the case where the error was generated by our server via
1638      * ap_die().
1639      */
1640     apr_pool_userdata_get(&dummy, CACHE_CTX_KEY, r->pool);
1641     if (dummy) {
1642         cache_request_rec *cache = (cache_request_rec *) dummy;
1643
1644         ap_remove_output_filter(cache->remove_url_filter);
1645
1646         if (cache->stale_handle && cache->save_filter
1647                 && !cache->stale_handle->cache_obj->info.control.must_revalidate
1648                 && !cache->stale_handle->cache_obj->info.control.proxy_revalidate) {
1649             const char *warn_head;
1650             cache_server_conf
1651                     *conf =
1652                             (cache_server_conf *) ap_get_module_config(r->server->module_config,
1653                                     &cache_module);
1654
1655             /* morph the current save filter into the out filter, and serve from
1656              * cache.
1657              */
1658             cache->handle = cache->stale_handle;
1659             if (r->main) {
1660                 cache->save_filter->frec = cache_out_subreq_filter_handle;
1661             }
1662             else {
1663                 cache->save_filter->frec = cache_out_filter_handle;
1664             }
1665
1666             r->output_filters = cache->save_filter;
1667
1668             r->err_headers_out = cache->stale_handle->resp_hdrs;
1669
1670             /* add a revalidation warning */
1671             warn_head = apr_table_get(r->err_headers_out, "Warning");
1672             if ((warn_head == NULL) || ((warn_head != NULL)
1673                     && (ap_strstr_c(warn_head, "111") == NULL))) {
1674                 apr_table_mergen(r->err_headers_out, "Warning",
1675                         "111 Revalidation failed");
1676             }
1677
1678             cache_run_cache_status(
1679                     cache->handle,
1680                     r,
1681                     r->err_headers_out,
1682                     AP_CACHE_HIT,
1683                     apr_psprintf(
1684                             r->pool,
1685                             "cache hit: %d status; stale content returned",
1686                             r->status));
1687
1688             /* give someone else the chance to cache the file */
1689             cache_remove_lock(conf, cache, r, NULL);
1690
1691         }
1692     }
1693
1694     return;
1695 }
1696
1697 /* -------------------------------------------------------------- */
1698 /* Setup configurable data */
1699
1700 static void *create_dir_config(apr_pool_t *p, char *dummy)
1701 {
1702     cache_dir_conf *dconf = apr_pcalloc(p, sizeof(cache_dir_conf));
1703
1704     dconf->no_last_mod_ignore = 0;
1705     dconf->store_expired = 0;
1706     dconf->store_private = 0;
1707     dconf->store_nostore = 0;
1708
1709     /* maximum time to cache a document */
1710     dconf->maxex = DEFAULT_CACHE_MAXEXPIRE;
1711     dconf->minex = DEFAULT_CACHE_MINEXPIRE;
1712     /* default time to cache a document */
1713     dconf->defex = DEFAULT_CACHE_EXPIRE;
1714
1715     /* factor used to estimate Expires date from LastModified date */
1716     dconf->factor = DEFAULT_CACHE_LMFACTOR;
1717
1718     dconf->x_cache = DEFAULT_X_CACHE;
1719     dconf->x_cache_detail = DEFAULT_X_CACHE_DETAIL;
1720
1721     dconf->stale_on_error = DEFAULT_CACHE_STALE_ON_ERROR;
1722
1723     /* array of providers for this URL space */
1724     dconf->cacheenable = apr_array_make(p, 10, sizeof(struct cache_enable));
1725
1726     return dconf;
1727 }
1728
1729 static void *merge_dir_config(apr_pool_t *p, void *basev, void *addv) {
1730     cache_dir_conf *new = (cache_dir_conf *) apr_pcalloc(p, sizeof(cache_dir_conf));
1731     cache_dir_conf *add = (cache_dir_conf *) addv;
1732     cache_dir_conf *base = (cache_dir_conf *) basev;
1733
1734     new->no_last_mod_ignore = (add->no_last_mod_ignore_set == 0) ? base->no_last_mod_ignore : add->no_last_mod_ignore;
1735     new->no_last_mod_ignore_set = add->no_last_mod_ignore_set || base->no_last_mod_ignore_set;
1736
1737     new->store_expired = (add->store_expired_set == 0) ? base->store_expired : add->store_expired;
1738     new->store_expired_set = add->store_expired_set || base->store_expired_set;
1739     new->store_private = (add->store_private_set == 0) ? base->store_private : add->store_private;
1740     new->store_private_set = add->store_private_set || base->store_private_set;
1741     new->store_nostore = (add->store_nostore_set == 0) ? base->store_nostore : add->store_nostore;
1742     new->store_nostore_set = add->store_nostore_set || base->store_nostore_set;
1743
1744     /* maximum time to cache a document */
1745     new->maxex = (add->maxex_set == 0) ? base->maxex : add->maxex;
1746     new->maxex_set = add->maxex_set || base->maxex_set;
1747     new->minex = (add->minex_set == 0) ? base->minex : add->minex;
1748     new->minex_set = add->minex_set || base->minex_set;
1749
1750     /* default time to cache a document */
1751     new->defex = (add->defex_set == 0) ? base->defex : add->defex;
1752     new->defex_set = add->defex_set || base->defex_set;
1753
1754     /* factor used to estimate Expires date from LastModified date */
1755     new->factor = (add->factor_set == 0) ? base->factor : add->factor;
1756     new->factor_set = add->factor_set || base->factor_set;
1757
1758     new->x_cache = (add->x_cache_set == 0) ? base->x_cache : add->x_cache;
1759     new->x_cache_set = add->x_cache_set || base->x_cache_set;
1760     new->x_cache_detail = (add->x_cache_detail_set == 0) ? base->x_cache_detail
1761             : add->x_cache_detail;
1762     new->x_cache_detail_set = add->x_cache_detail_set
1763             || base->x_cache_detail_set;
1764
1765     new->stale_on_error = (add->stale_on_error_set == 0) ? base->stale_on_error
1766             : add->stale_on_error;
1767     new->stale_on_error_set = add->stale_on_error_set
1768             || base->stale_on_error_set;
1769
1770     new->cacheenable = add->enable_set ? apr_array_append(p, base->cacheenable,
1771             add->cacheenable) : base->cacheenable;
1772     new->enable_set = add->enable_set || base->enable_set;
1773     new->disable = (add->disable_set == 0) ? base->disable : add->disable;
1774     new->disable_set = add->disable_set || base->disable_set;
1775
1776     return new;
1777 }
1778
1779 static void * create_cache_config(apr_pool_t *p, server_rec *s)
1780 {
1781     const char *tmppath;
1782     cache_server_conf *ps = apr_pcalloc(p, sizeof(cache_server_conf));
1783
1784     /* array of URL prefixes for which caching is enabled */
1785     ps->cacheenable = apr_array_make(p, 10, sizeof(struct cache_enable));
1786     /* array of URL prefixes for which caching is disabled */
1787     ps->cachedisable = apr_array_make(p, 10, sizeof(struct cache_disable));
1788     ps->ignorecachecontrol = 0;
1789     ps->ignorecachecontrol_set = 0;
1790     /* array of headers that should not be stored in cache */
1791     ps->ignore_headers = apr_array_make(p, 10, sizeof(char *));
1792     ps->ignore_headers_set = CACHE_IGNORE_HEADERS_UNSET;
1793     /* flag indicating that query-string should be ignored when caching */
1794     ps->ignorequerystring = 0;
1795     ps->ignorequerystring_set = 0;
1796     /* by default, run in the quick handler */
1797     ps->quick = 1;
1798     ps->quick_set = 0;
1799     /* array of identifiers that should not be used for key calculation */
1800     ps->ignore_session_id = apr_array_make(p, 10, sizeof(char *));
1801     ps->ignore_session_id_set = CACHE_IGNORE_SESSION_ID_UNSET;
1802     ps->lock = 0; /* thundering herd lock defaults to off */
1803     ps->lock_set = 0;
1804     apr_temp_dir_get(&tmppath, p);
1805     if (tmppath) {
1806         ps->lockpath = apr_pstrcat(p, tmppath, DEFAULT_CACHE_LOCKPATH, NULL);
1807     }
1808     ps->lockmaxage = apr_time_from_sec(DEFAULT_CACHE_MAXAGE);
1809     ps->x_cache = DEFAULT_X_CACHE;
1810     ps->x_cache_detail = DEFAULT_X_CACHE_DETAIL;
1811     return ps;
1812 }
1813
1814 static void * merge_cache_config(apr_pool_t *p, void *basev, void *overridesv)
1815 {
1816     cache_server_conf *ps = apr_pcalloc(p, sizeof(cache_server_conf));
1817     cache_server_conf *base = (cache_server_conf *) basev;
1818     cache_server_conf *overrides = (cache_server_conf *) overridesv;
1819
1820     /* array of URL prefixes for which caching is disabled */
1821     ps->cachedisable = apr_array_append(p,
1822                                         base->cachedisable,
1823                                         overrides->cachedisable);
1824     /* array of URL prefixes for which caching is enabled */
1825     ps->cacheenable = apr_array_append(p,
1826                                        base->cacheenable,
1827                                        overrides->cacheenable);
1828
1829     ps->ignorecachecontrol  =
1830         (overrides->ignorecachecontrol_set == 0)
1831         ? base->ignorecachecontrol
1832         : overrides->ignorecachecontrol;
1833     ps->ignore_headers =
1834         (overrides->ignore_headers_set == CACHE_IGNORE_HEADERS_UNSET)
1835         ? base->ignore_headers
1836         : overrides->ignore_headers;
1837     ps->ignorequerystring =
1838         (overrides->ignorequerystring_set == 0)
1839         ? base->ignorequerystring
1840         : overrides->ignorequerystring;
1841     ps->ignore_session_id =
1842         (overrides->ignore_session_id_set == CACHE_IGNORE_SESSION_ID_UNSET)
1843         ? base->ignore_session_id
1844         : overrides->ignore_session_id;
1845     ps->lock =
1846         (overrides->lock_set == 0)
1847         ? base->lock
1848         : overrides->lock;
1849     ps->lockpath =
1850         (overrides->lockpath_set == 0)
1851         ? base->lockpath
1852         : overrides->lockpath;
1853     ps->lockmaxage =
1854         (overrides->lockmaxage_set == 0)
1855         ? base->lockmaxage
1856         : overrides->lockmaxage;
1857     ps->quick =
1858         (overrides->quick_set == 0)
1859         ? base->quick
1860         : overrides->quick;
1861     ps->x_cache =
1862         (overrides->x_cache_set == 0)
1863         ? base->x_cache
1864         : overrides->x_cache;
1865     ps->x_cache_detail =
1866         (overrides->x_cache_detail_set == 0)
1867         ? base->x_cache_detail
1868         : overrides->x_cache_detail;
1869     ps->base_uri =
1870         (overrides->base_uri_set == 0)
1871         ? base->base_uri
1872         : overrides->base_uri;
1873     return ps;
1874 }
1875
1876 static const char *set_cache_quick_handler(cmd_parms *parms, void *dummy,
1877                                            int flag)
1878 {
1879     cache_server_conf *conf;
1880
1881     conf =
1882         (cache_server_conf *)ap_get_module_config(parms->server->module_config
1883 ,
1884                                                   &cache_module);
1885     conf->quick = flag;
1886     conf->quick_set = 1;
1887     return NULL;
1888
1889 }
1890
1891 static const char *set_cache_ignore_no_last_mod(cmd_parms *parms, void *dummy,
1892                                                 int flag)
1893 {
1894     cache_dir_conf *dconf = (cache_dir_conf *)dummy;
1895
1896     dconf->no_last_mod_ignore = flag;
1897     dconf->no_last_mod_ignore_set = 1;
1898     return NULL;
1899
1900 }
1901
1902 static const char *set_cache_ignore_cachecontrol(cmd_parms *parms,
1903                                                  void *dummy, int flag)
1904 {
1905     cache_server_conf *conf;
1906
1907     conf =
1908         (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1909                                                   &cache_module);
1910     conf->ignorecachecontrol = flag;
1911     conf->ignorecachecontrol_set = 1;
1912     return NULL;
1913 }
1914
1915 static const char *set_cache_store_expired(cmd_parms *parms, void *dummy,
1916                                            int flag)
1917 {
1918     cache_dir_conf *dconf = (cache_dir_conf *)dummy;
1919
1920     dconf->store_expired = flag;
1921     dconf->store_expired_set = 1;
1922     return NULL;
1923 }
1924
1925 static const char *set_cache_store_private(cmd_parms *parms, void *dummy,
1926                                            int flag)
1927 {
1928     cache_dir_conf *dconf = (cache_dir_conf *)dummy;
1929
1930     dconf->store_private = flag;
1931     dconf->store_private_set = 1;
1932     return NULL;
1933 }
1934
1935 static const char *set_cache_store_nostore(cmd_parms *parms, void *dummy,
1936                                            int flag)
1937 {
1938     cache_dir_conf *dconf = (cache_dir_conf *)dummy;
1939
1940     dconf->store_nostore = flag;
1941     dconf->store_nostore_set = 1;
1942     return NULL;
1943 }
1944
1945 static const char *add_ignore_header(cmd_parms *parms, void *dummy,
1946                                      const char *header)
1947 {
1948     cache_server_conf *conf;
1949     char **new;
1950
1951     conf =
1952         (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1953                                                   &cache_module);
1954     if (!strcasecmp(header, "None")) {
1955         /* if header None is listed clear array */
1956         conf->ignore_headers->nelts = 0;
1957     }
1958     else {
1959         if ((conf->ignore_headers_set == CACHE_IGNORE_HEADERS_UNSET) ||
1960             (conf->ignore_headers->nelts)) {
1961             /* Only add header if no "None" has been found in header list
1962              * so far.
1963              * (When 'None' is passed, IGNORE_HEADERS_SET && nelts == 0.)
1964              */
1965             new = (char **)apr_array_push(conf->ignore_headers);
1966             (*new) = (char *)header;
1967         }
1968     }
1969     conf->ignore_headers_set = CACHE_IGNORE_HEADERS_SET;
1970     return NULL;
1971 }
1972
1973 static const char *add_ignore_session_id(cmd_parms *parms, void *dummy,
1974                                          const char *identifier)
1975 {
1976     cache_server_conf *conf;
1977     char **new;
1978
1979     conf =
1980         (cache_server_conf *)ap_get_module_config(parms->server->module_config,
1981                                                   &cache_module);
1982     if (!strcasecmp(identifier, "None")) {
1983         /* if identifier None is listed clear array */
1984         conf->ignore_session_id->nelts = 0;
1985     }
1986     else {
1987         if ((conf->ignore_session_id_set == CACHE_IGNORE_SESSION_ID_UNSET) ||
1988             (conf->ignore_session_id->nelts)) {
1989             /*
1990              * Only add identifier if no "None" has been found in identifier
1991              * list so far.
1992              */
1993             new = (char **)apr_array_push(conf->ignore_session_id);
1994             (*new) = (char *)identifier;
1995         }
1996     }
1997     conf->ignore_session_id_set = CACHE_IGNORE_SESSION_ID_SET;
1998     return NULL;
1999 }
2000
2001 static const char *add_cache_enable(cmd_parms *parms, void *dummy,
2002                                     const char *type,
2003                                     const char *url)
2004 {
2005     cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2006     cache_server_conf *conf;
2007     struct cache_enable *new;
2008
2009     const char *err = ap_check_cmd_context(parms,
2010                                            NOT_IN_DIRECTORY|NOT_IN_LIMIT|NOT_IN_FILES);
2011     if (err != NULL) {
2012         return err;
2013     }
2014
2015     if (*type == '/') {
2016         return apr_psprintf(parms->pool,
2017           "provider (%s) starts with a '/'.  Are url and provider switched?",
2018           type);
2019     }
2020
2021     if (!url) {
2022         url = parms->path;
2023     }
2024     if (!url) {
2025         return apr_psprintf(parms->pool,
2026           "CacheEnable provider (%s) is missing an URL.", type);
2027     }
2028     if (parms->path && strncmp(parms->path, url, strlen(parms->path))) {
2029         return "When in a Location, CacheEnable must specify a path or an URL below "
2030         "that location.";
2031     }
2032
2033     conf =
2034         (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2035                                                   &cache_module);
2036
2037     if (parms->path) {
2038         new = apr_array_push(dconf->cacheenable);
2039         dconf->enable_set = 1;
2040     }
2041     else {
2042         new = apr_array_push(conf->cacheenable);
2043     }
2044
2045     new->type = type;
2046     if (apr_uri_parse(parms->pool, url, &(new->url))) {
2047         return NULL;
2048     }
2049     if (new->url.path) {
2050         new->pathlen = strlen(new->url.path);
2051     } else {
2052         new->pathlen = 1;
2053         new->url.path = "/";
2054     }
2055     return NULL;
2056 }
2057
2058 static const char *add_cache_disable(cmd_parms *parms, void *dummy,
2059                                      const char *url)
2060 {
2061     cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2062     cache_server_conf *conf;
2063     struct cache_disable *new;
2064
2065     const char *err = ap_check_cmd_context(parms,
2066                                            NOT_IN_DIRECTORY|NOT_IN_LIMIT|NOT_IN_FILES);
2067     if (err != NULL) {
2068         return err;
2069     }
2070
2071     if (parms->path && !strcmp(url, "on")) {
2072         url = parms->path;
2073     }
2074     if (url[0] != '/' && !ap_strchr_c(url, ':')) {
2075         return "CacheDisable must specify a path or an URL, or when in a Location, "
2076             "the word 'on'.";
2077     }
2078
2079     if (parms->path && strncmp(parms->path, url, strlen(parms->path))) {
2080         return "When in a Location, CacheDisable must specify a path or an URL below "
2081         "that location.";
2082     }
2083
2084     conf =
2085         (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2086                                                   &cache_module);
2087
2088     if (parms->path) {
2089         dconf->disable = 1;
2090         dconf->disable_set = 1;
2091         return NULL;
2092     }
2093
2094     new = apr_array_push(conf->cachedisable);
2095     if (apr_uri_parse(parms->pool, url, &(new->url))) {
2096         return NULL;
2097     }
2098     if (new->url.path) {
2099         new->pathlen = strlen(new->url.path);
2100     } else {
2101         new->pathlen = 1;
2102         new->url.path = "/";
2103     }
2104     return NULL;
2105 }
2106
2107 static const char *set_cache_maxex(cmd_parms *parms, void *dummy,
2108                                    const char *arg)
2109 {
2110     cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2111
2112     dconf->maxex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
2113     dconf->maxex_set = 1;
2114     return NULL;
2115 }
2116
2117 static const char *set_cache_minex(cmd_parms *parms, void *dummy,
2118                                    const char *arg)
2119 {
2120     cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2121
2122     dconf->minex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
2123     dconf->minex_set = 1;
2124     return NULL;
2125 }
2126
2127 static const char *set_cache_defex(cmd_parms *parms, void *dummy,
2128                                    const char *arg)
2129 {
2130     cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2131
2132     dconf->defex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC);
2133     dconf->defex_set = 1;
2134     return NULL;
2135 }
2136
2137 static const char *set_cache_factor(cmd_parms *parms, void *dummy,
2138                                     const char *arg)
2139 {
2140     cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2141     double val;
2142
2143     if (sscanf(arg, "%lg", &val) != 1) {
2144         return "CacheLastModifiedFactor value must be a float";
2145     }
2146     dconf->factor = val;
2147     dconf->factor_set = 1;
2148     return NULL;
2149 }
2150
2151 static const char *set_cache_ignore_querystring(cmd_parms *parms, void *dummy,
2152                                                 int flag)
2153 {
2154     cache_server_conf *conf;
2155
2156     conf =
2157         (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2158                                                   &cache_module);
2159     conf->ignorequerystring = flag;
2160     conf->ignorequerystring_set = 1;
2161     return NULL;
2162 }
2163
2164 static const char *set_cache_lock(cmd_parms *parms, void *dummy,
2165                                                 int flag)
2166 {
2167     cache_server_conf *conf;
2168
2169     conf =
2170         (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2171                                                   &cache_module);
2172     conf->lock = flag;
2173     conf->lock_set = 1;
2174     return NULL;
2175 }
2176
2177 static const char *set_cache_lock_path(cmd_parms *parms, void *dummy,
2178                                     const char *arg)
2179 {
2180     cache_server_conf *conf;
2181
2182     conf =
2183         (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2184                                                   &cache_module);
2185
2186     conf->lockpath = ap_server_root_relative(parms->pool, arg);
2187     if (!conf->lockpath) {
2188         return apr_pstrcat(parms->pool, "Invalid CacheLockPath path ",
2189                            arg, NULL);
2190     }
2191     conf->lockpath_set = 1;
2192     return NULL;
2193 }
2194
2195 static const char *set_cache_lock_maxage(cmd_parms *parms, void *dummy,
2196                                     const char *arg)
2197 {
2198     cache_server_conf *conf;
2199     apr_int64_t seconds;
2200
2201     conf =
2202         (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2203                                                   &cache_module);
2204     seconds = apr_atoi64(arg);
2205     if (seconds <= 0) {
2206         return "CacheLockMaxAge value must be a non-zero positive integer";
2207     }
2208     conf->lockmaxage = apr_time_from_sec(seconds);
2209     conf->lockmaxage_set = 1;
2210     return NULL;
2211 }
2212
2213 static const char *set_cache_x_cache(cmd_parms *parms, void *dummy, int flag)
2214 {
2215
2216     if (parms->path) {
2217         cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2218
2219         dconf->x_cache = flag;
2220         dconf->x_cache_set = 1;
2221
2222     }
2223     else {
2224         cache_server_conf *conf =
2225             (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2226                                                       &cache_module);
2227
2228         conf->x_cache = flag;
2229         conf->x_cache_set = 1;
2230
2231     }
2232
2233     return NULL;
2234 }
2235
2236 static const char *set_cache_x_cache_detail(cmd_parms *parms, void *dummy, int flag)
2237 {
2238
2239     if (parms->path) {
2240         cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2241
2242         dconf->x_cache_detail = flag;
2243         dconf->x_cache_detail_set = 1;
2244
2245     }
2246     else {
2247         cache_server_conf *conf =
2248             (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2249                                                       &cache_module);
2250
2251         conf->x_cache_detail = flag;
2252         conf->x_cache_detail_set = 1;
2253
2254     }
2255
2256     return NULL;
2257 }
2258
2259 static const char *set_cache_key_base_url(cmd_parms *parms, void *dummy,
2260         const char *arg)
2261 {
2262     cache_server_conf *conf;
2263     apr_status_t rv;
2264
2265     conf =
2266         (cache_server_conf *)ap_get_module_config(parms->server->module_config,
2267                                                   &cache_module);
2268     conf->base_uri = apr_pcalloc(parms->pool, sizeof(apr_uri_t));
2269     rv = apr_uri_parse(parms->pool, arg, conf->base_uri);
2270     if (rv != APR_SUCCESS) {
2271         return apr_psprintf(parms->pool, "Could not parse '%s' as an URL.", arg);
2272     }
2273     else if (!conf->base_uri->scheme && !conf->base_uri->hostname &&
2274             !conf->base_uri->port_str) {
2275         return apr_psprintf(parms->pool, "URL '%s' must contain at least one of a scheme, a hostname or a port.", arg);
2276     }
2277     conf->base_uri_set = 1;
2278     return NULL;
2279 }
2280
2281 static const char *set_cache_stale_on_error(cmd_parms *parms, void *dummy,
2282         int flag)
2283 {
2284     cache_dir_conf *dconf = (cache_dir_conf *)dummy;
2285
2286     dconf->stale_on_error = flag;
2287     dconf->stale_on_error_set = 1;
2288     return NULL;
2289 }
2290
2291 static int cache_post_config(apr_pool_t *p, apr_pool_t *plog,
2292                              apr_pool_t *ptemp, server_rec *s)
2293 {
2294     /* This is the means by which unusual (non-unix) os's may find alternate
2295      * means to run a given command (e.g. shebang/registry parsing on Win32)
2296      */
2297     cache_generate_key = APR_RETRIEVE_OPTIONAL_FN(ap_cache_generate_key);
2298     if (!cache_generate_key) {
2299         cache_generate_key = cache_generate_key_default;
2300     }
2301     return OK;
2302 }
2303
2304
2305 static const command_rec cache_cmds[] =
2306 {
2307     /* XXX
2308      * Consider a new config directive that enables loading specific cache
2309      * implememtations (like mod_cache_mem, mod_cache_file, etc.).
2310      * Rather than using a LoadModule directive, admin would use something
2311      * like CacheModule  mem_cache_module | file_cache_module, etc,
2312      * which would cause the approprpriate cache module to be loaded.
2313      * This is more intuitive that requiring a LoadModule directive.
2314      */
2315
2316     AP_INIT_TAKE12("CacheEnable", add_cache_enable, NULL, RSRC_CONF|ACCESS_CONF,
2317                    "A cache type and partial URL prefix below which "
2318                    "caching is enabled"),
2319     AP_INIT_TAKE1("CacheDisable", add_cache_disable, NULL, RSRC_CONF|ACCESS_CONF,
2320                   "A partial URL prefix below which caching is disabled"),
2321     AP_INIT_TAKE1("CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF|ACCESS_CONF,
2322                   "The maximum time in seconds to cache a document"),
2323     AP_INIT_TAKE1("CacheMinExpire", set_cache_minex, NULL, RSRC_CONF|ACCESS_CONF,
2324                   "The minimum time in seconds to cache a document"),
2325     AP_INIT_TAKE1("CacheDefaultExpire", set_cache_defex, NULL, RSRC_CONF|ACCESS_CONF,
2326                   "The default time in seconds to cache a document"),
2327     AP_INIT_FLAG("CacheQuickHandler", set_cache_quick_handler, NULL,
2328                  RSRC_CONF,
2329                  "Run the cache in the quick handler, default on"),
2330     AP_INIT_FLAG("CacheIgnoreNoLastMod", set_cache_ignore_no_last_mod, NULL,
2331                  RSRC_CONF|ACCESS_CONF,
2332                  "Ignore Responses where there is no Last Modified Header"),
2333     AP_INIT_FLAG("CacheIgnoreCacheControl", set_cache_ignore_cachecontrol,
2334                  NULL, RSRC_CONF,
2335                  "Ignore requests from the client for uncached content"),
2336     AP_INIT_FLAG("CacheStoreExpired", set_cache_store_expired,
2337                  NULL, RSRC_CONF|ACCESS_CONF,
2338                  "Ignore expiration dates when populating cache, resulting in "
2339                  "an If-Modified-Since request to the backend on retrieval"),
2340     AP_INIT_FLAG("CacheStorePrivate", set_cache_store_private,
2341                  NULL, RSRC_CONF|ACCESS_CONF,
2342                  "Ignore 'Cache-Control: private' and store private content"),
2343     AP_INIT_FLAG("CacheStoreNoStore", set_cache_store_nostore,
2344                  NULL, RSRC_CONF|ACCESS_CONF,
2345                  "Ignore 'Cache-Control: no-store' and store sensitive content"),
2346     AP_INIT_ITERATE("CacheIgnoreHeaders", add_ignore_header, NULL, RSRC_CONF,
2347                     "A space separated list of headers that should not be "
2348                     "stored by the cache"),
2349     AP_INIT_FLAG("CacheIgnoreQueryString", set_cache_ignore_querystring,
2350                  NULL, RSRC_CONF,
2351                  "Ignore query-string when caching"),
2352     AP_INIT_ITERATE("CacheIgnoreURLSessionIdentifiers", add_ignore_session_id,
2353                     NULL, RSRC_CONF, "A space separated list of session "
2354                     "identifiers that should be ignored for creating the key "
2355                     "of the cached entity."),
2356     AP_INIT_TAKE1("CacheLastModifiedFactor", set_cache_factor, NULL, RSRC_CONF|ACCESS_CONF,
2357                   "The factor used to estimate Expires date from "
2358                   "LastModified date"),
2359     AP_INIT_FLAG("CacheLock", set_cache_lock,
2360                  NULL, RSRC_CONF,
2361                  "Enable or disable the thundering herd lock."),
2362     AP_INIT_TAKE1("CacheLockPath", set_cache_lock_path, NULL, RSRC_CONF,
2363                   "The thundering herd lock path. Defaults to the '"
2364                   DEFAULT_CACHE_LOCKPATH "' directory in the system "
2365                   "temp directory."),
2366     AP_INIT_TAKE1("CacheLockMaxAge", set_cache_lock_maxage, NULL, RSRC_CONF,
2367                   "Maximum age of any thundering herd lock."),
2368     AP_INIT_FLAG("CacheHeader", set_cache_x_cache, NULL, RSRC_CONF | ACCESS_CONF,
2369                  "Add a X-Cache header to responses. Default is off."),
2370     AP_INIT_FLAG("CacheDetailHeader", set_cache_x_cache_detail, NULL,
2371                  RSRC_CONF | ACCESS_CONF,
2372                  "Add a X-Cache-Detail header to responses. Default is off."),
2373     AP_INIT_TAKE1("CacheKeyBaseURL", set_cache_key_base_url, NULL, RSRC_CONF,
2374                   "Override the base URL of reverse proxied cache keys."),
2375     AP_INIT_FLAG("CacheStaleOnError", set_cache_stale_on_error,
2376                  NULL, RSRC_CONF|ACCESS_CONF,
2377                  "Serve stale content on 5xx errors if present. Defaults to on."),
2378     {NULL}
2379 };
2380
2381 static void register_hooks(apr_pool_t *p)
2382 {
2383     /* cache initializer */
2384     /* cache quick handler */
2385     ap_hook_quick_handler(cache_quick_handler, NULL, NULL, APR_HOOK_FIRST);
2386     /* cache handler */
2387     ap_hook_handler(cache_handler, NULL, NULL, APR_HOOK_REALLY_FIRST);
2388     /* cache status */
2389     cache_hook_cache_status(cache_status, NULL, NULL, APR_HOOK_MIDDLE);
2390     /* cache error handler */
2391     ap_hook_insert_error_filter(cache_insert_error_filter, NULL, NULL, APR_HOOK_MIDDLE);
2392     /* cache filters
2393      * XXX The cache filters need to run right after the handlers and before
2394      * any other filters. Consider creating AP_FTYPE_CACHE for this purpose.
2395      *
2396      * Depending on the type of request (subrequest / main request) they
2397      * need to be run before AP_FTYPE_CONTENT_SET / after AP_FTYPE_CONTENT_SET
2398      * filters. Thus create two filter handles for each type:
2399      * cache_save_filter_handle / cache_out_filter_handle to be used by
2400      * main requests and
2401      * cache_save_subreq_filter_handle / cache_out_subreq_filter_handle
2402      * to be run by subrequest
2403      */
2404     /*
2405      * CACHE is placed into the filter chain at an admin specified location,
2406      * and when the cache_handler is run, the CACHE filter is swapped with
2407      * the CACHE_OUT filter, or CACHE_SAVE filter as appropriate. This has
2408      * the effect of offering optional fine control of where the cache is
2409      * inserted into the filter chain.
2410      */
2411     cache_filter_handle =
2412         ap_register_output_filter("CACHE",
2413                                   cache_filter,
2414                                   NULL,
2415                                   AP_FTYPE_RESOURCE);
2416     /*
2417      * CACHE_SAVE must go into the filter chain after a possible DEFLATE
2418      * filter to ensure that the compressed content is stored.
2419      * Incrementing filter type by 1 ensures this happens.
2420      */
2421     cache_save_filter_handle =
2422         ap_register_output_filter("CACHE_SAVE",
2423                                   cache_save_filter,
2424                                   NULL,
2425                                   AP_FTYPE_CONTENT_SET+1);
2426     /*
2427      * CACHE_SAVE_SUBREQ must go into the filter chain before SUBREQ_CORE to
2428      * handle subrequsts. Decrementing filter type by 1 ensures this
2429      * happens.
2430      */
2431     cache_save_subreq_filter_handle =
2432         ap_register_output_filter("CACHE_SAVE_SUBREQ",
2433                                   cache_save_filter,
2434                                   NULL,
2435                                   AP_FTYPE_CONTENT_SET-1);
2436     /*
2437      * CACHE_OUT must go into the filter chain after a possible DEFLATE
2438      * filter to ensure that already compressed cache objects do not
2439      * get compressed again. Incrementing filter type by 1 ensures
2440      * this happens.
2441      */
2442     cache_out_filter_handle =
2443         ap_register_output_filter("CACHE_OUT",
2444                                   cache_out_filter,
2445                                   NULL,
2446                                   AP_FTYPE_CONTENT_SET+1);
2447     /*
2448      * CACHE_OUT_SUBREQ must go into the filter chain before SUBREQ_CORE to
2449      * handle subrequsts. Decrementing filter type by 1 ensures this
2450      * happens.
2451      */
2452     cache_out_subreq_filter_handle =
2453         ap_register_output_filter("CACHE_OUT_SUBREQ",
2454                                   cache_out_filter,
2455                                   NULL,
2456                                   AP_FTYPE_CONTENT_SET-1);
2457     /* CACHE_REMOVE_URL has to be a protocol filter to ensure that is
2458      * run even if the response is a canned error message, which
2459      * removes the content filters.
2460      */
2461     cache_remove_url_filter_handle =
2462         ap_register_output_filter("CACHE_REMOVE_URL",
2463                                   cache_remove_url_filter,
2464                                   NULL,
2465                                   AP_FTYPE_PROTOCOL);
2466     ap_hook_post_config(cache_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
2467 }
2468
2469 AP_DECLARE_MODULE(cache) =
2470 {
2471     STANDARD20_MODULE_STUFF,
2472     create_dir_config,      /* create per-directory config structure */
2473     merge_dir_config,       /* merge per-directory config structures */
2474     create_cache_config,    /* create per-server config structure */
2475     merge_cache_config,     /* merge per-server config structures */
2476     cache_cmds,             /* command apr_table_t */
2477     register_hooks
2478 };
2479
2480 APR_HOOK_STRUCT(
2481     APR_HOOK_LINK(cache_status)
2482 )
2483
2484 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(cache, CACHE, int, cache_status,
2485         (cache_handle_t *h, request_rec *r,
2486                 apr_table_t *headers, ap_cache_status_e status,
2487                 const char *reason), (h, r, headers, status, reason),
2488         OK, DECLINED)