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

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

Webmaster