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