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