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

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: #include "HTBind.h"                                     /* Implemented here */
                     41: 
                     42: typedef struct _HTBind {
                     43:     char *     suffix;
                     44:     HTFormat   type;                   /* Content-Type */
                     45:     HTEncoding encoding;               /* Content-Encoding */
                     46:     HTLanguage language;               /* Content-Language */
                     47:     double     quality;
                     48: } HTBind;
                     49: 
                     50: #define HASH_SIZE      101        /* Arbitrary prime. Memory/speed tradeoff */
                     51: 
                     52: /* Suffix registration */
                     53: PRIVATE BOOL HTCaseSen = YES;                /* Are suffixes case sensitive */
                     54: PRIVATE char *HTDelimiters = NULL;                       /* Set of suffixes */
                     55: 
                     56: PRIVATE HTList **HTBindings = NULL;   /* Point to table of lists of bindings */
                     57: 
                     58: PRIVATE HTBind no_suffix = { "*", NULL, NULL, NULL, 1.0 };
                     59: PRIVATE HTBind unknown_suffix = { "*.*", NULL, NULL, NULL, 1.0};
                     60: 
                     61: /* ------------------------------------------------------------------------- */
                     62: 
                     63: /*     
                     64: **     Set up the list of suffix bindings. Done by HTLibInit
                     65: */
2.11      frystyk    66: PUBLIC BOOL HTBind_init (void)
2.1       frystyk    67: {
2.8       frystyk    68:     if (!HTBindings) {
2.1       frystyk    69:        HTBindings = (HTList**) calloc(HASH_SIZE, sizeof(HTList *));
2.8       frystyk    70:        if (!HTBindings) outofmem(__FILE__, "HTBind_init");
                     71:     }
2.1       frystyk    72:     StrAllocCopy(HTDelimiters, DEFAULT_SUFFIXES);
                     73:     return YES;
                     74: }
                     75: 
                     76: 
                     77: /*
                     78: **     Cleans up the memory allocated by file bindings
                     79: **     Done by HTLibTerminate().
                     80: **     Written by Eric Sink, eric@spyglass.com, and Henrik
                     81: */
2.11      frystyk    82: PUBLIC BOOL HTBind_deleteAll (void)
2.1       frystyk    83: {
                     84:     int cnt;
                     85:     HTList *cur;
                     86:     if (!HTBindings)
                     87:        return NO;
                     88:     for (cnt=0; cnt<HASH_SIZE; cnt++) {
                     89:        if ((cur = HTBindings[cnt])) { 
                     90:            HTBind *pres;
                     91:            while ((pres = (HTBind *) HTList_nextObject(cur)) != NULL) {
                     92:                FREE(pres->suffix);
                     93:                free(pres);
                     94:            }
                     95:        }
                     96:        HTList_delete(HTBindings[cnt]);
                     97:        HTBindings[cnt] = NULL;
                     98:     }
                     99:     FREE(HTDelimiters);
                    100:     return YES;
                    101: }
                    102: 
                    103: 
                    104: /*     Make suffix bindings case sensitive
                    105: **     -----------------------------------
                    106: */
2.11      frystyk   107: PUBLIC void HTBind_caseSensitive (BOOL sensitive)
2.1       frystyk   108: {
                    109:     HTCaseSen = sensitive;
                    110: }
                    111: 
                    112: 
                    113: /*     Get set of suffixes
                    114: **     -------------------
                    115: */
2.11      frystyk   116: PUBLIC CONST char *HTBind_delimiters (void)
2.1       frystyk   117: {
                    118:     return HTDelimiters;
                    119: }
                    120: 
                    121: 
                    122: /*     Change set of suffixes
                    123: **     ----------------------
                    124: */
2.11      frystyk   125: PUBLIC void HTBind_setDelimiters (CONST char * new_suffixes)
2.1       frystyk   126: {
                    127:     if (new_suffixes && *new_suffixes)
                    128:        StrAllocCopy(HTDelimiters, new_suffixes);
                    129: }
                    130: 
                    131: 
                    132: /*     Define the representation associated with a file suffix
                    133: **     -------------------------------------------------------
                    134: **
                    135: **     Calling this with suffix set to "*" will set the default
                    136: **     representation.
                    137: **     Calling this with suffix set to "*.*" will set the default
                    138: **     representation for unknown suffix files which contain a "."
                    139: **
                    140: **     If filename suffix is already defined its previous
                    141: **     definition is overridden (or modified)
                    142: */
2.12      frystyk   143: PUBLIC BOOL HTBind_addType (CONST char *       suffix,
                    144:                            CONST char *        representation,
                    145:                            double              value)
2.1       frystyk   146: {
2.11      frystyk   147:     return HTBind_add(suffix, representation, NULL, NULL, value);
2.1       frystyk   148: }
                    149: 
2.11      frystyk   150: PUBLIC BOOL HTBind_addEncoding (CONST char *   suffix,
                    151:                                CONST char *    encoding,
                    152:                                double          value)
2.1       frystyk   153: {
2.11      frystyk   154:     return HTBind_add(suffix, NULL, encoding, NULL, value);
2.1       frystyk   155: }
                    156: 
2.11      frystyk   157: PUBLIC BOOL HTBind_addLanguage (CONST char *   suffix,
                    158:                                CONST char *    language,
                    159:                                double          value)
2.1       frystyk   160: {
2.11      frystyk   161:     return HTBind_add(suffix, NULL, NULL, language, value);
2.1       frystyk   162: }
                    163: 
2.11      frystyk   164: PUBLIC BOOL HTBind_add (CONST char *   suffix,
                    165:                        CONST char *    representation,
                    166:                        CONST char *    encoding,
                    167:                        CONST char *    language,
                    168:                        double          value)
2.1       frystyk   169: {
                    170:     HTBind * suff;
                    171:     if (!suffix)
                    172:        return NO;
                    173:     if (!strcmp(suffix, "*"))
                    174:        suff = &no_suffix;
                    175:     else if (!strcmp(suffix, "*.*"))
                    176:        suff = &unknown_suffix;
                    177:     else {
                    178:        HTList *suflist;
                    179:        int hash=0;
                    180:        CONST char *ptr=suffix;
                    181: 
                    182:        /* Select list from hash table */
                    183:        for( ; *ptr; ptr++)
                    184:            hash = (int) ((hash * 3 + (*(unsigned char*)ptr)) % HASH_SIZE);
                    185: 
                    186:        if (!HTBindings[hash]) HTBindings[hash] = HTList_new();
                    187:        suflist = HTBindings[hash];
                    188: 
                    189:        /* Look for existing binding */
                    190:        {
                    191:            HTList *cur = suflist;
                    192:            while ((suff = (HTBind *) HTList_nextObject(cur)) != NULL) {
                    193:                if (!strcmp(suff->suffix, suffix))
                    194:                    break;
                    195:            }
                    196:        }
                    197: 
                    198:        /* If not found -- create a new node */
                    199:        if (!suff) {
                    200:            if ((suff = (HTBind *) calloc(1, sizeof(HTBind))) == NULL)
2.11      frystyk   201:                outofmem(__FILE__, "HTBind_add");
2.1       frystyk   202:            HTList_addObject(suflist, (void *) suff);
                    203:            StrAllocCopy(suff->suffix, suffix);
                    204:        }
                    205:     }
                    206: 
                    207:     /* Set the appropriate values */
                    208:     {
                    209:        char *str = NULL;
                    210:        char *ptr;
                    211:        if (representation) {
                    212:            StrAllocCopy(str, representation);
                    213:            for (ptr=str; *ptr; ptr++)
                    214:                *ptr = TOLOWER(*ptr);
                    215:            suff->type = HTAtom_for(str);
                    216:        }
                    217:        if (language) {
                    218:            StrAllocCopy(str, language);
                    219:            for (ptr=str; *ptr; ptr++)
                    220:                *ptr = TOLOWER(*ptr);
                    221:            suff->language = HTAtom_for(str);
                    222:        }
                    223:        if (encoding) {
                    224:            StrAllocCopy(str, encoding);
                    225:            for (ptr=str; *ptr; ptr++)
                    226:                *ptr = TOLOWER(*ptr);
                    227:            suff->encoding = HTAtom_for(str);
                    228:        }
                    229:        FREE(str);
                    230:        suff->quality = value;
                    231:     }
                    232:     return YES;
                    233: }
                    234: 
                    235: 
                    236: /*     Determine a suitable suffix
                    237: **     ---------------------------
                    238: **  Use the set of bindings to find a suitable suffix (or index)
                    239: **  for a certain combination of language, media type and encoding
                    240: **  given in the anchor.
                    241: **
                    242: **  Returns a pointer to a suitable suffix string that must be freed 
                    243: **  by the caller. If more than one suffix is found they are all
                    244: **  concatenated using the first delimiter in HTDelimiters.
                    245: **  If no suffix is found, NULL is returned.
                    246: */
2.11      frystyk   247: PUBLIC char * HTBind_getSuffix (HTParentAnchor * anchor)
2.1       frystyk   248: {
                    249:     int cnt;
                    250:     HTList *cur;
                    251:     char *suffix = NULL;
2.5       frystyk   252:     char delimiter[2];
2.4       frystyk   253:     *delimiter = *HTDelimiters;
2.5       frystyk   254:     *(delimiter+1) = '\0';
2.1       frystyk   255:     if (anchor) {
                    256:        for (cnt=0; cnt<HASH_SIZE; cnt++) {
                    257:            if ((cur = HTBindings[cnt])) { 
                    258:                HTBind *pres;
                    259:                while ((pres = (HTBind *) HTList_nextObject(cur)) != NULL) {
                    260:                    if ((pres->type && pres->type==anchor->content_type) ||
                    261:                        (pres->encoding &&
                    262:                         pres->encoding!=WWW_ENC_7BIT &&
                    263:                         pres->encoding!=WWW_ENC_8BIT &&
                    264:                         pres->encoding!=WWW_ENC_BINARY &&
                    265:                         pres->encoding==anchor->content_encoding) ||
                    266:                        (pres->language &&
                    267:                         pres->language == anchor->content_language)) {
2.3       frystyk   268:                        StrAllocCat(suffix, delimiter);
2.1       frystyk   269:                        StrAllocCat(suffix, pres->suffix);
                    270:                    }
                    271:                }
                    272:            }
                    273:        }
                    274:     }
                    275:     return suffix;
                    276: }
                    277: 
                    278: /*     Determine the description of a file
                    279: **     -----------------------------------
                    280: **  Use the set of bindings to find the combination of language,
                    281: **  media type and encoding of a given file name.
                    282: **
                    283: **  If more than one suffix is found they are all searched. The last suffix
                    284: **  has highest priority, the first one lowest. See also HTBind_getFormat()
                    285: **
                    286: **  Returns a contentdescription object with the representations found. This
                    287: **  must be free by the caller
                    288: */
2.11      frystyk   289: PUBLIC HTContentDescription * HTBind_getDescription (char * file)
2.1       frystyk   290: {
                    291:     HTContentDescription * cd;
                    292:     cd = (HTContentDescription *) calloc(1, sizeof(HTContentDescription));
                    293:     if (!cd) outofmem(__FILE__, "HTContentDescription");
                    294:     if (HTBind_getFormat(file, &cd->content_type, &cd->content_encoding,
                    295:                         &cd->content_language, &cd->quality))
                    296:        return cd;
                    297:     else {
                    298:        free(cd);
                    299:        return NULL;
                    300:     }
                    301: }
                    302: 
                    303: /*     Determine the content of an Anchor
                    304: **     ----------------------------------
                    305: **  Use the set of bindings to find the combination of language,
                    306: **  media type and encoding of a given anchor.
                    307: **
                    308: **  If more than one suffix is found they are all searched. The last suffix
                    309: **  has highest priority, the first one lowest. See also HTBind_getFormat()
                    310: **
                    311: **  Returns the anchor object with the representations found
                    312: */
2.11      frystyk   313: PUBLIC BOOL HTBind_getBindings (HTParentAnchor * anchor)
2.1       frystyk   314: {
                    315:     BOOL status = NO;
                    316:     double quality=1.0;                  /* @@@ Should we add this into the anchor? */
                    317:     if (anchor) {
                    318:        char *addr = HTAnchor_physical(anchor);
                    319:        char *path = HTParse(addr, "", PARSE_PATH+PARSE_PUNCTUATION);
2.9       frystyk   320:        char *file;
                    321:        char *end;
                    322:        if ((end = strchr(path, ';')) || (end = strchr(path, '?')) ||
                    323:            (end = strchr(path, '#')))
                    324:            *end = '\0';
                    325:        if ((file = strrchr(path, '/'))) {
                    326:            if (BIND_TRACE)
                    327:                fprintf(TDEST,"Get Binding. for file: `%s\'\n", path);
2.1       frystyk   328:            status = HTBind_getFormat(file, &anchor->content_type,
                    329:                                      &anchor->content_encoding,
                    330:                                      &anchor->content_language,
                    331:                                      &quality);
                    332:        }
                    333:        FREE(path);
                    334:     }
                    335:     return status;
                    336: }
                    337: 
                    338: 
                    339: /*     Determine the content of an file name
                    340: **     -------------------------------------
                    341: **  Use the set of bindings to find the combination of language,
                    342: **  media type and encoding of a given anchor.
                    343: **
                    344: **  If more than one suffix is found they are all searched. The last suffix
                    345: **  has highest priority, the first one lowest. See also HTBind_getBindings()
2.10      frystyk   346: **  Either of format, encoding, or language can be NULL
2.1       frystyk   347: **  Returns the format, encoding, and language found
                    348: */
2.10      frystyk   349: PUBLIC BOOL HTBind_getFormat (CONST char * filename, HTFormat * format,
                    350:                              HTEncoding * enc, HTLanguage * lang,
                    351:                              double * quality)
2.1       frystyk   352: {
                    353:     int sufcnt=0;
                    354:     char *file=NULL;
2.6       frystyk   355: #ifdef HT_REENTRANT
                    356:     char *lasts;                                            /* For strtok_r */
                    357: #endif
2.1       frystyk   358:     if (*quality < HT_EPSILON)
                    359:        *quality = 1.0;                            /* Set to a neutral value */
                    360:     StrAllocCopy(file, filename);
                    361:     HTUnEscape(file);                             /* Unescape the file name */
2.6       frystyk   362: #ifdef HT_REENTRANT
                    363:     if (strtok_r(file, HTDelimiters, &lasts)) {         /* Do we have any suffixes? */
                    364: #else
2.1       frystyk   365:     if (strtok(file, HTDelimiters)) {           /* Do we have any suffixes? */
2.6       frystyk   366: #endif /* HT_REENTRANT */
2.1       frystyk   367:        char *suffix;
2.6       frystyk   368: #ifdef HT_REENTRANT
                    369:        while ((suffix=(char*)strtok_r(NULL, HTDelimiters, &lasts)) != NULL) {
                    370: #else
                    371:        while ((suffix=strtok(NULL, HTDelimiters)) != NULL) {
                    372: #endif /* HT_REENTRANT */
2.1       frystyk   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");
2.10      frystyk   391:                        if (suff->type && format) *format = suff->type;
                    392:                        if (suff->encoding && enc) *enc = suff->encoding;
                    393:                        if (suff->language && lang) *lang = suff->language;
2.1       frystyk   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");
2.10      frystyk   403:                if (format) *format = unknown_suffix.type;
                    404:                if (enc) *enc = unknown_suffix.encoding;
                    405:                if (lang) *lang = unknown_suffix.language;
2.1       frystyk   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);
2.10      frystyk   413:        if (format) *format = no_suffix.type;
                    414:        if (enc) *enc = no_suffix.encoding;
                    415:        if (lang) *lang = no_suffix.language;
2.1       frystyk   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,
2.10      frystyk   421:                (format && *format) ? HTAtom_name(*format) : "unknown",
                    422:                (enc && *enc) ? HTAtom_name(*enc) : "unknown",
                    423:                (lang && *lang) ? HTAtom_name(*lang) : "unknown",
2.1       frystyk   424:                *quality);
                    425:     free(file);
                    426:     return YES;
                    427: }
                    428: 

Webmaster