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

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 */
                     13: #include "tcp.h"
                     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.21      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:     }
                     49:     FREE(s_arr[i]);    /* Terminating NULL */
                     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.13      frystyk    70: #ifdef GOT_READ_DIR
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.13      frystyk   129:     STRUCT_DIRENT * dirbuf;
2.1       luotonen  130:     HTList * matches = NULL;
2.16      frystyk   131: #ifdef HT_REENTRANT
                    132:     STRUCT_DIRENT result;                                  /* For readdir_r */
                    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.22      frystyk   153:            TTYPrint(TDEST,"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
                    159:        while ((dirbuf = (STRUCT_DIRENT *) readdir_r(dp, &result))) {
                    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) {
                    179:                        cd->filename = (char*)malloc(strlen(dirname) + 2 +
                    180:                                                     strlen(dirbuf->d_name));
                    181:                        if (!cd->filename) outofmem(__FILE__, "dir_matches");
                    182:                        sprintf(cd->filename, "%s/%s",
                    183:                                dirname, dirbuf->d_name);
                    184:                        HTList_addObject(matches, (void*)cd);
                    185:                    }
                    186:                    else free(cd);
                    187:                }
                    188:            }
                    189:        }
                    190:     }
                    191:     closedir(dp);
                    192: 
                    193:   dir_match_failed:
                    194:     free(dirname);
                    195:     return matches;
                    196: }
                    197: 
                    198: 
                    199: /*
                    200: **     Get the best match for a given file
                    201: **     -----------------------------------
                    202: ** On entry:
                    203: **     req->conversions  accepted content-types
                    204: **     req->encodings    accepted content-transfer-encodings
                    205: **     req->languages    accepted content-languages
                    206: **     path              absolute pathname of the filename for
                    207: **                       which the match is desired.
                    208: ** On exit:
                    209: **     returns a newly allocated absolute filepath.
                    210: */
2.23    ! frystyk   211: PRIVATE char * HTGetBest (HTRequest * req, char * path)
2.1       luotonen  212: {
                    213:     HTList * matches;
                    214:     HTList * cur;
                    215:     HTContentDescription * cd;
                    216:     HTContentDescription * best = NULL;
                    217:     char * best_path = NULL;
                    218: 
2.13      frystyk   219:     if (!path || !*path) return NULL;
2.1       luotonen  220: 
                    221:     matches = dir_matches(path);
                    222:     if (!matches) {
2.13      frystyk   223:        if (PROT_TRACE)
2.22      frystyk   224:            TTYPrint(TDEST, "No matches.. for \"%s\"\n", path);
2.13      frystyk   225:        return NULL;
2.1       luotonen  226:     }
                    227: 
                    228:     /* BEGIN DEBUG */
                    229:     cur = matches;
2.13      frystyk   230:     if (PROT_TRACE)
2.22      frystyk   231:        TTYPrint(TDEST, "Multi....... Possibilities for \"%s\"\n", path);
2.13      frystyk   232:     if (PROT_TRACE)
2.22      frystyk   233:        TTYPrint(TDEST, "\nCONTENT-TYPE  LANGUAGE  ENCODING  QUALITY  FILE\n");
2.1       luotonen  234:     while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
2.13      frystyk   235:        if (PROT_TRACE)
2.22      frystyk   236:           TTYPrint(TDEST, "%s\t%s\t%s\t  %.5f  %s\n",
2.13      frystyk   237:                   cd->content_type    ?HTAtom_name(cd->content_type)  :"-\t",
                    238:                   cd->content_language?HTAtom_name(cd->content_language):"-",
                    239:                   cd->content_encoding?HTAtom_name(cd->content_encoding):"-",
                    240:                   cd->quality,
                    241:                   cd->filename        ?cd->filename                     :"-");
2.1       luotonen  242:     }
2.22      frystyk   243:     if (PROT_TRACE) TTYPrint(TDEST, "\n");
2.1       luotonen  244:     /* END DEBUG */
                    245: 
                    246:     /*
                    247:     ** Finally get best that is readable
                    248:     */
                    249:     if (HTRank(matches, req->conversions, req->languages, req->encodings)) {
                    250:        cur = matches;
                    251:        while ((best = (HTContentDescription*)HTList_nextObject(cur))) {
                    252:            if (best && best->filename) {
                    253:                if (access(best->filename, R_OK) != -1) {
                    254:                    StrAllocCopy(best_path, best->filename);
                    255:                    break;
2.13      frystyk   256:                } else if (PROT_TRACE)
2.22      frystyk   257:                    TTYPrint(TDEST, "Bad News.... \"%s\" is not readable\n",
2.1       luotonen  258:                            best->filename);
                    259:            }
                    260:        }
                    261:     } /* Select best */
                    262: 
                    263:     cur = matches;
                    264:     while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
                    265:        if (cd->filename) free(cd->filename);
                    266:        free(cd);
                    267:     }
                    268:     HTList_delete(matches);
                    269: 
                    270:     return best_path;
                    271: }
                    272: 
2.3       luotonen  273: 
                    274: 
2.23    ! frystyk   275: PRIVATE int welcome_value (char * name)
2.3       luotonen  276: {
                    277:     HTList * cur = welcome_names;
                    278:     char * welcome;
                    279:     int v = 0;
                    280: 
                    281:     while ((welcome = (char*)HTList_nextObject(cur))) {
                    282:        v++;
                    283:        if (!strcmp(welcome,name)) return v;
                    284:     }
                    285:     return 0;
                    286: }
                    287: 
                    288: 
                    289: 
2.23    ! frystyk   290: PRIVATE char * get_best_welcome (char * path)
2.3       luotonen  291: {
                    292:     char * best_welcome = NULL;
                    293:     int best_value = 0;
                    294:     DIR * dp;
2.13      frystyk   295:     STRUCT_DIRENT * dirbuf;
2.3       luotonen  296:     char * last = strrchr(path, '/');
                    297: 
                    298:     if (!welcome_names) {
                    299:        HTAddWelcome("Welcome.html");
                    300:        HTAddWelcome("welcome.html");
2.5       luotonen  301: #if 0
2.3       luotonen  302:        HTAddWelcome("Index.html");
2.5       luotonen  303: #endif
2.3       luotonen  304:        HTAddWelcome("index.html");
                    305:     }
                    306: 
2.5       luotonen  307:     if (last && last!=path) *last = 0;
2.3       luotonen  308:     dp = opendir(path);
2.5       luotonen  309:     if (last && last!=path) *last='/';
2.3       luotonen  310:     if (!dp) {
2.13      frystyk   311:        if (PROT_TRACE)
2.22      frystyk   312:            TTYPrint(TDEST, "Warning..... Can't open directory %s\n",path);
2.3       luotonen  313:        return NULL;
                    314:     }
                    315:     while ((dirbuf = readdir(dp))) {
2.13      frystyk   316:        if (!dirbuf->d_ino ||
2.3       luotonen  317:            !strcmp(dirbuf->d_name,".") ||
                    318:            !strcmp(dirbuf->d_name,"..") ||
2.20      frystyk   319:            !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3       luotonen  320:            continue;
                    321:        else {
                    322:            int v = welcome_value(dirbuf->d_name);
                    323:            if (v > best_value) {
                    324:                best_value = v;
                    325:                StrAllocCopy(best_welcome, dirbuf->d_name);
                    326:            }
                    327:        }
                    328:     }
                    329:     closedir(dp);
                    330: 
                    331:     if (best_welcome) {
                    332:        char * welcome = (char*)malloc(strlen(path) + strlen(best_welcome)+2);
                    333:        if (!welcome) outofmem(__FILE__, "get_best_welcome");
2.4       luotonen  334:        sprintf(welcome, "%s%s%s", path, last ? "" : "/", best_welcome);
2.3       luotonen  335:        free(best_welcome);
2.13      frystyk   336:        if (PROT_TRACE)
2.22      frystyk   337:            TTYPrint(TDEST,"Welcome..... \"%s\"\n",welcome);
2.3       luotonen  338:        return welcome;
                    339:     }
                    340:     return NULL;
                    341: }
                    342: 
2.13      frystyk   343: #endif /* GOT_READ_DIR */
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.13      frystyk   373: #ifdef GOT_READ_DIR
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.22      frystyk   382:                TTYPrint(TDEST, "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.22      frystyk   385:                    TTYPrint(TDEST, "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.22      frystyk   394:                    TTYPrint(TDEST,
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.22      frystyk   399:                        TTYPrint(TDEST, "AutoMulti... failed -- giving up\n");
2.3       luotonen  400:                    return NULL;
                    401:                }
                    402:                path = new_path;
                    403:            }
2.1       luotonen  404:        }
                    405:     }
2.13      frystyk   406: #endif /* GOT_READ_DIR */
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.22      frystyk   412:            TTYPrint(TDEST, "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