Annotation of libwww/Library/src/HTFile.c, revision 1.102
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.1 timbl 6: **
7: ** This is unix-specific code in general, with some VMS bits.
1.8 timbl 8: ** These are routines for file access used by browsers.
1.1 timbl 9: **
10: ** History:
11: ** Feb 91 Written Tim Berners-Lee CERN/CN
12: ** Apr 91 vms-vms access included using DECnet syntax
13: ** 26 Jun 92 (JFG) When running over DECnet, suppressed FTP.
14: ** Fixed access bug for relative names on VMS.
1.28 duns 15: ** Sep 93 (MD) Access to VMS files allows sharing.
16: ** 15 Nov 93 (MD) Moved HTVMSname to HTVMSUTILS.C
1.52 duns 17: ** 22 Feb 94 (MD) Excluded two routines if we are not READING directories
1.61 frystyk 18: ** 18 May 94 (HF) Directory stuff removed and stream handling updated,
19: ** error messages introduced etc.
1.1 timbl 20: **
21: ** Bugs:
1.2 timbl 22: ** FTP: Cannot access VMS files from a unix machine.
23: ** How can we know that the
1.1 timbl 24: ** target machine runs VMS?
25: */
26:
1.67 frystyk 27: /* Library Includes */
1.75 frystyk 28: #include "tcp.h"
1.67 frystyk 29: #include "HTUtils.h"
1.75 frystyk 30: #include "HTString.h"
1.1 timbl 31: #include "HTParse.h"
32: #include "HTTCP.h"
33: #include "HTAnchor.h"
1.2 timbl 34: #include "HTAtom.h"
35: #include "HTWriter.h"
1.75 frystyk 36: #include "HTFWrite.h"
1.52 duns 37: #include "HTFormat.h"
1.102 ! frystyk 38: #include "HTWWWStr.h"
! 39: #include "HTAccess.h"
1.54 luotonen 40: #include "HTMulti.h"
1.95 frystyk 41: #include "HTIcons.h"
42: #include "HTDir.h"
1.78 frystyk 43: #include "HTBind.h"
1.80 frystyk 44: #include "HTSocket.h"
1.92 frystyk 45: #include "HTNetMan.h"
1.61 frystyk 46: #include "HTError.h"
1.91 frystyk 47: #include "HTReqMan.h"
1.67 frystyk 48: #include "HTFile.h" /* Implemented here */
49:
1.91 frystyk 50: /* Final states have negative value */
1.80 frystyk 51: typedef enum _FileState {
1.95 frystyk 52: FS_RETRY = -4,
53: FS_ERROR = -3,
54: FS_NO_DATA = -2,
55: FS_GOT_DATA = -1,
56: FS_BEGIN = 0,
57: FS_DO_CN,
58: FS_NEED_OPEN_FILE,
59: FS_NEED_TARGET,
60: FS_NEED_BODY,
61: FS_PARSE_DIR,
62: FS_TRY_FTP
1.80 frystyk 63: } FileState;
64:
1.91 frystyk 65: /* This is the context structure for the this module */
1.77 frystyk 66: typedef struct _file_info {
1.80 frystyk 67: FileState state; /* Current state of the connection */
1.95 frystyk 68: char * local; /* Local representation of file name */
1.91 frystyk 69: #ifdef NO_UNIX_IO
1.80 frystyk 70: FILE * fp; /* If we can't use sockets on local files */
1.91 frystyk 71: #endif
1.77 frystyk 72: } file_info;
1.2 timbl 73:
1.80 frystyk 74: /* Local definition */
75: struct _HTStream {
76: CONST HTStreamClass * isa;
1.91 frystyk 77: /* ... */
1.80 frystyk 78: };
79:
1.95 frystyk 80: PRIVATE BOOL HTTakeBackup = YES;
1.1 timbl 81:
1.95 frystyk 82: PRIVATE HTDirReadme dir_readme = HT_DIR_README_TOP;
83: PRIVATE HTDirAccess dir_access = HT_DIR_OK;
84: PRIVATE HTDirShow dir_show = HT_DS_SIZE+HT_DS_DATE+HT_DS_DES+HT_DS_ICON;
85: PRIVATE HTDirKey dir_key = HT_DK_CINS;
1.2 timbl 86:
1.61 frystyk 87: /* ------------------------------------------------------------------------- */
1.11 timbl 88:
1.95 frystyk 89: /* Directory Access
90: ** ----------------
91: */
92: PUBLIC BOOL HTFile_setDirAccess (HTDirAccess mode)
93: {
94: dir_access = mode;
95: return YES;
96: }
97:
98: PUBLIC HTDirAccess HTFile_dirAccess (void)
99: {
100: return dir_access;
101: }
102:
103: /* Directory Readme
104: ** ----------------
105: */
106: PUBLIC BOOL HTFile_setDirReadme (HTDirReadme mode)
107: {
108: dir_readme = mode;
109: return YES;
110: }
111:
112: PUBLIC HTDirReadme HTFile_dirReadme (void)
113: {
114: return dir_readme;
115: }
116:
117: /* HTFile_readDir
118: ** --------------
119: ** Reads the directory "path"
120: ** Returns:
121: ** HT_ERROR Error
122: ** HT_NO_ACCESS Directory reading not allowed
123: ** HT_LOADED Successfully read the directory
1.1 timbl 124: */
1.95 frystyk 125: PRIVATE int HTFile_readDir (HTRequest * request, file_info *file)
1.1 timbl 126: {
1.95 frystyk 127: #ifndef GOT_READ_DIR
128: return HT_ERROR;
129: #else
130: DIR *dp;
131: struct stat file_info;
132: char *url = HTAnchor_physical(request->anchor);
133: char fullname[HT_MAX_PATH+1];
134: char *name;
1.98 frystyk 135: if (PROT_TRACE) TTYPrint(TDEST, "Reading..... directory\n");
1.95 frystyk 136: if (dir_access == HT_DIR_FORBID) {
1.100 frystyk 137: HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.95 frystyk 138: NULL, 0, "HTFile_readDir");
139: return HT_NO_ACCESS;
140: }
141:
142: /* Initialize path name for stat() */
143: if (*(name = (url+strlen(url)-1)) != '/') {
144: char *newurl = NULL;
145: StrAllocCopy(newurl, url);
146: StrAllocCat(newurl, "/");
147: FREE(file->local);
148: file->local = HTWWWToLocal(newurl, "");
149: free(newurl);
150: }
151: strcpy(fullname, file->local);
152: name = fullname+strlen(fullname); /* Point to end of fullname */
153:
154: /* Check if access is enabled */
155: if (dir_access == HT_DIR_SELECTIVE) {
156: strcpy(name, DEFAULT_DIR_FILE);
157: if (HT_STAT(fullname, &file_info)) {
1.80 frystyk 158: if (PROT_TRACE)
1.98 frystyk 159: TTYPrint(TDEST,
1.95 frystyk 160: "Read dir.... `%s\' not found\n", DEFAULT_DIR_FILE);
1.100 frystyk 161: HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.95 frystyk 162: NULL, 0, "HTFile_readDir");
163: return HT_NO_ACCESS;
1.1 timbl 164: }
165: }
166:
1.95 frystyk 167: if ((dp = opendir(file->local))) {
168: STRUCT_DIRENT *dirbuf;
169: HTDir *dir = HTDir_new(request, dir_show, dir_key);
170: char datestr[20];
171: char sizestr[10];
172: HTFileMode mode;
173: #ifdef HT_REENTRANT
174: STRUCT_DIRENT result; /* For readdir_r */
175: while ((dirbuf = (STRUCT_DIRENT *) readdir_r(dp, &result)))
176: #else
177: while ((dirbuf = readdir(dp)))
178: #endif /* HT_REENTRANT */
179: {
180: /* Current and parent directories are never shown in list */
181: if (!dirbuf->d_ino ||
182: !strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
183: continue;
184:
185: /* Make a lstat on the file */
186: strcpy(name, dirbuf->d_name);
187: if (HT_LSTAT(fullname, &file_info)) {
188: if (PROT_TRACE)
1.98 frystyk 189: TTYPrint(TDEST, "Read dir.... lstat failed: %s\n",fullname);
1.95 frystyk 190: continue;
191: }
1.1 timbl 192:
1.95 frystyk 193: /* Convert stat info to fit our setup */
194: if ((file_info.st_mode & S_IFMT) == S_IFDIR) {
195: #ifdef VMS
196: char *dot = strstr(name, ".DIR"); /* strip .DIR part... */
197: if (dot) *dot = '\0';
198: #endif /* VMS */
199: mode = HT_IS_DIR;
200: if (dir_show & HT_DS_SIZE) strcpy(sizestr, "-");
201: } else {
202: mode = HT_IS_FILE;
203: if (dir_show & HT_DS_SIZE)
204: HTNumToStr(file_info.st_size, sizestr, 10);
205: }
206: if (dir_show & HT_DS_DATE)
207: HTDateDirStr(&file_info.st_mtime, datestr, 20);
1.1 timbl 208:
1.95 frystyk 209: /* Add to the list */
210: if (HTDir_addElement(dir, name, datestr, sizestr, mode) != YES)
211: break;
212: }
213: closedir(dp);
214: HTDir_free(dir);
1.1 timbl 215: } else
1.100 frystyk 216: HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "opendir");
1.95 frystyk 217: return HT_LOADED;
218: #endif /* GOT_READ_DIR */
1.1 timbl 219: }
220:
221: /* Determine write access to a file
1.2 timbl 222: ** --------------------------------
1.80 frystyk 223: ** If stat_info is NULL then the function calls stat() on it's own,
224: ** otherwise it uses the information found in stat_info
1.2 timbl 225: ** On exit,
226: ** return value YES if file can be accessed and can be written to.
227: **
228: ** Bugs:
229: ** 1. No code for non-unix systems.
230: ** 2. Isn't there a quicker way?
1.1 timbl 231: */
1.95 frystyk 232: PRIVATE BOOL HTEditable (CONST char * filename, struct stat * stat_info)
1.80 frystyk 233: {
1.75 frystyk 234: #ifndef NO_UNIX_IO
235: #ifdef NO_GROUPS
1.80 frystyk 236: return NO; /* Safe answer till we find the correct algorithm */
1.1 timbl 237: #else
1.75 frystyk 238: #ifdef NeXT
1.80 frystyk 239: int groups[NGROUPS];
1.75 frystyk 240: #else
1.80 frystyk 241: gid_t groups[NGROUPS];
1.75 frystyk 242: #endif
1.80 frystyk 243: int i;
244: uid_t myUid;
245: int ngroups; /* The number of groups */
1.1 timbl 246: struct stat fileStatus;
1.80 frystyk 247: struct stat *fileptr = stat_info ? stat_info : &fileStatus;
1.1 timbl 248:
1.80 frystyk 249: if (!stat_info) {
1.90 frystyk 250: if (HT_STAT(filename, &fileStatus))
1.80 frystyk 251: return NO; /* Can't even access file! */
252: }
1.1 timbl 253: ngroups = getgroups(NGROUPS, groups); /* Groups to which I belong */
254: myUid = geteuid(); /* Get my user identifier */
255:
1.95 frystyk 256: if (PROT_TRACE) {
1.1 timbl 257: int i;
1.98 frystyk 258: TTYPrint(TDEST,
1.19 timbl 259: "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (",
1.80 frystyk 260: (unsigned int) fileptr->st_mode, (int) fileptr->st_uid,
261: (int) fileptr->st_gid, (int) myUid, ngroups);
1.98 frystyk 262: for (i=0; i<ngroups; i++) TTYPrint(TDEST, " %d", (int) groups[i]);
263: TTYPrint(TDEST, ")\n");
1.1 timbl 264: }
265:
1.80 frystyk 266: if (fileptr->st_mode & 0002) /* I can write anyway? */
1.1 timbl 267: return YES;
268:
1.80 frystyk 269: if ((fileptr->st_mode & 0200) /* I can write my own file? */
270: && (fileptr->st_uid == myUid))
1.1 timbl 271: return YES;
272:
1.80 frystyk 273: if (fileptr->st_mode & 0020) /* Group I am in can write? */
1.1 timbl 274: {
275: for (i=0; i<ngroups; i++) {
1.80 frystyk 276: if (groups[i] == fileptr->st_gid)
1.1 timbl 277: return YES;
278: }
279: }
1.98 frystyk 280: if (PROT_TRACE) TTYPrint(TDEST, "\tFile is not editable.\n");
1.1 timbl 281: return NO; /* If no excuse, can't do */
282: #endif
1.80 frystyk 283: #else
284: /*
285: ** We don't know and can't find out. Can we be sure that when opening
286: ** a file in mode "a" that the file is not modified?
287: */
288: return NO;
289: #endif /* !NO_UNIX_IO */
1.1 timbl 290: }
1.80 frystyk 291:
1.1 timbl 292:
1.2 timbl 293: /* Make a save stream
294: ** ------------------
295: **
296: ** The stream must be used for writing back the file.
297: ** @@@ no backup done
298: */
1.101 frystyk 299: PUBLIC HTStream * HTFileSaveStream (HTRequest * request)
1.2 timbl 300: {
301:
1.29 timbl 302: CONST char * addr = HTAnchor_address((HTAnchor*)request->anchor);
1.95 frystyk 303: char * filename = HTWWWToLocal(addr, "");
1.33 timbl 304: FILE* fp;
305:
306: /* @ Introduce CVS handling here one day
307: */
308: /* Take a backup before we do anything silly 931205
309: */
310: if (HTTakeBackup) {
1.69 frystyk 311: char * p;
312: char * backup_filename = (char *) malloc(strlen(filename)+2);
1.33 timbl 313: if (!backup_filename) outofmem(__FILE__, "taking backup");
314: strcpy(backup_filename, filename);
1.34 timbl 315: for(p=backup_filename+strlen(backup_filename);; p--) {
1.33 timbl 316: if ((*p=='/') || (p<backup_filename)) {
317: p[1]=','; /* Insert comma after slash */
318: break;
319: }
320: p[1] = p[0]; /* Move up everything to the right of it */
321: }
322:
1.65 duns 323:
324: #ifdef VMS
325: if ((fp=fopen(filename, "r", "shr=put", "shr=upd"))) { /* File exists */
326: #else /* not VMS */
1.35 luotonen 327: if ((fp=fopen(filename, "r"))) { /* File exists */
1.65 duns 328: #endif /* not VMS */
1.33 timbl 329: fclose(fp);
1.98 frystyk 330: if (PROT_TRACE) TTYPrint(TDEST, "File `%s' exists\n", filename);
1.83 frystyk 331: if (REMOVE(backup_filename)) {
1.98 frystyk 332: if (PROT_TRACE) TTYPrint(TDEST, "Backup file `%s' removed\n",
1.56 frystyk 333: backup_filename);
1.33 timbl 334: }
335: if (rename(filename, backup_filename)) { /* != 0 => Failure */
1.98 frystyk 336: if (PROT_TRACE) TTYPrint(TDEST, "Rename `%s' to `%s' FAILED!\n",
1.56 frystyk 337: filename, backup_filename);
1.33 timbl 338: } else { /* Success */
1.95 frystyk 339: if (PROT_TRACE)
1.98 frystyk 340: TTYPrint(TDEST, "Renamed `%s' to `%s'\n", filename,
1.95 frystyk 341: backup_filename);
1.33 timbl 342: }
343: }
344: free(backup_filename);
345: } /* if take backup */
1.2 timbl 346:
1.89 frystyk 347: if ((fp = fopen(filename, "wb")) == NULL) {
1.100 frystyk 348: HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "fopen");
1.61 frystyk 349: return NULL;
350: } else
1.40 frystyk 351: return HTFWriter_new(fp, NO);
1.2 timbl 352: }
353:
1.10 secret 354:
1.91 frystyk 355: /* FileCleanup
356: ** -----------
1.80 frystyk 357: ** This function closes the connection and frees memory.
1.91 frystyk 358: ** Returns YES on OK, else NO
1.80 frystyk 359: */
1.91 frystyk 360: PRIVATE int FileCleanup (HTRequest *req, int status)
1.80 frystyk 361: {
1.91 frystyk 362: HTNet *net = req->net;
363: file_info *file = (file_info *) net->context;
364: if (file) {
365: #ifdef NO_UNIX_IO
366: if (file->fp) {
1.80 frystyk 367: if (PROT_TRACE)
1.98 frystyk 368: TTYPrint(TDEST,"FileCleanup. Closing file %p\n", file->fp);
1.82 frystyk 369: fclose(file->fp);
1.91 frystyk 370: }
1.82 frystyk 371: #endif
1.95 frystyk 372: FREE(file->local);
1.80 frystyk 373: free(file);
374: }
1.91 frystyk 375: HTNet_delete(net, status);
376: return YES;
1.80 frystyk 377: }
378:
379:
1.1 timbl 380: /* Load a document
381: ** ---------------
382: **
383: ** On entry,
1.80 frystyk 384: ** request This is the request structure
1.1 timbl 385: ** On exit,
1.91 frystyk 386: ** returns HT_ERROR Error has occured in call back
387: ** HT_OK Call back was OK
1.1 timbl 388: */
1.91 frystyk 389: PUBLIC int HTLoadFile (SOCKET soc, HTRequest * request, SockOps ops)
1.1 timbl 390: {
1.80 frystyk 391: int status = HT_ERROR;
1.91 frystyk 392: HTNet *net = request->net; /* Generic protocol information */
1.80 frystyk 393: file_info *file; /* Specific access information */
1.99 frystyk 394: HTParentAnchor *anchor = HTRequest_anchor(request);
1.45 luotonen 395:
1.91 frystyk 396: /*
397: ** Initiate a new file structure and bind to request structure
398: ** This is actually state FILE_BEGIN, but it can't be in the state
399: ** machine as we need the structure first.
400: */
401: if (ops == FD_NONE) {
1.98 frystyk 402: if (PROT_TRACE) TTYPrint(TDEST, "HTLoadFile.. Looking for `%s\'\n",
1.99 frystyk 403: HTAnchor_physical(anchor));
1.80 frystyk 404: if ((file = (file_info *) calloc(1, sizeof(file_info))) == NULL)
405: outofmem(__FILE__, "HTLoadFILE");
1.95 frystyk 406: file->state = FS_BEGIN;
1.91 frystyk 407: net->context = file;
408: } if (ops == FD_CLOSE) { /* Interrupted */
409: if(HTRequest_isPostWeb(request)&&!HTRequest_isMainDestination(request))
410: FileCleanup(request, HT_IGNORE);
411: else
412: FileCleanup(request, HT_INTERRUPTED);
413: return HT_OK;
414: } else
415: file = (file_info *) net->context; /* Get existing copy */
1.36 luotonen 416:
1.80 frystyk 417: /* Now jump into the machine. We know the state from the previous run */
418: while (1) {
419: switch (file->state) {
1.95 frystyk 420: case FS_BEGIN:
1.102 ! frystyk 421: if (HTLib_secure()) {
1.80 frystyk 422: if (PROT_TRACE)
1.98 frystyk 423: TTYPrint(TDEST, "LoadFile.... No access to local file system\n");
1.95 frystyk 424: file->state = FS_TRY_FTP;
1.80 frystyk 425: break;
426: }
1.99 frystyk 427: file->local = HTWWWToLocal(HTAnchor_physical(anchor), "");
1.95 frystyk 428: if (!file->local) {
429: file->state = FS_TRY_FTP;
1.80 frystyk 430: break;
1.2 timbl 431: }
1.86 frystyk 432:
433: /* If cache element then jump directly to OPEN FILE state */
1.99 frystyk 434: file->state = HTAnchor_cacheHit(anchor) ?
1.95 frystyk 435: FS_NEED_OPEN_FILE : FS_DO_CN;
1.86 frystyk 436: break;
437:
1.95 frystyk 438: case FS_DO_CN:
1.80 frystyk 439: /*
440: ** If we have to do content negotiation then find the object that
441: ** fits best into either what the client has indicated in the
1.86 frystyk 442: ** accept headers or what the client has registered on its own.
1.80 frystyk 443: ** The object chosen can in fact be a directory! However, content
444: ** negotiation only makes sense it we can read the directory!
445: ** We stat the file in order to find the size and to see it if
446: ** exists.
447: */
448: {
449: struct stat stat_info; /* Contains actual file chosen */
450: if (request->ContentNegotiation) {
1.95 frystyk 451: char *new_path=HTMulti(request,file->local,&stat_info);
1.80 frystyk 452: if (new_path) {
1.95 frystyk 453: FREE(file->local);
454: file->local = new_path;
1.99 frystyk 455: HTAnchor_setPhysical(anchor, new_path);
1.80 frystyk 456: } else {
1.95 frystyk 457: file->state = FS_ERROR;
1.80 frystyk 458: break;
459: }
460: } else {
1.95 frystyk 461: if (HT_STAT(file->local, &stat_info) == -1) {
1.80 frystyk 462: if (PROT_TRACE)
1.98 frystyk 463: TTYPrint(TDEST, "HTLoadFile.. Can't stat %s\n",
1.95 frystyk 464: file->local);
1.100 frystyk 465: HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
1.81 frystyk 466: NULL, 0, "HTLoadFile");
1.95 frystyk 467: file->state = FS_ERROR;
1.80 frystyk 468: break;
469: }
470: }
471: /* Check to see if the 'localname' is in fact a directory */
472: if (((stat_info.st_mode) & S_IFMT) == S_IFDIR)
1.95 frystyk 473: file->state = FS_PARSE_DIR;
1.80 frystyk 474: else {
475: /*
476: ** If empty file then only serve it if it is editable
477: */
1.95 frystyk 478: BOOL editable = HTEditable(file->local, &stat_info);
1.99 frystyk 479: HTBind_getBindings(anchor);
1.80 frystyk 480: if (editable)
1.99 frystyk 481: HTAnchor_appendMethods(anchor, METHOD_PUT);
1.80 frystyk 482: if (stat_info.st_size)
1.99 frystyk 483: HTAnchor_setLength(anchor, stat_info.st_size);
1.80 frystyk 484:
1.83 frystyk 485: /* Done with relevant metainformation in anchor */
1.99 frystyk 486: HTAnchor_setHeaderParsed(anchor);
1.80 frystyk 487:
488: if (!editable && !stat_info.st_size) {
1.100 frystyk 489: HTRequest_addError(request, ERR_FATAL, NO, HTERR_NO_CONTENT,
1.80 frystyk 490: NULL, 0, "HTLoadFile");
1.95 frystyk 491: file->state = FS_NO_DATA;
1.80 frystyk 492: } else
1.95 frystyk 493: file->state = FS_NEED_OPEN_FILE;
1.80 frystyk 494: }
1.2 timbl 495: }
1.80 frystyk 496: break;
1.61 frystyk 497:
1.95 frystyk 498: case FS_NEED_OPEN_FILE:
1.80 frystyk 499: /*
500: ** If we have unix file descriptors then use this otherwise use
501: ** the ANSI C file descriptors
502: */
503: #ifndef NO_UNIX_IO
1.95 frystyk 504: if ((net->sockfd = open(file->local, O_RDONLY)) == -1) {
1.100 frystyk 505: HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "open");
1.95 frystyk 506: file->state = FS_ERROR;
1.82 frystyk 507: break;
508: }
509: if (PROT_TRACE)
1.98 frystyk 510: TTYPrint(TDEST,"HTLoadFile.. `%s' opened using socket %d \n",
1.95 frystyk 511: file->local, net->sockfd);
1.80 frystyk 512:
1.82 frystyk 513: /* If non-blocking protocol then change socket status
514: ** I use FCNTL so that I can ask the status before I set it.
515: ** See W. Richard Stevens (Advan. Prog. in UNIX env, p.364)
516: ** Be CAREFULL with the old `O_NDELAY' - it wont work as read()
517: ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD
518: ** and does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
519: */
1.85 frystyk 520: #ifndef NO_FCNTL
1.91 frystyk 521: if (!request->net->preemtive) {
522: if ((status = FCNTL(net->sockfd, F_GETFL, 0)) != -1) {
1.82 frystyk 523: status |= O_NONBLOCK; /* POSIX */
1.91 frystyk 524: status = FCNTL(net->sockfd, F_SETFL, status);
1.82 frystyk 525: }
526: if (PROT_TRACE) {
527: if (status == -1)
1.98 frystyk 528: TTYPrint(TDEST, "HTLoadFile.. Can't make socket non-blocking\n");
1.82 frystyk 529: else
1.98 frystyk 530: TTYPrint(TDEST,"HTLoadFile.. Using NON_BLOCKING I/O\n");
1.80 frystyk 531: }
1.61 frystyk 532: }
1.85 frystyk 533: #endif /* NO_FCNTL */
1.80 frystyk 534: #else
1.83 frystyk 535: #ifdef VMS
1.95 frystyk 536: if (!(file->fp = fopen(file->local,"r","shr=put","shr=upd"))) {
1.80 frystyk 537: #else
1.95 frystyk 538: if ((file->fp = fopen(file->local,"r")) == NULL) {
1.82 frystyk 539: #endif /* !VMS */
1.100 frystyk 540: HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "fopen");
1.95 frystyk 541: file->state = FS_ERROR;
1.82 frystyk 542: break;
1.80 frystyk 543: }
1.82 frystyk 544: if (PROT_TRACE)
1.98 frystyk 545: TTYPrint(TDEST,"HTLoadFile.. `%s' opened using FILE %p\n",
1.95 frystyk 546: file->local, file->fp);
1.80 frystyk 547: #endif /* !NO_UNIX_IO */
1.95 frystyk 548: file->state = FS_NEED_TARGET;
1.83 frystyk 549: break;
550:
1.95 frystyk 551: case FS_NEED_TARGET:
1.83 frystyk 552: /*
553: ** We need to wait for the destinations to get ready
554: */
555: if (HTRequest_isSource(request) && !request->output_stream)
1.91 frystyk 556: return HT_OK;
1.83 frystyk 557: /*
558: ** Set up concurrent read/write if this request isn't the
559: ** source for a PUT or POST. As source we don't start reading
560: ** before all destinations are ready. If destination then
561: ** register the input stream and get ready for read
562: */
563: if (HTRequest_isPostWeb(request)) {
1.91 frystyk 564: HTEvent_Register(net->sockfd, request, (SockOps) FD_READ,
565: HTLoadFile, net->priority);
1.83 frystyk 566: HTRequest_linkDestination(request);
567: }
1.82 frystyk 568:
1.86 frystyk 569: /*
570: ** Set up read buffer and streams.
571: ** If cache element, we know that it's MIME, so call MIME parser
572: ** If ANSI then sockfd=INVSOC
573: */
1.91 frystyk 574: net->isoc = HTInputSocket_new(net->sockfd);
1.99 frystyk 575: if (HTAnchor_cacheHit(anchor))HTAnchor_setFormat(anchor, WWW_MIME);
576: net->target = HTStreamStack(HTAnchor_format(anchor),
577: request->output_format,
578: request->output_stream,
579: request, YES);
1.95 frystyk 580: file->state = net->target ? FS_NEED_BODY : FS_ERROR;
1.80 frystyk 581: break;
1.65 duns 582:
1.95 frystyk 583: case FS_NEED_BODY:
1.80 frystyk 584: #ifndef NO_UNIX_IO
1.94 frystyk 585: status = HTSocketRead(request, net);
1.82 frystyk 586: #else
1.94 frystyk 587: status = HTFileRead(request, net, file->fp);
1.82 frystyk 588: #endif
1.80 frystyk 589: if (status == HT_WOULD_BLOCK)
1.91 frystyk 590: return HT_OK;
1.80 frystyk 591: else if (status == HT_LOADED) {
1.95 frystyk 592: file->state = FS_GOT_DATA;
1.61 frystyk 593: } else
1.95 frystyk 594: file->state = FS_ERROR;
1.80 frystyk 595: break;
1.1 timbl 596:
1.95 frystyk 597: case FS_PARSE_DIR:
598: status = HTFile_readDir(request, file);
599: if (status == HT_LOADED)
600: file->state = FS_GOT_DATA;
601: else
602: file->state = FS_ERROR;
1.80 frystyk 603: break;
604:
1.95 frystyk 605: case FS_TRY_FTP:
1.80 frystyk 606: {
1.99 frystyk 607: char *url = HTAnchor_physical(anchor);
1.80 frystyk 608: HTAnchor *anchor;
609: char *newname = NULL;
610: StrAllocCopy(newname, "ftp:");
611: if (!strncmp(url, "file:", 5))
612: StrAllocCat(newname, url+5);
613: else
614: StrAllocCat(newname, url);
615: anchor = HTAnchor_findAddress(newname);
616: free(newname);
1.91 frystyk 617: FileCleanup(request, HT_IGNORE);
1.97 frystyk 618: return HTLoad(request, YES);
1.80 frystyk 619: }
620: break;
1.1 timbl 621:
1.95 frystyk 622: case FS_GOT_DATA:
1.83 frystyk 623: if (HTRequest_isPostWeb(request)) {
1.96 frystyk 624: FileCleanup(request, HTRequest_isMainDestination(request) ?
625: HT_ERROR : HT_IGNORE);
1.87 frystyk 626: if (HTRequest_isDestination(request)) {
627: HTLink *link =
628: HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99 frystyk 629: (HTAnchor *) anchor);
1.87 frystyk 630: HTAnchor_setLinkResult(link, HT_LINK_OK);
631: }
1.83 frystyk 632: HTRequest_removeDestination(request);
1.91 frystyk 633: } else
634: FileCleanup(request, HT_LOADED);
635: return HT_OK;
1.80 frystyk 636: break;
637:
1.95 frystyk 638: case FS_NO_DATA:
1.83 frystyk 639: if (HTRequest_isPostWeb(request)) {
1.96 frystyk 640: FileCleanup(request, HTRequest_isMainDestination(request) ?
641: HT_ERROR : HT_IGNORE);
1.87 frystyk 642: if (HTRequest_isDestination(request)) {
643: HTLink *link =
644: HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99 frystyk 645: (HTAnchor *) anchor);
1.87 frystyk 646: HTAnchor_setLinkResult(link, HT_LINK_OK);
647: }
1.83 frystyk 648: HTRequest_removeDestination(request);
1.91 frystyk 649: } else
650: FileCleanup(request, HT_NO_DATA);
651: return HT_OK;
1.80 frystyk 652: break;
653:
1.95 frystyk 654: case FS_RETRY:
1.83 frystyk 655: if (HTRequest_isPostWeb(request)) {
1.96 frystyk 656: FileCleanup(request, HTRequest_isMainDestination(request) ?
657: HT_ERROR : HT_IGNORE);
1.87 frystyk 658: HTRequest_killPostWeb(request);
659: if (HTRequest_isDestination(request)) {
660: HTLink *link =
661: HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99 frystyk 662: (HTAnchor *) anchor);
1.87 frystyk 663: HTAnchor_setLinkResult(link, HT_LINK_ERROR);
664: }
1.83 frystyk 665: HTRequest_removeDestination(request);
1.87 frystyk 666: } else
1.91 frystyk 667: FileCleanup(request, HT_RETRY);
668: return HT_OK;
1.80 frystyk 669: break;
670:
1.95 frystyk 671: case FS_ERROR:
1.83 frystyk 672: /* Clean up the other connections or just this one */
673: if (HTRequest_isPostWeb(request)) {
1.96 frystyk 674: FileCleanup(request, HTRequest_isMainDestination(request) ?
675: HT_ERROR : HT_IGNORE);
1.83 frystyk 676: HTRequest_killPostWeb(request);
1.87 frystyk 677: if (HTRequest_isDestination(request)) {
678: HTLink *link =
679: HTAnchor_findLink((HTAnchor *) request->source->anchor,
1.99 frystyk 680: (HTAnchor *) anchor);
1.87 frystyk 681: HTAnchor_setLinkResult(link, HT_LINK_ERROR);
682: }
683: HTRequest_removeDestination(request);
1.83 frystyk 684: } else
1.91 frystyk 685: FileCleanup(request, HT_ERROR);
686: return HT_OK;
1.80 frystyk 687: break;
688: }
689: } /* End of while(1) */
1.1 timbl 690: }
Webmaster