/* Licensed to the Apache Software Foundation (ASF) under one or more *contributorlicenseagreements.SeetheNOTICEfiledistributedwith *thisworkforadditionalinformationregardingcopyrightownership. *TheASFlicensesthisfiletoYouundertheApacheLicense,Version2.0 *(the"License");youmaynotusethisfileexceptincompliancewith *theLicense.YoumayobtainacopyoftheLicenseat * *http://www.apache.org/licenses/LICENSE-2.0 * *Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense.
*/
/* Determine if "url" matches the hostname, scheme and port and path *in"filter".Allbutthepathcomparisonsarecase-insensitive.
*/ staticint uri_meets_conditions(const apr_uri_t *filter, const apr_size_t pathlen, const apr_uri_t *url, constchar *path)
{ /* Scheme, hostname port and local part. The filter URI and the *URIwetestmayhavethefollowingshapes: */<path> *<scheme>[:://<hostname>[:<port>][/<path>]] *Thatis,ifthereisnoschemethentheremustbeonlythepath, *andwecheckonlythepath;ifthereisascheme,wecheckthe *schemeforequality,andthenifpresentwematchthehostname, *andthenifpresentmatchtheport,andfinallythepathifany. * *Notethatthismeansthat"/<path>"onlymatcheslocalpaths, *andtomatchproxiedpathsone*must*specifythescheme.
*/
/* Is the filter is just for a local path or a proxy URI? */ if (!filter->scheme) { if (url->scheme || url->hostname) { return0;
}
} else { /* The URI scheme must be present and identical except for case. */ if (!url->scheme || ap_cstr_casecmp(filter->scheme, url->scheme)) { return0;
}
/* If the filter hostname is null or empty it matches any hostname, *ifitbeginswitha"*"itmatchesthe_end_oftheURIhostname *excludingthe"*",ifitbeginswitha"."itmatchesthe_end_ *oftheURI*hostnameincludingthe".",otherwiseitmustmatch
* the URI hostname exactly. */
/* If the filter port is empty it matches any URL port. *IfthefilterorURLportaremissing,ortheURLportis
* empty, they default to the port for their scheme. */
if (!(filter->port_str && !filter->port_str[0])) { /* NOTE: ap_port_of_scheme will return 0 if given NULL input */ constunsigned fport = filter->port_str ? filter->port
: apr_uri_port_of_scheme(filter->scheme); constunsigned uport = (url->port_str && url->port_str[0])
? url->port : apr_uri_port_of_scheme(url->scheme);
if (fport != uport) { return0;
}
}
}
/* For HTTP caching purposes, an empty (NULL) path is equivalent to *asingle"/"path.RFCs3986/2396
*/ if (!path) { if (*filter->path == '/' && pathlen == 1) { return1;
} else { return0;
}
}
/* Url has met all of the filter conditions so far, determine *ifthepathsmatch.
*/ return !strncmp(filter->path, path, pathlen);
}
int cache_use_early_url(request_rec *r)
{
cache_server_conf *conf;
if (r->proxyreq == PROXYREQ_PROXY) { return1;
}
conf = ap_get_module_config(r->server->module_config, &cache_module); if (conf->quick) { return1;
}
return0;
}
static cache_provider_list *get_provider(request_rec *r, struct cache_enable *ent,
cache_provider_list *providers)
{ /* Fetch from global config and add to the list. */
cache_provider *provider;
provider = ap_lookup_provider(CACHE_PROVIDER_GROUP, ent->type, "0"); if (!provider) { /* Log an error! */
} else {
cache_provider_list *newp;
newp = apr_pcalloc(r->pool, sizeof(cache_provider_list));
newp->provider_name = ent->type;
newp->provider = provider;
/* global cache disable */ for (i = 0; i < conf->cachedisable->nelts; i++) { struct cache_disable *ent =
(struct cache_disable *)conf->cachedisable->elts; if (uri_meets_conditions(&ent[i].url, ent[i].pathlen,
&r->parsed_uri, path)) { /* Stop searching now. */ return NULL;
}
}
/* loop through all the per directory cacheenable entries */ for (i = 0; i < dconf->cacheenable->nelts; i++) { struct cache_enable *ent =
(struct cache_enable *)dconf->cacheenable->elts;
providers = get_provider(r, &ent[i], providers);
}
/* loop through all the global cacheenable entries */ for (i = 0; i < conf->cacheenable->nelts; i++) { struct cache_enable *ent =
(struct cache_enable *)conf->cacheenable->elts; if (uri_meets_conditions(&ent[i].url, ent[i].pathlen,
&r->parsed_uri, path)) {
providers = get_provider(r, &ent[i], providers);
}
}
return providers;
}
/* do a HTTP/1.1 age calculation */
CACHE_DECLARE(apr_int64_t) ap_cache_current_age(cache_info *info, const apr_time_t age_value,
apr_time_t now)
{
apr_time_t apparent_age, corrected_received_age, response_delay,
corrected_initial_age, resident_time, current_age,
age_value_usec;
age_value_usec = apr_time_from_sec(age_value);
/* Perform an HTTP/1.1 age calculation. (RFC2616 13.2.3) */
/* This value comes from the client's initial request. */ if (!cache->control_in.parsed) { constchar *cc_req = cache_table_getm(r->pool, r->headers_in, "Cache-Control"); constchar *pragma = cache_table_getm(r->pool, r->headers_in, "Pragma");
ap_cache_control(r, &cache->control_in, cc_req, pragma, r->headers_in);
}
if (cache->control_in.no_cache) {
if (!conf->ignorecachecontrol) { return0;
} else {
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02657) "Incoming request is asking for an uncached version of " "%s, but we have been configured to ignore it and serve " "cached content anyway", r->unparsed_uri);
}
}
return1;
}
int ap_cache_check_no_store(cache_request_rec *cache, request_rec *r)
{
/* This value comes from the client's initial request. */ if (!cache->control_in.parsed) { constchar *cc_req = cache_table_getm(r->pool, r->headers_in, "Cache-Control"); constchar *pragma = cache_table_getm(r->pool, r->headers_in, "Pragma");
ap_cache_control(r, &cache->control_in, cc_req, pragma, r->headers_in);
}
if (cache->control_in.no_store) {
if (!conf->ignorecachecontrol) { /* We're not allowed to serve a cached copy */ return0;
} else {
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02658) "Incoming request is asking for a no-store version of " "%s, but we have been configured to ignore it and serve " "cached content anyway", r->unparsed_uri);
}
}
/* This value comes from the client's initial request. */
cc_req = apr_table_get(r->headers_in, "Cache-Control");
pragma = apr_table_get(r->headers_in, "Pragma");
if (!conf->ignorecachecontrol) { /* Treat as stale, causing revalidation */ return0;
}
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00781) "Incoming request is asking for a uncached version of " "%s, but we have been configured to ignore it and " "serve a cached response anyway",
r->unparsed_uri);
}
/* These come from the cached entity. */ if (h->cache_obj->info.control.no_cache
|| h->cache_obj->info.control.invalidated) { /* *ThecachedentitycontainedCache-Control:no-cache,ora *no-cachewithaheaderpresent,oraprivatewithaheader *present,orthecachedentityhasbeeninvalidatedinthe *past,sotreatasstalecausingrevalidation.
*/ return0;
}
/* Make sure we don't stomp on a previous warning, and don't dup *a113marningthatisalreadypresent.Also,makesuretoadd *thenewwarningtothecorrect*headers_outlocation.
*/ if ((warn_head == NULL) ||
((warn_head != NULL) && (ap_strstr_c(warn_head, "113") == NULL))) {
apr_table_mergen(h->resp_hdrs, "Warning", "113 Heuristic expiration");
}
} return1; /* Cache object is fresh (enough) */
}
/* *Atthispointwearestale,but:ifweareunderload,wemaylet *asignificantnumberofstalerequeststhroughbeforethefirst *stalerequestsuccessfullyrevalidatesitself,causingasudden *unexpectedthunderingherdwhichinturnbringsangstanddrama. * *So. * *Wewantthefirststalerequesttogothroughasnormal.Butthe *secondandsubsequentrequest,wemustpretendtobefreshuntil *thefirstrequestcomesbackwitheithernewcontentorconfirmation *thatthestalecontentisstillfresh. * *Toachievethis,wecreateaverysimplefilebasedlockbasedon *thekeyofthecachedobject.Weattempttoopenthelockfilewith *exclusivewriteaccess.Ifwesucceed,woohoo!we'refirst,andwe *followthestalepathtothebackendserver.Ifwefail,ohwell, *wefollowthefreshpath,andavoidbeingathunderingherd. * *Thelocklivesonlyaslongasthestalerequestthatwentonahead. *Iftherequestsucceeds,thelockisdeleted.Iftherequestfails, *thelockisdeleted,andanotherrequestgetstomakeanewlock *andtryagain. * *Atanytime,arequestmarked"no-cache"willforcearefresh, *ignoringthelock,ensuringanextendedlockoutisimpossible. * *Alockthatexceedsamaximumagewillbedeleted,andanother *requestgetstomakeanewlockandtryagain.
*/
status = cache_try_lock(conf, cache, r); if (APR_SUCCESS == status) { /* we obtained a lock, follow the stale path */
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00782) "Cache lock obtained for stale cached URL, " "revalidating entry: %s",
r->unparsed_uri); return0;
} elseif (APR_STATUS_IS_EEXIST(status)) { /* lock already exists, return stale data anyway, with a warning */
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00783) "Cache already locked for stale cached URL, " "pretend it is fresh: %s",
r->unparsed_uri);
/* make sure we don't stomp on a previous warning */
warn_head = apr_table_get(h->resp_hdrs, "Warning"); if ((warn_head == NULL) ||
((warn_head != NULL) && (ap_strstr_c(warn_head, "110") == NULL))) {
apr_table_mergen(h->resp_hdrs, "Warning", "110 Response is stale");
}
return1;
} else { /* some other error occurred, just treat the object as stale */
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r, APLOGNO(00784) "Attempt to obtain a cache lock for stale " "cached URL failed, revalidating entry anyway: %s",
r->unparsed_uri); return0;
}
}
/* return each comma separated token, one at a time */
CACHE_DECLARE(constchar *)ap_cache_tokstr(apr_pool_t *p, constchar *list, constchar **str)
{
apr_size_t i; constchar *s;
s = ap_strchr_c(list, ','); if (s != NULL) {
i = s - list; do
s++; while (apr_isspace(*s))
; /* noop */
} else
i = strlen(list);
/* Short circuit the common case that there are not *(yet)anyheaderspopulated.
*/ if (t == NULL) { return apr_table_make(pool, 10);
};
/* Make a copy of the headers, and remove from *thecopyanyhop-by-hopheaders,asdefinedinSection *13.5.1ofRFC2616
*/
headers_out = apr_table_copy(pool, t);
/* Remove the user defined headers set with CacheIgnoreHeaders. *ThismaybreakRFC2616complianceonbehalfoftheadministrator.
*/
header = (char **)conf->ignore_headers->elts; for (i = 0; i < conf->ignore_headers->nelts; i++) {
apr_table_unset(headers_out, header[i]);
} return headers_out;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.