mod_cache.c revision 98545bfcdf6b9ad9f293cdc0743bb831d785a2f7
/* ==================================================================== * The Apache Software License, Version 1.1 * Copyright (c) 2000-2002 The Apache Software Foundation. All rights * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * ==================================================================== * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * Portions of this software are based upon public domain software * originally written at the National Center for Supercomputing Applications, * University of Illinois, Urbana-Champaign. /* -------------------------------------------------------------- */ /* Handles for cache filters, resolved at startup to eliminate * a name-to-function mapping on each request * Can we deliver this request from the cache? * deliver the content by installing the CACHE_OUT filter. * check whether we're allowed to try cache it /* we don't handle anything but GET */ * Which cache module (if any) should handle this request? "cache: URL %s is being handled by %s",
path,
types);
"cache: URL exceeds length threshold: %s",
url);
/* DECLINE urls ending in / ??? EGP: why? */ /* make space for the per request config */ * Are we allowed to serve cached info at all? /* find certain cache controlling headers */ /* first things first - does the request allow us to return * cached information at all? If not, just decline the request. * Note that there is a big difference between not being allowed * to cache a request (no-store) and not being allowed to return * a cached request without revalidation (max-age=0). * Caching is forbidden under the following circumstances: * - RFC2616 14.9.2 Cache-Control: no-store * - Any requests requiring authorization. "incoming request is asking for a uncached version of " "%s, but we know better and are ignoring it",
url);
/* delete the previously cached file */ "cache: no-store forbids caching of %s",
url);
* Try to serve this request from the cache. * If no existing cache file * If non-conditional request * fudge response into a conditional * add cache_conditional filter /* no existing cache file */ "cache: no cache - add cache_in filter and DECLINE");
/* add cache_in filter to cache this request */ /* RFC2616 13.2 - Check cache object expiration */ /* fresh data available */ "cache: fresh cache - returning status %d",
rv);
* Not a conditionl request. Serve up the content "cache: fresh cache - add cache_out filter and " /* We are in the quick handler hook, which means that no output * filters have been set. So lets run the insert_filter hook. /* kick off the filter stack */ "cache: error returned while trying to return %s " /* stale data available */ "cache: stale cache - test conditional");
/* if conditional request */ "cache: conditional - add cache_in filter and " /* Why not add CACHE_CONDITIONAL? */ /* else if non-conditional request */ /* fudge response into a conditional */ "cache: nonconditional - fudge conditional " /* if we have a cached etag */ "cache: nonconditional - fudge conditional " /* if we have a cached IMS */ /* something else - pretend there was no cache */ "cache: nonconditional - no cached " /* add cache_conditional filter */ "cache: nonconditional - add cache_conditional " "cache: error returned while checking for cached file by " * Deliver cached content (headers and body) up the stack. /* user likely configured CACHE_OUT manually; they should use mod_cache * configuration to do that */ "CACHE_OUT enabled unexpectedly");
"cache: running CACHE_OUT filter");
/* cache_read_entity_headers() was called in cache_select_url() */ /* This filter is done once it has served up its content */ "cache: serving %s", r->
uri);
* CACHE_CONDITIONAL filter * ------------------------ * Decide whether or not cached content should be delivered * based on our fudged conditional request. * If response HTTP_NOT_MODIFIED * replace ourselves with cache_out filter * replace ourselves with cache_in filter "cache: running CACHE_CONDITIONAL filter");
/* replace ourselves with CACHE_OUT filter */ /* replace ourselves with CACHE_IN filter */ * Decide whether or not this content should be cached. * If we decide no it should: * remove the filter from the chain * If we decide yes it should: * pass the data to the storage manager * pass the data to the next filter (the network) /* check first whether running this filter has any point or not */ "cache: running CACHE_IN filter");
/* Setup cache_request_rec */ * This section passes the brigades into the cache modules, but only * if the setup section (see below) is complete. /* have we already run the cachability check and set up the /* pass the brigades into the cache, then pass them * This section opens the cache entity and sets various caching * parameters, and decides whether this URL should be cached at * all. This section is* run before the above section. /* read expiry date; if a bad date, then leave it so the client can /* read the last-modified date; if the date is bad, then delete it */ /* read the etag and cache-control from the entity */ * what responses should we not cache? * At this point we decide based on the response headers whether it * is appropriate _NOT_ to cache the data from the server. There are * a whole lot of conditions that prevent us from caching this data. * They are tested here one by one to be clear and unambiguous. /* RFC2616 13.4 we are allowed to cache 200, 203, 206, 300, 301 or 410 * We don't cache 206, because we don't (yet) cache partial responses. * We include 304 Not Modified here too as this is the origin server * telling us to serve the cached copy. /* if a broken Expires header is present, don't cache it */ /* if query string present but no expiration time, don't cache it reason =
"Query string present but no expires header";
/* if the server said 304 Not Modified but we have no cache * file - pass this untouched to the user agent, it's not for us. reason =
"HTTP Status 304 Not Modified";
/* 200 OK response from HTTP/1.0 and up without a Last-Modified * is why we have an optional function for a key-gen ;-) reason =
"No Last-Modified or Etag header";
/* RFC2616 14.9.2 Cache-Control: no-store response * indicating do not cache, or stop now if you are reason =
"Cache-Control: no-store present";
/* RFC2616 14.9.1 Cache-Control: private * this object is marked for this user's eyes only. Behave reason =
"Cache-Control: private present";
/* RFC2616 14.8 Authorisation: * if authorisation is included in the request, we don't cache, * but we can cache if the following exceptions are true: * 1) If Cache-Control: s-maxage is included * 2) If Cache-Control: must-revalidate is included * 3) If Cache-Control: public is included reason =
"Authorization required";
/* or we've been asked not to cache it above */ "cache: %s not cached. Reason: %s",
url,
reason);
/* remove this object from the cache * BillS Asks.. Why do we need to make this call to remove_url? /* remove this filter from the chain */ /* ship the data up the stack */ /* Set the content length if known. /* if we don't get the content-length, see if we have all the * buckets and use their length to calculate the size /* It's safe to cache the response. * There are two possiblities at this point: * - cache->handle == NULL. In this case there is no previously * cached entity anywhere on the system. We must create a brand * new entity and store the response in it. * - cache->handle != NULL. In this case there is a stale * entity in the system which needs to be replaced by new * content (unless the result was 304 Not Modified, which means * the cached entity is actually fresh, and we should update /* no cache handle, create a new entity */ /* pre-existing cache handle and 304, make entity fresh */ /* remove this filter ??? */ /* XXX is this right? we must set rv to something other than OK /* pre-existing cache handle and new entity, replace entity /* Caching layer declined the opportunity to cache the response */ "cache: Caching url: %s",
url);
* We now want to update the cache file header information with * the new date, last modified, expire and content length and write * it away to our cache file. First, we determine these values from * the response, using heuristics if appropriate. * In addition, we make HTTP/1.1 age calculations and write them away /* Read the date. Generate one if one is not supplied */ /* add one; N.B. use the time _now_ rather than when we were checking "cache: Added date header");
/* set response_time for HTTP/1.1 age calculations */ /* get the request time */ /* check last-modified date */ /* XXX FIXME we're referencing date on a path where we didn't set it */ /* if it's in the future, then replace by date */ "cache: Last modified is in the future, " /* if no expiry date then * expiry date = now + min((date - lastmod) * factor, maxexpire) * expire date = now + defaultexpire /* if lastmod == date then you get 0*conf->factor which results in * an expiration time of now. This causes some problems with * freshness calculations, so we choose the else path... * Write away header information to cache. /* -------------------------------------------------------------- */ /* Setup configurable data */ /* array of URL prefixes for which caching is enabled */ /* array of URL prefixes for which caching is disabled */ /* maximum time to cache a document */ /* default time to cache a document */ /* factor used to estimate Expires date from LastModified date */ /* default percentage to force cache completion */ /* array of URL prefixes for which caching is disabled */ /* array of URL prefixes for which caching is enabled */ /* maximum time to cache a document */ /* default time to cache a document */ /* factor used to estimate Expires date from LastModified date */ /* default percentage to force cache completion */ return "CacheLastModifiedFactor value must be a float";
return "CacheForceCompletion value must be a percentage";
/* This is the means by which unusual (non-unix) os's may find alternate * Consider a new config directive that enables loading specific cache * implememtations (like mod_cache_mem, mod_cache_file, etc.). * Rather than using a LoadModule directive, admin would use something * like CacheModule mem_cache_module | file_cache_module, etc, * which would cause the approprpriate cache module to be loaded. * This is more intuitive that requiring a LoadModule directive. "A cache type and partial URL prefix below which " "A partial URL prefix below which caching is disabled"),
"The maximum time in seconds to cache a document"),
"The default time in seconds to cache a document"),
"Ignore Responses where there is no Last Modified Header"),
"Ignore requests from the client for uncached content"),
"The factor used to estimate Expires date from " "Percentage of download to arrive for the cache to force " * XXX The cache filters need to run right after the handlers and before * any other filters. Consider creating AP_FTYPE_CACHE for this purpose. * Make them AP_FTYPE_CONTENT for now. * XXX ianhH:they should run AFTER all the other content filters. /* CACHE_OUT must go into the filter chain before SUBREQ_CORE to * handle subrequsts. Decrementing filter type by 1 ensures this NULL,
/* create per-directory config structure */ NULL,
/* merge per-directory config structures */