Annotation of libwww/Library/src/HTBind.c, revision 2.3
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.3 ! frystyk 266: char delimiter[] = { *HTDelimiters, '\0' };
2.1 frystyk 267: if (anchor) {
268: for (cnt=0; cnt<HASH_SIZE; cnt++) {
269: if ((cur = HTBindings[cnt])) {
270: HTBind *pres;
271: while ((pres = (HTBind *) HTList_nextObject(cur)) != NULL) {
272: if ((pres->type && pres->type==anchor->content_type) ||
273: (pres->encoding &&
274: pres->encoding!=WWW_ENC_7BIT &&
275: pres->encoding!=WWW_ENC_8BIT &&
276: pres->encoding!=WWW_ENC_BINARY &&
277: pres->encoding==anchor->content_encoding) ||
278: (pres->language &&
279: pres->language == anchor->content_language)) {
2.3 ! frystyk 280: StrAllocCat(suffix, delimiter);
2.1 frystyk 281: StrAllocCat(suffix, pres->suffix);
282: }
283: }
284: }
285: }
286: }
287: return suffix;
288: }
289:
290: /* Determine the description of a file
291: ** -----------------------------------
292: ** Use the set of bindings to find the combination of language,
293: ** media type and encoding of a given file name.
294: **
295: ** If more than one suffix is found they are all searched. The last suffix
296: ** has highest priority, the first one lowest. See also HTBind_getFormat()
297: **
298: ** Returns a contentdescription object with the representations found. This
299: ** must be free by the caller
300: */
301: PUBLIC HTContentDescription * HTBind_getDescription ARGS1(char *, file)
302: {
303: HTContentDescription * cd;
304: cd = (HTContentDescription *) calloc(1, sizeof(HTContentDescription));
305: if (!cd) outofmem(__FILE__, "HTContentDescription");
306: if (HTBind_getFormat(file, &cd->content_type, &cd->content_encoding,
307: &cd->content_language, &cd->quality))
308: return cd;
309: else {
310: free(cd);
311: return NULL;
312: }
313: }
314:
315: /* Determine the content of an Anchor
316: ** ----------------------------------
317: ** Use the set of bindings to find the combination of language,
318: ** media type and encoding of a given anchor.
319: **
320: ** If more than one suffix is found they are all searched. The last suffix
321: ** has highest priority, the first one lowest. See also HTBind_getFormat()
322: **
323: ** Returns the anchor object with the representations found
324: */
325: PUBLIC BOOL HTBind_getBindings ARGS1(HTParentAnchor *, anchor)
326: {
327: BOOL status = NO;
328: double quality=1.0; /* @@@ Should we add this into the anchor? */
329: if (anchor) {
330: char *addr = HTAnchor_physical(anchor);
331: char *path = HTParse(addr, "", PARSE_PATH+PARSE_PUNCTUATION);
332: char *file = strrchr(path, '/');
333: if (!file) {
334: if (BIND_TRACE)
335: fprintf(TDEST,"Get Binding. No file name found `%s\'\n", path);
336: } else {
337: status = HTBind_getFormat(file, &anchor->content_type,
338: &anchor->content_encoding,
339: &anchor->content_language,
340: &quality);
341: }
342: FREE(path);
343: }
344: return status;
345: }
346:
347:
348: /* Determine the content of an file name
349: ** -------------------------------------
350: ** Use the set of bindings to find the combination of language,
351: ** media type and encoding of a given anchor.
352: **
353: ** If more than one suffix is found they are all searched. The last suffix
354: ** has highest priority, the first one lowest. See also HTBind_getBindings()
355: **
356: ** Returns the format, encoding, and language found
357: */
358: PUBLIC BOOL HTBind_getFormat ARGS5(CONST char *,filename,
359: HTFormat *, format,
360: HTEncoding *,encoding,
361: HTLanguage *,language,
362: double *, quality)
363: {
364: int sufcnt=0;
365: char *file=NULL;
366: if (*quality < HT_EPSILON)
367: *quality = 1.0; /* Set to a neutral value */
368: StrAllocCopy(file, filename);
369: HTUnEscape(file); /* Unescape the file name */
370: if (strtok(file, HTDelimiters)) { /* Do we have any suffixes? */
371: char *suffix;
372: while ((suffix = strtok(NULL, HTDelimiters)) != NULL) {
373: HTBind *suff=NULL;
374: int hash=0;
375: char *ptr=suffix;
376: if (BIND_TRACE)
377: fprintf(TDEST, "Get Binding. Look for '%s\' ", suffix);
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)) {
390: if (BIND_TRACE) fprintf(TDEST, "Found!\n");
391: if (suff->type) *format = suff->type;
392: if (suff->encoding) *encoding = suff->encoding;
393: if (suff->language) *language = suff->language;
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)
402: fprintf(TDEST,"Not found - use default for \'*.*\'\n");
403: *format = unknown_suffix.type;
404: *encoding = unknown_suffix.encoding;
405: *language = unknown_suffix.language;
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)
412: fprintf(TDEST, "Get Binding. No suffix found - using default '%s\'\n", filename);
413: *format = no_suffix.type;
414: *encoding = no_suffix.encoding;
415: *language = no_suffix.language;
416: *quality = no_suffix.quality;
417: }
418: if (BIND_TRACE)
419: fprintf(TDEST, "Get Binding. Result for '%s\' is: type='%s\', encoding='%s\', language='%s\' with quality %.2f\n",
420: filename,
421: *format ? HTAtom_name(*format) : "unknown",
422: *encoding ? HTAtom_name(*encoding) : "unknown",
423: *language ? HTAtom_name(*language) : "unknown",
424: *quality);
425: free(file);
426: return YES;
427: }
428:
Webmaster