Annotation of libwww/Library/src/HTBind.c, revision 2.1

2.1     ! frystyk     1: /*                                                                  HTBind.c
        !             2: **     FILE SUFFIX BIND MANAGER
        !             3: **
        !             4: **     (c) COPYRIGHT MIT 1995
        !             5: **     Please first read the full copyright statement in the file COPYRIGH.
        !             6: **
        !             7: **     This module sets up the binding between a file Bind and a media
        !             8: **     type, language, encoding etc. In a client application the Binds
        !             9: **     are used in protocols that does not support media types etc., like
        !            10: **     FTP, and in server applications they are used to make the bindings
        !            11: **     between the server and the local file store that the server can
        !            12: **     serve to the rest of the world (well almost). The HTFormat module
        !            13: **     holds this information against the accept headers received in a
        !            14: **     request and uses if for format negotiation. All the binding management
        !            15: **     can all be replace by a database interface. 
        !            16: **
        !            17: ** History:
        !            18: **        Feb 91       Written Tim Berners-Lee CERN/CN
        !            19: **        Apr 91       vms-vms access included using DECnet syntax
        !            20: **     26 Jun 92 (JFG) When running over DECnet, suppressed FTP.
        !            21: **                     Fixed access bug for relative names on VMS.
        !            22: **        Sep 93 (MD)  Access to VMS files allows sharing.
        !            23: **     15 Nov 93 (MD)  Moved HTVMSname to HTVMSUTILS.C
        !            24: **     22 Feb 94 (MD)  Excluded two routines if we are not READING directories
        !            25: **     18 May 94 (HF)  Directory stuff removed and stream handling updated,
        !            26: **                     error messages introduced etc.
        !            27: **     10 Maj 95 HF    Spawned off from HTFile in order to make it easier to
        !            28: **                     override by a new module. It's now based on anchors
        !            29: **                     and hash tables
        !            30: ** Bugs:
        !            31: */
        !            32: 
        !            33: /* Library Includes */
        !            34: #include "tcp.h"
        !            35: #include "HTUtils.h"
        !            36: #include "HTString.h"
        !            37: #include "HTAnchor.h"
        !            38: #include "HTAtom.h"
        !            39: #include "HTParse.h"
        !            40: 
        !            41: #if 0
        !            42: #include "HTTCP.h"
        !            43: #include "HTWriter.h"
        !            44: #include "HTFWrite.h"
        !            45: #include "HTInit.h"
        !            46: #include "HTBTree.h"
        !            47: #include "HTFormat.h"
        !            48: #include "HTMulti.h"
        !            49: #include "HTError.h"
        !            50: #endif
        !            51: 
        !            52: #ifdef VMS
        !            53: #include "HTVMSUtils.h"
        !            54: #endif
        !            55: 
        !            56: #include "HTBind.h"                                     /* Implemented here */
        !            57: 
        !            58: typedef struct _HTBind {
        !            59:     char *     suffix;
        !            60:     HTFormat   type;                   /* Content-Type */
        !            61:     HTEncoding encoding;               /* Content-Encoding */
        !            62:     HTLanguage language;               /* Content-Language */
        !            63:     double     quality;
        !            64: } HTBind;
        !            65: 
        !            66: #define HASH_SIZE      101        /* Arbitrary prime. Memory/speed tradeoff */
        !            67: 
        !            68: /* Suffix registration */
        !            69: PRIVATE BOOL HTCaseSen = YES;                /* Are suffixes case sensitive */
        !            70: PRIVATE char *HTDelimiters = NULL;                       /* Set of suffixes */
        !            71: 
        !            72: PRIVATE HTList **HTBindings = NULL;   /* Point to table of lists of bindings */
        !            73: 
        !            74: PRIVATE HTBind no_suffix = { "*", NULL, NULL, NULL, 1.0 };
        !            75: PRIVATE HTBind unknown_suffix = { "*.*", NULL, NULL, NULL, 1.0};
        !            76: 
        !            77: /* ------------------------------------------------------------------------- */
        !            78: 
        !            79: /*     
        !            80: **     Set up the list of suffix bindings. Done by HTLibInit
        !            81: */
        !            82: PUBLIC BOOL HTBind_init NOARGS
        !            83: {
        !            84:     if (!HTBindings)
        !            85:        HTBindings = (HTList**) calloc(HASH_SIZE, sizeof(HTList *));
        !            86:     StrAllocCopy(HTDelimiters, DEFAULT_SUFFIXES);
        !            87:     return YES;
        !            88: }
        !            89: 
        !            90: 
        !            91: /*
        !            92: **     Cleans up the memory allocated by file bindings
        !            93: **     Done by HTLibTerminate().
        !            94: **     Written by Eric Sink, eric@spyglass.com, and Henrik
        !            95: */
        !            96: PUBLIC BOOL HTBind_deleteAll NOARGS
        !            97: {
        !            98:     int cnt;
        !            99:     HTList *cur;
        !           100:     if (!HTBindings)
        !           101:        return NO;
        !           102:     for (cnt=0; cnt<HASH_SIZE; cnt++) {
        !           103:        if ((cur = HTBindings[cnt])) { 
        !           104:            HTBind *pres;
        !           105:            while ((pres = (HTBind *) HTList_nextObject(cur)) != NULL) {
        !           106:                FREE(pres->suffix);
        !           107:                free(pres);
        !           108:            }
        !           109:        }
        !           110:        HTList_delete(HTBindings[cnt]);
        !           111:        HTBindings[cnt] = NULL;
        !           112:     }
        !           113:     FREE(HTDelimiters);
        !           114:     return YES;
        !           115: }
        !           116: 
        !           117: 
        !           118: /*     Make suffix bindings case sensitive
        !           119: **     -----------------------------------
        !           120: */
        !           121: PUBLIC void HTBind_setCaseSensitive ARGS1(BOOL, sensitive)
        !           122: {
        !           123:     HTCaseSen = sensitive;
        !           124: }
        !           125: 
        !           126: 
        !           127: /*     Get set of suffixes
        !           128: **     -------------------
        !           129: */
        !           130: PUBLIC CONST char *HTBind_getDelimiters NOARGS
        !           131: {
        !           132:     return HTDelimiters;
        !           133: }
        !           134: 
        !           135: 
        !           136: /*     Change set of suffixes
        !           137: **     ----------------------
        !           138: */
        !           139: PUBLIC void HTBind_setDelimiters ARGS1(CONST char *, new_suffixes)
        !           140: {
        !           141:     if (new_suffixes && *new_suffixes)
        !           142:        StrAllocCopy(HTDelimiters, new_suffixes);
        !           143: }
        !           144: 
        !           145: 
        !           146: /*     Define the representation associated with a file suffix
        !           147: **     -------------------------------------------------------
        !           148: **
        !           149: **     Calling this with suffix set to "*" will set the default
        !           150: **     representation.
        !           151: **     Calling this with suffix set to "*.*" will set the default
        !           152: **     representation for unknown suffix files which contain a "."
        !           153: **
        !           154: **     If filename suffix is already defined its previous
        !           155: **     definition is overridden (or modified)
        !           156: */
        !           157: PUBLIC BOOL HTBind_setType ARGS3(CONST char *, suffix,
        !           158:                                 CONST char *,  representation,
        !           159:                                 double,        value)
        !           160: {
        !           161:     return HTBind_setBinding(suffix, representation, NULL, NULL, value);
        !           162: }
        !           163: 
        !           164: PUBLIC BOOL HTBind_setEncoding ARGS3(CONST char *,     suffix,
        !           165:                                     CONST char *,      encoding,
        !           166:                                     double,            value)
        !           167: {
        !           168:     return HTBind_setBinding(suffix, NULL, encoding, NULL, value);
        !           169: }
        !           170: 
        !           171: PUBLIC BOOL HTBind_setLanguage ARGS3(CONST char *,     suffix,
        !           172:                                     CONST char *,      language,
        !           173:                                     double,            value)
        !           174: {
        !           175:     return HTBind_setBinding(suffix, NULL, NULL, language, value);
        !           176: }
        !           177: 
        !           178: PUBLIC BOOL HTBind_setBinding ARGS5(CONST char *,      suffix,
        !           179:                                    CONST char *,       representation,
        !           180:                                    CONST char *,       encoding,
        !           181:                                    CONST char *,       language,
        !           182:                                    double,             value)
        !           183: {
        !           184:     HTBind * suff;
        !           185:     if (!suffix)
        !           186:        return NO;
        !           187:     if (!strcmp(suffix, "*"))
        !           188:        suff = &no_suffix;
        !           189:     else if (!strcmp(suffix, "*.*"))
        !           190:        suff = &unknown_suffix;
        !           191:     else {
        !           192:        HTList *suflist;
        !           193:        int hash=0;
        !           194:        CONST char *ptr=suffix;
        !           195: 
        !           196:        /* Select list from hash table */
        !           197:        for( ; *ptr; ptr++)
        !           198:            hash = (int) ((hash * 3 + (*(unsigned char*)ptr)) % HASH_SIZE);
        !           199: 
        !           200:        if (!HTBindings[hash]) HTBindings[hash] = HTList_new();
        !           201:        suflist = HTBindings[hash];
        !           202: 
        !           203:        /* Look for existing binding */
        !           204:        {
        !           205:            HTList *cur = suflist;
        !           206:            while ((suff = (HTBind *) HTList_nextObject(cur)) != NULL) {
        !           207:                if (!strcmp(suff->suffix, suffix))
        !           208:                    break;
        !           209:            }
        !           210:        }
        !           211: 
        !           212:        /* If not found -- create a new node */
        !           213:        if (!suff) {
        !           214:            if ((suff = (HTBind *) calloc(1, sizeof(HTBind))) == NULL)
        !           215:                outofmem(__FILE__, "HTHTBind_setBinding");
        !           216:            HTList_addObject(suflist, (void *) suff);
        !           217:            StrAllocCopy(suff->suffix, suffix);
        !           218:        }
        !           219:     }
        !           220: 
        !           221:     /* Set the appropriate values */
        !           222:     {
        !           223:        char *str = NULL;
        !           224:        char *ptr;
        !           225:        if (representation) {
        !           226:            StrAllocCopy(str, representation);
        !           227:            for (ptr=str; *ptr; ptr++)
        !           228:                *ptr = TOLOWER(*ptr);
        !           229:            suff->type = HTAtom_for(str);
        !           230:        }
        !           231:        if (language) {
        !           232:            StrAllocCopy(str, language);
        !           233:            for (ptr=str; *ptr; ptr++)
        !           234:                *ptr = TOLOWER(*ptr);
        !           235:            suff->language = HTAtom_for(str);
        !           236:        }
        !           237:        if (encoding) {
        !           238:            StrAllocCopy(str, encoding);
        !           239:            for (ptr=str; *ptr; ptr++)
        !           240:                *ptr = TOLOWER(*ptr);
        !           241:            suff->encoding = HTAtom_for(str);
        !           242:        }
        !           243:        FREE(str);
        !           244:        suff->quality = value;
        !           245:     }
        !           246:     return YES;
        !           247: }
        !           248: 
        !           249: 
        !           250: /*     Determine a suitable suffix
        !           251: **     ---------------------------
        !           252: **  Use the set of bindings to find a suitable suffix (or index)
        !           253: **  for a certain combination of language, media type and encoding
        !           254: **  given in the anchor.
        !           255: **
        !           256: **  Returns a pointer to a suitable suffix string that must be freed 
        !           257: **  by the caller. If more than one suffix is found they are all
        !           258: **  concatenated using the first delimiter in HTDelimiters.
        !           259: **  If no suffix is found, NULL is returned.
        !           260: */
        !           261: PUBLIC CONST char * HTBind_getSuffix ARGS1(HTParentAnchor *, anchor)
        !           262: {
        !           263:     int cnt;
        !           264:     HTList *cur;
        !           265:     char *suffix = NULL;
        !           266:     char delimiter = *HTDelimiters;
        !           267:     if (anchor) {
        !           268:        for (cnt=0; cnt<HASH_SIZE; cnt++) {
        !           269:            if ((cur = HTBindings[cnt])) { 
        !           270:                HTBind *pres;
        !           271:                while ((pres = (HTBind *) HTList_nextObject(cur)) != NULL) {
        !           272:                    if ((pres->type && pres->type==anchor->content_type) ||
        !           273:                        (pres->encoding &&
        !           274:                         pres->encoding!=WWW_ENC_7BIT &&
        !           275:                         pres->encoding!=WWW_ENC_8BIT &&
        !           276:                         pres->encoding!=WWW_ENC_BINARY &&
        !           277:                         pres->encoding==anchor->content_encoding) ||
        !           278:                        (pres->language &&
        !           279:                         pres->language == anchor->content_language)) {
        !           280:                        StrAllocCat(suffix, &delimiter);
        !           281:                        StrAllocCat(suffix, pres->suffix);
        !           282:                    }
        !           283:                }
        !           284:            }
        !           285:        }
        !           286:     }
        !           287:     return suffix;
        !           288: }
        !           289: 
        !           290: /*     Determine the description of a file
        !           291: **     -----------------------------------
        !           292: **  Use the set of bindings to find the combination of language,
        !           293: **  media type and encoding of a given file name.
        !           294: **
        !           295: **  If more than one suffix is found they are all searched. The last suffix
        !           296: **  has highest priority, the first one lowest. See also HTBind_getFormat()
        !           297: **
        !           298: **  Returns a contentdescription object with the representations found. This
        !           299: **  must be free by the caller
        !           300: */
        !           301: PUBLIC HTContentDescription * HTBind_getDescription ARGS1(char *, file)
        !           302: {
        !           303:     HTContentDescription * cd;
        !           304:     cd = (HTContentDescription *) calloc(1, sizeof(HTContentDescription));
        !           305:     if (!cd) outofmem(__FILE__, "HTContentDescription");
        !           306:     if (HTBind_getFormat(file, &cd->content_type, &cd->content_encoding,
        !           307:                         &cd->content_language, &cd->quality))
        !           308:        return cd;
        !           309:     else {
        !           310:        free(cd);
        !           311:        return NULL;
        !           312:     }
        !           313: }
        !           314: 
        !           315: /*     Determine the content of an Anchor
        !           316: **     ----------------------------------
        !           317: **  Use the set of bindings to find the combination of language,
        !           318: **  media type and encoding of a given anchor.
        !           319: **
        !           320: **  If more than one suffix is found they are all searched. The last suffix
        !           321: **  has highest priority, the first one lowest. See also HTBind_getFormat()
        !           322: **
        !           323: **  Returns the anchor object with the representations found
        !           324: */
        !           325: PUBLIC BOOL HTBind_getBindings ARGS1(HTParentAnchor *, anchor)
        !           326: {
        !           327:     BOOL status = NO;
        !           328:     double quality=1.0;                  /* @@@ Should we add this into the anchor? */
        !           329:     if (anchor) {
        !           330:        char *addr = HTAnchor_physical(anchor);
        !           331:        char *path = HTParse(addr, "", PARSE_PATH+PARSE_PUNCTUATION);
        !           332:        char *file = strrchr(path, '/');
        !           333:        if (!file) {
        !           334:            if (BIND_TRACE)
        !           335:                fprintf(TDEST,"Get Binding. No file name found `%s\'\n", path);
        !           336:        } else {
        !           337:            status = HTBind_getFormat(file, &anchor->content_type,
        !           338:                                      &anchor->content_encoding,
        !           339:                                      &anchor->content_language,
        !           340:                                      &quality);
        !           341:        }
        !           342:        FREE(path);
        !           343:     }
        !           344:     return status;
        !           345: }
        !           346: 
        !           347: 
        !           348: /*     Determine the content of an file name
        !           349: **     -------------------------------------
        !           350: **  Use the set of bindings to find the combination of language,
        !           351: **  media type and encoding of a given anchor.
        !           352: **
        !           353: **  If more than one suffix is found they are all searched. The last suffix
        !           354: **  has highest priority, the first one lowest. See also HTBind_getBindings()
        !           355: **
        !           356: **  Returns the format, encoding, and language found
        !           357: */
        !           358: PUBLIC BOOL HTBind_getFormat ARGS5(CONST char *,filename,
        !           359:                                   HTFormat *,  format,
        !           360:                                   HTEncoding *,encoding,
        !           361:                                   HTLanguage *,language,
        !           362:                                   double *, quality)
        !           363: {
        !           364:     int sufcnt=0;
        !           365:     char *file=NULL;
        !           366:     if (*quality < HT_EPSILON)
        !           367:        *quality = 1.0;                            /* Set to a neutral value */
        !           368:     StrAllocCopy(file, filename);
        !           369:     HTUnEscape(file);                             /* Unescape the file name */
        !           370:     if (strtok(file, HTDelimiters)) {           /* Do we have any suffixes? */
        !           371:        char *suffix;
        !           372:        while ((suffix = strtok(NULL, HTDelimiters)) != NULL) {
        !           373:            HTBind *suff=NULL;
        !           374:            int hash=0;
        !           375:            char *ptr=suffix;
        !           376:            if (BIND_TRACE)
        !           377:                fprintf(TDEST, "Get Binding. Look for '%s\' ", suffix);
        !           378:            sufcnt++;
        !           379: 
        !           380:            /* Select list from hash table */
        !           381:            for( ; *ptr; ptr++)
        !           382:                hash = (int)((hash*3+(*(unsigned char*)ptr)) % HASH_SIZE);
        !           383: 
        !           384:            /* Now search list for entries (case or non case sensitive) */
        !           385:            if (HTBindings[hash]) {
        !           386:                HTList *cur = HTBindings[hash];
        !           387:                while ((suff = (HTBind *) HTList_nextObject(cur))) {
        !           388:                    if ((HTCaseSen && !strcmp(suff->suffix, suffix)) ||
        !           389:                        !strcasecomp(suff->suffix, suffix)) {
        !           390:                        if (BIND_TRACE) fprintf(TDEST, "Found!\n");
        !           391:                        if (suff->type) *format = suff->type;
        !           392:                        if (suff->encoding) *encoding = suff->encoding;
        !           393:                        if (suff->language) *language = suff->language;
        !           394:                        if (suff->quality > HT_EPSILON)
        !           395:                            *quality *= suff->quality;
        !           396:                        break;
        !           397:                    }
        !           398:                }
        !           399:            }
        !           400:            if (!suff) {        /* We don't have this suffix - use default */
        !           401:                if (BIND_TRACE)
        !           402:                    fprintf(TDEST,"Not found - use default for \'*.*\'\n");
        !           403:                *format = unknown_suffix.type;
        !           404:                *encoding = unknown_suffix.encoding;
        !           405:                *language = unknown_suffix.language;
        !           406:                *quality = unknown_suffix.quality;
        !           407:            }
        !           408:        } /* while we still have suffixes */
        !           409:     }
        !           410:     if (!sufcnt) {             /* No suffix so use default value */
        !           411:        if (BIND_TRACE)
        !           412:            fprintf(TDEST, "Get Binding. No suffix found - using default '%s\'\n", filename);
        !           413:        *format = no_suffix.type;
        !           414:        *encoding = no_suffix.encoding;
        !           415:        *language = no_suffix.language;
        !           416:        *quality = no_suffix.quality;
        !           417:     }
        !           418:     if (BIND_TRACE)
        !           419:        fprintf(TDEST, "Get Binding. Result for '%s\' is: type='%s\', encoding='%s\', language='%s\' with quality %.2f\n",
        !           420:                filename,
        !           421:                *format ? HTAtom_name(*format) : "unknown",
        !           422:                *encoding ? HTAtom_name(*encoding) : "unknown",
        !           423:                *language ? HTAtom_name(*language) : "unknown",
        !           424:                *quality);
        !           425:     free(file);
        !           426:     return YES;
        !           427: }
        !           428: 

Webmaster