cache_util.c revision e659202cdee59ca56484d1e0d0d7d68864fc60ca
842ae4bd224140319ae7feec1872b93dfd491143fielding/* Licensed to the Apache Software Foundation (ASF) under one or more
842ae4bd224140319ae7feec1872b93dfd491143fielding * contributor license agreements. See the NOTICE file distributed with
842ae4bd224140319ae7feec1872b93dfd491143fielding * this work for additional information regarding copyright ownership.
842ae4bd224140319ae7feec1872b93dfd491143fielding * The ASF licenses this file to You under the Apache License, Version 2.0
842ae4bd224140319ae7feec1872b93dfd491143fielding * (the "License"); you may not use this file except in compliance with
842ae4bd224140319ae7feec1872b93dfd491143fielding * the License. You may obtain a copy of the License at
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * http://www.apache.org/licenses/LICENSE-2.0
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Unless required by applicable law or agreed to in writing, software
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * distributed under the License is distributed on an "AS IS" BASIS,
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * See the License for the specific language governing permissions and
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * limitations under the License.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include "mod_cache.h"
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding#include <ap_provider.h>
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/* -------------------------------------------------------------- */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingextern APR_OPTIONAL_FN_TYPE(ap_cache_generate_key) *cache_generate_key;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
dc80439e9fba60c753cd145cb6799409ffea9b71ronaldextern module AP_MODULE_DECLARE_DATA cache_module;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
dc80439e9fba60c753cd145cb6799409ffea9b71ronald/* Determine if "url" matches the hostname, scheme and port and path
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * in "filter". All but the path comparisons are case-insensitive.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic int uri_meets_conditions(apr_uri_t filter, int pathlen, apr_uri_t url)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* Compare the hostnames */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if(filter.hostname) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!url.hostname) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else if (strcasecmp(filter.hostname, url.hostname)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
dc80439e9fba60c753cd145cb6799409ffea9b71ronald /* Compare the schemes */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if(filter.scheme) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!url.scheme) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald return 0;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald else if (strcasecmp(filter.scheme, url.scheme)) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald return 0;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
dc80439e9fba60c753cd145cb6799409ffea9b71ronald /* Compare the ports */
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if(filter.port_str) {
e8f95a682820a599fe41b22977010636be5c2717jim if (url.port_str && filter.port != url.port) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe /* NOTE: ap_port_of_scheme will return 0 if given NULL input */
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe else if (filter.port != apr_uri_port_of_scheme(url.scheme)) {
694e8dc146faadc46b2455f3bd0998121fc76c5drbb return 0;
c7d0205ec1649076e7742d72a25ac53779768312stoddard }
c7d0205ec1649076e7742d72a25ac53779768312stoddard }
29c30db45f6a469017e16b606611e460cc1a1f2caaron else if(url.port_str && filter.scheme) {
032b8a34c3911bbc5ad5385ca40af65af273bff9wrowe if (apr_uri_port_of_scheme(filter.scheme) == url.port) {
e33b627b40578d0166fdb79ce0487f9e46586befgstein return 0;
cd9f429ff62d134cdf6ec903c33430c5ebae12f0trawick }
cd9f429ff62d134cdf6ec903c33430c5ebae12f0trawick }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
e33b627b40578d0166fdb79ce0487f9e46586befgstein /* For HTTP caching purposes, an empty (NULL) path is equivalent to
e33b627b40578d0166fdb79ce0487f9e46586befgstein * a single "/" path. RFCs 3986/2396
e33b627b40578d0166fdb79ce0487f9e46586befgstein */
e33b627b40578d0166fdb79ce0487f9e46586befgstein if (!url.path) {
e33b627b40578d0166fdb79ce0487f9e46586befgstein if (*filter.path == '/' && pathlen == 1) {
e33b627b40578d0166fdb79ce0487f9e46586befgstein return 1;
e33b627b40578d0166fdb79ce0487f9e46586befgstein }
864c5615d55b8ebbde24e72043f6325741335a74fielding else {
e33b627b40578d0166fdb79ce0487f9e46586befgstein return 0;
26dfa083a1662d57ba7cc410eec4e0696b9be469wrowe }
26dfa083a1662d57ba7cc410eec4e0696b9be469wrowe }
e9f8410b788ef1e6f1baed6c706ffdf3da395a16jerenkrantz
e33b627b40578d0166fdb79ce0487f9e46586befgstein /* Url has met all of the filter conditions so far, determine
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz * if the paths match.
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz */
97d20d37d21b8d427a920e211858172f0a82427epoirier return !strncmp(filter.path, url.path, pathlen);
97d20d37d21b8d427a920e211858172f0a82427epoirier}
97d20d37d21b8d427a920e211858172f0a82427epoirier
8ec8f1c8f0f37ca3f5ebb0e0b491dd07481dccbfronaldCACHE_DECLARE(cache_provider_list *)ap_cache_get_providers(request_rec *r,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding cache_server_conf *conf,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_uri_t uri)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding cache_provider_list *providers = NULL;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz int i;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
9db34d31d4df0b29d128ecd724cd177905108b0frbb /* loop through all the cacheenable entries */
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe for (i = 0; i < conf->cacheenable->nelts; i++) {
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm struct cache_enable *ent =
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (struct cache_enable *)conf->cacheenable->elts;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (uri_meets_conditions(ent[i].url, ent[i].pathlen, uri)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* Fetch from global config and add to the list. */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding cache_provider *provider;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding provider = ap_lookup_provider(CACHE_PROVIDER_GROUP, ent[i].type,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "0");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!provider) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* Log an error! */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else {
e0fe4de2016336428729a620ac0034cd1198ad7awrowe cache_provider_list *newp;
e0fe4de2016336428729a620ac0034cd1198ad7awrowe newp = apr_pcalloc(r->pool, sizeof(cache_provider_list));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding newp->provider_name = ent[i].type;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding newp->provider = provider;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!providers) {
ec486beb201583aafddf7c7ee9009727a3ade0aafielding providers = newp;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding cache_provider_list *last = providers;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding while (last->next) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding last = last->next;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron last->next = newp;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
d0ba3b97557d47323bd055fb4002ed7692f703b9jerenkrantz }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* then loop through all the cachedisable entries
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Looking for urls that contain the full cachedisable url and possibly
dc80439e9fba60c753cd145cb6799409ffea9b71ronald * more.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * This means we are disabling cachedisable url and below...
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (i = 0; i < conf->cachedisable->nelts; i++) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding struct cache_disable *ent =
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (struct cache_disable *)conf->cachedisable->elts;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (uri_meets_conditions(ent[i].url, ent[i].pathlen, uri)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* Stop searching now. */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return providers;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/* do a HTTP/1.1 age calculation */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingCACHE_DECLARE(apr_int64_t) ap_cache_current_age(cache_info *info,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const apr_time_t age_value,
7ddfd45e4d3d13de264931df8eb27ee7619fdb0ejerenkrantz apr_time_t now)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_time_t apparent_age, corrected_received_age, response_delay,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding corrected_initial_age, resident_time, current_age,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding age_value_usec;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding age_value_usec = apr_time_from_sec(age_value);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* Perform an HTTP/1.1 age calculation. (RFC2616 13.2.3) */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apparent_age = MAX(0, info->response_time - info->date);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald corrected_received_age = MAX(apparent_age, age_value_usec);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron response_delay = info->response_time - info->request_time;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding corrected_initial_age = corrected_received_age + response_delay;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding resident_time = now - info->response_time;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding current_age = corrected_initial_age + resident_time;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_time_sec(current_age);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/**
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * Try obtain a cache wide lock on the given cache key.
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm *
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * If we return APR_SUCCESS, we obtained the lock, and we are clear to
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * proceed to the backend. If we return APR_EEXISTS, then the lock is
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * already locked, someone else has gone to refresh the backend data
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * already, so we must return stale data with a warning in the mean
dc80439e9fba60c753cd145cb6799409ffea9b71ronald * time. If we return anything else, then something has gone pear
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * shaped, and we allow the request through to the backend regardless.
26dfa083a1662d57ba7cc410eec4e0696b9be469wrowe *
26dfa083a1662d57ba7cc410eec4e0696b9be469wrowe * This lock is created from the request pool, meaning that should
26dfa083a1662d57ba7cc410eec4e0696b9be469wrowe * something go wrong and the lock isn't deleted on return of the
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * request headers from the backend for whatever reason, at worst the
29c30db45f6a469017e16b606611e460cc1a1f2caaron * lock will be cleaned up when the request dies or finishes.
29c30db45f6a469017e16b606611e460cc1a1f2caaron *
97d20d37d21b8d427a920e211858172f0a82427epoirier * If something goes truly bananas and the lock isn't deleted when the
97d20d37d21b8d427a920e211858172f0a82427epoirier * request dies, the lock will be trashed when its max-age is reached,
97d20d37d21b8d427a920e211858172f0a82427epoirier * or when a request arrives containing a Cache-Control: no-cache. At
dc80439e9fba60c753cd145cb6799409ffea9b71ronald * no point is it possible for this lock to permanently deny access to
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * the backend.
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronCACHE_DECLARE(apr_status_t) ap_cache_try_lock(cache_server_conf *conf,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding request_rec *r, char *key) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald apr_status_t status;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald const char *lockname;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *path;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding char dir[5];
138c8f7cb8254e035c6f45288e3909cd9c21be5cmartin apr_time_t now = apr_time_now();
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_finfo_t finfo;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding finfo.mtime = 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_file_t *lockfile;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding void *dummy;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm if (!conf || !conf->lock || !conf->lockpath) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* no locks configured, leave */
e8f95a682820a599fe41b22977010636be5c2717jim return APR_SUCCESS;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* lock already obtained earlier? if so, success */
97d20d37d21b8d427a920e211858172f0a82427epoirier apr_pool_userdata_get(&dummy, CACHE_LOCKFILE_KEY, r->pool);
97d20d37d21b8d427a920e211858172f0a82427epoirier if (dummy) {
97d20d37d21b8d427a920e211858172f0a82427epoirier return APR_SUCCESS;
97d20d37d21b8d427a920e211858172f0a82427epoirier }
97d20d37d21b8d427a920e211858172f0a82427epoirier
dc80439e9fba60c753cd145cb6799409ffea9b71ronald /* create the key if it doesn't exist */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!key) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron cache_generate_key(r, r->pool, &key);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
dc80439e9fba60c753cd145cb6799409ffea9b71ronald /* create a hashed filename from the key, and save it for later */
29c30db45f6a469017e16b606611e460cc1a1f2caaron lockname = ap_cache_generate_name(r->pool, 0, 0, key);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* lock files represent discrete just-went-stale URLs "in flight", so
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * we support a simple two level directory structure, more is overkill.
dc80439e9fba60c753cd145cb6799409ffea9b71ronald */
29c30db45f6a469017e16b606611e460cc1a1f2caaron dir[0] = '/';
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron dir[1] = lockname[0];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding dir[2] = '/';
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald dir[3] = lockname[1];
d0a225bdac006f3361e80bfc1be7e6f9b0e81f80ronald dir[4] = 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* make the directories */
e1753aabf5df187b5b04e72a958af4b65b1a125daaron path = apr_pstrcat(r->pool, conf->lockpath, dir, NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (APR_SUCCESS != (status = apr_dir_make_recursive(path,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm APR_UREAD|APR_UWRITE|APR_UEXECUTE, r->pool))) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
12901074f5d6b36d08be84d8637b6f2c21e0da26trawick "Could not create a cache lock directory: %s",
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron path);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return status;
afd0a335375c636605c8625b0d5755dd2408be2btrawick }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm lockname = apr_pstrcat(r->pool, path, "/", lockname, NULL);
afd0a335375c636605c8625b0d5755dd2408be2btrawick apr_pool_userdata_set(lockname, CACHE_LOCKNAME_KEY, NULL, r->pool);
afd0a335375c636605c8625b0d5755dd2408be2btrawick
afd0a335375c636605c8625b0d5755dd2408be2btrawick /* is an existing lock file too old? */
c7d0205ec1649076e7742d72a25ac53779768312stoddard status = apr_stat(&finfo, lockname,
e1753aabf5df187b5b04e72a958af4b65b1a125daaron APR_FINFO_MTIME | APR_FINFO_NLINK, r->pool);
e4c4fcc82268e0192db234c74a6db784b879fffdrbb if (!APR_STATUS_IS_ENOENT(status) && APR_SUCCESS != status) {
9d75c00eea5e840de5ab662f1163014932d9ee78wrowe ap_log_error(APLOG_MARK, APLOG_ERR, APR_EEXIST, r->server,
e8f95a682820a599fe41b22977010636be5c2717jim "Could not stat a cache lock file: %s",
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron lockname);
e1753aabf5df187b5b04e72a958af4b65b1a125daaron return status;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (APR_SUCCESS == status && ((now - finfo.mtime) > conf->lockmaxage)
12901074f5d6b36d08be84d8637b6f2c21e0da26trawick || (now < finfo.mtime)) {
e1753aabf5df187b5b04e72a958af4b65b1a125daaron ap_log_error(APLOG_MARK, APLOG_INFO, status, r->server,
e1753aabf5df187b5b04e72a958af4b65b1a125daaron "Cache lock file for '%s' too old, removing: %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->uri, lockname);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_file_remove(lockname, r->pool);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
dc80439e9fba60c753cd145cb6799409ffea9b71ronald /* try obtain a lock on the file */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (APR_SUCCESS == (status = apr_file_open(&lockfile, lockname,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron APR_WRITE | APR_CREATE | APR_EXCL | APR_DELONCLOSE,
dc80439e9fba60c753cd145cb6799409ffea9b71ronald APR_UREAD | APR_UWRITE, r->pool))) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald apr_pool_userdata_set(lockfile, CACHE_LOCKFILE_KEY, NULL, r->pool);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald return status;
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein}
97d20d37d21b8d427a920e211858172f0a82427epoirier
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/**
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Remove the cache lock, if present.
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm *
97d20d37d21b8d427a920e211858172f0a82427epoirier * First, try to close the file handle, whose delete-on-close should
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * kill the file. Otherwise, just delete the file by name.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * If no lock name has yet been calculated, do the calculation of the
97d20d37d21b8d427a920e211858172f0a82427epoirier * lock name first before trying to delete the file.
97d20d37d21b8d427a920e211858172f0a82427epoirier *
97d20d37d21b8d427a920e211858172f0a82427epoirier * If an optional bucket brigade is passed, the lock will only be
97d20d37d21b8d427a920e211858172f0a82427epoirier * removed if the bucket brigade contains an EOS bucket.
97d20d37d21b8d427a920e211858172f0a82427epoirier */
97d20d37d21b8d427a920e211858172f0a82427epoirierCACHE_DECLARE(apr_status_t) ap_cache_remove_lock(cache_server_conf *conf,
97d20d37d21b8d427a920e211858172f0a82427epoirier request_rec *r, char *key, apr_bucket_brigade *bb) {
97d20d37d21b8d427a920e211858172f0a82427epoirier void *dummy;
97d20d37d21b8d427a920e211858172f0a82427epoirier const char *lockname;
97d20d37d21b8d427a920e211858172f0a82427epoirier
97d20d37d21b8d427a920e211858172f0a82427epoirier if (!conf || !conf->lock || !conf->lockpath) {
97d20d37d21b8d427a920e211858172f0a82427epoirier /* no locks configured, leave */
97d20d37d21b8d427a920e211858172f0a82427epoirier return APR_SUCCESS;
97d20d37d21b8d427a920e211858172f0a82427epoirier }
97d20d37d21b8d427a920e211858172f0a82427epoirier if (bb) {
97d20d37d21b8d427a920e211858172f0a82427epoirier apr_bucket *e;
97d20d37d21b8d427a920e211858172f0a82427epoirier int eos_found = 0;
97d20d37d21b8d427a920e211858172f0a82427epoirier for (e = APR_BRIGADE_FIRST(bb);
97d20d37d21b8d427a920e211858172f0a82427epoirier e != APR_BRIGADE_SENTINEL(bb);
97d20d37d21b8d427a920e211858172f0a82427epoirier e = APR_BUCKET_NEXT(e))
97d20d37d21b8d427a920e211858172f0a82427epoirier {
97d20d37d21b8d427a920e211858172f0a82427epoirier if (APR_BUCKET_IS_EOS(e)) {
97d20d37d21b8d427a920e211858172f0a82427epoirier eos_found = 1;
97d20d37d21b8d427a920e211858172f0a82427epoirier break;
97d20d37d21b8d427a920e211858172f0a82427epoirier }
97d20d37d21b8d427a920e211858172f0a82427epoirier }
97d20d37d21b8d427a920e211858172f0a82427epoirier if (!eos_found) {
97d20d37d21b8d427a920e211858172f0a82427epoirier /* no eos found in brigade, don't delete anything just yet,
97d20d37d21b8d427a920e211858172f0a82427epoirier * we are not done.
97d20d37d21b8d427a920e211858172f0a82427epoirier */
97d20d37d21b8d427a920e211858172f0a82427epoirier return APR_SUCCESS;
97d20d37d21b8d427a920e211858172f0a82427epoirier }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
97d20d37d21b8d427a920e211858172f0a82427epoirier apr_pool_userdata_get(&dummy, CACHE_LOCKFILE_KEY, r->pool);
97d20d37d21b8d427a920e211858172f0a82427epoirier if (dummy) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald return apr_file_close((apr_file_t *)dummy);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
97d20d37d21b8d427a920e211858172f0a82427epoirier apr_pool_userdata_get(&dummy, CACHE_LOCKNAME_KEY, r->pool);
97d20d37d21b8d427a920e211858172f0a82427epoirier lockname = (const char *)dummy;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if (!lockname) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron const char *path;
97d20d37d21b8d427a920e211858172f0a82427epoirier char dir[5];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* create the key if it doesn't exist */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!key) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron cache_generate_key(r, r->pool, &key);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* create a hashed filename from the key, and save it for later */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding lockname = ap_cache_generate_name(r->pool, 0, 0, key);
97d20d37d21b8d427a920e211858172f0a82427epoirier
97d20d37d21b8d427a920e211858172f0a82427epoirier /* lock files represent discrete just-went-stale URLs "in flight", so
29c30db45f6a469017e16b606611e460cc1a1f2caaron * we support a simple two level directory structure, more is overkill.
29c30db45f6a469017e16b606611e460cc1a1f2caaron */
29c30db45f6a469017e16b606611e460cc1a1f2caaron dir[0] = '/';
29c30db45f6a469017e16b606611e460cc1a1f2caaron dir[1] = lockname[0];
dc80439e9fba60c753cd145cb6799409ffea9b71ronald dir[2] = '/';
29c30db45f6a469017e16b606611e460cc1a1f2caaron dir[3] = lockname[1];
97d20d37d21b8d427a920e211858172f0a82427epoirier dir[4] = 0;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
dc80439e9fba60c753cd145cb6799409ffea9b71ronald lockname = apr_pstrcat(r->pool, conf->lockpath, dir, "/", lockname, NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_file_remove(lockname, r->pool);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
97d20d37d21b8d427a920e211858172f0a82427epoirier
dc80439e9fba60c753cd145cb6799409ffea9b71ronaldCACHE_DECLARE(int) ap_cache_check_freshness(cache_handle_t *h,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron request_rec *r)
97d20d37d21b8d427a920e211858172f0a82427epoirier{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_status_t status;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_int64_t age, maxage_req, maxage_cresp, maxage, smaxage, maxstale;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_int64_t minfresh;
97d20d37d21b8d427a920e211858172f0a82427epoirier const char *cc_cresp, *cc_req;
97d20d37d21b8d427a920e211858172f0a82427epoirier const char *pragma;
97d20d37d21b8d427a920e211858172f0a82427epoirier const char *agestr = NULL;
29c30db45f6a469017e16b606611e460cc1a1f2caaron const char *expstr = NULL;
29c30db45f6a469017e16b606611e460cc1a1f2caaron char *val;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald apr_time_t age_c = 0;
29c30db45f6a469017e16b606611e460cc1a1f2caaron cache_info *info = &(h->cache_obj->info);
97d20d37d21b8d427a920e211858172f0a82427epoirier cache_server_conf *conf =
dc80439e9fba60c753cd145cb6799409ffea9b71ronald (cache_server_conf *)ap_get_module_config(r->server->module_config,
dc80439e9fba60c753cd145cb6799409ffea9b71ronald &cache_module);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * We now want to check if our cached data is still fresh. This depends
97d20d37d21b8d427a920e211858172f0a82427epoirier * on a few things, in this order:
dc80439e9fba60c753cd145cb6799409ffea9b71ronald *
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * - RFC2616 14.9.4 End to end reload, Cache-Control: no-cache. no-cache in
97d20d37d21b8d427a920e211858172f0a82427epoirier * either the request or the cached response means that we must
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * revalidate the request unconditionally, overriding any expiration
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * mechanism. It's equivalent to max-age=0,must-revalidate.
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron *
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * - RFC2616 14.32 Pragma: no-cache This is treated the same as
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Cache-Control: no-cache.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *
97d20d37d21b8d427a920e211858172f0a82427epoirier * - RFC2616 14.9.3 Cache-Control: max-stale, must-revalidate,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * proxy-revalidate if the max-stale request header exists, modify the
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * stale calculations below so that an object can be at most <max-stale>
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein * seconds stale before we request a revalidation, _UNLESS_ a
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein * must-revalidate or proxy-revalidate cached response header exists to
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein * stop us doing this.
9d0665da83d1e22c0ea0e5f6f940f70f75bf5237ianh *
e1753aabf5df187b5b04e72a958af4b65b1a125daaron * - RFC2616 14.9.3 Cache-Control: s-maxage the origin server specifies the
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * maximum age an object can be before it is considered stale. This
e1753aabf5df187b5b04e72a958af4b65b1a125daaron * directive has the effect of proxy|must revalidate, which in turn means
e1753aabf5df187b5b04e72a958af4b65b1a125daaron * simple ignore any max-stale setting.
e1753aabf5df187b5b04e72a958af4b65b1a125daaron *
e1753aabf5df187b5b04e72a958af4b65b1a125daaron * - RFC2616 14.9.4 Cache-Control: max-age this header can appear in both
e1753aabf5df187b5b04e72a958af4b65b1a125daaron * requests and responses. If both are specified, the smaller of the two
e1753aabf5df187b5b04e72a958af4b65b1a125daaron * takes priority.
e1753aabf5df187b5b04e72a958af4b65b1a125daaron *
e1753aabf5df187b5b04e72a958af4b65b1a125daaron * - RFC2616 14.21 Expires: if this request header exists in the cached
03a0fe8ed13b5883d43e40ad99c877a24cb97bfbbnicholes * entity, and it's value is in the past, it has expired.
e1753aabf5df187b5b04e72a958af4b65b1a125daaron *
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
e1753aabf5df187b5b04e72a958af4b65b1a125daaron /* This value comes from the client's initial request. */
e1753aabf5df187b5b04e72a958af4b65b1a125daaron cc_req = apr_table_get(r->headers_in, "Cache-Control");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron pragma = apr_table_get(r->headers_in, "Pragma");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if (ap_cache_liststr(NULL, pragma, "no-cache", NULL)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding || ap_cache_liststr(NULL, cc_req, "no-cache", NULL)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!conf->ignorecachecontrol) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* Treat as stale, causing revalidation */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return 0;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "Incoming request is asking for a uncached version of "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "%s, but we know better and are ignoring it",
97d20d37d21b8d427a920e211858172f0a82427epoirier r->unparsed_uri);
97d20d37d21b8d427a920e211858172f0a82427epoirier }
97d20d37d21b8d427a920e211858172f0a82427epoirier
97d20d37d21b8d427a920e211858172f0a82427epoirier /* These come from the cached entity. */
066877f1a045103acfdd376d48cdd473c33f409bdougm cc_cresp = apr_table_get(h->resp_hdrs, "Cache-Control");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron expstr = apr_table_get(h->resp_hdrs, "Expires");
9d0665da83d1e22c0ea0e5f6f940f70f75bf5237ianh
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (ap_cache_liststr(NULL, cc_cresp, "no-cache", NULL)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /*
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * The cached entity contained Cache-Control: no-cache, so treat as
dc80439e9fba60c753cd145cb6799409ffea9b71ronald * stale causing revalidation
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm */
dc80439e9fba60c753cd145cb6799409ffea9b71ronald return 0;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if ((agestr = apr_table_get(h->resp_hdrs, "Age"))) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald age_c = apr_atoi64(agestr);
97d20d37d21b8d427a920e211858172f0a82427epoirier }
97d20d37d21b8d427a920e211858172f0a82427epoirier
97d20d37d21b8d427a920e211858172f0a82427epoirier /* calculate age of object */
97d20d37d21b8d427a920e211858172f0a82427epoirier age = ap_cache_current_age(info, age_c, r->request_time);
97d20d37d21b8d427a920e211858172f0a82427epoirier
97d20d37d21b8d427a920e211858172f0a82427epoirier /* extract s-maxage */
97d20d37d21b8d427a920e211858172f0a82427epoirier if (cc_cresp && ap_cache_liststr(r->pool, cc_cresp, "s-maxage", &val)
97d20d37d21b8d427a920e211858172f0a82427epoirier && val != NULL) {
97d20d37d21b8d427a920e211858172f0a82427epoirier smaxage = apr_atoi64(val);
97d20d37d21b8d427a920e211858172f0a82427epoirier }
29c30db45f6a469017e16b606611e460cc1a1f2caaron else {
29c30db45f6a469017e16b606611e460cc1a1f2caaron smaxage = -1;
29c30db45f6a469017e16b606611e460cc1a1f2caaron }
29c30db45f6a469017e16b606611e460cc1a1f2caaron
29c30db45f6a469017e16b606611e460cc1a1f2caaron /* extract max-age from request */
29c30db45f6a469017e16b606611e460cc1a1f2caaron if (!conf->ignorecachecontrol
29c30db45f6a469017e16b606611e460cc1a1f2caaron && cc_req && ap_cache_liststr(r->pool, cc_req, "max-age", &val)
29c30db45f6a469017e16b606611e460cc1a1f2caaron && val != NULL) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron maxage_req = apr_atoi64(val);
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding maxage_req = -1;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* extract max-age from response */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (cc_cresp && ap_cache_liststr(r->pool, cc_cresp, "max-age", &val)
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm && val != NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding maxage_cresp = apr_atoi64(val);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron maxage_cresp = -1;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /*
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * if both maxage request and response, the smaller one takes priority
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (maxage_req == -1) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron maxage = maxage_cresp;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron else if (maxage_cresp == -1) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron maxage = maxage_req;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding maxage = MIN(maxage_req, maxage_cresp);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* extract max-stale */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (cc_req && ap_cache_liststr(r->pool, cc_req, "max-stale", &val)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if(val != NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding maxstale = apr_atoi64(val);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * If no value is assigned to max-stale, then the client is willing
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * to accept a stale response of any age (RFC2616 14.9.3). We will
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * set it to one year in this case as this situation is somewhat
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * similar to a "never expires" Expires header (RFC2616 14.21)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * which is set to a date one year from the time the response is
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * sent in this case.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding maxstale = APR_INT64_C(86400*365);
066877f1a045103acfdd376d48cdd473c33f409bdougm }
066877f1a045103acfdd376d48cdd473c33f409bdougm }
066877f1a045103acfdd376d48cdd473c33f409bdougm else {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron maxstale = 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* extract min-fresh */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!conf->ignorecachecontrol
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz && cc_req && ap_cache_liststr(r->pool, cc_req, "min-fresh", &val)
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz && val != NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding minfresh = apr_atoi64(val);
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz }
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz else {
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz minfresh = 0;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz }
941fcca87a4607a388e88cff3fd0cdefc29bb81cjerenkrantz
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz /* override maxstale if must-revalidate or proxy-revalidate */
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz if (maxstale && ((cc_cresp &&
e9f8410b788ef1e6f1baed6c706ffdf3da395a16jerenkrantz ap_cache_liststr(NULL, cc_cresp,
2e242dca7111f99d54dd144b7b8418d88d560032chrisd "must-revalidate", NULL)) ||
2e242dca7111f99d54dd144b7b8418d88d560032chrisd (cc_cresp &&
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz ap_cache_liststr(NULL, cc_cresp,
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz "proxy-revalidate", NULL)))) {
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz maxstale = 0;
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz }
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz /* handle expiration */
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz if (((smaxage != -1) && (age < (smaxage - minfresh))) ||
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz ((maxage != -1) && (age < (maxage + maxstale - minfresh))) ||
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz ((smaxage == -1) && (maxage == -1) &&
75031befec2825183c13931fc3266b56ed575c3dcovener (info->expire != APR_DATE_BAD) &&
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez (age < (apr_time_sec(info->expire - info->date) + maxstale - minfresh)))) {
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez const char *warn_head;
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez
941fcca87a4607a388e88cff3fd0cdefc29bb81cjerenkrantz warn_head = apr_table_get(h->resp_hdrs, "Warning");
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez
6e45872b4a23d493887830d82a2759b4c00b10b2wsanchez /* it's fresh darlings... */
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz /* set age header on response */
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz apr_table_set(h->resp_hdrs, "Age",
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz apr_psprintf(r->pool, "%lu", (unsigned long)age));
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz /* add warning if maxstale overrode freshness calculation */
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz if (!(((smaxage != -1) && age < smaxage) ||
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz ((maxage != -1) && age < maxage) ||
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz (info->expire != APR_DATE_BAD &&
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz (apr_time_sec(info->expire - info->date)) > age))) {
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz /* make sure we don't stomp on a previous warning */
bdfba727693ab86e9914ca90af68e62896946755jerenkrantz if ((warn_head == NULL) ||
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz ((warn_head != NULL) && (ap_strstr_c(warn_head, "110") == NULL))) {
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz apr_table_merge(h->resp_hdrs, "Warning",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "110 Response is stale");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * If none of Expires, Cache-Control: max-age, or Cache-Control:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * s-maxage appears in the response, and the response header age
54062d8f070826e448822c315895f1ea2b9414adwrowe * calculated is more than 24 hours add the warning 113
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((maxage_cresp == -1) && (smaxage == -1) &&
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding (expstr == NULL) && (age > 86400)) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron /* Make sure we don't stomp on a previous warning, and don't dup
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * a 113 marning that is already present. Also, make sure to add
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * the new warning to the correct *headers_out location.
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if ((warn_head == NULL) ||
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron ((warn_head != NULL) && (ap_strstr_c(warn_head, "113") == NULL))) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron apr_table_merge(h->resp_hdrs, "Warning",
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron "113 Heuristic expiration");
44a02fb58380bb801585f586ad3c7569de11840dpoirier }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return 1; /* Cache object is fresh (enough) */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron /*
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * At this point we are stale, but: if we are under load, we may let
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * a significant number of stale requests through before the first
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * stale request successfully revalidates itself, causing a sudden
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * unexpected thundering herd which in turn brings angst and drama.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * So.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * We want the first stale request to go through as normal. But the
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * second and subsequent request, we must pretend to be fresh until
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * the first request comes back with either new content or confirmation
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * that the stale content is still fresh.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * To achieve this, we create a very simple file based lock based on
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * the key of the cached object. We attempt to open the lock file with
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * exclusive write access. If we succeed, woohoo! we're first, and we
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * follow the stale path to the backend server. If we fail, oh well,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * we follow the fresh path, and avoid being a thundering herd.
dc80439e9fba60c753cd145cb6799409ffea9b71ronald *
e8f95a682820a599fe41b22977010636be5c2717jim * The lock lives only as long as the stale request that went on ahead.
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * If the request succeeds, the lock is deleted. If the request fails,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * the lock is deleted, and another request gets to make a new lock
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * and try again.
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron *
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * At any time, a request marked "no-cache" will force a refresh,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * ignoring the lock, ensuring an extended lockout is impossible.
e0fe4de2016336428729a620ac0034cd1198ad7awrowe *
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * A lock that exceeds a maximum age will be deleted, and another
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * request gets to make a new lock and try again.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding status = ap_cache_try_lock(conf, r, (char *)h->cache_obj->key);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (APR_SUCCESS == status) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* we obtained a lock, follow the stale path */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "Cache lock obtained for stale cached URL, "
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "revalidating entry: %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->unparsed_uri);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return 0;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
ac2eb54bac2d978c323ab346161b8591d134100cpoirier else if (APR_EEXIST == status) {
12901074f5d6b36d08be84d8637b6f2c21e0da26trawick /* lock already exists, return stale data anyway, with a warning */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron "Cache already locked for stale cached URL, "
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron "pretend it is fresh: %s",
ac2eb54bac2d978c323ab346161b8591d134100cpoirier r->unparsed_uri);
ac2eb54bac2d978c323ab346161b8591d134100cpoirier apr_table_merge(h->resp_hdrs, "Warning",
dc80439e9fba60c753cd145cb6799409ffea9b71ronald "110 Response is stale");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return 1;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* some other error occurred, just treat the object as stale */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_log_error(APLOG_MARK, APLOG_DEBUG, status, r->server,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "Attempt to obtain a cache lock for stale "
dc80439e9fba60c753cd145cb6799409ffea9b71ronald "cached URL failed, revalidating entry anyway: %s",
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron r->unparsed_uri);
12901074f5d6b36d08be84d8637b6f2c21e0da26trawick return 0;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron/*
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * list is a comma-separated list of case-insensitive tokens, with
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * optional whitespace around the tokens.
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * The return returns 1 if the token val is found in the list, or 0
dc80439e9fba60c753cd145cb6799409ffea9b71ronald * otherwise.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingCACHE_DECLARE(int) ap_cache_liststr(apr_pool_t *p, const char *list,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *key, char **val)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_size_t key_len;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *next;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!list) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return 0;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron key_len = strlen(key);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron next = list;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (;;) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* skip whitespace and commas to find the start of the next key */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding while (*next && (apr_isspace(*next) || (*next == ','))) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald next++;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if (!*next) {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald return 0;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
e8f95a682820a599fe41b22977010636be5c2717jim
10a4cdd68ef1ca0e54af296fe1d08ac00150c90bwrowe if (!strncasecmp(next, key, key_len)) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron /* this field matches the key (though it might just be
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * a prefix match, so make sure the match is followed
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * by either a space or an equals sign)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron next += key_len;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!*next || (*next == '=') || apr_isspace(*next) ||
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron (*next == ',')) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron /* valid match */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (val) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron while (*next && (*next != '=') && (*next != ',')) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron next++;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (*next == '=') {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald next++;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald while (*next && apr_isspace(*next )) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron next++;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron if (!*next) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron *val = NULL;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald else {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald const char *val_start = next;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron while (*next && !apr_isspace(*next) &&
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron (*next != ',')) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron next++;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
12901074f5d6b36d08be84d8637b6f2c21e0da26trawick *val = apr_pstrmemdup(p, val_start,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron next - val_start);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
dc80439e9fba60c753cd145cb6799409ffea9b71ronald else {
dc80439e9fba60c753cd145cb6799409ffea9b71ronald *val = NULL;
dc80439e9fba60c753cd145cb6799409ffea9b71ronald }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return 1;
e8f95a682820a599fe41b22977010636be5c2717jim }
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb }
1df208eeb79b689410598b0f6fd1ac3fb2401c44nd
322b350d0f1ac750b112ec15481a33efc92d182cjerenkrantz /* skip to the next field */
e8f95a682820a599fe41b22977010636be5c2717jim do {
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb next++;
e8f95a682820a599fe41b22977010636be5c2717jim if (!*next) {
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb return 0;
e8f95a682820a599fe41b22977010636be5c2717jim }
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb } while (*next != ',');
e8f95a682820a599fe41b22977010636be5c2717jim }
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb}
e8f95a682820a599fe41b22977010636be5c2717jim
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb/* return each comma separated token, one at a time */
e8f95a682820a599fe41b22977010636be5c2717jimCACHE_DECLARE(const char *)ap_cache_tokstr(apr_pool_t *p, const char *list,
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb const char **str)
e8f95a682820a599fe41b22977010636be5c2717jim{
090a954a1fe65b29a6f4a696f0136ef12ea0f1b1rbb apr_size_t i;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *s;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding s = ap_strchr_c(list, ',');
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (s != NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding i = s - list;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding do
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding s++;
b6832863054a2d09233ce92945e0faceb932a620jwoolley while (apr_isspace(*s))
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ; /* noop */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding i = strlen(list);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding while (i > 0 && apr_isspace(list[i - 1]))
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding i--;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding *str = s;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (i)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_pstrndup(p, list, i);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return NULL;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Converts apr_time_t expressed as hex digits to
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * a true apr_time_t.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingCACHE_DECLARE(apr_time_t) ap_cache_hex2usec(const char *x)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding int i, ch;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_time_t j;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (i = 0, j = 0; i < sizeof(j) * 2; i++) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ch = x[i];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding j <<= 4;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (apr_isdigit(ch))
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding j |= ch - '0';
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else if (apr_isupper(ch))
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding j |= ch - ('A' - 10);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding j |= ch - ('a' - 10);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return j;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Converts apr_time_t to apr_time_t expressed as hex digits.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingCACHE_DECLARE(void) ap_cache_usec2hex(apr_time_t j, char *y)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
b29f87f4b6c6886a04dccc296177a7033f70dfedtrawick int i, ch;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (i = (sizeof(j) * 2)-1; i >= 0; i--) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ch = (int)(j & 0xF);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding j >>= 4;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (ch >= 10)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding y[i] = ch + ('A' - 10);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding else
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding y[i] = ch + '0';
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding y[sizeof(j) * 2] = '\0';
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic void cache_hash(const char *it, char *val, int ndepth, int nlength)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_md5_ctx_t context;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding unsigned char digest[16];
dc80439e9fba60c753cd145cb6799409ffea9b71ronald char tmp[22];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding int i, k, d;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding unsigned int x;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding static const char enc_table[64] =
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@";
29c30db45f6a469017e16b606611e460cc1a1f2caaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_md5_init(&context);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron apr_md5_update(&context, (const unsigned char *) it, strlen(it));
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron apr_md5_final(digest, &context);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* encode 128 bits as 22 characters, using a modified uuencoding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * the encoding is 3 bytes -> 4 characters* i.e. 128 bits is
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron for (i = 0, k = 0; i < 15; i += 3) {
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron x = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tmp[k++] = enc_table[x >> 18];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tmp[k++] = enc_table[(x >> 12) & 0x3f];
29c30db45f6a469017e16b606611e460cc1a1f2caaron tmp[k++] = enc_table[(x >> 6) & 0x3f];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tmp[k++] = enc_table[x & 0x3f];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron }
12901074f5d6b36d08be84d8637b6f2c21e0da26trawick
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron /* one byte left */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron x = digest[15];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron tmp[k++] = enc_table[x >> 2]; /* use up 6 bits */
12901074f5d6b36d08be84d8637b6f2c21e0da26trawick tmp[k++] = enc_table[(x << 4) & 0x3f];
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron /* now split into directory levels */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (i = k = d = 0; d < ndepth; ++d) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding memcpy(&val[i], &tmp[k], nlength);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding k += nlength;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding val[i + nlength] = '/';
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding i += nlength + 1;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding memcpy(&val[i], &tmp[k], 22 - k);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding val[i + 22 - k] = '\0';
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingCACHE_DECLARE(char *)ap_cache_generate_name(apr_pool_t *p, int dirlevels,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding int dirlength, const char *name)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding char hashfile[66];
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding cache_hash(name, hashfile, dirlevels, dirlength);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_pstrdup(p, hashfile);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron/*
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * Create a new table consisting of those elements from an
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * headers table that are allowed to be stored in a cache.
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronCACHE_DECLARE(apr_table_t *)ap_cache_cacheable_headers(apr_pool_t *pool,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron apr_table_t *t,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron server_rec *s)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron{
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron cache_server_conf *conf;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron char **header;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron int i;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron apr_table_t *headers_out;
97d20d37d21b8d427a920e211858172f0a82427epoirier
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron /* Short circuit the common case that there are not
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * (yet) any headers populated.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (t == NULL) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return apr_table_make(pool, 10);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding };
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* Make a copy of the headers, and remove from
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * the copy any hop-by-hop headers, as defined in Section
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * 13.5.1 of RFC 2616
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding headers_out = apr_table_copy(pool, t);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_unset(headers_out, "Connection");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_unset(headers_out, "Keep-Alive");
dc80439e9fba60c753cd145cb6799409ffea9b71ronald apr_table_unset(headers_out, "Proxy-Authenticate");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_unset(headers_out, "Proxy-Authorization");
dc80439e9fba60c753cd145cb6799409ffea9b71ronald apr_table_unset(headers_out, "TE");
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron apr_table_unset(headers_out, "Trailers");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_unset(headers_out, "Transfer-Encoding");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_unset(headers_out, "Upgrade");
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding conf = (cache_server_conf *)ap_get_module_config(s->module_config,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding &cache_module);
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron /* Remove the user defined headers set with CacheIgnoreHeaders.
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * This may break RFC 2616 compliance on behalf of the administrator.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding header = (char **)conf->ignore_headers->elts;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding for (i = 0; i < conf->ignore_headers->nelts; i++) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_unset(headers_out, header[i]);
29c30db45f6a469017e16b606611e460cc1a1f2caaron }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return headers_out;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
97d20d37d21b8d427a920e211858172f0a82427epoirier/*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Legacy call - functionally equivalent to ap_cache_cacheable_headers.
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron * @deprecated @see ap_cache_cacheable_headers
12901074f5d6b36d08be84d8637b6f2c21e0da26trawick */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronCACHE_DECLARE(apr_table_t *)ap_cache_cacheable_hdrs_out(apr_pool_t *p,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron apr_table_t *t,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron server_rec *s)
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron{
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return ap_cache_cacheable_headers(p,t,s);
97d20d37d21b8d427a920e211858172f0a82427epoirier}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron
97d20d37d21b8d427a920e211858172f0a82427epoirier/*
97d20d37d21b8d427a920e211858172f0a82427epoirier * Create a new table consisting of those elements from an input
97d20d37d21b8d427a920e211858172f0a82427epoirier * headers table that are allowed to be stored in a cache.
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron */
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaronCACHE_DECLARE(apr_table_t *)ap_cache_cacheable_headers_in(request_rec *r)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return ap_cache_cacheable_headers(r->pool, r->headers_in, r->server);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding}
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
dc80439e9fba60c753cd145cb6799409ffea9b71ronald/*
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Create a new table consisting of those elements from an output
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * headers table that are allowed to be stored in a cache;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * ensure there is a content type and capture any errors.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding */
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingCACHE_DECLARE(apr_table_t *)ap_cache_cacheable_headers_out(request_rec *r)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding{
29c30db45f6a469017e16b606611e460cc1a1f2caaron apr_table_t *headers_out;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
12901074f5d6b36d08be84d8637b6f2c21e0da26trawick headers_out = apr_table_overlay(r->pool, r->headers_out,
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron r->err_headers_out);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_clear(r->err_headers_out);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding headers_out = ap_cache_cacheable_headers(r->pool, headers_out,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->server);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!apr_table_get(headers_out, "Content-Type")
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding && r->content_type) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_setn(headers_out, "Content-Type",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ap_make_content_type(r, r->content_type));
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
dc80439e9fba60c753cd145cb6799409ffea9b71ronald if (!apr_table_get(headers_out, "Content-Encoding")
58fd79b56eb624bf011772994e9761d3c2e228c1orlikowski && r->content_encoding) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding apr_table_setn(headers_out, "Content-Encoding",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding r->content_encoding);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron return headers_out;
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron}
0ec6007a40ac877a7c8d87767ca8e306d89f6595aaron