⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 htcache.c

📁 Open VXI. This is a open source.
💻 C
📖 第 1 页 / 共 5 页
字号:
    long new_size = size*MEGA;    if (new_size > 0 && new_size < HTCacheTotalSize-HTCacheFolderSize) {	long old_size = HTCacheMaxEntrySize;	HTCacheMaxEntrySize = new_size;	if (new_size < old_size) HTCacheGarbage();	HTTRACE(CACHE_TRACE, "Cache...... Max entry cache size is %ld\n" _ HTCacheMaxEntrySize);	return YES;    }    HTTRACE(CACHE_TRACE, "Cache...... Max entry cache size is unchanged\n");    return NO;}PUBLIC int HTCacheMode_maxCacheEntrySize (void){    return HTCacheMaxEntrySize / MEGA;}/*** Set the default expiration time. In seconds.*/PUBLIC void HTCacheMode_setDefaultExpiration (const int exp_time){    DefaultExpiration = exp_time;}PUBLIC int HTCacheMode_DefaultExpiration (void){    return DefaultExpiration;}/* ------------------------------------------------------------------------- *//*  				 CACHE OBJECT				     *//* ------------------------------------------------------------------------- */PRIVATE BOOL free_object (HTCache * me){    HT_FREE(me->url);    HT_FREE(me->cachename);    HT_FREE(me->etag);    HT_FREE(me);    return YES;}PRIVATE BOOL delete_object (HTList * list, HTCache * me){    HTTRACE(CACHE_TRACE, "Cache....... delete %p from list %p\n" _ me _ list);    HTList_removeObject(list, (void *) me);    HTCacheContentSize -= me->size;    free_object(me);    return YES;}/***	Create directory path for cache file**** On exit:**	return YES**		if directories created -- after that caller**		can rely on fopen(cfn,"w") succeeding.***/PRIVATE BOOL HTCache_createLocation (HTCache * me){    if (me && HTCacheRoot) {	BOOL status = YES;	char * path = NULL;	struct stat stat_info;	if ((path = (char *) HT_MALLOC(strlen(HTCacheRoot) + 10)) == NULL)	    HT_OUTOFMEM("HTCache_createLocation");	/*	** Find the path and check whether the directory already exists or not	*/	sprintf(path, "%s%d", HTCacheRoot, me->hash);	if (HT_STAT(path, &stat_info) == -1) {	    HTTRACE(CACHE_TRACE, "Cache....... Create dir `%s\'\n" _ path);	    if (MKDIR(path, 0777) < 0) {		HTTRACE(CACHE_TRACE, "Cache....... Can't create...\n");		status = NO;	    }	} else {	    HTTRACE(CACHE_TRACE, "Cache....... Directory `%s\' already exists\n" _ path);	}	/*	** Find a non-existent filename within the path that we just created	*/	me->cachename = HTGetTmpFileName(path);	HT_FREE(path);	return status;    }    return NO;}/***	Find a cache filename for this cache object.*/#if 0PRIVATE BOOL HTCache_findName (HTCache * me){    if (me) {	/*	** Create path for this cache entry. We base the cache location on the	** hash calculated as a function of the URL. That way, we ensure a 	** resonably uniform distribution.	*/	me->cachename = HTGetTmpFileName(NULL);	return HTCache_createLocation(me);    }    return NO;}#endif/***  Calculate the corrected_initial_age of the object. We use the time**  when this function is called as the response_time as this is when**  we have received the complete response. This may cause a delay if**  the reponse header is very big but should not cause any incorrect**  behavior.*/PRIVATE BOOL calculate_time (HTCache * me, HTRequest * request,			     HTResponse * response){    if (me && request) {	HTParentAnchor * anchor = HTRequest_anchor(request);	time_t date = HTAnchor_date(anchor);	me->response_time = time(NULL);	me->expires = HTAnchor_expires(anchor);	{	    time_t apparent_age = HTMAX(0, me->response_time - date);	    time_t corrected_received_age = HTMAX(apparent_age, HTAnchor_age(anchor));	    time_t response_delay = me->response_time - HTRequest_date(request);	    me->corrected_initial_age = corrected_received_age + response_delay;	}	/*	**  Estimate an expires time using the max-age and expires time. If we	**  don't have an explicit expires time then set it to 10% of the LM	**  date (although max 24 h). If no LM date is available then use 24 hours.	*/	{	    time_t freshness_lifetime = HTResponse_maxAge(response);	    if (freshness_lifetime < 0) {		if (me->expires < 0) {		    time_t lm = HTAnchor_lastModified(anchor);		    if (lm < 0) {			freshness_lifetime = DefaultExpiration;		    } else {			freshness_lifetime = LM_EXPIRATION(date - lm);			if (freshness_lifetime > WARN_HEURISTICS)			    HTRequest_addError(request, ERR_WARN, NO,					       HTERR_HEURISTIC_EXPIRATION, NULL, 0,					       "calculate_time");		    }		} else		    freshness_lifetime = me->expires - date;	    }	    me->freshness_lifetime = HTMAX(0, freshness_lifetime);	}	HTTRACE(CACHE_TRACE, "Cache....... Received Age %d, corrected %d, freshness lifetime %d\n" _		HTAnchor_age(anchor) _ me->corrected_initial_age _ me->freshness_lifetime);	return YES;    }    return NO;}/***  Create a new cache entry and add it to the list*/PRIVATE HTCache * HTCache_new (HTRequest * request, HTResponse * response,			       HTParentAnchor * anchor){    HTList * list = NULL;			    /* Current list in cache */    HTCache * pres = NULL;    int hash = 0;    char * url = NULL;    if (!request || !response || !anchor) {	HTTRACE(CORE_TRACE, "Cache....... Bad argument\n");	return NULL;    }        /* Find a hash for this anchor */    if ((url = HTAnchor_address((HTAnchor *) anchor))) {	char * ptr;	for (ptr=url; *ptr; ptr++)	    hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HT_XL_HASH_SIZE);	if (!CacheTable) {	    if ((CacheTable = (HTList **) HT_CALLOC(HT_XL_HASH_SIZE,						   sizeof(HTList *))) == NULL)	        HT_OUTOFMEM("HTCache_new");	}	if (!CacheTable[hash]) CacheTable[hash] = HTList_new();	list = CacheTable[hash];    } else	return NULL;    /* Search the cache */    {	HTList * cur = list;	while ((pres = (HTCache *) HTList_nextObject(cur))) {	    if (!strcmp(pres->url, url)) break;	}    }    /* If not found then create new cache object, else use existing one */    if (!pres) {	if ((pres = (HTCache *) HT_CALLOC(1, sizeof(HTCache))) == NULL)	    HT_OUTOFMEM("HTCache_new");	pres->hash = hash;	pres->url = url;	pres->range = NO;	HTCache_createLocation(pres);	HTList_addObject(list, (void *) pres);	new_entries++;    } else	HT_FREE(url);    if (HTCache_hasLock(pres)) {	if (HTCache_breakLock(pres, request) == NO) {	    HTTRACE(CACHE_TRACE, "Cache....... Entry %p already in use\n");	    return pres;	}    }    HTCache_getLock(pres, request);    /* Calculate the various times */    calculate_time(pres, request, response);    /* Get the last-modified and etag values if any */    {	char * etag = HTAnchor_etag(anchor);	if (etag) StrAllocCopy(pres->etag, etag);	pres->lm = HTAnchor_lastModified(anchor);    }    /* Must we revalidate this every time? */    pres->must_revalidate = HTResponse_mustRevalidate(response);    return pres;}/***  Add an entry for a resource that has just been created so that we can **  remember the etag and other things. This allows us to guarantee that**  we don't loose data due to the lost update problem*/PUBLIC HTCache * HTCache_touch (HTRequest * request, HTResponse * response,				HTParentAnchor * anchor){    HTCache * cache = NULL;    /* Get a new cache entry */    if ((cache = HTCache_new(request, response, anchor)) == NULL) {	HTTRACE(CACHE_TRACE, "Cache....... Can't get a cache object\n");	return NULL;    }    /* We don't have any of the data in cache - only meta information */    if (cache) {	cache->size = 0;	cache->range = YES;    }    return cache;}/***	Cache Validation BEFORE Filter**	------------------------------**	Check the cache mode to see if we can use an already loaded version**	of this document. If so and our copy is valid then we don't have**	to go out and get it unless we are forced to**	We only check the cache in caseof a GET request. Otherwise, we go**	directly to the source.*/PRIVATE int HTCacheFilter (HTRequest * request, void * param, int mode){    HTParentAnchor * anchor = HTRequest_anchor(request);    char * default_name = HTRequest_defaultPutName (request);     HTCache * cache = NULL;    HTReload reload = HTRequest_reloadMode(request);    HTMethod method = HTRequest_method(request);    HTDisconnectedMode disconnect = HTCacheMode_disconnected();    BOOL validate = NO;    /*    **  If the cache is disabled all together then it won't help looking, huh?    */    if (!HTCacheMode_enabled()) return HT_OK;    HTTRACE(CACHE_TRACE, "Cachefilter. Checking persistent cache\n");    /*    **  Now check the cache...    */    if (method != METHOD_GET) {	HTTRACE(CACHE_TRACE, "Cachefilter. We only check GET methods\n");    } else if (reload == HT_CACHE_FLUSH) {	/*	** If the mode if "Force Reload" then don't even bother to check the	** cache - we flush everything we know abut this document anyway.	** Add the appropriate request headers. We use both the "pragma"	** and the "cache-control" headers in order to be	** backwards compatible with HTTP/1.0	*/	validate = YES;	HTRequest_addGnHd(request, HT_G_PRAGMA_NO_CACHE);	HTRequest_addCacheControl(request, "no-cache", "");	/*	**  We also flush the information in the anchor as we don't want to	**  inherit any "old" values	*/	HTAnchor_clearHeader(anchor);    } else {	/*	** Check the persistent cache manager. If we have a cache hit then	** continue to see if the reload mode requires us to do a validation	** check. This filter assumes that we can get the cached version	** through one of our protocol modules (for example the file module)	*/	cache = HTCache_find(anchor, default_name);	if (cache) {	    HTReload cache_mode = HTCache_isFresh(cache, request);	    if (cache_mode == HT_CACHE_ERROR) cache = NULL;	    reload = HTMAX(reload, cache_mode);	    HTRequest_setReloadMode(request, reload);	    /*	    **  Now check the mode and add the right headers for the validation	    **  If we are to validate a cache entry then we get a lock	    **  on it so that not other requests can steal it.	    */	    if (reload == HT_CACHE_RANGE_VALIDATE) {		/*		**  If we were asked to range validate the cached object then		**  use the etag or the last modified for cache validation		*/		validate = YES;		HTCache_getLock(cache, request);		HTRequest_addRqHd(request, HT_C_IF_RANGE);	    } else if (reload == HT_CACHE_END_VALIDATE) {		/*		**  If we were asked to end-to-end validate the cached object		**  then use a max-age=0 cache control directive		*/		validate = YES;		HTCache_getLock(cache, request);		HTRequest_addCacheControl(request, "max-age", "0");	    } else if (reload == HT_CACHE_VALIDATE) {		/*		**  If we were asked to validate the cached object then		**  use the etag or the last modified for cache validation		**  We use both If-None-Match or If-Modified-Since.		*/		validate = YES;		HTCache_getLock(cache, request);		HTRequest_addRqHd(request, HT_C_IF_NONE_MATCH | HT_C_IMS);	    } else if (cache) {		/*		**  The entity does not require any validation at all. We		**  can just go ahead and get it from the cache. In case we		**  have a fresh subpart of the entity, then we issue a 		**  conditional GET request with the range set by the cache		**  manager. Issuing the conditional range request is 		**  equivalent to a validation as we have to go out on the		**  net. This may have an effect if running in disconnected		**  mode. We disable all BEFORE filters as they don't make		**  sense while loading the cache entry.		*/		{		    char * name = HTCache_name(cache);		    HTAnchor_setPhysical(anchor, name);		    HTCache_addHit(cache);		    HT_FREE(name);		}	    }	}    }        /*    **  If we are in disconnected mode and we are to validate an entry    **  then check whether what mode of disconnected mode we're in. If    **  we are to use our own cache then return a "504 Gateway Timeout"    */    if ((!cache || validate) && disconnect != HT_DISCONNECT_NONE) {	if (disconnect == HT_DISCONNECT_EXTERNAL)	    HTRequest_addCacheControl(request, "only-if-cached", "");	else {	    HTRequest_addError(request, ERR_FATAL, NO,			       HTERR_GATE_TIMEOUT, "Disconnected Cache Mode",			       0, "HTCacheFilter");	    return HT_ERROR;	}    }    return HT_OK;}/***	Cache Update AFTER filter**	-------------------------**	On our way out we catch the metainformation and stores it in**	our persistent store. If we have a cache validation (a 304**	response then we use the new metainformation and merges it with**	the existing information already captured in the cache.*/PRIVATE int  HTCacheUpdateFilter (HTRequest * request, HTResponse * response,				 void * param, int status){    HTParentAnchor * anchor = HTRequest_anchor(request);    char * default_name = HTRequest_defaultPutName(request);    HTCache * cache = HTCache_find(anchor, default_name);    if (cache) {	/*	**  It may in fact be that the information in the 304 response	**  told us that we can't cache the entity anymore. If this is the	**  case then flush it now. Otherwise prepare for a cache read	*/	HTTRACE(CACHE_TRACE, "Cache....... Merging metainformation\n");	if (HTResponse_isCachable(response) == HT_NO_CACHE) {	    HTCache_remove(cache);	} else {	    char * name = HTCache_name(cache);	    HTAnchor_setPhysical(anchor, name);	    HTCache_addHit(cache);	    HT_FREE(name);	    HTCache_updateMeta(cache, request, response);	}	/*	**  Start request directly from the cache. As with the redirection filter	**  we reuse the same request object which means that we must	**  keep this around until the cache load request has terminated	**  In the case of a 	*/	HTLoad(request, YES);	return HT_ERROR;    } else {	/* If entry doesn't already exist then create a new entry */	HTCache_touch(request, response, anchor);    }    return HT_OK;}/***	Cache Check AFTER filter**	------------------------**	Add an entry for a resource that has just been created so that we can **	remember the etag and other things. This allows us to guarantee that**	we don't loose data due to the lost update problem. We also check**	whether we should delete the cached entry if the request/response**	invalidated it (if success and method was not "safe")*/PRIVATE int HTCacheCheckFilter (HTRequest * request, HTResponse * response,				void * param, int status){    if (status/100==2 && !HTMethod_isSafe(HTRequest_method(request))) {        if (status==201) {	    HTParentAnchor * anchor = HTAnchor_parent(HTResponse_redirection(response));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -