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