Annotation of libwww/Library/src/HTBind.c, revision 2.23
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.23 ! frystyk 6: ** @(#) $Id: HTBind.c,v 2.22 1996/04/15 21:05:48 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;
2.23 ! frystyk 277: HTList * cur;
! 278: HTChunk * suffix = HTChunk_new(48);
! 279: char delimiter = *HTDelimiters;
! 280: BOOL ct=NO, ce=NO, cl=NO;
2.1 frystyk 281: if (anchor) {
282: for (cnt=0; cnt<HASH_SIZE; cnt++) {
283: if ((cur = HTBindings[cnt])) {
284: HTBind *pres;
2.21 frystyk 285: while ((pres = (HTBind *) HTList_nextObject(cur))) {
2.23 ! frystyk 286: if (!ct && (pres->type && pres->type==anchor->content_type)){
! 287: HTChunk_putc(suffix, delimiter);
! 288: HTChunk_puts(suffix, pres->suffix);
! 289: ct = YES;
! 290: } else if (!ce && pres->encoding && anchor->content_encoding) {
2.21 frystyk 291:
292: /* @@@ Search list @@@ */
2.23 ! frystyk 293: ce = YES;
2.21 frystyk 294:
2.23 ! frystyk 295: } else if (!cl && !pres->language && anchor->content_language) {
2.21 frystyk 296:
297: /* @@@ Search list @@@ */
298:
2.23 ! frystyk 299: cl = YES;
2.1 frystyk 300: }
301: }
302: }
303: }
304: }
2.23 ! frystyk 305: return HTChunk_toCString(suffix);
2.1 frystyk 306: }
307:
2.23 ! frystyk 308: #if 0
2.1 frystyk 309: /* Determine the description of a file
310: ** -----------------------------------
311: ** Use the set of bindings to find the combination of language,
312: ** media type and encoding of a given file name.
313: **
314: ** If more than one suffix is found they are all searched. The last suffix
315: ** has highest priority, the first one lowest. See also HTBind_getFormat()
316: **
317: ** Returns a contentdescription object with the representations found. This
2.21 frystyk 318: ** must be freed by the caller
2.1 frystyk 319: */
2.23 ! frystyk 320: PRIVATE HTContentDescription * HTBind_getDescription (char * file)
2.1 frystyk 321: {
322: HTContentDescription * cd;
2.17 frystyk 323: if ((cd = (HTContentDescription *) HT_CALLOC(1, sizeof(HTContentDescription))) == NULL)
324: HT_OUTOFMEM("HTContentDescription");
2.1 frystyk 325: if (HTBind_getFormat(file, &cd->content_type, &cd->content_encoding,
2.21 frystyk 326: &cd->content_transfer, &cd->content_language,
327: &cd->quality))
2.1 frystyk 328: return cd;
329: else {
2.17 frystyk 330: HT_FREE(cd);
2.1 frystyk 331: return NULL;
332: }
333: }
2.23 ! frystyk 334: #endif /* Not needed anymore */
2.1 frystyk 335:
336: /* Determine the content of an Anchor
337: ** ----------------------------------
338: ** Use the set of bindings to find the combination of language,
339: ** media type and encoding of a given anchor.
2.21 frystyk 340: ** We comprise here as bindings only can have one language and one encoding.
2.1 frystyk 341: ** If more than one suffix is found they are all searched. The last suffix
342: ** has highest priority, the first one lowest. See also HTBind_getFormat()
343: **
344: ** Returns the anchor object with the representations found
345: */
2.11 frystyk 346: PUBLIC BOOL HTBind_getBindings (HTParentAnchor * anchor)
2.1 frystyk 347: {
348: BOOL status = NO;
349: double quality=1.0; /* @@@ Should we add this into the anchor? */
350: if (anchor) {
351: char *addr = HTAnchor_physical(anchor);
352: char *path = HTParse(addr, "", PARSE_PATH+PARSE_PUNCTUATION);
2.9 frystyk 353: char *file;
354: char *end;
355: if ((end = strchr(path, ';')) || (end = strchr(path, '?')) ||
356: (end = strchr(path, '#')))
357: *end = '\0';
358: if ((file = strrchr(path, '/'))) {
2.21 frystyk 359: HTFormat format = NULL;
360: HTEncoding encoding = NULL;
2.22 frystyk 361: HTEncoding transfer = NULL;
2.21 frystyk 362: HTLanguage language = NULL;
363: if (BIND_TRACE) HTTrace("Get Binding. for file: `%s\'\n", path);
2.22 frystyk 364: status = HTBind_getFormat(file, &format, &encoding, &transfer,
2.21 frystyk 365: &language, &quality);
366: if (status) {
367: HTAnchor_setFormat(anchor, format);
2.22 frystyk 368: HTAnchor_setTransfer(anchor, transfer);
2.21 frystyk 369: HTAnchor_addEncoding(anchor, encoding);
370: HTAnchor_addLanguage(anchor, language);
371: }
2.1 frystyk 372: }
2.17 frystyk 373: HT_FREE(path);
2.1 frystyk 374: }
375: return status;
376: }
377:
378:
379: /* Determine the content of an file name
380: ** -------------------------------------
381: ** Use the set of bindings to find the combination of language,
2.21 frystyk 382: ** media type, encoding, and transfer encoding of a given anchor.
2.1 frystyk 383: ** If more than one suffix is found they are all searched. The last suffix
384: ** has highest priority, the first one lowest. See also HTBind_getBindings()
2.10 frystyk 385: ** Either of format, encoding, or language can be NULL
2.1 frystyk 386: ** Returns the format, encoding, and language found
387: */
2.21 frystyk 388: PUBLIC BOOL HTBind_getFormat (const char * filename,
389: HTFormat * format,
390: HTEncoding * enc,
2.22 frystyk 391: HTEncoding * cte,
2.21 frystyk 392: HTLanguage * lang,
393: double * quality)
2.1 frystyk 394: {
395: int sufcnt=0;
396: char *file=NULL;
2.6 frystyk 397: #ifdef HT_REENTRANT
398: char *lasts; /* For strtok_r */
399: #endif
2.1 frystyk 400: if (*quality < HT_EPSILON)
401: *quality = 1.0; /* Set to a neutral value */
402: StrAllocCopy(file, filename);
403: HTUnEscape(file); /* Unescape the file name */
2.6 frystyk 404: #ifdef HT_REENTRANT
405: if (strtok_r(file, HTDelimiters, &lasts)) { /* Do we have any suffixes? */
406: #else
2.1 frystyk 407: if (strtok(file, HTDelimiters)) { /* Do we have any suffixes? */
2.6 frystyk 408: #endif /* HT_REENTRANT */
2.1 frystyk 409: char *suffix;
2.6 frystyk 410: #ifdef HT_REENTRANT
411: while ((suffix=(char*)strtok_r(NULL, HTDelimiters, &lasts)) != NULL) {
412: #else
413: while ((suffix=strtok(NULL, HTDelimiters)) != NULL) {
414: #endif /* HT_REENTRANT */
2.1 frystyk 415: HTBind *suff=NULL;
416: int hash=0;
417: char *ptr=suffix;
418: if (BIND_TRACE)
2.18 eric 419: HTTrace("Get Binding. Look for '%s\' ", suffix);
2.1 frystyk 420: sufcnt++;
421:
422: /* Select list from hash table */
423: for( ; *ptr; ptr++)
424: hash = (int)((hash*3+(*(unsigned char*)ptr)) % HASH_SIZE);
425:
426: /* Now search list for entries (case or non case sensitive) */
427: if (HTBindings[hash]) {
428: HTList *cur = HTBindings[hash];
429: while ((suff = (HTBind *) HTList_nextObject(cur))) {
430: if ((HTCaseSen && !strcmp(suff->suffix, suffix)) ||
431: !strcasecomp(suff->suffix, suffix)) {
2.18 eric 432: if (BIND_TRACE) HTTrace("Found!\n");
2.10 frystyk 433: if (suff->type && format) *format = suff->type;
434: if (suff->encoding && enc) *enc = suff->encoding;
2.22 frystyk 435: if (suff->transfer && cte) *cte = suff->transfer;
2.10 frystyk 436: if (suff->language && lang) *lang = suff->language;
2.1 frystyk 437: if (suff->quality > HT_EPSILON)
438: *quality *= suff->quality;
439: break;
440: }
441: }
442: }
443: if (!suff) { /* We don't have this suffix - use default */
444: if (BIND_TRACE)
2.18 eric 445: HTTrace("Not found - use default for \'*.*\'\n");
2.10 frystyk 446: if (format) *format = unknown_suffix.type;
447: if (enc) *enc = unknown_suffix.encoding;
2.21 frystyk 448: if (cte) *cte = unknown_suffix.transfer;
2.10 frystyk 449: if (lang) *lang = unknown_suffix.language;
2.1 frystyk 450: *quality = unknown_suffix.quality;
451: }
452: } /* while we still have suffixes */
453: }
454: if (!sufcnt) { /* No suffix so use default value */
455: if (BIND_TRACE)
2.18 eric 456: HTTrace("Get Binding. No suffix found - using default '%s\'\n", filename);
2.10 frystyk 457: if (format) *format = no_suffix.type;
458: if (enc) *enc = no_suffix.encoding;
2.21 frystyk 459: if (cte) *cte = no_suffix.transfer;
2.10 frystyk 460: if (lang) *lang = no_suffix.language;
2.1 frystyk 461: *quality = no_suffix.quality;
462: }
463: if (BIND_TRACE)
2.21 frystyk 464: HTTrace("Get Binding. Result for '%s\' is: type='%s\', encoding='%s\', cte='%s\', language='%s\' with quality %.2f\n",
2.1 frystyk 465: filename,
2.10 frystyk 466: (format && *format) ? HTAtom_name(*format) : "unknown",
467: (enc && *enc) ? HTAtom_name(*enc) : "unknown",
2.21 frystyk 468: (cte && *cte) ? HTAtom_name(*cte) : "unknown",
2.10 frystyk 469: (lang && *lang) ? HTAtom_name(*lang) : "unknown",
2.1 frystyk 470: *quality);
2.17 frystyk 471: HT_FREE(file);
2.1 frystyk 472: return YES;
473: }
474:
Webmaster