📄 mod_mem_cache.c
字号:
/* CACHE_TYPE_FILE is only valid for local content handled by the * default handler. Need a better way to check if the file is * local or not. */ if (!r->filename) { return DECLINED; } } /* Allocate and initialize cache_object_t */ obj = calloc(1, sizeof(*obj)); if (!obj) { return DECLINED; } key_len = strlen(key) + 1; obj->key = malloc(key_len); if (!obj->key) { cleanup_cache_object(obj); return DECLINED; } memcpy((void*)obj->key, key, key_len); /* Allocate and init mem_cache_object_t */ mobj = calloc(1, sizeof(*mobj)); if (!mobj) { cleanup_cache_object(obj); return DECLINED; } /* Finish initing the cache object */ apr_atomic_set32(&obj->refcount, 1); mobj->total_refs = 1; obj->complete = 0; obj->vobj = mobj; /* Safe cast: We tested < sconf->max_cache_object_size above */ mobj->m_len = (apr_size_t)len; mobj->type = type_e; /* Place the cache_object_t into the hash table. * Note: Perhaps we should wait to put the object in the * hash table when the object is complete? I add the object here to * avoid multiple threads attempting to cache the same content only * to discover at the very end that only one of them will succeed. * Furthermore, adding the cache object to the table at the end could * open up a subtle but easy to exploit DoS hole: someone could request * a very large file with multiple requests. Better to detect this here * rather than after the cache object has been completely built and * initialized... * XXX Need a way to insert into the cache w/o such coarse grained locking */ if (sconf->lock) { apr_thread_mutex_lock(sconf->lock); } tmp_obj = (cache_object_t *) cache_find(sconf->cache_cache, key); if (!tmp_obj) { cache_insert(sconf->cache_cache, obj); /* Add a refcount to account for the reference by the * hashtable in the cache. Refcount should be 2 now, one * for this thread, and one for the cache. */ apr_atomic_inc32(&obj->refcount); } if (sconf->lock) { apr_thread_mutex_unlock(sconf->lock); } 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); return DECLINED; } apr_pool_cleanup_register(r->pool, obj, decrement_refcount, apr_pool_cleanup_null); /* Populate the cache handle */ h->cache_obj = obj; return OK;}static int create_mem_entity(cache_handle_t *h, request_rec *r, const char *key, apr_off_t len){ return create_entity(h, CACHE_TYPE_HEAP, r, key, len);}static int create_fd_entity(cache_handle_t *h, request_rec *r, const char *key, apr_off_t len){ return create_entity(h, CACHE_TYPE_FILE, r, key, len);}static int open_entity(cache_handle_t *h, request_rec *r, const char *key){ cache_object_t *obj; /* Look up entity keyed to 'url' */ if (sconf->lock) { apr_thread_mutex_lock(sconf->lock); } obj = (cache_object_t *) cache_find(sconf->cache_cache, key); if (obj) { if (obj->complete) { request_rec *rmain=r, *rtmp; apr_atomic_inc32(&obj->refcount); /* cache is worried about overall counts, not 'open' ones */ cache_update(sconf->cache_cache, obj); /* If this is a subrequest, register the cleanup against * the main request. This will prevent the cache object * from being cleaned up from under the request after the * subrequest is destroyed. */ rtmp = r; while (rtmp) { rmain = rtmp; rtmp = rmain->main; } apr_pool_cleanup_register(rmain->pool, obj, decrement_refcount, apr_pool_cleanup_null); } else { obj = NULL; } } if (sconf->lock) { apr_thread_mutex_unlock(sconf->lock); } if (!obj) { return DECLINED; } /* Initialize the cache_handle */ h->cache_obj = obj; h->req_hdrs = NULL; /* Pick these up in recall_headers() */ return OK;}/* remove_entity() * Notes: * refcount should be at least 1 upon entry to this function to account * for this thread's reference to the object. If the refcount is 1, then * object has been removed from the cache by another thread and this thread * is the last thread accessing the object. */static int remove_entity(cache_handle_t *h){ cache_object_t *obj = h->cache_obj; cache_object_t *tobj = NULL; if (sconf->lock) { apr_thread_mutex_lock(sconf->lock); } /* If the entity is still in the cache, remove it and decrement the * refcount. If the entity is not in the cache, do nothing. In both cases * decrement_refcount called by the last thread referencing the object will * trigger the cleanup. */ tobj = cache_find(sconf->cache_cache, obj->key); if (tobj == obj) { cache_remove(sconf->cache_cache, obj); apr_atomic_dec32(&obj->refcount); } if (sconf->lock) { apr_thread_mutex_unlock(sconf->lock); } return OK;}static apr_status_t serialize_table(cache_header_tbl_t **obj, apr_ssize_t *nelts, apr_table_t *table){ const apr_array_header_t *elts_arr = apr_table_elts(table); apr_table_entry_t *elts = (apr_table_entry_t *) elts_arr->elts; apr_ssize_t i; apr_size_t len = 0; apr_size_t idx = 0; char *buf; *nelts = elts_arr->nelts; if (*nelts == 0 ) { *obj=NULL; return APR_SUCCESS; } *obj = malloc(sizeof(cache_header_tbl_t) * elts_arr->nelts); if (NULL == *obj) { return APR_ENOMEM; } for (i = 0; i < elts_arr->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) { *obj = NULL; return APR_ENOMEM; } for (i = 0; i < *nelts; ++i) { (*obj)[i].hdr = &buf[idx]; len = strlen(elts[i].key) + 1; /* Include NULL terminator */ memcpy(&buf[idx], elts[i].key, len); idx+=len; (*obj)[i].val = &buf[idx]; len = strlen(elts[i].val) + 1; memcpy(&buf[idx], elts[i].val, len); idx+=len; } return APR_SUCCESS;}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_addn(t, ctbl[i].hdr, ctbl[i].val); } return APR_SUCCESS;}/* Define request processing hook handlers *//* remove_url() * Notes: */static int remove_url(cache_handle_t *h, apr_pool_t *p){ cache_object_t *obj; int cleanup = 0; if (sconf->lock) { apr_thread_mutex_lock(sconf->lock); } obj = h->cache_obj; if (obj) { cache_remove(sconf->cache_cache, obj); /* For performance, cleanup cache object after releasing the lock */ cleanup = !apr_atomic_dec32(&obj->refcount); } if (sconf->lock) { apr_thread_mutex_unlock(sconf->lock); } if (cleanup) { cleanup_cache_object(obj); } return OK;}static apr_status_t recall_headers(cache_handle_t *h, request_rec *r){ int rc; mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj; h->req_hdrs = apr_table_make(r->pool, mobj->num_req_hdrs); h->resp_hdrs = apr_table_make(r->pool, mobj->num_header_out); rc = unserialize_table(mobj->req_hdrs, mobj->num_req_hdrs, h->req_hdrs); rc = unserialize_table(mobj->header_out, mobj->num_header_out, h->resp_hdrs); return rc;}static apr_status_t recall_body(cache_handle_t *h, apr_pool_t *p, apr_bucket_brigade *bb){ apr_bucket *b; mem_cache_object_t *mobj = (mem_cache_object_t*) h->cache_obj->vobj; if (mobj->type == CACHE_TYPE_FILE) { /* CACHE_TYPE_FILE */ apr_file_t *file; apr_os_file_put(&file, &mobj->fd, mobj->flags, p); b = apr_bucket_file_create(file, 0, mobj->m_len, p, bb->bucket_alloc); } else { /* CACHE_TYPE_HEAP */ b = apr_bucket_immortal_create(mobj->m, mobj->m_len, bb->bucket_alloc); } APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_eos_create(bb->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); return APR_SUCCESS;}static apr_status_t store_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*) obj->vobj; int rc; apr_table_t *headers_out; /* * The cache needs to keep track of the following information: * - Date, LastMod, Version, ReqTime, RespTime, ContentLength * - The original request headers (for Vary) * - The original response headers (for returning with a cached response) * - The body of the message */ rc = serialize_table(&mobj->req_hdrs, &mobj->num_req_hdrs, r->headers_in); if (rc != APR_SUCCESS) { return rc; } /* Precompute how much storage we need to hold the headers */ headers_out = ap_cache_cacheable_hdrs_out(r->pool, r->headers_out, r->server); headers_out = apr_table_overlay(r->pool, headers_out, r->err_headers_out); rc = serialize_table(&mobj->header_out, &mobj->num_header_out, headers_out); if (rc != APR_SUCCESS) { return rc; } /* Init the info struct */ obj->info.status = info->status; if (info->date) { obj->info.date = info->date; } if (info->response_time) { obj->info.response_time = info->response_time; } if (info->request_time) { obj->info.request_time = info->request_time; } if (info->expire) { obj->info.expire = info->expire; } return APR_SUCCESS;}static apr_status_t store_body(cache_handle_t *h, request_rec *r, apr_bucket_brigade *b){ apr_status_t rv; cache_object_t *obj = h->cache_obj; cache_object_t *tobj = NULL; mem_cache_object_t *mobj = (mem_cache_object_t*) obj->vobj; apr_read_type_e eblock = APR_BLOCK_READ; apr_bucket *e; char *cur;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -