Annotation of libwww/Library/src/HTBind.c, revision 2.10
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: #ifdef VMS
42: #include "HTVMSUtils.h"
43: #endif
44:
45: #include "HTBind.h" /* Implemented here */
46:
47: typedef struct _HTBind {
48: char * suffix;
49: HTFormat type; /* Content-Type */
50: HTEncoding encoding; /* Content-Encoding */
51: HTLanguage language; /* Content-Language */
52: double quality;
53: } HTBind;
54:
55: #define HASH_SIZE 101 /* Arbitrary prime. Memory/speed tradeoff */
56:
57: /* Suffix registration */
58: PRIVATE BOOL HTCaseSen = YES; /* Are suffixes case sensitive */
59: PRIVATE char *HTDelimiters = NULL; /* Set of suffixes */
60:
61: PRIVATE HTList **HTBindings = NULL; /* Point to table of lists of bindings */
62:
63: PRIVATE HTBind no_suffix = { "*", NULL, NULL, NULL, 1.0 };
64: PRIVATE HTBind unknown_suffix = { "*.*", NULL, NULL, NULL, 1.0};
65:
66: /* ------------------------------------------------------------------------- */
67:
68: /*
69: ** Set up the list of suffix bindings. Done by HTLibInit
70: */
71: PUBLIC BOOL HTBind_init NOARGS
72: {
2.8 frystyk 73: if (!HTBindings) {
2.1 frystyk 74: HTBindings = (HTList**) calloc(HASH_SIZE, sizeof(HTList *));
2.8 frystyk 75: if (!HTBindings) outofmem(__FILE__, "HTBind_init");
76: }
2.1 frystyk 77: StrAllocCopy(HTDelimiters, DEFAULT_SUFFIXES);
78: return YES;
79: }
80:
81:
82: /*
83: ** Cleans up the memory allocated by file bindings
84: ** Done by HTLibTerminate().
85: ** Written by Eric Sink, eric@spyglass.com, and Henrik
86: */
87: PUBLIC BOOL HTBind_deleteAll NOARGS
88: {
89: int cnt;
90: HTList *cur;
91: if (!HTBindings)
92: return NO;
93: for (cnt=0; cnt<HASH_SIZE; cnt++) {
94: if ((cur = HTBindings[cnt])) {
95: HTBind *pres;
96: while ((pres = (HTBind *) HTList_nextObject(cur)) != NULL) {
97: FREE(pres->suffix);
98: free(pres);
99: }
100: }
101: HTList_delete(HTBindings[cnt]);
102: HTBindings[cnt] = NULL;
103: }
104: FREE(HTDelimiters);
105: return YES;
106: }
107:
108:
109: /* Make suffix bindings case sensitive
110: ** -----------------------------------
111: */
112: PUBLIC void HTBind_setCaseSensitive ARGS1(BOOL, sensitive)
113: {
114: HTCaseSen = sensitive;
115: }
116:
117:
118: /* Get set of suffixes
119: ** -------------------
120: */
121: PUBLIC CONST char *HTBind_getDelimiters NOARGS
122: {
123: return HTDelimiters;
124: }
125:
126:
127: /* Change set of suffixes
128: ** ----------------------
129: */
130: PUBLIC void HTBind_setDelimiters ARGS1(CONST char *, new_suffixes)
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: */
148: PUBLIC BOOL HTBind_setType ARGS3(CONST char *, suffix,
149: CONST char *, representation,
150: double, value)
151: {
152: return HTBind_setBinding(suffix, representation, NULL, NULL, value);
153: }
154:
155: PUBLIC BOOL HTBind_setEncoding ARGS3(CONST char *, suffix,
156: CONST char *, encoding,
157: double, value)
158: {
159: return HTBind_setBinding(suffix, NULL, encoding, NULL, value);
160: }
161:
162: PUBLIC BOOL HTBind_setLanguage ARGS3(CONST char *, suffix,
163: CONST char *, language,
164: double, value)
165: {
166: return HTBind_setBinding(suffix, NULL, NULL, language, value);
167: }
168:
169: PUBLIC BOOL HTBind_setBinding ARGS5(CONST char *, suffix,
170: CONST char *, representation,
171: CONST char *, encoding,
172: CONST char *, language,
173: double, value)
174: {
175: HTBind * suff;
176: if (!suffix)
177: return NO;
178: if (!strcmp(suffix, "*"))
179: suff = &no_suffix;
180: else if (!strcmp(suffix, "*.*"))
181: suff = &unknown_suffix;
182: else {
183: HTList *suflist;
184: int hash=0;
185: CONST char *ptr=suffix;
186:
187: /* Select list from hash table */
188: for( ; *ptr; ptr++)
189: hash = (int) ((hash * 3 + (*(unsigned char*)ptr)) % HASH_SIZE);
190:
191: if (!HTBindings[hash]) HTBindings[hash] = HTList_new();
192: suflist = HTBindings[hash];
193:
194: /* Look for existing binding */
195: {
196: HTList *cur = suflist;
197: while ((suff = (HTBind *) HTList_nextObject(cur)) != NULL) {
198: if (!strcmp(suff->suffix, suffix))
199: break;
200: }
201: }
202:
203: /* If not found -- create a new node */
204: if (!suff) {
205: if ((suff = (HTBind *) calloc(1, sizeof(HTBind))) == NULL)
206: outofmem(__FILE__, "HTHTBind_setBinding");
207: HTList_addObject(suflist, (void *) suff);
208: StrAllocCopy(suff->suffix, suffix);
209: }
210: }
211:
212: /* Set the appropriate values */
213: {
214: char *str = NULL;
215: char *ptr;
216: if (representation) {
217: StrAllocCopy(str, representation);
218: for (ptr=str; *ptr; ptr++)
219: *ptr = TOLOWER(*ptr);
220: suff->type = HTAtom_for(str);
221: }
222: if (language) {
223: StrAllocCopy(str, language);
224: for (ptr=str; *ptr; ptr++)
225: *ptr = TOLOWER(*ptr);
226: suff->language = HTAtom_for(str);
227: }
228: if (encoding) {
229: StrAllocCopy(str, encoding);
230: for (ptr=str; *ptr; ptr++)
231: *ptr = TOLOWER(*ptr);
232: suff->encoding = HTAtom_for(str);
233: }
234: FREE(str);
235: suff->quality = value;
236: }
237: return YES;
238: }
239:
240:
241: /* Determine a suitable suffix
242: ** ---------------------------
243: ** Use the set of bindings to find a suitable suffix (or index)
244: ** for a certain combination of language, media type and encoding
245: ** given in the anchor.
246: **
247: ** Returns a pointer to a suitable suffix string that must be freed
248: ** by the caller. If more than one suffix is found they are all
249: ** concatenated using the first delimiter in HTDelimiters.
250: ** If no suffix is found, NULL is returned.
251: */
2.2 frystyk 252: PUBLIC char * HTBind_getSuffix ARGS1(HTParentAnchor *, anchor)
2.1 frystyk 253: {
254: int cnt;
255: HTList *cur;
256: char *suffix = NULL;
2.5 frystyk 257: char delimiter[2];
2.4 frystyk 258: *delimiter = *HTDelimiters;
2.5 frystyk 259: *(delimiter+1) = '\0';
2.1 frystyk 260: if (anchor) {
261: for (cnt=0; cnt<HASH_SIZE; cnt++) {
262: if ((cur = HTBindings[cnt])) {
263: HTBind *pres;
264: while ((pres = (HTBind *) HTList_nextObject(cur)) != NULL) {
265: if ((pres->type && pres->type==anchor->content_type) ||
266: (pres->encoding &&
267: pres->encoding!=WWW_ENC_7BIT &&
268: pres->encoding!=WWW_ENC_8BIT &&
269: pres->encoding!=WWW_ENC_BINARY &&
270: pres->encoding==anchor->content_encoding) ||
271: (pres->language &&
272: pres->language == anchor->content_language)) {
2.3 frystyk 273: StrAllocCat(suffix, delimiter);
2.1 frystyk 274: StrAllocCat(suffix, pres->suffix);
275: }
276: }
277: }
278: }
279: }
280: return suffix;
281: }
282:
283: /* Determine the description of a file
284: ** -----------------------------------
285: ** Use the set of bindings to find the combination of language,
286: ** media type and encoding of a given file name.
287: **
288: ** If more than one suffix is found they are all searched. The last suffix
289: ** has highest priority, the first one lowest. See also HTBind_getFormat()
290: **
291: ** Returns a contentdescription object with the representations found. This
292: ** must be free by the caller
293: */
294: PUBLIC HTContentDescription * HTBind_getDescription ARGS1(char *, file)
295: {
296: HTContentDescription * cd;
297: cd = (HTContentDescription *) calloc(1, sizeof(HTContentDescription));
298: if (!cd) outofmem(__FILE__, "HTContentDescription");
299: if (HTBind_getFormat(file, &cd->content_type, &cd->content_encoding,
300: &cd->content_language, &cd->quality))
301: return cd;
302: else {
303: free(cd);
304: return NULL;
305: }
306: }
307:
308: /* Determine the content of an Anchor
309: ** ----------------------------------
310: ** Use the set of bindings to find the combination of language,
311: ** media type and encoding of a given anchor.
312: **
313: ** If more than one suffix is found they are all searched. The last suffix
314: ** has highest priority, the first one lowest. See also HTBind_getFormat()
315: **
316: ** Returns the anchor object with the representations found
317: */
318: PUBLIC BOOL HTBind_getBindings ARGS1(HTParentAnchor *, anchor)
319: {
320: BOOL status = NO;
321: double quality=1.0; /* @@@ Should we add this into the anchor? */
322: if (anchor) {
323: char *addr = HTAnchor_physical(anchor);
324: char *path = HTParse(addr, "", PARSE_PATH+PARSE_PUNCTUATION);
2.9 frystyk 325: char *file;
326: char *end;
327: if ((end = strchr(path, ';')) || (end = strchr(path, '?')) ||
328: (end = strchr(path, '#')))
329: *end = '\0';
330: if ((file = strrchr(path, '/'))) {
331: if (BIND_TRACE)
332: fprintf(TDEST,"Get Binding. for file: `%s\'\n", path);
2.1 frystyk 333: status = HTBind_getFormat(file, &anchor->content_type,
334: &anchor->content_encoding,
335: &anchor->content_language,
336: &quality);
337: }
338: FREE(path);
339: }
340: return status;
341: }
342:
343:
344: /* Determine the content of an file name
345: ** -------------------------------------
346: ** Use the set of bindings to find the combination of language,
347: ** media type and encoding of a given anchor.
348: **
349: ** If more than one suffix is found they are all searched. The last suffix
350: ** has highest priority, the first one lowest. See also HTBind_getBindings()
2.10 ! frystyk 351: ** Either of format, encoding, or language can be NULL
2.1 frystyk 352: ** Returns the format, encoding, and language found
353: */
2.10 ! frystyk 354: PUBLIC BOOL HTBind_getFormat (CONST char * filename, HTFormat * format,
! 355: HTEncoding * enc, HTLanguage * lang,
! 356: double * quality)
2.1 frystyk 357: {
358: int sufcnt=0;
359: char *file=NULL;
2.6 frystyk 360: #ifdef HT_REENTRANT
361: char *lasts; /* For strtok_r */
362: #endif
2.1 frystyk 363: if (*quality < HT_EPSILON)
364: *quality = 1.0; /* Set to a neutral value */
365: StrAllocCopy(file, filename);
366: HTUnEscape(file); /* Unescape the file name */
2.6 frystyk 367: #ifdef HT_REENTRANT
368: if (strtok_r(file, HTDelimiters, &lasts)) { /* Do we have any suffixes? */
369: #else
2.1 frystyk 370: if (strtok(file, HTDelimiters)) { /* Do we have any suffixes? */
2.6 frystyk 371: #endif /* HT_REENTRANT */
2.1 frystyk 372: char *suffix;
2.6 frystyk 373: #ifdef HT_REENTRANT
374: while ((suffix=(char*)strtok_r(NULL, HTDelimiters, &lasts)) != NULL) {
375: #else
376: while ((suffix=strtok(NULL, HTDelimiters)) != NULL) {
377: #endif /* HT_REENTRANT */
2.1 frystyk 378: HTBind *suff=NULL;
379: int hash=0;
380: char *ptr=suffix;
381: if (BIND_TRACE)
382: fprintf(TDEST, "Get Binding. Look for '%s\' ", suffix);
383: sufcnt++;
384:
385: /* Select list from hash table */
386: for( ; *ptr; ptr++)
387: hash = (int)((hash*3+(*(unsigned char*)ptr)) % HASH_SIZE);
388:
389: /* Now search list for entries (case or non case sensitive) */
390: if (HTBindings[hash]) {
391: HTList *cur = HTBindings[hash];
392: while ((suff = (HTBind *) HTList_nextObject(cur))) {
393: if ((HTCaseSen && !strcmp(suff->suffix, suffix)) ||
394: !strcasecomp(suff->suffix, suffix)) {
395: if (BIND_TRACE) fprintf(TDEST, "Found!\n");
2.10 ! frystyk 396: if (suff->type && format) *format = suff->type;
! 397: if (suff->encoding && enc) *enc = suff->encoding;
! 398: if (suff->language && lang) *lang = suff->language;
2.1 frystyk 399: if (suff->quality > HT_EPSILON)
400: *quality *= suff->quality;
401: break;
402: }
403: }
404: }
405: if (!suff) { /* We don't have this suffix - use default */
406: if (BIND_TRACE)
407: fprintf(TDEST,"Not found - use default for \'*.*\'\n");
2.10 ! frystyk 408: if (format) *format = unknown_suffix.type;
! 409: if (enc) *enc = unknown_suffix.encoding;
! 410: if (lang) *lang = unknown_suffix.language;
2.1 frystyk 411: *quality = unknown_suffix.quality;
412: }
413: } /* while we still have suffixes */
414: }
415: if (!sufcnt) { /* No suffix so use default value */
416: if (BIND_TRACE)
417: fprintf(TDEST, "Get Binding. No suffix found - using default '%s\'\n", filename);
2.10 ! frystyk 418: if (format) *format = no_suffix.type;
! 419: if (enc) *enc = no_suffix.encoding;
! 420: if (lang) *lang = no_suffix.language;
2.1 frystyk 421: *quality = no_suffix.quality;
422: }
423: if (BIND_TRACE)
424: fprintf(TDEST, "Get Binding. Result for '%s\' is: type='%s\', encoding='%s\', language='%s\' with quality %.2f\n",
425: filename,
2.10 ! frystyk 426: (format && *format) ? HTAtom_name(*format) : "unknown",
! 427: (enc && *enc) ? HTAtom_name(*enc) : "unknown",
! 428: (lang && *lang) ? HTAtom_name(*lang) : "unknown",
2.1 frystyk 429: *quality);
430: free(file);
431: return YES;
432: }
433:
Webmaster