Commit fc4a822c authored by Bill Stoddard's avatar Bill Stoddard
Browse files

Backport all of experimental mod_cache, mod_disk_cache and mod_mem_cache changes from 2.1

parent d99fb3b0
Loading
Loading
Loading
Loading
+3 −0
Changes for CHANGES: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
Changes with Apache 2.0.51
  *) Backport all mod_cache, mod_mem_cache, mod_disk_cache and
     related cache utilities from the Apache 2.1 branch.
     [Bill Stoddard]
  *) mod_autoindex: Don't truncate the directory listing if a stat()
     call fails (for instance on a >2Gb file).  PR 17357.
+30 −83
Changes for modules/experimental/cache_storage.c: 30 added lines, 83 removed lines.
Original line number Diff line number Diff line
@@ -17,12 +17,6 @@

#include "mod_cache.h"

APR_HOOK_STRUCT(
	APR_HOOK_LINK(remove_url)
	APR_HOOK_LINK(create_entity)
	APR_HOOK_LINK(open_entity)
)

extern APR_OPTIONAL_FN_TYPE(ap_cache_generate_key) *cache_generate_key;

extern module AP_MODULE_DECLARE_DATA cache_module;
@@ -33,22 +27,25 @@ extern module AP_MODULE_DECLARE_DATA cache_module;
 * delete all URL entities from the cache
 *
 */
int cache_remove_url(request_rec *r, const char *types, char *url)
int cache_remove_url(request_rec *r, char *url)
{
    const char *next = types;
    const char *type;
    cache_provider_list *list;
    apr_status_t rv;
    char *key;
    cache_request_rec *cache = (cache_request_rec *) 
                         ap_get_module_config(r->request_config, &cache_module);

    rv = cache_generate_key(r,r->pool,&key);
    if (rv != APR_SUCCESS) {
        return rv;
    }

    list = cache->providers;

    /* for each specified cache type, delete the URL */
    while(next) {
        type = ap_cache_tokstr(r->pool, next, &next);
        cache_run_remove_url(type, key);
    while(list) {
        list->provider->remove_url(key);
        list = list->next;
    }
    return OK;
}
@@ -65,11 +62,10 @@ int cache_remove_url(request_rec *r, const char *types, char *url)
 * decide whether or not it wants to cache this particular entity.
 * If the size is unknown, a size of -1 should be set.
 */
int cache_create_entity(request_rec *r, const char *types, char *url, apr_off_t size)
int cache_create_entity(request_rec *r, char *url, apr_off_t size)
{
    cache_provider_list *list;
    cache_handle_t *h = apr_pcalloc(r->pool, sizeof(cache_handle_t));
    const char *next = types;
    const char *type;
    char *key;
    apr_status_t rv;
    cache_request_rec *cache = (cache_request_rec *) 
@@ -79,15 +75,19 @@ int cache_create_entity(request_rec *r, const char *types, char *url, apr_off_t
    if (rv != APR_SUCCESS) {
        return rv;
    }

    list = cache->providers;
    /* for each specified cache type, delete the URL */
    while (next) {
        type = ap_cache_tokstr(r->pool, next, &next);
        switch (rv = cache_run_create_entity(h, r, type, key, size)) {
    while (list) {
        switch (rv = list->provider->create_entity(h, r, key, size)) {
        case OK: {
            cache->handle = h;
            cache->provider = list->provider;
            cache->provider_name = list->provider_name;
            return OK;
        }
        case DECLINED: {
            list = list->next;
            continue;
        }
        default: {
@@ -98,19 +98,6 @@ int cache_create_entity(request_rec *r, const char *types, char *url, apr_off_t
    return DECLINED;
}

/*
 * remove a specific URL entity from the cache
 *
 * The specific entity referenced by the cache_handle is removed
 * from the cache, and the cache_handle is closed.
 */
/* XXX Don't think we need to pass in request_rec or types ... */
int cache_remove_entity(request_rec *r, const char *types, cache_handle_t *h)
{
    h->remove_entity(h);
    return 1;
}

/*
 * select a specific URL entity in the cache
 *
@@ -122,10 +109,9 @@ int cache_remove_entity(request_rec *r, const char *types, cache_handle_t *h)
 * This function returns OK if successful, DECLINED if no
 * cached entity fits the bill.
 */
int cache_select_url(request_rec *r, const char *types, char *url)
int cache_select_url(request_rec *r, char *url)
{
    const char *next = types;
    const char *type;
    cache_provider_list *list;
    apr_status_t rv;
    cache_handle_t *h;
    char *key;
@@ -139,17 +125,20 @@ int cache_select_url(request_rec *r, const char *types, char *url)
    /* go through the cache types till we get a match */
    h = 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(h, r, type, key))) {
    list = cache->providers;

    while (list) {
        switch ((rv = list->provider->open_entity(h, r, key))) {
        case OK: {
            char *vary = NULL;
            const char *varyhdr = NULL;
            if (cache_read_entity_headers(h, r) != APR_SUCCESS) {
            if (list->provider->recall_headers(h, r) != APR_SUCCESS) {
                /* TODO: Handle this error */
                return DECLINED;
            }

            r->filename = apr_pstrdup(r->pool, h->cache_obj->info.filename);

            /*
             * Check Content-Negotiation - Vary
             * 
@@ -205,10 +194,13 @@ int cache_select_url(request_rec *r, const char *types, char *url)
                    return DECLINED;
                }
            }
            cache->provider = list->provider;
            cache->provider_name = list->provider_name;
            return OK;
        }
        case DECLINED: {
            /* try again with next cache type */
            list = list->next;
            continue;
        }
        default: {
@@ -222,37 +214,6 @@ 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)
{
    return (h->write_headers(h, r, info));
}
apr_status_t cache_write_entity_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *b) 
{
    return (h->write_body(h, r, b));
}

apr_status_t cache_read_entity_headers(cache_handle_t *h, request_rec *r)
{
    apr_status_t rv;
    cache_info *info = &(h->cache_obj->info);

    /* Build the header table from info in the info struct */
    rv = h->read_headers(h, r);
    if (rv != APR_SUCCESS) {
        return rv;
    }

    r->filename = apr_pstrdup(r->pool, info->filename );

    return APR_SUCCESS;
}
apr_status_t cache_read_entity_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *b) 
{
    return (h->read_body(h, p, b));
}

apr_status_t cache_generate_key_default( request_rec *r, apr_pool_t*p, char**key ) 
{
    if (r->hostname) {
@@ -263,17 +224,3 @@ apr_status_t cache_generate_key_default( request_rec *r, apr_pool_t*p, char**key
    }
    return APR_SUCCESS;
}

APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, create_entity, 
                                      (cache_handle_t *h, request_rec *r, const char *type, 
                                      const char *urlkey, apr_off_t len),
                                      (h, r, type,urlkey,len),DECLINED)
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, open_entity,  
                                      (cache_handle_t *h, request_rec *r, const char *type, 
                                      const char *urlkey),(h,r,type,urlkey),
                                      DECLINED)
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(cache, CACHE, int, remove_url, 
                                    (const char *type, const char *urlkey),
                                    (type,urlkey),OK,DECLINED)

+74 −55
Changes for modules/experimental/cache_util.c: 74 added lines, 55 removed lines.
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@

#include "mod_cache.h"


#include <ap_provider.h>

/* -------------------------------------------------------------- */

@@ -28,76 +28,76 @@ CACHE_DECLARE(int) ap_cache_request_is_conditional(request_rec *r)
        apr_table_get(r->headers_in, "If-None-Match") ||
        apr_table_get(r->headers_in, "If-Modified-Since") ||
        apr_table_get(r->headers_in, "If-Unmodified-Since")) {

        return 1;
    }
    return 0;
}


/* remove other filters from filter stack */
CACHE_DECLARE(void) ap_cache_reset_output_filters(request_rec *r)
{
    ap_filter_t *f = r->output_filters;

    while (f) {
        if (!strcasecmp(f->frec->name, "CORE") ||
            !strcasecmp(f->frec->name, "CONTENT_LENGTH") ||
            !strcasecmp(f->frec->name, "HTTP_HEADER")) {
            f = f->next;
            continue;
        }
        else {
            ap_remove_output_filter(f);
            f = f->next;
        }
    }
}

CACHE_DECLARE(const char *)ap_cache_get_cachetype(request_rec *r, 
CACHE_DECLARE(cache_provider_list *)ap_cache_get_providers(request_rec *r,
                                                  cache_server_conf *conf, 
                                                  const char *url)
{
    const char *type = NULL;
    cache_provider_list *providers = NULL;
    int i;

    /* we can't cache if there's no URL */
    /* Is this case even possible?? */
    if (!url) return NULL;

    /* 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;
        if ((ent[i].url) && !strncasecmp(url, ent[i].url, ent[i].urllen)) {
            /* Fetch from global config and add to the list. */
            cache_provider *provider;
            provider = ap_lookup_provider(CACHE_PROVIDER_GROUP, ent[i].type,
                                          "0");
            if (!provider) {
                /* Log an error! */
            }
            else {
                type = apr_pstrcat(r->pool, type, ",", thistype, NULL);
                cache_provider_list *newp;
                newp = apr_pcalloc(r->pool, sizeof(cache_provider_list));
                newp->provider_name = ent[i].type;
                newp->provider = provider;

                if (!providers) {
                    providers = newp;
                }
                else {
                    cache_provider_list *last = providers;

                    while (last->next) {
                        last = last->next;
                    }
                    last->next = newp;
                }
            }
        }
    }

    /* then loop through all the cachedisable entries */
    /* Looking for urls that contain the full cachedisable url and possibly more. */
    /*   This means we are disabling cachedisable url and below... */
    /* then loop through all the cachedisable entries
     * Looking for urls that contain the full cachedisable url and possibly
     * more.
     * This means we are disabling cachedisable url and below...
     */
    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;
        if ((ent[i].url) && !strncasecmp(url, ent[i].url, ent[i].urllen)) {
            /* Stop searching now. */
            return NULL;
        }
    }

    return type;
    return providers;
}


/* do a HTTP/1.1 age calculation */
CACHE_DECLARE(apr_int64_t) ap_cache_current_age(cache_info *info, const apr_time_t age_value,
CACHE_DECLARE(apr_int64_t) ap_cache_current_age(cache_info *info,
                                                const apr_time_t age_value,
                                                apr_time_t now)
{
    apr_time_t apparent_age, corrected_received_age, response_delay,
@@ -121,7 +121,8 @@ CACHE_DECLARE(apr_int64_t) ap_cache_current_age(cache_info *info, const apr_time
CACHE_DECLARE(int) ap_cache_check_freshness(cache_request_rec *cache, 
                                            request_rec *r)
{
    apr_int64_t age, maxage_req, maxage_cresp, maxage, smaxage, maxstale, minfresh;
    apr_int64_t age, maxage_req, maxage_cresp, maxage, smaxage, maxstale;
    apr_int64_t minfresh;
    int age_in_errhdr = 0;
    const char *cc_cresp, *cc_ceresp, *cc_req;
    const char *agestr = NULL;
@@ -134,7 +135,7 @@ CACHE_DECLARE(int) ap_cache_check_freshness(cache_request_rec *cache,
     * We now want to check if our cached data is still fresh. This depends
     * on a few things, in this order:
     *
     * - RFC2616 14.9.4 End to end reload, Cache-Control: no-cache no-cache in
     * - RFC2616 14.9.4 End to end reload, Cache-Control: no-cache. no-cache in
     * either the request or the cached response means that we must
     * revalidate the request unconditionally, overriding any expiration
     * mechanism. It's equivalent to max-age=0,must-revalidate.
@@ -182,50 +183,64 @@ CACHE_DECLARE(int) ap_cache_check_freshness(cache_request_rec *cache,
    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))
    if (cc_cresp && ap_cache_liststr(r->pool, cc_cresp, "s-maxage", &val)) {
        smaxage = apr_atoi64(val);
    }
    else if (cc_ceresp && ap_cache_liststr(r->pool, cc_ceresp, "s-maxage", &val)) {
        smaxage = apr_atoi64(val);
    }
    else
    else {
        smaxage = -1;
    }

    /* extract max-age from request */
    if (cc_req && ap_cache_liststr(r->pool, cc_req, "max-age", &val))
    if (cc_req && ap_cache_liststr(r->pool, cc_req, "max-age", &val)) {
        maxage_req = apr_atoi64(val);
    else
    }
    else {
        maxage_req = -1;
    }

    /* extract max-age from response */
    if (cc_cresp && ap_cache_liststr(r->pool, cc_cresp, "max-age", &val))
    if (cc_cresp && ap_cache_liststr(r->pool, cc_cresp, "max-age", &val)) {
        maxage_cresp = apr_atoi64(val);
    }
    else if (cc_ceresp && ap_cache_liststr(r->pool, cc_ceresp, "max-age", &val)) {
        maxage_cresp = apr_atoi64(val);
    }
    else
    {
        maxage_cresp = -1;
    }

    /*
     * if both maxage request and response, the smaller one takes priority
     */
    if (-1 == maxage_req)
    if (-1 == maxage_req) {
        maxage = maxage_cresp;
    else if (-1 == maxage_cresp)
    }
    else if (-1 == maxage_cresp) {
        maxage = maxage_req;
    else
    }
    else {
        maxage = MIN(maxage_req, maxage_cresp);
    }

    /* extract max-stale */
    if (cc_req && ap_cache_liststr(r->pool, cc_req, "max-stale", &val))
    if (cc_req && ap_cache_liststr(r->pool, cc_req, "max-stale", &val)) {
        maxstale = apr_atoi64(val);
    else
    }
    else {
        maxstale = 0;
    }

    /* extract min-fresh */
    if (cc_req && ap_cache_liststr(r->pool, cc_req, "min-fresh", &val))
    if (cc_req && ap_cache_liststr(r->pool, cc_req, "min-fresh", &val)) {
        minfresh = apr_atoi64(val);
    else
    }
    else {
        minfresh = 0;
    }

    /* override maxstale if must-revalidate or proxy-revalidate */
    if (maxstale && ((cc_cresp &&
@@ -275,7 +290,8 @@ CACHE_DECLARE(int) ap_cache_check_freshness(cache_request_rec *cache,
        /* add warning if maxstale overrode freshness calculation */
        if (!(((smaxage != -1) && age < smaxage) ||
              ((maxage != -1) && age < maxage) ||
              (info->expire != APR_DATE_BAD && (info->expire - info->date) > age))) {
              (info->expire != APR_DATE_BAD &&
               (info->expire - info->date) > age))) {
            /* make sure we don't stomp on a previous warning */
            if ((warn_head == NULL) ||
                ((warn_head != NULL) && (ap_strstr_c(warn_head, "110") == NULL))) {
@@ -303,6 +319,7 @@ CACHE_DECLARE(int) ap_cache_check_freshness(cache_request_rec *cache,
    }
    return 0;        /* Cache object is stale */
}

/*
 * list is a comma-separated list of case-insensitive tokens, with
 * optional whitespace around the tokens.
@@ -380,7 +397,8 @@ CACHE_DECLARE(int) ap_cache_liststr(apr_pool_t *p, const char *list,
}

/* return each comma separated token, one at a time */
CACHE_DECLARE(const char *)ap_cache_tokstr(apr_pool_t *p, const char *list, const char **str)
CACHE_DECLARE(const char *)ap_cache_tokstr(apr_pool_t *p, const char *list,
                                           const char **str)
{
    apr_size_t i;
    const char *s;
@@ -487,7 +505,8 @@ static void cache_hash(const char *it, char *val, int ndepth, int nlength)
    val[i + 22 - k] = '\0';
}

CACHE_DECLARE(char *)generate_name(apr_pool_t *p, int dirlevels, int dirlength, const char *name)
CACHE_DECLARE(char *)generate_name(apr_pool_t *p, int dirlevels,
                                   int dirlength, const char *name)
{
    char hashfile[66];
    cache_hash(name, hashfile, dirlevels, dirlength);
+134 −182

File changed.

Preview size limit exceeded, changes collapsed.

+41 −39
Changes for modules/experimental/mod_cache.h: 41 added lines, 39 removed lines.
Original line number Diff line number Diff line
@@ -64,11 +64,7 @@
#include <arpa/inet.h>
#endif

/* USE_ATOMICS should be replaced with the appropriate APR feature macro */
#define USE_ATOMICS
#ifdef USE_ATOMICS
#include "apr_atomic.h"
#endif

#ifndef MAX
#define MAX(a,b)                ((a) > (b) ? (a) : (b))
@@ -79,7 +75,6 @@

/* default completion is 60% */
#define DEFAULT_CACHE_COMPLETION (60)
#define MAX_URL_LENGTH 1024
#define MSEC_ONE_DAY    ((apr_time_t)(86400*APR_USEC_PER_SEC)) /* one day, in microseconds */
#define MSEC_ONE_HR     ((apr_time_t)(3600*APR_USEC_PER_SEC))  /* one hour, in microseconds */
#define MSEC_ONE_MIN    ((apr_time_t)(60*APR_USEC_PER_SEC))    /* one minute, in microseconds */
@@ -112,10 +107,12 @@
struct cache_enable {
    const char *url;
    const char *type;
    apr_size_t urllen;
};

struct cache_disable {
    const char *url;
    apr_size_t urllen;
};

/* static information about the local cache */
@@ -175,29 +172,46 @@ struct cache_object {
    void *vobj;         /* Opaque portion (specific to the cache implementation) of the cache object */
    apr_size_t count;   /* Number of body bytes written to the cache so far */
    int complete;
#ifdef USE_ATOMICS
    apr_atomic_t refcount;
#else
    apr_size_t refcount;
#endif
    apr_uint32_t refcount;
    apr_size_t cleanup;
};

typedef struct cache_handle cache_handle_t;

#define CACHE_PROVIDER_GROUP "cache"

typedef struct {
    int (*remove_entity) (cache_handle_t *h);
    apr_status_t (*store_headers)(cache_handle_t *h, request_rec *r, cache_info *i);
    apr_status_t (*store_body)(cache_handle_t *h, request_rec *r, apr_bucket_brigade *b);
    apr_status_t (*recall_headers) (cache_handle_t *h, request_rec *r);
    apr_status_t (*recall_body) (cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb); 
    int (*create_entity) (cache_handle_t *h, request_rec *r,
                           const char *urlkey, apr_off_t len);
    int (*open_entity) (cache_handle_t *h, request_rec *r,
                           const char *urlkey);
    int (*remove_url) (const char *urlkey);
} cache_provider;

/* A linked-list of authn providers. */
typedef struct cache_provider_list cache_provider_list;

struct cache_provider_list {
    const char *provider_name;
    const cache_provider *provider;
    cache_provider_list *next;
};

struct cache_handle {
    cache_object_t *cache_obj;
    int (*remove_entity) (cache_handle_t *h);
    apr_status_t (*write_headers)(cache_handle_t *h, request_rec *r, cache_info *i);
    apr_status_t (*write_body)(cache_handle_t *h, request_rec *r, apr_bucket_brigade *b);
    apr_status_t (*read_headers) (cache_handle_t *h, request_rec *r);
    apr_status_t (*read_body) (cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb); 
    apr_table_t *req_hdrs;   /* These are the original request headers */
};

/* per request cache information */
typedef struct {
    const char *types;			/* the types of caches allowed */
    const char *type;			/* the type of cache selected */
    cache_provider_list *providers;         /* possible cache providers */
    const cache_provider *provider;         /* current cache provider */
    const char *provider_name;              /* current cache provider name */
    int fresh;				/* is the entitey fresh? */
    cache_handle_t *handle;		/* current cache handle */
    int in_checked;			/* CACHE_IN must cache the entity */
@@ -227,8 +241,7 @@ CACHE_DECLARE(char *) generate_name(apr_pool_t *p, int dirlevels,
                                    int dirlength, 
                                    const char *name);
CACHE_DECLARE(int) ap_cache_request_is_conditional(request_rec *r);
CACHE_DECLARE(void) ap_cache_reset_output_filters(request_rec *r);
CACHE_DECLARE(const char *)ap_cache_get_cachetype(request_rec *r, cache_server_conf *conf, const char *url);
CACHE_DECLARE(cache_provider_list *)ap_cache_get_providers(request_rec *r, cache_server_conf *conf, const char *url);
CACHE_DECLARE(int) ap_cache_liststr(apr_pool_t *p, const char *list,
                                    const char *key, char **val);
CACHE_DECLARE(const char *)ap_cache_tokstr(apr_pool_t *p, const char *list, const char **str);
@@ -241,10 +254,9 @@ CACHE_DECLARE(apr_table_t *)ap_cache_cacheable_hdrs_out(apr_pool_t *pool, apr_ta
/**
 * cache_storage.c
 */
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_off_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);
int cache_remove_url(request_rec *r, char *url);
int cache_create_entity(request_rec *r, char *url, apr_off_t size);
int cache_select_url(request_rec *r, char *url);
apr_status_t cache_generate_key_default( request_rec *r, apr_pool_t*p, char**key );
/**
 * create a key for the cache based on the request record
@@ -252,12 +264,13 @@ apr_status_t cache_generate_key_default( request_rec *r, apr_pool_t*p, char**key
 */
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_status_t cache_write_entity_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *bb);

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_pool_t *p, apr_bucket_brigade *bb);
/*
apr_status_t cache_store_entity_headers(cache_handle_t *h, request_rec *r, cache_info *info);
apr_status_t cache_store_entity_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *bb);

apr_status_t cache_recall_entity_headers(cache_handle_t *h, request_rec *r);
apr_status_t cache_recall_entity_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb);
*/

/* hooks */

@@ -282,17 +295,6 @@ apr_status_t cache_read_entity_body(cache_handle_t *h, apr_pool_t *p, apr_bucket
#define CACHE_DECLARE_DATA             __declspec(dllimport)
#endif

APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, create_entity, 
                          (cache_handle_t *h, request_rec *r, const char *type,
                           const char *urlkey, apr_off_t len))
APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, open_entity,  
                          (cache_handle_t *h, request_rec *r, const char *type,
                           const char *urlkey))
APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, remove_url, 
                          (const char *type, const char *urlkey))



APR_DECLARE_OPTIONAL_FN(apr_status_t, 
                        ap_cache_generate_key, 
                        (request_rec *r, apr_pool_t*p, char**key ));
Loading