From: Graham Leggett Date: Sat, 16 Oct 2010 23:15:52 +0000 (+0000) Subject: Complete the optimisation of Cache-Control header parsing. Make the X-Git-Tag: 2.3.9~306 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7229aa211bf86594876f88dd85aec57055ec4895;p=thirdparty%2Fapache%2Fhttpd.git Complete the optimisation of Cache-Control header parsing. Make the cache_control_t structure public so as to be available to mod_disk_cache. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1023387 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/cache/cache_util.c b/modules/cache/cache_util.c index 55475758649..56daff298ff 100644 --- a/modules/cache/cache_util.c +++ b/modules/cache/cache_util.c @@ -442,18 +442,16 @@ CACHE_DECLARE(int) ap_cache_check_allowed(cache_request_rec *cache, request_rec } -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; @@ -499,8 +497,9 @@ int cache_check_freshness(cache_handle_t *h, 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 */ @@ -515,10 +514,9 @@ int cache_check_freshness(cache_handle_t *h, } /* 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 @@ -534,32 +532,16 @@ int cache_check_freshness(cache_handle_t *h, 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 @@ -575,9 +557,9 @@ int cache_check_freshness(cache_handle_t *h, } /* 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 { /* @@ -596,22 +578,16 @@ int cache_check_freshness(cache_handle_t *h, } /* 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; } @@ -1099,14 +1075,14 @@ int ap_cache_control(request_rec *r, cache_control_t *cc, 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; @@ -1117,7 +1093,7 @@ int ap_cache_control(request_rec *r, cache_control_t *cc, 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; } @@ -1164,7 +1140,7 @@ int ap_cache_control(request_rec *r, cache_control_t *cc, 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; } diff --git a/modules/cache/cache_util.h b/modules/cache/cache_util.h index 0aa20fe0b09..a6827a3def0 100644 --- a/modules/cache/cache_util.h +++ b/modules/cache/cache_util.h @@ -190,31 +190,6 @@ 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; diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c index 7c1cbc14c9d..ae2915e244d 100644 --- a/modules/cache/mod_cache.c +++ b/modules/cache/mod_cache.c @@ -724,7 +724,8 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) 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; @@ -732,6 +733,7 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) 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); @@ -794,10 +796,8 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) 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 @@ -871,10 +871,18 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) 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? * @@ -927,9 +935,8 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) /* 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) */ @@ -942,10 +949,9 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) */ 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. @@ -955,26 +961,22 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) */ 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: @@ -1196,6 +1198,9 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) * 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) { @@ -1241,14 +1246,12 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) * 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; } diff --git a/modules/cache/mod_cache.h b/modules/cache/mod_cache.h index 3a060801923..0e454f2b174 100644 --- a/modules/cache/mod_cache.h +++ b/modules/cache/mod_cache.h @@ -52,6 +52,32 @@ #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 { @@ -71,6 +97,8 @@ struct cache_info { * status code finally issued to the request. */ int status; + /* cached cache-control */ + cache_control_t control; }; /* cache handle information */ diff --git a/modules/cache/mod_disk_cache.c b/modules/cache/mod_disk_cache.c index 08ad732118d..37f01883148 100644 --- a/modules/cache/mod_disk_cache.c +++ b/modules/cache/mod_disk_cache.c @@ -235,6 +235,8 @@ static int file_cache_recall_mydata(apr_file_t *fd, cache_info *info, 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); @@ -1011,6 +1013,8 @@ static apr_status_t write_headers(cache_handle_t *h, request_rec *r) 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; diff --git a/modules/cache/mod_disk_cache.h b/modules/cache/mod_disk_cache.h index 6658c15ef32..9f090e1ad31 100644 --- a/modules/cache/mod_disk_cache.h +++ b/modules/cache/mod_disk_cache.h @@ -17,6 +17,7 @@ #ifndef MOD_DISK_CACHE_H #define MOD_DISK_CACHE_H +#include "mod_cache.h" #include "apr_file_io.h" /* @@ -57,6 +58,8 @@ typedef struct { /* 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 {