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