[BACK] Return to HTMulti.c CVS log [TXT] [DIR] Up to [Public] / libwww / Library / src

Annotation of libwww/Library/src/HTMulti.c, revision 2.35

2.29 frystyk 1: /*
 2: **   CONTENT NEGOTIATION
2.11 frystyk 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.35 ! frystyk 6: **   @(#) $Id: HTMulti.c,v 2.34 1999年02月07日 18:24:19 frystyk Exp $
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.32 frystyk 14: #include "wwwsys.h"
2.28 frystyk 15: #include "WWWUtil.h"
 16: #include "WWWCore.h"
2.2 duns 17: #include "HTMulti.h"
2.34 frystyk 18: #include "HTBind.h"
2.20 frystyk 19: #include "HTFile.h"
2.1 luotonen 20: 
2.29 frystyk 21: #define MULTI_SUFFIX  ".multi"/* Extension for scanning formats */
 22: #define MAX_SUFF    15   /* Maximum number of suffixes for a file */
 23: #define VARIANTS    4    /* We start with this array size */
 24: 
 25: typedef struct _HTContentDescription {
 26:   char *   filename;
 27:   HTFormat  content_type;
 28:   HTLanguage content_language;
 29:   HTEncoding content_encoding;
 30:   HTEncoding content_transfer;
 31:   int        content_length;
 32:   double   quality;
 33: } HTContentDescription;
 34: 
2.3 luotonen 35: PRIVATE HTList * welcome_names = NULL; /* Welcome.html, index.html etc. */
 36: 
2.29 frystyk 37: /* ------------------------------------------------------------------------- */
 38: 
 39: /*
 40: ** Sort the q values in descending order
 41: */
 42: PRIVATE int VariantSort (const void * a, const void * b)
 43: {
 44:   HTContentDescription * aa = *(HTContentDescription **) a;
 45:   HTContentDescription * bb = *(HTContentDescription **) b;
2.33 frystyk 46:   if (aa && bb) return (aa->quality > bb->quality) ? -1 : 1;
 47:   return bb - aa;
2.29 frystyk 48: }
 49: 
 50: /*
 51: * Added by takada@seraph.ntt.jp (94/04/08)
 52: */
 53: PRIVATE BOOL lang_match (HTAtom * tmplate, HTAtom * actual)
 54: {
 55:   const char *t, *a;
 56:   char *st, *sa;
 57:   BOOL match = NO;
 58: 
 59:   if (tmplate && actual &&
 60:    (t = HTAtom_name(tmplate)) && (a = HTAtom_name(actual))) {
 61:    st = strchr(t, '_');
 62:    sa = strchr(a, '_');
 63:    if ((st != NULL) && (sa != NULL)) {
 64:      if (!strcasecomp(t, a))
 65:       match = YES;
 66:      else
 67:       match = NO;
 68:    }
 69:    else {
 70:      if (st != NULL) *st = 0;
 71:      if (sa != NULL) *sa = 0;
 72:      if (!strcasecomp(t, a))
 73:       match = YES;
 74:      else
 75:       match = NO;
 76:      if (st != NULL) *st = '_';
 77:      if (sa != NULL) *sa = '_';
 78:    }
 79:   }
 80:   return match;
 81: }
 82: 
 83: PRIVATE double type_value (HTAtom * content_type, HTList * accepted)
 84: {
 85:   if (!content_type) return (1.0);
 86:   if (accepted) {
 87:    HTList * cur = accepted;
 88:    HTPresentation * pres;
 89:    HTPresentation * wild = NULL;
 90:    while ((pres = (HTPresentation *) HTList_nextObject(cur))) {
 91:      if (pres->rep == content_type)
 92:        return pres->quality;
2.30 frystyk 93:      else if (HTMIMEMatch(pres->rep, content_type))
2.29 frystyk 94:        wild = pres;
 95:    }
 96:    if (wild) return wild->quality;
 97:    else return (0.0);                /* Nothing matched */
 98:   }
 99:   return (1.0);                  /* We accept all types */
 100: }
 101: 
 102: PRIVATE double lang_value (HTAtom * language, HTList * accepted)
 103: {
 104:   if (!language) return (1.0);
 105:   if (accepted) {
 106:    HTList * cur = accepted;
 107:    HTAcceptNode * node;
 108:    HTAcceptNode * wild = NULL;
 109:    while ((node = (HTAcceptNode *) HTList_nextObject(cur))) {
 110:      if (node->atom == language)
 111:        return node->quality;
 112:      /*
 113:       * patch by takada@seraph.ntt.jp (94/04/08)
 114:       * the original line was
2.30 frystyk 115:       * else if (HTMIMEMatch(node->atom, language)) {
2.29 frystyk 116:       * and the new line is
 117:       */
 118:      else if (lang_match(node->atom, language))
 119:        wild = node;
 120:    }
 121:    if (wild) return wild->quality;
 122:    else return (0.0);                /* Nothing matched */
 123:   }
 124:   return (1.0);                /* We accept all languages */
 125: }
 126: 
 127: PRIVATE double encoding_value (HTAtom * encoding, HTList * accepted)
 128: {
 129:   if (!encoding) return (1.0);
 130:   if (accepted) {
 131:    HTList * cur = accepted;
 132:    HTAcceptNode * node;
 133:    HTAcceptNode * wild = NULL;
 134:    const char * e = HTAtom_name(encoding);
 135:    if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
 136:      return (1.0);
 137:    while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
 138:      if (node->atom == encoding)
 139:        return node->quality;
2.30 frystyk 140:      else if (HTMIMEMatch(node->atom, encoding))
2.29 frystyk 141:        wild = node;
 142:    }
 143:    if (wild) return wild->quality;
 144:    else return (0.0);                /* Nothing matched */
 145:   }
 146:   return (1.0);                /* We accept all encodings */
 147: }
 148: 
 149: PRIVATE BOOL HTRank (HTRequest * request, HTArray * variants)
 150: {
 151:   HTContentDescription * cd;
 152:   void ** data;
 153:   if (!variants) {
2.35 ! frystyk 154:    HTTRACE(PROT_TRACE, "Ranking..... No variants\n");
2.29 frystyk 155:    return NO;
 156:   }
 157:   /* 
 158:   ** Walk through the list of local and global preferences and find the
 159:   ** overall q factor for each variant
 160:   */
 161:   cd = (HTContentDescription *) HTArray_firstObject(variants, data);
 162:   while (cd) {
 163:    double ctq_local = type_value(cd->content_type, HTRequest_conversion(request));
 164:    double ctq_global = type_value(cd->content_type, HTFormat_conversion());
 165:    double clq_local = lang_value(cd->content_language, HTRequest_language(request));
 166:    double clq_global = lang_value(cd->content_language, HTFormat_language());
 167:    double ceq_local = encoding_value(cd->content_encoding, HTRequest_encoding(request));
 168:    double ceq_global = encoding_value(cd->content_encoding, HTFormat_contentCoding());
2.35 ! frystyk 169:    HTTRACE(PROT_TRACE, "Qualities... Content type: %.3f, Content language: %.3f, Content encoding: %.3f\n" _ 
 ! 170:          HTMAX(ctq_local, ctq_global) _ 
 ! 171:          HTMAX(clq_local, clq_global) _ 
2.29 frystyk 172:          HTMAX(ceq_local, ceq_global));
 173:    cd->quality *= (HTMAX(ctq_local, ctq_global) *
 174:            HTMAX(clq_local, clq_global) *
 175:            HTMAX(ceq_local, ceq_global));
 176:    cd = (HTContentDescription *) HTArray_nextObject(variants, data);
 177:   }
 178: 
 179:   /* Sort the array of all our accepted preferences */
 180:   HTArray_sort(variants, VariantSort);
 181: 
 182:   /* Write out the result */
2.35 ! frystyk 183: #ifdef HTDEBUG 
2.29 frystyk 184:   if (PROT_TRACE) {
 185:    int cnt = 1;
 186:    cd = (HTContentDescription *) HTArray_firstObject(variants, data);
2.35 ! frystyk 187:    HTTRACE(PROT_TRACE, "Ranking.....\n");
 ! 188:    HTTRACE(PROT_TRACE, "RANK QUALITY CONTENT-TYPE     LANGUAGE ENCODING FILE\n");
2.29 frystyk 189:    while (cd) {
2.35 ! frystyk 190:      HTTRACE(PROT_TRACE, "%d.  %.4f %-20.20s %-8.8s %-10.10s %s\n" _
 ! 191:          cnt++ _
 ! 192:          cd->quality _
 ! 193:          cd->content_type ? HTAtom_name(cd->content_type) : "-" _
 ! 194:          cd->content_language?HTAtom_name(cd->content_language):"-" _
 ! 195:          cd->content_encoding?HTAtom_name(cd->content_encoding):"-" _
2.29 frystyk 196:          cd->filename ? cd->filename :"-");
 197:      cd = (HTContentDescription *) HTArray_nextObject(variants, data);
 198:    }
 199:   }
2.35 ! frystyk 200: #endif /* HTDEBUG */
2.29 frystyk 201:   return YES;
 202: }
2.3 luotonen 203: 
2.14 frystyk 204: /* PUBLIC                       HTSplitFilename()
 205: **
 206: **   Split the filename to an array of suffixes.
 207: **   Return the number of parts placed to the array.
 208: **   Array should have MAX_SUFF+1 items.
 209: */
2.23 frystyk 210: PRIVATE int HTSplitFilename (char * s_str, char ** s_arr)
2.14 frystyk 211: {
2.26 frystyk 212:   const char *delimiters = HTBind_delimiters();
2.14 frystyk 213:   char * start = s_str;
 214:   char * end;
 215:   char save;
 216:   int i;
 217: 
 218:   if (!s_str || !s_arr) return 0;
 219: 
 220:   for (i=0; i < MAX_SUFF && *start; i++) {
 221:    for(end=start+1; *end && !strchr(delimiters, *end); end++);
 222:    save = *end;
 223:    *end = 0;
 224:    StrAllocCopy(s_arr[i], start); /* Frees the previous value */
 225:    *end = save;
 226:    start = end;
 227:   }
2.24 frystyk 228:   HT_FREE(s_arr[i]);    /* Terminating NULL */
2.14 frystyk 229:   return i;
 230: }
 231: 
 232: 
2.3 luotonen 233: /*
 234: **   Set default file name for welcome page on each directory.
 235: */
2.23 frystyk 236: PUBLIC void HTAddWelcome (char * name)
2.3 luotonen 237: {
 238:   if (name) {
 239:    char * mycopy = NULL;
 240:    StrAllocCopy(mycopy,name);
 241: 
 242:    if (!welcome_names)
 243:      welcome_names = HTList_new();
 244:    HTList_addObject(welcome_names, (void*)mycopy);
 245:   }
 246: }
 247: 
 248: 
2.26 frystyk 249: #ifdef HAVE_READDIR
2.1 luotonen 250: 
 251: /* PRIVATE                       multi_match()
 252: **
 253: **   Check if actual filename (split in parts) fulfills
 254: **   the requirements.
 255: */
2.23 frystyk 256: PRIVATE BOOL multi_match (char ** required, int m, char ** actual, int n)
2.1 luotonen 257: {
 258:   int c;
 259:   int i,j;
 260: 
2.2 duns 261: #ifdef VMS
 262:   for(c=0; c<m && c<n && !strcasecomp(required[c], actual[c]); c++);
 263: #else /* not VMS */
2.1 luotonen 264:   for(c=0; c<m && c<n && !strcmp(required[c], actual[c]); c++);
2.2 duns 265: #endif /* not VMS */
2.1 luotonen 266: 
 267:   if (!c) return NO;     /* Names differ rigth from start */
 268: 
 269:   for(i=c; i<m; i++) {
 270:    BOOL found = NO;
 271:    for(j=c; j<n; j++) {
2.2 duns 272: #ifdef VMS
 273:      if (!strcasecomp(required[i], actual[j])) {
 274: #else /* not VMS */
2.1 luotonen 275:      if (!strcmp(required[i], actual[j])) {
2.2 duns 276: #endif /* not VMS */
2.1 luotonen 277:        found = YES;
 278:        break;
 279:      }
 280:    }
 281:    if (!found) return NO;
 282:   }
 283:   return YES;
 284: }
 285: 
 286: 
 287: /*
 288: **   Get multi-match possibilities for a given file
 289: **   ----------------------------------------------
 290: ** On entry:
 291: **   path  absolute path to one file in a directory,
 292: **       may end in .multi.
 293: ** On exit:
 294: **   returns a list of ContentDesription structures
 295: **       describing the mathing files.
 296: **
 297: */
2.29 frystyk 298: PRIVATE HTArray * dir_matches (char * path)
2.1 luotonen 299: {
 300:   static char * required[MAX_SUFF+1];
 301:   static char * actual[MAX_SUFF+1];
 302:   int m,n;
 303:   char * dirname = NULL;
 304:   char * basename = NULL;
 305:   int baselen;
 306:   char * multi = NULL;
 307:   DIR * dp;
2.26 frystyk 308:   struct dirent * dirbuf;
2.29 frystyk 309:   HTArray * matches = NULL;
2.16 frystyk 310: #ifdef HT_REENTRANT
2.31 frystyk 311:   struct dirent result;                    /* For readdir_r */
2.16 frystyk 312: #endif
2.1 luotonen 313: 
 314:   if (!path) return NULL;
 315: 
 316:   StrAllocCopy(dirname, path);
 317:   basename = (strrchr(dirname, '/'));
 318:   if (!basename)
 319:    goto dir_match_failed;
 320:   *basename++ = 0;
 321: 
 322:   multi = strrchr(basename, MULTI_SUFFIX[0]);
2.2 duns 323:   if (multi && !strcasecomp(multi, MULTI_SUFFIX))
2.1 luotonen 324:    *multi = 0;
 325:   baselen = strlen(basename);
 326: 
 327:   m = HTSplitFilename(basename, required);
 328: 
 329:   dp = opendir(dirname);
 330:   if (!dp) {
2.35 ! frystyk 331:    HTTRACE(PROT_TRACE, "Warning..... Can't open directory %s\n" _ dirname);
2.1 luotonen 332:    goto dir_match_failed;
 333:   }
 334: 
2.29 frystyk 335:   matches = HTArray_new(VARIANTS);
2.16 frystyk 336: #ifdef HT_REENTRANT
2.31 frystyk 337:    while ((dirbuf = (struct dirent *) readdir_r(dp, &result))) {
2.16 frystyk 338: #else
 339:    while ((dirbuf = readdir(dp))) {
 340: #endif /* HT_REENTRANT */
2.1 luotonen 341:    if (!dirbuf->d_ino) continue;  /* Not in use */
2.3 luotonen 342:    if (!strcmp(dirbuf->d_name,".") ||
 343:      !strcmp(dirbuf->d_name,"..") ||
2.20 frystyk 344:      !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3 luotonen 345:      continue;
2.7 frystyk 346: 
2.13 frystyk 347:    /* Use of direct->namlen is only valid in BSD'ish system */
 348:    /* Thanks to chip@chinacat.unicom.com (Chip Rosenthal) */
 349:    /* if ((int)(dirbuf->d_namlen) >= baselen) { */
 350:    if ((int) strlen(dirbuf->d_name) >= baselen) {
2.1 luotonen 351:      n = HTSplitFilename(dirbuf->d_name, actual);
 352:      if (multi_match(required, m, actual, n)) {
 353:        HTContentDescription * cd;
2.29 frystyk 354:        if ((cd = (HTContentDescription *)
 355:           HT_CALLOC(1, sizeof(HTContentDescription))) == NULL)
 356:          HT_OUTOFMEM("dir_matches");
 357:        if (HTBind_getFormat(dirbuf->d_name,
 358:                   &cd->content_type,
 359:                   &cd->content_encoding,
 360:                   &cd->content_transfer,
 361:                   &cd->content_language,
 362:                   &cd->quality)) {
2.1 luotonen 363:          if (cd->content_type) {
2.24 frystyk 364:            if ((cd->filename = (char *) HT_MALLOC(strlen(dirname) + 2 + strlen(dirbuf->d_name))) == NULL)
 365:              HT_OUTOFMEM("dir_matches");
2.29 frystyk 366:            sprintf(cd->filename, "%s/%s", dirname, dirbuf->d_name);
 367:            HTArray_addObject(matches, (void *) cd);
 368:          } else {
 369:            HT_FREE(cd);
2.1 luotonen 370:          }
2.29 frystyk 371:        } else {
 372:          HT_FREE(cd);
2.1 luotonen 373:        }
 374:      }
 375:    }
 376:   }
 377:   closedir(dp);
 378: 
 379:  dir_match_failed:
2.24 frystyk 380:   HT_FREE(dirname);
2.1 luotonen 381:   return matches;
 382: }
 383: 
 384: 
 385: /*
 386: **   Get the best match for a given file
 387: **   -----------------------------------
 388: ** On entry:
 389: **   req->conversions accepted content-types
 390: **   req->encodings  accepted content-transfer-encodings
 391: **   req->languages  accepted content-languages
 392: **   path       absolute pathname of the filename for
 393: **            which the match is desired.
 394: ** On exit:
 395: **   returns a newly allocated absolute filepath.
 396: */
2.23 frystyk 397: PRIVATE char * HTGetBest (HTRequest * req, char * path)
2.1 luotonen 398: {
2.29 frystyk 399:   HTArray * variants = NULL;
 400:   char * representation = NULL;
2.1 luotonen 401: 
2.13 frystyk 402:   if (!path || !*path) return NULL;
2.1 luotonen 403: 
2.29 frystyk 404:   if ((variants = dir_matches(path)) == NULL) {
2.35 ! frystyk 405:    HTTRACE(PROT_TRACE, "No matches.. for \"%s\"\n" _ path);
2.13 frystyk 406:    return NULL;
2.1 luotonen 407:   }
 408: 
2.35 ! frystyk 409: #ifdef HTDEBUG
2.29 frystyk 410:   if (PROT_TRACE) {
 411:    void ** data;
 412:    HTContentDescription * cd = HTArray_firstObject(variants, data);
2.35 ! frystyk 413:    HTTRACE(PROT_TRACE, "Multi....... Possibilities for \"%s\"\n" _ path);
 ! 414:    HTTRACE(PROT_TRACE, "   QUALITY CONTENT-TYPE     LANGUAGE ENCODING FILE\n");
2.29 frystyk 415:    while (cd) {
2.35 ! frystyk 416:      HTTRACE(PROT_TRACE, "   %.4f %-20.20s %-8.8s %-10.10s %s\n" _
 ! 417:          cd->quality _
 ! 418:          cd->content_type  ?HTAtom_name(cd->content_type) :"-\t" _
 ! 419:          cd->content_language?HTAtom_name(cd->content_language):"-" _
 ! 420:          cd->content_encoding?HTAtom_name(cd->content_encoding):"-" _
2.29 frystyk 421:          cd->filename    ?cd->filename          :"-");
 422:      cd = (HTContentDescription *) HTArray_nextObject(variants, data);
 423:    }
2.1 luotonen 424:   }
2.35 ! frystyk 425: #endif /* HTDEBUG */
2.1 luotonen 426: 
 427:   /*
2.29 frystyk 428:   ** Finally get the best variant which is readable
2.1 luotonen 429:   */
2.29 frystyk 430:   if (HTRank(req, variants)) {
 431:    void ** data;
 432:    HTContentDescription * cd = HTArray_firstObject(variants, data);
 433:    while (cd) {
 434:      if (cd->filename) {
 435:        if (access(cd->filename, R_OK) != -1)
 436:          StrAllocCopy(representation, cd->filename);
2.35 ! frystyk 437:        else HTTRACE(PROT_TRACE, "Multi....... `%s\' is not readable\n" _ 
2.29 frystyk 438:              cd->filename);
2.1 luotonen 439:      }
2.29 frystyk 440:      HT_FREE(cd->filename);
 441:      HT_FREE(cd);
 442:      cd = (HTContentDescription *) HTArray_nextObject(variants, data);
2.1 luotonen 443:    }
 444:   }
2.29 frystyk 445:   HTArray_delete(variants);
 446:   return representation;
2.1 luotonen 447: }
 448: 
2.3 luotonen 449: 
 450: 
2.23 frystyk 451: PRIVATE int welcome_value (char * name)
2.3 luotonen 452: {
 453:   HTList * cur = welcome_names;
 454:   char * welcome;
 455:   int v = 0;
 456: 
 457:   while ((welcome = (char*)HTList_nextObject(cur))) {
 458:    v++;
 459:    if (!strcmp(welcome,name)) return v;
 460:   }
 461:   return 0;
 462: }
 463: 
 464: 
 465: 
2.23 frystyk 466: PRIVATE char * get_best_welcome (char * path)
2.3 luotonen 467: {
 468:   char * best_welcome = NULL;
 469:   int best_value = 0;
 470:   DIR * dp;
2.26 frystyk 471:   struct dirent * dirbuf;
2.3 luotonen 472:   char * last = strrchr(path, '/');
 473: 
 474:   if (!welcome_names) {
 475:    HTAddWelcome("Welcome.html");
 476:    HTAddWelcome("welcome.html");
2.5 luotonen 477: #if 0
2.3 luotonen 478:    HTAddWelcome("Index.html");
2.5 luotonen 479: #endif
2.3 luotonen 480:    HTAddWelcome("index.html");
 481:   }
 482: 
2.5 luotonen 483:   if (last && last!=path) *last = 0;
2.3 luotonen 484:   dp = opendir(path);
2.5 luotonen 485:   if (last && last!=path) *last='/';
2.3 luotonen 486:   if (!dp) {
2.35 ! frystyk 487:    HTTRACE(PROT_TRACE, "Warning..... Can't open directory %s\n" _ path);
2.3 luotonen 488:    return NULL;
 489:   }
 490:   while ((dirbuf = readdir(dp))) {
2.13 frystyk 491:    if (!dirbuf->d_ino ||
2.3 luotonen 492:      !strcmp(dirbuf->d_name,".") ||
 493:      !strcmp(dirbuf->d_name,"..") ||
2.20 frystyk 494:      !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3 luotonen 495:      continue;
 496:    else {
 497:      int v = welcome_value(dirbuf->d_name);
 498:      if (v > best_value) {
 499:        best_value = v;
 500:        StrAllocCopy(best_welcome, dirbuf->d_name);
 501:      }
 502:    }
 503:   }
 504:   closedir(dp);
 505: 
 506:   if (best_welcome) {
2.24 frystyk 507:    char * welcome;
 508:    if ((welcome = (char *) HT_MALLOC(strlen(path) + strlen(best_welcome)+2)) == NULL)
 509:      HT_OUTOFMEM("get_best_welcome");
2.4 luotonen 510:    sprintf(welcome, "%s%s%s", path, last ? "" : "/", best_welcome);
2.24 frystyk 511:    HT_FREE(best_welcome);
2.35 ! frystyk 512:    HTTRACE(PROT_TRACE, "Welcome..... \"%s\"\n" _ welcome);
2.3 luotonen 513:    return welcome;
 514:   }
 515:   return NULL;
 516: }
 517: 
2.26 frystyk 518: #endif /* HAVE_READDIR */
2.1 luotonen 519: 
 520: 
 521: /*
 522: **   Do multiformat handling
 523: **   -----------------------
 524: ** On entry:
 525: **   req->conversions accepted content-types
 526: **   req->encodings  accepted content-transfer-encodings
 527: **   req->languages  accepted content-languages
 528: **   path       absolute pathname of the filename for
 529: **            which the match is desired.
 530: **   stat_info     pointer to result space.
 531: **
 532: ** On exit:
 533: **   returns a newly allocated absolute filepath of the best
 534: **       match, or NULL if no match.
 535: **   stat_info     will contain inode information as
 536: **            returned by stat().
 537: */
2.23 frystyk 538: PUBLIC char * HTMulti (HTRequest *   req,
 539:            char *      path,
 540:            struct stat *  stat_info)
2.1 luotonen 541: {
 542:   char * new_path = NULL;
 543:   int stat_status = -1;
 544: 
2.3 luotonen 545:   if (!req || !path || !*path || !stat_info)
2.1 luotonen 546:    return NULL;
 547: 
2.26 frystyk 548: #ifdef HAVE_READDIR
2.19 frystyk 549:   if (*(path+strlen(path)-1) == '/') {    /* Find welcome page */
2.3 luotonen 550:    new_path = get_best_welcome(path);
 551:    if (new_path) path = new_path;
2.29 frystyk 552:   } else{
2.3 luotonen 553:    char * multi = strrchr(path, MULTI_SUFFIX[0]);
 554:    if (multi && !strcasecomp(multi, MULTI_SUFFIX)) {
2.35 ! frystyk 555:      HTTRACE(PROT_TRACE, "Multi....... by %s suffix\n" _ MULTI_SUFFIX);
2.1 luotonen 556:      if (!(new_path = HTGetBest(req, path))) {
2.35 ! frystyk 557:        HTTRACE(PROT_TRACE, "Multi....... failed -- giving up\n");
2.1 luotonen 558:        return NULL;
 559:      }
 560:      path = new_path;
2.29 frystyk 561:    } else {
2.18 frystyk 562:      stat_status = HT_STAT(path, stat_info);
2.3 luotonen 563:      if (stat_status == -1) {
2.35 ! frystyk 564:        HTTRACE(PROT_TRACE, "AutoMulti... can't stat \"%s\"(errno %d)\n" _ 
 ! 565:              path _ errno);
2.3 luotonen 566:        if (!(new_path = HTGetBest(req, path))) {
2.35 ! frystyk 567:          HTTRACE(PROT_TRACE, "AutoMulti... failed -- giving up\n");
2.3 luotonen 568:          return NULL;
 569:        }
 570:        path = new_path;
 571:      }
2.1 luotonen 572:    }
 573:   }
2.26 frystyk 574: #endif /* HAVE_READDIR */
2.1 luotonen 575: 
 576:   if (stat_status == -1)
2.18 frystyk 577:    stat_status = HT_STAT(path, stat_info);
2.1 luotonen 578:   if (stat_status == -1) {
2.35 ! frystyk 579:    HTTRACE(PROT_TRACE, "Stat fails.. on \"%s\" -- giving up (errno %d)\n" _ 
 ! 580:          path _ errno);
2.1 luotonen 581:    return NULL;
2.29 frystyk 582:   } else {
2.1 luotonen 583:    if (!new_path) {
 584:      StrAllocCopy(new_path, path);
 585:      return new_path;
 586:    }
 587:    else return path;
 588:   }
 589: }
 590: 
 591: 

Webmaster

AltStyle によって変換されたページ (->オリジナル) /