static void snprintf_int64(CuTest *tc) { char buf[100]; apr_int64_t i = APR_INT64_C(-42); apr_uint64_t ui = APR_INT64_C(42); /* no APR_UINT64_C */ apr_uint64_t big = APR_INT64_C(3141592653589793238); apr_snprintf(buf, sizeof buf, "%" APR_INT64_T_FMT, i); CuAssertStrEquals(tc, buf, "-42"); apr_snprintf(buf, sizeof buf, "%" APR_UINT64_T_FMT, ui); CuAssertStrEquals(tc, buf, "42"); apr_snprintf(buf, sizeof buf, "%" APR_UINT64_T_FMT, big); CuAssertStrEquals(tc, buf, "3141592653589793238"); }
void log4cxx::helpers::RelativeTimeDateFormat::format( LogString &s, log4cxx_time_t date, Pool& p) const { log4cxx_int64_t interval = (date - startTime) / APR_INT64_C(1000); StringHelper::toString(interval, p, s); }
static void test_insertfile(abts_case *tc, void *ctx) { apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); apr_bucket_brigade *bb; const apr_off_t bignum = (APR_INT64_C(2) << 32) + 424242; apr_off_t count; apr_file_t *f; apr_bucket *e; ABTS_ASSERT(tc, "open test file", apr_file_open(&f, TIF_FNAME, APR_FOPEN_WRITE | APR_FOPEN_TRUNCATE | APR_FOPEN_CREATE | APR_FOPEN_SPARSE, APR_OS_DEFAULT, p) == APR_SUCCESS); if (apr_file_trunc(f, bignum)) { apr_file_close(f); apr_file_remove(TIF_FNAME, p); ABTS_NOT_IMPL(tc, "Skipped: could not create large file"); return; } bb = apr_brigade_create(p, ba); e = apr_brigade_insert_file(bb, f, 0, bignum, p); ABTS_ASSERT(tc, "inserted file was not at end of brigade", e == APR_BRIGADE_LAST(bb)); /* check that the total size of inserted buckets is equal to the * total size of the file. */ count = 0; for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) { ABTS_ASSERT(tc, "bucket size sane", e->length != (apr_size_t)-1); count += e->length; } ABTS_ASSERT(tc, "total size of buckets incorrect", count == bignum); apr_brigade_destroy(bb); /* Truncate the file to zero size before close() so that we don't * actually write out the large file if we are on a non-sparse file * system - like Mac OS X's HFS. Otherwise, pity the poor user who * has to wait for the 8GB file to be written to disk. */ apr_file_trunc(f, 0); apr_file_close(f); apr_bucket_alloc_destroy(ba); apr_file_remove(TIF_FNAME, p); }
static void more_int64_fmts(abts_case *tc, void *data) { char buf[100]; apr_int64_t i = APR_INT64_C(-42); apr_int64_t ibig = APR_INT64_C(-314159265358979323); apr_uint64_t ui = APR_UINT64_C(42); apr_uint64_t big = APR_UINT64_C(3141592653589793238); apr_snprintf(buf, sizeof buf, "%" APR_INT64_T_FMT, i); ABTS_STR_EQUAL(tc, buf, "-42"); apr_snprintf(buf, sizeof buf, "%" APR_UINT64_T_FMT, ui); ABTS_STR_EQUAL(tc, buf, "42"); apr_snprintf(buf, sizeof buf, "%" APR_UINT64_T_FMT, big); ABTS_STR_EQUAL(tc, buf, "3141592653589793238"); apr_snprintf(buf, sizeof buf, "%" APR_INT64_T_FMT, ibig); ABTS_STR_EQUAL(tc, buf, "-314159265358979323"); }
static void string_strtoi64(CuTest *tc) { static const struct { int errnum, base; const char *in, *end; apr_int64_t result; } ts[] = { /* base 10 tests */ { 0, 10, "123545", NULL, APR_INT64_C(123545) }, { 0, 10, " 123545", NULL, APR_INT64_C(123545) }, { 0, 10, " +123545", NULL, APR_INT64_C(123545) }, { 0, 10, "-123545", NULL, APR_INT64_C(-123545) }, { 0, 10, " 00000123545", NULL, APR_INT64_C(123545) }, { 0, 10, "123545ZZZ", "ZZZ", APR_INT64_C(123545) }, { 0, 10, " 123545 ", " ", APR_INT64_C(123545) }, /* base 16 tests */ { 0, 16, "1E299", NULL, APR_INT64_C(123545) }, { 0, 16, "1e299", NULL, APR_INT64_C(123545) }, { 0, 16, "0x1e299", NULL, APR_INT64_C(123545) }, { 0, 16, "0X1E299", NULL, APR_INT64_C(123545) }, { 0, 16, "+1e299", NULL, APR_INT64_C(123545) }, { 0, 16, "-1e299", NULL, APR_INT64_C(-123545) }, { 0, 16, " -1e299", NULL, APR_INT64_C(-123545) }, /* automatic base detection tests */ { 0, 0, "123545", NULL, APR_INT64_C(123545) }, { 0, 0, "0x1e299", NULL, APR_INT64_C(123545) }, { 0, 0, " 0x1e299", NULL, APR_INT64_C(123545) }, { 0, 0, "+0x1e299", NULL, APR_INT64_C(123545) }, { 0, 0, "-0x1e299", NULL, APR_INT64_C(-123545) }, /* large number tests */ { 0, 10, "8589934605", NULL, APR_INT64_C(8589934605) }, { 0, 10, "-8589934605", NULL, APR_INT64_C(-8589934605) }, { 0, 16, "0x20000000D", NULL, APR_INT64_C(8589934605) }, { 0, 16, "-0x20000000D", NULL, APR_INT64_C(-8589934605) }, { 0, 16, " 0x20000000D", NULL, APR_INT64_C(8589934605) }, { 0, 16, " 0x20000000D", NULL, APR_INT64_C(8589934605) }, /* error cases */ { ERANGE, 10, "999999999999999999999999999999999", "", MY_LLONG_MAX }, { ERANGE, 10, "-999999999999999999999999999999999", "", MY_LLONG_MIN }, #if 0 /* C99 doesn't require EINVAL for an invalid range. */ { EINVAL, 99, "", (void *)-1 /* don't care */, 0 }, #endif /* some strtoll implementations give EINVAL when no conversion * is performed. */ { -1 /* don't care */, 10, "zzz", "zzz", APR_INT64_C(0) }, { -1 /* don't care */, 10, "", NULL, APR_INT64_C(0) } }; int n; for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) { char *end = "end ptr not changed"; apr_int64_t result; int errnum; errno = 0; result = apr_strtoi64(ts[n].in, &end, ts[n].base); errnum = errno; CuAssert(tc, apr_psprintf(p, "for '%s': result was %" APR_INT64_T_FMT " not %" APR_INT64_T_FMT, ts[n].in, result, ts[n].result), result == ts[n].result); if (ts[n].errnum != -1) { CuAssert(tc, apr_psprintf(p, "for '%s': errno was %d not %d", ts[n].in, errnum, ts[n].errnum), ts[n].errnum == errnum); } if (ts[n].end == NULL) { /* end must point to NUL terminator of .in */ CuAssertPtrEquals(tc, ts[n].in + strlen(ts[n].in), end); } else if (ts[n].end != (void *)-1) { CuAssert(tc, apr_psprintf(p, "for '%s', end was '%s' not '%s'", ts[n].in, end, ts[n].end), strcmp(ts[n].end, end) == 0); } } }
CACHE_DECLARE(int) ap_cache_check_freshness(cache_handle_t *h, request_rec *r) { apr_int64_t age, maxage_req, maxage_cresp, maxage, smaxage, maxstale; apr_int64_t minfresh; const char *cc_cresp, *cc_req; const char *pragma; const char *agestr = NULL; const char *expstr = NULL; char *val; apr_time_t age_c = 0; cache_info *info = &(h->cache_obj->info); cache_server_conf *conf = (cache_server_conf *)ap_get_module_config(r->server->module_config, &cache_module); /* * We now want to check if our cached data is still fresh. This depends * on a few things, in this order: * * - RFC2616 14.9.4 End to end reload, Cache-Control: no-cache. no-cache in * either the request or the cached response means that we must * revalidate the request unconditionally, overriding any expiration * mechanism. It's equivalent to max-age=0,must-revalidate. * * - RFC2616 14.32 Pragma: no-cache This is treated the same as * Cache-Control: no-cache. * * - RFC2616 14.9.3 Cache-Control: max-stale, must-revalidate, * proxy-revalidate if the max-stale request header exists, modify the * stale calculations below so that an object can be at most <max-stale> * seconds stale before we request a revalidation, _UNLESS_ a * must-revalidate or proxy-revalidate cached response header exists to * stop us doing this. * * - RFC2616 14.9.3 Cache-Control: s-maxage the origin server specifies the * maximum age an object can be before it is considered stale. This * directive has the effect of proxy|must revalidate, which in turn means * simple ignore any max-stale setting. * * - RFC2616 14.9.4 Cache-Control: max-age this header can appear in both * requests and responses. If both are specified, the smaller of the two * takes priority. * * - RFC2616 14.21 Expires: if this request header exists in the cached * entity, and it's value is in the past, it has expired. * */ /* 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 (ap_cache_liststr(NULL, pragma, "no-cache", NULL) || ap_cache_liststr(NULL, cc_req, "no-cache", NULL)) { if (!conf->ignorecachecontrol) { /* Treat as stale, causing revalidation */ return 0; } ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "Incoming request is asking for a uncached version of " "%s, but we know better and are ignoring it", r->unparsed_uri); } /* These come from the cached entity. */ cc_cresp = apr_table_get(h->resp_hdrs, "Cache-Control"); expstr = apr_table_get(h->resp_hdrs, "Expires"); if (ap_cache_liststr(NULL, cc_cresp, "no-cache", NULL)) { /* * The cached entity contained Cache-Control: no-cache, so treat as * stale causing revalidation */ return 0; } if ((agestr = apr_table_get(h->resp_hdrs, "Age"))) { age_c = apr_atoi64(agestr); } /* calculate age of object */ age = ap_cache_current_age(info, age_c, r->request_time); /* extract s-maxage */ if (cc_cresp && ap_cache_liststr(r->pool, cc_cresp, "s-maxage", &val) && val != NULL) { smaxage = apr_atoi64(val); } else { smaxage = -1; } /* extract max-age from request */ if (!conf->ignorecachecontrol && cc_req && ap_cache_liststr(r->pool, cc_req, "max-age", &val) && val != NULL) { maxage_req = apr_atoi64(val); } else { maxage_req = -1; } /* extract max-age from response */ if (cc_cresp && ap_cache_liststr(r->pool, cc_cresp, "max-age", &val) && val != NULL) { maxage_cresp = apr_atoi64(val); } else { maxage_cresp = -1; } /* * if both maxage request and response, the smaller one takes priority */ if (maxage_req == -1) { maxage = maxage_cresp; } else if (maxage_cresp == -1) { maxage = maxage_req; } else { maxage = MIN(maxage_req, maxage_cresp); } /* extract max-stale */ if (cc_req && ap_cache_liststr(r->pool, cc_req, "max-stale", &val)) { if(val != NULL) { maxstale = apr_atoi64(val); } else { /* * If no value is assigned to max-stale, then the client is willing * to accept a stale response of any age (RFC2616 14.9.3). We will * set it to one year in this case as this situation is somewhat * similar to a "never expires" Expires header (RFC2616 14.21) * which is set to a date one year from the time the response is * sent in this case. */ maxstale = APR_INT64_C(86400*365); } } else { maxstale = 0; } /* extract min-fresh */ if (!conf->ignorecachecontrol && cc_req && ap_cache_liststr(r->pool, cc_req, "min-fresh", &val) && val != NULL) { minfresh = apr_atoi64(val); } else { minfresh = 0; } /* override maxstale if must-revalidate or proxy-revalidate */ if (maxstale && ((cc_cresp && ap_cache_liststr(NULL, cc_cresp, "must-revalidate", NULL)) || (cc_cresp && ap_cache_liststr(NULL, cc_cresp, "proxy-revalidate", NULL)))) { maxstale = 0; } /* handle expiration */ if (((smaxage != -1) && (age < (smaxage - minfresh))) || ((maxage != -1) && (age < (maxage + maxstale - minfresh))) || ((smaxage == -1) && (maxage == -1) && (info->expire != APR_DATE_BAD) && (age < (apr_time_sec(info->expire - info->date) + maxstale - minfresh)))) { const char *warn_head; warn_head = apr_table_get(h->resp_hdrs, "Warning"); /* it's fresh darlings... */ /* set age header on response */ apr_table_set(h->resp_hdrs, "Age", apr_psprintf(r->pool, "%lu", (unsigned long)age)); /* add warning if maxstale overrode freshness calculation */ if (!(((smaxage != -1) && age < smaxage) || ((maxage != -1) && age < maxage) || (info->expire != APR_DATE_BAD && (apr_time_sec(info->expire - info->date)) > age))) { /* make sure we don't stomp on a previous warning */ if ((warn_head == NULL) || ((warn_head != NULL) && (ap_strstr_c(warn_head, "110") == NULL))) { apr_table_merge(h->resp_hdrs, "Warning", "110 Response is stale"); } } /* * If none of Expires, Cache-Control: max-age, or Cache-Control: * s-maxage appears in the response, and the respose header age * calculated is more than 24 hours add the warning 113 */ if ((maxage_cresp == -1) && (smaxage == -1) && (expstr == NULL) && (age > 86400)) { /* Make sure we don't stomp on a previous warning, and don't dup * a 113 marning that is already present. Also, make sure to add * the new warning to the correct *headers_out location. */ if ((warn_head == NULL) || ((warn_head != NULL) && (ap_strstr_c(warn_head, "113") == NULL))) { apr_table_merge(h->resp_hdrs, "Warning", "113 Heuristic expiration"); } } return 1; /* Cache object is fresh (enough) */ } return 0; /* Cache object is stale */ }
#include "apr_errno.h" #include "apr_general.h" #include "apr_lib.h" #include "test_apr.h" #include "apr_strings.h" #include <time.h> #define STR_SIZE 45 /* The time value is used throughout the tests, so just make this a global. * Also, we need a single value that we can test for the positive tests, so * I chose the number below, it corresponds to: * 2002-08-14 12:05:36.186711 -25200 [257 Sat]. * Which happens to be when I wrote the new tests. */ static apr_time_t now = APR_INT64_C(1032030336186711); static char* print_time (apr_pool_t *pool, const apr_time_exp_t *xt) { return apr_psprintf (pool, "%04d-%02d-%02d %02d:%02d:%02d.%06d %+05d [%d %s]%s", xt->tm_year + 1900, xt->tm_mon, xt->tm_mday, xt->tm_hour, xt->tm_min, xt->tm_sec, xt->tm_usec, xt->tm_gmtoff, xt->tm_yday + 1, apr_day_snames[xt->tm_wday],
#include "apr_date.h" #ifndef srand48 #define srand48 srandom #endif #ifndef mrand48 #define mrand48 random #endif void gm_timestr_822(char *ts, apr_time_t sec); void gm_timestr_850(char *ts, apr_time_t sec); void gm_timestr_ccc(char *ts, apr_time_t sec); static const apr_time_t year2secs[] = { APR_INT64_C(0), /* 1970 */ APR_INT64_C(31536000), /* 1971 */ APR_INT64_C(63072000), /* 1972 */ APR_INT64_C(94694400), /* 1973 */ APR_INT64_C(126230400), /* 1974 */ APR_INT64_C(157766400), /* 1975 */ APR_INT64_C(189302400), /* 1976 */ APR_INT64_C(220924800), /* 1977 */ APR_INT64_C(252460800), /* 1978 */ APR_INT64_C(283996800), /* 1979 */ APR_INT64_C(315532800), /* 1980 */ APR_INT64_C(347155200), /* 1981 */ APR_INT64_C(378691200), /* 1982 */ APR_INT64_C(410227200), /* 1983 */ APR_INT64_C(441763200), /* 1984 */ APR_INT64_C(473385600), /* 1985 */
int cache_check_freshness(cache_handle_t *h, cache_request_rec *cache, request_rec *r) { apr_status_t status; apr_int64_t age, maxage_req, maxage_cresp, maxage, smaxage, maxstale; apr_int64_t minfresh; const char *cc_req; const char *pragma; const char *agestr = NULL; apr_time_t age_c = 0; cache_info *info = &(h->cache_obj->info); const char *warn_head; cache_server_conf *conf = (cache_server_conf *)ap_get_module_config(r->server->module_config, &cache_module); /* * We now want to check if our cached data is still fresh. This depends * on a few things, in this order: * * - RFC2616 14.9.4 End to end reload, Cache-Control: no-cache. no-cache * in either the request or the cached response means that we must * perform the request unconditionally, and ignore cached content. We * should never reach here, but if we do, mark the content as stale, * as this is the best we can do. * * - RFC2616 14.32 Pragma: no-cache This is treated the same as * Cache-Control: no-cache. * * - RFC2616 14.9.3 Cache-Control: max-stale, must-revalidate, * proxy-revalidate if the max-stale request header exists, modify the * stale calculations below so that an object can be at most <max-stale> * seconds stale before we request a revalidation, _UNLESS_ a * must-revalidate or proxy-revalidate cached response header exists to * stop us doing this. * * - RFC2616 14.9.3 Cache-Control: s-maxage the origin server specifies the * maximum age an object can be before it is considered stale. This * directive has the effect of proxy|must revalidate, which in turn means * simple ignore any max-stale setting. * * - RFC2616 14.9.4 Cache-Control: max-age this header can appear in both * requests and responses. If both are specified, the smaller of the two * takes priority. * * - RFC2616 14.21 Expires: if this request header exists in the cached * entity, and it's value is in the past, it has expired. * */ /* 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"); ap_cache_control(r, &cache->control_in, cc_req, pragma, r->headers_in); if (cache->control_in.no_cache) { if (!conf->ignorecachecontrol) { /* Treat as stale, causing revalidation */ return 0; } 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) { /* * The cached entity contained Cache-Control: no-cache, or a * no-cache with a header present, or a private with a header * present, or the cached entity has been invalidated in the * past, so treat as stale causing revalidation. */ return 0; } if ((agestr = apr_table_get(h->resp_hdrs, "Age"))) { char *endp; apr_off_t offt; if (!apr_strtoff(&offt, agestr, &endp, 10) && endp > agestr && !*endp) { age_c = offt; } } /* calculate age of object */ age = ap_cache_current_age(info, age_c, r->request_time); /* extract s-maxage */ smaxage = h->cache_obj->info.control.s_maxage_value; /* extract max-age from request */ maxage_req = -1; if (!conf->ignorecachecontrol) { maxage_req = cache->control_in.max_age_value; } /* * extract max-age from response, if both s-maxage and max-age, s-maxage * takes priority */ if (smaxage != -1) { maxage_cresp = smaxage; } else { maxage_cresp = h->cache_obj->info.control.max_age_value; } /* * if both maxage request and response, the smaller one takes priority */ if (maxage_req == -1) { maxage = maxage_cresp; } else if (maxage_cresp == -1) { maxage = maxage_req; } else { maxage = MIN(maxage_req, maxage_cresp); } /* extract max-stale */ if (cache->control_in.max_stale) { if(cache->control_in.max_stale_value != -1) { maxstale = cache->control_in.max_stale_value; } else { /* * If no value is assigned to max-stale, then the client is willing * to accept a stale response of any age (RFC2616 14.9.3). We will * set it to one year in this case as this situation is somewhat * similar to a "never expires" Expires header (RFC2616 14.21) * which is set to a date one year from the time the response is * sent in this case. */ maxstale = APR_INT64_C(86400*365); } } else { maxstale = 0; } /* extract min-fresh */ if (!conf->ignorecachecontrol && cache->control_in.min_fresh) { minfresh = cache->control_in.min_fresh_value; } else { minfresh = 0; } /* override maxstale if must-revalidate, proxy-revalidate or s-maxage */ if (maxstale && (h->cache_obj->info.control.must_revalidate || h->cache_obj->info.control.proxy_revalidate || smaxage != -1)) { maxstale = 0; } /* handle expiration */ if (((maxage != -1) && (age < (maxage + maxstale - minfresh))) || ((smaxage == -1) && (maxage == -1) && (info->expire != APR_DATE_BAD) && (age < (apr_time_sec(info->expire - info->date) + maxstale - minfresh)))) { warn_head = apr_table_get(h->resp_hdrs, "Warning"); /* it's fresh darlings... */ /* set age header on response */ apr_table_set(h->resp_hdrs, "Age", apr_psprintf(r->pool, "%lu", (unsigned long)age)); /* add warning if maxstale overrode freshness calculation */ if (!(((maxage != -1) && age < maxage) || (info->expire != APR_DATE_BAD && (apr_time_sec(info->expire - info->date)) > age))) { /* make sure we don't stomp on a previous 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"); } } /* * If none of Expires, Cache-Control: max-age, or Cache-Control: * s-maxage appears in the response, and the response header age * calculated is more than 24 hours add the warning 113 */ if ((maxage_cresp == -1) && (smaxage == -1) && (apr_table_get( h->resp_hdrs, "Expires") == NULL) && (age > 86400)) { /* Make sure we don't stomp on a previous warning, and don't dup * a 113 marning that is already present. Also, make sure to add * the new warning to the correct *headers_out location. */ if ((warn_head == NULL) || ((warn_head != NULL) && (ap_strstr_c(warn_head, "113") == NULL))) { apr_table_mergen(h->resp_hdrs, "Warning", "113 Heuristic expiration"); } } return 1; /* Cache object is fresh (enough) */ } /* * At this point we are stale, but: if we are under load, we may let * a significant number of stale requests through before the first * stale request successfully revalidates itself, causing a sudden * unexpected thundering herd which in turn brings angst and drama. * * So. * * We want the first stale request to go through as normal. But the * second and subsequent request, we must pretend to be fresh until * the first request comes back with either new content or confirmation * that the stale content is still fresh. * * To achieve this, we create a very simple file based lock based on * the key of the cached object. We attempt to open the lock file with * exclusive write access. If we succeed, woohoo! we're first, and we * follow the stale path to the backend server. If we fail, oh well, * we follow the fresh path, and avoid being a thundering herd. * * The lock lives only as long as the stale request that went on ahead. * If the request succeeds, the lock is deleted. If the request fails, * the lock is deleted, and another request gets to make a new lock * and try again. * * At any time, a request marked "no-cache" will force a refresh, * ignoring the lock, ensuring an extended lockout is impossible. * * A lock that exceeds a maximum age will be deleted, and another * request gets to make a new lock and try again. */ 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); return 0; } else if (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"); } return 1; } 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); return 0; } }