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