1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-08 15:02:10 +03:00

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
This commit is contained in:
Graham Leggett
2010-10-16 19:30:08 +00:00
parent 7c19e4963f
commit 796d4cd074
5 changed files with 216 additions and 15 deletions

View File

@@ -274,12 +274,13 @@
* 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 */

View 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;
}

View 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);
}

View 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

View 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,