mirror of
https://github.com/apache/httpd.git
synced 2026-01-26 19:01:35 +03:00
Introduce the notion of a multi part cache object. Part of the cache_object
is common across any cache implementation, the other part is private to the particular implementation (eg, mem_cache_object_t/mod_mem_cache). Use a cache_handle_t allocated out of the request pool to hold references to the callback functions and common cache object. The cache_handle_t contains implementation specific callback functions and a reference to a common cache_object_t. The cache_object_t contains a reference to an implementation specific cache object extension (mem_cache_object_t for example). All this simplifies managing the callback function pointers (don't want to save them in each cache entry) and collections of cache_object_t keyed to a single url. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@90994 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -101,7 +101,7 @@ 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)
|
||||
{
|
||||
cache_handle *h;
|
||||
cache_handle_t *h = apr_pcalloc(r->pool, sizeof(h));
|
||||
const char *next = types;
|
||||
const char *type;
|
||||
apr_status_t rv;
|
||||
@@ -111,7 +111,7 @@ int cache_create_entity(request_rec *r, const char *types, char *url, apr_size_t
|
||||
/* 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, type, url, size)) {
|
||||
switch (rv = cache_run_create_entity(h, type, url, size)) {
|
||||
case OK: {
|
||||
cache->handle = h;
|
||||
return OK;
|
||||
@@ -134,7 +134,7 @@ int cache_create_entity(request_rec *r, const char *types, char *url, apr_size_t
|
||||
* 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 *h)
|
||||
int cache_remove_entity(request_rec *r, const char *types, cache_handle_t *h)
|
||||
{
|
||||
h->remove_entity(h);
|
||||
return 1;
|
||||
@@ -160,17 +160,25 @@ int cache_select_url(request_rec *r, const char *types, char *url)
|
||||
&cache_module);
|
||||
|
||||
/* go through the cache types till we get a match */
|
||||
cache->handle = apr_palloc(r->pool, sizeof(cache_handle));
|
||||
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))) {
|
||||
case OK: {
|
||||
/* cool bananas! */
|
||||
/*** loop through returned entities */
|
||||
/*** do freshness calculation here */
|
||||
cache->fresh = 1;
|
||||
/*** do content negotiation here */
|
||||
/* XXX:
|
||||
* Handle being returned a collection of entities.
|
||||
*/
|
||||
|
||||
/* Has the cache entry expired? */
|
||||
#if 0
|
||||
if (r->request_time > cache->handle... need to get info out of the cache... info.expire)
|
||||
cache->fresh = 0;
|
||||
else
|
||||
#endif
|
||||
cache->fresh = 1;
|
||||
|
||||
/*** do content negotiation here */
|
||||
return OK;
|
||||
}
|
||||
case DECLINED: {
|
||||
@@ -188,13 +196,13 @@ int cache_select_url(request_rec *r, const char *types, char *url)
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
apr_status_t cache_write_entity_headers(cache_handle *h, request_rec *r, cache_info *info,
|
||||
apr_status_t cache_write_entity_headers(cache_handle_t *h, request_rec *r, cache_info *info,
|
||||
apr_table_t *headers)
|
||||
{
|
||||
h->write_headers(h, r, info, headers);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
apr_status_t cache_write_entity_body(cache_handle *h, apr_bucket_brigade *b)
|
||||
apr_status_t cache_write_entity_body(cache_handle_t *h, apr_bucket_brigade *b)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
if (h->write_body(h, b) != OK) {
|
||||
@@ -202,29 +210,27 @@ apr_status_t cache_write_entity_body(cache_handle *h, apr_bucket_brigade *b)
|
||||
return rv;
|
||||
}
|
||||
|
||||
apr_status_t cache_read_entity_headers(cache_handle *h, request_rec *r,
|
||||
apr_status_t cache_read_entity_headers(cache_handle_t *h, request_rec *r,
|
||||
apr_table_t **headers)
|
||||
{
|
||||
cache_info *info;
|
||||
|
||||
/* Build the header table from info in the info struct */
|
||||
*headers = apr_table_make(r->pool, 15);
|
||||
|
||||
h->read_headers(h, r, &info, *headers);
|
||||
h->read_headers(h, r, *headers);
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
apr_status_t cache_read_entity_body(cache_handle *h, apr_bucket_brigade *b)
|
||||
apr_status_t cache_read_entity_body(cache_handle_t *h, apr_bucket_brigade *b)
|
||||
{
|
||||
h->read_body(h, b);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, create_entity,
|
||||
(cache_handle **hp, const char *type,
|
||||
char *url, apr_size_t len),(hp,type,url,len),DECLINED)
|
||||
(cache_handle_t *h, const char *type,
|
||||
char *url, apr_size_t len),(h,type,url,len),DECLINED)
|
||||
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(cache, CACHE, int, open_entity,
|
||||
(cache_handle *h, const char *type,
|
||||
(cache_handle_t *h, const char *type,
|
||||
char *url),(h,type,url),DECLINED)
|
||||
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(cache, CACHE, int, remove_url,
|
||||
(const char *type, char *url),(type,url),OK,DECLINED)
|
||||
|
||||
@@ -186,13 +186,13 @@ int ap_url_cache_handler(request_rec *r)
|
||||
|
||||
/* We are in the quick handler hook, which means that no output
|
||||
* filters have been set. So lets run the insert_filter hook.
|
||||
* Humm... Probably should not go through most of these hooks
|
||||
* for a proxy request, so take out all but the basics.
|
||||
* XXX - Should we be inserting filters in the output stream
|
||||
* for proxy requests? Certainly we need the core filters
|
||||
* (byterange, chunking, etc.). I can also see the need to
|
||||
* conditionally insert tag processing filters (e.g. INCLUDES).
|
||||
*/
|
||||
ap_run_insert_filter(r);
|
||||
if (r->proxyreq) {
|
||||
ap_cache_reset_output_filters(r);
|
||||
}
|
||||
|
||||
/* Now add the cache_out filter. cache_out is a FTYPE_CONTENT
|
||||
* which means it will be inserted first in the stream, which
|
||||
* is exactly what we need.
|
||||
|
||||
@@ -146,7 +146,6 @@ typedef struct {
|
||||
int factor_set;
|
||||
int complete; /* Force cache completion after this point */
|
||||
int complete_set;
|
||||
|
||||
} cache_server_conf;
|
||||
|
||||
/* cache info information */
|
||||
@@ -165,21 +164,24 @@ struct cache_info {
|
||||
};
|
||||
|
||||
/* cache handle information */
|
||||
typedef struct cache_handle cache_handle;
|
||||
struct cache_handle {
|
||||
cache_info *info;
|
||||
cache_handle *next;
|
||||
|
||||
void *cache_obj; /* Pointer to cache specific object */
|
||||
typedef struct cache_object cache_object_t;
|
||||
struct cache_object {
|
||||
char *key;
|
||||
cache_object_t *next;
|
||||
cache_info info;
|
||||
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;
|
||||
};
|
||||
|
||||
/* Cache call back functions */
|
||||
int (*remove_entity) (cache_handle *h);
|
||||
int (*write_headers)(cache_handle *h, request_rec *r, cache_info *i, apr_table_t *headers);
|
||||
int (*write_body)(cache_handle *h, apr_bucket_brigade *b);
|
||||
int (*read_headers) (cache_handle *h, request_rec *r, cache_info **i, apr_table_t *headers);
|
||||
int (*read_body) (cache_handle *h, apr_bucket_brigade *bb);
|
||||
|
||||
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_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_body) (cache_handle_t *h, apr_bucket_brigade *bb);
|
||||
};
|
||||
|
||||
/* per request cache information */
|
||||
@@ -187,7 +189,7 @@ typedef struct {
|
||||
const char *types; /* the types of caches allowed */
|
||||
const char *type; /* the type of cache selected */
|
||||
int fresh; /* is the entitey fresh? */
|
||||
cache_handle *handle; /* current cache handle */
|
||||
cache_handle_t *handle; /* current cache handle */
|
||||
int in_checked; /* CACHE_IN must cache the entity */
|
||||
} cache_request_rec;
|
||||
|
||||
@@ -204,15 +206,15 @@ const char *ap_cache_tokstr(apr_pool_t *p, const char *list, const char **str);
|
||||
*/
|
||||
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 *h);
|
||||
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);
|
||||
|
||||
apr_status_t cache_write_entity_headers(cache_handle *h, request_rec *r, cache_info *info,
|
||||
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_body(cache_handle *h, apr_bucket_brigade *bb);
|
||||
apr_status_t cache_write_entity_body(cache_handle_t *h, apr_bucket_brigade *bb);
|
||||
|
||||
apr_status_t cache_read_entity_headers(cache_handle *h, request_rec *r, apr_table_t **headers);
|
||||
apr_status_t cache_read_entity_body(cache_handle *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_body(cache_handle_t *h, apr_bucket_brigade *bb);
|
||||
|
||||
|
||||
/* hooks */
|
||||
@@ -239,10 +241,10 @@ apr_status_t cache_read_entity_body(cache_handle *h, apr_bucket_brigade *bb);
|
||||
#endif
|
||||
|
||||
APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, create_entity,
|
||||
(cache_handle **hp, const char *type,
|
||||
(cache_handle_t *h, const char *type,
|
||||
char *url, apr_size_t len))
|
||||
APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, open_entity,
|
||||
(cache_handle *h, const char *type,
|
||||
(cache_handle_t *h, const char *type,
|
||||
char *url))
|
||||
APR_DECLARE_EXTERNAL_HOOK(cache, CACHE, int, remove_url,
|
||||
(const char *type, char *url))
|
||||
|
||||
@@ -85,16 +85,13 @@ typedef struct {
|
||||
char* val;
|
||||
} cache_header_tbl_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct mem_cache_object {
|
||||
cache_type_e type;
|
||||
char *key;
|
||||
apr_ssize_t num_headers;
|
||||
cache_header_tbl_t *tbl;
|
||||
apr_size_t m_len;
|
||||
void *m;
|
||||
cache_info info;
|
||||
int complete;
|
||||
} cache_object_t;
|
||||
} mem_cache_object_t;
|
||||
|
||||
typedef struct {
|
||||
apr_lock_t *lock;
|
||||
@@ -109,16 +106,17 @@ static mem_cache_conf *sconf;
|
||||
#define CACHEFILE_LEN 20
|
||||
|
||||
/* Forward declarations */
|
||||
static int remove_entity(cache_handle *h);
|
||||
static int write_headers(cache_handle *h, request_rec *r, cache_info *i,
|
||||
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_body(cache_handle *h, apr_bucket_brigade *b);
|
||||
static int read_headers(cache_handle *h, request_rec *r, cache_info **info,
|
||||
apr_table_t *headers);
|
||||
static int read_body(cache_handle *h, apr_bucket_brigade *bb);
|
||||
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_body(cache_handle_t *h, apr_bucket_brigade *bb);
|
||||
|
||||
static void cleanup_cache_object(cache_object_t *obj)
|
||||
{
|
||||
mem_cache_object_t *mobj = obj->vobj;
|
||||
|
||||
/* The cache object has been removed from the cache. Now clean
|
||||
* it up, freeing any storage, closing file descriptors, etc.
|
||||
*/
|
||||
@@ -149,18 +147,25 @@ static void cleanup_cache_object(cache_object_t *obj)
|
||||
}
|
||||
*/
|
||||
|
||||
if (obj->info.content_type)
|
||||
free((char*) obj->info.content_type);
|
||||
if (obj->key)
|
||||
/* Cleanup the cache_object_t */
|
||||
if (obj->key) {
|
||||
free(obj->key);
|
||||
if (obj->m)
|
||||
free(obj->m);
|
||||
|
||||
/* XXX Cleanup the headers */
|
||||
if (obj->num_headers) {
|
||||
|
||||
}
|
||||
free(obj);
|
||||
|
||||
/* Cleanup the mem_cache_object_t */
|
||||
if (!mobj) {
|
||||
return;
|
||||
}
|
||||
if (mobj->m) {
|
||||
free(mobj->m);
|
||||
}
|
||||
|
||||
/* XXX Cleanup the headers */
|
||||
if (mobj->num_headers) {
|
||||
|
||||
}
|
||||
free(mobj);
|
||||
}
|
||||
|
||||
static apr_status_t cleanup_cache_mem(void *sconfv)
|
||||
@@ -203,100 +208,88 @@ static void *create_cache_config(apr_pool_t *p, server_rec *s)
|
||||
return sconf;
|
||||
}
|
||||
|
||||
static int create_entity(cache_handle **hp, const char *type, char *key, apr_size_t len)
|
||||
static int create_entity(cache_handle_t *h, const char *type, char *key, apr_size_t len)
|
||||
{
|
||||
cache_object_t *obj, *eobj = NULL;
|
||||
cache_handle *h;
|
||||
cache_object_t *obj, *tmp_obj;
|
||||
mem_cache_object_t *mobj;
|
||||
|
||||
/* Create the cache handle and begin populating it.
|
||||
*/
|
||||
if (strcasecmp(type, "mem")) {
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
/* Check len to see if it is withing acceptable bounds
|
||||
* XXX max cache check should be configurable variable.
|
||||
/* XXX Check len to see if it is withing acceptable bounds
|
||||
* max cache check should be configurable variable.
|
||||
*/
|
||||
if (len < 0 || len > MAX_CACHE) {
|
||||
return DECLINED;
|
||||
}
|
||||
/* Check total cache size and number of entries. Are they within the
|
||||
/* XXX Check total cache size and number of entries. Are they within the
|
||||
* configured limits? If not, kick off garbage collection thread.
|
||||
*/
|
||||
|
||||
/* Allocate the cache_handle and set up call back functions specific to
|
||||
* this cache handler.
|
||||
*/
|
||||
h = malloc(sizeof(cache_handle));
|
||||
*hp = h;
|
||||
if (!h) {
|
||||
/* handle the error */
|
||||
return DECLINED;
|
||||
}
|
||||
h->read_body = &read_body;
|
||||
h->read_headers = &read_headers;
|
||||
h->write_body = &write_body;
|
||||
h->write_headers = &write_headers;
|
||||
|
||||
/* Allocate and initialize the cache object. The cache object is
|
||||
* unique to this implementation.
|
||||
*/
|
||||
/* Allocate and initialize cache_object_t */
|
||||
obj = malloc(sizeof(*obj));
|
||||
if (!obj) {
|
||||
/* Handle ther error */
|
||||
free(h);
|
||||
return DECLINED;
|
||||
}
|
||||
memset(obj,'\0', sizeof(*obj));
|
||||
|
||||
obj->key = malloc(strlen(key) + 1);
|
||||
if (!obj->key) {
|
||||
/* XXX Uuugh, there has got to be a better way to manage memory.
|
||||
*/
|
||||
free(h);
|
||||
free(obj);
|
||||
return DECLINED;
|
||||
}
|
||||
obj->m_len = len; /* One of these len fields can go */
|
||||
obj->info.len = len;
|
||||
strncpy(obj->key, key, strlen(key) + 1);
|
||||
h->cache_obj = (void *) obj;
|
||||
|
||||
/* Mark the cache object as incomplete and put it into the cache */
|
||||
obj->complete = 0;
|
||||
obj->info.len = len;
|
||||
obj->complete = 0; /* Cache object is not complete */
|
||||
|
||||
/* XXX Need a way to insert into the cache w/o such coarse grained locking */
|
||||
|
||||
/* Allocate and init mem_cache_object_t */
|
||||
mobj = malloc(sizeof(*mobj));
|
||||
if (!mobj) {
|
||||
/* XXX: Cleanup */
|
||||
cleanup_cache_object(obj);
|
||||
}
|
||||
memset(mobj,'\0', sizeof(*mobj));
|
||||
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 */
|
||||
|
||||
|
||||
/* Place the cache_object_t into the hash table
|
||||
* XXX Need a way to insert into the cache w/o such coarse grained locking
|
||||
* XXX Need to enable caching multiple cache objects (representing different
|
||||
* views of the same content) under a single search key
|
||||
*/
|
||||
if (sconf->lock) {
|
||||
apr_lock_acquire(sconf->lock);
|
||||
}
|
||||
/* Do not allow the new cache object to replace an existing cache object.
|
||||
* We should find eobj only when another thread is in the process of
|
||||
* caching the same object as this thread. If we hit this case, decline
|
||||
* the request.
|
||||
*/
|
||||
eobj = (cache_object_t *) apr_hash_get(sconf->cacheht, key, APR_HASH_KEY_STRING);
|
||||
if (!eobj) {
|
||||
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);
|
||||
}
|
||||
if (sconf->lock) {
|
||||
apr_lock_release(sconf->lock);
|
||||
}
|
||||
|
||||
if (eobj) {
|
||||
if (tmp_obj) {
|
||||
/* This thread collided with another thread loading the same object
|
||||
* into the cache at the same time. Defer to the other thread which
|
||||
* is further along.
|
||||
*/
|
||||
cleanup_cache_object(obj);
|
||||
free(h);
|
||||
*hp = NULL;
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
/* Populate the cache handle */
|
||||
h->cache_obj = obj;
|
||||
h->read_body = &read_body;
|
||||
h->read_headers = &read_headers;
|
||||
h->write_body = &write_body;
|
||||
h->write_headers = &write_headers;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int open_entity(cache_handle *h, const char *type, char *key)
|
||||
static int open_entity(cache_handle_t *h, const char *type, char *key)
|
||||
{
|
||||
cache_object_t *obj;
|
||||
|
||||
@@ -322,15 +315,13 @@ static int open_entity(cache_handle *h, const char *type, char *key)
|
||||
h->write_body = &write_body;
|
||||
h->write_headers = &write_headers;
|
||||
h->cache_obj = obj;
|
||||
if (!obj || !(obj->complete)) {
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int remove_entity(cache_handle *h)
|
||||
static int remove_entity(cache_handle_t *h)
|
||||
{
|
||||
cache_object_t *obj = (cache_object_t *) h->cache_obj;
|
||||
cache_object_t *obj = h->cache_obj;
|
||||
|
||||
if (sconf->lock) {
|
||||
apr_lock_acquire(sconf->lock);
|
||||
@@ -342,9 +333,6 @@ static int remove_entity(cache_handle *h)
|
||||
|
||||
cleanup_cache_object(obj);
|
||||
|
||||
/* Reinit the cache_handle fields? */
|
||||
h->cache_obj = NULL;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -390,26 +378,24 @@ static int remove_url(const char *type, char *key)
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int read_headers(cache_handle *h, request_rec *r, cache_info **info,
|
||||
apr_table_t *headers)
|
||||
static int read_headers(cache_handle_t *h, request_rec *r, apr_table_t *headers)
|
||||
{
|
||||
cache_object_t *obj = (cache_object_t*) h->cache_obj;
|
||||
mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < obj->num_headers; ++i) {
|
||||
apr_table_setn(headers, obj->tbl[i].hdr, obj->tbl[i].val);
|
||||
for (i = 0; i < mobj->num_headers; ++i) {
|
||||
apr_table_setn(headers, mobj->tbl[i].hdr, mobj->tbl[i].val);
|
||||
}
|
||||
*info = &(obj->info);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int read_body(cache_handle *h, apr_bucket_brigade *bb)
|
||||
static int read_body(cache_handle_t *h, apr_bucket_brigade *bb)
|
||||
{
|
||||
apr_bucket *b;
|
||||
cache_object_t *obj = h->cache_obj;
|
||||
mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj;
|
||||
|
||||
b = apr_bucket_immortal_create(obj->m, obj->m_len);
|
||||
b = apr_bucket_immortal_create(mobj->m, mobj->m_len);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
b = apr_bucket_eos_create();
|
||||
APR_BRIGADE_INSERT_TAIL(bb, b);
|
||||
@@ -417,9 +403,9 @@ static int read_body(cache_handle *h, apr_bucket_brigade *bb)
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int write_headers(cache_handle *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, apr_table_t *headers)
|
||||
{
|
||||
cache_object_t *obj = (cache_object_t*) 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;
|
||||
@@ -427,8 +413,9 @@ static int write_headers(cache_handle *h, request_rec *r, cache_info *info, apr_
|
||||
char *buf;
|
||||
|
||||
/* Precompute how much storage we need to hold the headers */
|
||||
obj->tbl = malloc(sizeof(cache_header_tbl_t) * headers->a.nelts);
|
||||
if (NULL == obj->tbl) {
|
||||
mobj->tbl = malloc(sizeof(cache_header_tbl_t) * headers->a.nelts);
|
||||
if (NULL == mobj->tbl) {
|
||||
/* cleanup_cache_obj(h->cache_obj); */
|
||||
return DECLINED;
|
||||
}
|
||||
for (i = 0; i < headers->a.nelts; ++i) {
|
||||
@@ -440,18 +427,19 @@ static int write_headers(cache_handle *h, request_rec *r, cache_info *info, apr_
|
||||
/* Transfer the headers into a contiguous memory block */
|
||||
buf = malloc(len);
|
||||
if (!buf) {
|
||||
free(obj->tbl);
|
||||
obj->tbl = NULL;
|
||||
free(mobj->tbl);
|
||||
mobj->tbl = NULL;
|
||||
/* cleanup_cache_obj(h->cache_obj); */
|
||||
return DECLINED;
|
||||
}
|
||||
obj->num_headers = headers->a.nelts;
|
||||
for (i = 0; i < obj->num_headers; ++i) {
|
||||
obj->tbl[i].hdr = &buf[idx];
|
||||
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;
|
||||
|
||||
obj->tbl[i].val = &buf[idx];
|
||||
mobj->tbl[i].val = &buf[idx];
|
||||
len = strlen(elts[i].val) + 1;
|
||||
strncpy(&buf[idx], elts[i].val, len);
|
||||
idx+=len;
|
||||
@@ -476,10 +464,10 @@ static int write_headers(cache_handle *h, request_rec *r, cache_info *info, apr_
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int write_body(cache_handle *h, apr_bucket_brigade *b)
|
||||
static int write_body(cache_handle_t *h, apr_bucket_brigade *b)
|
||||
{
|
||||
apr_status_t rv;
|
||||
cache_object_t *obj = (cache_object_t *) h->cache_obj;
|
||||
mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj;
|
||||
apr_read_type_e eblock = APR_BLOCK_READ;
|
||||
apr_bucket *e;
|
||||
char *cur;
|
||||
@@ -488,15 +476,15 @@ static int write_body(cache_handle *h, apr_bucket_brigade *b)
|
||||
* Enable this decision to be configured....
|
||||
* XXX cache buckets...
|
||||
*/
|
||||
if (obj->m == NULL) {
|
||||
obj->m = malloc(obj->m_len);
|
||||
if (obj->m == NULL) {
|
||||
if (mobj->m == NULL) {
|
||||
mobj->m = malloc(mobj->m_len);
|
||||
if (mobj->m == NULL) {
|
||||
/* Cleanup cache entry and return */
|
||||
}
|
||||
obj->type = CACHE_TYPE_HEAP;
|
||||
h->count = 0;
|
||||
mobj->type = CACHE_TYPE_HEAP;
|
||||
h->cache_obj->count = 0;
|
||||
}
|
||||
cur = (char*) obj->m + h->count;
|
||||
cur = (char*) mobj->m + h->cache_obj->count;
|
||||
|
||||
/* Iterate accross the brigade and populate the cache storage */
|
||||
APR_BRIGADE_FOREACH(e, b) {
|
||||
@@ -504,7 +492,7 @@ static int write_body(cache_handle *h, apr_bucket_brigade *b)
|
||||
apr_size_t len;
|
||||
|
||||
if (APR_BUCKET_IS_EOS(e)) {
|
||||
obj->complete = 1;
|
||||
h->cache_obj->complete = 1;
|
||||
break;
|
||||
}
|
||||
rv = apr_bucket_read(e, &s, &len, eblock);
|
||||
@@ -515,12 +503,12 @@ static int write_body(cache_handle *h, apr_bucket_brigade *b)
|
||||
if (len ) {
|
||||
memcpy(cur, s, len);
|
||||
cur+=len;
|
||||
h->count+=len;
|
||||
h->cache_obj->count+=len;
|
||||
}
|
||||
/* This should not happen, but if it does, we are in BIG trouble
|
||||
* cause we just stomped all over the heap.
|
||||
*/
|
||||
AP_DEBUG_ASSERT(h->count > obj->m_len);
|
||||
AP_DEBUG_ASSERT(h->cache_object->count > mobj->m_len);
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
Reference in New Issue
Block a user