Annotation of libwww/Library/src/HTCache.c, revision 2.12

2.1       frystyk     1: /*                                                                 HTCache.c
                      2: **     CACHE WRITER
                      3: **
                      4: **     (c) COPYRIGHT MIT 1995.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
                      6: **
                      7: **     This modules manages the cache
                      8: **
                      9: **      History:
                     10: **         HFN: spawned from HTFwrite
                     11: **         HWL: converted the caching scheme to be hierachical by taking
                     12: **              AL code from Deamon
                     13: **
                     14: */
                     15: 
                     16: /* Library include files */
                     17: #include "tcp.h"
                     18: #include "HTUtils.h"
                     19: #include "HTString.h"
                     20: #include "HTFormat.h"
                     21: #include "HTFWrite.h"
2.12    ! frystyk    22: #include "HTAccess.h"
2.1       frystyk    23: #include "HTBind.h"
                     24: #include "HTList.h"
2.7       frystyk    25: #include "HTReqMan.h"
2.1       frystyk    26: #include "HTParse.h"
                     27: #include "HTCache.h"                                    /* Implemented here */
                     28: 
                     29: /*
                     30: ** The cache limit is the number of files which are kept. Yes, I know,
                     31: ** the amount of disk space would be more relevant. So this may change.
                     32: ** Currently it is preset to 100 but may be changed by the application by
                     33: ** writing into this variable.
                     34: */
                     35: #define CACHE_LIMIT    5                                 /* Number of files */
                     36: 
                     37: #define CACHE_INFO     ".cache_info"
                     38: #define INDEX_FILE     ".cache_dirindex"
                     39: #define WELCOME_FILE   ".cache_welcome"
                     40: #define TMP_SUFFIX     ".cache_tmp"
                     41: #define LOCK_SUFFIX    ".cache_lock"
                     42: 
2.7       frystyk    43: /* This is the default cache directory: */
                     44: #ifndef HT_CACHE_ROOT
                     45: #define HT_CACHE_ROOT  "/tmp"
                     46: #endif
                     47: 
                     48: typedef struct _HTCache {
2.1       frystyk    49:     HTFormat           format;         /* May have many formats per anchor */
                     50:     char *             filename;
                     51:     time_t             start_time;
                     52:     time_t             load_delay;
                     53:     int                        reference_count;
2.7       frystyk    54: } HTCache;
2.1       frystyk    55: 
                     56: struct _HTStream {
                     57:     CONST HTStreamClass *      isa;
                     58:     FILE *                     fp;
2.7       frystyk    59:     HTCache *                  cache;
2.1       frystyk    60:     HTRequest *                        request;
                     61: };
                     62: 
                     63: PRIVATE BOOL           HTCacheEnable = NO;
                     64: PRIVATE char *         HTCacheRoot = NULL;         /* Destination for cache */
2.7       frystyk    65: PRIVATE HTList *       HTCacheList = NULL;       /* List of cached elements */
2.1       frystyk    66: PRIVATE int            HTCacheLimit = CACHE_LIMIT;
                     67: 
2.7       frystyk    68: PRIVATE HTExpiresMode HTExpMode = HT_EXPIRES_IGNORE;
                     69: PRIVATE char *HTExpNotify = NULL;
                     70: 
                     71: PRIVATE HTMemoryCacheHandler *HTMemoryCache = NULL;  /* Memory cache handler */
2.2       frystyk    72: 
2.1       frystyk    73: /* ------------------------------------------------------------------------- */
2.2       frystyk    74: /*                           GARBAGE COLLECTOR                              */
2.1       frystyk    75: /* ------------------------------------------------------------------------- */
                     76: 
                     77: /*
                     78: **  Removes cache item from disk and corresponding object from list in memory
                     79: */
2.12    ! frystyk    80: PRIVATE void HTCache_remove (HTCache * item)
2.1       frystyk    81: {
2.7       frystyk    82:     if (HTCacheList && item) {
2.1       frystyk    83:        if (CACHE_TRACE)
2.10      frystyk    84:            TTYPrint(TDEST, "Cache....... Removing %s\n", item->filename);
2.7       frystyk    85:        HTList_removeObject(HTCacheList, item);
2.1       frystyk    86:        REMOVE(item->filename);
                     87:        
                     88:        /* HWL 22/9/94: Clean up hierachical file structure */
                     89:        {
                     90:            char * p;
                     91:            while ((p = strrchr(item->filename,'/')) && (p != NULL)){
                     92:                item->filename[p-item->filename] = 0;
                     93:                if (strcmp(item->filename, HTCacheRoot) != 0) {
                     94:                    if (CACHE_TRACE) 
2.10      frystyk    95:                        TTYPrint(TDEST, "rmdir....... %s\n", item->filename);
2.1       frystyk    96:                    RMDIR(item->filename); /* fails if directory isn't empty */
                     97:                }
                     98:            }
                     99:        }
                    100:        free(item->filename);
                    101:        free(item);
                    102:     }
                    103: }
                    104: 
                    105: 
                    106: /*
                    107: **  Remove a file from the cache to prevent too many files from being cached
                    108: */
2.12    ! frystyk   109: PRIVATE void limit_cache (HTList * list)
2.1       frystyk   110: {
                    111:     HTList * cur = list;
2.7       frystyk   112:     HTCache * item;
2.1       frystyk   113:     time_t best_delay = 0;   /* time_t in principle can be any arith type */
2.7       frystyk   114:     HTCache* best_item = NULL;
2.1       frystyk   115: 
                    116:     if (HTList_count(list) < HTCacheLimit) return;   /* Limit not reached */
                    117: 
2.7       frystyk   118:     while (NULL != (item = (HTCache*)HTList_nextObject(cur))) {
2.1       frystyk   119:         if (best_delay == 0  ||  item->load_delay < best_delay) {
                    120:             best_delay = item->load_delay;
                    121:             best_item = item;
                    122:         }
                    123:     }
                    124:     if (best_item) HTCache_remove(best_item);
                    125: }
                    126: 
                    127: /*
                    128: **     Check that the name we're about to generate doesn't
                    129: **     clash with anything used by the caching system.
                    130: */
2.12    ! frystyk   131: PRIVATE BOOL reserved_name (char * url)
2.1       frystyk   132: {
                    133:     char * name = strrchr(url, '/');
                    134:     char * suff = NULL;
                    135: 
                    136:     if (name) name++;
                    137:     else name = url;
                    138: 
                    139:     if (!strcmp(name, CACHE_INFO) ||
                    140:        !strcmp(name, INDEX_FILE) ||
                    141:        !strcmp(name, WELCOME_FILE))
                    142:        return YES;
                    143: 
                    144:     suff = strrchr(name, TMP_SUFFIX[0]);
                    145:     if (suff && !strcmp(suff, TMP_SUFFIX))
                    146:        return YES;
                    147: 
                    148:     suff = strrchr(name, LOCK_SUFFIX[0]);
                    149:     if (suff && !strcmp(suff, LOCK_SUFFIX))
                    150:        return YES;
                    151: 
                    152:     return NO;
                    153: }
                    154: 
                    155: /*
2.2       frystyk   156: **  Removes all cache entries in memory
                    157: */
2.12    ! frystyk   158: PUBLIC void HTCache_clearMem (void)
2.2       frystyk   159: {
2.7       frystyk   160:     HTList *cur=HTCacheList;
                    161:     HTCache *pres;
2.2       frystyk   162:     if (cur) {
2.7       frystyk   163:        while ((pres = (HTCache *) HTList_nextObject(cur))) {
2.2       frystyk   164:            FREE(pres->filename);
                    165:            free(pres);
                    166:        }
2.7       frystyk   167:        HTList_delete(HTCacheList);
                    168:        HTCacheList = NULL;
2.2       frystyk   169:     }
                    170: }
                    171: 
                    172: /*
                    173: **  Removes all cache entries in memory and on disk
                    174: */
2.12    ! frystyk   175: PUBLIC void HTCache_deleteAll (void)
2.2       frystyk   176: {
2.7       frystyk   177:     HTList *cur=HTCacheList;
                    178:     HTCache * pres;
2.2       frystyk   179:     if (cur) {
2.7       frystyk   180:        while ((pres = (HTCache *) HTList_lastObject(cur)))
2.2       frystyk   181:            HTCache_remove(pres);
2.7       frystyk   182:        HTList_delete(HTCacheList);
                    183:        HTCacheList = NULL;
2.2       frystyk   184:     }
                    185: }
                    186: 
                    187: /* ------------------------------------------------------------------------- */
                    188: /*                              NAMING SCHEME                               */
                    189: /* ------------------------------------------------------------------------- */
                    190: 
                    191: /*
2.1       frystyk   192: **     Map url to cache file name.
                    193: */
2.12    ! frystyk   194: PRIVATE char * cache_file_name (char * url)
2.1       frystyk   195: {
                    196:     char * access = NULL;
                    197:     char * host = NULL;
                    198:     char * path = NULL;
                    199:     char * cfn = NULL;
                    200:     BOOL welcome = NO;
                    201:     BOOL res = NO;
                    202: 
                    203:     if (!url ||  strchr(url, '?')  ||  (res = reserved_name(url))  ||
                    204:        !(access = HTParse(url, "", PARSE_ACCESS)) ||
                    205:        (0 != strcmp(access, "http") &&
                    206:         0 != strcmp(access, "ftp")  &&
                    207:         0 != strcmp(access, "gopher"))) {
                    208: 
                    209:        if (access) free(access);
                    210: 
                    211:        if (res && CACHE_TRACE)
2.10      frystyk   212:            TTYPrint(TDEST,
2.1       frystyk   213:                    "Cache....... Clash with reserved name (\"%s\")\n",url);
                    214: 
                    215:        return NULL;
                    216:     }
                    217: 
                    218:     host = HTParse(url, "", PARSE_HOST);
                    219:     path = HTParse(url, "", PARSE_PATH | PARSE_PUNCTUATION);
                    220:     if (path && path[strlen(path)-1] == '/')
                    221:        welcome = YES;
                    222: 
                    223:     cfn = (char*)malloc(strlen(HTCacheRoot) +
                    224:                        strlen(access) +
                    225:                        (host ? strlen(host) : 0) +
                    226:                        (path ? strlen(path) : 0) +
                    227:                        (welcome ? strlen(WELCOME_FILE) : 0) + 3);
                    228:     if (!cfn) outofmem(__FILE__, "cache_file_name");
                    229: 
                    230:     /* Removed extra slash - HF May2,95 */
                    231:     sprintf(cfn, "%s%s/%s%s%s", HTCacheRoot, access, host, path,
                    232:            (welcome ? WELCOME_FILE : ""));
                    233: 
                    234:     FREE(access); FREE(host); FREE(path);
                    235: 
                    236:     /*
                    237:     ** This checks that the last component is not too long.
                    238:     ** It could check all the components, but the last one
                    239:     ** is most important because it could later blow up the
                    240:     ** whole gc when reading cache info files.
                    241:     ** Operating system handles other cases.
                    242:     ** 64 = 42 + 22  and  22 = 42 - 20  :-)
                    243:     ** In other words I just picked some number, it doesn't
                    244:     ** really matter that much.
                    245:     */
                    246:     {
                    247:        char * last = strrchr(cfn, '/');
                    248:        if (!last) last = cfn;
                    249:        if ((int)strlen(last) > 64) {
                    250:            if (CACHE_TRACE)
2.10      frystyk   251:                TTYPrint(TDEST, "Too long.... cache file name \"%s\"\n", cfn);
2.1       frystyk   252:            free(cfn);
                    253:            cfn = NULL;
                    254:        }
                    255:     }
                    256:     return cfn;
                    257: }
                    258: 
                    259: 
                    260: /*
                    261: **     Create directory path for cache file
                    262: **
                    263: ** On exit:
                    264: **     return YES
                    265: **             if directories created -- after that caller
                    266: **             can rely on fopen(cfn,"w") succeeding.
                    267: **
                    268: */
2.12    ! frystyk   269: PRIVATE BOOL create_cache_place (char * cfn)
2.1       frystyk   270: {
                    271:     struct stat stat_info;
                    272:     char * cur = NULL;
                    273:     BOOL create = NO;
                    274: 
                    275:     if (!cfn  ||  (int)strlen(cfn) <= (int)strlen(HTCacheRoot) + 1)
                    276:        return NO;
                    277: 
                    278:     cur = cfn + strlen(HTCacheRoot) + 1;
                    279: 
                    280:     while ((cur = strchr(cur, '/'))) {
                    281:        *cur = 0;
2.6       frystyk   282:        if (create || HT_STAT(cfn, &stat_info) == -1) {
2.1       frystyk   283:            create = YES;       /* To avoid doing stat()s in vain */
                    284:            if (CACHE_TRACE)
2.10      frystyk   285:                TTYPrint(TDEST,"Cache....... creating cache dir \"%s\"\n",cfn);
2.1       frystyk   286:            if (MKDIR(cfn, 0777) < 0) {
                    287:                if (CACHE_TRACE)
2.10      frystyk   288:                    TTYPrint(TDEST,"Cache....... can't create dir `%s\'\n",cfn);
2.1       frystyk   289:                return NO;
                    290:            }
                    291:        } else {
                    292:            if (S_ISREG(stat_info.st_mode)) {
                    293:                int len = strlen(cfn);
                    294:                char * tmp1 = (char*)malloc(len + strlen(TMP_SUFFIX) + 1);
                    295:                char * tmp2 = (char*)malloc(len + strlen(INDEX_FILE) + 2);
                    296:                /* time_t t1,t2,t3,t4,t5; */
                    297: 
                    298: 
                    299:                sprintf(tmp1, "%s%s", cfn, TMP_SUFFIX);
                    300:                sprintf(tmp2, "%s/%s", cfn, INDEX_FILE);
                    301: 
                    302:                if (CACHE_TRACE) {
2.10      frystyk   303:                    TTYPrint(TDEST,"Cache....... moving \"%s\" to \"%s\"\n",
2.1       frystyk   304:                            cfn,tmp1);
2.10      frystyk   305:                    TTYPrint(TDEST,"and......... creating dir \"%s\"\n",
2.1       frystyk   306:                            cfn);
2.10      frystyk   307:                    TTYPrint(TDEST,"and......... moving \"%s\" to \"%s\"\n",
2.1       frystyk   308:                            tmp1,tmp2);
                    309:                }
                    310:                rename(cfn,tmp1);
                    311:                (void) MKDIR(cfn, 0777);
                    312:                rename(tmp1,tmp2);
                    313:                free(tmp1);
                    314:                free(tmp2);
                    315:            }
                    316:            else {
                    317:                if (CACHE_TRACE)
2.10      frystyk   318:                    TTYPrint(TDEST,"Cache....... dir \"%s\" already exists\n",
2.1       frystyk   319:                            cfn);
                    320:            }
                    321:        }
                    322:        *cur = '/';
                    323:        cur++;
                    324:     }
                    325:     return YES;
                    326: }
                    327: 
                    328: 
                    329: /*     Create a cache path
                    330: **     -------------------
                    331: **     Find a full path name for the cache file and create the path if it
                    332: **     does not already exist. Returns name or NULL
                    333: **     HWL 22/9/94
                    334: **     HWL added support for hierachical structure
                    335: */
2.12    ! frystyk   336: PRIVATE char *HTCache_getName (char * url)
2.1       frystyk   337: {
                    338:     char *filename = cache_file_name(url);
                    339:     if (!filename)
                    340:        return NULL;
                    341:     if (create_cache_place(filename))
                    342:        return(filename);
                    343:     return NULL;
                    344: }
                    345: 
                    346: /*
                    347: **  Make a WWW name from a cache name and returns it if OK, else NULL.
                    348: **  The string returned must be freed by the caller.
                    349: **  We keep this function private as we might change the naming scheme for
                    350: **  cache files. Right now it follows the file hierarchi.
                    351: */
2.12    ! frystyk   352: PRIVATE char *HTCache_wwwName  (char * name)
2.1       frystyk   353: {
                    354:     char * result = NULL;
                    355:     if (name && *name) {
                    356:        StrAllocCopy(result, "file:");       /* We get an absolute file name */
                    357: #ifdef VMS 
                    358:        /* convert directory name to Unix-style syntax */
2.4       frystyk   359:        {
                    360:            char * disk = strchr (name, ':');
                    361:            char * dir = strchr (name, '[');
                    362:            if (disk) {
                    363:                *disk = '\0';
                    364:                StrAllocCat(result, "/"); /* needs delimiter */
                    365:                StrAllocCat(result, name);
                    366:            }
                    367:            if (dir) {
                    368:                char *p;
                    369:                *dir = '/';     /* Convert leading '[' */
                    370:                for (p = dir ; *p != ']'; ++p)
                    371:                    if (*p == '.') *p = '/';
                    372:                *p = '\0';      /* Cut on final ']' */
                    373:                StrAllocCat(result, dir);
                    374:            }
2.1       frystyk   375:        }
                    376: #else  /* not VMS */
                    377: #ifdef WIN32
2.4       frystyk   378:        {
                    379:            char * p = name;                                      /* a colon */
                    380:            while( *p != 0 ) { 
                    381:                if (*p == '\\')                  /* change to one true slash */
                    382:                    *p = '/' ;
                    383:                p++;
                    384:            }
                    385:            StrAllocCat(result, name);
2.1       frystyk   386:        }
                    387: #else /* not WIN32 */
                    388:        StrAllocCat (result, name);
                    389: #endif /* not WIN32 */
                    390: #endif /* not VMS */
                    391:     }
                    392:     return result;
                    393: }
                    394: 
2.2       frystyk   395: /* ------------------------------------------------------------------------- */
                    396: /*                           CACHE PARAMETERS                               */
                    397: /* ------------------------------------------------------------------------- */
2.1       frystyk   398: 
                    399: /*     Enable Cache
                    400: **     ------------
                    401: **     If `cache_root' is NULL then reuse old value or use HT_CACHE_ROOT.
                    402: **     An empty string will make '/' as cache root
2.12    ! frystyk   403: **     We can only enable the cache if the HTSecure flag is not set. This
        !           404: **     is for example the case if using an application as a telnet shell.
2.1       frystyk   405: */
2.12    ! frystyk   406: PUBLIC BOOL HTCache_enable (CONST char * cache_root)
2.1       frystyk   407: {
2.12    ! frystyk   408:     if (!HTLib_secure()) {
2.1       frystyk   409:        HTCache_setRoot(cache_root);
2.12    ! frystyk   410:        HTCacheEnable = YES;
        !           411:        return YES;
        !           412:     }
        !           413:     return NO;
2.1       frystyk   414: }
                    415: 
                    416: 
                    417: /*     Disable Cache
                    418: **     ------------
                    419: **     Turns off the cache. Note that the cache can be disabled and enabled
                    420: **     at any time. The cache root is kept and can be reused during the
                    421: **     execution.
                    422: */
2.12    ! frystyk   423: PUBLIC BOOL HTCache_disable (void)
2.1       frystyk   424: {
                    425:     HTCacheEnable = NO;
                    426:     return YES;
                    427: }
                    428: 
                    429: /*     Is Cache Enabled
                    430: **     ----------------
                    431: **     Returns YES or NO. Also makes sure that we have a root value
                    432: **     (even though it might be invalid)
                    433: */
2.12    ! frystyk   434: PUBLIC BOOL HTCache_isEnabled (void)
2.1       frystyk   435: {
2.12    ! frystyk   436:     return HTCacheEnable;
2.1       frystyk   437: }
                    438: 
                    439: 
                    440: /*     Set Cache Root
                    441: **     --------------
                    442: **     If `cache_root' is NULL then the current value (might be a define)
                    443: **     Should we check if the cache_root is actually OK? I think not!
                    444: */
2.12    ! frystyk   445: PUBLIC BOOL HTCache_setRoot (CONST char * cache_root)
2.1       frystyk   446: {
                    447:     StrAllocCopy(HTCacheRoot, cache_root ? cache_root : HT_CACHE_ROOT);
                    448:     if (*(HTCacheRoot+strlen(HTCacheRoot)-1) != '/')
                    449:        StrAllocCat(HTCacheRoot, "/");
                    450:     if (CACHE_TRACE)
2.10      frystyk   451:        TTYPrint(TDEST, "Cache Root.. Root set to `%s\'\n", HTCacheRoot);
2.1       frystyk   452:     return YES;
                    453: }
                    454: 
                    455: 
                    456: /*     Get Cache Root
                    457: **     --------------
                    458: */
2.12    ! frystyk   459: PUBLIC CONST char * HTCache_getRoot (void)
2.1       frystyk   460: {
                    461:     return HTCacheRoot;
                    462: }
                    463: 
                    464: /*     Free Cache Root
                    465: **     --------------
                    466: **     For clean up memory
                    467: */
2.12    ! frystyk   468: PUBLIC void HTCache_freeRoot (void)
2.1       frystyk   469: {
                    470:     FREE(HTCacheRoot);
                    471: }
                    472: 
                    473: /* ------------------------------------------------------------------------- */
2.7       frystyk   474: /*                              MEMORY CACHE                                */
                    475: /* ------------------------------------------------------------------------- */
                    476: 
                    477: /*
                    478: **  Register a Memory Cache Handler. This function is introduced in order to
                    479: **  avoid having references to HText module outside HTML.
                    480: */
                    481: PUBLIC BOOL HTMemoryCache_register (HTMemoryCacheHandler * cbf)
                    482: {
                    483:     return (HTMemoryCache = cbf) ? YES : NO;
                    484: }
                    485: 
                    486: PUBLIC BOOL HTMemoryCache_unRegister (void)
                    487: {
                    488:     HTMemoryCache = NULL;
                    489:     return YES;
                    490: }
                    491: 
                    492: PUBLIC int HTMemoryCache_check (HTRequest * request)
                    493: {
2.8       frystyk   494:     return HTMemoryCache ? HTMemoryCache(request,HTExpMode,HTExpNotify) : 0;
2.7       frystyk   495: }
                    496: 
                    497: /*
                    498: **  Set the mode for how we handle Expires header from the local history
                    499: **  list. The following modes are available:
                    500: **
                    501: **     HT_EXPIRES_IGNORE : No update in the history list
                    502: **     HT_EXPIRES_NOTIFY : The user is notified but no reload
                    503: **     HT_EXPIRES_AUTO   : Automatic reload
                    504: **
                    505: **  The notify only makes sense when HT_EXPIRES_NOTIFY. NULL is valid.
                    506: */
2.12    ! frystyk   507: PUBLIC void HTCache_setExpiresMode (HTExpiresMode mode, char * notify)
2.7       frystyk   508: {
                    509:     HTExpMode = mode;
                    510:     HTExpNotify = notify;
                    511: }
                    512: 
2.12    ! frystyk   513: PUBLIC HTExpiresMode HTCache_expiresMode (char ** notify)
2.7       frystyk   514: {
                    515:     *notify = HTExpNotify ? HTExpNotify : "This version has expired!";
                    516:     return HTExpMode;
                    517: }
                    518: 
                    519: /* ------------------------------------------------------------------------- */
2.2       frystyk   520: /*                              CACHE MANAGER                               */
                    521: /* ------------------------------------------------------------------------- */
                    522: 
                    523: /*
                    524: **  Verifies if a cache object exists for this URL and if so returns a URL
                    525: **  for the cached object. It does not verify whether the object is valid or
                    526: **  not, for example it might have expired.
                    527: **
                    528: **  Returns: file name If OK (must be freed by caller)
                    529: **          NULL       If no cache object found
                    530: */
2.12    ! frystyk   531: PUBLIC char * HTCache_getReference (char * url)
2.2       frystyk   532: {
                    533:     if (url && HTCache_isEnabled()) {
                    534:        char *fnam = cache_file_name(url);
                    535:        if (fnam) {
                    536:            FILE *fp = fopen(fnam, "r");
                    537:            if (fp) {
                    538:                char *url = HTCache_wwwName(fnam);
                    539:                fclose(fp);
                    540:                if (CACHE_TRACE)
2.10      frystyk   541:                    TTYPrint(TDEST, "Cache....... Object found `%s\'\n", url);
2.2       frystyk   542:                free(fnam);
                    543:                return url;
                    544:            } else
                    545:                free(fnam);
                    546:        }
                    547:     }
                    548:     return NULL;
                    549: }
                    550: 
                    551: /*
                    552: **  This function checks whether a document has expired or not.
                    553: **  The check is based on the metainformation passed in the anchor object
                    554: **  The function returns YES or NO.
                    555: */
2.12    ! frystyk   556: PUBLIC BOOL HTCache_isValid (HTParentAnchor * anchor)
2.2       frystyk   557: {
                    558:     time_t cur = time(NULL);
                    559:     time_t expires = HTAnchor_expires(anchor);
                    560:     return (expires>0 && cur>0 && expires<cur) ? NO : YES;
                    561: }
                    562: 
                    563: /* ------------------------------------------------------------------------- */
2.1       frystyk   564: /*                          CACHE WRITER STREAM                             */
                    565: /* ------------------------------------------------------------------------- */
                    566: 
2.12    ! frystyk   567: PRIVATE int HTCache_flush (HTStream * me)
2.1       frystyk   568: {
                    569:     return (fflush(me->fp) == EOF) ? HT_ERROR : HT_OK;
                    570: }
                    571: 
2.12    ! frystyk   572: PRIVATE int HTCache_putBlock (HTStream * me, CONST char * s, int  l)
2.1       frystyk   573: {
                    574:     int status = (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK;
                    575:     if (l > 1 && status == HT_OK)
                    576:        (void) HTCache_flush(me);
                    577:     return status;
                    578: }
                    579: 
2.12    ! frystyk   580: PRIVATE int HTCache_putChar (HTStream * me, char c)
2.1       frystyk   581: {
                    582:     return HTCache_putBlock(me, &c, 1);
                    583: }
                    584: 
2.12    ! frystyk   585: PRIVATE int HTCache_putString (HTStream * me, CONST char * s)
2.1       frystyk   586: {
                    587:     return HTCache_putBlock(me, s, (int) strlen(s));
                    588: }
                    589: 
2.12    ! frystyk   590: PRIVATE int HTCache_free (HTStream * me)
2.1       frystyk   591: {
2.7       frystyk   592:     me->cache->load_delay = time(NULL) - me->cache->start_time;
2.1       frystyk   593:     fclose(me->fp);
                    594:     free(me);
                    595:     return HT_OK;
                    596: }
                    597: 
2.12    ! frystyk   598: PRIVATE int HTCache_abort (HTStream * me, HTList * e)
2.1       frystyk   599: {
                    600:     if (CACHE_TRACE)
2.10      frystyk   601:        TTYPrint(TDEST, "Cache....... ABORTING\n");
2.1       frystyk   602:     if (me->fp)
                    603:        fclose(me->fp);
                    604:     if (me->cache)
                    605:        HTCache_remove(me->cache);
                    606:     free(me);
                    607:     return HT_ERROR;
                    608: }
                    609: 
                    610: PRIVATE CONST HTStreamClass HTCacheClass =
                    611: {              
                    612:     "Cache",
                    613:     HTCache_flush,
                    614:     HTCache_free,
                    615:     HTCache_abort,
                    616:     HTCache_putChar,
                    617:     HTCache_putString,
                    618:     HTCache_putBlock
                    619: };
                    620: 
                    621: 
                    622: /*     Cache Writer
                    623: **     ------------------
                    624: **
                    625: */
2.12    ! frystyk   626: PUBLIC HTStream* HTCacheWriter (HTRequest *    request,
        !           627:                                void *          param,
        !           628:                                HTFormat        input_format,
        !           629:                                HTFormat        output_format,
        !           630:                                HTStream *      output_stream)
2.1       frystyk   631: {
                    632:     char *fnam;
                    633:     HTStream *me;
2.12    ! frystyk   634:     if (!HTCacheEnable) {
        !           635:        if (CACHE_TRACE) TTYPrint(TDEST, "Cache....... Not enabled\n");
2.1       frystyk   636:        return HTBlackHole();
                    637:     }
                    638: 
                    639:     /* Get a file name and open file */
                    640:     if ((fnam = HTCache_getName(HTAnchor_physical(request->anchor))) == NULL)
                    641:        return HTBlackHole();
                    642: 
                    643:     /* Set up the stream */
                    644:     if ((me = (HTStream *) calloc(sizeof(*me), 1)) == NULL)
                    645:        outofmem(__FILE__, "Cache");
                    646:     me->isa = &HTCacheClass;
                    647:     me->request = request;
2.5       frystyk   648:     if ((me->fp = fopen(fnam, "wb")) == NULL) {
2.1       frystyk   649:        if (CACHE_TRACE)
2.10      frystyk   650:            TTYPrint(TDEST, "Cache....... Can't open %s for writing\n", fnam);
2.1       frystyk   651:        free(fnam);
                    652:        return HTBlackHole();
                    653:     } else
                    654:        if (CACHE_TRACE)
2.10      frystyk   655:            TTYPrint(TDEST, "Cache....... Creating file %s\n", fnam);
2.1       frystyk   656: 
                    657:     /* Set up a cache record */
2.7       frystyk   658:     if ((me->cache = (HTCache *) calloc(sizeof(*me->cache), 1)) == NULL)
2.1       frystyk   659:        outofmem(__FILE__, "Cache");
                    660:     me->cache->filename = fnam;
                    661:     me->cache->start_time = time(NULL);
                    662:     me->cache->format = input_format;
                    663: 
                    664:     /* Keep a global list of all cache items */
2.7       frystyk   665:     if (!HTCacheList) HTCacheList = HTList_new();
                    666:     HTList_addObject(HTCacheList, me->cache);
                    667:     limit_cache(HTCacheList);           /* Limit number (not size) of files */
2.1       frystyk   668:     return me;
                    669: }

Webmaster