ASF Bugzilla – Attachment 11169 Details for
Bug 27791
mod_cache doesn't re-cache expired content
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
modified mod_cache.c file that is delivered with 2.0.49
mod_cache.c.txt (text/plain), 42.77 KB, created by
Darron Wood
on 2004-04-07 15:09:00 UTC
(
hide
)
Description:
modified mod_cache.c file that is delivered with 2.0.49
Filename:
MIME Type:
Creator:
Darron Wood
Created:
2004-04-07 15:09:00 UTC
Size:
42.77 KB
patch
obsolete
>/* Copyright 2000-2004 The Apache Software Foundation > * > * Licensed under the Apache License, Version 2.0 (the "License"); > * you may not use this file except in compliance with the License. > * You may obtain a copy of the License at > * > * http://www.apache.org/licenses/LICENSE-2.0 > * > * Unless required by applicable law or agreed to in writing, software > * distributed under the License is distributed on an "AS IS" BASIS, > * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > * See the License for the specific language governing permissions and > * limitations under the License. > */ > >#define CORE_PRIVATE > >#include "mod_cache.h" > >module AP_MODULE_DECLARE_DATA cache_module; >APR_OPTIONAL_FN_TYPE(ap_cache_generate_key) *cache_generate_key; > >/* -------------------------------------------------------------- */ > > >/* Handles for cache filters, resolved at startup to eliminate > * a name-to-function mapping on each request > */ >static ap_filter_rec_t *cache_in_filter_handle; >static ap_filter_rec_t *cache_out_filter_handle; >static ap_filter_rec_t *cache_conditional_filter_handle; > >/* > * CACHE handler > * ------------- > * > * Can we deliver this request from the cache? > * If yes: > * deliver the content by installing the CACHE_OUT filter. > * If no: > * check whether we're allowed to try cache it > * If yes: > * add CACHE_IN filter > * If No: > * oh well. > */ > >static int cache_url_handler(request_rec *r, int lookup) >{ > apr_status_t rv; > const char *cc_in, *pragma, *auth; > apr_uri_t uri = r->parsed_uri; > char *url = r->unparsed_uri; > apr_size_t urllen; > char *path = uri.path; > const char *types; > cache_info *info = NULL; > cache_request_rec *cache; > cache_server_conf *conf; > const char *etag; > const char *if_match, *if_modified_since, *if_unmodified, *if_nonematch; > apr_time_t tmp_time; > apr_int64_t mtime; > > conf = (cache_server_conf *) ap_get_module_config(r->server->module_config, > &cache_module); > > /* we don't handle anything but GET */ > if (r->method_number != M_GET) { > return DECLINED; > } > > /* > * Which cache module (if any) should handle this request? > */ > if (!(types = ap_cache_get_cachetype(r, conf, path))) { > return DECLINED; > } > > urllen = strlen(url); > if (urllen > MAX_URL_LENGTH) { > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, > "cache: URL exceeds length threshold: %s", url); > return DECLINED; > } > /* DECLINE urls ending in / ??? EGP: why? */ > if (url[urllen-1] == '/') { > return DECLINED; > } > > /* make space for the per request config */ > cache = (cache_request_rec *) ap_get_module_config(r->request_config, > &cache_module); > if (!cache) { > cache = apr_pcalloc(r->pool, sizeof(cache_request_rec)); > ap_set_module_config(r->request_config, &cache_module, cache); > } > > /* save away the type */ > cache->types = types; > > /* > * Are we allowed to serve cached info at all? > */ > > /* find certain cache controlling headers */ > cc_in = apr_table_get(r->headers_in, "Cache-Control"); > pragma = apr_table_get(r->headers_in, "Pragma"); > auth = apr_table_get(r->headers_in, "Authorization"); > > /* 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 > * - Pragma: no-cache > * - Any requests requiring authorization. > */ > if (conf->ignorecachecontrol == 1 && auth == NULL) { > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, > "incoming request is asking for a uncached version of " > "%s, but we know better and are ignoring it", url); > } > else { >/* if (ap_cache_liststr(NULL, cc_in, "no-store", NULL) || > ap_cache_liststr(NULL, pragma, "no-cache", NULL) || (auth != NULL)) { >*/ > if (ap_cache_liststr(NULL, cc_in, "no-store", NULL) || > ap_cache_liststr(NULL, cc_in, "no-cache", NULL) || > ap_cache_liststr(NULL, pragma, "no-store", NULL) || > ap_cache_liststr(NULL, pragma, "no-cache", NULL) || > (auth != NULL)) { > > /* delete the previously cached file */ > cache_remove_url(r, cache->types, url); > > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, > "cache: no-store forbids caching of %s", url); > return DECLINED; > } > } > > /* > * Try to serve this request from the cache. > * > * If no existing cache file > * add cache_in filter > * If stale cache file > * If conditional request > * add cache_in filter > * If non-conditional request > * fudge response into a conditional > * add cache_conditional filter > * If fresh cache file > * clear filter stack > * add cache_out filter > */ > > rv = cache_select_url(r, cache->types, url); > if (DECLINED == rv) { > if (!lookup) { > /* no existing cache file */ > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, > "cache: no cache - add cache_in filter and DECLINE"); > /* add cache_in filter to cache this request */ > ap_add_output_filter_handle(cache_in_filter_handle, NULL, r, > r->connection); > } > return DECLINED; > } > else if (OK == rv) { > /* RFC2616 13.2 - Check cache object expiration */ > cache->fresh = ap_cache_check_freshness(cache, r); > if (cache->fresh) { > /* fresh data available */ > apr_bucket_brigade *out; > conn_rec *c = r->connection; > > if (lookup) { > return OK; > } > > > /* Check for conditional requests --- note that we only want to do > * this if we are successful so far and we are not processing a > * subrequest or an ErrorDocument. > * > * The order of the checks is important, since ETag checks are supposed > * to be more accurate than checks relative to the modification time. > * However, not all documents are guaranteed to *have* ETags, and some > * might have Last-Modified values w/o ETags, so this gets a little > * complicated. > */ > > if (!ap_is_HTTP_SUCCESS(r->status) || r->no_local_copy) { >/* return OK; */ > } > > etag = apr_table_get(r->headers_out, "ETag"); > > /* All of our comparisons must be in seconds, because that's the > * highest time resolution the HTTP specification allows. > */ > /* XXX: we should define a "time unset" constant */ > tmp_time = ((r->mtime != 0) ? r->mtime : apr_time_now()); > mtime = apr_time_sec(tmp_time); > > /* If an If-Match request-header field was given > * AND the field value is not "*" (meaning match anything) > * AND if our strong ETag does not match any entity tag in that field, > * respond with a status of 412 (Precondition Failed). > */ > if ((if_match = apr_table_get(r->headers_in, "If-Match")) != NULL) { > if (if_match[0] != '*' > && (etag == NULL || etag[0] == 'W' > || !ap_find_list_item(r->pool, if_match, etag))) { > > rv = HTTP_PRECONDITION_FAILED; > } > } > else { > /* Else if a valid If-Unmodified-Since request-header field was given > * AND the requested resource has been modified since the time > * specified in this field, then the server MUST > * respond with a status of 412 (Precondition Failed). > */ > if_unmodified = apr_table_get(r->headers_in, "If-Unmodified-Since"); > if (if_unmodified != NULL) { > apr_time_t ius = apr_date_parse_http(if_unmodified); > > if ((ius != APR_DATE_BAD) && (mtime > apr_time_sec(ius))) { > rv = HTTP_PRECONDITION_FAILED; > } > } > } > > /* If an If-None-Match request-header field was given > * AND the field value is "*" (meaning match anything) > * OR our ETag matches any of the entity tags in that field, fail. > * > * If the request method was GET or HEAD, failure means the server > * SHOULD respond with a 304 (Not Modified) response. > * For all other request methods, failure means the server MUST > * respond with a status of 412 (Precondition Failed). > * > * GET or HEAD allow weak etag comparison, all other methods require > * strong comparison. We can only use weak if it's not a range request. > */ > if_nonematch = apr_table_get(r->headers_in, "If-None-Match"); > if (if_nonematch != NULL) { > if (r->method_number == M_GET) { > if (strcmp(if_nonematch, "*")) { > return HTTP_NOT_MODIFIED; > } > if (etag != NULL) { > if (apr_table_get(r->headers_in, "Range")) { > if (etag[0] != 'W' > && ap_find_list_item(r->pool, if_nonematch, etag)) { > return HTTP_NOT_MODIFIED; > } > } > else if (ap_strstr_c(if_nonematch, etag)) { > return HTTP_NOT_MODIFIED; > } > } > } > else if (strcmp(if_nonematch, "*") > || (etag != NULL > && ap_find_list_item(r->pool, if_nonematch, etag))) { > > rv = HTTP_PRECONDITION_FAILED; > } > } > /* Else if a valid If-Modified-Since request-header field was given > * AND it is a GET or HEAD request > * AND the requested resource has not been modified since the time > * specified in this field, then the server MUST > * respond with a status of 304 (Not Modified). > * A date later than the server's current request time is invalid. > */ > else if ((r->method_number == M_GET) > && ((if_modified_since = > apr_table_get(r->headers_in, > "If-Modified-Since")) != NULL)) { > apr_time_t ims_time; > apr_int64_t ims, reqtime; > > ims_time = apr_date_parse_http(if_modified_since); > ims = apr_time_sec(ims_time); > reqtime = apr_time_sec(r->request_time); > > if ((ims >= mtime) && (ims <= reqtime)) { > return HTTP_NOT_MODIFIED; > } > } > > /* rv = ap_meets_conditions(r); */ /* found ap_meets_conditions did not work */ > if (rv != OK) { > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, > "cache: fresh cache - returning status %d", rv); > return rv; > } > > /* > * Not a conditionl request. Serve up the content > */ > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, > "cache: fresh cache - add cache_out filter and " > "handle request"); > > /* We are in the quick handler hook, which means that no output > * filters have been set. So lets run the insert_filter hook. > */ > ap_run_insert_filter(r); > ap_add_output_filter_handle(cache_out_filter_handle, NULL, > r, r->connection); > > /* kick off the filter stack */ > out = apr_brigade_create(r->pool, c->bucket_alloc); > if (APR_SUCCESS > != (rv = ap_pass_brigade(r->output_filters, out))) { > ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, > "cache: error returned while trying to return %s " > "cached data", > cache->type); > return rv; > } > return OK; > } > else { > if (!r->err_headers_out) { > r->err_headers_out = apr_table_make(r->pool, 3); > } > /* stale data available */ > if (lookup) { > return DECLINED; > } > > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, > "cache: stale cache - test conditional"); > /* if conditional request */ > if (ap_cache_request_is_conditional(r)) { > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, > r->server, > "cache: conditional - add cache_in filter and " > "DECLINE"); > /* Why not add CACHE_CONDITIONAL? */ > ap_add_output_filter_handle(cache_in_filter_handle, NULL, > r, r->connection); > > return DECLINED; > } > /* else if non-conditional request */ > else { > /* Temporarily hack this to work the way it had been. Its broken, > * but its broken the way it was before. I'm working on figuring > * out why the filter add in the conditional filter doesn't work. pjr > * > * info = &(cache->handle->cache_obj->info); > * > * Uncomment the above when the code in cache_conditional_filter_handle > * is properly fixed... pjr > */ > > /* fudge response into a conditional */ > if (info && info->etag) { > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, > r->server, > "cache: nonconditional - fudge conditional " > "by etag"); > /* if we have a cached etag */ > apr_table_set(r->headers_in, "If-None-Match", info->etag); > } > else if (info && info->lastmods) { > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, > r->server, > "cache: nonconditional - fudge conditional " > "by lastmod"); > /* if we have a cached IMS */ > apr_table_set(r->headers_in, > "If-Modified-Since", > info->lastmods); > } > else { > /* something else - pretend there was no cache */ > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, > r->server, > "cache: nonconditional - no cached " > "etag/lastmods - add cache_in and DECLINE"); > > ap_add_output_filter_handle(cache_in_filter_handle, NULL, > r, r->connection); > > return DECLINED; > } > /* add cache_conditional filter */ > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, > r->server, > "cache: nonconditional - add cache_conditional " > "and DECLINE"); > ap_add_output_filter_handle(cache_conditional_filter_handle, > NULL, > r, > r->connection); > > return DECLINED; > } > } > } > else { > /* error */ > ap_log_error(APLOG_MARK, APLOG_ERR, rv, > r->server, > "cache: error returned while checking for cached file by " > "%s cache", > cache->type); > return DECLINED; > } >} > >/* > * CACHE_OUT filter > * ---------------- > * > * Deliver cached content (headers and body) up the stack. > */ >static int cache_out_filter(ap_filter_t *f, apr_bucket_brigade *bb) >{ > request_rec *r = f->r; > cache_request_rec *cache; > > cache = (cache_request_rec *) ap_get_module_config(r->request_config, > &cache_module); > > if (!cache) { > /* user likely configured CACHE_OUT manually; they should use mod_cache > * configuration to do that */ > ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, > "CACHE_OUT enabled unexpectedly"); > ap_remove_output_filter(f); > return ap_pass_brigade(f->next, bb); > } > > ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server, > "cache: running CACHE_OUT filter"); > > /* cache_read_entity_headers() was called in cache_select_url() */ > cache_read_entity_body(cache->handle, r->pool, bb); > > /* This filter is done once it has served up its content */ > ap_remove_output_filter(f); > > ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r->server, > "cache: serving %s", r->uri); > return ap_pass_brigade(f->next, bb); >} > > >/* > * 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 > * Otherwise > * replace ourselves with cache_in filter > */ > >static int cache_conditional_filter(ap_filter_t *f, apr_bucket_brigade *in) >{ > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, f->r->server, > "cache: running CACHE_CONDITIONAL filter"); > > if (f->r->status == HTTP_NOT_MODIFIED) { > /* replace ourselves with CACHE_OUT filter */ > ap_add_output_filter_handle(cache_out_filter_handle, NULL, > f->r, f->r->connection); > } > else { > /* replace ourselves with CACHE_IN filter */ > ap_add_output_filter_handle(cache_in_filter_handle, NULL, > f->r, f->r->connection); > } > ap_remove_output_filter(f); > > return ap_pass_brigade(f->next, in); >} > > >/* > * 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) > * > */ > >static int cache_in_filter(ap_filter_t *f, apr_bucket_brigade *in) >{ > int rv; > int date_in_errhdr = 0; > request_rec *r = f->r; > cache_request_rec *cache; > cache_server_conf *conf; > char *url = r->unparsed_uri; > const char *cc_out, *cl; > const char *exps, *lastmods, *dates, *etag; > apr_time_t exp, date, lastmod, now; > apr_off_t size; > cache_info *info; > char *reason; > apr_pool_t *p; > > /* check first whether running this filter has any point or not */ > if(r->no_cache) { > ap_remove_output_filter(f); > return ap_pass_brigade(f->next, in); > } > > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, > "cache: running CACHE_IN filter"); > > /* Setup cache_request_rec */ > cache = (cache_request_rec *) ap_get_module_config(r->request_config, &cache_module); > if (!cache) { > cache = apr_pcalloc(r->pool, sizeof(cache_request_rec)); > ap_set_module_config(r->request_config, &cache_module, cache); > } > > reason = NULL; > p = r->pool; > /* > * Pass Data to Cache > * ------------------ > * 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 > * cached file handle? > */ > if (cache->in_checked) { > /* pass the brigades into the cache, then pass them > * up the filter stack > */ > rv = cache_write_entity_body(cache->handle, r, in); > if (rv != APR_SUCCESS) { > ap_remove_output_filter(f); > } > return ap_pass_brigade(f->next, in); > } > > /* > * Setup Data in Cache > * ------------------- > * 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. > */ > info = apr_pcalloc(r->pool, sizeof(cache_info)); > > /* read expiry date; if a bad date, then leave it so the client can > * read it > */ > exps = apr_table_get(r->err_headers_out, "Expires"); > if (exps == NULL) { > exps = apr_table_get(r->headers_out, "Expires"); > } > if (exps != NULL) { > if (APR_DATE_BAD == (exp = apr_date_parse_http(exps))) { > exps = NULL; > } > } > else { > exp = APR_DATE_BAD; > } > > /* read the last-modified date; if the date is bad, then delete it */ > lastmods = apr_table_get(r->err_headers_out, "Last-Modified"); > if (lastmods ==NULL) { > lastmods = apr_table_get(r->headers_out, "Last-Modified"); > } > if (lastmods != NULL) { > if (APR_DATE_BAD == (lastmod = apr_date_parse_http(lastmods))) { > lastmods = NULL; > } > } > else { > lastmod = APR_DATE_BAD; > } > > conf = (cache_server_conf *) ap_get_module_config(r->server->module_config, &cache_module); > /* read the etag and cache-control from the entity */ > etag = apr_table_get(r->err_headers_out, "Etag"); > if (etag == NULL) { > etag = apr_table_get(r->headers_out, "Etag"); > } > cc_out = apr_table_get(r->err_headers_out, "Cache-Control"); > if (cc_out == NULL) { > cc_out = apr_table_get(r->headers_out, "Cache-Control"); > } > > /* > * 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. > */ > if (r->status != HTTP_OK && r->status != HTTP_NON_AUTHORITATIVE > && r->status != HTTP_MULTIPLE_CHOICES > && r->status != HTTP_MOVED_PERMANENTLY > && r->status != HTTP_NOT_MODIFIED) { > /* 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. > */ > reason = apr_psprintf(p, "Response status %d", r->status); > } > else if (exps != NULL && exp == APR_DATE_BAD) { > /* if a broken Expires header is present, don't cache it */ > reason = apr_pstrcat(p, "Broken expires header: ", exps, NULL); > } > else if (r->args && exps == NULL) { > /* if query string present but no expiration time, don't cache it > * (RFC 2616/13.9) > */ > reason = "Query string present but no expires header"; > } > else if (r->status == HTTP_NOT_MODIFIED && (NULL == cache->handle)) { > /* 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"; > } > else if (r->status == HTTP_OK && lastmods == NULL && etag == NULL > && (exps == NULL) && (conf->no_last_mod_ignore ==0)) { > /* 200 OK response from HTTP/1.0 and up without Last-Modified, > * Etag, or Expires headers. > */ > /* Note: mod-include clears last_modified/expires/etags - this > * is why we have an optional function for a key-gen ;-) > */ > reason = "No Last-Modified, Etag, or Expires headers"; > } > else if (r->header_only) { > /* HEAD requests */ > reason = "HTTP HEAD request"; > } > else if (ap_cache_liststr(NULL, cc_out, "no-store", NULL)) { > /* RFC2616 14.9.2 Cache-Control: no-store response > * indicating do not cache, or stop now if you are > * trying to cache it */ > reason = "Cache-Control: no-store present"; > } > else if (ap_cache_liststr(NULL, cc_out, "private", NULL)) { > /* RFC2616 14.9.1 Cache-Control: private > * this object is marked for this user's eyes only. Behave > * as a tunnel. > */ > reason = "Cache-Control: private present"; > } > else if (apr_table_get(r->headers_in, "Authorization") != NULL > && !(ap_cache_liststr(NULL, cc_out, "s-maxage", NULL) > || ap_cache_liststr(NULL, cc_out, "must-revalidate", NULL) > || ap_cache_liststr(NULL, cc_out, "public", NULL))) { > /* 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"; > } > else if (r->no_cache) { > /* or we've been asked not to cache it above */ > reason = "no_cache present"; > } > > if (reason) { > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, > "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? > * leave it in for now.. > */ > cache_remove_url(r, cache->types, url); > > /* remove this filter from the chain */ > ap_remove_output_filter(f); > > /* ship the data up the stack */ > return ap_pass_brigade(f->next, in); > } > cache->in_checked = 1; > > /* Set the content length if known. > */ > cl = apr_table_get(r->err_headers_out, "Content-Length"); > if (cl == NULL) { > cl = apr_table_get(r->headers_out, "Content-Length"); > } > if (cl) { > size = apr_atoi64(cl); > } > else { > /* if we don't get the content-length, see if we have all the > * buckets and use their length to calculate the size > */ > apr_bucket *e; > int all_buckets_here=0; > int unresolved_length = 0; > size=0; > APR_BRIGADE_FOREACH(e, in) { > if (APR_BUCKET_IS_EOS(e)) { > all_buckets_here=1; > break; > } > if (APR_BUCKET_IS_FLUSH(e)) { > unresolved_length = 1; > continue; > } > if (e->length == (apr_size_t)-1) { > break; > } > size += e->length; > } > if (!all_buckets_here) { > size = -1; > } > } > > /* 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 > * the headers). > */ > /* no cache handle, create a new entity */ > if (!cache->handle) { > rv = cache_create_entity(r, cache->types, url, size); > } > /* pre-existing cache handle and 304, make entity fresh */ > else if (r->status == HTTP_NOT_MODIFIED) { > /* update headers: TODO */ > > /* remove this filter ??? */ > > /* XXX is this right? we set rv to OK so we replace stale header > * in this path > */ > /*rv = HTTP_NOT_MODIFIED; */ > rv = OK; > } > /* pre-existing cache handle and new entity, replace entity > * with this one > */ > else { > cache_remove_entity(r, cache->types, cache->handle); > rv = cache_create_entity(r, cache->types, url, size); > } > > if (rv != OK) { > /* Caching layer declined the opportunity to cache the response */ > ap_remove_output_filter(f); > return ap_pass_brigade(f->next, in); > } > > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, > "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 > * too. > */ > > /* Read the date. Generate one if one is not supplied */ > dates = apr_table_get(r->err_headers_out, "Date"); > if (dates != NULL) { > date_in_errhdr = 1; > } > else { > dates = apr_table_get(r->headers_out, "Date"); > } > if (dates != NULL) { > info->date = apr_date_parse_http(dates); > } > else { > info->date = APR_DATE_BAD; > } > > now = apr_time_now(); > if (info->date == APR_DATE_BAD) { /* No, or bad date */ > char *dates; > /* no date header (or bad header)! */ > /* add one; N.B. use the time _now_ rather than when we were checking > * the cache > */ > if (date_in_errhdr == 1) { > apr_table_unset(r->err_headers_out, "Date"); > } > date = now; > dates = apr_pcalloc(r->pool, MAX_STRING_LEN); > apr_rfc822_date(dates, now); > apr_table_set(r->headers_out, "Date", dates); > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, > "cache: Added date header"); > info->date = date; > } > else { > date = info->date; > } > > /* set response_time for HTTP/1.1 age calculations */ > info->response_time = now; > > /* get the request time */ > info->request_time = r->request_time; > > /* check last-modified date */ > if (lastmod != APR_DATE_BAD && lastmod > date) { > /* if it's in the future, then replace by date */ > lastmod = date; > lastmods = dates; > ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, > r->server, > "cache: Last modified is in the future, " > "replacing with now"); > } > info->lastmod = lastmod; > > /* if no expiry date then > * if lastmod > * expiry date = date + min((date - lastmod) * factor, maxexpire) > * else > * expire date = date + defaultexpire > */ > if (exp == APR_DATE_BAD) { > /* 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... > */ > if ((lastmod != APR_DATE_BAD) && (lastmod < date)) { > apr_time_t x = (apr_time_t) ((date - lastmod) * conf->factor); > > if (x > conf->maxex) { > x = conf->maxex; > } > exp = date + x; > } > else { > exp = date + conf->defex; > } > } > info->expire = exp; > > info->content_type = apr_pstrdup(r->pool, r->content_type); > info->etag = apr_pstrdup(r->pool, etag); > info->lastmods = apr_pstrdup(r->pool, lastmods); > info->filename = apr_pstrdup(r->pool, r->filename ); > > /* > * Write away header information to cache. > */ > rv = cache_write_entity_headers(cache->handle, r, info); > if (rv == APR_SUCCESS) { > rv = cache_write_entity_body(cache->handle, r, in); > } > if (rv != APR_SUCCESS) { > ap_remove_output_filter(f); > } > > return ap_pass_brigade(f->next, in); >} > >/* -------------------------------------------------------------- */ >/* Setup configurable data */ > >static void * create_cache_config(apr_pool_t *p, server_rec *s) >{ > cache_server_conf *ps = apr_pcalloc(p, sizeof(cache_server_conf)); > > /* array of URL prefixes for which caching is enabled */ > ps->cacheenable = apr_array_make(p, 10, sizeof(struct cache_enable)); > /* array of URL prefixes for which caching is disabled */ > ps->cachedisable = apr_array_make(p, 10, sizeof(struct cache_disable)); > /* maximum time to cache a document */ > ps->maxex = DEFAULT_CACHE_MAXEXPIRE; > ps->maxex_set = 0; > /* default time to cache a document */ > ps->defex = DEFAULT_CACHE_EXPIRE; > ps->defex_set = 0; > /* factor used to estimate Expires date from LastModified date */ > ps->factor = DEFAULT_CACHE_LMFACTOR; > ps->factor_set = 0; > /* default percentage to force cache completion */ > ps->complete = DEFAULT_CACHE_COMPLETION; > ps->complete_set = 0; > ps->no_last_mod_ignore_set = 0; > ps->no_last_mod_ignore = 0; > ps->ignorecachecontrol = 0; > ps->ignorecachecontrol_set = 0 ; > return ps; >} > >static void * merge_cache_config(apr_pool_t *p, void *basev, void *overridesv) >{ > cache_server_conf *ps = apr_pcalloc(p, sizeof(cache_server_conf)); > cache_server_conf *base = (cache_server_conf *) basev; > cache_server_conf *overrides = (cache_server_conf *) overridesv; > > /* array of URL prefixes for which caching is disabled */ > ps->cachedisable = apr_array_append(p, > base->cachedisable, > overrides->cachedisable); > /* array of URL prefixes for which caching is enabled */ > ps->cacheenable = apr_array_append(p, > base->cacheenable, > overrides->cacheenable); > /* maximum time to cache a document */ > ps->maxex = (overrides->maxex_set == 0) ? base->maxex : overrides->maxex; > /* default time to cache a document */ > ps->defex = (overrides->defex_set == 0) ? base->defex : overrides->defex; > /* factor used to estimate Expires date from LastModified date */ > ps->factor = > (overrides->factor_set == 0) ? base->factor : overrides->factor; > /* default percentage to force cache completion */ > ps->complete = > (overrides->complete_set == 0) ? base->complete : overrides->complete; > > ps->no_last_mod_ignore = > (overrides->no_last_mod_ignore_set == 0) > ? base->no_last_mod_ignore > : overrides->no_last_mod_ignore; > ps->ignorecachecontrol = > (overrides->ignorecachecontrol_set == 0) > ? base->ignorecachecontrol > : overrides->ignorecachecontrol; > return ps; >} >static const char *set_cache_ignore_no_last_mod(cmd_parms *parms, void *dummy, > int flag) >{ > cache_server_conf *conf; > > conf = > (cache_server_conf *)ap_get_module_config(parms->server->module_config, > &cache_module); > conf->no_last_mod_ignore = flag; > conf->no_last_mod_ignore_set = 1; > return NULL; > >} > >static const char *set_cache_ignore_cachecontrol(cmd_parms *parms, > void *dummy, int flag) >{ > cache_server_conf *conf; > > conf = > (cache_server_conf *)ap_get_module_config(parms->server->module_config, > &cache_module); > conf->ignorecachecontrol = flag; > conf->ignorecachecontrol_set = 1; > return NULL; >} > >static const char *add_cache_enable(cmd_parms *parms, void *dummy, > const char *type, > const char *url) >{ > cache_server_conf *conf; > struct cache_enable *new; > > conf = > (cache_server_conf *)ap_get_module_config(parms->server->module_config, > &cache_module); > new = apr_array_push(conf->cacheenable); > new->type = type; > new->url = url; > return NULL; >} > >static const char *add_cache_disable(cmd_parms *parms, void *dummy, > const char *url) >{ > cache_server_conf *conf; > struct cache_enable *new; > > conf = > (cache_server_conf *)ap_get_module_config(parms->server->module_config, > &cache_module); > new = apr_array_push(conf->cachedisable); > new->url = url; > return NULL; >} > >static const char *set_cache_maxex(cmd_parms *parms, void *dummy, > const char *arg) >{ > cache_server_conf *conf; > > conf = > (cache_server_conf *)ap_get_module_config(parms->server->module_config, > &cache_module); > conf->maxex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC); > conf->maxex_set = 1; > return NULL; >} > >static const char *set_cache_defex(cmd_parms *parms, void *dummy, > const char *arg) >{ > cache_server_conf *conf; > > conf = > (cache_server_conf *)ap_get_module_config(parms->server->module_config, > &cache_module); > conf->defex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC); > conf->defex_set = 1; > return NULL; >} > >static const char *set_cache_factor(cmd_parms *parms, void *dummy, > const char *arg) >{ > cache_server_conf *conf; > double val; > > conf = > (cache_server_conf *)ap_get_module_config(parms->server->module_config, > &cache_module); > if (sscanf(arg, "%lg", &val) != 1) { > return "CacheLastModifiedFactor value must be a float"; > } > conf->factor = val; > conf->factor_set = 1; > return NULL; >} > >static const char *set_cache_complete(cmd_parms *parms, void *dummy, > const char *arg) >{ > cache_server_conf *conf; > int val; > > conf = > (cache_server_conf *)ap_get_module_config(parms->server->module_config, > &cache_module); > if (sscanf(arg, "%u", &val) != 1) { > return "CacheForceCompletion value must be a percentage"; > } > conf->complete = val; > conf->complete_set = 1; > return NULL; >} > >static int cache_post_config(apr_pool_t *p, apr_pool_t *plog, > apr_pool_t *ptemp, server_rec *s) >{ > /* This is the means by which unusual (non-unix) os's may find alternate > * means to run a given command (e.g. shebang/registry parsing on Win32) > */ > cache_generate_key = APR_RETRIEVE_OPTIONAL_FN(ap_cache_generate_key); > if (!cache_generate_key) { > cache_generate_key = cache_generate_key_default; > } > return OK; >} > >static const command_rec cache_cmds[] = >{ > /* XXX > * 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. > */ > > AP_INIT_TAKE2("CacheEnable", add_cache_enable, NULL, RSRC_CONF, > "A cache type and partial URL prefix below which " > "caching is enabled"), > AP_INIT_TAKE1("CacheDisable", add_cache_disable, NULL, RSRC_CONF, > "A partial URL prefix below which caching is disabled"), > AP_INIT_TAKE1("CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF, > "The maximum time in seconds to cache a document"), > AP_INIT_TAKE1("CacheDefaultExpire", set_cache_defex, NULL, RSRC_CONF, > "The default time in seconds to cache a document"), > AP_INIT_FLAG("CacheIgnoreNoLastMod", set_cache_ignore_no_last_mod, NULL, > RSRC_CONF, > "Ignore Responses where there is no Last Modified Header"), > AP_INIT_FLAG("CacheIgnoreCacheControl", set_cache_ignore_cachecontrol, > NULL, > RSRC_CONF, > "Ignore requests from the client for uncached content"), > AP_INIT_TAKE1("CacheLastModifiedFactor", set_cache_factor, NULL, RSRC_CONF, > "The factor used to estimate Expires date from " > "LastModified date"), > AP_INIT_TAKE1("CacheForceCompletion", set_cache_complete, NULL, RSRC_CONF, > "Percentage of download to arrive for the cache to force " > "complete transfer"), > {NULL} >}; > >static void register_hooks(apr_pool_t *p) >{ > /* cache initializer */ > /* cache handler */ > ap_hook_quick_handler(cache_url_handler, NULL, NULL, APR_HOOK_FIRST); > /* cache filters > * 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_in_filter_handle = > ap_register_output_filter("CACHE_IN", > cache_in_filter, > NULL, > AP_FTYPE_CONTENT_SET-1); > /* CACHE_OUT must go into the filter chain before SUBREQ_CORE to > * handle subrequsts. Decrementing filter type by 1 ensures this > * happens. > */ > cache_out_filter_handle = > ap_register_output_filter("CACHE_OUT", > cache_out_filter, > NULL, > AP_FTYPE_CONTENT_SET-1); > cache_conditional_filter_handle = > ap_register_output_filter("CACHE_CONDITIONAL", > cache_conditional_filter, > NULL, > AP_FTYPE_CONTENT_SET); > ap_hook_post_config(cache_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST); >} > >module AP_MODULE_DECLARE_DATA cache_module = >{ > STANDARD20_MODULE_STUFF, > NULL, /* create per-directory config structure */ > NULL, /* merge per-directory config structures */ > create_cache_config, /* create per-server config structure */ > merge_cache_config, /* merge per-server config structures */ > cache_cmds, /* command apr_table_t */ > register_hooks >};
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 27791
: 11169 |
11170
|
11176
|
11177