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