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