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

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

Webmaster