Annotation of libwww/Library/src/HTAccess.c, revision 1.76
1.61 frystyk 1: /* HTAccess.c
2: ** ACCESS MANAGER
3: **
1.75 frystyk 4: ** (c) COPYRIGHT MIT 1995.
1.61 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
1.1 timbl 6: **
7: ** Authors
8: ** TBL Tim Berners-Lee timbl@info.cern.ch
1.4 timbl 9: ** JFG Jean-Francois Groff jfg@dxcern.cern.ch
1.1 timbl 10: ** DD Denis DeLaRoca (310) 825-4580 <CSP1DWD@mvs.oac.ucla.edu>
11: ** History
12: ** 8 Jun 92 Telnet hopping prohibited as telnet is not secure TBL
13: ** 26 Jun 92 When over DECnet, suppressed FTP, Gopher and News. JFG
1.42 frystyk 14: ** 6 Oct 92 Moved HTClientHost and HTlogfile into here. TBL
1.1 timbl 15: ** 17 Dec 92 Tn3270 added, bug fix. DD
1.2 timbl 16: ** 4 Feb 93 Access registration, Search escapes bad chars TBL
1.9 timbl 17: ** PARAMETERS TO HTSEARCH AND HTLOADRELATIVE CHANGED
18: ** 28 May 93 WAIS gateway explicit if no WAIS library linked in.
1.19 timbl 19: ** Dec 93 Bug change around, more reentrant, etc
1.42 frystyk 20: ** 09 May 94 logfile renamed to HTlogfile to avoid clash with WAIS
1.53 duns 21: ** 8 Jul 94 Insulate free() from _free structure element.
1.2 timbl 22: ** Bugs
23: ** This module assumes that that the graphic object is hypertext, as it
1.9 timbl 24: ** needs to select it when it has been loaded. A superclass needs to be
1.2 timbl 25: ** defined which accepts select and select_anchor.
1.1 timbl 26: */
27:
1.68 frystyk 28: #if !defined(HT_DIRECT_WAIS) && !defined(HT_DEFAULT_WAIS_GATEWAY)
29: #define HT_DEFAULT_WAIS_GATEWAY "http://www.w3.org:8001/"
1.54 frystyk 30: #endif
1.8 timbl 31:
1.67 frystyk 32: /* Library include files */
33: #include "tcp.h"
34: #include "HTUtils.h"
1.1 timbl 35: #include "HTParse.h"
1.4 timbl 36: #include "HTML.h" /* SCW */
1.2 timbl 37: #include "HTList.h"
38: #include "HText.h" /* See bugs above */
39: #include "HTAlert.h"
1.67 frystyk 40: #include "HTFWrite.h" /* for cache stuff */
1.70 frystyk 41: #include "HTLog.h"
1.17 timbl 42: #include "HTTee.h"
1.46 frystyk 43: #include "HTError.h"
1.67 frystyk 44: #include "HTString.h"
1.57 howcome 45: #include "HTTCP.h" /* HWL: for HTFindRelatedName */
1.59 frystyk 46: #include "HTThread.h"
1.63 frystyk 47: #include "HTEvent.h"
1.73 frystyk 48: #include "HTBind.h"
1.70 frystyk 49: #include "HTInit.h"
1.74 frystyk 50:
1.67 frystyk 51: #ifndef NO_RULES
52: #include "HTRules.h"
53: #endif
1.74 frystyk 54:
1.67 frystyk 55: #include "HTAccess.h" /* Implemented here */
1.2 timbl 56:
1.54 frystyk 57: /* These flags may be set to modify the operation of this module */
1.73 frystyk 58: PUBLIC int HTMaxRedirections = 10; /* Max number of redirections */
59:
1.54 frystyk 60: PUBLIC char * HTClientHost = 0; /* Name of remote login host if any */
1.70 frystyk 61: PUBLIC BOOL HTSecure = NO; /* Disable access for telnet users? */
1.41 luotonen 62:
1.43 luotonen 63: PUBLIC char * HTImServer = NULL;/* cern_httpd sets this to the translated URL*/
1.70 frystyk 64: PUBLIC BOOL HTImProxy = NO; /* cern_httpd as a proxy? */
1.1 timbl 65:
1.70 frystyk 66: PRIVATE HTList * protocols = NULL; /* List of registered protocols */
1.43 luotonen 67:
1.74 frystyk 68: #ifdef _WINDOWS
69: PUBLIC HWND HTsocketWin = 0 ;
70: unsigned long HTwinMsg = 0 ;
71: #endif
72:
1.63 frystyk 73: /* Superclass defn */
1.24 timbl 74: struct _HTStream {
75: HTStreamClass * isa;
76: /* ... */
77: };
78:
1.59 frystyk 79: /* --------------------------------------------------------------------------*/
80: /* Management of the HTRequest structure */
81: /* --------------------------------------------------------------------------*/
82:
1.15 timbl 83: /* Create a request structure
84: ** ---------------------------
85: */
86: PUBLIC HTRequest * HTRequest_new NOARGS
87: {
1.28 luotonen 88: HTRequest * me = (HTRequest*) calloc(1, sizeof(*me)); /* zero fill */
1.15 timbl 89: if (!me) outofmem(__FILE__, "HTRequest_new()");
90:
1.70 frystyk 91: me->conversions = HTList_new(); /* No conversions registered yet */
92: me->output_format = WWW_PRESENT; /* default it to present to user */
1.72 frystyk 93: me->error_format = WWW_HTML; /* default format of error messages */
1.70 frystyk 94: me->HeaderMask = DEFAULT_HEADERS; /* Send these headers */
95: me->EntityMask = DEFAULT_ENTITY_HEADERS; /* Also these */
1.74 frystyk 96:
97: #ifdef _WINDOWS
98: me->hwnd = HTsocketWin;
99: me->winMsg = HTwinMsg;
100: #endif
101:
1.15 timbl 102: return me;
103: }
104:
105:
1.49 frystyk 106: /* Clear a request structure
107: ** ---------------------------
108: ** This function clears the reguest structure so that only the
109: ** conversions remain. Everything else is as if it was created from
110: ** scratch.
111: */
112: PUBLIC void HTRequest_clear ARGS1(HTRequest *, req)
113: {
114: HTList *conversions;
115: if (!req) {
116: if (TRACE)
1.67 frystyk 117: fprintf(TDEST, "Clear....... request: Bad argument!\n");
1.49 frystyk 118: return;
119: }
120: conversions = req->conversions; /* Save the conversions */
121: HTErrorFree(req);
122: HTAACleanup(req);
123: memset(req, '\0', sizeof(HTRequest));
124:
125: /* Now initialize as from scratch but with the old list of conversions */
126: req->conversions = conversions;
127: req->output_format = WWW_PRESENT; /* default it to present to user */
1.74 frystyk 128:
129: #ifdef _WINDOWS
1.76 ! frystyk 130: req->hwnd = HTsocketWin ;
! 131: req->winMsg = HTwinMsg ;
1.74 frystyk 132: #endif
133:
1.49 frystyk 134: }
135:
136:
1.20 luotonen 137: /* Delete a request structure
138: ** --------------------------
139: */
140: PUBLIC void HTRequest_delete ARGS1(HTRequest *, req)
141: {
142: if (req) {
1.59 frystyk 143: FREE(req->redirect);
144: FREE(req->authenticate);
145: HTFormatDelete(req);
1.46 frystyk 146: HTErrorFree(req);
1.34 frystyk 147: HTAACleanup(req);
1.61 frystyk 148:
149: /* These are temporary until we get a MIME thingy */
150: FREE(req->redirect);
151: FREE(req->WWWAAScheme);
152: FREE(req->WWWAARealm);
153: FREE(req->WWWprotection);
154:
1.34 frystyk 155: FREE(req);
1.20 luotonen 156: }
157: }
158:
1.59 frystyk 159: /* --------------------------------------------------------------------------*/
160: /* Management of HTTP Methods */
161: /* --------------------------------------------------------------------------*/
1.20 luotonen 162:
1.70 frystyk 163: static char *method_names[] =
1.22 luotonen 164: {
165: "INVALID-METHOD",
166: "GET",
167: "HEAD",
168: "POST",
169: "PUT",
170: "DELETE",
171: "LINK",
172: "UNLINK",
173: NULL
174: };
175:
176: /* Get method enum value
177: ** ---------------------
178: */
1.70 frystyk 179: PUBLIC HTMethod HTMethod_enum ARGS1(CONST char *, name)
1.22 luotonen 180: {
181: if (name) {
1.70 frystyk 182: if (!strcmp(name, *(method_names+1)))
183: return METHOD_GET;
184: else if (!strcmp(name, *(method_names+2)))
185: return METHOD_HEAD;
186: else if (!strcmp(name, *(method_names+3)))
187: return METHOD_POST;
188: else if (!strcmp(name, *(method_names+4)))
189: return METHOD_PUT;
190: else if (!strcmp(name, *(method_names+5)))
191: return METHOD_DELETE;
192: else if (!strcmp(name, *(method_names+6)))
193: return METHOD_LINK;
194: else if (!strcmp(name, *(method_names+7)))
195: return METHOD_UNLINK;
1.22 luotonen 196: }
197: return METHOD_INVALID;
198: }
199:
200:
201: /* Get method name
202: ** ---------------
1.70 frystyk 203: ** Returns pointer to entry in static table in memory
1.22 luotonen 204: */
1.70 frystyk 205: PUBLIC CONST char * HTMethod_name ARGS1(HTMethod, method)
1.22 luotonen 206: {
1.70 frystyk 207: if (method & METHOD_GET)
208: return *(method_names+1);
209: else if (method == METHOD_HEAD)
210: return *(method_names+2);
211: else if (method == METHOD_POST)
212: return *(method_names+3);
213: else if (method == METHOD_PUT)
214: return *(method_names+4);
215: else if (method == METHOD_DELETE)
216: return *(method_names+5);
217: else if (method == METHOD_LINK)
218: return *(method_names+6);
219: else if (method == METHOD_UNLINK)
220: return *(method_names+7);
221: else
222: return *method_names;
223: #if 0
224: if ((int)METHOD_INVALID && (int)method < (int)MAX_METHODS)
1.22 luotonen 225: return method_names[(int)method];
226: else
227: return method_names[(int)METHOD_INVALID];
1.70 frystyk 228: #endif
1.22 luotonen 229: }
230:
231:
1.70 frystyk 232: #if 0
233: /* NOT NEEDED AS METHODS IS NOT A BIT-FLAG */
1.22 luotonen 234: /* Is method in a list of method names?
235: ** -----------------------------------
236: */
237: PUBLIC BOOL HTMethod_inList ARGS2(HTMethod, method,
238: HTList *, list)
239: {
240: char * method_name = HTMethod_name(method);
241: HTList *cur = list;
242: char *item;
243:
244: while (NULL != (item = (char*)HTList_nextObject(cur))) {
1.67 frystyk 245: if (PROT_TRACE)
246: fprintf(TDEST, " %s", item);
1.22 luotonen 247: if (0==strcasecomp(item, method_name))
248: return YES;
249: }
250: return NO; /* Not found */
251: }
1.70 frystyk 252: #endif
1.22 luotonen 253:
1.59 frystyk 254: /* --------------------------------------------------------------------------*/
255: /* Management of the HTProtocol structure */
256: /* --------------------------------------------------------------------------*/
1.22 luotonen 257:
1.63 frystyk 258: /*
259: ** Register a Protocol as an active access method
1.1 timbl 260: */
1.56 frystyk 261: PUBLIC BOOL HTRegisterProtocol ARGS1(HTProtocol *, protocol)
1.1 timbl 262: {
263: if (!protocols) protocols = HTList_new();
1.59 frystyk 264: HTList_addObject(protocols, (void *) protocol);
1.1 timbl 265: return YES;
266: }
267:
1.63 frystyk 268:
269: /*
270: ** Delete the list of registered access methods. This is called from
271: ** within HTLibTerminate. Written by Eric Sink, eric@spyglass.com
272: */
273: PUBLIC void HTDisposeProtocols NOARGS
274: {
275: if (protocols) {
276: HTList_delete(protocols);
277: protocols = NULL;
278: }
279: }
280:
281:
282: /*
1.65 frystyk 283: ** Is a protocol registered as BLOCKING? The default behavior registered
284: ** when the protocol module was registered can be overridden by the
285: ** BlockingIO field in the HTRequest structure
1.63 frystyk 286: */
1.59 frystyk 287: PUBLIC BOOL HTProtocolBlocking ARGS1(HTRequest *, me)
288: {
1.65 frystyk 289: if (me) {
290: return (me->BlockingIO || (me->anchor && me->anchor->protocol &&
291: ((HTProtocol *) (me->anchor->protocol))->block == SOC_BLOCK));
292: }
293: return NO;
1.59 frystyk 294: }
295:
1.61 frystyk 296: /* --------------------------------------------------------------------------*/
297: /* Initialization and Termination of the Library */
298: /* --------------------------------------------------------------------------*/
299:
300: /* HTLibInit
301: **
302: ** This function initiates the Library and it MUST be called when
303: ** starting up an application. See also HTLibTerminate()
304: */
305: PUBLIC BOOL HTLibInit NOARGS
306: {
1.67 frystyk 307: #ifdef NO_STDIO /* Open trace file */
308: if ((TDEST = fopen(TRACE_FILE, "a")) != NULL) {
309: if (setvbuf(TDEST, NULL, _IOLBF, 0) < 0) { /* Change to line buffer */
1.70 frystyk 310: printf("WWWLibInit.. Can't initialize TRACE buffer - no TRACE\n");
1.67 frystyk 311: fclose(TDEST);
312: TDEST = NULL;
313: WWW_TraceFlag = 0;
314: }
315: } else
316: WWW_TraceFlag = 0;
317: #endif
318:
1.61 frystyk 319: if (TRACE)
1.67 frystyk 320: fprintf(TDEST, "WWWLibInit.. INITIALIZING LIBRARY OF COMMON CODE\n");
1.63 frystyk 321:
1.73 frystyk 322: /* Put up a global conversion list, but leave initialization
323: to the application */
324: HTBind_init();
325: if (!HTConversions)
326: HTConversions = HTList_new();
327:
328: /* Initialize the bindings between (access method, protocol module),
329: (file extension, media type)? */
1.70 frystyk 330: #ifndef HT_NO_INIT
331: HTAccessInit(); /* Bind access schemes and protocol modules */
332: HTFileInit(); /* Bind file extensions and media types */
1.63 frystyk 333: #endif
1.61 frystyk 334:
1.62 frystyk 335: #ifdef WWWLIB_SIG
1.61 frystyk 336: /* On Solaris (and others?) we get a BROKEN PIPE signal when connecting
1.67 frystyk 337: ** to a port where we should get `connection refused'. We ignore this
1.61 frystyk 338: ** using the following function call
339: */
340: HTSetSignal(); /* Set signals in library */
1.1 timbl 341: #endif
342:
1.67 frystyk 343: #ifdef _WINDOWS
344: /*
345: ** Initialise WinSock DLL. This must also be shut down! PMH
346: */
347: {
348: WSADATA wsadata;
349: if (WSAStartup(DESIRED_WINSOCK_VERSION, &wsadata)) {
350: if (TRACE)
351: fprintf(TDEST, "WWWLibInit.. Can't initialize WinSoc\n");
352: WSACleanup();
353: return NO;
354: }
355: if (wsadata.wVersion < MINIMUM_WINSOCK_VERSION) {
356: if (TRACE)
357: fprintf(TDEST, "WWWLibInit.. Bad version of WinSoc\n");
358: WSACleanup();
359: return NO;
360: }
361: }
362: #endif /* _WINDOWS */
363:
1.71 frystyk 364: #ifndef NO_TIMEGM
365: HTGetTimeZoneOffset(); /* Find offset from GMT if using mktime() */
366: #endif
1.70 frystyk 367: HTTmp_setRoot(NULL); /* Set up default tmp directory */
1.61 frystyk 368: HTThreadInit(); /* Initialize bit arrays */
369: return YES;
370: }
371:
372:
373: /* HTLibTerminate
374: **
375: ** This function frees memory kept by the Library and should be called
1.63 frystyk 376: ** before exit of an application (if you are on a PC platform)
1.61 frystyk 377: */
378: PUBLIC BOOL HTLibTerminate NOARGS
379: {
380: if (TRACE)
1.67 frystyk 381: fprintf(TDEST, "WWWLibTerm.. Cleaning up LIBRARY OF COMMON CODE\n");
1.63 frystyk 382: HTAtom_deleteAll();
383: HTDisposeConversions();
384: HTTCPCacheRemoveAll();
1.73 frystyk 385:
386: #ifndef HT_NO_INIT
387: HTDisposeProtocols(); /* Remove bindings between access and protocols */
388: HTBind_deleteAll(); /* Remove bindings between suffixes, media types */
389: #endif
390:
1.63 frystyk 391: HTFreeHostName();
392: HTFreeMailAddress();
1.70 frystyk 393: HTCache_freeRoot();
394: HTTmp_freeRoot();
1.67 frystyk 395:
396: #ifdef _WINDOWS
397: WSACleanup();
398: #endif
399:
400: #ifdef NO_STDIO /* Close trace file */
401: if (TDEST) {
402: fclose(TDEST);
403: TDEST = NULL;
404: WWW_TraceFlag = 0;
405: }
406: #endif
1.61 frystyk 407: return YES;
408: }
409:
1.59 frystyk 410: /* --------------------------------------------------------------------------*/
411: /* Physical Anchor Address Manager */
412: /* --------------------------------------------------------------------------*/
1.33 luotonen 413:
414: /* override_proxy()
415: **
416: ** Check the no_proxy environment variable to get the list
417: ** of hosts for which proxy server is not consulted.
418: **
419: ** no_proxy is a comma- or space-separated list of machine
420: ** or domain names, with optional :port part. If no :port
421: ** part is present, it applies to all ports on that domain.
422: **
423: ** Example:
424: ** no_proxy="cern.ch,some.domain:8001"
425: **
426: */
427: PRIVATE BOOL override_proxy ARGS1(CONST char *, addr)
428: {
429: CONST char * no_proxy = getenv("no_proxy");
430: char * p = NULL;
431: char * host = NULL;
432: int port = 0;
433: int h_len = 0;
434:
435: if (!no_proxy || !addr || !(host = HTParse(addr, "", PARSE_HOST)))
436: return NO;
437: if (!*host) { free(host); return NO; }
438:
1.34 frystyk 439: if ((p = strchr(host, ':')) != NULL) { /* Port specified */
1.33 luotonen 440: *p++ = 0; /* Chop off port */
441: port = atoi(p);
442: }
443: else { /* Use default port */
444: char * access = HTParse(addr, "", PARSE_ACCESS);
445: if (access) {
446: if (!strcmp(access,"http")) port = 80;
447: else if (!strcmp(access,"gopher")) port = 70;
448: else if (!strcmp(access,"ftp")) port = 21;
449: free(access);
450: }
451: }
452: if (!port) port = 80; /* Default */
453: h_len = strlen(host);
454:
455: while (*no_proxy) {
456: CONST char * end;
457: CONST char * colon = NULL;
458: int templ_port = 0;
459: int t_len;
460:
461: while (*no_proxy && (WHITE(*no_proxy) || *no_proxy==','))
462: no_proxy++; /* Skip whitespace and separators */
463:
464: end = no_proxy;
465: while (*end && !WHITE(*end) && *end != ',') { /* Find separator */
466: if (*end==':') colon = end; /* Port number given */
467: end++;
468: }
469:
470: if (colon) {
471: templ_port = atoi(colon+1);
472: t_len = colon - no_proxy;
473: }
474: else {
475: t_len = end - no_proxy;
476: }
477:
478: if ((!templ_port || templ_port == port) &&
479: (t_len > 0 && t_len <= h_len &&
480: !strncmp(host + h_len - t_len, no_proxy, t_len))) {
481: free(host);
482: return YES;
483: }
484: if (*end) no_proxy = end+1;
485: else break;
486: }
487:
488: free(host);
489: return NO;
490: }
491:
492:
493:
1.2 timbl 494: /* Find physical name and access protocol
495: ** --------------------------------------
1.1 timbl 496: **
497: **
498: ** On entry,
499: ** addr must point to the fully qualified hypertext reference.
500: ** anchor a pareent anchor with whose address is addr
501: **
1.59 frystyk 502: ** On exit,
503: ** returns HT_NO_ACCESS no protocol module found
504: ** HT_FORBIDDEN Error has occured.
1.2 timbl 505: ** HT_OK Success
1.1 timbl 506: **
507: */
1.21 luotonen 508: PRIVATE int get_physical ARGS1(HTRequest *, req)
509: {
1.1 timbl 510: char * access=0; /* Name of access method */
1.21 luotonen 511: char * addr = HTAnchor_address((HTAnchor*)req->anchor); /* free me */
1.27 luotonen 512:
1.70 frystyk 513: #ifndef HT_NO_RULES
1.47 luotonen 514: if (HTImServer) { /* cern_httpd has already done its own translations */
1.45 luotonen 515: HTAnchor_setPhysical(req->anchor, HTImServer);
1.47 luotonen 516: StrAllocCopy(addr, HTImServer); /* Oops, queries thru many proxies */
517: /* didn't work without this -- AL */
518: }
1.21 luotonen 519: else {
1.27 luotonen 520: char * physical = HTTranslate(addr);
1.21 luotonen 521: if (!physical) {
1.47 luotonen 522: free(addr);
1.21 luotonen 523: return HT_FORBIDDEN;
524: }
525: HTAnchor_setPhysical(req->anchor, physical);
526: free(physical); /* free our copy */
1.2 timbl 527: }
528: #else
1.21 luotonen 529: HTAnchor_setPhysical(req->anchor, addr);
1.70 frystyk 530: #endif /* HT_NO_RULES */
1.2 timbl 531:
1.21 luotonen 532: access = HTParse(HTAnchor_physical(req->anchor),
1.27 luotonen 533: "file:", PARSE_ACCESS);
1.1 timbl 534:
535: /* Check whether gateway access has been set up for this
1.8 timbl 536: ** This function can be replaced by the rule system above.
1.1 timbl 537: */
1.70 frystyk 538: #ifndef HT_NO_PROXY
1.39 luotonen 539:
540: /* make sure the using_proxy variable is false */
1.70 frystyk 541: req->using_proxy = NO;
1.39 luotonen 542:
1.33 luotonen 543: if (!override_proxy(addr)) {
1.27 luotonen 544: char * gateway_parameter, *gateway, *proxy;
545:
1.2 timbl 546: gateway_parameter = (char *)malloc(strlen(access)+20);
547: if (gateway_parameter == NULL) outofmem(__FILE__, "HTLoad");
1.27 luotonen 548:
549: /* search for proxy gateways */
1.2 timbl 550: strcpy(gateway_parameter, "WWW_");
551: strcat(gateway_parameter, access);
552: strcat(gateway_parameter, "_GATEWAY");
553: gateway = (char *)getenv(gateway_parameter); /* coerce for decstation */
1.27 luotonen 554:
555: /* search for proxy servers */
556: strcpy(gateway_parameter, access);
557: strcat(gateway_parameter, "_proxy");
558: proxy = (char *)getenv(gateway_parameter);
559:
1.2 timbl 560: free(gateway_parameter);
1.27 luotonen 561:
1.68 frystyk 562: #ifndef HT_DIRECT_WAIS
1.9 timbl 563: if (!gateway && 0==strcmp(access, "wais")) {
1.69 frystyk 564: gateway = HT_DEFAULT_WAIS_GATEWAY;
1.8 timbl 565: }
566: #endif
1.27 luotonen 567:
1.70 frystyk 568: if (TRACE && gateway)
569: fprintf(TDEST,"Gateway..... Found: `%s\'\n", gateway);
570: if (TRACE && proxy)
571: fprintf(TDEST,"Proxy....... Found: `%s\'\n", proxy);
572:
1.27 luotonen 573: /* proxy servers have precedence over gateway servers */
1.60 frystyk 574: if (proxy && *proxy) {
1.27 luotonen 575: char * gatewayed=0;
576:
577: StrAllocCopy(gatewayed,proxy);
578: StrAllocCat(gatewayed,addr);
1.70 frystyk 579: req->using_proxy = YES;
1.27 luotonen 580: HTAnchor_setPhysical(req->anchor, gatewayed);
581: free(gatewayed);
582: free(access);
583:
584: access = HTParse(HTAnchor_physical(req->anchor),
585: "http:", PARSE_ACCESS);
1.60 frystyk 586: } else if (gateway && *gateway) {
1.9 timbl 587: char * path = HTParse(addr, "",
588: PARSE_HOST + PARSE_PATH + PARSE_PUNCTUATION);
589: /* Chop leading / off to make host into part of path */
590: char * gatewayed = HTParse(path+1, gateway, PARSE_ALL);
591: free(path);
1.21 luotonen 592: HTAnchor_setPhysical(req->anchor, gatewayed);
1.9 timbl 593: free(gatewayed);
1.2 timbl 594: free(access);
1.9 timbl 595:
1.21 luotonen 596: access = HTParse(HTAnchor_physical(req->anchor),
1.8 timbl 597: "http:", PARSE_ACCESS);
1.2 timbl 598: }
599: }
1.70 frystyk 600: #endif /* HT_NO_PROXY */
1.1 timbl 601:
1.19 timbl 602: free(addr);
1.1 timbl 603:
1.61 frystyk 604: /* Search registered protocols to find suitable one */
1.1 timbl 605: {
1.61 frystyk 606: HTList *cur = protocols;
1.20 luotonen 607: HTProtocol *p;
1.61 frystyk 608: if (!cur) {
609: if (TRACE)
1.67 frystyk 610: fprintf(TDEST, "HTAccess.... NO PROTOCOL MODULES INITIATED\n");
1.61 frystyk 611: } else {
612: while ((p = (HTProtocol*)HTList_nextObject(cur))) {
613: if (strcmp(p->name, access)==0) {
614: HTAnchor_setProtocol(req->anchor, p);
615: free(access);
616: return (HT_OK);
617: }
1.1 timbl 618: }
619: }
620: }
621: free(access);
1.2 timbl 622: return HT_NO_ACCESS;
1.1 timbl 623: }
624:
1.59 frystyk 625: /* --------------------------------------------------------------------------*/
626: /* Document Loader */
627: /* --------------------------------------------------------------------------*/
1.1 timbl 628:
629: /* Load a document
630: ** ---------------
631: **
1.2 timbl 632: ** This is an internal routine, which has an address AND a matching
633: ** anchor. (The public routines are called with one OR the other.)
634: **
635: ** On entry,
1.15 timbl 636: ** request->
1.35 luotonen 637: ** anchor a parent anchor with fully qualified
638: ** hypertext reference as its address set
1.15 timbl 639: ** output_format valid
640: ** output_stream valid on NULL
1.2 timbl 641: **
642: ** On exit,
1.59 frystyk 643: ** returns HT_WOULD_BLOCK An I/O operation would block
644: ** HT_ERROR Error has occured
1.2 timbl 645: ** HT_LOADED Success
646: ** HT_NO_DATA Success, but no document loaded.
1.8 timbl 647: ** (telnet sesssion started etc)
1.72 frystyk 648: ** HT_RETRY if service isn't available before
649: ** request->retry_after
1.2 timbl 650: */
1.52 frystyk 651: PUBLIC int HTLoad ARGS2(HTRequest *, request, BOOL, keep_error_stack)
1.2 timbl 652: {
1.25 frystyk 653: char *arg = NULL;
654: HTProtocol *p;
655: int status;
656:
1.22 luotonen 657: if (request->method == METHOD_INVALID)
658: request->method = METHOD_GET;
1.52 frystyk 659: if (!keep_error_stack) {
660: HTErrorFree(request);
661: request->error_block = NO;
662: }
663:
1.59 frystyk 664: if ((status = get_physical(request)) < 0) {
665: if (status == HT_FORBIDDEN) {
666: char *url = HTAnchor_address((HTAnchor *) request->anchor);
667: if (url) {
668: HTUnEscape(url);
669: HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
670: (void *) url, (int) strlen(url), "HTLoad");
671: free(url);
672: } else {
673: HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
674: NULL, 0, "HTLoad");
675: }
676: }
677: return HT_ERROR; /* Can't resolve or forbidden */
1.2 timbl 678: }
1.25 frystyk 679:
680: if(!(arg = HTAnchor_physical(request->anchor)) || !*arg)
1.59 frystyk 681: return HT_ERROR;
1.27 luotonen 682:
1.56 frystyk 683: p = (HTProtocol *) HTAnchor_protocol(request->anchor);
1.17 timbl 684: return (*(p->load))(request);
1.2 timbl 685: }
686:
687:
1.61 frystyk 688: /* Terminate a LOAD
689: ** ----------------
690: **
691: ** This function looks at the status code from the HTLoadDocument
692: ** function and updates logfiles, creates error messages etc.
693: **
694: ** On Entry,
695: ** Status code from load function
696: */
697: PUBLIC BOOL HTLoadTerminate ARGS2(HTRequest *, request, int, status)
698: {
699: char * uri = HTAnchor_address((HTAnchor*)request->anchor);
700:
1.70 frystyk 701: HTLog_request(request);
1.61 frystyk 702:
703: /* The error stack might contain general information to the client
704: about what has been going on in the library (not only errors) */
705: if (!HTImProxy && request->error_stack)
706: HTErrorMsg(request);
707:
708: switch (status) {
709: case HT_LOADED:
710: if (PROT_TRACE) {
1.72 frystyk 711: fprintf(TDEST, "HTAccess.... OK: `%s\' has been accessed.\n", uri);
1.61 frystyk 712: }
713: break;
714:
715: case HT_NO_DATA:
716: if (PROT_TRACE) {
1.72 frystyk 717: fprintf(TDEST, "HTAccess.... OK BUT NO DATA: `%s\'\n", uri);
1.61 frystyk 718: }
719: break;
720:
721: case HT_WOULD_BLOCK:
722: if (PROT_TRACE) {
1.72 frystyk 723: fprintf(TDEST, "HTAccess.... WOULD BLOCK: `%s\'\n", uri);
724: }
725: break;
726:
727: case HT_RETRY:
728: if (PROT_TRACE) {
729: fprintf(TDEST, "HTAccess.... NOT AVAILABLE, RETRY AT `%s\'\n",uri);
1.61 frystyk 730: }
731: break;
732:
733: case HT_ERROR:
734: if (HTImProxy)
735: HTErrorMsg(request); /* Only on a real error */
736: if (PROT_TRACE) {
1.72 frystyk 737: fprintf(TDEST, "HTAccess.... ERROR: Can't access `%s\'\n", uri);
1.61 frystyk 738: }
739: break;
740:
741: default:
742: if (PROT_TRACE) {
1.67 frystyk 743: fprintf(TDEST, "HTAccess.... **** Internal software error in CERN WWWLib version %s ****\n", HTLibraryVersion);
744: fprintf(TDEST, "............ Please mail libwww@info.cern.ch quoting what software\n");
745: fprintf(TDEST, "............ and version you are using including the URL:\n");
746: fprintf(TDEST, "............ `%s\'\n", uri);
747: fprintf(TDEST, "............ that caused the problem, thanks!\n");
1.61 frystyk 748: }
749: break;
750: }
751: free(uri);
752: return YES;
753: }
754:
755:
1.2 timbl 756: /* Load a document - with logging etc
757: ** ----------------------------------
758: **
759: ** - Checks or documents already loaded
760: ** - Logs the access
761: ** - Trace ouput and error messages
762: **
1.1 timbl 763: ** On Entry,
1.19 timbl 764: ** request->anchor valid for of the document to be accessed.
765: ** request->childAnchor optional anchor within doc to be selected
766: **
1.15 timbl 767: ** request->anchor is the node_anchor for the document
768: ** request->output_format is valid
769: **
1.59 frystyk 770: ** On exit,
771: ** returns HT_WOULD_BLOCK An I/O operation would block
772: ** HT_ERROR Error has occured
773: ** HT_LOADED Success
774: ** HT_NO_DATA Success, but no document loaded.
775: ** (telnet sesssion started etc)
1.72 frystyk 776: ** HT_RETRY if service isn't available before
777: ** request->retry_after
1.1 timbl 778: */
1.59 frystyk 779: PRIVATE int HTLoadDocument ARGS2(HTRequest *, request,
780: BOOL, keep_error_stack)
1.1 timbl 781:
782: {
783: int status;
784: HText * text;
1.19 timbl 785: char * full_address = HTAnchor_address((HTAnchor*)request->anchor);
1.54 frystyk 786:
1.67 frystyk 787: if (PROT_TRACE) fprintf (TDEST, "HTAccess.... Loading document %s\n",
1.59 frystyk 788: full_address);
1.1 timbl 789:
1.18 timbl 790: request->using_cache = NULL;
791:
1.15 timbl 792: if (!request->output_format) request->output_format = WWW_PRESENT;
1.25 frystyk 793:
1.67 frystyk 794: /* Check if document is already loaded or in cache */
1.70 frystyk 795: if (!request->ForceReload) {
1.67 frystyk 796: if ((text=(HText *)HTAnchor_document(request->anchor))) {
797: if (PROT_TRACE)
798: fprintf(TDEST, "HTAccess.... Document already in memory.\n");
799: if (request->childAnchor) {
800: HText_selectAnchor(text, request->childAnchor);
801: } else {
802: HText_select(text);
803: }
804: free(full_address);
805: return HT_LOADED;
1.19 timbl 806: }
1.67 frystyk 807:
808: /* Check the Cache */
809: /* Bug: for each format, we only check whether it is ok, we
810: don't check them all and chose the best */
811: if (request->anchor->cacheItems) {
812: HTList * list = request->anchor->cacheItems;
813: HTList * cur = list;
814: HTCacheItem * item;
815: while ((item = (HTCacheItem*)HTList_nextObject(cur))) {
816: HTStream * s;
817: request->using_cache = item;
818: s = HTStreamStack(item->format, request->output_format,
819: request->output_stream, request, NO);
820: if (s) { /* format was suitable */
821: FILE * fp = fopen(item->filename, "r");
822: if (PROT_TRACE)
1.70 frystyk 823: fprintf(TDEST, "Cache....... HIT file %s for %s\n",
1.67 frystyk 824: item->filename,
825: full_address);
826: if (fp) {
827: HTFileCopy(fp, s);
828: (*s->isa->_free)(s); /* close up pipeline */
829: fclose(fp);
830: free(full_address);
831: return HT_LOADED;
832: } else {
833: fprintf(TDEST, "***** Can't read cache file %s !\n",
834: item->filename);
835: } /* file open ok */
836: } /* stream ok */
837: } /* next cache item */
838: } /* if cache available for this anchor */
1.70 frystyk 839: } else { /* Make sure that we don't use old headers */
840: HTAnchor_clearHeader(request->anchor);
841: request->HeaderMask += HT_PRAGMA; /* Force reload through proxy */
1.1 timbl 842: }
1.61 frystyk 843: if ((status = HTLoad(request, keep_error_stack)) != HT_WOULD_BLOCK)
844: HTLoadTerminate(request, status);
1.19 timbl 845: free(full_address);
1.59 frystyk 846: return status;
1.58 frystyk 847: }
1.1 timbl 848:
849:
850: /* Load a document from absolute name
851: ** ---------------
852: **
1.59 frystyk 853: ** On Entry,
1.1 timbl 854: ** addr The absolute address of the document to be accessed.
855: **
1.59 frystyk 856: ** On exit,
857: ** returns HT_WOULD_BLOCK An I/O operation would block
858: ** HT_ERROR Error has occured
859: ** HT_LOADED Success
860: ** HT_NO_DATA Success, but no document loaded.
861: ** (telnet sesssion started etc)
1.72 frystyk 862: ** HT_RETRY if service isn't available before
863: ** request->retry_after
1.1 timbl 864: */
1.59 frystyk 865: PUBLIC int HTLoadAbsolute ARGS2(CONST char *,addr, HTRequest*, request)
1.2 timbl 866: {
1.19 timbl 867: HTAnchor * anchor = HTAnchor_findAddress(addr);
868: request->anchor = HTAnchor_parent(anchor);
869: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ?
870: NULL : (HTChildAnchor*) anchor;
1.52 frystyk 871: return HTLoadDocument(request, NO);
1.2 timbl 872: }
873:
874:
875: /* Load a document from absolute name to stream
876: ** --------------------------------------------
877: **
1.59 frystyk 878: ** On Entry,
1.2 timbl 879: ** addr The absolute address of the document to be accessed.
1.15 timbl 880: ** request->output_stream if non-NULL, send data down this stream
1.2 timbl 881: **
1.59 frystyk 882: ** On exit,
883: ** returns HT_WOULD_BLOCK An I/O operation would block
884: ** HT_ERROR Error has occured
885: ** HT_LOADED Success
886: ** HT_NO_DATA Success, but no document loaded.
887: ** (telnet sesssion started etc)
1.72 frystyk 888: ** HT_RETRY if service isn't available before
889: ** request->retry_after
1.2 timbl 890: */
1.59 frystyk 891: PUBLIC int HTLoadToStream ARGS3(CONST char *, addr,
892: BOOL, filter,
893: HTRequest*, request)
1.1 timbl 894: {
1.63 frystyk 895: HTAnchor * anchor = HTAnchor_findAddress(addr);
896: request->anchor = HTAnchor_parent(anchor);
897: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL :
1.19 timbl 898: (HTChildAnchor*) anchor;
1.15 timbl 899: request->output_stream = request->output_stream;
1.52 frystyk 900: return HTLoadDocument(request, NO);
1.1 timbl 901: }
902:
903:
904: /* Load a document from relative name
905: ** ---------------
906: **
1.59 frystyk 907: ** On Entry,
1.2 timbl 908: ** relative_name The relative address of the document
909: ** to be accessed.
1.1 timbl 910: **
1.59 frystyk 911: ** On exit,
912: ** returns HT_WOULD_BLOCK An I/O operation would block
913: ** HT_ERROR Error has occured
914: ** HT_LOADED Success
915: ** HT_NO_DATA Success, but no document loaded.
916: ** (telnet sesssion started etc)
1.72 frystyk 917: ** HT_RETRY if service isn't available before
918: ** request->retry_after
1.1 timbl 919: */
1.59 frystyk 920: PUBLIC int HTLoadRelative ARGS3(CONST char *, relative_name,
921: HTParentAnchor *, here,
922: HTRequest *, request)
1.1 timbl 923: {
924: char * full_address = 0;
1.65 frystyk 925: int result;
1.1 timbl 926: char * mycopy = 0;
927: char * stripped = 0;
928: char * current_address =
1.2 timbl 929: HTAnchor_address((HTAnchor*)here);
1.1 timbl 930:
931: StrAllocCopy(mycopy, relative_name);
932:
933: stripped = HTStrip(mycopy);
934: full_address = HTParse(stripped,
935: current_address,
936: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.15 timbl 937: result = HTLoadAbsolute(full_address, request);
1.1 timbl 938: free(full_address);
939: free(current_address);
940: free(mycopy); /* Memory leak fixed 10/7/92 -- JFG */
941: return result;
942: }
943:
944:
945: /* Load if necessary, and select an anchor
946: ** --------------------------------------
947: **
1.59 frystyk 948: ** On Entry,
1.1 timbl 949: ** destination The child or parenet anchor to be loaded.
950: **
1.59 frystyk 951: ** On exit,
952: ** returns HT_WOULD_BLOCK An I/O operation would block
953: ** HT_ERROR Error has occured
954: ** HT_LOADED Success
955: ** HT_NO_DATA Success, but no document loaded.
956: ** (telnet sesssion started etc)
1.72 frystyk 957: ** HT_RETRY if service isn't available before
958: ** request->retry_after
1.1 timbl 959: */
1.59 frystyk 960: PUBLIC int HTLoadAnchor ARGS2(HTAnchor*, anchor, HTRequest *, request)
1.1 timbl 961: {
1.70 frystyk 962: if (!anchor || !request)
963: return HT_ERROR;
964: request->anchor = HTAnchor_parent(anchor);
1.59 frystyk 965: request->childAnchor = ((HTAnchor *) request->anchor == anchor) ?
966: NULL : (HTChildAnchor*) anchor;
967: return HTLoadDocument(request, NO);
968: }
1.52 frystyk 969:
970:
971: /* Load if necessary, and select an anchor
972: ** --------------------------------------
973: **
974: ** This function is almost identical to HTLoadAnchor, but it doesn't
975: ** clear the error stack so that the information in there is kept.
976: **
1.59 frystyk 977: ** On Entry,
1.52 frystyk 978: ** destination The child or parenet anchor to be loaded.
979: **
1.59 frystyk 980: ** On exit,
981: ** returns HT_WOULD_BLOCK An I/O operation would block
982: ** HT_ERROR Error has occured
983: ** HT_LOADED Success
984: ** HT_NO_DATA Success, but no document loaded.
985: ** (telnet sesssion started etc)
1.72 frystyk 986: ** HT_RETRY if service isn't available before
987: ** request->retry_after
1.52 frystyk 988: */
1.59 frystyk 989: PUBLIC int HTLoadAnchorRecursive ARGS2(HTAnchor*, anchor,
990: HTRequest *, request)
1.52 frystyk 991: {
1.59 frystyk 992: if (!anchor) return HT_ERROR; /* No link */
1.52 frystyk 993:
994: request->anchor = HTAnchor_parent(anchor);
1.59 frystyk 995: request->childAnchor = ((HTAnchor *) request->anchor == anchor) ?
996: NULL : (HTChildAnchor*) anchor;
1.52 frystyk 997:
1.59 frystyk 998: return HTLoadDocument(request, YES);
999: }
1.1 timbl 1000:
1001:
1002: /* Search
1003: ** ------
1004: ** Performs a keyword search on word given by the user. Adds the keyword to
1005: ** the end of the current address and attempts to open the new address.
1006: **
1007: ** On Entry,
1008: ** *keywords space-separated keyword list or similar search list
1.2 timbl 1009: ** here is anchor search is to be done on.
1.59 frystyk 1010: **
1011: ** On exit,
1012: ** returns HT_WOULD_BLOCK An I/O operation would block
1013: ** HT_ERROR Error has occured
1014: ** HT_LOADED Success
1015: ** HT_NO_DATA Success, but no document loaded.
1016: ** (telnet sesssion started etc)
1.72 frystyk 1017: ** HT_RETRY if service isn't available before
1018: ** request->retry_after
1.1 timbl 1019: */
1.56 frystyk 1020: PRIVATE char hex ARGS1(int, i)
1.2 timbl 1021: {
1.13 timbl 1022: char * hexchars = "0123456789ABCDEF";
1023: return hexchars[i];
1.2 timbl 1024: }
1.1 timbl 1025:
1.59 frystyk 1026: PUBLIC int HTSearch ARGS3(CONST char *, keywords,
1027: HTParentAnchor *, here,
1028: HTRequest *, request)
1.1 timbl 1029: {
1.2 timbl 1030:
1031: #define acceptable \
1032: "1234567890abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_"
1033:
1034: char *q, *u;
1035: CONST char * p, *s, *e; /* Pointers into keywords */
1036: char * address = HTAnchor_address((HTAnchor*)here);
1.65 frystyk 1037: int result;
1.56 frystyk 1038: char * escaped = (char *) malloc(strlen(keywords)*3+1);
1.2 timbl 1039:
1.29 frystyk 1040: /* static CONST BOOL isAcceptable[96] = */
1041: /* static AND const is not good for a gnu compiler! Frystyk 25/02-94 */
1.30 luotonen 1042: static BOOL isAcceptable[96] =
1.2 timbl 1043: /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
1044: { 0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0, /* 2x !"#$%&'()*+,-./ */
1045: 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */
1046: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x @ABCDEFGHIJKLMNO */
1047: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, /* 5X PQRSTUVWXYZ[\]^_ */
1048: 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x `abcdefghijklmno */
1049: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0 }; /* 7X pqrstuvwxyz{\}~ DEL */
1050:
1051: if (escaped == NULL) outofmem(__FILE__, "HTSearch");
1052:
1.29 frystyk 1053: /* Convert spaces to + and hex escape unacceptable characters */
1.2 timbl 1054:
1.29 frystyk 1055: for(s=keywords; *s && WHITE(*s); s++); /*scan */ /* Skip white space */
1056: for(e = s + strlen(s); e>s && WHITE(*(e-1)) ; e--); /* Skip trailers */
1057: for(q=escaped, p=s; p<e; p++) { /* scan stripped field */
1.2 timbl 1058: int c = (int)TOASCII(*p);
1059: if (WHITE(*p)) {
1060: *q++ = '+';
1.29 frystyk 1061: } else if (c>=32 && c<=127 && isAcceptable[c-32] != 0) {
1.13 timbl 1062: *q++ = *p; /* 930706 TBL for MVS bug */
1.2 timbl 1063: } else {
1064: *q++ = '%';
1065: *q++ = hex(c / 16);
1066: *q++ = hex(c % 16);
1067: }
1068: } /* Loop over string */
1.1 timbl 1069:
1.2 timbl 1070: *q=0;
1071: /* terminate escaped sctring */
1072: u=strchr(address, '?'); /* Find old search string */
1073: if (u) *u = 0; /* Chop old search off */
1.1 timbl 1074:
1075: StrAllocCat(address, "?");
1.2 timbl 1076: StrAllocCat(address, escaped);
1077: free(escaped);
1.15 timbl 1078: result = HTLoadRelative(address, here, request);
1.1 timbl 1079: free(address);
1.2 timbl 1080:
1.1 timbl 1081: return result;
1.2 timbl 1082: }
1083:
1084:
1085: /* Search Given Indexname
1086: ** ------
1087: ** Performs a keyword search on word given by the user. Adds the keyword to
1088: ** the end of the current address and attempts to open the new address.
1089: **
1.59 frystyk 1090: ** On Entry,
1.2 timbl 1091: ** *keywords space-separated keyword list or similar search list
1092: ** *addres is name of object search is to be done on.
1.59 frystyk 1093: ** On exit,
1094: ** returns HT_WOULD_BLOCK An I/O operation would block
1095: ** HT_ERROR Error has occured
1096: ** HT_LOADED Success
1097: ** HT_NO_DATA Success, but no document loaded.
1098: ** (telnet sesssion started etc)
1.72 frystyk 1099: ** HT_RETRY if service isn't available before
1100: ** request->retry_after
1.2 timbl 1101: */
1.59 frystyk 1102: PUBLIC int HTSearchAbsolute ARGS3(CONST char *, keywords,
1103: CONST char *, indexname,
1104: HTRequest *, request)
1.2 timbl 1105: {
1106: HTParentAnchor * anchor =
1107: (HTParentAnchor*) HTAnchor_findAddress(indexname);
1.15 timbl 1108: return HTSearch(keywords, anchor, request);
1.57 howcome 1109: }
1110:
1.70 frystyk 1111: /* --------------------------------------------------------------------------*/
1112: /* Document Poster */
1113: /* --------------------------------------------------------------------------*/
1114:
1115: /* Get a save stream for a document
1116: ** --------------------------------
1117: */
1118: PUBLIC HTStream *HTSaveStream ARGS1(HTRequest *, request)
1119: {
1120: HTProtocol * p;
1121: int status;
1122: request->method = METHOD_PUT;
1123: status = get_physical(request);
1124: if (status == HT_FORBIDDEN) {
1125: char *url = HTAnchor_address((HTAnchor *) request->anchor);
1126: if (url) {
1127: HTUnEscape(url);
1128: HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1129: (void *) url, (int) strlen(url), "HTLoad");
1130: free(url);
1131: } else {
1132: HTErrorAdd(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1133: NULL, 0, "HTLoad");
1134: }
1135: return NULL; /* should return error status? */
1136: }
1137: if (status < 0) return NULL; /* @@ error. Can't resolve or forbidden */
1138:
1139: p = (HTProtocol *) HTAnchor_protocol(request->anchor);
1140: if (!p) return NULL;
1141:
1142: return (*p->saveStream)(request);
1143:
1144: }
1145:
1146: /* COPY AN ANCHOR
1147: ** --------------
1148: ** Fetch the URL (possibly local file URL) and send it using either PUT
1149: ** or POST to the remote destination using HTTP. The caller can decide the
1150: ** exact method used and which HTTP header fields to transmit by setting the
1151: ** user fields in the request structure.
1152: **
1153: ** returns HT_WOULD_BLOCK An I/O operation would block
1154: ** HT_ERROR Error has occured
1155: ** HT_LOADED Success
1156: ** HT_NO_DATA Success, but no document loaded.
1.72 frystyk 1157: ** HT_RETRY if service isn't available before
1158: ** request->retry_after
1.70 frystyk 1159: */
1160: PUBLIC int HTCopyAnchor ARGS4(HTAnchor *, src_anchor,
1161: HTRequest *, src_req,
1162: HTParentAnchor *, dest_anchor,
1163: HTRequest *, dest_req)
1164: {
1165: if (!(src_anchor && src_req && dest_anchor && dest_req))
1166: return HT_ERROR;
1167:
1168: if (!(dest_anchor->methods & dest_req->method)) {
1169: char buf[80];
1170: sprintf(buf, "It might not be allowed to %s to this destination, continue?", HTMethod_name(dest_req->method));
1171: if (!HTConfirm(buf))
1172: return HT_ERROR;
1173: }
1174:
1175: /* First open the destination then open the source */
1176: if (HTLoadAnchor((HTAnchor *) dest_anchor, dest_req) != HT_ERROR) {
1177: src_req->ForceReload = YES;
1178: src_req->HeaderMask += HT_DATE; /* Send date header */
1179: if (src_req->output_format == WWW_PRESENT) /* Use source */
1180: src_req->output_format = WWW_SOURCE;
1181:
1182: /* Now make the link between the two request structures. First setup
1183: the output stream of the source so that data get redirected to
1184: the destination. Then set up the call back function so that
1185: the destination can call for more data */
1186: src_req->output_stream = dest_req->input_stream;
1187: dest_req->CopyRequest = src_req;
1188: dest_req->PostCallBack = HTSocketRead;
1189:
1190: return HTLoadAnchor(src_anchor, src_req);
1191: }
1192: return HT_ERROR;
1193: }
1194:
1195:
1196: /* UPLOAD AN ANCHOR
1197: ** ----------------
1198: ** Send the contents (in hyperdoc) of the source anchor using either PUT
1199: ** or POST to the remote destination using HTTP. The caller can decide the
1200: ** exact method used and which HTTP header fields to transmit by setting the
1201: ** user fields in the request structure.
1202: **
1203: ** returns HT_WOULD_BLOCK An I/O operation would block
1204: ** HT_ERROR Error has occured
1205: ** HT_LOADED Success
1206: ** HT_NO_DATA Success, but no document loaded.
1.72 frystyk 1207: ** HT_RETRY if service isn't available before
1208: ** request->retry_after
1.70 frystyk 1209: */
1210: PUBLIC int HTUploadAnchor ARGS3(HTAnchor *, src_anchor,
1211: HTParentAnchor *, dest_anchor,
1212: HTRequest *, dest_req)
1213: {
1214: if (!(src_anchor && dest_anchor && dest_req))
1215: return HT_ERROR;
1216:
1217: if (!(dest_anchor->methods & dest_req->method)) {
1218: char buf[80];
1219: sprintf(buf, "It might not be allowed to %s to this destination, continue?", HTMethod_name(dest_req->method));
1220: if (!HTConfirm(buf))
1221: return HT_ERROR;
1222: }
1223:
1224: return HT_ERROR;
1225: }
1226:
1227: /* --------------------------------------------------------------------------*/
1228: /* Anchor help routines */
1229: /* --------------------------------------------------------------------------*/
1.57 howcome 1230:
1231: /*
1232: ** Find Related Name
1233: **
1234: ** Creates a string that can be used as a related name when
1235: ** calling HTParse initially.
1236: **
1237: ** The code for this routine originates from the Linemode
1238: ** browser and was moved here by howcome@dxcern.cern.ch
1239: ** in order for all clients to take advantage.
1240: **
1.59 frystyk 1241: ** The string returned must be freed by the caller
1.57 howcome 1242: */
1243: PUBLIC char * HTFindRelatedName NOARGS
1244: {
1.59 frystyk 1245: char* default_default = NULL; /* Parse home relative to this */
1246: CONST char *host = HTGetHostName();
1.57 howcome 1247: StrAllocCopy(default_default, "file://");
1.59 frystyk 1248: if (host)
1249: StrAllocCat(default_default, host);
1250: else
1251: StrAllocCat(default_default, "localhost");
1252: {
1253: char wd[HT_MAX_PATH+1];
1.67 frystyk 1254:
1255: #ifdef NO_GETWD
1256: #ifdef HAS_GETCWD /* System V variant SIGN CHANGED TBL 921006 !! */
1257: char *result = (char *) getcwd(wd, sizeof(wd));
1258: #else
1259: char *result = NULL;
1260: HTAlert("This platform does not support neither getwd nor getcwd\n");
1261: #endif
1262: #else
1263: char *result = (char *) getwd(wd);
1264: #endif
1.59 frystyk 1265: *(wd+HT_MAX_PATH) = '\0';
1.57 howcome 1266: if (result) {
1267: #ifdef VMS
1268: /* convert directory name to Unix-style syntax */
1269: char * disk = strchr (wd, ':');
1270: char * dir = strchr (wd, '[');
1271: if (disk) {
1272: *disk = '\0';
1273: StrAllocCat (default_default, "/"); /* needs delimiter */
1274: StrAllocCat (default_default, wd);
1275: }
1276: if (dir) {
1277: char *p;
1278: *dir = '/'; /* Convert leading '[' */
1279: for (p = dir ; *p != ']'; ++p)
1280: if (*p == '.') *p = '/';
1281: *p = '\0'; /* Cut on final ']' */
1282: StrAllocCat (default_default, dir);
1283: }
1.74 frystyk 1284: #else /* not VMS */
1.70 frystyk 1285: #ifdef WIN32
1286: char * p = wd ; /* a colon */
1287: StrAllocCat(default_default, "/");
1288: while( *p != 0 ) {
1289: if (*p == '\\') /* change to one true slash */
1290: *p = '/' ;
1291: p++;
1292: }
1.74 frystyk 1293: StrAllocCat( default_default, wd);
1294: #else /* not WIN32 */
1.57 howcome 1295: StrAllocCat (default_default, wd);
1.70 frystyk 1296: #endif /* not WIN32 */
1.67 frystyk 1297: #endif /* not VMS */
1.57 howcome 1298: }
1.67 frystyk 1299: }
1.57 howcome 1300: StrAllocCat(default_default, "/default.html");
1301: return default_default;
1.2 timbl 1302: }
1303:
1304:
1305: /* Generate the anchor for the home page
1306: ** -------------------------------------
1307: **
1308: ** As it involves file access, this should only be done once
1309: ** when the program first runs.
1.10 timbl 1310: ** This is a default algorithm -- browser don't HAVE to use this.
1311: ** But consistency betwen browsers is STRONGLY recommended!
1.2 timbl 1312: **
1.10 timbl 1313: ** Priority order is:
1314: **
1315: ** 1 WWW_HOME environment variable (logical name, etc)
1316: ** 2 ~/WWW/default.html
1317: ** 3 /usr/local/bin/default.html
1.70 frystyk 1318: ** 4 http://www.w3.org/default.html
1.10 timbl 1319: **
1.2 timbl 1320: */
1321: PUBLIC HTParentAnchor * HTHomeAnchor NOARGS
1322: {
1.12 timbl 1323: char * my_home_document = NULL;
1.70 frystyk 1324: char * home = (char *) getenv(LOGICAL_DEFAULT);
1.2 timbl 1325: char * ref;
1326: HTParentAnchor * anchor;
1.1 timbl 1327:
1.70 frystyk 1328: /* Someone telnets in, they get a special home */
1.12 timbl 1329: if (home) {
1330: StrAllocCopy(my_home_document, home);
1.70 frystyk 1331: } else if (HTClientHost) { /* Telnet server */
1.12 timbl 1332: FILE * fp = fopen(REMOTE_POINTER, "r");
1333: char * status;
1334: if (fp) {
1.59 frystyk 1335: my_home_document = (char*) malloc(HT_MAX_PATH);
1336: status = fgets(my_home_document, HT_MAX_PATH, fp);
1.12 timbl 1337: if (!status) {
1338: free(my_home_document);
1339: my_home_document = NULL;
1340: }
1341: fclose(fp);
1342: }
1343: if (!my_home_document) StrAllocCopy(my_home_document, REMOTE_ADDRESS);
1344: }
1345:
1.67 frystyk 1346: #ifdef unix
1.10 timbl 1347: if (!my_home_document) {
1348: FILE * fp = NULL;
1.70 frystyk 1349: char * home = (char *) getenv("HOME");
1.10 timbl 1350: if (home) {
1351: my_home_document = (char *)malloc(
1352: strlen(home)+1+ strlen(PERSONAL_DEFAULT)+1);
1353: if (my_home_document == NULL) outofmem(__FILE__, "HTLocalName");
1354: sprintf(my_home_document, "%s/%s", home, PERSONAL_DEFAULT);
1355: fp = fopen(my_home_document, "r");
1356: }
1357:
1358: if (!fp) {
1359: StrAllocCopy(my_home_document, LOCAL_DEFAULT_FILE);
1360: fp = fopen(my_home_document, "r");
1361: }
1.2 timbl 1362: if (fp) {
1363: fclose(fp);
1364: } else {
1.62 frystyk 1365: if (TRACE)
1.67 frystyk 1366: fprintf(TDEST,
1.62 frystyk 1367: "HTBrowse: No local home document ~/%s or %s\n",
1368: PERSONAL_DEFAULT, LOCAL_DEFAULT_FILE);
1.11 timbl 1369: free(my_home_document);
1370: my_home_document = NULL;
1.2 timbl 1371: }
1372: }
1.67 frystyk 1373: #endif
1.70 frystyk 1374: ref = HTParse(my_home_document ? my_home_document :
1375: HTClientHost ? REMOTE_ADDRESS : LAST_RESORT, "file:",
1376: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.10 timbl 1377: if (my_home_document) {
1.62 frystyk 1378: if (TRACE)
1.67 frystyk 1379: fprintf(TDEST,
1.62 frystyk 1380: "HTAccess.... `%s\' used for custom home page as\n`%s\'\n",
1381: my_home_document, ref);
1.10 timbl 1382: free(my_home_document);
1.2 timbl 1383: }
1384: anchor = (HTParentAnchor*) HTAnchor_findAddress(ref);
1385: free(ref);
1386: return anchor;
1.1 timbl 1387: }
1.26 frystyk 1388:
1389:
1390: /* Bind an Anchor to the request structure
1391: ** ---------------------------------------
1392: **
1393: ** On Entry,
1394: ** anchor The child or parenet anchor to be binded
1395: ** request The request sturcture
1396: ** On Exit,
1397: ** returns YES Success
1398: ** NO Failure
1399: **
1400: ** Note: Actually the same as HTLoadAnchor() but DOES NOT do the loading
1401: ** Henrik Frystyk 17/02-94
1402: */
1403:
1404: PUBLIC BOOL HTBindAnchor ARGS2(HTAnchor*, anchor, HTRequest *, request)
1405: {
1406: if (!anchor) return NO; /* No link */
1407:
1408: request->anchor = HTAnchor_parent(anchor);
1409: request->childAnchor = ((HTAnchor*)request->anchor == anchor) ? NULL
1410: : (HTChildAnchor*) anchor;
1411:
1.29 frystyk 1412: return YES;
1.70 frystyk 1413: }
1.59 frystyk 1414:
1.26 frystyk 1415:
Webmaster