From: Ian Holsman Date: Fri, 25 Jan 2002 20:09:33 +0000 (+0000) Subject: I haven't created the optional function to specify the cache_key yet, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9421a80d9111d7f2f2beaf726fce10013a33c9af;p=apache I haven't created the optional function to specify the cache_key yet, That will come after this patch. ok.. brief summary of whats changed * new Optional Directives * CacheMemEntrySize -- max size of a individual entry in memory cache * CacheIgnoreNoLastMod - so we can cache mod-included files * it tries to figure out the size of the request based on buckets if the content-length header isn't set * mem_cache now caches the subprocess_env & notes tables * the CACHE_IN/OUT/CONDITIONAL run at FTYPE_CONTENT+1, so that all other content filters run BEFORE the cache in. note: the code is still experimental, and we need a bit more work mainly... * garbage collection * cache stats/reporting * manual removal of a key. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@93030 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/experimental/cache_storage.c b/modules/experimental/cache_storage.c index 36e1546245..1c3605d347 100644 --- a/modules/experimental/cache_storage.c +++ b/modules/experimental/cache_storage.c @@ -78,11 +78,14 @@ int cache_remove_url(request_rec *r, const char *types, char *url) { const char *next = types; const char *type; + const char *key; + + key = cache_create_key(r); /* for each specified cache type, delete the URL */ while(next) { type = ap_cache_tokstr(r->pool, next, &next); - cache_run_remove_url(type, url); + cache_run_remove_url(type, key); } return OK; } @@ -104,14 +107,16 @@ int cache_create_entity(request_rec *r, const char *types, char *url, apr_size_t cache_handle_t *h = apr_pcalloc(r->pool, sizeof(h)); const char *next = types; const char *type; + const char *key; apr_status_t rv; - cache_request_rec *cache = (cache_request_rec *) ap_get_module_config(r->request_config, - &cache_module); + cache_request_rec *cache = (cache_request_rec *) + ap_get_module_config(r->request_config, &cache_module); /* for each specified cache type, delete the URL */ + key = cache_create_key(r); while (next) { type = ap_cache_tokstr(r->pool, next, &next); - switch (rv = cache_run_create_entity(h, type, url, size)) { + switch (rv = cache_run_create_entity(h, type, key, size)) { case OK: { cache->handle = h; return OK; @@ -157,15 +162,16 @@ int cache_select_url(request_rec *r, const char *types, char *url) const char *type; apr_status_t rv; cache_info *info; - cache_request_rec *cache = (cache_request_rec *) ap_get_module_config(r->request_config, - &cache_module); - + const char *key; + cache_request_rec *cache = (cache_request_rec *) + ap_get_module_config(r->request_config, &cache_module); + key = cache_create_key(r); /* go through the cache types till we get a match */ cache->handle = apr_palloc(r->pool, sizeof(cache_handle_t)); while (next) { type = ap_cache_tokstr(r->pool, next, &next); - switch ((rv = cache_run_open_entity(cache->handle, type, url))) { + switch ((rv = cache_run_open_entity(cache->handle, type, key))) { case OK: { info = &(cache->handle->cache_obj->info); /* XXX: @@ -196,10 +202,11 @@ int cache_select_url(request_rec *r, const char *types, char *url) return DECLINED; } -apr_status_t cache_write_entity_headers(cache_handle_t *h, request_rec *r, cache_info *info, - apr_table_t *headers) +apr_status_t cache_write_entity_headers(cache_handle_t *h, + request_rec *r, + cache_info *info) { - h->write_headers(h, r, info, headers); + h->write_headers(h, r, info); return APR_SUCCESS; } apr_status_t cache_write_entity_body(cache_handle_t *h, apr_bucket_brigade *b) @@ -210,17 +217,15 @@ apr_status_t cache_write_entity_body(cache_handle_t *h, apr_bucket_brigade *b) return rv; } -apr_status_t cache_read_entity_headers(cache_handle_t *h, request_rec *r, - apr_table_t **headers) +apr_status_t cache_read_entity_headers(cache_handle_t *h, request_rec *r) { cache_info *info = &(h->cache_obj->info); /* Build the header table from info in the info struct */ - *headers = apr_table_make(r->pool, 15); - - h->read_headers(h, r, *headers); + h->read_headers(h, r); r->content_type = apr_pstrdup(r->pool, info->content_type); + r->filename = apr_pstrdup(r->pool, info->filename ); return APR_SUCCESS; } @@ -230,37 +235,18 @@ apr_status_t cache_read_entity_body(cache_handle_t *h, apr_bucket_brigade *b) return APR_SUCCESS; } +const char* cache_create_key( request_rec *r ) +{ + return r->uri; +} APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, create_entity, (cache_handle_t *h, const char *type, - char *url, apr_size_t len),(h,type,url,len),DECLINED) + const char *urlkey, apr_size_t len), + (h,type,urlkey,len),DECLINED) APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, open_entity, (cache_handle_t *h, const char *type, - char *url),(h,type,url),DECLINED) + const char *urlkey),(h,type,urlkey), + DECLINED) APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(cache, CACHE, int, remove_url, - (const char *type, char *url),(type,url),OK,DECLINED) -#if 0 -/* BillS doesn't think these should be hooks. - * All functions which accept a cache_handle * argument should use - * function pointers in the cache_handle. Leave them here for now as - * points for discussion... - */ - -APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, remove_entity, - (cache_handle *h),(h),DECLINED) - -APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, read_entity_headers, - (cache_handle *h, request_rec *r, - apr_table_t **headers), - (h,info,headers_in,headers_out),DECLINED) -APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, read_entity_body, - (cache_handle *h, - apr_bucket_brigade *out),(h,out),DECLINED) -APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, write_entity_headers, - (cache_handle *h, cache_info *info, - apr_table_t *headers_in, - apr_table_t *headers_out), - (h,info,headers_in,headers_out),DECLINED) -APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, write_entity_body, - (cache_handle *h, - apr_bucket_brigade *in),(h,in),DECLINED) -#endif + (const char *type, const char *urlkey), + (type,urlkey),OK,DECLINED) diff --git a/modules/experimental/cache_util.c b/modules/experimental/cache_util.c index 48af63620b..41186dd4ed 100644 --- a/modules/experimental/cache_util.c +++ b/modules/experimental/cache_util.c @@ -72,7 +72,7 @@ int ap_cache_request_is_conditional(request_rec *r) apr_table_get(r->headers_in, "If-Modified-Since") || apr_table_get(r->headers_in, "If-Unmodified-Since")) { - return 1; + return 1; } return 0; } @@ -97,33 +97,37 @@ void ap_cache_reset_output_filters(request_rec *r) } } -const char *ap_cache_get_cachetype(request_rec *r, cache_server_conf *conf, const char *url) +const char *ap_cache_get_cachetype(request_rec *r, + cache_server_conf *conf, + const char *url) { const char *type = NULL; int i; /* loop through all the cacheenable entries */ for (i = 0; i < conf->cacheenable->nelts; i++) { - struct cache_enable *ent = (struct cache_enable *) conf->cacheenable->elts; - const char *thisurl = ent[i].url; - const char *thistype = ent[i].type; - if ((thisurl) && !strncasecmp(thisurl, url, strlen(thisurl))) { - if (!type) { - type = thistype; - } - else { - type = apr_pstrcat(r->pool, type, ",", thistype, NULL); - } - } + struct cache_enable *ent = + (struct cache_enable *)conf->cacheenable->elts; + const char *thisurl = ent[i].url; + const char *thistype = ent[i].type; + if ((thisurl) && !strncasecmp(thisurl, url, strlen(thisurl))) { + if (!type) { + type = thistype; + } + else { + type = apr_pstrcat(r->pool, type, ",", thistype, NULL); + } + } } /* then loop through all the cachedisable entries */ for (i = 0; i < conf->cachedisable->nelts; i++) { - struct cache_disable *ent = (struct cache_disable *) conf->cachedisable->elts; - const char *thisurl = ent[i].url; - if ((thisurl) && !strncasecmp(thisurl, url, strlen(thisurl))) { - type = NULL; - } + struct cache_disable *ent = + (struct cache_disable *)conf->cachedisable->elts; + const char *thisurl = ent[i].url; + if ((thisurl) && !strncasecmp(thisurl, url, strlen(thisurl))) { + type = NULL; + } } return type; @@ -145,35 +149,35 @@ int ap_cache_liststr(const char *list, const char *key, char **val) len = strlen(key); while (list != NULL) { - p = strchr((char *) list, ','); - if (p != NULL) { - i = p - list; - do - p++; - while (ap_isspace(*p)); - } - else - i = strlen(list); - - while (i > 0 && ap_isspace(list[i - 1])) - i--; - if (i == len && strncasecmp(list, key, len) == 0) { - if (val) { - p = strchr((char *) list, ','); - while (ap_isspace(*list)) { - list++; - } - if ('=' == list[0]) - list++; - while (ap_isspace(*list)) { - list++; - } - strncpy(valbuf, list, MIN(p-list, sizeof(valbuf)-1)); - *val = valbuf; - } - return 1; - } - list = p; + p = strchr((char *) list, ','); + if (p != NULL) { + i = p - list; + do + p++; + while (ap_isspace(*p)); + } + else + i = strlen(list); + + while (i > 0 && ap_isspace(list[i - 1])) + i--; + if (i == len && strncasecmp(list, key, len) == 0) { + if (val) { + p = strchr((char *) list, ','); + while (ap_isspace(*list)) { + list++; + } + if ('=' == list[0]) + list++; + while (ap_isspace(*list)) { + list++; + } + strncpy(valbuf, list, MIN(p-list, sizeof(valbuf)-1)); + *val = valbuf; + } + return 1; + } + list = p; } return 0; } @@ -186,21 +190,22 @@ const char *ap_cache_tokstr(apr_pool_t *p, const char *list, const char **str) s = ap_strchr_c(list, ','); if (s != NULL) { - i = s - list; - do - s++; - while (apr_isspace(*s)); + i = s - list; + do + s++; + while (apr_isspace(*s)) + ; /* noop */ } else - i = strlen(list); + i = strlen(list); while (i > 0 && apr_isspace(list[i - 1])) - i--; + i--; *str = s; if (i) - return apr_pstrndup(p, list, i); + return apr_pstrndup(p, list, i); else - return NULL; + return NULL; } diff --git a/modules/experimental/mod_cache.c b/modules/experimental/mod_cache.c index aa30a3b7d2..80979d54a8 100644 --- a/modules/experimental/mod_cache.c +++ b/modules/experimental/mod_cache.c @@ -83,8 +83,6 @@ module AP_MODULE_DECLARE_DATA cache_module; * oh well. */ -int ap_url_cache_handler(request_rec *r); - int ap_url_cache_handler(request_rec *r) { apr_status_t rv; @@ -95,8 +93,9 @@ int ap_url_cache_handler(request_rec *r) const char *types; cache_info *info = NULL; cache_request_rec *cache; - cache_server_conf *conf = (cache_server_conf *) ap_get_module_config(r->server->module_config, - &cache_module); + cache_server_conf *conf = + (cache_server_conf *) ap_get_module_config(r->server->module_config, + &cache_module); /* we don't handle anything but GET */ if (r->method_number != M_GET) return DECLINED; @@ -111,7 +110,8 @@ int ap_url_cache_handler(request_rec *r) "cache: URL %s is being handled by %s", path, types); /* make space for the per request config */ - cache = (cache_request_rec *) ap_get_module_config(r->request_config, &cache_module); + cache = (cache_request_rec *) ap_get_module_config(r->request_config, + &cache_module); if (!cache) { cache = ap_pcalloc(r->pool, sizeof(cache_request_rec)); ap_set_module_config(r->request_config, &cache_module, cache); @@ -182,7 +182,8 @@ int ap_url_cache_handler(request_rec *r) /* fresh data available */ ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, - "cache: fresh cache - add cache_out filter and handle request"); + "cache: fresh cache - add cache_out filter and " + "handle request"); /* We are in the quick handler hook, which means that no output * filters have been set. So lets run the insert_filter hook. @@ -203,7 +204,9 @@ int ap_url_cache_handler(request_rec *r) out = apr_brigade_create(r->pool); if (APR_SUCCESS != (rv = ap_pass_brigade(r->output_filters, out))) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "cache: error returned while trying to return %s cached data", cache->type); + "cache: error returned while trying to return %s " + "cached data", + cache->type); return rv; } return OK; @@ -214,8 +217,10 @@ int ap_url_cache_handler(request_rec *r) "cache: stale cache - test conditional"); /* if conditional request */ if (ap_cache_request_is_conditional(r)) { - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, - "cache: conditional - add cache_in filter and DECLINE"); + ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, + r->server, + "cache: conditional - add cache_in filter and " + "DECLINE"); /* add cache_in filter */ ap_add_output_filter("CACHE_IN", NULL, r, r->connection); /* return DECLINED */ @@ -225,30 +230,43 @@ int ap_url_cache_handler(request_rec *r) else { /* fudge response into a conditional */ if (info && info->etag) { - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, - "cache: nonconditional - fudge conditional by etag"); + ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, + r->server, + "cache: nonconditional - fudge conditional " + "by etag"); /* if we have a cached etag */ apr_table_set(r->headers_in, "If-None-Match", info->etag); } else if (info && info->lastmods) { - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, - "cache: nonconditional - fudge conditional by lastmod"); + ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, + r->server, + "cache: nonconditional - fudge conditional " + "by lastmod"); /* if we have a cached IMS */ - apr_table_set(r->headers_in, "If-Modified-Since", info->lastmods); + apr_table_set(r->headers_in, + "If-Modified-Since", + info->lastmods); } else { /* something else - pretend there was no cache */ - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, - "cache: nonconditional - no cached etag/lastmods - add cache_in and DECLINE"); + ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, + r->server, + "cache: nonconditional - no cached " + "etag/lastmods - add cache_in and DECLINE"); /* add cache_in filter to cache this request */ ap_add_output_filter("CACHE_IN", NULL, r, r->connection); /* return DECLINED */ return DECLINED; } /* add cache_conditional filter */ - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, - "cache: nonconditional - add cache_conditional and DECLINE"); - ap_add_output_filter("CACHE_CONDITIONAL", NULL, r, r->connection); + ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, + r->server, + "cache: nonconditional - add cache_conditional and" + " DECLINE"); + ap_add_output_filter("CACHE_CONDITIONAL", + NULL, + r, + r->connection); /* return DECLINED */ return DECLINED; } @@ -256,8 +274,11 @@ int ap_url_cache_handler(request_rec *r) } else { /* error */ - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "cache: error returned while checking for cached file by %s cache", cache->type); + ap_log_error(APLOG_MARK, APLOG_ERR, rv, + r->server, + "cache: error returned while checking for cached file by " + "%s cache", + cache->type); return DECLINED; } } @@ -268,14 +289,12 @@ int ap_url_cache_handler(request_rec *r) * * Deliver cached content (headers and body) up the stack. */ -int ap_cache_out_filter(ap_filter_t *f, apr_bucket_brigade *bb); - int ap_cache_out_filter(ap_filter_t *f, apr_bucket_brigade *bb) { request_rec *r = f->r; - apr_table_t *headers; - cache_request_rec *cache = (cache_request_rec *) ap_get_module_config(r->request_config, - &cache_module); + cache_request_rec *cache = + (cache_request_rec *) ap_get_module_config(r->request_config, + &cache_module); if (!cache) { /* user likely configured CACHE_OUT manually; they should use mod_cache @@ -287,10 +306,9 @@ int ap_cache_out_filter(ap_filter_t *f, apr_bucket_brigade *bb) } ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, - "cache: running CACHE_OUT filter"); + "cache: running CACHE_OUT filter"); - cache_read_entity_headers(cache->handle, r, &headers); - r->headers_out = headers; + cache_read_entity_headers(cache->handle, r); cache_read_entity_body(cache->handle, bb); /* This filter is done once it has served up its content */ @@ -310,7 +328,6 @@ int ap_cache_out_filter(ap_filter_t *f, apr_bucket_brigade *bb) * Otherwise * replace ourselves with cache_in filter */ -int ap_cache_conditional_filter(ap_filter_t *f, apr_bucket_brigade *in); int ap_cache_conditional_filter(ap_filter_t *f, apr_bucket_brigade *in) { @@ -343,7 +360,6 @@ int ap_cache_conditional_filter(ap_filter_t *f, apr_bucket_brigade *in) * pass the data to the next filter (the network) * */ -int ap_cache_in_filter(ap_filter_t *f, apr_bucket_brigade *in); int ap_cache_in_filter(ap_filter_t *f, apr_bucket_brigade *in) { @@ -387,7 +403,9 @@ int ap_cache_in_filter(ap_filter_t *f, apr_bucket_brigade *in) * if the setup section (see below) is complete. */ - /* have we already run the cachability check and set up the cached file handle? */ + /* have we already run the cachability check and set up the cached file + * handle? + */ if(cache->in_checked) { /* pass the brigades into the cache, then pass them * up the filter stack @@ -447,7 +465,8 @@ int ap_cache_in_filter(ap_filter_t *f, apr_bucket_brigade *in) * telling us to serve the cached copy. */ if ((r->status != HTTP_OK && r->status != HTTP_NON_AUTHORITATIVE && r->status != HTTP_MULTIPLE_CHOICES && - r->status != HTTP_MOVED_PERMANENTLY && r->status != HTTP_NOT_MODIFIED) || + r->status != HTTP_MOVED_PERMANENTLY && + r->status != HTTP_NOT_MODIFIED) || /* if a broken Expires header is present, don't cache it */ (exps != NULL && exp == APR_DATE_BAD) || @@ -456,8 +475,13 @@ int ap_cache_in_filter(ap_filter_t *f, apr_bucket_brigade *in) * this untouched to the user agent, it's not for us. */ (r->status == HTTP_NOT_MODIFIED && (NULL == cache->handle)) || - /* 200 OK response from HTTP/1.0 and up without a Last-Modified header/Etag */ - (r->status == HTTP_OK && lastmods == NULL && etag == NULL) || + /* 200 OK response from HTTP/1.0 and up without a Last-Modified header/Etag + */ + /* XXX mod-include clears last_modified/expires/etags - this is why we have + * a optional function for a key-gen ;-) + */ + (r->status == HTTP_OK && lastmods == NULL && etag == NULL + && (conf->no_last_mod_ignore ==0)) || /* HEAD requests */ r->header_only || @@ -515,8 +539,29 @@ int ap_cache_in_filter(ap_filter_t *f, apr_bucket_brigade *in) if (cl) { size = atol(cl); } - else - size = -1; + else { + + /* if we don't get the content-length, see if we have all the + * buckets and use their length to calculate the size + */ + apr_bucket *e; + int all_buckets_here=0; + size=0; + APR_BRIGADE_FOREACH(e, in) { + if (APR_BUCKET_IS_EOS(e)) { + all_buckets_here=1; + break; + } + if (APR_BUCKET_IS_FLUSH(e)) { + continue; + } + size += e->length; + } + + if (!all_buckets_here) { + size = -1; + } + } } /* It's safe to cache the response. @@ -579,10 +624,12 @@ int ap_cache_in_filter(ap_filter_t *f, apr_bucket_brigade *in) info->date = APR_DATE_BAD; now = apr_time_now(); - if (info->date == APR_DATE_BAD) { /* No, or bad date */ + if (info->date == APR_DATE_BAD) { /* No, or bad date */ char *dates; /* no date header! */ - /* add one; N.B. use the time _now_ rather than when we were checking the cache */ + /* add one; N.B. use the time _now_ rather than when we were checking + * the cache + */ date = now; dates = apr_pcalloc(r->pool, MAX_STRING_LEN); apr_rfc822_date(dates, now); @@ -605,11 +652,13 @@ int ap_cache_in_filter(ap_filter_t *f, apr_bucket_brigade *in) /* XXX FIXME we're referencing date on a path where we didn't set it */ if (lastmod != APR_DATE_BAD && lastmod > date) { - /* if its in the future, then replace by date */ + /* if its in the future, then replace by date */ lastmod = date; lastmods = dates; - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, r->server, - "cache: Last modified is in the future, replacing with now"); + ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, + r->server, + "cache: Last modified is in the future, " + "replacing with now"); } info->lastmod = lastmod; @@ -638,11 +687,12 @@ int ap_cache_in_filter(ap_filter_t *f, apr_bucket_brigade *in) info->expire = exp; info->content_type = apr_pstrdup(r->pool, r->content_type); + info->filename = apr_pstrdup(r->pool, r->filename ); /* * Write away header information to cache. */ - cache_write_entity_headers(cache->handle, r, info, r->headers_out); + cache_write_entity_headers(cache->handle, r, info); cache_write_entity_body(cache->handle, in); return ap_pass_brigade(f->next, in); } @@ -673,6 +723,8 @@ static void * create_cache_config(apr_pool_t *p, server_rec *s) /* default percentage to force cache completion */ ps->complete = DEFAULT_CACHE_COMPLETION; ps->complete_set = 0; + ps->no_last_mod_ignore_set = 0; + ps->no_last_mod_ignore = 0; return ps; } @@ -683,11 +735,16 @@ static void * merge_cache_config(apr_pool_t *p, void *basev, void *overridesv) cache_server_conf *overrides = (cache_server_conf *) overridesv; /* 1 if the cache is enabled, 0 otherwise */ - ps->cacheon = (overrides->cacheon_set == 0) ? base->cacheon : overrides->cacheon; + ps->cacheon = + (overrides->cacheon_set == 0) ? base->cacheon : overrides->cacheon; /* array of URL prefixes for which caching is disabled */ - ps->cachedisable = ap_append_arrays(p, base->cachedisable, overrides->cachedisable); + ps->cachedisable = ap_append_arrays(p, + base->cachedisable, + overrides->cachedisable); /* array of URL prefixes for which caching is enabled */ - ps->cacheenable = ap_append_arrays(p, base->cacheenable, overrides->cacheenable); + ps->cacheenable = ap_append_arrays(p, + base->cacheenable, + overrides->cacheenable); /* maximum time to cache a document */ ps->maxex = (overrides->maxex_set == 0) ? base->maxex : overrides->maxex; /* default time to cache a document */ @@ -695,15 +752,31 @@ static void * merge_cache_config(apr_pool_t *p, void *basev, void *overridesv) /* factor used to estimate Expires date from LastModified date */ ps->factor = (overrides->factor_set == 0) ? base->factor : overrides->factor; /* default percentage to force cache completion */ - ps->complete = (overrides->complete_set == 0) ? base->complete : overrides->complete; + ps->complete = + (overrides->complete_set == 0) ? base->complete : overrides->complete; + ps->no_last_mod_ignore = + (overrides->no_last_mod_ignore_set) ? + base->no_last_mod_ignore : + overrides->no_last_mod_ignore; return ps; } +static const char +*set_cache_ignore_no_last_mod( cmd_parms *parms, void *dummy, int flag) +{ + cache_server_conf *conf = ap_get_module_config(parms->server->module_config, + &cache_module); + conf->no_last_mod_ignore = 1; + conf->no_last_mod_ignore_set = 1; + return NULL; + +} static const char *set_cache_on(cmd_parms *parms, void *dummy, int flag) { - cache_server_conf *conf = ap_get_module_config(parms->server->module_config, &cache_module); + cache_server_conf *conf = ap_get_module_config(parms->server->module_config, + &cache_module); conf->cacheon = 1; conf->cacheon_set = 1; @@ -711,9 +784,13 @@ static const char } static const char -*add_cache_enable(cmd_parms *parms, void *dummy, const char *type, const char *url) +*add_cache_enable(cmd_parms *parms, + void *dummy, + const char *type, + const char *url) { - cache_server_conf *conf = ap_get_module_config(parms->server->module_config, &cache_module); + cache_server_conf *conf = ap_get_module_config(parms->server->module_config, + &cache_module); struct cache_enable *new; new = apr_array_push(conf->cacheenable); @@ -725,7 +802,8 @@ static const char static const char *add_cache_disable(cmd_parms *parms, void *dummy, const char *url) { - cache_server_conf *conf = ap_get_module_config(parms->server->module_config, &cache_module); + cache_server_conf *conf = ap_get_module_config(parms->server->module_config, + &cache_module); struct cache_enable *new; new = apr_array_push(conf->cachedisable); @@ -736,7 +814,8 @@ static const char static const char *set_cache_maxex(cmd_parms *parms, void *dummy, const char *arg) { - cache_server_conf *conf = ap_get_module_config(parms->server->module_config, &cache_module); + cache_server_conf *conf = ap_get_module_config(parms->server->module_config, + &cache_module); double val; if (sscanf(arg, "%lg", &val) != 1) @@ -748,7 +827,8 @@ static const char static const char *set_cache_maxex_min(cmd_parms *parms, void *dummy, const char *arg) { - cache_server_conf *conf = ap_get_module_config(parms->server->module_config, &cache_module); + cache_server_conf *conf = ap_get_module_config(parms->server->module_config, + &cache_module); long val; val = atol(arg); @@ -761,7 +841,8 @@ static const char static const char *set_cache_defex(cmd_parms *parms, void *dummy, const char *arg) { - cache_server_conf *conf = ap_get_module_config(parms->server->module_config, &cache_module); + cache_server_conf *conf = ap_get_module_config(parms->server->module_config, + &cache_module); double val; if (sscanf(arg, "%lg", &val) != 1) @@ -773,7 +854,8 @@ static const char static const char *set_cache_defex_min(cmd_parms *parms, void *dummy, const char *arg) { - cache_server_conf *conf = ap_get_module_config(parms->server->module_config, &cache_module); + cache_server_conf *conf = ap_get_module_config(parms->server->module_config, + &cache_module); long val; val = atol(arg); @@ -786,7 +868,8 @@ static const char static const char *set_cache_factor(cmd_parms *parms, void *dummy, const char *arg) { - cache_server_conf *conf = ap_get_module_config(parms->server->module_config, &cache_module); + cache_server_conf *conf = ap_get_module_config(parms->server->module_config, + &cache_module); double val; if (sscanf(arg, "%lg", &val) != 1) @@ -799,7 +882,8 @@ static const char static const char *set_cache_complete(cmd_parms *parms, void *dummy, const char *arg) { - cache_server_conf *conf = ap_get_module_config(parms->server->module_config, &cache_module); + cache_server_conf *conf = ap_get_module_config(parms->server->module_config, + &cache_module); int val; if (sscanf(arg, "%u", &val) != 1) @@ -835,6 +919,9 @@ static const command_rec cache_cmds[] = "The default time in hours to cache a document"), AP_INIT_TAKE1("CacheDefaultExpireMin", set_cache_defex_min, NULL, RSRC_CONF, "The default time in Minutes to cache a document"), + AP_INIT_TAKE1("CacheIgnoreNoLastMod", set_cache_ignore_no_last_mod, NULL, + RSRC_CONF, + "Ignore Responses where there is no Last Modified Header"), AP_INIT_TAKE1("CacheLastModifiedFactor", set_cache_factor, NULL, RSRC_CONF, "The factor used to estimate Expires date from LastModified date"), @@ -853,19 +940,26 @@ register_hooks(apr_pool_t *p) * XXX The cache filters need to run right after the handlers and before * any other filters. Consider creating AP_FTYPE_CACHE for this purpose. * Make them AP_FTYPE_CONTENT for now. + * XXX ianhH:they should run AFTER all the other content filters. */ - ap_register_output_filter("CACHE_IN", ap_cache_in_filter, AP_FTYPE_CONTENT); - ap_register_output_filter("CACHE_OUT", ap_cache_out_filter, AP_FTYPE_CONTENT); - ap_register_output_filter("CACHE_CONDITIONAL", ap_cache_conditional_filter, AP_FTYPE_CONTENT); + ap_register_output_filter("CACHE_IN", + ap_cache_in_filter, + AP_FTYPE_CONTENT+1); + ap_register_output_filter("CACHE_OUT", + ap_cache_out_filter, + AP_FTYPE_CONTENT+1); + ap_register_output_filter("CACHE_CONDITIONAL", + ap_cache_conditional_filter, + AP_FTYPE_CONTENT+1); } module AP_MODULE_DECLARE_DATA cache_module = { STANDARD20_MODULE_STUFF, - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - create_cache_config, /* create per-server config structure */ - merge_cache_config, /* merge per-server config structures */ - cache_cmds, /* command apr_table_t */ + NULL, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + create_cache_config, /* create per-server config structure */ + merge_cache_config, /* merge per-server config structures */ + cache_cmds, /* command apr_table_t */ register_hooks }; diff --git a/modules/experimental/mod_cache.h b/modules/experimental/mod_cache.h index 1afa94a061..d9d2979c40 100644 --- a/modules/experimental/mod_cache.h +++ b/modules/experimental/mod_cache.h @@ -142,12 +142,15 @@ typedef struct { apr_array_header_t *cachedisable; /* URLs not to cache */ apr_time_t maxex; /* Maximum time to keep cached files in msecs */ int maxex_set; - apr_time_t defex; /* default time to keep cached file in msecs */ + apr_time_t defex; /* default time to keep cached file in msecs */ int defex_set; - double factor; /* factor for estimating expires date */ + double factor; /* factor for estimating expires date */ int factor_set; - int complete; /* Force cache completion after this point */ + int complete; /* Force cache completion after this point */ int complete_set; + /* ignore the last-modified header when deciding to cache this request */ + int no_last_mod_ignore_set; + int no_last_mod_ignore; } cache_server_conf; /* cache info information */ @@ -155,7 +158,8 @@ typedef struct cache_info cache_info; struct cache_info { const char *content_type; const char *etag; - const char *lastmods; /* last modified of cache entity */ + const char *lastmods; /* last modified of cache entity */ + const char *filename; apr_time_t date; apr_time_t lastmod; char lastmod_str[APR_RFC822_DATE_LEN]; @@ -180,9 +184,9 @@ typedef struct cache_handle cache_handle_t; struct cache_handle { cache_object_t *cache_obj; int (*remove_entity) (cache_handle_t *h); - int (*write_headers)(cache_handle_t *h, request_rec *r, cache_info *i, apr_table_t *headers); + int (*write_headers)(cache_handle_t *h, request_rec *r, cache_info *i); int (*write_body)(cache_handle_t *h, apr_bucket_brigade *b); - int (*read_headers) (cache_handle_t *h, request_rec *r, apr_table_t *headers); + int (*read_headers) (cache_handle_t *h, request_rec *r); int (*read_body) (cache_handle_t *h, apr_bucket_brigade *bb); }; @@ -210,12 +214,16 @@ int cache_remove_url(request_rec *r, const char *types, char *url); int cache_create_entity(request_rec *r, const char *types, char *url, apr_size_t size); int cache_remove_entity(request_rec *r, const char *types, cache_handle_t *h); int cache_select_url(request_rec *r, const char *types, char *url); +/** + * create a key for the cache based on the request record + * this is the 'default' version, which can be overridden by a default function + */ +const char* cache_create_key( request_rec*r ); -apr_status_t cache_write_entity_headers(cache_handle_t *h, request_rec *r, cache_info *info, - apr_table_t *headers); +apr_status_t cache_write_entity_headers(cache_handle_t *h, request_rec *r, cache_info *info); apr_status_t cache_write_entity_body(cache_handle_t *h, apr_bucket_brigade *bb); -apr_status_t cache_read_entity_headers(cache_handle_t *h, request_rec *r, apr_table_t **headers); +apr_status_t cache_read_entity_headers(cache_handle_t *h, request_rec *r); apr_status_t cache_read_entity_body(cache_handle_t *h, apr_bucket_brigade *bb); @@ -244,28 +252,11 @@ apr_status_t cache_read_entity_body(cache_handle_t *h, apr_bucket_brigade *bb); APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, create_entity, (cache_handle_t *h, const char *type, - char *url, apr_size_t len)) + const char *urlkey, apr_size_t len)) APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, open_entity, (cache_handle_t *h, const char *type, - char *url)) + const char *urlkey)) APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, remove_url, - (const char *type, char *url)) - -#if 0 -APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, remove_entity, - (cache_handle *h)) -APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, read_entity_headers, - (cache_handle *h, cache_info **info, - apr_table_t **headers)) -APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, read_entity_body, - (cache_handle *h, - apr_bucket_brigade *out)) -APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, write_entity_headers, - (cache_handle *h, cache_info *info, - apr_table_t *headers)) -APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, write_entity_body, - (cache_handle *h, - apr_bucket_brigade *in)) -#endif + (const char *type, const char *urlkey)) #endif /*MOD_CACHE_H*/ diff --git a/modules/experimental/mod_mem_cache.c b/modules/experimental/mod_mem_cache.c index 9b5cf5fe5c..934e22c696 100644 --- a/modules/experimental/mod_mem_cache.c +++ b/modules/experimental/mod_mem_cache.c @@ -66,7 +66,7 @@ #error This module does not currently compile unless you have a thread-capable APR. Sorry! #endif -#define MAX_CACHE 5000 +static apr_size_t max_cache_entry_size = 5000; module AP_MODULE_DECLARE_DATA mem_cache_module; /* @@ -93,8 +93,12 @@ typedef struct { typedef struct mem_cache_object { cache_type_e type; - apr_ssize_t num_headers; - cache_header_tbl_t *tbl; + apr_ssize_t num_header_out; + apr_ssize_t num_subprocess_env; + apr_ssize_t num_notes; + cache_header_tbl_t *header_out; + cache_header_tbl_t *subprocess_env; + cache_header_tbl_t *notes; apr_size_t m_len; void *m; } mem_cache_object_t; @@ -113,10 +117,9 @@ static mem_cache_conf *sconf; /* Forward declarations */ static int remove_entity(cache_handle_t *h); -static int write_headers(cache_handle_t *h, request_rec *r, cache_info *i, - apr_table_t *headers); +static int write_headers(cache_handle_t *h, request_rec *r, cache_info *i); static int write_body(cache_handle_t *h, apr_bucket_brigade *b); -static int read_headers(cache_handle_t *h, request_rec *r, apr_table_t *headers); +static int read_headers(cache_handle_t *h, request_rec *r); static int read_body(cache_handle_t *h, apr_bucket_brigade *bb); static void cleanup_cache_object(cache_object_t *obj) @@ -166,9 +169,18 @@ static void cleanup_cache_object(cache_object_t *obj) if (mobj->m) { free(mobj->m); } - + /* XXX should freeing of the info be done here or in cache_storage ? + if (obj->info.content_type ) { + free((char*)obj->info.content_type ); + obj->info.content_type =NULL; + } + if (obj->info.filename ) { + free( (char*)obj->info.filename ); + obj->info.filename= NULL; + } + */ /* XXX Cleanup the headers */ - if (mobj->num_headers) { + if (mobj->num_header_out) { } free(mobj); @@ -199,10 +211,6 @@ static void *create_cache_config(apr_pool_t *p, server_rec *s) sconf = apr_pcalloc(p, sizeof(mem_cache_conf)); sconf->space = DEFAULT_CACHE_SPACE; -#if 0 - sconf->maxexpire = DEFAULT_CACHE_MAXEXPIRE; - sconf->defaultexpire = DEFAULT_CACHE_EXPIRE; -#endif ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded_mpm); if (threaded_mpm) { @@ -214,7 +222,10 @@ static void *create_cache_config(apr_pool_t *p, server_rec *s) return sconf; } -static int create_entity(cache_handle_t *h, const char *type, char *key, apr_size_t len) +static int create_entity(cache_handle_t *h, + const char *type, + const char *key, + apr_size_t len) { cache_object_t *obj, *tmp_obj; mem_cache_object_t *mobj; @@ -226,7 +237,7 @@ static int create_entity(cache_handle_t *h, const char *type, char *key, apr_siz /* XXX Check len to see if it is withing acceptable bounds * max cache check should be configurable variable. */ - if (len < 0 || len > MAX_CACHE) { + if (len < 0 || len > max_cache_entry_size) { return DECLINED; } /* XXX Check total cache size and number of entries. Are they within the @@ -256,7 +267,9 @@ static int create_entity(cache_handle_t *h, const char *type, char *key, apr_siz cleanup_cache_object(obj); } memset(mobj,'\0', sizeof(*mobj)); - obj->vobj = mobj; /* Reference the mem_cache_object_t out of cache_object_t */ + obj->vobj = mobj; /* Reference the mem_cache_object_t out of + * cache_object_t + */ mobj->m_len = len; /* Duplicates info in cache_object_t info */ @@ -268,7 +281,9 @@ static int create_entity(cache_handle_t *h, const char *type, char *key, apr_siz if (sconf->lock) { apr_thread_mutex_lock(sconf->lock); } - tmp_obj = (cache_object_t *) apr_hash_get(sconf->cacheht, key, APR_HASH_KEY_STRING); + tmp_obj = (cache_object_t *) apr_hash_get(sconf->cacheht, + key, + APR_HASH_KEY_STRING); if (!tmp_obj) { apr_hash_set(sconf->cacheht, obj->key, strlen(obj->key), obj); } @@ -296,7 +311,7 @@ static int create_entity(cache_handle_t *h, const char *type, char *key, apr_siz return OK; } -static int open_entity(cache_handle_t *h, const char *type, char *key) +static int open_entity(cache_handle_t *h, const char *type, const char *key) { cache_object_t *obj; @@ -307,7 +322,9 @@ static int open_entity(cache_handle_t *h, const char *type, char *key) if (sconf->lock) { apr_thread_mutex_lock(sconf->lock); } - obj = (cache_object_t *) apr_hash_get(sconf->cacheht, key, APR_HASH_KEY_STRING); + obj = (cache_object_t *) apr_hash_get(sconf->cacheht, + key, + APR_HASH_KEY_STRING); if (sconf->lock) { apr_thread_mutex_unlock(sconf->lock); } @@ -343,9 +360,69 @@ static int remove_entity(cache_handle_t *h) return OK; } +static int serialize_table( cache_header_tbl_t **obj, + int*nelts, + apr_table_t *table) +{ + apr_table_entry_t *elts = (apr_table_entry_t *) table->a.elts; + apr_ssize_t i; + apr_size_t len = 0; + apr_size_t idx = 0; + char *buf; + + *nelts = table->a.nelts; + if (*nelts ==0 ) { + *obj=NULL; + return OK; + } + *obj = malloc(sizeof(cache_header_tbl_t) * table->a.nelts); + if (NULL == *obj) { + /* cleanup_cache_obj(h->cache_obj); */ + return DECLINED; + } + for (i = 0; i < table->a.nelts; ++i) { + len += strlen(elts[i].key); + len += strlen(elts[i].val); + len += 2; /* Extra space for NULL string terminator for key and val */ + } + + /* Transfer the headers into a contiguous memory block */ + buf = malloc(len); + if (!buf) { + free(obj); + *obj = NULL; + /* cleanup_cache_obj(h->cache_obj); */ + return DECLINED; + } + + for (i = 0; i < *nelts; ++i) { + (*obj)[i].hdr = &buf[idx]; + len = strlen(elts[i].key) + 1; /* Include NULL terminator */ + strncpy(&buf[idx], elts[i].key, len); + idx+=len; + + (*obj)[i].val = &buf[idx]; + len = strlen(elts[i].val) + 1; + strncpy(&buf[idx], elts[i].val, len); + idx+=len; + } + return OK; + +} +static int unserialize_table( cache_header_tbl_t *ctbl, + int num_headers, + apr_table_t *t ) +{ + int i; + for (i = 0; i < num_headers; ++i) { + apr_table_setn(t, ctbl[i].hdr, ctbl[i].val); + } + + return OK; +} /* Define request processing hook handlers */ -static int remove_url(const char *type, char *key) +static int remove_url(const char *type, const char *key) { cache_object_t *obj; @@ -363,7 +440,9 @@ static int remove_url(const char *type, char *key) if (sconf->lock) { apr_thread_mutex_lock(sconf->lock); } - obj = (cache_object_t *) apr_hash_get(sconf->cacheht, key, APR_HASH_KEY_STRING); + obj = (cache_object_t *) apr_hash_get(sconf->cacheht, + key, + APR_HASH_KEY_STRING); if (sconf->lock) { apr_thread_mutex_unlock(sconf->lock); } @@ -386,16 +465,25 @@ static int remove_url(const char *type, char *key) return OK; } -static int read_headers(cache_handle_t *h, request_rec *r, apr_table_t *headers) +static int read_headers(cache_handle_t *h, request_rec *r) { + int rc; mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj; - int i; - for (i = 0; i < mobj->num_headers; ++i) { - apr_table_setn(headers, mobj->tbl[i].hdr, mobj->tbl[i].val); - } + r->headers_out = apr_table_make(r->pool,mobj->num_header_out); + r->subprocess_env = apr_table_make(r->pool, mobj->num_subprocess_env); + r->notes = apr_table_make(r->pool, mobj->num_notes); + rc = unserialize_table( mobj->header_out, + mobj->num_header_out, + r->headers_out); + rc = unserialize_table( mobj->subprocess_env, + mobj->num_subprocess_env, + r->subprocess_env); + rc = unserialize_table( mobj->notes, + mobj->num_notes, + r->notes); + return rc; - return OK; } static int read_body(cache_handle_t *h, apr_bucket_brigade *bb) @@ -411,49 +499,33 @@ static int read_body(cache_handle_t *h, apr_bucket_brigade *bb) return OK; } -static int write_headers(cache_handle_t *h, request_rec *r, cache_info *info, apr_table_t *headers) + +static int write_headers(cache_handle_t *h, request_rec *r, cache_info *info) { cache_object_t *obj = h->cache_obj; mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj; - apr_table_entry_t *elts = (apr_table_entry_t *) headers->a.elts; - apr_ssize_t i; - apr_size_t len = 0; - apr_size_t idx = 0; - char *buf; + int rc; /* Precompute how much storage we need to hold the headers */ - mobj->tbl = malloc(sizeof(cache_header_tbl_t) * headers->a.nelts); - if (NULL == mobj->tbl) { - /* cleanup_cache_obj(h->cache_obj); */ - return DECLINED; + rc = serialize_table(&mobj->header_out, + &mobj->num_header_out, + r->headers_out); + if (rc != OK ) { + return rc; } - for (i = 0; i < headers->a.nelts; ++i) { - len += strlen(elts[i].key); - len += strlen(elts[i].val); - len += 2; /* Extra space for NULL string terminator for key and val */ + rc = serialize_table(&mobj->subprocess_env, + &mobj->num_subprocess_env, + r->subprocess_env ); + if (rc != OK ) { + return rc; } - /* Transfer the headers into a contiguous memory block */ - buf = malloc(len); - if (!buf) { - free(mobj->tbl); - mobj->tbl = NULL; - /* cleanup_cache_obj(h->cache_obj); */ - return DECLINED; - } - mobj->num_headers = headers->a.nelts; - for (i = 0; i < mobj->num_headers; ++i) { - mobj->tbl[i].hdr = &buf[idx]; - len = strlen(elts[i].key) + 1; /* Include NULL terminator */ - strncpy(&buf[idx], elts[i].key, len); - idx+=len; - - mobj->tbl[i].val = &buf[idx]; - len = strlen(elts[i].val) + 1; - strncpy(&buf[idx], elts[i].val, len); - idx+=len; + rc = serialize_table(&mobj->notes, &mobj->num_notes, r->notes); + if (rc != OK ) { + return rc; } + /* Init the info struct */ if (info->date) { obj->info.date = info->date; @@ -472,6 +544,15 @@ static int write_headers(cache_handle_t *h, request_rec *r, cache_info *info, ap } strcpy((char*) obj->info.content_type, info->content_type); } + if ( info->filename) { + obj->info.filename = (char*) malloc(strlen(info->filename )+1); + if (!obj->info.filename ) { + free( (char*)obj->info.content_type ); + obj->info.content_type =NULL; + return DECLINED; + } + strcpy((char*) obj->info.filename, info->filename ); + } return OK; } @@ -522,7 +603,6 @@ static int write_body(cache_handle_t *h, apr_bucket_brigade *b) */ AP_DEBUG_ASSERT(h->cache_obj->count > mobj->m_len); } - return OK; } @@ -537,45 +617,19 @@ static const char sconf->space = val; return NULL; } -#if 0 -static const char -*set_cache_factor(cmd_parms *parms, void *dummy, char *arg) +static const char +*set_cache_entry_size(cmd_parms *parms, void *in_struct_ptr, const char *arg) { - double val; - - if (sscanf(arg, "%lg", &val) != 1) - return "CacheLastModifiedFactor value must be a float"; - sconf->lmfactor = val; + int val; + if (sscanf(arg, "%d", &val) != 1) { + return "CacheSize value must be an integer (bytes)"; + } + max_cache_entry_size = val; return NULL; } -#endif -#if 0 -static const char -*set_cache_maxex(cmd_parms *parms, void *dummy, char *arg) -{ - mem_cache_conf *pc = ap_get_module_config(parms->server->module_config, &mem_cache_module); - double val; - if (sscanf(arg, "%lg", &val) != 1) - return "CacheMaxExpire value must be a float"; - sconf->maxexpire = (apr_time_t) (val * MSEC_ONE_HR); - return NULL; -} -#endif -#if 0 -static const char -*set_cache_defex(cmd_parms *parms, void *dummy, char *arg) -{ - mem_cache_conf *pc = ap_get_module_config(parms->server->module_config, &mem_cache_module); - double val; - if (sscanf(arg, "%lg", &val) != 1) - return "CacheDefaultExpire value must be a float"; - pc->defaultexpire = (apr_time_t) (val * MSEC_ONE_HR); - return NULL; -} -#endif static const command_rec cache_cmds[] = { /* XXX @@ -585,8 +639,10 @@ static const command_rec cache_cmds[] = * max entry size, and max size of the cache should * be managed by this module. */ - AP_INIT_TAKE1("CacheSizeMem", set_cache_size, NULL, RSRC_CONF, - "The maximum disk space used by the cache in Kb"), + AP_INIT_TAKE1("CacheMemSize", set_cache_size, NULL, RSRC_CONF, + "The maximum space used by the cache in Kb"), + AP_INIT_TAKE1("CacheMemEntrySize", set_cache_entry_size, NULL, RSRC_CONF, + "The maximum size (in bytes) that a entry can take"), {NULL} };