Annotation of libwww/Library/src/HTFile.c, revision 1.127

1.72      frystyk     1: /*                                                                    HTFile.c
                      2: **     FILE ACCESS
                      3: **
1.79      frystyk     4: **     (c) COPYRIGHT MIT 1995.
1.72      frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
1.127   ! frystyk     6: **     @(#) $Id: HTFile.c,v 1.126 1996/07/02 22:54:26 frystyk Exp $
1.1       timbl       7: **
                      8: **     This is unix-specific code in general, with some VMS bits.
1.8       timbl       9: **     These are routines for file access used by browsers.
1.1       timbl      10: **
                     11: ** History:
                     12: **        Feb 91       Written Tim Berners-Lee CERN/CN
                     13: **        Apr 91       vms-vms access included using DECnet syntax
                     14: **     26 Jun 92 (JFG) When running over DECnet, suppressed FTP.
                     15: **                     Fixed access bug for relative names on VMS.
1.28      duns       16: **        Sep 93 (MD)  Access to VMS files allows sharing.
                     17: **     15 Nov 93 (MD)  Moved HTVMSname to HTVMSUTILS.C
1.52      duns       18: **     22 Feb 94 (MD)  Excluded two routines if we are not READING directories
1.61      frystyk    19: **     18 May 94 (HF)  Directory stuff removed and stream handling updated,
                     20: **                     error messages introduced etc.
1.120     frystyk    21: **               HFN   Separated transport
1.1       timbl      22: **
                     23: ** Bugs:
1.2       timbl      24: **     FTP: Cannot access VMS files from a unix machine.
                     25: **      How can we know that the
1.1       timbl      26: **     target machine runs VMS?
                     27: */
                     28: 
1.67      frystyk    29: /* Library Includes */
1.112     frystyk    30: #include "sysdep.h"
1.120     frystyk    31: #include "WWWUtil.h"
                     32: #include "WWWCore.h"
1.124     frystyk    33: #include "WWWDir.h"
                     34: #include "WWWTrans.h"
1.126     frystyk    35: #include "HTNetMan.h"
1.120     frystyk    36: #include "HTReqMan.h"
1.124     frystyk    37: #include "HTMulti.h"
1.67      frystyk    38: #include "HTFile.h"            /* Implemented here */
                     39: 
1.91      frystyk    40: /* Final states have negative value */
1.80      frystyk    41: typedef enum _FileState {
1.95      frystyk    42:     FS_RETRY           = -4,
                     43:     FS_ERROR           = -3,
                     44:     FS_NO_DATA         = -2,
                     45:     FS_GOT_DATA                = -1,
                     46:     FS_BEGIN           = 0,
                     47:     FS_DO_CN,
                     48:     FS_NEED_OPEN_FILE,
                     49:     FS_NEED_BODY,
                     50:     FS_PARSE_DIR,
                     51:     FS_TRY_FTP
1.80      frystyk    52: } FileState;
                     53: 
1.91      frystyk    54: /* This is the context structure for the this module */
1.77      frystyk    55: typedef struct _file_info {
1.80      frystyk    56:     FileState          state;            /* Current state of the connection */
1.95      frystyk    57:     char *             local;          /* Local representation of file name */
1.125     frystyk    58:     struct stat                stat_info;            /* Contains actual file chosen */
1.77      frystyk    59: } file_info;
1.2       timbl      60: 
1.80      frystyk    61: struct _HTStream {
1.112     frystyk    62:     const HTStreamClass *      isa;
1.80      frystyk    63: };
                     64: 
1.120     frystyk    65: struct _HTInputStream {
                     66:     const HTInputStreamClass * isa;
                     67: };
                     68: 
1.123     frystyk    69: #if 0
1.95      frystyk    70: PRIVATE BOOL           HTTakeBackup = YES;
1.123     frystyk    71: #endif
1.1       timbl      72: 
1.95      frystyk    73: PRIVATE HTDirReadme    dir_readme = HT_DIR_README_TOP;
                     74: PRIVATE HTDirAccess    dir_access = HT_DIR_OK;
                     75: PRIVATE HTDirShow      dir_show = HT_DS_SIZE+HT_DS_DATE+HT_DS_DES+HT_DS_ICON;
                     76: PRIVATE HTDirKey       dir_key = HT_DK_CINS;
1.2       timbl      77: 
1.61      frystyk    78: /* ------------------------------------------------------------------------- */
1.11      timbl      79: 
1.95      frystyk    80: /*     Directory Access
                     81: **     ----------------
                     82: */
                     83: PUBLIC BOOL HTFile_setDirAccess (HTDirAccess mode)
                     84: {
                     85:     dir_access = mode;
                     86:     return YES;
                     87: }
                     88: 
                     89: PUBLIC HTDirAccess HTFile_dirAccess (void)
                     90: {
                     91:     return dir_access;
                     92: }
                     93: 
                     94: /*     Directory Readme
                     95: **     ----------------
                     96: */
                     97: PUBLIC BOOL HTFile_setDirReadme (HTDirReadme mode)
                     98: {
                     99:     dir_readme = mode;
                    100:     return YES;
                    101: }
                    102: 
                    103: PUBLIC HTDirReadme HTFile_dirReadme (void)
                    104: {
                    105:     return dir_readme;
                    106: }
                    107: 
                    108: /*     HTFile_readDir
                    109: **     --------------
                    110: **     Reads the directory "path"
                    111: **     Returns:
                    112: **             HT_ERROR        Error
1.107     frystyk   113: **             HT_FORBIDDEN    Directory reading not allowed
1.95      frystyk   114: **             HT_LOADED       Successfully read the directory
1.1       timbl     115: */
1.95      frystyk   116: PRIVATE int HTFile_readDir (HTRequest * request, file_info *file)
1.1       timbl     117: {
1.112     frystyk   118: #ifdef HAVE_READDIR
                    119:     DIR * dp;
1.95      frystyk   120:     struct stat file_info;
1.124     frystyk   121:     HTParentAnchor * anchor = HTRequest_anchor(request);
                    122:     char *url = HTAnchor_physical(anchor);
1.95      frystyk   123:     char fullname[HT_MAX_PATH+1];
                    124:     char *name;
1.111     eric      125:     if (PROT_TRACE) HTTrace("Reading..... directory\n");
1.95      frystyk   126:     if (dir_access == HT_DIR_FORBID) {
1.100     frystyk   127:        HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.95      frystyk   128:                   NULL, 0, "HTFile_readDir");
1.107     frystyk   129:        return HT_FORBIDDEN;
1.95      frystyk   130:     }
                    131:     
                    132:     /* Initialize path name for stat() */
                    133:     if (*(name = (url+strlen(url)-1)) != '/') {
                    134:        char *newurl = NULL;
                    135:        StrAllocCopy(newurl, url);
                    136:        StrAllocCat(newurl, "/");
1.110     frystyk   137:        HT_FREE(file->local);
1.123     frystyk   138:        file->local = HTWWWToLocal(newurl, "", HTRequest_userProfile(request));
1.110     frystyk   139:        HT_FREE(newurl);
1.95      frystyk   140:     }
                    141:     strcpy(fullname, file->local);
                    142:     name = fullname+strlen(fullname);           /* Point to end of fullname */
                    143: 
                    144:     /* Check if access is enabled */
                    145:     if (dir_access == HT_DIR_SELECTIVE) {
                    146:        strcpy(name, DEFAULT_DIR_FILE);
                    147:        if (HT_STAT(fullname, &file_info)) {
1.80      frystyk   148:            if (PROT_TRACE)
1.111     eric      149:                HTTrace(
1.95      frystyk   150:                        "Read dir.... `%s\' not found\n", DEFAULT_DIR_FILE);
1.100     frystyk   151:            HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.95      frystyk   152:                       NULL, 0, "HTFile_readDir");
1.107     frystyk   153:            return HT_FORBIDDEN;
1.1       timbl     154:        }
                    155:     }
                    156: 
1.95      frystyk   157:     if ((dp = opendir(file->local))) {
1.112     frystyk   158:        struct dirent * dirbuf;
1.95      frystyk   159:        HTDir *dir = HTDir_new(request, dir_show, dir_key);
                    160:        char datestr[20];
                    161:        char sizestr[10];
                    162:        HTFileMode mode;
                    163: #ifdef HT_REENTRANT
1.112     frystyk   164:        struct dirent * result;                             /* For readdir_r */
                    165:        while ((dirbuf = (dirent *) readdir_r(dp, &result)))
1.95      frystyk   166: #else
                    167:        while ((dirbuf = readdir(dp)))
                    168: #endif /* HT_REENTRANT */
                    169:        {
                    170:            /* Current and parent directories are never shown in list */
1.112     frystyk   171: #ifdef HAVE_DIRENT_INO
1.95      frystyk   172:            if (!dirbuf->d_ino ||
                    173:                !strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
1.112     frystyk   174: #else
                    175:            if (!strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
                    176: #endif
1.95      frystyk   177:                continue;
                    178: 
                    179:            /* Make a lstat on the file */
                    180:            strcpy(name, dirbuf->d_name);
                    181:            if (HT_LSTAT(fullname, &file_info)) {
                    182:                if (PROT_TRACE)
1.111     eric      183:                    HTTrace("Read dir.... lstat failed: %s\n",fullname);
1.95      frystyk   184:                continue;
                    185:            }
1.1       timbl     186: 
1.95      frystyk   187:            /* Convert stat info to fit our setup */
1.103     frystyk   188:            if (((mode_t) file_info.st_mode & S_IFMT) == S_IFDIR) {
1.95      frystyk   189: #ifdef VMS
                    190:                char *dot = strstr(name, ".DIR");      /* strip .DIR part... */
                    191:                if (dot) *dot = '\0';
                    192: #endif /* VMS */
                    193:                mode = HT_IS_DIR;
                    194:                if (dir_show & HT_DS_SIZE) strcpy(sizestr, "-");
                    195:            } else {
                    196:                mode = HT_IS_FILE;
                    197:                if (dir_show & HT_DS_SIZE)
                    198:                    HTNumToStr(file_info.st_size, sizestr, 10);
                    199:            }
                    200:            if (dir_show & HT_DS_DATE)
                    201:                HTDateDirStr(&file_info.st_mtime, datestr, 20);
1.1       timbl     202: 
1.95      frystyk   203:            /* Add to the list */
                    204:            if (HTDir_addElement(dir, name, datestr, sizestr, mode) != YES)
                    205:                break;
                    206:        }
                    207:        closedir(dp);
                    208:        HTDir_free(dir);
1.127   ! frystyk   209:        return HT_LOADED;
        !           210:     } else {
1.100     frystyk   211:        HTRequest_addSystemError(request,  ERR_FATAL, errno, NO, "opendir");
1.127   ! frystyk   212:        return HT_ERROR;
        !           213:     }
1.112     frystyk   214: #else
1.114     eric      215:     return HT_ERROR;   /* needed for WWW_MSWINDOWS */
1.112     frystyk   216: #endif /* HAVE_READDIR */
1.1       timbl     217: }
                    218: 
                    219: /*     Determine write access to a file
1.2       timbl     220: **     --------------------------------
1.80      frystyk   221: **     If stat_info is NULL then the function calls stat() on it's own,
                    222: **     otherwise it uses the information found in stat_info
1.2       timbl     223: ** On exit,
                    224: **     return value    YES if file can be accessed and can be written to.
                    225: **
                    226: ** Bugs:
                    227: **     1.      No code for non-unix systems.
                    228: **     2.      Isn't there a quicker way?
1.1       timbl     229: */
1.112     frystyk   230: PRIVATE BOOL HTEditable (const char * filename, struct stat * stat_info)
1.80      frystyk   231: {
1.112     frystyk   232: #ifdef GETGROUPS_T
1.80      frystyk   233:     int i;
                    234:     uid_t myUid;
                    235:     int        ngroups;                        /* The number of groups  */
1.1       timbl     236:     struct stat        fileStatus;
1.80      frystyk   237:     struct stat *fileptr = stat_info ? stat_info : &fileStatus;
1.112     frystyk   238:     GETGROUPS_T groups[NGROUPS];
1.80      frystyk   239:     if (!stat_info) {
1.90      frystyk   240:        if (HT_STAT(filename, &fileStatus))
1.80      frystyk   241:            return NO;                            /* Can't even access file! */
                    242:     }
1.1       timbl     243:     ngroups = getgroups(NGROUPS, groups);      /* Groups to which I belong  */
                    244:     myUid = geteuid();                         /* Get my user identifier */
                    245: 
1.95      frystyk   246:     if (PROT_TRACE) {
1.1       timbl     247:         int i;
1.111     eric      248:        HTTrace(
1.19      timbl     249:            "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (",
1.80      frystyk   250:            (unsigned int) fileptr->st_mode, (int) fileptr->st_uid,
                    251:            (int) fileptr->st_gid, (int) myUid, ngroups);
1.111     eric      252:        for (i=0; i<ngroups; i++) HTTrace(" %d", (int) groups[i]);
                    253:        HTTrace(")\n");
1.1       timbl     254:     }
                    255:     
1.80      frystyk   256:     if (fileptr->st_mode & 0002)               /* I can write anyway? */
1.1       timbl     257:        return YES;
                    258:        
1.80      frystyk   259:     if ((fileptr->st_mode & 0200)              /* I can write my own file? */
                    260:      && (fileptr->st_uid == myUid))
1.1       timbl     261:        return YES;
                    262: 
1.80      frystyk   263:     if (fileptr->st_mode & 0020)               /* Group I am in can write? */
1.1       timbl     264:     {
                    265:        for (i=0; i<ngroups; i++) {
1.80      frystyk   266:             if (groups[i] == fileptr->st_gid)
1.1       timbl     267:                return YES;
                    268:        }
                    269:     }
1.111     eric      270:     if (PROT_TRACE) HTTrace("\tFile is not editable.\n");
1.1       timbl     271:     return NO;                                 /* If no excuse, can't do */
1.80      frystyk   272: #else
                    273:     /*
                    274:     ** We don't know and can't find out. Can we be sure that when opening
                    275:     ** a file in mode "a" that the file is not modified?
                    276:     */
                    277:     return NO;
1.112     frystyk   278: #endif /* GETGROUPS_T */
1.1       timbl     279: }
1.80      frystyk   280: 
1.91      frystyk   281: /*     FileCleanup
                    282: **     -----------
1.80      frystyk   283: **      This function closes the connection and frees memory.
1.91      frystyk   284: **      Returns YES on OK, else NO
1.80      frystyk   285: */
1.91      frystyk   286: PRIVATE int FileCleanup (HTRequest *req, int status)
1.80      frystyk   287: {
1.126     frystyk   288:     HTNet * net = HTRequest_net(req);
                    289:     file_info * file = (file_info *) HTNet_context(net);
                    290:     HTStream * input = HTRequest_inputStream(req);
1.106     frystyk   291: 
                    292:     /* Free stream with data TO Local file system */
1.107     frystyk   293:     if (HTRequest_isDestination(req))
                    294:        HTRequest_removeDestination(req);
1.126     frystyk   295:     else  if (input) {
1.106     frystyk   296:        if (status == HT_INTERRUPTED)
1.126     frystyk   297:            (*input->isa->abort)(input, NULL);
1.106     frystyk   298:        else
1.126     frystyk   299:            (*input->isa->_free)(input);
                    300:        HTRequest_setInputStream(req, NULL);
1.106     frystyk   301:     }
                    302: 
1.91      frystyk   303:     if (file) {
1.110     frystyk   304:        HT_FREE(file->local);
                    305:        HT_FREE(file);
1.80      frystyk   306:     }
1.126     frystyk   307:     HTNet_delete(net, HTRequest_internal(req) ? HT_IGNORE : status);
1.91      frystyk   308:     return YES;
1.80      frystyk   309: }
                    310: 
                    311: 
1.1       timbl     312: /*     Load a document
                    313: **     ---------------
                    314: **
                    315: ** On entry,
1.80      frystyk   316: **     request         This is the request structure
1.1       timbl     317: ** On exit,
1.91      frystyk   318: **     returns         HT_ERROR        Error has occured in call back
                    319: **                     HT_OK           Call back was OK
1.1       timbl     320: */
1.91      frystyk   321: PUBLIC int HTLoadFile (SOCKET soc, HTRequest * request, SockOps ops)
1.1       timbl     322: {
1.80      frystyk   323:     int status = HT_ERROR;
1.124     frystyk   324:     HTNet * net = HTRequest_net(request);
                    325:     HTParentAnchor * anchor = HTRequest_anchor(request);
1.80      frystyk   326:     file_info *file;                         /* Specific access information */
1.45      luotonen  327: 
1.91      frystyk   328:     /*
                    329:     ** Initiate a new file structure and bind to request structure
                    330:     ** This is actually state FILE_BEGIN, but it can't be in the state
                    331:     ** machine as we need the structure first.
                    332:     */
                    333:     if (ops == FD_NONE) {
1.111     eric      334:        if (PROT_TRACE) HTTrace("HTLoadFile.. Looking for `%s\'\n",
1.99      frystyk   335:                                HTAnchor_physical(anchor));
1.110     frystyk   336:        if ((file = (file_info *) HT_CALLOC(1, sizeof(file_info))) == NULL)
                    337:            HT_OUTOFMEM("HTLoadFILE");
1.95      frystyk   338:        file->state = FS_BEGIN;
1.91      frystyk   339:        net->context = file;
                    340:     } if (ops == FD_CLOSE) {                                 /* Interrupted */
1.107     frystyk   341:        HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED,
                    342:                           NULL, 0, "HTLoadHTTP");
                    343:        FileCleanup(request, HT_INTERRUPTED);
1.91      frystyk   344:        return HT_OK;
                    345:     } else
                    346:        file = (file_info *) net->context;              /* Get existing copy */
1.36      luotonen  347: 
1.80      frystyk   348:     /* Now jump into the machine. We know the state from the previous run */
                    349:     while (1) {
                    350:        switch (file->state) {
1.95      frystyk   351:          case FS_BEGIN:
1.102     frystyk   352:            if (HTLib_secure()) {
1.80      frystyk   353:                if (PROT_TRACE)
1.111     eric      354:                    HTTrace("LoadFile.... No access to local file system\n");
1.95      frystyk   355:                file->state = FS_TRY_FTP;
1.80      frystyk   356:                break;
                    357:            }
1.123     frystyk   358:            file->local = HTWWWToLocal(HTAnchor_physical(anchor), "",
                    359:                                       HTRequest_userProfile(request));
1.95      frystyk   360:            if (!file->local) {
                    361:                file->state = FS_TRY_FTP;
1.80      frystyk   362:                break;
1.2       timbl     363:            }
1.125     frystyk   364:            file->state = FS_DO_CN;
1.86      frystyk   365:            break;
                    366: 
1.95      frystyk   367:          case FS_DO_CN:
1.80      frystyk   368:            /*
                    369:            ** If we have to do content negotiation then find the object that
                    370:            ** fits best into either what the client has indicated in the
1.86      frystyk   371:            ** accept headers or what the client has registered on its own.
1.80      frystyk   372:            ** The object chosen can in fact be a directory! However, content
                    373:            ** negotiation only makes sense it we can read the directory!
                    374:            ** We stat the file in order to find the size and to see it if
                    375:            ** exists.
                    376:            */
1.125     frystyk   377:            if ((HTRequest_negotiation(request) &&
                    378:                 HTMethod_isSafe(HTRequest_method(request)) &&
                    379:                 !HTAnchor_cacheHit(anchor))) {
                    380:                char * conneg = HTMulti(request, file->local,&file->stat_info);
                    381:                if (conneg) {
                    382:                    HT_FREE(file->local);
                    383:                    file->local = conneg;
                    384:                    HTAnchor_setPhysical(anchor, conneg);
                    385:                    if (PROT_TRACE)
                    386:                        HTTrace("Load File... Found `%s\'\n", conneg);
1.80      frystyk   387:                } else {
1.125     frystyk   388:                    if (PROT_TRACE)
                    389:                        HTTrace("Load File... Not found - even tried content negotiation\n");
1.126     frystyk   390:                    HTRequest_addError(request, ERR_INFO, NO, HTERR_NOT_FOUND,
                    391:                                       NULL, 0, "HTLoadFile");
1.125     frystyk   392:                    file->state = FS_ERROR;
                    393:                    break;
1.80      frystyk   394:                }
1.125     frystyk   395:            } else {
                    396:                if (HT_STAT(file->local, &file->stat_info) == -1) {
                    397:                    if (PROT_TRACE)
                    398:                        HTTrace("Load.File... Not found `%s\'\n", file->local);
                    399:                    HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
                    400:                                       NULL, 0, "HTLoadFile");
                    401:                    file->state = FS_ERROR;
                    402:                    break;
1.80      frystyk   403:                }
1.125     frystyk   404:            }
                    405: 
                    406:            /*
                    407:            ** Check to see if the 'localname' is in fact a directory
                    408:            */
                    409:            if (((file->stat_info.st_mode) & S_IFMT) == S_IFDIR) {
                    410:                file->state = FS_PARSE_DIR;
                    411:                break;
                    412:            }
                    413: 
                    414:            /*
                    415:            ** If empty file then only serve it if it is editable
                    416:            */
                    417:            {
                    418:                BOOL editable = HTEditable(file->local, &file->stat_info);
                    419:                HTBind_getBindings(anchor);
                    420:                if (editable) HTAnchor_appendMethods(anchor, METHOD_PUT);
                    421:                if (file->stat_info.st_size)
                    422:                    HTAnchor_setLength(anchor, file->stat_info.st_size);
                    423: 
                    424:                /* Done with relevant metainformation in anchor */
                    425:                HTAnchor_setHeaderParsed(anchor);
                    426: 
                    427:                if (!editable && !file->stat_info.st_size) {
                    428:                    HTRequest_addError(request, ERR_FATAL,NO,HTERR_NO_CONTENT,
                    429:                                       NULL, 0, "HTLoadFile");
                    430:                    file->state = FS_NO_DATA;
                    431:                } else
                    432:                    file->state = FS_NEED_OPEN_FILE;
1.2       timbl     433:            }
1.80      frystyk   434:            break;
1.61      frystyk   435: 
1.95      frystyk   436:          case FS_NEED_OPEN_FILE:
1.120     frystyk   437:            status = HTFileOpen(net, file->local, HT_FT_RDONLY);
                    438:            if (status == HT_OK) {
                    439:                /* 
                    440:                ** Create the stream pipe FROM the channel to the application.
                    441:                ** The target for the input stream pipe is set up using the
                    442:                ** stream stack. If we are reading from the cache then use the
                    443:                ** MIME parser as well.
                    444:                */
                    445:                if (HTAnchor_cacheHit(anchor))
                    446:                    HTAnchor_setFormat(anchor, WWW_MIME);
1.124     frystyk   447:                HTNet_getInput(net,
                    448:                               HTStreamStack(HTAnchor_format(anchor),
                    449:                                             HTRequest_outputFormat(request),
                    450:                                             HTRequest_outputStream(request),
                    451:                                             request, YES), NULL, 0);
1.126     frystyk   452:                HTRequest_setOutputConnected(request, YES);
                    453: 
1.120     frystyk   454:                /*
                    455:                ** Create the stream pipe TO the channel from the application
                    456:                ** and hook it up to the request object
                    457:                */
                    458:                {
                    459:                    HTOutputStream * output = HTNet_getOutput(net, NULL, 0);
                    460:                    HTRequest_setInputStream(request, (HTStream *) output);
                    461:                }
1.80      frystyk   462: 
1.120     frystyk   463:                /*
                    464:                ** Set up concurrent read/write if this request isn't the
                    465:                ** source for a PUT or POST. As source we don't start reading
                    466:                ** before all destinations are ready. If destination then
                    467:                ** register the input stream and get ready for read
                    468:                */
                    469:                if (HTRequest_isDestination(request)) {
1.122     eric      470:                    HTEvent_register(net->sockfd, request, (SockOps) FD_READ,
1.120     frystyk   471:                                     HTLoadFile, net->priority);
                    472:                    HTRequest_linkDestination(request);
1.82      frystyk   473:                }
1.120     frystyk   474:                if (HTRequest_isSource(request) &&
                    475:                    !HTRequest_destinationsReady(request))
                    476:                    return HT_OK;
1.126     frystyk   477:                HTRequest_addError(request, ERR_INFO, NO, HTERR_OK,
                    478:                                   NULL, 0, "HTLoadFile");
1.120     frystyk   479:                file->state = FS_NEED_BODY;
1.106     frystyk   480: 
1.116     frystyk   481: #ifndef NO_UNIX_IO
1.120     frystyk   482:                /* If we are _not_ using preemptive mode and we are Unix fd's
                    483:                ** then return here to get the same effect as when we are
                    484:                ** connecting to a socket. That way, HTFile acts just like any
                    485:                ** other protocol module even though we are in fact doing
                    486:                ** blocking connect
                    487:                */
                    488:                if (!net->preemptive) {
                    489:                    if (PROT_TRACE) HTTrace("HTLoadFile.. returning\n");
1.122     eric      490:                    HTEvent_register(net->sockfd, request, (SockOps) FD_READ,
1.120     frystyk   491:                                     net->cbf, net->priority);
                    492:                    return HT_WOULD_BLOCK;
                    493:                }
1.116     frystyk   494: #endif
1.120     frystyk   495:            } else if (status == HT_WOULD_BLOCK || status == HT_PERSISTENT)
                    496:                return HT_OK;
1.126     frystyk   497:            else {
                    498:                HTRequest_addError(request, ERR_INFO, NO, HTERR_INTERNAL,
                    499:                                   NULL, 0, "HTLoadFile");
1.120     frystyk   500:                file->state = FS_ERROR;                /* Error or interrupt */
1.126     frystyk   501:            }
1.107     frystyk   502:            break;
1.82      frystyk   503: 
1.95      frystyk   504:          case FS_NEED_BODY:
1.120     frystyk   505:            status = (*net->input->isa->read)(net->input);
1.80      frystyk   506:            if (status == HT_WOULD_BLOCK)
1.91      frystyk   507:                return HT_OK;
1.108     frystyk   508:            else if (status == HT_LOADED || status == HT_CLOSED) {
1.95      frystyk   509:                file->state = FS_GOT_DATA;
1.126     frystyk   510:            } else {
                    511:                HTRequest_addError(request, ERR_INFO, NO, HTERR_FORBIDDEN,
                    512:                                   NULL, 0, "HTLoadFile");
1.95      frystyk   513:                file->state = FS_ERROR;
1.126     frystyk   514:            }
1.80      frystyk   515:            break;
1.1       timbl     516: 
1.95      frystyk   517:          case FS_PARSE_DIR:
                    518:            status = HTFile_readDir(request, file);
                    519:            if (status == HT_LOADED)
                    520:                file->state = FS_GOT_DATA;
1.127   ! frystyk   521:            else
1.95      frystyk   522:                file->state = FS_ERROR;
1.80      frystyk   523:            break;
                    524: 
1.95      frystyk   525:          case FS_TRY_FTP:
1.80      frystyk   526:            {
1.99      frystyk   527:                char *url = HTAnchor_physical(anchor);
1.80      frystyk   528:                HTAnchor *anchor;
                    529:                char *newname = NULL;
                    530:                StrAllocCopy(newname, "ftp:");
                    531:                if (!strncmp(url, "file:", 5))
                    532:                    StrAllocCat(newname, url+5);
                    533:                else
                    534:                    StrAllocCat(newname, url);
                    535:                anchor = HTAnchor_findAddress(newname);
1.109     frystyk   536:                HTRequest_setAnchor(request, anchor);
1.110     frystyk   537:                HT_FREE(newname);
1.91      frystyk   538:                FileCleanup(request, HT_IGNORE);
1.97      frystyk   539:                return HTLoad(request, YES);
1.80      frystyk   540:            }
                    541:            break;
1.1       timbl     542: 
1.95      frystyk   543:          case FS_GOT_DATA:
1.83      frystyk   544:            if (HTRequest_isPostWeb(request)) {
1.87      frystyk   545:                if (HTRequest_isDestination(request)) {
1.124     frystyk   546:                    HTRequest * source = HTRequest_source(request);
1.87      frystyk   547:                    HTLink *link =
1.126     frystyk   548:                        HTLink_find((HTAnchor *)HTRequest_anchor(source),
1.99      frystyk   549:                                          (HTAnchor *) anchor);
1.104     frystyk   550:                    HTLink_setResult(link, HT_LINK_OK);
1.87      frystyk   551:                }
1.107     frystyk   552:            }
                    553:            FileCleanup(request, HT_LOADED);
1.91      frystyk   554:            return HT_OK;
1.80      frystyk   555:            break;
                    556: 
1.95      frystyk   557:          case FS_NO_DATA:
1.83      frystyk   558:            if (HTRequest_isPostWeb(request)) {
1.87      frystyk   559:                if (HTRequest_isDestination(request)) {
1.124     frystyk   560:                    HTRequest * source = HTRequest_source(request);
1.87      frystyk   561:                    HTLink *link =
1.126     frystyk   562:                        HTLink_find((HTAnchor *)HTRequest_anchor(source),
1.99      frystyk   563:                                          (HTAnchor *) anchor);
1.104     frystyk   564:                    HTLink_setResult(link, HT_LINK_OK);
1.87      frystyk   565:                }
1.107     frystyk   566:            }
                    567:            FileCleanup(request, HT_NO_DATA);
1.91      frystyk   568:            return HT_OK;
1.80      frystyk   569:            break;
                    570: 
1.95      frystyk   571:          case FS_RETRY:
1.83      frystyk   572:            if (HTRequest_isPostWeb(request)) {
1.87      frystyk   573:                if (HTRequest_isDestination(request)) {
1.124     frystyk   574:                    HTRequest * source = HTRequest_source(request);
1.87      frystyk   575:                    HTLink *link =
1.126     frystyk   576:                        HTLink_find((HTAnchor *)HTRequest_anchor(source),
1.99      frystyk   577:                                          (HTAnchor *) anchor);
1.104     frystyk   578:                    HTLink_setResult(link, HT_LINK_ERROR);
1.87      frystyk   579:                }
1.107     frystyk   580:                HTRequest_killPostWeb(request);
                    581:            }
                    582:            FileCleanup(request, HT_RETRY);
1.91      frystyk   583:            return HT_OK;
1.80      frystyk   584:            break;
                    585: 
1.95      frystyk   586:          case FS_ERROR:
1.83      frystyk   587:            if (HTRequest_isPostWeb(request)) {
1.87      frystyk   588:                if (HTRequest_isDestination(request)) {
1.124     frystyk   589:                    HTRequest * source = HTRequest_source(request);
1.87      frystyk   590:                    HTLink *link =
1.126     frystyk   591:                        HTLink_find((HTAnchor *)HTRequest_anchor(source),
1.99      frystyk   592:                                          (HTAnchor *) anchor);
1.104     frystyk   593:                    HTLink_setResult(link, HT_LINK_ERROR);
1.87      frystyk   594:                }
1.107     frystyk   595:                HTRequest_killPostWeb(request);
                    596:            }
                    597:            FileCleanup(request, HT_ERROR);
1.91      frystyk   598:            return HT_OK;
1.80      frystyk   599:            break;
                    600:        }
                    601:     } /* End of while(1) */
1.1       timbl     602: }

Webmaster