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

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.36    ! kahan       6: **     @(#) $Id: HTMulti.c,v 2.35 1999/02/22 22:10:11 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.36    ! kahan     336: #ifdef HAVE_READDIR_R_2
2.31      frystyk   337:        while ((dirbuf = (struct dirent *) readdir_r(dp, &result))) {
2.36    ! kahan     338: #elif defined(HAVE_READDIR_R_3)
        !           339:         while (readdir_r(dp, &result, &dirbuf) == 0) {
2.16      frystyk   340: #else
                    341:        while ((dirbuf = readdir(dp))) {
2.36    ! kahan     342: #endif /* HAVE_READDIR_R_2 */
2.1       luotonen  343:        if (!dirbuf->d_ino) continue;   /* Not in use */
2.3       luotonen  344:        if (!strcmp(dirbuf->d_name,".") ||
                    345:            !strcmp(dirbuf->d_name,"..") ||
2.20      frystyk   346:            !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3       luotonen  347:            continue;
2.7       frystyk   348: 
2.13      frystyk   349:        /* Use of direct->namlen is only valid in BSD'ish system */
                    350:        /* Thanks to chip@chinacat.unicom.com (Chip Rosenthal) */
                    351:        /* if ((int)(dirbuf->d_namlen) >= baselen) { */
                    352:        if ((int) strlen(dirbuf->d_name) >= baselen) {
2.1       luotonen  353:            n = HTSplitFilename(dirbuf->d_name, actual);
                    354:            if (multi_match(required, m, actual, n)) {
                    355:                HTContentDescription * cd;
2.29      frystyk   356:                if ((cd = (HTContentDescription  *)
                    357:                     HT_CALLOC(1, sizeof(HTContentDescription))) == NULL)
                    358:                    HT_OUTOFMEM("dir_matches");
                    359:                if (HTBind_getFormat(dirbuf->d_name,
                    360:                                     &cd->content_type,
                    361:                                     &cd->content_encoding,
                    362:                                     &cd->content_transfer,
                    363:                                     &cd->content_language,
                    364:                                     &cd->quality)) {
2.1       luotonen  365:                    if (cd->content_type) {
2.24      frystyk   366:                        if ((cd->filename = (char *) HT_MALLOC(strlen(dirname) + 2 + strlen(dirbuf->d_name))) == NULL)
                    367:                            HT_OUTOFMEM("dir_matches");
2.29      frystyk   368:                        sprintf(cd->filename, "%s/%s", dirname, dirbuf->d_name);
                    369:                        HTArray_addObject(matches, (void *) cd);
                    370:                    } else {
                    371:                        HT_FREE(cd);
2.1       luotonen  372:                    }
2.29      frystyk   373:                } else {
                    374:                    HT_FREE(cd);
2.1       luotonen  375:                }
                    376:            }
                    377:        }
                    378:     }
                    379:     closedir(dp);
                    380: 
                    381:   dir_match_failed:
2.24      frystyk   382:     HT_FREE(dirname);
2.1       luotonen  383:     return matches;
                    384: }
                    385: 
                    386: 
                    387: /*
                    388: **     Get the best match for a given file
                    389: **     -----------------------------------
                    390: ** On entry:
                    391: **     req->conversions  accepted content-types
                    392: **     req->encodings    accepted content-transfer-encodings
                    393: **     req->languages    accepted content-languages
                    394: **     path              absolute pathname of the filename for
                    395: **                       which the match is desired.
                    396: ** On exit:
                    397: **     returns a newly allocated absolute filepath.
                    398: */
2.23      frystyk   399: PRIVATE char * HTGetBest (HTRequest * req, char * path)
2.1       luotonen  400: {
2.29      frystyk   401:     HTArray * variants = NULL;
                    402:     char * representation = NULL;
2.1       luotonen  403: 
2.13      frystyk   404:     if (!path || !*path) return NULL;
2.1       luotonen  405: 
2.29      frystyk   406:     if ((variants = dir_matches(path)) == NULL) {
2.35      frystyk   407:        HTTRACE(PROT_TRACE, "No matches.. for \"%s\"\n" _ path);
2.13      frystyk   408:        return NULL;
2.1       luotonen  409:     }
                    410: 
2.35      frystyk   411: #ifdef HTDEBUG
2.29      frystyk   412:     if (PROT_TRACE) {
                    413:        void ** data;
                    414:        HTContentDescription * cd = HTArray_firstObject(variants, data);
2.35      frystyk   415:        HTTRACE(PROT_TRACE, "Multi....... Possibilities for \"%s\"\n" _ path);
                    416:        HTTRACE(PROT_TRACE, "     QUALITY CONTENT-TYPE         LANGUAGE ENCODING  FILE\n");
2.29      frystyk   417:        while (cd) {
2.35      frystyk   418:            HTTRACE(PROT_TRACE, "     %.4f  %-20.20s %-8.8s %-10.10s %s\n" _
                    419:                    cd->quality _
                    420:                    cd->content_type    ?HTAtom_name(cd->content_type)  :"-\t" _
                    421:                    cd->content_language?HTAtom_name(cd->content_language):"-" _
                    422:                    cd->content_encoding?HTAtom_name(cd->content_encoding):"-" _
2.29      frystyk   423:                    cd->filename        ?cd->filename                    :"-");
                    424:            cd = (HTContentDescription *) HTArray_nextObject(variants, data);
                    425:        }
2.1       luotonen  426:     }
2.35      frystyk   427: #endif /* HTDEBUG */
2.1       luotonen  428: 
                    429:     /*
2.29      frystyk   430:     ** Finally get the best variant which is readable
2.1       luotonen  431:     */
2.29      frystyk   432:     if (HTRank(req, variants)) {
                    433:        void ** data;
                    434:        HTContentDescription * cd = HTArray_firstObject(variants, data);
                    435:        while (cd) {
                    436:            if (cd->filename) {
                    437:                if (access(cd->filename, R_OK) != -1)
                    438:                    StrAllocCopy(representation, cd->filename);
2.35      frystyk   439:                else HTTRACE(PROT_TRACE, "Multi....... `%s\' is not readable\n" _ 
2.29      frystyk   440:                            cd->filename);
2.1       luotonen  441:            }
2.29      frystyk   442:            HT_FREE(cd->filename);
                    443:            HT_FREE(cd);
                    444:            cd = (HTContentDescription *) HTArray_nextObject(variants, data);
2.1       luotonen  445:        }
                    446:     }
2.29      frystyk   447:     HTArray_delete(variants);
                    448:     return representation;
2.1       luotonen  449: }
                    450: 
2.3       luotonen  451: 
                    452: 
2.23      frystyk   453: PRIVATE int welcome_value (char * name)
2.3       luotonen  454: {
                    455:     HTList * cur = welcome_names;
                    456:     char * welcome;
                    457:     int v = 0;
                    458: 
                    459:     while ((welcome = (char*)HTList_nextObject(cur))) {
                    460:        v++;
                    461:        if (!strcmp(welcome,name)) return v;
                    462:     }
                    463:     return 0;
                    464: }
                    465: 
                    466: 
                    467: 
2.23      frystyk   468: PRIVATE char * get_best_welcome (char * path)
2.3       luotonen  469: {
                    470:     char * best_welcome = NULL;
                    471:     int best_value = 0;
                    472:     DIR * dp;
2.26      frystyk   473:     struct dirent * dirbuf;
2.3       luotonen  474:     char * last = strrchr(path, '/');
                    475: 
                    476:     if (!welcome_names) {
                    477:        HTAddWelcome("Welcome.html");
                    478:        HTAddWelcome("welcome.html");
2.5       luotonen  479: #if 0
2.3       luotonen  480:        HTAddWelcome("Index.html");
2.5       luotonen  481: #endif
2.3       luotonen  482:        HTAddWelcome("index.html");
                    483:     }
                    484: 
2.5       luotonen  485:     if (last && last!=path) *last = 0;
2.3       luotonen  486:     dp = opendir(path);
2.5       luotonen  487:     if (last && last!=path) *last='/';
2.3       luotonen  488:     if (!dp) {
2.35      frystyk   489:        HTTRACE(PROT_TRACE, "Warning..... Can't open directory %s\n" _ path);
2.3       luotonen  490:        return NULL;
                    491:     }
                    492:     while ((dirbuf = readdir(dp))) {
2.13      frystyk   493:        if (!dirbuf->d_ino ||
2.3       luotonen  494:            !strcmp(dirbuf->d_name,".") ||
                    495:            !strcmp(dirbuf->d_name,"..") ||
2.20      frystyk   496:            !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3       luotonen  497:            continue;
                    498:        else {
                    499:            int v = welcome_value(dirbuf->d_name);
                    500:            if (v > best_value) {
                    501:                best_value = v;
                    502:                StrAllocCopy(best_welcome, dirbuf->d_name);
                    503:            }
                    504:        }
                    505:     }
                    506:     closedir(dp);
                    507: 
                    508:     if (best_welcome) {
2.24      frystyk   509:        char * welcome;
                    510:        if ((welcome = (char *) HT_MALLOC(strlen(path) + strlen(best_welcome)+2)) == NULL)
                    511:            HT_OUTOFMEM("get_best_welcome");
2.4       luotonen  512:        sprintf(welcome, "%s%s%s", path, last ? "" : "/", best_welcome);
2.24      frystyk   513:        HT_FREE(best_welcome);
2.35      frystyk   514:        HTTRACE(PROT_TRACE, "Welcome..... \"%s\"\n" _ welcome);
2.3       luotonen  515:        return welcome;
                    516:     }
                    517:     return NULL;
                    518: }
                    519: 
2.26      frystyk   520: #endif /* HAVE_READDIR */
2.1       luotonen  521: 
                    522: 
                    523: /*
                    524: **     Do multiformat handling
                    525: **     -----------------------
                    526: ** On entry:
                    527: **     req->conversions  accepted content-types
                    528: **     req->encodings    accepted content-transfer-encodings
                    529: **     req->languages    accepted content-languages
                    530: **     path              absolute pathname of the filename for
                    531: **                       which the match is desired.
                    532: **     stat_info         pointer to result space.
                    533: **
                    534: ** On exit:
                    535: **     returns a newly allocated absolute filepath of the best
                    536: **             match, or NULL if no match.
                    537: **     stat_info         will contain inode information as
                    538: **                       returned by stat().
                    539: */
2.23      frystyk   540: PUBLIC char * HTMulti (HTRequest *     req,
                    541:                       char *           path,
                    542:                       struct stat *    stat_info)
2.1       luotonen  543: {
                    544:     char * new_path = NULL;
                    545:     int stat_status = -1;
                    546: 
2.3       luotonen  547:     if (!req || !path || !*path || !stat_info)
2.1       luotonen  548:        return NULL;
                    549: 
2.26      frystyk   550: #ifdef HAVE_READDIR
2.19      frystyk   551:     if (*(path+strlen(path)-1) == '/') {       /* Find welcome page */
2.3       luotonen  552:        new_path = get_best_welcome(path);
                    553:        if (new_path) path = new_path;
2.29      frystyk   554:     } else{
2.3       luotonen  555:        char * multi = strrchr(path, MULTI_SUFFIX[0]);
                    556:        if (multi && !strcasecomp(multi, MULTI_SUFFIX)) {
2.35      frystyk   557:            HTTRACE(PROT_TRACE, "Multi....... by %s suffix\n" _ MULTI_SUFFIX);
2.1       luotonen  558:            if (!(new_path = HTGetBest(req, path))) {
2.35      frystyk   559:                HTTRACE(PROT_TRACE, "Multi....... failed -- giving up\n");
2.1       luotonen  560:                return NULL;
                    561:            }
                    562:            path = new_path;
2.29      frystyk   563:        } else {
2.18      frystyk   564:            stat_status = HT_STAT(path, stat_info);
2.3       luotonen  565:            if (stat_status == -1) {
2.35      frystyk   566:                HTTRACE(PROT_TRACE, "AutoMulti... can't stat \"%s\"(errno %d)\n" _ 
                    567:                            path _ errno);
2.3       luotonen  568:                if (!(new_path = HTGetBest(req, path))) {
2.35      frystyk   569:                    HTTRACE(PROT_TRACE, "AutoMulti... failed -- giving up\n");
2.3       luotonen  570:                    return NULL;
                    571:                }
                    572:                path = new_path;
                    573:            }
2.1       luotonen  574:        }
                    575:     }
2.26      frystyk   576: #endif /* HAVE_READDIR */
2.1       luotonen  577: 
                    578:     if (stat_status == -1)
2.18      frystyk   579:        stat_status = HT_STAT(path, stat_info);
2.1       luotonen  580:     if (stat_status == -1) {
2.35      frystyk   581:        HTTRACE(PROT_TRACE, "Stat fails.. on \"%s\" -- giving up (errno %d)\n" _ 
                    582:                    path _ errno);
2.1       luotonen  583:        return NULL;
2.29      frystyk   584:     } else {
2.1       luotonen  585:        if (!new_path) {
                    586:            StrAllocCopy(new_path, path);
                    587:            return new_path;
                    588:        }
                    589:        else return path;
                    590:     }
                    591: }
                    592: 
                    593: 

Webmaster