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

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: */
2.2       frystyk   261: PUBLIC char * HTBind_getSuffix ARGS1(HTParentAnchor *, anchor)
2.1       frystyk   262: {
                    263:     int cnt;
                    264:     HTList *cur;
                    265:     char *suffix = NULL;
2.5       frystyk   266:     char delimiter[2];
2.4       frystyk   267:     *delimiter = *HTDelimiters;
2.5       frystyk   268:     *(delimiter+1) = '\0';
2.1       frystyk   269:     if (anchor) {
                    270:        for (cnt=0; cnt<HASH_SIZE; cnt++) {
                    271:            if ((cur = HTBindings[cnt])) { 
                    272:                HTBind *pres;
                    273:                while ((pres = (HTBind *) HTList_nextObject(cur)) != NULL) {
                    274:                    if ((pres->type && pres->type==anchor->content_type) ||
                    275:                        (pres->encoding &&
                    276:                         pres->encoding!=WWW_ENC_7BIT &&
                    277:                         pres->encoding!=WWW_ENC_8BIT &&
                    278:                         pres->encoding!=WWW_ENC_BINARY &&
                    279:                         pres->encoding==anchor->content_encoding) ||
                    280:                        (pres->language &&
                    281:                         pres->language == anchor->content_language)) {
2.3       frystyk   282:                        StrAllocCat(suffix, delimiter);
2.1       frystyk   283:                        StrAllocCat(suffix, pres->suffix);
                    284:                    }
                    285:                }
                    286:            }
                    287:        }
                    288:     }
                    289:     return suffix;
                    290: }
                    291: 
                    292: /*     Determine the description of a file
                    293: **     -----------------------------------
                    294: **  Use the set of bindings to find the combination of language,
                    295: **  media type and encoding of a given file name.
                    296: **
                    297: **  If more than one suffix is found they are all searched. The last suffix
                    298: **  has highest priority, the first one lowest. See also HTBind_getFormat()
                    299: **
                    300: **  Returns a contentdescription object with the representations found. This
                    301: **  must be free by the caller
                    302: */
                    303: PUBLIC HTContentDescription * HTBind_getDescription ARGS1(char *, file)
                    304: {
                    305:     HTContentDescription * cd;
                    306:     cd = (HTContentDescription *) calloc(1, sizeof(HTContentDescription));
                    307:     if (!cd) outofmem(__FILE__, "HTContentDescription");
                    308:     if (HTBind_getFormat(file, &cd->content_type, &cd->content_encoding,
                    309:                         &cd->content_language, &cd->quality))
                    310:        return cd;
                    311:     else {
                    312:        free(cd);
                    313:        return NULL;
                    314:     }
                    315: }
                    316: 
                    317: /*     Determine the content of an Anchor
                    318: **     ----------------------------------
                    319: **  Use the set of bindings to find the combination of language,
                    320: **  media type and encoding of a given anchor.
                    321: **
                    322: **  If more than one suffix is found they are all searched. The last suffix
                    323: **  has highest priority, the first one lowest. See also HTBind_getFormat()
                    324: **
                    325: **  Returns the anchor object with the representations found
                    326: */
                    327: PUBLIC BOOL HTBind_getBindings ARGS1(HTParentAnchor *, anchor)
                    328: {
                    329:     BOOL status = NO;
                    330:     double quality=1.0;                  /* @@@ Should we add this into the anchor? */
                    331:     if (anchor) {
                    332:        char *addr = HTAnchor_physical(anchor);
                    333:        char *path = HTParse(addr, "", PARSE_PATH+PARSE_PUNCTUATION);
                    334:        char *file = strrchr(path, '/');
                    335:        if (!file) {
                    336:            if (BIND_TRACE)
                    337:                fprintf(TDEST,"Get Binding. No file name found `%s\'\n", path);
                    338:        } else {
                    339:            status = HTBind_getFormat(file, &anchor->content_type,
                    340:                                      &anchor->content_encoding,
                    341:                                      &anchor->content_language,
                    342:                                      &quality);
                    343:        }
                    344:        FREE(path);
                    345:     }
                    346:     return status;
                    347: }
                    348: 
                    349: 
                    350: /*     Determine the content of an file name
                    351: **     -------------------------------------
                    352: **  Use the set of bindings to find the combination of language,
                    353: **  media type and encoding of a given anchor.
                    354: **
                    355: **  If more than one suffix is found they are all searched. The last suffix
                    356: **  has highest priority, the first one lowest. See also HTBind_getBindings()
                    357: **
                    358: **  Returns the format, encoding, and language found
                    359: */
                    360: PUBLIC BOOL HTBind_getFormat ARGS5(CONST char *,filename,
                    361:                                   HTFormat *,  format,
                    362:                                   HTEncoding *,encoding,
                    363:                                   HTLanguage *,language,
                    364:                                   double *, quality)
                    365: {
                    366:     int sufcnt=0;
                    367:     char *file=NULL;
2.6     ! frystyk   368: #ifdef HT_REENTRANT
        !           369:     char *lasts;                                            /* For strtok_r */
        !           370: #endif
2.1       frystyk   371:     if (*quality < HT_EPSILON)
                    372:        *quality = 1.0;                            /* Set to a neutral value */
                    373:     StrAllocCopy(file, filename);
                    374:     HTUnEscape(file);                             /* Unescape the file name */
2.6     ! frystyk   375: #ifdef HT_REENTRANT
        !           376:     if (strtok_r(file, HTDelimiters, &lasts)) {         /* Do we have any suffixes? */
        !           377: #else
2.1       frystyk   378:     if (strtok(file, HTDelimiters)) {           /* Do we have any suffixes? */
2.6     ! frystyk   379: #endif /* HT_REENTRANT */
2.1       frystyk   380:        char *suffix;
2.6     ! frystyk   381: #ifdef HT_REENTRANT
        !           382:        while ((suffix=(char*)strtok_r(NULL, HTDelimiters, &lasts)) != NULL) {
        !           383: #else
        !           384:        while ((suffix=strtok(NULL, HTDelimiters)) != NULL) {
        !           385: #endif /* HT_REENTRANT */
2.1       frystyk   386:            HTBind *suff=NULL;
                    387:            int hash=0;
                    388:            char *ptr=suffix;
                    389:            if (BIND_TRACE)
                    390:                fprintf(TDEST, "Get Binding. Look for '%s\' ", suffix);
                    391:            sufcnt++;
                    392: 
                    393:            /* Select list from hash table */
                    394:            for( ; *ptr; ptr++)
                    395:                hash = (int)((hash*3+(*(unsigned char*)ptr)) % HASH_SIZE);
                    396: 
                    397:            /* Now search list for entries (case or non case sensitive) */
                    398:            if (HTBindings[hash]) {
                    399:                HTList *cur = HTBindings[hash];
                    400:                while ((suff = (HTBind *) HTList_nextObject(cur))) {
                    401:                    if ((HTCaseSen && !strcmp(suff->suffix, suffix)) ||
                    402:                        !strcasecomp(suff->suffix, suffix)) {
                    403:                        if (BIND_TRACE) fprintf(TDEST, "Found!\n");
                    404:                        if (suff->type) *format = suff->type;
                    405:                        if (suff->encoding) *encoding = suff->encoding;
                    406:                        if (suff->language) *language = suff->language;
                    407:                        if (suff->quality > HT_EPSILON)
                    408:                            *quality *= suff->quality;
                    409:                        break;
                    410:                    }
                    411:                }
                    412:            }
                    413:            if (!suff) {        /* We don't have this suffix - use default */
                    414:                if (BIND_TRACE)
                    415:                    fprintf(TDEST,"Not found - use default for \'*.*\'\n");
                    416:                *format = unknown_suffix.type;
                    417:                *encoding = unknown_suffix.encoding;
                    418:                *language = unknown_suffix.language;
                    419:                *quality = unknown_suffix.quality;
                    420:            }
                    421:        } /* while we still have suffixes */
                    422:     }
                    423:     if (!sufcnt) {             /* No suffix so use default value */
                    424:        if (BIND_TRACE)
                    425:            fprintf(TDEST, "Get Binding. No suffix found - using default '%s\'\n", filename);
                    426:        *format = no_suffix.type;
                    427:        *encoding = no_suffix.encoding;
                    428:        *language = no_suffix.language;
                    429:        *quality = no_suffix.quality;
                    430:     }
                    431:     if (BIND_TRACE)
                    432:        fprintf(TDEST, "Get Binding. Result for '%s\' is: type='%s\', encoding='%s\', language='%s\' with quality %.2f\n",
                    433:                filename,
                    434:                *format ? HTAtom_name(*format) : "unknown",
                    435:                *encoding ? HTAtom_name(*encoding) : "unknown",
                    436:                *language ? HTAtom_name(*language) : "unknown",
                    437:                *quality);
                    438:     free(file);
                    439:     return YES;
                    440: }
                    441: 

Webmaster