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