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