summaryrefslogtreecommitdiffstats
path: root/modules/cache
diff options
context:
space:
mode:
authorGraham Leggett <minfrin@apache.org>2010-10-16 21:30:08 +0200
committerGraham Leggett <minfrin@apache.org>2010-10-16 21:30:08 +0200
commit796d4cd0743f5865d88c23be4e7237d9795c64e9 (patch)
tree6fa28a83f417d2015f16c1ed92a261a8ad119fe5 /modules/cache
parentupdate transformations (diff)
downloadapache2-796d4cd0743f5865d88c23be4e7237d9795c64e9.tar.xz
apache2-796d4cd0743f5865d88c23be4e7237d9795c64e9.zip
Begin the process of optimising the parsing of Cache-Control headers. Parse
the incoming Cache-Control and Pragma headers once, instead of on each test. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1023360 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/cache')
-rw-r--r--modules/cache/cache_storage.c2
-rw-r--r--modules/cache/cache_util.c174
-rw-r--r--modules/cache/cache_util.h43
-rw-r--r--modules/cache/mod_cache.h9
4 files changed, 214 insertions, 14 deletions
diff --git a/modules/cache/cache_storage.c b/modules/cache/cache_storage.c
index c0bea51262..457f63c70a 100644
--- a/modules/cache/cache_storage.c
+++ b/modules/cache/cache_storage.c
@@ -216,7 +216,7 @@ int cache_select(cache_request_rec *cache, request_rec *r)
}
}
- if (!ap_cache_check_allowed(r)) {
+ if (!ap_cache_check_allowed(cache, r)) {
return DECLINED;
}
diff --git a/modules/cache/cache_util.c b/modules/cache/cache_util.c
index 9982c20f63..5547575864 100644
--- a/modules/cache/cache_util.c
+++ b/modules/cache/cache_util.c
@@ -383,7 +383,7 @@ apr_status_t cache_remove_lock(cache_server_conf *conf,
return apr_file_remove(lockname, r->pool);
}
-CACHE_DECLARE(int) ap_cache_check_allowed(request_rec *r) {
+CACHE_DECLARE(int) ap_cache_check_allowed(cache_request_rec *cache, request_rec *r) {
const char *cc_req;
const char *pragma;
cache_server_conf *conf =
@@ -409,8 +409,9 @@ CACHE_DECLARE(int) ap_cache_check_allowed(request_rec *r) {
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) {
return 0;
@@ -423,7 +424,7 @@ CACHE_DECLARE(int) ap_cache_check_allowed(request_rec *r) {
}
}
- if (ap_cache_liststr(NULL, cc_req, "no-store", NULL)) {
+ if (cache->control_in.no_store) {
if (!conf->ignorecachecontrol) {
/* We're not allowed to serve a cached copy */
@@ -1012,3 +1013,168 @@ CACHE_DECLARE(apr_table_t *)ap_cache_cacheable_headers_out(request_rec *r)
return headers_out;
}
+
+/**
+ * Parse the Cache-Control and Pragma headers in one go, marking
+ * which tokens appear within the header. Populate the structure
+ * passed in.
+ */
+int ap_cache_control(request_rec *r, cache_control_t *cc,
+ const char *cc_header, const char *pragma_header, apr_table_t *headers)
+{
+ char *last;
+
+ if (cc->parsed) {
+ return cc->cache_control || cc->pragma;
+ }
+
+ cc->parsed = 1;
+ cc->max_age_value = -1;
+ cc->max_stale_value = -1;
+ cc->min_fresh_value = -1;
+ cc->s_maxage_value = -1;
+
+ if (pragma_header) {
+ char *header = apr_pstrdup(r->pool, pragma_header);
+ const char *token = apr_strtok(header, ", ", &last);
+ while (token) {
+ /* handle most common quickest case... */
+ if (!strcmp(token, "no-cache")) {
+ cc->no_cache = 1;
+ }
+ /* ...then try slowest case */
+ else if (!strcasecmp(token, "no-cache")) {
+ cc->no_cache = 1;
+ }
+ token = apr_strtok(NULL, ", ", &last);
+ }
+ cc->pragma = 1;
+ }
+
+ if (cc_header) {
+ char *header = apr_pstrdup(r->pool, cc_header);
+ const char *token = apr_strtok(header, ", ", &last);
+ while (token) {
+ switch (token[0]) {
+ case 'n':
+ case 'N': {
+ /* handle most common quickest cases... */
+ if (!strcmp(token, "no-cache")) {
+ cc->no_cache = 1;
+ }
+ else if (!strcmp(token, "no-store")) {
+ cc->no_store = 1;
+ }
+ /* ...then try slowest cases */
+ else if (!strncasecmp(token, "no-cache", 8)) {
+ if (token[8] == '=') {
+ if (apr_table_get(headers, token + 9)) {
+ cc->no_cache_header = 1;
+ }
+ }
+ else if (!token[8]) {
+ cc->no_cache = 1;
+ }
+ break;
+ }
+ else if (!strcasecmp(token, "no-store")) {
+ cc->no_store = 1;
+ }
+ else if (!strcasecmp(token, "no-transform")) {
+ cc->no_transform = 1;
+ }
+ break;
+ }
+ case 'm':
+ case 'M': {
+ /* handle most common quickest cases... */
+ if (!strcmp(token, "max-age=0")) {
+ cc->max_age = 1;
+ cc->max_age_value = 0;
+ }
+ else if (!strcmp(token, "must-revalidate")) {
+ cc->must_revalidate = 1;
+ }
+ /* ...then try slowest cases */
+ else if (!strncasecmp(token, "max-age", 7)) {
+ if (token[7] == '=') {
+ cc->max_age = 1;
+ cc->max_age_value = atoi(token + 8);
+ }
+ break;
+ }
+ else if (!strncasecmp(token, "max-stale", 9)) {
+ if (token[9] == '=') {
+ cc->max_stale = 1;
+ cc->max_stale_value = atoi(token + 10);
+ }
+ else if (!token[10]) {
+ cc->max_stale = 1;
+ cc->max_stale_value = -1;
+ }
+ break;
+ }
+ else if (!strncasecmp(token, "min-fresh", 9)) {
+ if (token[9] == '=') {
+ cc->min_fresh = 1;
+ cc->min_fresh_value = atoi(token + 10);
+ }
+ break;
+ }
+ else if (!strcasecmp(token, "must-revalidate")) {
+ cc->must_revalidate = 1;
+ }
+ break;
+ }
+ case 'o':
+ case 'O': {
+ if (!strcasecmp(token, "only-if-cached")) {
+ cc->only_if_cached = 1;
+ }
+ break;
+ }
+ case 'p':
+ case 'P': {
+ /* handle most common quickest cases... */
+ if (!strcmp(token, "private")) {
+ cc->private = 1;
+ }
+ /* ...then try slowest cases */
+ else if (!strcasecmp(token, "public")) {
+ cc->public = 1;
+ }
+ else if (!strncasecmp(token, "private", 7)) {
+ if (token[7] == '=') {
+ if (apr_table_get(headers, token + 8)) {
+ cc->private_header = 1;
+ }
+ }
+ else if (!token[7]) {
+ cc->private = 1;
+ }
+ break;
+ }
+ else if (!strcasecmp(token, "proxy-revalidate")) {
+ cc->proxy_revalidate = 1;
+ }
+ break;
+ }
+ case 's':
+ case 'S': {
+ if (!strncasecmp(token, "s-maxage", 8)) {
+ if (token[8] == '=') {
+ cc->s_maxage = 1;
+ cc->s_maxage_value = atoi(token + 9);
+ }
+ break;
+ }
+ break;
+ }
+ }
+ token = apr_strtok(NULL, ", ", &last);
+ }
+ cc->cache_control = 1;
+ }
+
+ return (cc_header != NULL || pragma_header != NULL);
+}
diff --git a/modules/cache/cache_util.h b/modules/cache/cache_util.h
index 1189694298..0aa20fe0b0 100644
--- a/modules/cache/cache_util.h
+++ b/modules/cache/cache_util.h
@@ -190,6 +190,31 @@ typedef struct {
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;
@@ -222,9 +247,27 @@ typedef struct {
*/
apr_off_t size; /* the content length from the headers, or -1 */
apr_bucket_brigade *out; /* brigade to reuse for upstream responses */
+ cache_control_t control_in; /* cache control incoming */
} cache_request_rec;
/**
+ * Parse the Cache-Control and Pragma headers in one go, marking
+ * which tokens appear within the header. Populate the structure
+ * passed in.
+ */
+int ap_cache_control(request_rec *r, cache_control_t *cc, const char *cc_header,
+ const char *pragma_header, apr_table_t *headers);
+
+/**
+ * Check the whether the request allows a cached object to be served as per RFC2616
+ * section 14.9.4 (Cache Revalidation and Reload Controls)
+ * @param h cache_handle_t
+ * @param r request_rec
+ * @return 0 ==> cache object may not be served, 1 ==> cache object may be served
+ */
+CACHE_DECLARE(int) ap_cache_check_allowed(cache_request_rec *cache, request_rec *r);
+
+/**
* Check the freshness of the cache object per RFC2616 section 13.2 (Expiration Model)
* @param h cache_handle_t
* @param r request_rec
diff --git a/modules/cache/mod_cache.h b/modules/cache/mod_cache.h
index 3944dfd7e1..3a06080192 100644
--- a/modules/cache/mod_cache.h
+++ b/modules/cache/mod_cache.h
@@ -124,15 +124,6 @@ typedef enum {
CACHE_DECLARE(apr_time_t) ap_cache_current_age(cache_info *info, const apr_time_t age_value,
apr_time_t now);
-/**
- * Check the whether the request allows a cached object to be served as per RFC2616
- * section 14.9.4 (Cache Revalidation and Reload Controls)
- * @param h cache_handle_t
- * @param r request_rec
- * @return 0 ==> cache object may not be served, 1 ==> cache object may be served
- */
-CACHE_DECLARE(int) ap_cache_check_allowed(request_rec *r);
-
CACHE_DECLARE(apr_time_t) ap_cache_hex2usec(const char *x);
CACHE_DECLARE(void) ap_cache_usec2hex(apr_time_t j, char *y);
CACHE_DECLARE(char *) ap_cache_generate_name(apr_pool_t *p, int dirlevels,