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