📄 htcache.c
字号:
if (!anchor) anchor = HTRequest_anchor(request); HTCache_touch(request, response, anchor); } else { HTParentAnchor * anchor = HTRequest_anchor(request); char * default_name = HTRequest_defaultPutName(request); HTCache * cache = HTCache_find(anchor, default_name); if (cache) { /* ** If we receive a 204 and the method is unsafe then we have ** to delete the cache body but not the header information */ /* ** @@ JK: see how to add all the methods here (201, etc.) when ** it's a PUT */ if (status == 204) { HTCache_updateMeta(cache, request, response); cache->size = 0; cache->range = YES; /* @@ JK: update the cache meta data on disk */ HTCache_writeMeta (cache, request, response); /* @@ JK: and we remove the file name as it's obsolete now */ REMOVE(cache->cachename); } else HTCache_remove(cache); } /* @@ this operation will clear the cache->size and cache_range */ HTCache_touch(request, response, anchor); } } return HT_OK;}/*** Set the size of a cached object. We don't consider the metainformation as** part of the size which is the the reason for why the min cache size should** not be less than 5M. When we set the cache size we also check whether we ** should run the gc or not.*/PRIVATE BOOL HTCache_setSize (HTCache * cache, long written, BOOL append){ if (cache) { /* ** First look to see if we already have registered this cache entry ** with a certain size. This size may be a subpart of the total entity ** (in case the download was interrupted) */ if (cache->size > 0 && !append) HTCacheContentSize -= cache->size; cache->size = written; HTCacheContentSize += written; /* ** Now add the new size to the total cache size. If the new size is ** bigger than the legal cache size then start the gc. */ HTTRACE(CACHE_TRACE, "Cache....... Total size %ld\n" _ HTCacheContentSize); if (startGC()) HTCacheGarbage(); return YES; } return NO;}/*** Verifies if a cache object exists for this URL and if so returns a URL** for the cached object. It does not verify whether the object is valid or** not, for example it might have expired.**** Returns: file name If OK (must be freed by caller)** NULL If no cache object found*/PUBLIC HTCache * HTCache_find (HTParentAnchor * anchor, char * default_name){ HTList * list = NULL; HTCache * pres = NULL; /* Find a hash entry for this URL */ if (HTCacheMode_enabled() && anchor && CacheTable) { char * url = NULL; int hash = 0; char * ptr; if (default_name) StrAllocCopy (url, default_name); else url = HTAnchor_address((HTAnchor *) anchor); ptr = url; for (; *ptr; ptr++) hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HT_XL_HASH_SIZE); if (!CacheTable[hash]) { HT_FREE(url); return NULL; } list = CacheTable[hash]; /* Search the cache */ { HTList * cur = list; while ((pres = (HTCache *) HTList_nextObject(cur))) { if (!strcmp(pres->url, url)) { HTTRACE(CACHE_TRACE, "Cache....... Found %p hits %d\n" _ pres _ pres->hits); break; } } } HT_FREE(url); } return pres;}/* HTCache_delete** --------------** Deletes a cache entry*/PRIVATE BOOL HTCache_delete (HTCache * cache){ if (cache && CacheTable) { HTList * cur = CacheTable[cache->hash]; return cur && delete_object(cur, cache); } return NO;}/* HTCache_deleteAll** -----------------** Destroys all cache entried in memory but does not write anything to** disk*/PUBLIC BOOL HTCache_deleteAll (void){ if (CacheTable) { HTList * cur; int cnt; /* Delete the rest */ for (cnt=0; cnt<HT_XL_HASH_SIZE; cnt++) { if ((cur = CacheTable[cnt])) { HTCache * pres; while ((pres = (HTCache *) HTList_nextObject(cur)) != NULL) free_object(pres); } HTList_delete(CacheTable[cnt]); } HT_FREE(CacheTable); HTCacheContentSize = 0L; return YES; } return NO;}/*** Is we have a valid entry in the cache then we also need a location** where we can get it. Hopefully, we may be able to access it** thourgh one of our protocol modules, for example the local file** module. The name returned is in URL syntax and must be freed by** the caller*/PRIVATE char * HTCache_metaLocation (HTCache * cache){ char * local = NULL; if (cache && cache->cachename && *cache->cachename) { if ((local = (char *) HT_MALLOC(strlen(cache->cachename) + strlen(HT_CACHE_META) + 5)) == NULL) HT_OUTOFMEM("HTCache_metaLocation"); sprintf(local, "%s%s", cache->cachename, HT_CACHE_META); } return local;}/*** Walk through the set of headers and write those out that we are allowed** to store in the cache. We look into the connection header to see what the ** hop-by-hop headers are and also into the cache-control directive to see what** headers should not be cached.*/PRIVATE BOOL meta_write (FILE * fp, HTRequest * request, HTResponse * response){ if (fp && request && response) { HTAssocList * headers = HTAnchor_header(HTRequest_anchor(request)); HTAssocList * connection = HTResponse_connection(response); char * nocache = HTResponse_noCache(response); /* ** If we don't have any headers then just return now. */ if (!headers) return NO; /* ** Check whether either the connection header or the cache control ** header includes header names that we should not cache */ if (connection || nocache) { /* ** Walk though the cache control no-cache directive */ if (nocache) { char * line = NULL; char * ptr = NULL; char * field = NULL; StrAllocCopy(line, nocache); /* Get our own copy */ ptr = line; while ((field = HTNextField(&ptr)) != NULL) HTAssocList_removeObject(headers, field); HT_FREE(line); } /* ** Walk though the connection header */ if (connection) { HTAssoc * pres; while ((pres=(HTAssoc *) HTAssocList_nextObject(connection))) { char * field = HTAssoc_name(pres); HTAssocList_removeObject(headers, field); } } } /* ** Write out the remaining list of headers that we not already store ** in the index file. */ { HTAssocList * cur = headers; HTAssoc * pres; while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) { char * name = HTAssoc_name(pres); /* Don't write the headers that are already hop-by-hop */ if (strcasecomp(name, "connection") && strcasecomp(name, "keep-alive") && strcasecomp(name, "proxy-authenticate") && strcasecomp(name, "proxy-authorization") && strcasecomp(name, "transfer-encoding") && strcasecomp(name, "upgrade")) { if (fprintf(fp, "%s: %s\n", name, HTAssoc_value(pres)) < 0) { HTTRACE(CACHE_TRACE, "Cache....... Error writing metainfo\n"); return NO; } } } } /* ** Terminate the header with a newline */ if (fprintf(fp, "\n") < 0) { HTTRACE(CACHE_TRACE, "Cache....... Error writing metainfo\n"); return NO; } return YES; } return NO;}/*** Save the metainformation for the data object. If no headers** are available then the meta file is empty*/PUBLIC BOOL HTCache_writeMeta (HTCache * cache, HTRequest * request, HTResponse * response){ if (cache && request && response) { BOOL status; FILE * fp; char * name = HTCache_metaLocation(cache); if (!name) { HTTRACE(CACHE_TRACE, "Cache....... Invalid cache entry\n"); HTCache_remove(cache); return NO; } if ((fp = fopen(name, "wb")) == NULL) { HTTRACE(CACHE_TRACE, "Cache....... Can't open `%s\' for writing\n" _ name); HTCache_remove(cache); HT_FREE(name); return NO; } status = meta_write(fp, request, response); fclose(fp); HT_FREE(name); return status; } return NO;}PRIVATE BOOL meta_read (FILE * fp, HTRequest * request, HTStream * target){ if (fp && request && target) { int status; char buffer[512]; while (1) { if ((status = fread(buffer, 1, 512, fp)) <= 0) { HTTRACE(PROT_TRACE, "Cache....... Meta information loaded\n"); return YES; } /* Send the data down the pipe */ status = (*target->isa->put_block)(target, buffer, status); if (status == HT_LOADED) { (*target->isa->flush)(target); return YES; } if (status < 0) { HTTRACE(PROT_TRACE, "Cache....... Target ERROR %d\n" _ status); break; } } } return NO;}/*** Read the metainformation for the data object. If no headers are** available then the meta file is empty*/PRIVATE BOOL HTCache_readMeta (HTCache * cache, HTRequest * request){ HTParentAnchor * anchor = HTRequest_anchor(request); if (cache && request && anchor) { BOOL status; FILE * fp; char * name = HTCache_metaLocation(cache); if (!name) { HTTRACE(CACHE_TRACE, "Cache....... Invalid meta name\n" _ name); HTCache_remove(cache); return NO; } HTTRACE(CACHE_TRACE, "Cache....... Looking for `%s\'\n" _ name); if ((fp = fopen(name, "rb")) == NULL) { HTTRACE(CACHE_TRACE, "Cache....... Can't open `%s\' for reading\n" _ name); HTCache_remove(cache); HT_FREE(name); } else { HTStream * target = HTStreamStack(WWW_MIME_HEAD, WWW_DEBUG, HTBlackHole(), request, NO); /* ** Make sure that we save the reponse information in the anchor */ HTResponse_setCachable(HTRequest_response(request), HT_CACHE_ALL); status = meta_read(fp, request, target); (*target->isa->_free)(target); /* JK: Moved the delete outside of meta_read, because it was being deleted multiple times. Delete the response headers. In principle, they are already available in the anchor */ HTRequest_setResponse(request, NULL); fclose(fp); HT_FREE(name); return status; } } return NO;}/*** Merge metainformation with existing version. This means that we have had a** successful validation and hence a true cache hit. We only regard the** following headers: Date, content-location, expires, cache-control, and vary.*/PUBLIC BOOL HTCache_updateMeta (HTCache * cache, HTRequest * request, HTResponse * response){ if (cache && request && response) { HTParentAnchor * anchor = HTRequest_anchor(request); cache->hits++; /* Calculate the various times */ calculate_time(cache, request, response); /* Get the last-modified and etag values if any */ { char * etag = HTAnchor_etag(anchor); if (etag) StrAllocCopy(cache->etag, etag); cache->lm = HTAnchor_lastModified(anchor); } /* Must we revalidate this every time? */ cache->must_revalidate = HTResponse_mustRevalidate(response); return YES; } return NO;}/*** Remove from disk. You must explicitly remove a lock** before this operation can succeed*/PRIVATE BOOL flush_object (HTCache * cache){ if (cache && !HTCache_hasLock(cache)) { char * head = HTCache_metaLocation(cache); REMOVE(head); HT_FREE(head); REMOVE(cache->cachename); return YES; } return NO;}/* HTCache_flushAll** ----------------** Destroys all cache entried in memory and on disk. Resets the cache** to empty but the cache does not have to be reinitialized before we** can use it again.*/PUBLIC BOOL HTCache_flushAll (void){ if (CacheTable) { HTList * cur; int cnt; /* Delete the rest */ for (cnt=0; cnt<HT_XL_HASH_SIZE; cnt++) { if ((cur = CacheTable[cnt])) { HTCache * pres; while ((pres = (HTCache *) HTList_nextObject(cur)) != NULL) { flush_object(pres); free_object(pres); } } HTList_delete(CacheTable[cnt]); CacheTable[cnt] = NULL; } /* Write the new empty index to disk */ HTCacheIndex_write(HTCacheRoot); HTCacheContentSize = 0L; return YES; } return NO;}/*** This function checks whether a document has expired or not.** The check is based on the metainformation passed in the anchor object** The function returns the level of validation needed for getting a fresh** version. We also check the cache control directives in the request to** see if they change the freshness discission. */PUBLIC HTReload HTCache_isFresh (HTCache * cache, HTRequest * request){ HTAssocList * cc = HTRequest_cacheControl(request); if (cache) { time_t max_age = -1; time_t max_stale = -1; time_t min_fresh = -1; /* ** Make sure that we have the metainformation loaded from the ** persistent cache */ HTParentAnchor * anchor = HTRequest_anchor(request); if (!HTAnchor_headerParsed(anchor)) { if (HTCache_readMeta(cache, request) != YES) return HT_CACHE_ERROR; HTAnchor_setHeaderParsed(anchor); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -