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

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.123   ! frystyk     6: **     @(#) $Id: HTFile.c,v 1.122 1996/05/15 22:34:14 eric 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.54      luotonen   33: #include "HTMulti.h"
1.95      frystyk    34: #include "HTIcons.h"
                     35: #include "HTDir.h"
1.120     frystyk    36: #include "HTLocal.h"
                     37: #include "HTReqMan.h"
1.92      frystyk    38: #include "HTNetMan.h"
1.120     frystyk    39: 
1.67      frystyk    40: #include "HTFile.h"            /* Implemented here */
                     41: 
1.91      frystyk    42: /* Final states have negative value */
1.80      frystyk    43: typedef enum _FileState {
1.95      frystyk    44:     FS_RETRY           = -4,
                     45:     FS_ERROR           = -3,
                     46:     FS_NO_DATA         = -2,
                     47:     FS_GOT_DATA                = -1,
                     48:     FS_BEGIN           = 0,
                     49:     FS_DO_CN,
                     50:     FS_NEED_OPEN_FILE,
                     51:     FS_NEED_BODY,
                     52:     FS_PARSE_DIR,
                     53:     FS_TRY_FTP
1.80      frystyk    54: } FileState;
                     55: 
1.91      frystyk    56: /* This is the context structure for the this module */
1.77      frystyk    57: typedef struct _file_info {
1.80      frystyk    58:     FileState          state;            /* Current state of the connection */
1.95      frystyk    59:     char *             local;          /* Local representation of file name */
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;
                    122:     char *url = HTAnchor_physical(request->anchor);
                    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.1       timbl     209:     } else
1.100     frystyk   210:        HTRequest_addSystemError(request,  ERR_FATAL, errno, NO, "opendir");
1.95      frystyk   211:     return HT_LOADED;
1.112     frystyk   212: #else
1.114     eric      213:     return HT_ERROR;   /* needed for WWW_MSWINDOWS */
1.112     frystyk   214: #endif /* HAVE_READDIR */
1.1       timbl     215: }
                    216: 
                    217: /*     Determine write access to a file
1.2       timbl     218: **     --------------------------------
1.80      frystyk   219: **     If stat_info is NULL then the function calls stat() on it's own,
                    220: **     otherwise it uses the information found in stat_info
1.2       timbl     221: ** On exit,
                    222: **     return value    YES if file can be accessed and can be written to.
                    223: **
                    224: ** Bugs:
                    225: **     1.      No code for non-unix systems.
                    226: **     2.      Isn't there a quicker way?
1.1       timbl     227: */
1.112     frystyk   228: PRIVATE BOOL HTEditable (const char * filename, struct stat * stat_info)
1.80      frystyk   229: {
1.112     frystyk   230: #ifdef GETGROUPS_T
1.80      frystyk   231:     int i;
                    232:     uid_t myUid;
                    233:     int        ngroups;                        /* The number of groups  */
1.1       timbl     234:     struct stat        fileStatus;
1.80      frystyk   235:     struct stat *fileptr = stat_info ? stat_info : &fileStatus;
1.112     frystyk   236:     GETGROUPS_T groups[NGROUPS];
1.80      frystyk   237:     if (!stat_info) {
1.90      frystyk   238:        if (HT_STAT(filename, &fileStatus))
1.80      frystyk   239:            return NO;                            /* Can't even access file! */
                    240:     }
1.1       timbl     241:     ngroups = getgroups(NGROUPS, groups);      /* Groups to which I belong  */
                    242:     myUid = geteuid();                         /* Get my user identifier */
                    243: 
1.95      frystyk   244:     if (PROT_TRACE) {
1.1       timbl     245:         int i;
1.111     eric      246:        HTTrace(
1.19      timbl     247:            "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (",
1.80      frystyk   248:            (unsigned int) fileptr->st_mode, (int) fileptr->st_uid,
                    249:            (int) fileptr->st_gid, (int) myUid, ngroups);
1.111     eric      250:        for (i=0; i<ngroups; i++) HTTrace(" %d", (int) groups[i]);
                    251:        HTTrace(")\n");
1.1       timbl     252:     }
                    253:     
1.80      frystyk   254:     if (fileptr->st_mode & 0002)               /* I can write anyway? */
1.1       timbl     255:        return YES;
                    256:        
1.80      frystyk   257:     if ((fileptr->st_mode & 0200)              /* I can write my own file? */
                    258:      && (fileptr->st_uid == myUid))
1.1       timbl     259:        return YES;
                    260: 
1.80      frystyk   261:     if (fileptr->st_mode & 0020)               /* Group I am in can write? */
1.1       timbl     262:     {
                    263:        for (i=0; i<ngroups; i++) {
1.80      frystyk   264:             if (groups[i] == fileptr->st_gid)
1.1       timbl     265:                return YES;
                    266:        }
                    267:     }
1.111     eric      268:     if (PROT_TRACE) HTTrace("\tFile is not editable.\n");
1.1       timbl     269:     return NO;                                 /* If no excuse, can't do */
1.80      frystyk   270: #else
                    271:     /*
                    272:     ** We don't know and can't find out. Can we be sure that when opening
                    273:     ** a file in mode "a" that the file is not modified?
                    274:     */
                    275:     return NO;
1.112     frystyk   276: #endif /* GETGROUPS_T */
1.1       timbl     277: }
1.80      frystyk   278: 
1.120     frystyk   279: #if 0
1.2       timbl     280: /*     Make a save stream
                    281: **     ------------------
                    282: **
                    283: **     The stream must be used for writing back the file.
                    284: **     @@@ no backup done
                    285: */
1.121     eric      286: PRIVATE HTStream * HTFileSaveStream (HTRequest * request)
1.2       timbl     287: {
                    288: 
1.112     frystyk   289:     const char * addr = HTAnchor_address((HTAnchor*)request->anchor);
1.123   ! frystyk   290:     char * filename = HTWWWToLocal(addr, "", HTRequest_userProfile(request));
1.33      timbl     291:     FILE* fp;
                    292: 
                    293: /*     @ Introduce CVS handling here one day
                    294: */
                    295: /*     Take a backup before we do anything silly   931205
                    296: */        
                    297:     if (HTTakeBackup) {
1.69      frystyk   298:        char * p;
1.110     frystyk   299:        char * backup_filename;
                    300:        if ((backup_filename = (char  *) HT_MALLOC(strlen(filename)+2)) == NULL)
                    301:            HT_OUTOFMEM("taking backup");
1.33      timbl     302:        strcpy(backup_filename, filename);
1.34      timbl     303:        for(p=backup_filename+strlen(backup_filename);; p--) {
1.33      timbl     304:            if ((*p=='/') || (p<backup_filename)) {
                    305:                p[1]=',';               /* Insert comma after slash */
                    306:                break;
                    307:            }
                    308:            p[1] = p[0];        /* Move up everything to the right of it */
                    309:        }
                    310:        
1.65      duns      311: 
                    312: #ifdef VMS
                    313:        if ((fp=fopen(filename, "r", "shr=put", "shr=upd"))) {  /* File exists */
                    314: #else /* not VMS */
1.35      luotonen  315:        if ((fp=fopen(filename, "r"))) {                /* File exists */
1.65      duns      316: #endif /* not VMS */
1.33      timbl     317:            fclose(fp);
1.111     eric      318:            if (PROT_TRACE) HTTrace("File `%s' exists\n", filename);
1.83      frystyk   319:            if (REMOVE(backup_filename)) {
1.111     eric      320:                if (PROT_TRACE) HTTrace("Backup file `%s' removed\n",
1.56      frystyk   321:                                   backup_filename);
1.33      timbl     322:            }
                    323:            if (rename(filename, backup_filename)) {    /* != 0 => Failure */
1.111     eric      324:                if (PROT_TRACE) HTTrace("Rename `%s' to `%s' FAILED!\n",
1.56      frystyk   325:                                   filename, backup_filename);
1.33      timbl     326:            } else {                                    /* Success */
1.95      frystyk   327:                if (PROT_TRACE)
1.111     eric      328:                    HTTrace("Renamed `%s' to `%s'\n", filename,
1.95      frystyk   329:                            backup_filename);
1.33      timbl     330:            }
                    331:        }
1.110     frystyk   332:        HT_FREE(backup_filename);
1.33      timbl     333:     } /* if take backup */    
1.2       timbl     334:     
1.89      frystyk   335:     if ((fp = fopen(filename, "wb")) == NULL) {
1.100     frystyk   336:        HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "fopen");
1.61      frystyk   337:        return NULL;
                    338:     } else
1.108     frystyk   339:        return HTFWriter_new(request, fp, NO);
1.2       timbl     340: }
1.120     frystyk   341: #endif
1.2       timbl     342: 
1.91      frystyk   343: /*     FileCleanup
                    344: **     -----------
1.80      frystyk   345: **      This function closes the connection and frees memory.
1.91      frystyk   346: **      Returns YES on OK, else NO
1.80      frystyk   347: */
1.91      frystyk   348: PRIVATE int FileCleanup (HTRequest *req, int status)
1.80      frystyk   349: {
1.91      frystyk   350:     HTNet *net = req->net;
                    351:     file_info *file = (file_info *) net->context;
1.106     frystyk   352: 
                    353:     /* Free stream with data TO Local file system */
1.107     frystyk   354:     if (HTRequest_isDestination(req))
                    355:        HTRequest_removeDestination(req);
                    356:     else  if (req->input_stream) {
1.106     frystyk   357:        if (status == HT_INTERRUPTED)
                    358:            (*req->input_stream->isa->abort)(req->input_stream, NULL);
                    359:        else
                    360:            (*req->input_stream->isa->_free)(req->input_stream);
                    361:        req->input_stream = NULL;
                    362:     }
                    363: 
1.91      frystyk   364:     if (file) {
1.110     frystyk   365:        HT_FREE(file->local);
                    366:        HT_FREE(file);
1.80      frystyk   367:     }
1.107     frystyk   368:     HTNet_delete(net, req->internal ? HT_IGNORE : status);
1.91      frystyk   369:     return YES;
1.80      frystyk   370: }
                    371: 
                    372: 
1.1       timbl     373: /*     Load a document
                    374: **     ---------------
                    375: **
                    376: ** On entry,
1.80      frystyk   377: **     request         This is the request structure
1.1       timbl     378: ** On exit,
1.91      frystyk   379: **     returns         HT_ERROR        Error has occured in call back
                    380: **                     HT_OK           Call back was OK
1.1       timbl     381: */
1.91      frystyk   382: PUBLIC int HTLoadFile (SOCKET soc, HTRequest * request, SockOps ops)
1.1       timbl     383: {
1.80      frystyk   384:     int status = HT_ERROR;
1.91      frystyk   385:     HTNet *net = request->net;              /* Generic protocol information */
1.80      frystyk   386:     file_info *file;                         /* Specific access information */
1.99      frystyk   387:     HTParentAnchor *anchor = HTRequest_anchor(request);
1.45      luotonen  388: 
1.91      frystyk   389:     /*
                    390:     ** Initiate a new file structure and bind to request structure
                    391:     ** This is actually state FILE_BEGIN, but it can't be in the state
                    392:     ** machine as we need the structure first.
                    393:     */
                    394:     if (ops == FD_NONE) {
1.111     eric      395:        if (PROT_TRACE) HTTrace("HTLoadFile.. Looking for `%s\'\n",
1.99      frystyk   396:                                HTAnchor_physical(anchor));
1.110     frystyk   397:        if ((file = (file_info *) HT_CALLOC(1, sizeof(file_info))) == NULL)
                    398:            HT_OUTOFMEM("HTLoadFILE");
1.95      frystyk   399:        file->state = FS_BEGIN;
1.91      frystyk   400:        net->context = file;
                    401:     } if (ops == FD_CLOSE) {                                 /* Interrupted */
1.107     frystyk   402:        HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED,
                    403:                           NULL, 0, "HTLoadHTTP");
                    404:        FileCleanup(request, HT_INTERRUPTED);
1.91      frystyk   405:        return HT_OK;
                    406:     } else
                    407:        file = (file_info *) net->context;              /* Get existing copy */
1.36      luotonen  408: 
1.80      frystyk   409:     /* Now jump into the machine. We know the state from the previous run */
                    410:     while (1) {
                    411:        switch (file->state) {
1.95      frystyk   412:          case FS_BEGIN:
1.102     frystyk   413:            if (HTLib_secure()) {
1.80      frystyk   414:                if (PROT_TRACE)
1.111     eric      415:                    HTTrace("LoadFile.... No access to local file system\n");
1.95      frystyk   416:                file->state = FS_TRY_FTP;
1.80      frystyk   417:                break;
                    418:            }
1.123   ! frystyk   419:            file->local = HTWWWToLocal(HTAnchor_physical(anchor), "",
        !           420:                                       HTRequest_userProfile(request));
1.95      frystyk   421:            if (!file->local) {
                    422:                file->state = FS_TRY_FTP;
1.80      frystyk   423:                break;
1.2       timbl     424:            }
1.86      frystyk   425: 
                    426:            /* If cache element then jump directly to OPEN FILE state */
1.99      frystyk   427:            file->state = HTAnchor_cacheHit(anchor) ?
1.95      frystyk   428:                FS_NEED_OPEN_FILE : FS_DO_CN;
1.86      frystyk   429:            break;
                    430: 
1.95      frystyk   431:          case FS_DO_CN:
1.80      frystyk   432:            /*
                    433:            ** If we have to do content negotiation then find the object that
                    434:            ** fits best into either what the client has indicated in the
1.86      frystyk   435:            ** accept headers or what the client has registered on its own.
1.80      frystyk   436:            ** The object chosen can in fact be a directory! However, content
                    437:            ** negotiation only makes sense it we can read the directory!
                    438:            ** We stat the file in order to find the size and to see it if
                    439:            ** exists.
                    440:            */
                    441:            {
                    442:                struct stat stat_info;        /* Contains actual file chosen */
                    443:                if (request->ContentNegotiation) {
1.95      frystyk   444:                    char *new_path=HTMulti(request,file->local,&stat_info);
1.80      frystyk   445:                    if (new_path) {
1.110     frystyk   446:                        HT_FREE(file->local);
1.95      frystyk   447:                        file->local = new_path;
1.99      frystyk   448:                        HTAnchor_setPhysical(anchor, new_path);
1.80      frystyk   449:                    } else {
1.95      frystyk   450:                        file->state = FS_ERROR;
1.80      frystyk   451:                        break;
                    452:                    }
                    453:                } else {
1.95      frystyk   454:                    if (HT_STAT(file->local, &stat_info) == -1) {
1.80      frystyk   455:                        if (PROT_TRACE)
1.111     eric      456:                            HTTrace("HTLoadFile.. Can't stat %s\n",
1.95      frystyk   457:                                    file->local);
1.100     frystyk   458:                        HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
1.81      frystyk   459:                                   NULL, 0, "HTLoadFile");
1.95      frystyk   460:                        file->state = FS_ERROR;
1.80      frystyk   461:                        break;
                    462:                    }
                    463:                }
                    464:                /* Check to see if the 'localname' is in fact a directory */
                    465:                if (((stat_info.st_mode) & S_IFMT) == S_IFDIR)
1.95      frystyk   466:                    file->state = FS_PARSE_DIR;
1.80      frystyk   467:                else {
                    468:                    /*
                    469:                    ** If empty file then only serve it if it is editable
                    470:                    */
1.95      frystyk   471:                    BOOL editable = HTEditable(file->local, &stat_info);
1.99      frystyk   472:                    HTBind_getBindings(anchor);
1.80      frystyk   473:                    if (editable)
1.99      frystyk   474:                        HTAnchor_appendMethods(anchor, METHOD_PUT);
1.80      frystyk   475:                    if (stat_info.st_size)
1.99      frystyk   476:                        HTAnchor_setLength(anchor, stat_info.st_size);
1.80      frystyk   477: 
1.83      frystyk   478:                    /* Done with relevant metainformation in anchor */
1.99      frystyk   479:                    HTAnchor_setHeaderParsed(anchor);
1.80      frystyk   480: 
                    481:                    if (!editable && !stat_info.st_size) {
1.100     frystyk   482:                        HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_CONTENT,
1.80      frystyk   483:                                   NULL, 0, "HTLoadFile");
1.95      frystyk   484:                        file->state = FS_NO_DATA;
1.80      frystyk   485:                    } else
1.95      frystyk   486:                        file->state = FS_NEED_OPEN_FILE;
1.80      frystyk   487:                }
1.2       timbl     488:            }
1.80      frystyk   489:            break;
1.61      frystyk   490: 
1.95      frystyk   491:          case FS_NEED_OPEN_FILE:
1.120     frystyk   492:            status = HTFileOpen(net, file->local, HT_FT_RDONLY);
                    493:            if (status == HT_OK) {
                    494:                /* 
                    495:                ** Create the stream pipe FROM the channel to the application.
                    496:                ** The target for the input stream pipe is set up using the
                    497:                ** stream stack. If we are reading from the cache then use the
                    498:                ** MIME parser as well.
                    499:                */
                    500:                if (HTAnchor_cacheHit(anchor))
                    501:                    HTAnchor_setFormat(anchor, WWW_MIME);
                    502:                HTNet_getInput(net, HTStreamStack(HTAnchor_format(anchor),
                    503:                                                  request->output_format,
                    504:                                                  request->output_stream,
                    505:                                                  request, YES), NULL, 0);
                    506:                /*
                    507:                ** Create the stream pipe TO the channel from the application
                    508:                ** and hook it up to the request object
                    509:                */
                    510:                {
                    511:                    HTOutputStream * output = HTNet_getOutput(net, NULL, 0);
                    512:                    HTRequest_setInputStream(request, (HTStream *) output);
                    513:                }
1.80      frystyk   514: 
1.120     frystyk   515:                /*
                    516:                ** Set up concurrent read/write if this request isn't the
                    517:                ** source for a PUT or POST. As source we don't start reading
                    518:                ** before all destinations are ready. If destination then
                    519:                ** register the input stream and get ready for read
                    520:                */
                    521:                if (HTRequest_isDestination(request)) {
1.122     eric      522:                    HTEvent_register(net->sockfd, request, (SockOps) FD_READ,
1.120     frystyk   523:                                     HTLoadFile, net->priority);
                    524:                    HTRequest_linkDestination(request);
1.82      frystyk   525:                }
1.120     frystyk   526:                if (HTRequest_isSource(request) &&
                    527:                    !HTRequest_destinationsReady(request))
                    528:                    return HT_OK;
1.106     frystyk   529: 
1.120     frystyk   530:                file->state = FS_NEED_BODY;
1.106     frystyk   531: 
1.116     frystyk   532: #ifndef NO_UNIX_IO
1.120     frystyk   533:                /* If we are _not_ using preemptive mode and we are Unix fd's
                    534:                ** then return here to get the same effect as when we are
                    535:                ** connecting to a socket. That way, HTFile acts just like any
                    536:                ** other protocol module even though we are in fact doing
                    537:                ** blocking connect
                    538:                */
                    539:                if (!net->preemptive) {
                    540:                    if (PROT_TRACE) HTTrace("HTLoadFile.. returning\n");
1.122     eric      541:                    HTEvent_register(net->sockfd, request, (SockOps) FD_READ,
1.120     frystyk   542:                                     net->cbf, net->priority);
                    543:                    return HT_WOULD_BLOCK;
                    544:                }
1.116     frystyk   545: #endif
1.120     frystyk   546:            } else if (status == HT_WOULD_BLOCK || status == HT_PERSISTENT)
                    547:                return HT_OK;
                    548:            else
                    549:                file->state = FS_ERROR;                /* Error or interrupt */
1.107     frystyk   550:            break;
1.82      frystyk   551: 
1.95      frystyk   552:          case FS_NEED_BODY:
1.120     frystyk   553:            status = (*net->input->isa->read)(net->input);
1.80      frystyk   554:            if (status == HT_WOULD_BLOCK)
1.91      frystyk   555:                return HT_OK;
1.108     frystyk   556:            else if (status == HT_LOADED || status == HT_CLOSED) {
1.95      frystyk   557:                file->state = FS_GOT_DATA;
1.61      frystyk   558:            } else
1.95      frystyk   559:                file->state = FS_ERROR;
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;
                    566:            else
                    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)) {
                    591:                    HTLink *link =
                    592:                        HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99      frystyk   593:                                          (HTAnchor *) anchor);
1.104     frystyk   594:                    HTLink_setResult(link, HT_LINK_OK);
1.87      frystyk   595:                }
1.107     frystyk   596:            }
                    597:            FileCleanup(request, HT_LOADED);
1.91      frystyk   598:            return HT_OK;
1.80      frystyk   599:            break;
                    600: 
1.95      frystyk   601:          case FS_NO_DATA:
1.83      frystyk   602:            if (HTRequest_isPostWeb(request)) {
1.87      frystyk   603:                if (HTRequest_isDestination(request)) {
                    604:                    HTLink *link =
                    605:                        HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99      frystyk   606:                                          (HTAnchor *) anchor);
1.104     frystyk   607:                    HTLink_setResult(link, HT_LINK_OK);
1.87      frystyk   608:                }
1.107     frystyk   609:            }
                    610:            FileCleanup(request, HT_NO_DATA);
1.91      frystyk   611:            return HT_OK;
1.80      frystyk   612:            break;
                    613: 
1.95      frystyk   614:          case FS_RETRY:
1.83      frystyk   615:            if (HTRequest_isPostWeb(request)) {
1.87      frystyk   616:                if (HTRequest_isDestination(request)) {
                    617:                    HTLink *link =
                    618:                        HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99      frystyk   619:                                          (HTAnchor *) anchor);
1.104     frystyk   620:                    HTLink_setResult(link, HT_LINK_ERROR);
1.87      frystyk   621:                }
1.107     frystyk   622:                HTRequest_killPostWeb(request);
                    623:            }
                    624:            FileCleanup(request, HT_RETRY);
1.91      frystyk   625:            return HT_OK;
1.80      frystyk   626:            break;
                    627: 
1.95      frystyk   628:          case FS_ERROR:
1.83      frystyk   629:            if (HTRequest_isPostWeb(request)) {
1.87      frystyk   630:                if (HTRequest_isDestination(request)) {
                    631:                    HTLink *link =
                    632:                        HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99      frystyk   633:                                          (HTAnchor *) anchor);
1.104     frystyk   634:                    HTLink_setResult(link, HT_LINK_ERROR);
1.87      frystyk   635:                }
1.107     frystyk   636:                HTRequest_killPostWeb(request);
                    637:            }
                    638:            FileCleanup(request, HT_ERROR);
1.91      frystyk   639:            return HT_OK;
1.80      frystyk   640:            break;
                    641:        }
                    642:     } /* End of while(1) */
1.1       timbl     643: }

Webmaster