Annotation of libwww/Library/src/HTAccess.c, revision 1.122
1.120 eric 1: /* htaccess.c
1.61 frystyk 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.122 ! frystyk 6: ** @(#) $Id: HTAccess.c,v 1.121 1996/05/20 15:06:18 frystyk Exp $
1.1 timbl 7: **
8: ** Authors
1.79 frystyk 9: ** TBL Tim Berners-Lee timbl@w3.org
1.4 timbl 10: ** JFG Jean-Francois Groff jfg@dxcern.cern.ch
1.1 timbl 11: ** DD Denis DeLaRoca (310) 825-4580 <CSP1DWD@mvs.oac.ucla.edu>
1.122 ! frystyk 12: ** HFN Henrik Frystyk, frystyk@w3.org
1.1 timbl 13: ** History
14: ** 8 Jun 92 Telnet hopping prohibited as telnet is not secure TBL
15: ** 26 Jun 92 When over DECnet, suppressed FTP, Gopher and News. JFG
1.42 frystyk 16: ** 6 Oct 92 Moved HTClientHost and HTlogfile into here. TBL
1.1 timbl 17: ** 17 Dec 92 Tn3270 added, bug fix. DD
1.2 timbl 18: ** 4 Feb 93 Access registration, Search escapes bad chars TBL
1.9 timbl 19: ** PARAMETERS TO HTSEARCH AND HTLOADRELATIVE CHANGED
20: ** 28 May 93 WAIS gateway explicit if no WAIS library linked in.
1.19 timbl 21: ** Dec 93 Bug change around, more reentrant, etc
1.42 frystyk 22: ** 09 May 94 logfile renamed to HTlogfile to avoid clash with WAIS
1.114 frystyk 23: ** 8 Jul 94 Insulate HT_FREE();
1.88 frystyk 24: ** Sep 95 Rewritten, HFN
1.1 timbl 25: */
26:
1.67 frystyk 27: /* Library include files */
1.122 ! frystyk 28: #include "WWWUtil.h"
! 29: #include "WWWCore.h"
! 30: #include "WWWStream.h"
1.93 frystyk 31: #include "HTReqMan.h"
32: #include "HTAccess.h" /* Implemented here */
1.88 frystyk 33:
1.111 frystyk 34: #define PUTBLOCK(b, l) (*target->isa->put_block)(target, b, l)
35:
36: struct _HTStream {
37: HTStreamClass * isa;
38: };
39:
1.122 ! frystyk 40: /* ------------------------------------------------------------------------- */
1.33 luotonen 41:
1.90 frystyk 42: /* Request a document
43: ** -----------------
44: ** Private version that requests a document from the request manager
45: ** Returns YES if request accepted, else NO
1.88 frystyk 46: */
1.101 frystyk 47: PRIVATE BOOL HTLoadDocument (HTRequest * request, BOOL recursive)
1.88 frystyk 48: {
49: if (PROT_TRACE) {
1.90 frystyk 50: HTParentAnchor *anchor = HTRequest_anchor(request);
51: char * full_address = HTAnchor_address((HTAnchor *) anchor);
1.115 eric 52: HTTrace("HTAccess.... Accessing document %s\n", full_address);
1.114 frystyk 53: HT_FREE(full_address);
1.88 frystyk 54: }
1.96 frystyk 55: return HTLoad(request, recursive);
1.58 frystyk 56: }
1.1 timbl 57:
58:
1.90 frystyk 59: /* Request a document from absolute name
60: ** -------------------------------------
61: ** Request a document referencd by an absolute URL.
62: ** Returns YES if request accepted, else NO
63: */
1.122 ! frystyk 64: PUBLIC BOOL HTLoadAbsolute (const char * url, HTRequest * request)
1.90 frystyk 65: {
66: if (url && request) {
67: HTAnchor * anchor = HTAnchor_findAddress(url);
68: HTRequest_setAnchor(request, anchor);
69: return HTLoadDocument(request, NO);
70: }
71: return NO;
72: }
73:
74:
75: /* Request a document from absolute name to stream
76: ** -----------------------------------------------
77: ** Request a document referencd by an absolute URL and sending the data
78: ** down a stream. This is _excactly_ the same as HTLoadAbsolute as
79: ** the ourputstream is specified using the function
80: ** HTRequest_setOutputStream(). 'filter' is ignored!
81: ** Returns YES if request accepted, else NO
82: */
1.117 frystyk 83: PUBLIC BOOL HTLoadToStream (const char * url, BOOL filter, HTRequest *request)
1.90 frystyk 84: {
85: return HTLoadAbsolute(url, request);
86: }
87:
1.122 ! frystyk 88: /*
! 89: ** Load a URL to a mem buffer
! 90: ** --------------------------
! 91: ** Load a request and store the result in a memory buffer.
! 92: ** Returns chunk if OK - else NULL
! 93: */
! 94: PUBLIC HTChunk * HTLoadToChunk (const char * url, HTRequest * request)
! 95: {
! 96: if (url && request) {
! 97: HTChunk * chunk = NULL;
! 98: HTStream * target = HTStreamToChunk(request, &chunk, 0);
! 99: HTAnchor * anchor = HTAnchor_findAddress(url);
! 100: HTRequest_setAnchor(request, anchor);
! 101: HTRequest_setOutputStream(request, target);
! 102: if (HTLoadDocument(request, NO) == YES)
! 103: return chunk;
! 104: else {
! 105: HTChunk_delete(chunk);
! 106: return NULL;
! 107: }
! 108: }
! 109: return NULL;
! 110: }
1.90 frystyk 111:
112: /* Request a document from relative name
113: ** -------------------------------------
114: ** Request a document referenced by a relative URL. The relative URL is
115: ** made absolute by resolving it relative to the address of the 'base'
116: ** anchor.
117: ** Returns YES if request accepted, else NO
118: */
1.117 frystyk 119: PUBLIC BOOL HTLoadRelative (const char * relative,
1.90 frystyk 120: HTParentAnchor * base,
121: HTRequest * request)
122: {
123: BOOL status = NO;
124: if (relative && base && request) {
125: char * rel = NULL;
126: char * full_url = NULL;
127: char * base_url = HTAnchor_address((HTAnchor *) base);
128: StrAllocCopy(rel, relative);
129: full_url = HTParse(HTStrip(rel), base_url,
130: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
131: status = HTLoadAbsolute(full_url, request);
1.114 frystyk 132: HT_FREE(rel);
133: HT_FREE(full_url);
134: HT_FREE(base_url);
1.90 frystyk 135: }
136: return status;
137: }
138:
139:
140: /* Request an anchor
141: ** -----------------
142: ** Request the document referenced by the anchor
143: ** Returns YES if request accepted, else NO
144: */
145: PUBLIC BOOL HTLoadAnchor (HTAnchor * anchor, HTRequest * request)
146: {
147: if (anchor && request) {
148: HTRequest_setAnchor(request, anchor);
149: return HTLoadDocument(request, NO);
150: }
151: return NO;
152: }
153:
154:
155: /* Request an anchor
156: ** -----------------
157: ** Same as HTLoadAnchor but any information in the Error Stack in the
158: ** request object is kept, so that any error messages in one
1.52 frystyk 159: ** This function is almost identical to HTLoadAnchor, but it doesn't
160: ** clear the error stack so that the information in there is kept.
1.90 frystyk 161: ** Returns YES if request accepted, else NO
162: */
163: PUBLIC BOOL HTLoadAnchorRecursive (HTAnchor * anchor, HTRequest * request)
164: {
165: if (anchor && request) {
166: HTRequest_setAnchor(request, anchor);
167: return HTLoadDocument(request, YES);
168: }
169: return NO;
170: }
171:
1.122 ! frystyk 172:
! 173: /*
! 174: ** Load a URL to a mem buffer
! 175: ** --------------------------
! 176: ** Load a request and store the result in a memory buffer.
! 177: ** Returns chunk if OK - else NULL
! 178: */
! 179: PUBLIC HTChunk * HTLoadAnchorToChunk (HTAnchor * anchor, HTRequest * request)
! 180: {
! 181: if (anchor && request) {
! 182: HTChunk * chunk = NULL;
! 183: HTStream * target = HTStreamToChunk(request, &chunk, 0);
! 184: HTRequest_setAnchor(request, anchor);
! 185: HTRequest_setOutputStream(request, target);
! 186: if (HTLoadDocument(request, NO) == YES)
! 187: return chunk;
! 188: else {
! 189: HTChunk_delete(chunk);
! 190: return NULL;
! 191: }
! 192: }
! 193: return NULL;
! 194: }
1.90 frystyk 195:
196: /* Search an Anchor
197: ** ----------------
198: ** Performs a keyword search on word given by the user. Adds the keyword
199: ** to the end of the current address and attempts to open the new address.
200: ** The list of keywords must be a space-separated list and spaces will
201: ** be converted to '+' before the request is issued.
202: ** Search can also be performed by HTLoadAbsolute() etc.
203: ** Returns YES if request accepted, else NO
204: */
1.117 frystyk 205: PUBLIC BOOL HTSearch (const char * keywords,
1.90 frystyk 206: HTParentAnchor * base,
207: HTRequest * request)
208: {
1.99 frystyk 209: BOOL status = NO;
1.90 frystyk 210: if (keywords && base && request) {
211: char *base_url = HTAnchor_address((HTAnchor *) base);
212: if (*keywords) {
213: char *plus;
214: StrAllocCat(base_url, "?");
215: StrAllocCat(base_url, keywords);
216: plus = strchr(base_url, '?');
217: while (*plus) {
218: if (*plus == ' ') *plus = '+';
219: plus++;
220: }
1.2 timbl 221: }
1.99 frystyk 222: status = HTLoadAbsolute(base_url, request);
1.114 frystyk 223: HT_FREE(base_url);
1.90 frystyk 224: }
1.99 frystyk 225: return status;
1.2 timbl 226: }
227:
228:
1.90 frystyk 229: /* Search a document from absolute name
230: ** ------------------------------------
231: ** Request a document referencd by an absolute URL appended with the
232: ** keywords given. The URL can NOT contain any fragment identifier!
233: ** The list of keywords must be a space-separated list and spaces will
234: ** be converted to '+' before the request is issued.
235: ** Returns YES if request accepted, else NO
236: */
1.117 frystyk 237: PUBLIC BOOL HTSearchAbsolute (const char * keywords,
238: const char * url,
1.90 frystyk 239: HTRequest * request)
240: {
241: if (url && request) {
242: HTAnchor * anchor = HTAnchor_findAddress(url);
243: return HTSearch(keywords, HTAnchor_parent(anchor), request);
244: }
245: return NO;
1.57 howcome 246: }
247:
1.70 frystyk 248: /* --------------------------------------------------------------------------*/
1.104 frystyk 249: /* Post Access Functions */
1.70 frystyk 250: /* --------------------------------------------------------------------------*/
251:
1.90 frystyk 252: /* Copy an anchor
1.70 frystyk 253: ** --------------
1.90 frystyk 254: ** Fetch the URL (possibly local file URL) and send it using either PUT
255: ** or POST to the remote destination using HTTP. The caller can decide the
256: ** exact method used and which HTTP header fields to transmit by setting
257: ** the user fields in the request structure.
1.92 frystyk 258: ** If posting to NNTP then we can't dispatch at this level but must pass
259: ** the source anchor to the news module that then takes all the refs
260: ** to NNTP and puts into the "newsgroups" header
1.90 frystyk 261: ** Returns YES if request accepted, else NO
1.70 frystyk 262: */
1.109 frystyk 263: PUBLIC BOOL HTCopyAnchor (HTAnchor * src_anchor, HTRequest * main_dest)
1.80 frystyk 264: {
1.106 frystyk 265: HTRequest * src_req;
266: HTList * cur;
1.109 frystyk 267: if (!src_anchor || !main_dest) {
1.115 eric 268: if (WWWTRACE) HTTrace("Copy........ BAD ARGUMENT\n");
1.90 frystyk 269: return NO;
1.109 frystyk 270: }
1.70 frystyk 271:
1.112 frystyk 272: /* Set the source anchor */
273: main_dest->source_anchor = HTAnchor_parent(src_anchor);
274:
1.80 frystyk 275: /* Build the POST web if not already there */
1.109 frystyk 276: if (!main_dest->source) {
277: src_req = HTRequest_dupInternal(main_dest); /* Get a duplicate */
1.80 frystyk 278: HTAnchor_clearHeader((HTParentAnchor *) src_anchor);
1.109 frystyk 279: src_req->method = METHOD_GET;
1.85 frystyk 280: src_req->reload = HT_MEM_REFRESH;
1.104 frystyk 281: src_req->output_stream = NULL;
1.80 frystyk 282: src_req->output_format = WWW_SOURCE; /* We want source (for now) */
283:
284: /* Set up the main link in the source anchor */
285: {
1.106 frystyk 286: HTLink * main_link = HTAnchor_mainLink((HTAnchor *) src_anchor);
287: HTAnchor *main_anchor = HTLink_destination(main_link);
288: HTMethod method = HTLink_method(main_link);
1.85 frystyk 289: if (!main_link || method==METHOD_INVALID) {
1.91 frystyk 290: if (WWWTRACE)
1.115 eric 291: HTTrace("Copy Anchor. No destination found or unspecified method\n");
1.80 frystyk 292: HTRequest_delete(src_req);
1.90 frystyk 293: return NO;
1.80 frystyk 294: }
1.109 frystyk 295: main_dest->GenMask |= HT_G_DATE; /* Send date header */
296: main_dest->reload = HT_CACHE_REFRESH;
297: main_dest->method = method;
298: main_dest->input_format = WWW_SOURCE;
299: HTRequest_addDestination(src_req, main_dest);
300: if (HTLoadAnchor(main_anchor, main_dest) == NO)
301: return NO;
1.80 frystyk 302: }
1.78 frystyk 303:
1.80 frystyk 304: /* For all other links in the source anchor */
1.106 frystyk 305: if ((cur = HTAnchor_subLinks(src_anchor))) {
306: HTLink * pres;
1.109 frystyk 307: while ((pres = (HTLink *) HTList_nextObject(cur))) {
1.106 frystyk 308: HTAnchor *dest = HTLink_destination(pres);
309: HTMethod method = HTLink_method(pres);
1.80 frystyk 310: HTRequest *dest_req;
311: if (!dest || method==METHOD_INVALID) {
1.91 frystyk 312: if (WWWTRACE)
1.115 eric 313: HTTrace("Copy Anchor. Bad anchor setup %p\n",
1.80 frystyk 314: dest);
1.90 frystyk 315: return NO;
1.80 frystyk 316: }
1.109 frystyk 317: dest_req = HTRequest_dupInternal(main_dest);
1.107 frystyk 318: dest_req->GenMask |= HT_G_DATE; /* Send date header */
1.85 frystyk 319: dest_req->reload = HT_CACHE_REFRESH;
1.80 frystyk 320: dest_req->method = method;
1.104 frystyk 321: dest_req->output_stream = NULL;
322: dest_req->output_format = WWW_SOURCE;
1.109 frystyk 323: HTRequest_addDestination(src_req, dest_req);
1.104 frystyk 324:
1.90 frystyk 325: if (HTLoadAnchor(dest, dest_req) == NO)
326: return NO;
1.80 frystyk 327: }
328: }
329: } else { /* Use the existing Post Web and restart it */
1.109 frystyk 330: src_req = main_dest->source;
1.80 frystyk 331: if (src_req->mainDestination)
1.109 frystyk 332: if (HTLoadDocument(main_dest, NO) == NO)
1.90 frystyk 333: return NO;
1.80 frystyk 334: if (src_req->destinations) {
1.106 frystyk 335: HTRequest * pres;
336: cur = HTAnchor_subLinks(src_anchor);
1.80 frystyk 337: while ((pres = (HTRequest *) HTList_nextObject(cur)) != NULL) {
1.90 frystyk 338: if (HTLoadDocument(pres, NO) == NO)
339: return NO;
1.80 frystyk 340: }
341: }
1.78 frystyk 342: }
343:
1.80 frystyk 344: /* Now open the source */
345: return HTLoadAnchor(src_anchor, src_req);
1.70 frystyk 346: }
347:
348:
1.90 frystyk 349: /* Upload an Anchor
1.70 frystyk 350: ** ----------------
1.111 frystyk 351: ** This function can be used to send data along with a request to a remote
352: ** server. It can for example be used to POST form data to a remote HTTP
353: ** server - or it can be used to post a newsletter to a NNTP server. In
354: ** either case, you pass a callback function which the request calls when
355: ** the remote destination is ready to accept data. In this callback
356: ** you get the current request object and a stream into where you can
357: ** write data. It is very important that you return the value returned
358: ** by this stream to the Library so that it knows what to do next. The
359: ** reason is that the outgoing stream might block or an error may
360: ** occur and in that case the Library must know about it. The source
361: ** anchor represents the data object in memory and it points to
362: ** the destination anchor by using the POSTWeb method. The source anchor
363: ** contains metainformation about the data object in memory and the
364: ** destination anchor represents the reponse from the remote server.
1.90 frystyk 365: ** Returns YES if request accepted, else NO
366: */
1.111 frystyk 367: PUBLIC BOOL HTUploadAnchor (HTAnchor * source_anchor,
368: HTRequest * request,
369: HTPostCallback * callback)
370: {
371: HTLink * link = HTAnchor_mainLink((HTAnchor *) source_anchor);
372: HTAnchor * dest_anchor = HTLink_destination(link);
373: HTMethod method = HTLink_method(link);
374: if (!link || method==METHOD_INVALID || !callback) {
375: if (WWWTRACE)
1.115 eric 376: HTTrace("Upload...... No destination found or unspecified method\n");
1.90 frystyk 377: return NO;
1.109 frystyk 378: }
1.111 frystyk 379: request->GenMask |= HT_G_DATE; /* Send date header */
380: request->reload = HT_CACHE_REFRESH;
381: request->method = method;
382: request->source_anchor = HTAnchor_parent(source_anchor);
383: request->PostCallback = callback;
384: return HTLoadAnchor(dest_anchor, request);
385: }
386:
387: /* POST Callback Handler
388: ** ---------------------
389: ** If you do not want to handle the stream interface on your own, you
390: ** can use this function which writes the source anchor hyperdoc to the
391: ** target stream for the anchor upload and also handles the return value
392: ** from the stream. If you don't want to write the source anchor hyperdoc
393: ** then you can register your own callback function that can get the data
394: ** you want.
395: */
396: PUBLIC int HTUpload_callback (HTRequest * request, HTStream * target)
397: {
1.115 eric 398: if (WWWTRACE) HTTrace("Uploading... from callback function\n");
1.111 frystyk 399: if (!request || !request->source_anchor || !target) return HT_ERROR;
400: {
401: int status;
402: HTParentAnchor * source = request->source_anchor;
403: char * document = (char *) HTAnchor_document(request->source_anchor);
404: int len = HTAnchor_length(source);
405: if (len < 0) {
406: len = strlen(document);
407: HTAnchor_setLength(source, len);
408: }
409: status = (*target->isa->put_block)(target, document, len);
410: if (status == HT_OK)
411: return (*target->isa->flush)(target);
412: if (status == HT_WOULD_BLOCK) {
1.115 eric 413: if (PROT_TRACE)HTTrace("POST Anchor. Target WOULD BLOCK\n");
1.111 frystyk 414: return HT_WOULD_BLOCK;
415: } else if (status == HT_PAUSE) {
1.115 eric 416: if (PROT_TRACE) HTTrace("POST Anchor. Target PAUSED\n");
1.111 frystyk 417: return HT_PAUSE;
418: } else if (status > 0) { /* Stream specific return code */
419: if (PROT_TRACE)
1.115 eric 420: HTTrace("POST Anchor. Target returns %d\n", status);
1.111 frystyk 421: return status;
1.120 eric 422: } else { /* we have a real error */
1.115 eric 423: if (PROT_TRACE) HTTrace("POST Anchor. Target ERROR\n");
1.111 frystyk 424: return status;
425: }
1.70 frystyk 426: }
1.1 timbl 427: }
Webmaster