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