Annotation of libwww/Library/src/HTBind.c, revision 2.34
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.34 ! kahan 6: ** @(#) $Id: HTBind.c,v 2.33 1999/02/22 22:10:10 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.26 frystyk 35: #include "wwwsys.h"
2.21 frystyk 36: #include "WWWUtil.h"
2.24 frystyk 37: #include "HTAnchor.h"
38: #include "HTResponse.h"
2.1 frystyk 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 */
2.22 frystyk 46: HTEncoding transfer; /* Content-Transfer-Encoding */
2.1 frystyk 47: HTLanguage language; /* Content-Language */
48: double quality;
49: } HTBind;
50:
51: /* Suffix registration */
52: PRIVATE BOOL HTCaseSen = YES; /* Are suffixes case sensitive */
53: PRIVATE char *HTDelimiters = NULL; /* Set of suffixes */
54:
55: PRIVATE HTList **HTBindings = NULL; /* Point to table of lists of bindings */
56:
2.21 frystyk 57: PRIVATE HTBind no_suffix = { "*", NULL, NULL, NULL, NULL, 0.5 };
58: PRIVATE HTBind unknown_suffix = { "*.*", NULL, NULL, NULL, NULL, 0.5 };
2.1 frystyk 59:
60: /* ------------------------------------------------------------------------- */
61:
62: /*
63: ** Set up the list of suffix bindings. Done by HTLibInit
64: */
2.11 frystyk 65: PUBLIC BOOL HTBind_init (void)
2.1 frystyk 66: {
2.8 frystyk 67: if (!HTBindings) {
2.31 frystyk 68: if (!(HTBindings = (HTList **) HT_CALLOC(HT_L_HASH_SIZE, sizeof(HTList *))))
2.17 frystyk 69: HT_OUTOFMEM("HTBind_init");
2.8 frystyk 70: }
2.1 frystyk 71: StrAllocCopy(HTDelimiters, DEFAULT_SUFFIXES);
2.15 frystyk 72: no_suffix.type = WWW_UNKNOWN;
2.25 frystyk 73: no_suffix.encoding = WWW_CODING_BINARY;
2.15 frystyk 74: unknown_suffix.type = WWW_UNKNOWN;
2.25 frystyk 75: unknown_suffix.encoding = WWW_CODING_BINARY;
2.1 frystyk 76: return YES;
77: }
78:
79:
80: /*
81: ** Cleans up the memory allocated by file bindings
82: ** Done by HTLibTerminate().
83: ** Written by Eric Sink, eric@spyglass.com, and Henrik
84: */
2.11 frystyk 85: PUBLIC BOOL HTBind_deleteAll (void)
2.1 frystyk 86: {
87: int cnt;
88: HTList *cur;
89: if (!HTBindings)
90: return NO;
2.31 frystyk 91: for (cnt=0; cnt<HT_L_HASH_SIZE; cnt++) {
2.1 frystyk 92: if ((cur = HTBindings[cnt])) {
93: HTBind *pres;
94: while ((pres = (HTBind *) HTList_nextObject(cur)) != NULL) {
2.17 frystyk 95: HT_FREE(pres->suffix);
96: HT_FREE(pres);
2.1 frystyk 97: }
98: }
99: HTList_delete(HTBindings[cnt]);
100: HTBindings[cnt] = NULL;
101: }
2.19 frystyk 102: HT_FREE(HTBindings);
2.17 frystyk 103: HT_FREE(HTDelimiters);
2.1 frystyk 104: return YES;
105: }
106:
107:
108: /* Make suffix bindings case sensitive
109: ** -----------------------------------
110: */
2.11 frystyk 111: PUBLIC void HTBind_caseSensitive (BOOL sensitive)
2.1 frystyk 112: {
113: HTCaseSen = sensitive;
114: }
115:
116:
117: /* Get set of suffixes
118: ** -------------------
119: */
2.20 frystyk 120: PUBLIC const char *HTBind_delimiters (void)
2.1 frystyk 121: {
122: return HTDelimiters;
123: }
124:
125:
126: /* Change set of suffixes
127: ** ----------------------
128: */
2.20 frystyk 129: PUBLIC void HTBind_setDelimiters (const char * new_suffixes)
2.1 frystyk 130: {
131: if (new_suffixes && *new_suffixes)
132: StrAllocCopy(HTDelimiters, new_suffixes);
133: }
134:
135:
136: /* Define the representation associated with a file suffix
137: ** -------------------------------------------------------
138: **
139: ** Calling this with suffix set to "*" will set the default
140: ** representation.
141: ** Calling this with suffix set to "*.*" will set the default
142: ** representation for unknown suffix files which contain a "."
143: **
144: ** If filename suffix is already defined its previous
145: ** definition is overridden (or modified)
146: */
2.20 frystyk 147: PUBLIC BOOL HTBind_addType (const char * suffix,
148: const char * representation,
2.12 frystyk 149: double value)
2.1 frystyk 150: {
2.21 frystyk 151: return HTBind_add(suffix, representation, NULL, NULL, NULL, value);
2.1 frystyk 152: }
153:
2.20 frystyk 154: PUBLIC BOOL HTBind_addEncoding (const char * suffix,
155: const char * encoding,
2.11 frystyk 156: double value)
2.1 frystyk 157: {
2.21 frystyk 158: return HTBind_add(suffix, NULL, encoding, NULL, NULL, value);
2.1 frystyk 159: }
160:
2.21 frystyk 161: PUBLIC BOOL HTBind_addTransfer (const char * suffix,
162: const char * transfer,
163: double value)
164: {
165: return HTBind_add(suffix, NULL, NULL, transfer, NULL, value);
166: }
167:
2.20 frystyk 168: PUBLIC BOOL HTBind_addLanguage (const char * suffix,
169: const char * language,
2.11 frystyk 170: double value)
2.1 frystyk 171: {
2.21 frystyk 172: return HTBind_add(suffix, NULL, NULL, NULL, language, value);
2.1 frystyk 173: }
174:
2.20 frystyk 175: PUBLIC BOOL HTBind_add (const char * suffix,
176: const char * representation,
177: const char * encoding,
2.21 frystyk 178: const char * transfer,
2.20 frystyk 179: const char * language,
2.11 frystyk 180: double value)
2.1 frystyk 181: {
182: HTBind * suff;
183: if (!suffix)
184: return NO;
185: if (!strcmp(suffix, "*"))
186: suff = &no_suffix;
187: else if (!strcmp(suffix, "*.*"))
188: suff = &unknown_suffix;
189: else {
2.31 frystyk 190: HTList * suflist;
191: int hash;
192: const unsigned char * p;
2.1 frystyk 193:
194: /* Select list from hash table */
2.31 frystyk 195: for (p=suffix, hash=0; *p; p++) {
196: hash = (hash * 3 + TOLOWER(*p)) % HT_L_HASH_SIZE;
197: }
2.1 frystyk 198:
2.32 frystyk 199: if (!HTBindings) HTBind_init();
2.1 frystyk 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) {
2.17 frystyk 214: if ((suff = (HTBind *) HT_CALLOC(1, sizeof(HTBind))) == NULL)
215: HT_OUTOFMEM("HTBind_add");
2.1 frystyk 216: HTList_addObject(suflist, (void *) suff);
217: StrAllocCopy(suff->suffix, suffix);
218: }
219: }
220:
221: /* Set the appropriate values */
222: {
2.21 frystyk 223: HTChunk * chunk = HTChunk_new(32);
2.1 frystyk 224: char *ptr;
225: if (representation) {
2.21 frystyk 226: HTChunk_puts(chunk, representation);
227: ptr = HTChunk_data(chunk);
228: for (; *ptr; ptr++)
2.1 frystyk 229: *ptr = TOLOWER(*ptr);
2.21 frystyk 230: suff->type = HTAtom_for(HTChunk_data(chunk));
2.34 ! kahan 231: HTChunk_truncate(chunk,0);
2.1 frystyk 232: }
2.21 frystyk 233: if (encoding) {
234: HTChunk_puts(chunk, encoding);
235: ptr = HTChunk_data(chunk);
236: for (; *ptr; ptr++)
2.1 frystyk 237: *ptr = TOLOWER(*ptr);
2.21 frystyk 238: suff->encoding = HTAtom_for(HTChunk_data(chunk));
2.34 ! kahan 239: HTChunk_truncate(chunk,0);
2.1 frystyk 240: }
2.21 frystyk 241: if (transfer) {
242: HTChunk_puts(chunk, transfer);
243: ptr = HTChunk_data(chunk);
244: for (; *ptr; ptr++)
2.1 frystyk 245: *ptr = TOLOWER(*ptr);
2.21 frystyk 246: suff->transfer = HTAtom_for(HTChunk_data(chunk));
2.34 ! kahan 247: HTChunk_truncate(chunk,0);
2.1 frystyk 248: }
2.21 frystyk 249: if (language) {
250: HTChunk_puts(chunk, language);
251: ptr = HTChunk_data(chunk);
252: for (; *ptr; ptr++)
253: *ptr = TOLOWER(*ptr);
254: suff->language = HTAtom_for(HTChunk_data(chunk));
2.34 ! kahan 255: HTChunk_truncate(chunk,0);
2.21 frystyk 256: }
257: HTChunk_delete(chunk);
2.1 frystyk 258: suff->quality = value;
259: }
260: return YES;
261: }
262:
263:
264: /* Determine a suitable suffix
265: ** ---------------------------
266: ** Use the set of bindings to find a suitable suffix (or index)
267: ** for a certain combination of language, media type and encoding
268: ** given in the anchor.
269: **
2.21 frystyk 270: ** Returns a pointer to a suitable suffix string that must be freed
2.1 frystyk 271: ** by the caller. If more than one suffix is found they are all
272: ** concatenated using the first delimiter in HTDelimiters.
273: ** If no suffix is found, NULL is returned.
274: */
2.11 frystyk 275: PUBLIC char * HTBind_getSuffix (HTParentAnchor * anchor)
2.1 frystyk 276: {
277: int cnt;
2.23 frystyk 278: HTList * cur;
279: HTChunk * suffix = HTChunk_new(48);
280: char delimiter = *HTDelimiters;
2.30 frystyk 281: char * ct=NULL, * ce=NULL, * cl=NULL;
2.24 frystyk 282: HTFormat format = HTAnchor_format(anchor);
283: HTList * encoding = HTAnchor_encoding(anchor);
284: HTList * language = HTAnchor_language(anchor);
2.32 frystyk 285: if (!HTBindings) HTBind_init();
2.1 frystyk 286: if (anchor) {
2.31 frystyk 287: for (cnt=0; cnt<HT_L_HASH_SIZE; cnt++) {
2.1 frystyk 288: if ((cur = HTBindings[cnt])) {
289: HTBind *pres;
2.21 frystyk 290: while ((pres = (HTBind *) HTList_nextObject(cur))) {
2.24 frystyk 291: if (!ct && (pres->type && pres->type == format)){
2.30 frystyk 292: ct = pres->suffix;
2.24 frystyk 293: } else if (!ce && pres->encoding && encoding) {
2.30 frystyk 294: HTList * cur_enc = encoding;
295: HTEncoding pres_enc;
296: while ((pres_enc = (HTEncoding) HTList_nextObject(cur_enc))) {
297: if (pres_enc == pres->encoding) {
298: ce = pres->suffix;
299: break;
300: }
301: }
2.24 frystyk 302: } else if (!cl && pres->language && language) {
2.30 frystyk 303: HTList * cur_lang = language;
304: HTLanguage pres_lang;
305: while ((pres_lang = (HTLanguage) HTList_nextObject(cur_lang))) {
306: if (pres_lang == pres->language) {
307: cl = pres->suffix;
308: break;
309: }
310: }
2.1 frystyk 311: }
312: }
313: }
2.30 frystyk 314: }
315:
316: /* Put the found suffixes together */
317: if (ct) {
318: HTChunk_putc(suffix, delimiter);
319: HTChunk_puts(suffix, ct);
320: }
321: if (ce) {
322: HTChunk_putc(suffix, delimiter);
323: HTChunk_puts(suffix, ce);
324: }
325: if (cl) {
326: HTChunk_putc(suffix, delimiter);
327: HTChunk_puts(suffix, cl);
2.1 frystyk 328: }
329: }
2.23 frystyk 330: return HTChunk_toCString(suffix);
2.1 frystyk 331: }
332:
2.24 frystyk 333: /*
2.1 frystyk 334: ** Use the set of bindings to find the combination of language,
2.24 frystyk 335: ** media type and encoding of a given object. This information can either be
336: ** stored in the anchor obejct or in the response object depending on which
337: ** function is called.
2.1 frystyk 338: **
2.21 frystyk 339: ** We comprise here as bindings only can have one language and one encoding.
2.1 frystyk 340: ** If more than one suffix is found they are all searched. The last suffix
341: ** has highest priority, the first one lowest. See also HTBind_getFormat()
342: */
2.24 frystyk 343: PUBLIC BOOL HTBind_getAnchorBindings (HTParentAnchor * anchor)
2.1 frystyk 344: {
345: BOOL status = NO;
346: double quality=1.0; /* @@@ Should we add this into the anchor? */
347: if (anchor) {
2.28 frystyk 348: char *addr = HTAnchor_address((HTAnchor *) anchor);
2.1 frystyk 349: char *path = HTParse(addr, "", PARSE_PATH+PARSE_PUNCTUATION);
2.9 frystyk 350: char *file;
351: char *end;
352: if ((end = strchr(path, ';')) || (end = strchr(path, '?')) ||
353: (end = strchr(path, '#')))
354: *end = '\0';
355: if ((file = strrchr(path, '/'))) {
2.21 frystyk 356: HTFormat format = NULL;
357: HTEncoding encoding = NULL;
2.22 frystyk 358: HTEncoding transfer = NULL;
2.21 frystyk 359: HTLanguage language = NULL;
2.33 frystyk 360: HTTRACE(BIND_TRACE, "Anchor...... Get bindings for `%s\'\n" _ path);
2.22 frystyk 361: status = HTBind_getFormat(file, &format, &encoding, &transfer,
2.21 frystyk 362: &language, &quality);
363: if (status) {
364: HTAnchor_setFormat(anchor, format);
2.25 frystyk 365: HTAnchor_setContentTransferEncoding(anchor, transfer);
2.29 frystyk 366:
367: HTAnchor_deleteEncodingAll(anchor);
368: HTAnchor_addEncoding(anchor, encoding);
369:
370: HTAnchor_deleteLanguageAll(anchor);
371: HTAnchor_addLanguage(anchor, language);
2.21 frystyk 372: }
2.1 frystyk 373: }
2.27 frystyk 374: HT_FREE(addr);
375: HT_FREE(path);
2.1 frystyk 376: }
377: return status;
378: }
379:
2.24 frystyk 380: PUBLIC BOOL HTBind_getResponseBindings (HTResponse * response, const char * url)
381: {
382: BOOL status = NO;
383: double quality = 1.0;
384: if (response) {
385: char * path = HTParse(url, "", PARSE_PATH + PARSE_PUNCTUATION);
386: char * file;
387: char * end;
388: if ((end = strchr(path, ';')) || (end = strchr(path, '?')) ||
389: (end = strchr(path, '#')))
390: *end = '\0';
391: if ((file = strrchr(path, '/'))) {
392: HTFormat format = NULL;
393: HTEncoding encoding = NULL;
394: HTEncoding transfer = NULL;
395: HTLanguage language = NULL;
2.33 frystyk 396: HTTRACE(BIND_TRACE, "Response.... Get Bindings for `%s\'\n" _ path);
2.24 frystyk 397: status = HTBind_getFormat(file, &format, &encoding, &transfer,
398: &language, &quality);
399: if (status) {
400: HTResponse_setFormat(response, format);
2.25 frystyk 401: HTResponse_setContentTransferEncoding(response, transfer);
2.24 frystyk 402: HTResponse_addEncoding(response, encoding);
403: #if 0
404: HTResponse_addLanguage(response, language);
405: #endif
406: }
407: }
408: HT_FREE(path);
409: }
410: return status;
411: }
2.1 frystyk 412:
413: /* Determine the content of an file name
414: ** -------------------------------------
415: ** Use the set of bindings to find the combination of language,
2.21 frystyk 416: ** media type, encoding, and transfer encoding of a given anchor.
2.1 frystyk 417: ** If more than one suffix is found they are all searched. The last suffix
418: ** has highest priority, the first one lowest. See also HTBind_getBindings()
2.10 frystyk 419: ** Either of format, encoding, or language can be NULL
2.1 frystyk 420: ** Returns the format, encoding, and language found
421: */
2.21 frystyk 422: PUBLIC BOOL HTBind_getFormat (const char * filename,
423: HTFormat * format,
424: HTEncoding * enc,
2.22 frystyk 425: HTEncoding * cte,
2.21 frystyk 426: HTLanguage * lang,
427: double * quality)
2.1 frystyk 428: {
429: int sufcnt=0;
430: char *file=NULL;
2.6 frystyk 431: #ifdef HT_REENTRANT
432: char *lasts; /* For strtok_r */
433: #endif
2.32 frystyk 434: if (!HTBindings) HTBind_init();
2.1 frystyk 435: if (*quality < HT_EPSILON)
436: *quality = 1.0; /* Set to a neutral value */
437: StrAllocCopy(file, filename);
438: HTUnEscape(file); /* Unescape the file name */
2.6 frystyk 439: #ifdef HT_REENTRANT
440: if (strtok_r(file, HTDelimiters, &lasts)) { /* Do we have any suffixes? */
441: #else
2.1 frystyk 442: if (strtok(file, HTDelimiters)) { /* Do we have any suffixes? */
2.6 frystyk 443: #endif /* HT_REENTRANT */
2.1 frystyk 444: char *suffix;
2.6 frystyk 445: #ifdef HT_REENTRANT
446: while ((suffix=(char*)strtok_r(NULL, HTDelimiters, &lasts)) != NULL) {
447: #else
448: while ((suffix=strtok(NULL, HTDelimiters)) != NULL) {
449: #endif /* HT_REENTRANT */
2.1 frystyk 450: HTBind *suff=NULL;
2.31 frystyk 451: int hash;
452: unsigned char * p;
2.33 frystyk 453: HTTRACE(BIND_TRACE, "Get Binding. Look for '%s\' " _ suffix);
2.1 frystyk 454: sufcnt++;
455:
456: /* Select list from hash table */
2.31 frystyk 457: for (p=suffix, hash=0; *p; p++) {
458: hash = (hash * 3 + TOLOWER(*p)) % HT_L_HASH_SIZE;
459: }
2.1 frystyk 460:
461: /* Now search list for entries (case or non case sensitive) */
462: if (HTBindings[hash]) {
463: HTList *cur = HTBindings[hash];
464: while ((suff = (HTBind *) HTList_nextObject(cur))) {
465: if ((HTCaseSen && !strcmp(suff->suffix, suffix)) ||
466: !strcasecomp(suff->suffix, suffix)) {
2.33 frystyk 467: HTTRACE(BIND_TRACE, "Found!\n");
2.10 frystyk 468: if (suff->type && format) *format = suff->type;
469: if (suff->encoding && enc) *enc = suff->encoding;
2.22 frystyk 470: if (suff->transfer && cte) *cte = suff->transfer;
2.10 frystyk 471: if (suff->language && lang) *lang = suff->language;
2.1 frystyk 472: if (suff->quality > HT_EPSILON)
473: *quality *= suff->quality;
474: break;
475: }
476: }
477: }
478: if (!suff) { /* We don't have this suffix - use default */
2.33 frystyk 479: HTTRACE(BIND_TRACE, "Not found - use default for \'*.*\'\n");
2.10 frystyk 480: if (format) *format = unknown_suffix.type;
481: if (enc) *enc = unknown_suffix.encoding;
2.21 frystyk 482: if (cte) *cte = unknown_suffix.transfer;
2.10 frystyk 483: if (lang) *lang = unknown_suffix.language;
2.1 frystyk 484: *quality = unknown_suffix.quality;
485: }
486: } /* while we still have suffixes */
487: }
488: if (!sufcnt) { /* No suffix so use default value */
2.33 frystyk 489: HTTRACE(BIND_TRACE, "Get Binding. No suffix found - using default '%s\'\n" _ filename);
2.10 frystyk 490: if (format) *format = no_suffix.type;
491: if (enc) *enc = no_suffix.encoding;
2.21 frystyk 492: if (cte) *cte = no_suffix.transfer;
2.10 frystyk 493: if (lang) *lang = no_suffix.language;
2.1 frystyk 494: *quality = no_suffix.quality;
495: }
2.33 frystyk 496: HTTRACE(BIND_TRACE, "Get Binding. Result for '%s\' is: type='%s\', encoding='%s\', cte='%s\', language='%s\' with quality %.2f\n" _
497: filename _
498: (format && *format) ? HTAtom_name(*format) : "unknown" _
499: (enc && *enc) ? HTAtom_name(*enc) : "unknown" _
500: (cte && *cte) ? HTAtom_name(*cte) : "unknown" _
501: (lang && *lang) ? HTAtom_name(*lang) : "unknown" _
2.1 frystyk 502: *quality);
2.17 frystyk 503: HT_FREE(file);
2.1 frystyk 504: return YES;
505: }
506:
Webmaster