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

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.14      frystyk    17: #include "HTDirBrw.h"
                     18: #include "HTBind.h"
2.1       luotonen   19: #include "HTList.h"
                     20: 
                     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: */
                     31: PRIVATE int HTSplitFilename ARGS2(char *,      s_str,
                     32:                                  char **,      s_arr)
                     33: {
                     34:     CONST char *delimiters = HTBind_getDelimiters();
                     35:     char * start = s_str;
                     36:     char * end;
                     37:     char save;
                     38:     int i;
                     39: 
                     40:     if (!s_str || !s_arr) return 0;
                     41: 
                     42:     for (i=0; i < MAX_SUFF && *start; i++) {
                     43:        for(end=start+1; *end && !strchr(delimiters, *end); end++);
                     44:        save = *end;
                     45:        *end = 0;
                     46:        StrAllocCopy(s_arr[i], start);  /* Frees the previous value */
                     47:        *end = save;
                     48:        start = end;
                     49:     }
                     50:     FREE(s_arr[i]);    /* Terminating NULL */
                     51:     return i;
                     52: }
                     53: 
                     54: 
2.3       luotonen   55: /*
                     56: **     Set default file name for welcome page on each directory.
                     57: */
                     58: PUBLIC void HTAddWelcome ARGS1(char *, name)
                     59: {
                     60:     if (name) {
                     61:        char * mycopy = NULL;
                     62:        StrAllocCopy(mycopy,name);
                     63: 
                     64:        if (!welcome_names)
                     65:            welcome_names = HTList_new();
                     66:        HTList_addObject(welcome_names, (void*)mycopy);
                     67:     }
                     68: }
                     69: 
                     70: 
2.13      frystyk    71: #ifdef GOT_READ_DIR
2.1       luotonen   72: 
                     73: /* PRIVATE                                             multi_match()
                     74: **
                     75: **     Check if actual filename (split in parts) fulfills
                     76: **     the requirements.
                     77: */
                     78: PRIVATE BOOL multi_match ARGS4(char **, required,
                     79:                               int,     m,
                     80:                               char **, actual,
                     81:                               int,     n)
                     82: {
                     83:     int c;
                     84:     int i,j;
                     85: 
2.2       duns       86: #ifdef VMS
                     87:     for(c=0;  c<m && c<n && !strcasecomp(required[c], actual[c]);  c++);
                     88: #else /* not VMS */
2.1       luotonen   89:     for(c=0;  c<m && c<n && !strcmp(required[c], actual[c]);  c++);
2.2       duns       90: #endif /* not VMS */
2.1       luotonen   91: 
                     92:     if (!c) return NO;         /* Names differ rigth from start */
                     93: 
                     94:     for(i=c; i<m; i++) {
                     95:        BOOL found = NO;
                     96:        for(j=c; j<n; j++) {
2.2       duns       97: #ifdef VMS
                     98:            if (!strcasecomp(required[i], actual[j])) {
                     99: #else /* not VMS */
2.1       luotonen  100:            if (!strcmp(required[i], actual[j])) {
2.2       duns      101: #endif /* not VMS */
2.1       luotonen  102:                found = YES;
                    103:                break;
                    104:            }
                    105:        }
                    106:        if (!found) return NO;
                    107:     }
                    108:     return YES;
                    109: }
                    110: 
                    111: 
                    112: /*
                    113: **     Get multi-match possibilities for a given file
                    114: **     ----------------------------------------------
                    115: ** On entry:
                    116: **     path    absolute path to one file in a directory,
                    117: **             may end in .multi.
                    118: ** On exit:
                    119: **     returns a list of ContentDesription structures
                    120: **             describing the mathing files.
                    121: **
                    122: */
                    123: PRIVATE HTList * dir_matches ARGS1(char *, path)
                    124: {
                    125:     static char * required[MAX_SUFF+1];
                    126:     static char * actual[MAX_SUFF+1];
                    127:     int m,n;
                    128:     char * dirname = NULL;
                    129:     char * basename = NULL;
                    130:     int baselen;
                    131:     char * multi = NULL;
                    132:     DIR * dp;
2.13      frystyk   133:     STRUCT_DIRENT * dirbuf;
2.1       luotonen  134:     HTList * matches = NULL;
2.16      frystyk   135: #ifdef HT_REENTRANT
                    136:     STRUCT_DIRENT result;                                  /* For readdir_r */
                    137: #endif
2.1       luotonen  138: 
                    139:     if (!path) return NULL;
                    140: 
                    141:     StrAllocCopy(dirname, path);
                    142:     basename = (strrchr(dirname, '/'));
                    143:     if (!basename)
                    144:        goto dir_match_failed;
                    145:     *basename++ = 0;
                    146: 
                    147:     multi = strrchr(basename, MULTI_SUFFIX[0]);
2.2       duns      148:     if (multi && !strcasecomp(multi, MULTI_SUFFIX))
2.1       luotonen  149:        *multi = 0;
                    150:     baselen = strlen(basename);
                    151: 
                    152:     m = HTSplitFilename(basename, required);
                    153: 
                    154:     dp = opendir(dirname);
                    155:     if (!dp) {
2.13      frystyk   156:        if (PROT_TRACE)
                    157:            fprintf(TDEST,"Warning..... Can't open directory %s\n", dirname);
2.1       luotonen  158:        goto dir_match_failed;
                    159:     }
                    160: 
                    161:     matches = HTList_new();
2.16      frystyk   162: #ifdef HT_REENTRANT
                    163:        while ((dirbuf = (STRUCT_DIRENT *) readdir_r(dp, &result))) {
                    164: #else
                    165:        while ((dirbuf = readdir(dp))) {
                    166: #endif /* HT_REENTRANT */
2.1       luotonen  167:        if (!dirbuf->d_ino) continue;   /* Not in use */
2.3       luotonen  168:        if (!strcmp(dirbuf->d_name,".") ||
                    169:            !strcmp(dirbuf->d_name,"..") ||
2.10      frystyk   170:            !strcmp(dirbuf->d_name, HT_DIR_ENABLE_FILE))
2.3       luotonen  171:            continue;
2.7       frystyk   172: 
2.13      frystyk   173:        /* Use of direct->namlen is only valid in BSD'ish system */
                    174:        /* Thanks to chip@chinacat.unicom.com (Chip Rosenthal) */
                    175:        /* if ((int)(dirbuf->d_namlen) >= baselen) { */
                    176:        if ((int) strlen(dirbuf->d_name) >= baselen) {
2.1       luotonen  177:            n = HTSplitFilename(dirbuf->d_name, actual);
                    178:            if (multi_match(required, m, actual, n)) {
                    179:                HTContentDescription * cd;
2.14      frystyk   180:                cd = HTBind_getDescription(dirbuf->d_name);
2.1       luotonen  181:                if (cd) {
                    182:                    if (cd->content_type) {
                    183:                        cd->filename = (char*)malloc(strlen(dirname) + 2 +
                    184:                                                     strlen(dirbuf->d_name));
                    185:                        if (!cd->filename) outofmem(__FILE__, "dir_matches");
                    186:                        sprintf(cd->filename, "%s/%s",
                    187:                                dirname, dirbuf->d_name);
                    188:                        HTList_addObject(matches, (void*)cd);
                    189:                    }
                    190:                    else free(cd);
                    191:                }
                    192:            }
                    193:        }
                    194:     }
                    195:     closedir(dp);
                    196: 
                    197:   dir_match_failed:
                    198:     free(dirname);
                    199:     return matches;
                    200: }
                    201: 
                    202: 
                    203: /*
                    204: **     Get the best match for a given file
                    205: **     -----------------------------------
                    206: ** On entry:
                    207: **     req->conversions  accepted content-types
                    208: **     req->encodings    accepted content-transfer-encodings
                    209: **     req->languages    accepted content-languages
                    210: **     path              absolute pathname of the filename for
                    211: **                       which the match is desired.
                    212: ** On exit:
                    213: **     returns a newly allocated absolute filepath.
                    214: */
                    215: PRIVATE char * HTGetBest ARGS2(HTRequest *,    req,
                    216:                               char *,          path)
                    217: {
                    218:     HTList * matches;
                    219:     HTList * cur;
                    220:     HTContentDescription * cd;
                    221:     HTContentDescription * best = NULL;
                    222:     char * best_path = NULL;
                    223: 
2.13      frystyk   224:     if (!path || !*path) return NULL;
2.1       luotonen  225: 
                    226:     matches = dir_matches(path);
                    227:     if (!matches) {
2.13      frystyk   228:        if (PROT_TRACE)
                    229:            fprintf(TDEST, "No matches.. for \"%s\"\n", path);
                    230:        return NULL;
2.1       luotonen  231:     }
                    232: 
                    233:     /* BEGIN DEBUG */
                    234:     cur = matches;
2.13      frystyk   235:     if (PROT_TRACE)
                    236:        fprintf(TDEST, "Multi....... Possibilities for \"%s\"\n", path);
                    237:     if (PROT_TRACE)
                    238:        fprintf(TDEST, "\nCONTENT-TYPE  LANGUAGE  ENCODING  QUALITY  FILE\n");
2.1       luotonen  239:     while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
2.13      frystyk   240:        if (PROT_TRACE)
                    241:           fprintf(TDEST, "%s\t%s\t%s\t  %.5f  %s\n",
                    242:                   cd->content_type    ?HTAtom_name(cd->content_type)  :"-\t",
                    243:                   cd->content_language?HTAtom_name(cd->content_language):"-",
                    244:                   cd->content_encoding?HTAtom_name(cd->content_encoding):"-",
                    245:                   cd->quality,
                    246:                   cd->filename        ?cd->filename                     :"-");
2.1       luotonen  247:     }
2.13      frystyk   248:     if (PROT_TRACE) fprintf(TDEST, "\n");
2.1       luotonen  249:     /* END DEBUG */
                    250: 
                    251:     /*
                    252:     ** Finally get best that is readable
                    253:     */
                    254:     if (HTRank(matches, req->conversions, req->languages, req->encodings)) {
                    255:        cur = matches;
                    256:        while ((best = (HTContentDescription*)HTList_nextObject(cur))) {
                    257:            if (best && best->filename) {
                    258:                if (access(best->filename, R_OK) != -1) {
                    259:                    StrAllocCopy(best_path, best->filename);
                    260:                    break;
2.13      frystyk   261:                } else if (PROT_TRACE)
                    262:                    fprintf(TDEST, "Bad News.... \"%s\" is not readable\n",
2.1       luotonen  263:                            best->filename);
                    264:            }
                    265:        }
                    266:     } /* Select best */
                    267: 
                    268:     cur = matches;
                    269:     while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
                    270:        if (cd->filename) free(cd->filename);
                    271:        free(cd);
                    272:     }
                    273:     HTList_delete(matches);
                    274: 
                    275:     return best_path;
                    276: }
                    277: 
2.3       luotonen  278: 
                    279: 
                    280: PRIVATE int welcome_value ARGS1(char *, name)
                    281: {
                    282:     HTList * cur = welcome_names;
                    283:     char * welcome;
                    284:     int v = 0;
                    285: 
                    286:     while ((welcome = (char*)HTList_nextObject(cur))) {
                    287:        v++;
                    288:        if (!strcmp(welcome,name)) return v;
                    289:     }
                    290:     return 0;
                    291: }
                    292: 
                    293: 
                    294: 
                    295: PRIVATE char * get_best_welcome ARGS1(char *, path)
                    296: {
                    297:     char * best_welcome = NULL;
                    298:     int best_value = 0;
                    299:     DIR * dp;
2.13      frystyk   300:     STRUCT_DIRENT * dirbuf;
2.3       luotonen  301:     char * last = strrchr(path, '/');
                    302: 
                    303:     if (!welcome_names) {
                    304:        HTAddWelcome("Welcome.html");
                    305:        HTAddWelcome("welcome.html");
2.5       luotonen  306: #if 0
2.3       luotonen  307:        HTAddWelcome("Index.html");
2.5       luotonen  308: #endif
2.3       luotonen  309:        HTAddWelcome("index.html");
                    310:     }
                    311: 
2.5       luotonen  312:     if (last && last!=path) *last = 0;
2.3       luotonen  313:     dp = opendir(path);
2.5       luotonen  314:     if (last && last!=path) *last='/';
2.3       luotonen  315:     if (!dp) {
2.13      frystyk   316:        if (PROT_TRACE)
                    317:            fprintf(TDEST, "Warning..... Can't open directory %s\n",path);
2.3       luotonen  318:        return NULL;
                    319:     }
                    320:     while ((dirbuf = readdir(dp))) {
2.13      frystyk   321:        if (!dirbuf->d_ino ||
2.3       luotonen  322:            !strcmp(dirbuf->d_name,".") ||
                    323:            !strcmp(dirbuf->d_name,"..") ||
2.10      frystyk   324:            !strcmp(dirbuf->d_name, HT_DIR_ENABLE_FILE))
2.3       luotonen  325:            continue;
                    326:        else {
                    327:            int v = welcome_value(dirbuf->d_name);
                    328:            if (v > best_value) {
                    329:                best_value = v;
                    330:                StrAllocCopy(best_welcome, dirbuf->d_name);
                    331:            }
                    332:        }
                    333:     }
                    334:     closedir(dp);
                    335: 
                    336:     if (best_welcome) {
                    337:        char * welcome = (char*)malloc(strlen(path) + strlen(best_welcome)+2);
                    338:        if (!welcome) outofmem(__FILE__, "get_best_welcome");
2.4       luotonen  339:        sprintf(welcome, "%s%s%s", path, last ? "" : "/", best_welcome);
2.3       luotonen  340:        free(best_welcome);
2.13      frystyk   341:        if (PROT_TRACE)
                    342:            fprintf(TDEST,"Welcome..... \"%s\"\n",welcome);
2.3       luotonen  343:        return welcome;
                    344:     }
                    345:     return NULL;
                    346: }
                    347: 
2.13      frystyk   348: #endif /* GOT_READ_DIR */
2.1       luotonen  349: 
                    350: 
                    351: /*
                    352: **     Do multiformat handling
                    353: **     -----------------------
                    354: ** On entry:
                    355: **     req->conversions  accepted content-types
                    356: **     req->encodings    accepted content-transfer-encodings
                    357: **     req->languages    accepted content-languages
                    358: **     path              absolute pathname of the filename for
                    359: **                       which the match is desired.
                    360: **     stat_info         pointer to result space.
                    361: **
                    362: ** On exit:
                    363: **     returns a newly allocated absolute filepath of the best
                    364: **             match, or NULL if no match.
                    365: **     stat_info         will contain inode information as
                    366: **                       returned by stat().
                    367: */
                    368: PUBLIC char * HTMulti ARGS3(HTRequest *,       req,
                    369:                            char *,             path,
                    370:                            struct stat *,      stat_info)
                    371: {
                    372:     char * new_path = NULL;
                    373:     int stat_status = -1;
2.3       luotonen  374:     int len;
2.1       luotonen  375: 
2.3       luotonen  376:     if (!req || !path || !*path || !stat_info)
2.1       luotonen  377:        return NULL;
                    378: 
2.13      frystyk   379: #ifdef GOT_READ_DIR
2.3       luotonen  380:     len = strlen(path);
                    381:     if (path[len-1] == '/') {  /* Find welcome page */
                    382:        new_path = get_best_welcome(path);
                    383:        if (new_path) path = new_path;
2.1       luotonen  384:     }
2.3       luotonen  385:     else{
                    386:        char * multi = strrchr(path, MULTI_SUFFIX[0]);
                    387:        if (multi && !strcasecomp(multi, MULTI_SUFFIX)) {
2.13      frystyk   388:            if (PROT_TRACE)
                    389:                fprintf(TDEST, "Multi....... by %s suffix\n", MULTI_SUFFIX);
2.1       luotonen  390:            if (!(new_path = HTGetBest(req, path))) {
2.13      frystyk   391:                if (PROT_TRACE)
                    392:                    fprintf(TDEST, "Multi....... failed -- giving up\n");
2.1       luotonen  393:                return NULL;
                    394:            }
                    395:            path = new_path;
2.3       luotonen  396:        }
                    397:        else {
2.18    ! frystyk   398:            stat_status = HT_STAT(path, stat_info);
2.3       luotonen  399:            if (stat_status == -1) {
2.13      frystyk   400:                if (PROT_TRACE)
                    401:                    fprintf(TDEST,
                    402:                            "AutoMulti... can't stat \"%s\"(errno %d)\n",
                    403:                            path, errno);
2.3       luotonen  404:                if (!(new_path = HTGetBest(req, path))) {
2.13      frystyk   405:                    if (PROT_TRACE)
                    406:                        fprintf(TDEST, "AutoMulti... failed -- giving up\n");
2.3       luotonen  407:                    return NULL;
                    408:                }
                    409:                path = new_path;
                    410:            }
2.1       luotonen  411:        }
                    412:     }
2.13      frystyk   413: #endif /* GOT_READ_DIR */
2.1       luotonen  414: 
                    415:     if (stat_status == -1)
2.18    ! frystyk   416:        stat_status = HT_STAT(path, stat_info);
2.1       luotonen  417:     if (stat_status == -1) {
2.13      frystyk   418:        if (PROT_TRACE)
                    419:            fprintf(TDEST, "Stat fails.. on \"%s\" -- giving up (errno %d)\n",
                    420:                    path, errno);
2.1       luotonen  421:        return NULL;
                    422:     }
                    423:     else {
                    424:        if (!new_path) {
                    425:            StrAllocCopy(new_path, path);
                    426:            return new_path;
                    427:        }
                    428:        else return path;
                    429:     }
                    430: }
                    431: 
                    432: 

Webmaster