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