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