}
-int cache_check_freshness(cache_handle_t *h,
- cache_request_rec *cache,
+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_cresp, *cc_req;
+ const char *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);
const char *warn_head;
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)) {
+ 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 */
}
/* 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)) {
+ if (h->cache_obj->info.control.no_cache) {
/*
* The cached entity contained Cache-Control: no-cache, so treat as
* stale causing revalidation
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;
- }
+ smaxage = h->cache_obj->info.control.s_maxage_value;
/* 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;
+ maxage_req = -1;
+ if (!conf->ignorecachecontrol) {
+ maxage_req = cache->control_in.max_age_value;
}
/* 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;
- }
+ maxage_cresp = h->cache_obj->info.control.max_age_value;
/*
* if both maxage request and response, the smaller one takes priority
}
/* extract max-stale */
- if (cc_req && ap_cache_liststr(r->pool, cc_req, "max-stale", &val)) {
- if(val != NULL) {
- maxstale = apr_atoi64(val);
+ if (cache->control_in.max_stale) {
+ if(cache->control_in.max_stale_value != -1) {
+ maxstale = cache->control_in.max_stale_value;
}
else {
/*
}
/* extract min-fresh */
- if (!conf->ignorecachecontrol
- && cc_req && ap_cache_liststr(r->pool, cc_req, "min-fresh", &val)
- && val != NULL) {
- minfresh = apr_atoi64(val);
+ if (!conf->ignorecachecontrol && cache->control_in.min_fresh) {
+ minfresh = cache->control_in.min_fresh_value;
}
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)))) {
+ if (maxstale && (h->cache_obj->info.control.must_revalidate
+ || h->cache_obj->info.control.proxy_revalidate)) {
maxstale = 0;
}
else if (!strncasecmp(token, "max-age", 7)) {
if (token[7] == '=') {
cc->max_age = 1;
- cc->max_age_value = atoi(token + 8);
+ cc->max_age_value = apr_atoi64(token + 8);
}
break;
}
else if (!strncasecmp(token, "max-stale", 9)) {
if (token[9] == '=') {
cc->max_stale = 1;
- cc->max_stale_value = atoi(token + 10);
+ cc->max_stale_value = apr_atoi64(token + 10);
}
else if (!token[10]) {
cc->max_stale = 1;
else if (!strncasecmp(token, "min-fresh", 9)) {
if (token[9] == '=') {
cc->min_fresh = 1;
- cc->min_fresh_value = atoi(token + 10);
+ cc->min_fresh_value = apr_atoi64(token + 10);
}
break;
}
if (!strncasecmp(token, "s-maxage", 8)) {
if (token[8] == '=') {
cc->s_maxage = 1;
- cc->s_maxage_value = atoi(token + 9);
+ cc->s_maxage_value = apr_atoi64(token + 9);
}
break;
}
int stale_on_error_set;
} cache_dir_conf;
-/* a cache control header breakdown */
-typedef struct {
- unsigned int parsed:1;
- unsigned int cache_control:1;
- unsigned int pragma:1;
- unsigned int no_cache:1;
- unsigned int no_cache_header:1; /* no cache by header match */
- unsigned int no_store:1;
- unsigned int max_age:1;
- unsigned int max_stale:1;
- unsigned int min_fresh:1;
- unsigned int no_transform:1;
- unsigned int only_if_cached:1;
- unsigned int public:1;
- unsigned int private:1;
- unsigned int private_header:1; /* private by header match */
- unsigned int must_revalidate:1;
- unsigned int proxy_revalidate:1;
- unsigned int s_maxage:1;
- int max_age_value; /* if positive, then set */
- int max_stale_value; /* if positive, then set */
- int min_fresh_value; /* if positive, then set */
- int s_maxage_value; /* if positive, then set */
-} cache_control_t;
-
/* A linked-list of authn providers. */
typedef struct cache_provider_list cache_provider_list;
cache_request_rec *cache = (cache_request_rec *)f->ctx;
cache_server_conf *conf;
cache_dir_conf *dconf;
- const char *cc_out, *cl;
+ cache_control_t control;
+ const char *cc_out, *cl, *pragma;
const char *exps, *lastmods, *dates, *etag;
apr_time_t exp, date, lastmod, now;
apr_off_t size = -1;
char *reason;
apr_pool_t *p;
apr_bucket *e;
+ apr_table_t *headers;
conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
&cache_module);
ap_remove_output_filter(cache->remove_url_filter);
- if (cache->stale_handle && !ap_cache_liststr(
- NULL,
- apr_table_get(cache->stale_handle->resp_hdrs, "Cache-Control"),
- "must-revalidate", NULL)) {
+ if (cache->stale_handle
+ && cache->stale_handle->cache_obj->info.control.must_revalidate) {
const char *warn_head;
/* morph the current save filter into the out filter, and serve from
etag = apr_table_get(r->headers_out, "Etag");
}
cc_out = apr_table_get(r->err_headers_out, "Cache-Control");
- if (cc_out == NULL) {
+ pragma = apr_table_get(r->err_headers_out, "Pragma");
+ headers = r->err_headers_out;
+ if (cc_out == NULL && pragma == NULL) {
cc_out = apr_table_get(r->headers_out, "Cache-Control");
+ pragma = apr_table_get(r->headers_out, "Pragma");
+ headers = r->headers_out;
}
+ /* Parse the cache control header */
+ memset(&control, 0, sizeof(cache_control_t));
+ ap_cache_control(r, &control, cc_out, pragma, headers);
+
/*
* what responses should we not cache?
*
/* if a Expires header is in the past, don't cache it */
reason = "Expires header already expired; not cacheable";
}
- else if (!conf->ignorequerystring && r->parsed_uri.query && exps == NULL &&
- !ap_cache_liststr(NULL, cc_out, "max-age", NULL) &&
- !ap_cache_liststr(NULL, cc_out, "s-maxage", NULL)) {
+ else if (!conf->ignorequerystring && r->parsed_uri.query && exps == NULL
+ && !control.max_age && !control.s_maxage) {
/* if a query string is present but no explicit expiration time,
* don't cache it (RFC 2616/13.9 & 13.2.1)
*/
*/
reason = "HTTP Status 304 Not Modified";
}
- else if (r->status == HTTP_OK && lastmods == NULL && etag == NULL
- && (exps == NULL) && (dconf->no_last_mod_ignore ==0) &&
- !ap_cache_liststr(NULL, cc_out, "max-age", NULL) &&
- !ap_cache_liststr(NULL, cc_out, "s-maxage", NULL)) {
+ else if (r->status == HTTP_OK && lastmods == NULL && etag == NULL && (exps
+ == NULL) && (dconf->no_last_mod_ignore == 0) && !control.max_age
+ && !control.s_maxage) {
/* 200 OK response from HTTP/1.0 and up without Last-Modified,
* Etag, Expires, Cache-Control:max-age, or Cache-Control:s-maxage
* headers.
*/
reason = "No Last-Modified; Etag; Expires; Cache-Control:max-age or Cache-Control:s-maxage headers";
}
- else if (!dconf->store_nostore &&
- ap_cache_liststr(NULL, cc_out, "no-store", NULL)) {
+ else if (!dconf->store_nostore && control.no_store) {
/* RFC2616 14.9.2 Cache-Control: no-store response
* indicating do not cache, or stop now if you are
* trying to cache it.
*/
reason = "Cache-Control: no-store present";
}
- else if (!dconf->store_private &&
- ap_cache_liststr(NULL, cc_out, "private", NULL)) {
+ else if (!dconf->store_private && control.private) {
/* RFC2616 14.9.1 Cache-Control: private response
* this object is marked for this user's eyes only. Behave
* as a tunnel.
*/
reason = "Cache-Control: private present";
}
- else if (apr_table_get(r->headers_in, "Authorization") != NULL
- && !(ap_cache_liststr(NULL, cc_out, "s-maxage", NULL)
- || ap_cache_liststr(NULL, cc_out, "must-revalidate", NULL)
- || ap_cache_liststr(NULL, cc_out, "public", NULL))) {
+ else if (apr_table_get(r->headers_in, "Authorization")
+ && !(control.s_maxage || control.must_revalidate || control.public)) {
/* RFC2616 14.8 Authorisation:
* if authorisation is included in the request, we don't cache,
* but we can cache if the following exceptions are true:
* too.
*/
+ /* store away the previously parsed cache control headers */
+ memcpy(&info->control, &control, sizeof(cache_control_t));
+
/* Read the date. Generate one if one is not supplied */
dates = apr_table_get(r->err_headers_out, "Date");
if (dates == NULL) {
* expire date = date + defaultexpire
*/
if (exp == APR_DATE_BAD) {
- char *max_age_val;
- if (ap_cache_liststr(r->pool, cc_out, "max-age", &max_age_val) &&
- max_age_val != NULL) {
+ if (control.max_age) {
apr_int64_t x;
errno = 0;
- x = apr_atoi64(max_age_val);
+ x = control.max_age_value;
if (errno) {
x = dconf->defex;
}
#define CACHE_DECLARE_DATA __declspec(dllimport)
#endif
+/* a cache control header breakdown */
+typedef struct cache_control cache_control_t;
+struct cache_control {
+ unsigned int parsed:1;
+ unsigned int cache_control:1;
+ unsigned int pragma:1;
+ unsigned int no_cache:1;
+ unsigned int no_cache_header:1; /* no cache by header match */
+ unsigned int no_store:1;
+ unsigned int max_age:1;
+ unsigned int max_stale:1;
+ unsigned int min_fresh:1;
+ unsigned int no_transform:1;
+ unsigned int only_if_cached:1;
+ unsigned int public:1;
+ unsigned int private:1;
+ unsigned int private_header:1; /* private by header match */
+ unsigned int must_revalidate:1;
+ unsigned int proxy_revalidate:1;
+ unsigned int s_maxage:1;
+ apr_int64_t max_age_value; /* if positive, then set */
+ apr_int64_t max_stale_value; /* if positive, then set */
+ apr_int64_t min_fresh_value; /* if positive, then set */
+ apr_int64_t s_maxage_value; /* if positive, then set */
+};
+
/* cache info information */
typedef struct cache_info cache_info;
struct cache_info {
* status code finally issued to the request.
*/
int status;
+ /* cached cache-control */
+ cache_control_t control;
};
/* cache handle information */
info->request_time = dobj->disk_info.request_time;
info->response_time = dobj->disk_info.response_time;
+ memcpy(&info->control, &dobj->disk_info.control, sizeof(cache_control_t));
+
/* Note that we could optimize this by conditionally doing the palloc
* depending upon the size. */
urlbuff = apr_palloc(r->pool, dobj->disk_info.name_len + 1);
disk_info.name_len = strlen(dobj->name);
+ memcpy(&disk_info.control, &h->cache_obj->info.control, sizeof(cache_control_t));
+
iov[0].iov_base = (void*)&disk_info;
iov[0].iov_len = sizeof(disk_cache_info_t);
iov[1].iov_base = (void*)dobj->name;
#ifndef MOD_DISK_CACHE_H
#define MOD_DISK_CACHE_H
+#include "mod_cache.h"
#include "apr_file_io.h"
/*
/* Does this cached request have a body? */
int has_body;
int header_only;
+ /* The parsed cache control header */
+ cache_control_t control;
} disk_cache_info_t;
typedef struct {