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