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