Annotation of libwww/Library/src/HTAccess.c, revision 1.100
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
1.79 frystyk 8: ** TBL Tim Berners-Lee timbl@w3.org
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.88 frystyk 22: ** Sep 95 Rewritten, HFN
1.1 timbl 23: */
24:
1.68 frystyk 25: #if !defined(HT_DIRECT_WAIS) && !defined(HT_DEFAULT_WAIS_GATEWAY)
26: #define HT_DEFAULT_WAIS_GATEWAY "http://www.w3.org:8001/"
1.54 frystyk 27: #endif
1.8 timbl 28:
1.67 frystyk 29: /* Library include files */
1.88 frystyk 30: #include "WWWLib.h"
1.93 frystyk 31: #include "HTReqMan.h"
32: #include "HTAccess.h" /* Implemented here */
1.88 frystyk 33:
1.99 frystyk 34: #ifndef VC
35: #define VC "unknown"
36: #endif
37:
1.93 frystyk 38: PRIVATE char * HTAppName = NULL; /* Application name: please supply */
39: PRIVATE char * HTAppVersion = NULL; /* Application version: please supply */
1.2 timbl 40:
1.99 frystyk 41: PRIVATE char * HTLibName = "libwww";
42: PRIVATE char * HTLibVersion = VC;
43:
44: PRIVATE BOOL HTSecure = NO; /* Can we access local file system? */
45:
1.59 frystyk 46: /* --------------------------------------------------------------------------*/
1.61 frystyk 47: /* Initialization and Termination of the Library */
48: /* --------------------------------------------------------------------------*/
49:
1.99 frystyk 50: /* Information about the Application
51: ** ---------------------------------
1.93 frystyk 52: */
53: PUBLIC CONST char * HTLib_appName (void)
54: {
1.99 frystyk 55: return HTAppName ? HTAppName : "UNKNOWN";
56: }
57:
58: PUBLIC CONST char * HTLib_appVersion (void)
59: {
60: return HTAppVersion ? HTAppVersion : "0.0";
1.93 frystyk 61: }
62:
1.99 frystyk 63: /* Information about libwww
64: ** ------------------------
65: */
66: PUBLIC CONST char * HTLib_name (void)
67: {
68: return HTLibName ? HTLibName : "UNKNOWN";
69: }
70:
71: PUBLIC CONST char * HTLib_version (void)
72: {
73: return HTLibVersion ? HTLibVersion : "0.0";
74: }
75:
76: /* Access Local File System
77: ** ------------------------
78: ** In this mode we do not tough the local file system at all
1.93 frystyk 79: */
1.99 frystyk 80: PUBLIC BOOL HTLib_secure (void)
81: {
82: return HTSecure;
83: }
84:
85: PUBLIC void HTLib_setSecure (BOOL mode)
1.93 frystyk 86: {
1.99 frystyk 87: HTSecure = mode;
1.93 frystyk 88: }
89:
1.61 frystyk 90: /* HTLibInit
91: **
92: ** This function initiates the Library and it MUST be called when
93: ** starting up an application. See also HTLibTerminate()
94: */
1.93 frystyk 95: PUBLIC BOOL HTLibInit (CONST char * AppName, CONST char * AppVersion)
1.61 frystyk 96: {
1.97 frystyk 97: #if WWWTRACE_MODE == WWWTRACE_FILE /* Open trace file */
1.67 frystyk 98: if ((TDEST = fopen(TRACE_FILE, "a")) != NULL) {
99: if (setvbuf(TDEST, NULL, _IOLBF, 0) < 0) { /* Change to line buffer */
1.97 frystyk 100: TTYPrint(TDEST, "WWWLibInit.. Can't initialize TRACE buffer - no TRACE\n");
1.67 frystyk 101: fclose(TDEST);
102: TDEST = NULL;
103: WWW_TraceFlag = 0;
104: }
105: } else
106: WWW_TraceFlag = 0;
1.97 frystyk 107: #endif /* WWWTRACE_FILE */
1.67 frystyk 108:
1.91 frystyk 109: if (WWWTRACE)
1.97 frystyk 110: TTYPrint(TDEST, "WWWLibInit.. INITIALIZING LIBRARY OF COMMON CODE\n");
1.63 frystyk 111:
1.93 frystyk 112: /* Set the application name and version */
113: if (AppName) {
114: char *ptr;
115: StrAllocCopy(HTAppName, AppName);
116: ptr = HTAppName;
117: while (*ptr) {
118: if (WHITE(*ptr)) *ptr = '_';
119: ptr++;
120: }
121: }
122: if (AppVersion) {
123: char *ptr;
124: StrAllocCopy(HTAppVersion, AppVersion);
125: ptr = HTAppVersion;
126: while (*ptr) {
127: if (WHITE(*ptr)) *ptr = '_';
128: ptr++;
129: }
130: }
131:
132: HTBind_init(); /* Initialize bindings */
1.61 frystyk 133:
1.77 frystyk 134: #ifndef HT_DIRECT_WAIS
1.95 frystyk 135: HTGateway_add("wais", HT_DEFAULT_WAIS_GATEWAY);
1.77 frystyk 136: #endif
137:
1.88 frystyk 138: /* Register a call back function for the Net Manager */
139: HTNet_register (HTLoad_terminate, HT_ALL);
140:
1.62 frystyk 141: #ifdef WWWLIB_SIG
1.61 frystyk 142: /* On Solaris (and others?) we get a BROKEN PIPE signal when connecting
1.67 frystyk 143: ** to a port where we should get `connection refused'. We ignore this
1.61 frystyk 144: ** using the following function call
145: */
146: HTSetSignal(); /* Set signals in library */
1.1 timbl 147: #endif
148:
1.67 frystyk 149: #ifdef _WINDOWS
150: /*
151: ** Initialise WinSock DLL. This must also be shut down! PMH
152: */
153: {
154: WSADATA wsadata;
155: if (WSAStartup(DESIRED_WINSOCK_VERSION, &wsadata)) {
1.91 frystyk 156: if (WWWTRACE)
1.97 frystyk 157: TTYPrint(TDEST, "WWWLibInit.. Can't initialize WinSoc\n");
1.67 frystyk 158: WSACleanup();
159: return NO;
160: }
161: if (wsadata.wVersion < MINIMUM_WINSOCK_VERSION) {
1.91 frystyk 162: if (WWWTRACE)
1.97 frystyk 163: TTYPrint(TDEST, "WWWLibInit.. Bad version of WinSoc\n");
1.67 frystyk 164: WSACleanup();
165: return NO;
166: }
167: }
168: #endif /* _WINDOWS */
169:
1.71 frystyk 170: #ifndef NO_TIMEGM
171: HTGetTimeZoneOffset(); /* Find offset from GMT if using mktime() */
172: #endif
1.70 frystyk 173: HTTmp_setRoot(NULL); /* Set up default tmp directory */
1.61 frystyk 174: return YES;
175: }
176:
177:
1.90 frystyk 178: /* HTLibTerminate
179: ** --------------
1.61 frystyk 180: ** This function frees memory kept by the Library and should be called
1.63 frystyk 181: ** before exit of an application (if you are on a PC platform)
1.61 frystyk 182: */
183: PUBLIC BOOL HTLibTerminate NOARGS
184: {
1.91 frystyk 185: if (WWWTRACE)
1.97 frystyk 186: TTYPrint(TDEST, "WWWLibTerm.. Cleaning up LIBRARY OF COMMON CODE\n");
1.63 frystyk 187: HTAtom_deleteAll();
1.89 frystyk 188: HTDNS_deleteAll();
1.73 frystyk 189:
1.81 frystyk 190: HTProtocol_deleteAll(); /* Remove bindings between access and protocols */
1.73 frystyk 191: HTBind_deleteAll(); /* Remove bindings between suffixes, media types */
192:
1.95 frystyk 193: HTProxy_deleteAll(); /* Clean up lists of proxies and gateways */
194: HTNoProxy_deleteAll();
195: HTGateway_deleteAll();
1.77 frystyk 196:
197: HTFreeHostName(); /* Free up some internal strings */
1.63 frystyk 198: HTFreeMailAddress();
1.70 frystyk 199: HTCache_freeRoot();
1.84 frystyk 200: HTCache_clearMem(); /* Keep the disk versions! */
1.70 frystyk 201: HTTmp_freeRoot();
1.98 frystyk 202: HTError_freePrefix();
1.67 frystyk 203:
204: #ifdef _WINDOWS
205: WSACleanup();
206: #endif
207:
1.97 frystyk 208: #if WWWTRACE_MODE == WWWTRACE_FILE /* Close trace file */
1.67 frystyk 209: if (TDEST) {
210: fclose(TDEST);
211: TDEST = NULL;
212: WWW_TraceFlag = 0;
213: }
1.97 frystyk 214: #endif /* WWWTRACE_FILE */
1.61 frystyk 215: return YES;
216: }
217:
1.59 frystyk 218: /* --------------------------------------------------------------------------*/
1.88 frystyk 219: /* Access functions */
1.59 frystyk 220: /* --------------------------------------------------------------------------*/
1.33 luotonen 221:
1.90 frystyk 222: /* Request a document
223: ** -----------------
224: ** Private version that requests a document from the request manager
225: ** Returns YES if request accepted, else NO
1.88 frystyk 226: */
1.90 frystyk 227: PRIVATE BOOL HTLoadDocument ARGS2(HTRequest *, request, BOOL, recursive)
1.88 frystyk 228: {
229: if (PROT_TRACE) {
1.90 frystyk 230: HTParentAnchor *anchor = HTRequest_anchor(request);
231: char * full_address = HTAnchor_address((HTAnchor *) anchor);
1.97 frystyk 232: TTYPrint(TDEST, "HTAccess.... Accessing document %s\n", full_address);
1.88 frystyk 233: free(full_address);
234: }
1.96 frystyk 235: return HTLoad(request, recursive);
1.58 frystyk 236: }
1.1 timbl 237:
238:
1.90 frystyk 239: /* Request a document from absolute name
240: ** -------------------------------------
241: ** Request a document referencd by an absolute URL.
242: ** Returns YES if request accepted, else NO
243: */
244: PUBLIC BOOL HTLoadAbsolute (CONST char * url, HTRequest* request)
245: {
246: if (url && request) {
247: HTAnchor * anchor = HTAnchor_findAddress(url);
248: HTRequest_setAnchor(request, anchor);
249: return HTLoadDocument(request, NO);
250: }
251: return NO;
252: }
253:
254:
255: /* Request a document from absolute name to stream
256: ** -----------------------------------------------
257: ** Request a document referencd by an absolute URL and sending the data
258: ** down a stream. This is _excactly_ the same as HTLoadAbsolute as
259: ** the ourputstream is specified using the function
260: ** HTRequest_setOutputStream(). 'filter' is ignored!
261: ** Returns YES if request accepted, else NO
262: */
263: PUBLIC BOOL HTLoadToStream (CONST char * url, BOOL filter, HTRequest *request)
264: {
265: return HTLoadAbsolute(url, request);
266: }
267:
268:
269: /* Request a document from relative name
270: ** -------------------------------------
271: ** Request a document referenced by a relative URL. The relative URL is
272: ** made absolute by resolving it relative to the address of the 'base'
273: ** anchor.
274: ** Returns YES if request accepted, else NO
275: */
276: PUBLIC BOOL HTLoadRelative (CONST char * relative,
277: HTParentAnchor * base,
278: HTRequest * request)
279: {
280: BOOL status = NO;
281: if (relative && base && request) {
282: char * rel = NULL;
283: char * full_url = NULL;
284: char * base_url = HTAnchor_address((HTAnchor *) base);
285: StrAllocCopy(rel, relative);
286: full_url = HTParse(HTStrip(rel), base_url,
287: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
288: status = HTLoadAbsolute(full_url, request);
289: free(rel);
290: free(full_url);
291: free(base_url);
292: }
293: return status;
294: }
295:
296:
297: /* Request an anchor
298: ** -----------------
299: ** Request the document referenced by the anchor
300: ** Returns YES if request accepted, else NO
301: */
302: PUBLIC BOOL HTLoadAnchor (HTAnchor * anchor, HTRequest * request)
303: {
304: if (anchor && request) {
305: HTRequest_setAnchor(request, anchor);
306: return HTLoadDocument(request, NO);
307: }
308: return NO;
309: }
310:
311:
312: /* Request an anchor
313: ** -----------------
314: ** Same as HTLoadAnchor but any information in the Error Stack in the
315: ** request object is kept, so that any error messages in one
1.52 frystyk 316: ** This function is almost identical to HTLoadAnchor, but it doesn't
317: ** clear the error stack so that the information in there is kept.
1.90 frystyk 318: ** Returns YES if request accepted, else NO
319: */
320: PUBLIC BOOL HTLoadAnchorRecursive (HTAnchor * anchor, HTRequest * request)
321: {
322: if (anchor && request) {
323: HTRequest_setAnchor(request, anchor);
324: return HTLoadDocument(request, YES);
325: }
326: return NO;
327: }
328:
329:
330: /* Search an Anchor
331: ** ----------------
332: ** Performs a keyword search on word given by the user. Adds the keyword
333: ** to the end of the current address and attempts to open the new address.
334: ** The list of keywords must be a space-separated list and spaces will
335: ** be converted to '+' before the request is issued.
336: ** Search can also be performed by HTLoadAbsolute() etc.
337: ** Returns YES if request accepted, else NO
338: */
339: PUBLIC BOOL HTSearch (CONST char * keywords,
340: HTParentAnchor * base,
341: HTRequest * request)
342: {
1.99 frystyk 343: BOOL status = NO;
1.90 frystyk 344: if (keywords && base && request) {
345: char *base_url = HTAnchor_address((HTAnchor *) base);
346: if (*keywords) {
347: char *plus;
348: StrAllocCat(base_url, "?");
349: StrAllocCat(base_url, keywords);
350: plus = strchr(base_url, '?');
351: while (*plus) {
352: if (*plus == ' ') *plus = '+';
353: plus++;
354: }
1.2 timbl 355: }
1.99 frystyk 356: status = HTLoadAbsolute(base_url, request);
357: free(base_url);
1.90 frystyk 358: }
1.99 frystyk 359: return status;
1.2 timbl 360: }
361:
362:
1.90 frystyk 363: /* Search a document from absolute name
364: ** ------------------------------------
365: ** Request a document referencd by an absolute URL appended with the
366: ** keywords given. The URL can NOT contain any fragment identifier!
367: ** The list of keywords must be a space-separated list and spaces will
368: ** be converted to '+' before the request is issued.
369: ** Returns YES if request accepted, else NO
370: */
371: PUBLIC BOOL HTSearchAbsolute (CONST char * keywords,
372: CONST char * url,
373: HTRequest * request)
374: {
375: if (url && request) {
376: HTAnchor * anchor = HTAnchor_findAddress(url);
377: return HTSearch(keywords, HTAnchor_parent(anchor), request);
378: }
379: return NO;
1.57 howcome 380: }
381:
1.70 frystyk 382: /* --------------------------------------------------------------------------*/
383: /* Document Poster */
384: /* --------------------------------------------------------------------------*/
385:
1.90 frystyk 386: /* Copy an anchor
1.70 frystyk 387: ** --------------
1.90 frystyk 388: ** Fetch the URL (possibly local file URL) and send it using either PUT
389: ** or POST to the remote destination using HTTP. The caller can decide the
390: ** exact method used and which HTTP header fields to transmit by setting
391: ** the user fields in the request structure.
1.92 frystyk 392: ** If posting to NNTP then we can't dispatch at this level but must pass
393: ** the source anchor to the news module that then takes all the refs
394: ** to NNTP and puts into the "newsgroups" header
1.90 frystyk 395: ** Returns YES if request accepted, else NO
1.70 frystyk 396: */
1.90 frystyk 397: PUBLIC BOOL HTCopyAnchor (HTAnchor * src_anchor, HTRequest * main_req)
1.80 frystyk 398: {
1.78 frystyk 399: HTRequest *src_req;
1.85 frystyk 400: if (!src_anchor || !main_req)
1.90 frystyk 401: return NO;
1.70 frystyk 402:
1.80 frystyk 403: /* Build the POST web if not already there */
1.85 frystyk 404: if (!main_req->source) {
1.80 frystyk 405: src_req = HTRequest_new(); /* First set up the source */
406: HTAnchor_clearHeader((HTParentAnchor *) src_anchor);
1.85 frystyk 407: src_req->reload = HT_MEM_REFRESH;
1.80 frystyk 408: src_req->source = src_req; /* Point to myself */
409: src_req->output_format = WWW_SOURCE; /* We want source (for now) */
410:
411: /* Set up the main link in the source anchor */
412: {
1.85 frystyk 413: HTLink *main_link = HTAnchor_findMainLink(src_anchor);
414: HTAnchor *main_anchor = HTAnchor_linkDest(main_link);
415: HTMethod method = HTAnchor_linkMethod(main_link);
416: if (!main_link || method==METHOD_INVALID) {
1.91 frystyk 417: if (WWWTRACE)
1.97 frystyk 418: TTYPrint(TDEST, "Copy Anchor. No destination found or unspecified method");
1.80 frystyk 419: HTRequest_delete(src_req);
1.90 frystyk 420: return NO;
1.80 frystyk 421: }
1.85 frystyk 422: if (HTAnchor_linkResult(main_link) == HT_LINK_NONE) {
423: main_req->GenMask |= HT_DATE; /* Send date header */
424: main_req->source = src_req;
425: main_req->reload = HT_CACHE_REFRESH;
426: main_req->method = method;
427: HTRequest_addDestination(src_req, main_req);
428: main_req->input_format = WWW_SOURCE; /* for now :-( @@@ */
1.90 frystyk 429: if (HTLoadAnchor(main_anchor, main_req) == NO)
430: return NO;
1.85 frystyk 431: }
1.80 frystyk 432: }
1.78 frystyk 433:
1.80 frystyk 434: /* For all other links in the source anchor */
435: if (src_anchor->links) {
436: HTList *cur = src_anchor->links;
437: HTLink *pres;
1.85 frystyk 438: while ((pres = (HTLink *) HTList_nextObject(cur)) &&
439: HTAnchor_linkResult(pres) == HT_LINK_NONE) {
440: HTAnchor *dest = HTAnchor_linkDest(pres);
441: HTMethod method = HTAnchor_linkMethod(pres);
1.80 frystyk 442: HTRequest *dest_req;
443: if (!dest || method==METHOD_INVALID) {
1.91 frystyk 444: if (WWWTRACE)
1.97 frystyk 445: TTYPrint(TDEST, "Copy Anchor. Bad anchor setup %p\n",
1.80 frystyk 446: dest);
1.90 frystyk 447: return NO;
1.80 frystyk 448: }
449: dest_req = HTRequest_new();
1.85 frystyk 450: dest_req->GenMask |= HT_DATE; /* Send date header */
1.80 frystyk 451: dest_req->source = src_req;
1.85 frystyk 452: dest_req->reload = HT_CACHE_REFRESH;
1.80 frystyk 453: dest_req->method = method;
454: HTRequest_addDestination(src_req, dest_req);
455: dest_req->input_format = WWW_SOURCE; /* for now :-( @@@ */
1.90 frystyk 456: if (HTLoadAnchor(dest, dest_req) == NO)
457: return NO;
1.80 frystyk 458: }
459: }
460: } else { /* Use the existing Post Web and restart it */
1.85 frystyk 461: src_req = main_req->source;
1.80 frystyk 462: if (src_req->mainDestination)
1.90 frystyk 463: if (HTLoadDocument(main_req, NO) == NO)
464: return NO;
1.80 frystyk 465: if (src_req->destinations) {
466: HTList *cur = src_anchor->links;
467: HTRequest *pres;
468: while ((pres = (HTRequest *) HTList_nextObject(cur)) != NULL) {
1.90 frystyk 469: if (HTLoadDocument(pres, NO) == NO)
470: return NO;
1.80 frystyk 471: }
472: }
1.78 frystyk 473: }
474:
1.80 frystyk 475: /* Now open the source */
476: return HTLoadAnchor(src_anchor, src_req);
1.70 frystyk 477: }
478:
479:
1.90 frystyk 480: /* Upload an Anchor
1.70 frystyk 481: ** ----------------
1.90 frystyk 482: ** Send the contents (in hyperdoc) of the source anchor using either PUT
483: ** or POST to the remote destination using HTTP. The caller can decide the
484: ** exact method used and which HTTP header fields to transmit by setting
485: ** the user fields in the request structure.
486: ** Returns YES if request accepted, else NO
487: */
488: PUBLIC BOOL HTUploadAnchor (HTAnchor * src_anchor,
489: HTParentAnchor * dest_anchor,
490: HTRequest * dest_req)
1.70 frystyk 491: {
1.90 frystyk 492: if (!src_anchor || !dest_anchor || !dest_req)
493: return NO;
1.70 frystyk 494: if (!(dest_anchor->methods & dest_req->method)) {
495: char buf[80];
496: sprintf(buf, "It might not be allowed to %s to this destination, continue?", HTMethod_name(dest_req->method));
1.86 frystyk 497: if (!HTConfirm(dest_req, buf))
1.90 frystyk 498: return NO;
1.70 frystyk 499: }
1.77 frystyk 500:
501: /* @@@ NOT FINISHED @@@ */
1.70 frystyk 502:
1.90 frystyk 503: return NO;
1.1 timbl 504: }
1.97 frystyk 505:
Webmaster