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