]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Begin the process of optimising the parsing of Cache-Control headers. Parse
authorGraham Leggett <minfrin@apache.org>
Sat, 16 Oct 2010 19:30:08 +0000 (19:30 +0000)
committerGraham Leggett <minfrin@apache.org>
Sat, 16 Oct 2010 19:30:08 +0000 (19:30 +0000)
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

include/ap_mmn.h
modules/cache/cache_storage.c
modules/cache/cache_util.c
modules/cache/cache_util.h
modules/cache/mod_cache.h

index 0ee469b2323ec87b48f3104f850d3f58f84fe6c3..5f433c3e3c524ecafda814c7e8b04a87debc10bc 100644 (file)
  *                         Make root parameter of ap_expr_eval() const.
  * 20100923.3 (2.3.9-dev)  Add "last" member to ap_directive_t
  * 20101012.0 (2.3.9-dev)  Add header to cache_status hook.
+ * 20101016.0 (2.3.9-dev)  Remove ap_cache_check_allowed().
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
 
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
-#define MODULE_MAGIC_NUMBER_MAJOR 20101012
+#define MODULE_MAGIC_NUMBER_MAJOR 20101016
 #endif
 #define MODULE_MAGIC_NUMBER_MINOR 0                     /* 0...n */
 
index c0bea512621f2cbed5c09a38ae7d6c906fcc1db7..457f63c70a25ea40e538a68dd1bdefa20a608d18 100644 (file)
@@ -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;
     }
 
index 9982c20f6390f543401f2bd9817168803c9acbc5..554757586495e2852ec880ffb1fa090a67acd560 100644 (file)
@@ -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);
+}
index 11896942984c55c1ac39c54fea39d2d677487b0f..0aa20fe0b0966c4fa98ed16e9d708ce6329e812e 100644 (file)
@@ -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,8 +247,26 @@ 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
index 3944dfd7e1e06fd2f9844b5e71857672f51b6af4..3a06080192355027ad08184be33c25b0cfcbc23f 100644 (file)
@@ -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,