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

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

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

Webmaster

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