Annotation of libwww/Library/src/HTBind.c, revision 2.14
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)
2.14 ! frystyk 327: TTYPrint(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)
2.14 ! frystyk 377: TTYPrint(TDEST, "Get Binding. Look for '%s\' ", suffix);
2.1 frystyk 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)) {
2.14 ! frystyk 390: if (BIND_TRACE) TTYPrint(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)
2.14 ! frystyk 402: TTYPrint(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)
2.14 ! frystyk 412: TTYPrint(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)
2.14 ! frystyk 419: TTYPrint(TDEST, "Get Binding. Result for '%s\' is: type='%s\', encoding='%s\', language='%s\' with quality %.2f\n",
2.1 frystyk 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