Annotation of libwww/Library/src/HTMulti.c, revision 2.27
2.11 frystyk 1: /* HTMulti.c
2: ** MULTIFORMAT HANDLING
3: **
2.15 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.11 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
2.27 ! frystyk 6: ** @(#) $Id: Date Author State $
2.1 luotonen 7: **
8: ** History:
9: ** March 94 AL Separated from HTFile.c because
10: ** multiformat handling would be a mess in VMS.
11: */
12:
2.13 frystyk 13: /* Library include files */
2.26 frystyk 14: #include "sysdep.h"
2.13 frystyk 15: #include "HTUtils.h"
16: #include "HTString.h"
2.2 duns 17: #include "HTMulti.h"
2.20 frystyk 18: #include "HTFile.h"
2.14 frystyk 19: #include "HTBind.h"
2.1 luotonen 20: #include "HTList.h"
2.19 frystyk 21: #include "HTReqMan.h"
2.1 luotonen 22:
2.3 luotonen 23: PRIVATE HTList * welcome_names = NULL; /* Welcome.html, index.html etc. */
24:
25:
2.14 frystyk 26: /* PUBLIC HTSplitFilename()
27: **
28: ** Split the filename to an array of suffixes.
29: ** Return the number of parts placed to the array.
30: ** Array should have MAX_SUFF+1 items.
31: */
2.23 frystyk 32: PRIVATE int HTSplitFilename (char * s_str, char ** s_arr)
2.14 frystyk 33: {
2.26 frystyk 34: const char *delimiters = HTBind_delimiters();
2.14 frystyk 35: char * start = s_str;
36: char * end;
37: char save;
38: int i;
39:
40: if (!s_str || !s_arr) return 0;
41:
42: for (i=0; i < MAX_SUFF && *start; i++) {
43: for(end=start+1; *end && !strchr(delimiters, *end); end++);
44: save = *end;
45: *end = 0;
46: StrAllocCopy(s_arr[i], start); /* Frees the previous value */
47: *end = save;
48: start = end;
49: }
2.24 frystyk 50: HT_FREE(s_arr[i]); /* Terminating NULL */
2.14 frystyk 51: return i;
52: }
53:
54:
2.3 luotonen 55: /*
56: ** Set default file name for welcome page on each directory.
57: */
2.23 frystyk 58: PUBLIC void HTAddWelcome (char * name)
2.3 luotonen 59: {
60: if (name) {
61: char * mycopy = NULL;
62: StrAllocCopy(mycopy,name);
63:
64: if (!welcome_names)
65: welcome_names = HTList_new();
66: HTList_addObject(welcome_names, (void*)mycopy);
67: }
68: }
69:
70:
2.26 frystyk 71: #ifdef HAVE_READDIR
2.1 luotonen 72:
73: /* PRIVATE multi_match()
74: **
75: ** Check if actual filename (split in parts) fulfills
76: ** the requirements.
77: */
2.23 frystyk 78: PRIVATE BOOL multi_match (char ** required, int m, char ** actual, int n)
2.1 luotonen 79: {
80: int c;
81: int i,j;
82:
2.2 duns 83: #ifdef VMS
84: for(c=0; c<m && c<n && !strcasecomp(required[c], actual[c]); c++);
85: #else /* not VMS */
2.1 luotonen 86: for(c=0; c<m && c<n && !strcmp(required[c], actual[c]); c++);
2.2 duns 87: #endif /* not VMS */
2.1 luotonen 88:
89: if (!c) return NO; /* Names differ rigth from start */
90:
91: for(i=c; i<m; i++) {
92: BOOL found = NO;
93: for(j=c; j<n; j++) {
2.2 duns 94: #ifdef VMS
95: if (!strcasecomp(required[i], actual[j])) {
96: #else /* not VMS */
2.1 luotonen 97: if (!strcmp(required[i], actual[j])) {
2.2 duns 98: #endif /* not VMS */
2.1 luotonen 99: found = YES;
100: break;
101: }
102: }
103: if (!found) return NO;
104: }
105: return YES;
106: }
107:
108:
109: /*
110: ** Get multi-match possibilities for a given file
111: ** ----------------------------------------------
112: ** On entry:
113: ** path absolute path to one file in a directory,
114: ** may end in .multi.
115: ** On exit:
116: ** returns a list of ContentDesription structures
117: ** describing the mathing files.
118: **
119: */
2.23 frystyk 120: PRIVATE HTList * dir_matches (char * path)
2.1 luotonen 121: {
122: static char * required[MAX_SUFF+1];
123: static char * actual[MAX_SUFF+1];
124: int m,n;
125: char * dirname = NULL;
126: char * basename = NULL;
127: int baselen;
128: char * multi = NULL;
129: DIR * dp;
2.26 frystyk 130: struct dirent * dirbuf;
2.1 luotonen 131: HTList * matches = NULL;
2.16 frystyk 132: #ifdef HT_REENTRANT
2.26 frystyk 133: DIR result; /* For readdir_r */
2.16 frystyk 134: #endif
2.1 luotonen 135:
136: if (!path) return NULL;
137:
138: StrAllocCopy(dirname, path);
139: basename = (strrchr(dirname, '/'));
140: if (!basename)
141: goto dir_match_failed;
142: *basename++ = 0;
143:
144: multi = strrchr(basename, MULTI_SUFFIX[0]);
2.2 duns 145: if (multi && !strcasecomp(multi, MULTI_SUFFIX))
2.1 luotonen 146: *multi = 0;
147: baselen = strlen(basename);
148:
149: m = HTSplitFilename(basename, required);
150:
151: dp = opendir(dirname);
152: if (!dp) {
2.13 frystyk 153: if (PROT_TRACE)
2.25 eric 154: HTTrace("Warning..... Can't open directory %s\n", dirname);
2.1 luotonen 155: goto dir_match_failed;
156: }
157:
158: matches = HTList_new();
2.16 frystyk 159: #ifdef HT_REENTRANT
2.26 frystyk 160: while ((dirbuf = (DIR *) readdir_r(dp, &result))) {
2.16 frystyk 161: #else
162: while ((dirbuf = readdir(dp))) {
163: #endif /* HT_REENTRANT */
2.1 luotonen 164: if (!dirbuf->d_ino) continue; /* Not in use */
2.3 luotonen 165: if (!strcmp(dirbuf->d_name,".") ||
166: !strcmp(dirbuf->d_name,"..") ||
2.20 frystyk 167: !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3 luotonen 168: continue;
2.7 frystyk 169:
2.13 frystyk 170: /* Use of direct->namlen is only valid in BSD'ish system */
171: /* Thanks to chip@chinacat.unicom.com (Chip Rosenthal) */
172: /* if ((int)(dirbuf->d_namlen) >= baselen) { */
173: if ((int) strlen(dirbuf->d_name) >= baselen) {
2.1 luotonen 174: n = HTSplitFilename(dirbuf->d_name, actual);
175: if (multi_match(required, m, actual, n)) {
176: HTContentDescription * cd;
2.14 frystyk 177: cd = HTBind_getDescription(dirbuf->d_name);
2.1 luotonen 178: if (cd) {
179: if (cd->content_type) {
2.24 frystyk 180: if ((cd->filename = (char *) HT_MALLOC(strlen(dirname) + 2 + strlen(dirbuf->d_name))) == NULL)
181: HT_OUTOFMEM("dir_matches");
2.1 luotonen 182: sprintf(cd->filename, "%s/%s",
183: dirname, dirbuf->d_name);
184: HTList_addObject(matches, (void*)cd);
185: }
2.24 frystyk 186: else HT_FREE(cd);
2.1 luotonen 187: }
188: }
189: }
190: }
191: closedir(dp);
192:
193: dir_match_failed:
2.24 frystyk 194: HT_FREE(dirname);
2.1 luotonen 195: return matches;
196: }
197:
198:
199: /*
200: ** Get the best match for a given file
201: ** -----------------------------------
202: ** On entry:
203: ** req->conversions accepted content-types
204: ** req->encodings accepted content-transfer-encodings
205: ** req->languages accepted content-languages
206: ** path absolute pathname of the filename for
207: ** which the match is desired.
208: ** On exit:
209: ** returns a newly allocated absolute filepath.
210: */
2.23 frystyk 211: PRIVATE char * HTGetBest (HTRequest * req, char * path)
2.1 luotonen 212: {
213: HTList * matches;
214: HTList * cur;
215: HTContentDescription * cd;
216: HTContentDescription * best = NULL;
217: char * best_path = NULL;
218:
2.13 frystyk 219: if (!path || !*path) return NULL;
2.1 luotonen 220:
221: matches = dir_matches(path);
222: if (!matches) {
2.13 frystyk 223: if (PROT_TRACE)
2.25 eric 224: HTTrace("No matches.. for \"%s\"\n", path);
2.13 frystyk 225: return NULL;
2.1 luotonen 226: }
227:
228: /* BEGIN DEBUG */
229: cur = matches;
2.13 frystyk 230: if (PROT_TRACE)
2.25 eric 231: HTTrace("Multi....... Possibilities for \"%s\"\n", path);
2.13 frystyk 232: if (PROT_TRACE)
2.25 eric 233: HTTrace("\nCONTENT-TYPE LANGUAGE ENCODING QUALITY FILE\n");
2.1 luotonen 234: while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
2.13 frystyk 235: if (PROT_TRACE)
2.25 eric 236: HTTrace("%s\t%s\t%s\t %.5f %s\n",
2.13 frystyk 237: cd->content_type ?HTAtom_name(cd->content_type) :"-\t",
238: cd->content_language?HTAtom_name(cd->content_language):"-",
239: cd->content_encoding?HTAtom_name(cd->content_encoding):"-",
240: cd->quality,
241: cd->filename ?cd->filename :"-");
2.1 luotonen 242: }
2.25 eric 243: if (PROT_TRACE) HTTrace("\n");
2.1 luotonen 244: /* END DEBUG */
245:
246: /*
247: ** Finally get best that is readable
248: */
249: if (HTRank(matches, req->conversions, req->languages, req->encodings)) {
250: cur = matches;
251: while ((best = (HTContentDescription*)HTList_nextObject(cur))) {
252: if (best && best->filename) {
253: if (access(best->filename, R_OK) != -1) {
254: StrAllocCopy(best_path, best->filename);
255: break;
2.13 frystyk 256: } else if (PROT_TRACE)
2.25 eric 257: HTTrace("Bad News.... \"%s\" is not readable\n",
2.1 luotonen 258: best->filename);
259: }
260: }
261: } /* Select best */
262:
263: cur = matches;
264: while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
2.24 frystyk 265: if (cd->filename) HT_FREE(cd->filename);
266: HT_FREE(cd);
2.1 luotonen 267: }
268: HTList_delete(matches);
269:
270: return best_path;
271: }
272:
2.3 luotonen 273:
274:
2.23 frystyk 275: PRIVATE int welcome_value (char * name)
2.3 luotonen 276: {
277: HTList * cur = welcome_names;
278: char * welcome;
279: int v = 0;
280:
281: while ((welcome = (char*)HTList_nextObject(cur))) {
282: v++;
283: if (!strcmp(welcome,name)) return v;
284: }
285: return 0;
286: }
287:
288:
289:
2.23 frystyk 290: PRIVATE char * get_best_welcome (char * path)
2.3 luotonen 291: {
292: char * best_welcome = NULL;
293: int best_value = 0;
294: DIR * dp;
2.26 frystyk 295: struct dirent * dirbuf;
2.3 luotonen 296: char * last = strrchr(path, '/');
297:
298: if (!welcome_names) {
299: HTAddWelcome("Welcome.html");
300: HTAddWelcome("welcome.html");
2.5 luotonen 301: #if 0
2.3 luotonen 302: HTAddWelcome("Index.html");
2.5 luotonen 303: #endif
2.3 luotonen 304: HTAddWelcome("index.html");
305: }
306:
2.5 luotonen 307: if (last && last!=path) *last = 0;
2.3 luotonen 308: dp = opendir(path);
2.5 luotonen 309: if (last && last!=path) *last='/';
2.3 luotonen 310: if (!dp) {
2.13 frystyk 311: if (PROT_TRACE)
2.25 eric 312: HTTrace("Warning..... Can't open directory %s\n",path);
2.3 luotonen 313: return NULL;
314: }
315: while ((dirbuf = readdir(dp))) {
2.13 frystyk 316: if (!dirbuf->d_ino ||
2.3 luotonen 317: !strcmp(dirbuf->d_name,".") ||
318: !strcmp(dirbuf->d_name,"..") ||
2.20 frystyk 319: !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3 luotonen 320: continue;
321: else {
322: int v = welcome_value(dirbuf->d_name);
323: if (v > best_value) {
324: best_value = v;
325: StrAllocCopy(best_welcome, dirbuf->d_name);
326: }
327: }
328: }
329: closedir(dp);
330:
331: if (best_welcome) {
2.24 frystyk 332: char * welcome;
333: if ((welcome = (char *) HT_MALLOC(strlen(path) + strlen(best_welcome)+2)) == NULL)
334: HT_OUTOFMEM("get_best_welcome");
2.4 luotonen 335: sprintf(welcome, "%s%s%s", path, last ? "" : "/", best_welcome);
2.24 frystyk 336: HT_FREE(best_welcome);
2.13 frystyk 337: if (PROT_TRACE)
2.25 eric 338: HTTrace("Welcome..... \"%s\"\n",welcome);
2.3 luotonen 339: return welcome;
340: }
341: return NULL;
342: }
343:
2.26 frystyk 344: #endif /* HAVE_READDIR */
2.1 luotonen 345:
346:
347: /*
348: ** Do multiformat handling
349: ** -----------------------
350: ** On entry:
351: ** req->conversions accepted content-types
352: ** req->encodings accepted content-transfer-encodings
353: ** req->languages accepted content-languages
354: ** path absolute pathname of the filename for
355: ** which the match is desired.
356: ** stat_info pointer to result space.
357: **
358: ** On exit:
359: ** returns a newly allocated absolute filepath of the best
360: ** match, or NULL if no match.
361: ** stat_info will contain inode information as
362: ** returned by stat().
363: */
2.23 frystyk 364: PUBLIC char * HTMulti (HTRequest * req,
365: char * path,
366: struct stat * stat_info)
2.1 luotonen 367: {
368: char * new_path = NULL;
369: int stat_status = -1;
370:
2.3 luotonen 371: if (!req || !path || !*path || !stat_info)
2.1 luotonen 372: return NULL;
373:
2.26 frystyk 374: #ifdef HAVE_READDIR
2.19 frystyk 375: if (*(path+strlen(path)-1) == '/') { /* Find welcome page */
2.3 luotonen 376: new_path = get_best_welcome(path);
377: if (new_path) path = new_path;
2.1 luotonen 378: }
2.3 luotonen 379: else{
380: char * multi = strrchr(path, MULTI_SUFFIX[0]);
381: if (multi && !strcasecomp(multi, MULTI_SUFFIX)) {
2.13 frystyk 382: if (PROT_TRACE)
2.25 eric 383: HTTrace("Multi....... by %s suffix\n", MULTI_SUFFIX);
2.1 luotonen 384: if (!(new_path = HTGetBest(req, path))) {
2.13 frystyk 385: if (PROT_TRACE)
2.25 eric 386: HTTrace("Multi....... failed -- giving up\n");
2.1 luotonen 387: return NULL;
388: }
389: path = new_path;
2.3 luotonen 390: }
391: else {
2.18 frystyk 392: stat_status = HT_STAT(path, stat_info);
2.3 luotonen 393: if (stat_status == -1) {
2.13 frystyk 394: if (PROT_TRACE)
2.25 eric 395: HTTrace(
2.13 frystyk 396: "AutoMulti... can't stat \"%s\"(errno %d)\n",
397: path, errno);
2.3 luotonen 398: if (!(new_path = HTGetBest(req, path))) {
2.13 frystyk 399: if (PROT_TRACE)
2.25 eric 400: HTTrace("AutoMulti... failed -- giving up\n");
2.3 luotonen 401: return NULL;
402: }
403: path = new_path;
404: }
2.1 luotonen 405: }
406: }
2.26 frystyk 407: #endif /* HAVE_READDIR */
2.1 luotonen 408:
409: if (stat_status == -1)
2.18 frystyk 410: stat_status = HT_STAT(path, stat_info);
2.1 luotonen 411: if (stat_status == -1) {
2.13 frystyk 412: if (PROT_TRACE)
2.25 eric 413: HTTrace("Stat fails.. on \"%s\" -- giving up (errno %d)\n",
2.13 frystyk 414: path, errno);
2.1 luotonen 415: return NULL;
416: }
417: else {
418: if (!new_path) {
419: StrAllocCopy(new_path, path);
420: return new_path;
421: }
422: else return path;
423: }
424: }
425:
426:
Webmaster