Annotation of libwww/Library/src/HTAccess.c, revision 1.131
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.131 ! frystyk 6: ** @(#) $Id: HTAccess.c,v 1.130 1996/08/19 18:30:10 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.123 frystyk 31: #include "WWWRules.h"
1.93 frystyk 32: #include "HTReqMan.h"
33: #include "HTAccess.h" /* Implemented here */
1.88 frystyk 34:
1.111 frystyk 35: #define PUTBLOCK(b, l) (*target->isa->put_block)(target, b, l)
36:
37: struct _HTStream {
38: HTStreamClass * isa;
39: };
40:
1.124 frystyk 41: typedef enum _HTPutState {
1.125 frystyk 42: HT_LOAD_SOURCE = 0,
1.128 frystyk 43: HT_SAVE_DEST,
44: HT_ABORT_SAVE
1.124 frystyk 45: } HTPutState;
46:
47: typedef struct _HTPutContext {
48: HTParentAnchor * source;
49: HTAnchor * destination;
50: HTChunk * document;
51: HTFormat format;
52: HTStream * target; /* Any existing output stream */
53: void * placeholder; /* Any existing doc in anchor */
54: HTPutState state;
55: } HTPutContext;
56:
1.123 frystyk 57: /* --------------------------------------------------------------------------*/
58: /* THE GET METHOD */
59: /* --------------------------------------------------------------------------*/
1.33 luotonen 60:
1.90 frystyk 61: /* Request a document
62: ** -----------------
63: ** Private version that requests a document from the request manager
64: ** Returns YES if request accepted, else NO
1.88 frystyk 65: */
1.124 frystyk 66: PRIVATE BOOL launch_request (HTRequest * request, BOOL recursive)
1.88 frystyk 67: {
68: if (PROT_TRACE) {
1.90 frystyk 69: HTParentAnchor *anchor = HTRequest_anchor(request);
70: char * full_address = HTAnchor_address((HTAnchor *) anchor);
1.115 eric 71: HTTrace("HTAccess.... Accessing document %s\n", full_address);
1.114 frystyk 72: HT_FREE(full_address);
1.88 frystyk 73: }
1.96 frystyk 74: return HTLoad(request, recursive);
1.58 frystyk 75: }
1.1 timbl 76:
1.90 frystyk 77: /* Request a document from absolute name
78: ** -------------------------------------
79: ** Request a document referencd by an absolute URL.
80: ** Returns YES if request accepted, else NO
81: */
1.122 frystyk 82: PUBLIC BOOL HTLoadAbsolute (const char * url, HTRequest * request)
1.90 frystyk 83: {
84: if (url && request) {
85: HTAnchor * anchor = HTAnchor_findAddress(url);
86: HTRequest_setAnchor(request, anchor);
1.124 frystyk 87: return launch_request(request, NO);
1.90 frystyk 88: }
89: return NO;
90: }
91:
1.123 frystyk 92: /* Request a document from relative name
93: ** -------------------------------------
94: ** Request a document referenced by a relative URL. The relative URL is
95: ** made absolute by resolving it relative to the address of the 'base'
96: ** anchor.
97: ** Returns YES if request accepted, else NO
98: */
99: PUBLIC BOOL HTLoadRelative (const char * relative,
100: HTParentAnchor * base,
101: HTRequest * request)
102: {
103: BOOL status = NO;
104: if (relative && base && request) {
105: char * full_url = NULL;
106: char * base_url = HTAnchor_address((HTAnchor *) base);
107: full_url = HTParse(relative, base_url,
108: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
109: status = HTLoadAbsolute(full_url, request);
110: HT_FREE(full_url);
111: HT_FREE(base_url);
112: }
113: return status;
114: }
1.90 frystyk 115:
116: /* Request a document from absolute name to stream
117: ** -----------------------------------------------
118: ** Request a document referencd by an absolute URL and sending the data
1.123 frystyk 119: ** down a stream.
120: ** Returns YES if request accepted, else NO
121: */
122: PUBLIC BOOL HTLoadToStream (const char * url, HTStream * output,
123: HTRequest * request)
124: {
125: if (url && output && request) {
126: HTRequest_setOutputStream(request, output);
127: return HTLoadAbsolute(url, request);
128: }
129: return NO;
130: }
131:
132: /* Load a document and save it ASIS in a local file
133: ** ------------------------------------------------
1.90 frystyk 134: ** Returns YES if request accepted, else NO
135: */
1.123 frystyk 136: PUBLIC BOOL HTLoadToFile (const char * url, HTRequest * request,
137: const char * filename)
1.90 frystyk 138: {
1.123 frystyk 139: if (url && filename && request) {
140: FILE * fp = NULL;
141:
142: /* Check if file exists. If so then ask user if we can replace it */
143: if (access(filename, F_OK) != -1) {
144: HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
145: if (prompt) {
146: if ((*prompt)(request, HT_A_CONFIRM, HT_MSG_FILE_REPLACE, NULL,
147: NULL, NULL) != YES)
148: return NO;
149: }
150: }
151:
152: /* If replace then open the file */
153: if ((fp = fopen(filename, "wb")) == NULL) {
154: HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
155: (char *) filename, strlen(filename),
156: "HTLoadToFile");
157: return NO;
158: }
159:
160: /* Set the output stream and start the request */
161: HTRequest_setOutputFormat(request, WWW_SOURCE);
162: HTRequest_setOutputStream(request, HTFWriter_new(request, fp, NO));
163: return HTLoadAbsolute(url, request);
164: }
165: return NO;
1.90 frystyk 166: }
167:
1.122 frystyk 168: /*
169: ** Load a URL to a mem buffer
170: ** --------------------------
171: ** Load a request and store the result in a memory buffer.
172: ** Returns chunk if OK - else NULL
173: */
174: PUBLIC HTChunk * HTLoadToChunk (const char * url, HTRequest * request)
175: {
176: if (url && request) {
177: HTChunk * chunk = NULL;
178: HTStream * target = HTStreamToChunk(request, &chunk, 0);
179: HTAnchor * anchor = HTAnchor_findAddress(url);
180: HTRequest_setAnchor(request, anchor);
181: HTRequest_setOutputStream(request, target);
1.124 frystyk 182: if (launch_request(request, NO) == YES)
1.122 frystyk 183: return chunk;
184: else {
185: HTChunk_delete(chunk);
186: return NULL;
187: }
188: }
189: return NULL;
190: }
1.90 frystyk 191:
192: /* Request an anchor
193: ** -----------------
194: ** Request the document referenced by the anchor
195: ** Returns YES if request accepted, else NO
196: */
197: PUBLIC BOOL HTLoadAnchor (HTAnchor * anchor, HTRequest * request)
198: {
199: if (anchor && request) {
200: HTRequest_setAnchor(request, anchor);
1.124 frystyk 201: return launch_request(request, NO);
1.90 frystyk 202: }
203: return NO;
204: }
205:
206: /* Request an anchor
207: ** -----------------
208: ** Same as HTLoadAnchor but any information in the Error Stack in the
209: ** request object is kept, so that any error messages in one
1.52 frystyk 210: ** This function is almost identical to HTLoadAnchor, but it doesn't
211: ** clear the error stack so that the information in there is kept.
1.90 frystyk 212: ** Returns YES if request accepted, else NO
213: */
214: PUBLIC BOOL HTLoadAnchorRecursive (HTAnchor * anchor, HTRequest * request)
215: {
216: if (anchor && request) {
217: HTRequest_setAnchor(request, anchor);
1.124 frystyk 218: return launch_request(request, YES);
1.90 frystyk 219: }
220: return NO;
221: }
222:
1.122 frystyk 223: /*
224: ** Load a URL to a mem buffer
225: ** --------------------------
226: ** Load a request and store the result in a memory buffer.
227: ** Returns chunk if OK - else NULL
228: */
229: PUBLIC HTChunk * HTLoadAnchorToChunk (HTAnchor * anchor, HTRequest * request)
230: {
1.124 frystyk 231: HTChunk * chunk = NULL;
1.122 frystyk 232: if (anchor && request) {
233: HTStream * target = HTStreamToChunk(request, &chunk, 0);
234: HTRequest_setAnchor(request, anchor);
235: HTRequest_setOutputStream(request, target);
1.124 frystyk 236: if (launch_request(request, NO) == YES)
1.122 frystyk 237: return chunk;
238: else {
239: HTChunk_delete(chunk);
240: return NULL;
241: }
242: }
243: return NULL;
244: }
1.90 frystyk 245:
1.123 frystyk 246: /*
247: ** Load a Rule File
248: ** ----------------
249: ** Load a rule find with the URL specified and add the set of rules to
250: ** the existing set.
251: */
252: PUBLIC BOOL HTLoadRules (const char * url)
253: {
254: BOOL status = NO;
255: if (url) {
256: HTList * list = HTList_new();
257: HTRequest * request = HTRequest_new();
258: HTRequest_setPreemptive(request, YES);
259: HTAlert_setInteractive(NO);
260: HTConversion_add(list, "application/x-www-rules", "*/*", HTRules,
261: 1.0, 0.0, 0.0);
262: HTRequest_setConversion(request, list, YES);
263: status = HTLoadAbsolute(url, request);
264: HTConversion_deleteAll(list);
265: HTRequest_delete(request);
266: }
267: return status;
268: }
269:
270: /* --------------------------------------------------------------------------*/
271: /* GET WITH KEYWORDS (SEARCH) */
272: /* --------------------------------------------------------------------------*/
273:
274: /*
275: ** This function creates a URL with a searh part as defined by RFC 1866
276: ** Both the baseurl and the keywords must be escaped.
277: **
278: ** 1. The form field names and values are escaped: space
279: ** characters are replaced by `+', and then reserved characters
280: ** are escaped as per [URL]; that is, non-alphanumeric
281: ** characters are replaced by `%HH', a percent sign and two
282: ** hexadecimal digits representing the ASCII code of the
283: ** character. Line breaks, as in multi-line text field values,
284: ** are represented as CR LF pairs, i.e. `%0D%0A'.
285: **
286: ** 2. The fields are listed in the order they appear in the
287: ** document with the name separated from the value by `=' and
288: ** the pairs separated from each other by `&'. Fields with null
289: ** values may be omitted. In particular, unselected radio
290: ** buttons and checkboxes should not appear in the encoded
291: ** data, but hidden fields with VALUE attributes present
292: ** should.
293: **
294: ** NOTE - The URI from a query form submission can be
295: ** used in a normal anchor style hyperlink.
296: ** Unfortunately, the use of the `&' character to
297: ** separate form fields interacts with its use in SGML
298: ** attribute values as an entity reference delimiter.
299: ** For example, the URI `http://host/?x=1&y=2' must be
300: ** written `<a href="http://host/?x=1&y=2"' or `<a
301: ** href="http://host/?x=1&y=2">'.
302: **
303: ** HTTP server implementors, and in particular, CGI
304: ** implementors are encouraged to support the use of
305: ** `;' in place of `&' to save users the trouble of
306: ** escaping `&' characters this way.
307: */
308: PRIVATE char * query_url_encode (const char * baseurl, HTChunk * keywords)
309: {
310: char * fullurl = NULL;
311: if (baseurl && keywords && HTChunk_size(keywords)) {
312: int len = strlen(baseurl);
313: fullurl = (char *) HT_MALLOC(len + HTChunk_size(keywords) + 2);
314: sprintf(fullurl, "%s?%s", baseurl, HTChunk_data(keywords));
315: {
316: char * ptr = fullurl+len;
317: while (*ptr) {
318: if (*ptr == ' ') *ptr = '+';
319: ptr++;
320: }
321: }
322: }
323: return fullurl;
324: }
325:
326: PRIVATE char * form_url_encode (const char * baseurl, HTAssocList * formdata)
327: {
328: if (formdata) {
329: BOOL first = YES;
330: int cnt = HTList_count((HTList *) formdata);
331: HTChunk * fullurl = HTChunk_new(128);
332: HTAssoc * pres;
1.124 frystyk 333: if (baseurl) {
334: HTChunk_puts(fullurl, baseurl);
335: HTChunk_putc(fullurl, '?');
336: }
1.123 frystyk 337: while (cnt > 0) {
338: pres = (HTAssoc *) HTList_objectAt((HTList *) formdata, --cnt);
339: if (first)
340: first = NO;
341: else
342: HTChunk_putc(fullurl, '&'); /* Could use ';' instead */
343: HTChunk_puts(fullurl, HTAssoc_name(pres));
344: HTChunk_putc(fullurl, '=');
345: HTChunk_puts(fullurl, HTAssoc_value(pres));
346: }
347: return HTChunk_toCString(fullurl);
348: }
349: return NULL;
350: }
351:
352: /* Search a document from absolute name
353: ** ------------------------------------
354: ** Request a document referencd by an absolute URL appended with the
355: ** keywords given. The URL can NOT contain any fragment identifier!
356: ** The list of keywords must be a space-separated list and spaces will
357: ** be converted to '+' before the request is issued.
358: ** Returns YES if request accepted, else NO
359: */
360: PUBLIC BOOL HTSearchAbsolute (HTChunk * keywords,
361: const char * base,
362: HTRequest * request)
363: {
364: if (keywords && base && request) {
365: char * full = query_url_encode(base, keywords);
366: if (full) {
367: HTAnchor * anchor = HTAnchor_findAddress(full);
368: HTRequest_setAnchor(request, anchor);
369: HT_FREE(full);
1.124 frystyk 370: return launch_request(request, NO);
1.123 frystyk 371: }
372: }
373: return NO;
374: }
375:
376: /* Search a document from relative name
377: ** -------------------------------------
378: ** Request a document referenced by a relative URL. The relative URL is
379: ** made absolute by resolving it relative to the address of the 'base'
380: ** anchor.
381: ** Returns YES if request accepted, else NO
382: */
383: PUBLIC BOOL HTSearchRelative (HTChunk * keywords,
384: const char * relative,
385: HTParentAnchor * base,
386: HTRequest * request)
387: {
388: BOOL status = NO;
389: if (keywords && relative && base && request) {
390: char * full_url = NULL;
391: char * base_url = HTAnchor_address((HTAnchor *) base);
392: full_url = HTParse(relative, base_url,
393: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
394: status = HTSearchAbsolute(keywords, full_url, request);
395: HT_FREE(full_url);
396: HT_FREE(base_url);
397: }
398: return status;
399: }
400:
401: /*
402: ** Search a string
403: ** ---------------
404: ** This is the same as HTSearchAbsolute but instead of using a chunk
405: ** you can pass a string.
406: */
407: PUBLIC BOOL HTSearchString (const char * keywords,
408: HTAnchor * anchor,
409: HTRequest * request)
410: {
411: BOOL status = NO;
412: if (keywords && anchor && request) {
413: char * base_url = HTAnchor_address((HTAnchor *) anchor);
414: HTChunk * chunk = HTChunk_new(strlen(keywords)+2);
415: HTChunk_puts(chunk, keywords);
416: status = HTSearchAbsolute(chunk, base_url, request);
417: HT_FREE(base_url);
418: HTChunk_delete(chunk);
419: }
420: return status;
421: }
422:
1.90 frystyk 423: /* Search an Anchor
424: ** ----------------
425: ** Performs a keyword search on word given by the user. Adds the keyword
426: ** to the end of the current address and attempts to open the new address.
427: ** The list of keywords must be a space-separated list and spaces will
428: ** be converted to '+' before the request is issued.
429: ** Search can also be performed by HTLoadAbsolute() etc.
430: ** Returns YES if request accepted, else NO
431: */
1.123 frystyk 432: PUBLIC BOOL HTSearchAnchor (HTChunk * keywords,
433: HTAnchor * anchor,
434: HTRequest * request)
1.90 frystyk 435: {
1.99 frystyk 436: BOOL status = NO;
1.123 frystyk 437: if (keywords && anchor && request) {
438: char * base_url = HTAnchor_address(anchor);
439: status = HTSearchAbsolute(keywords, base_url, request);
1.114 frystyk 440: HT_FREE(base_url);
1.90 frystyk 441: }
1.99 frystyk 442: return status;
1.2 timbl 443: }
444:
1.123 frystyk 445: /* --------------------------------------------------------------------------*/
446: /* HANDLING FORMS USING GET AND POST */
447: /* --------------------------------------------------------------------------*/
1.2 timbl 448:
1.123 frystyk 449: /* Send a Form request using GET from absolute name
450: ** ------------------------------------------------
1.90 frystyk 451: ** Request a document referencd by an absolute URL appended with the
1.123 frystyk 452: ** formdata given. The URL can NOT contain any fragment identifier!
453: ** The list of form data must be given as an association list where
454: ** the name is the field name and the value is the value of the field.
455: ** Returns YES if request accepted, else NO
456: */
457: PUBLIC BOOL HTGetFormAbsolute (HTAssocList * formdata,
458: const char * base,
459: HTRequest * request)
460: {
461: if (formdata && base && request) {
462: char * full = form_url_encode(base, formdata);
463: if (full) {
464: HTAnchor * anchor = HTAnchor_findAddress(full);
465: HTRequest_setAnchor(request, anchor);
466: HT_FREE(full);
1.124 frystyk 467: return launch_request(request, NO);
1.123 frystyk 468: }
469: }
470: return NO;
471: }
472:
473: /* Send a Form request using GET from relative name
474: ** ------------------------------------------------
475: ** Request a document referencd by a relative URL appended with the
476: ** formdata given. The URL can NOT contain any fragment identifier!
477: ** The list of form data must be given as an association list where
478: ** the name is the field name and the value is the value of the field.
479: ** Returns YES if request accepted, else NO
480: */
481: PUBLIC BOOL HTGetFormRelative (HTAssocList * formdata,
482: const char * relative,
483: HTParentAnchor * base,
484: HTRequest * request)
485: {
486: BOOL status = NO;
487: if (formdata && relative && base && request) {
488: char * full_url = NULL;
489: char * base_url = HTAnchor_address((HTAnchor *) base);
490: full_url=HTParse(relative, base_url,
491: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
492: status = HTGetFormAbsolute(formdata, full_url, request);
493: HT_FREE(full_url);
494: HT_FREE(base_url);
495: }
496: return status;
497: }
498:
499: /* Send a Form request using GET from an anchor
500: ** --------------------------------------------
501: ** Request a document referencd by an anchor object appended with the
502: ** formdata given. The URL can NOT contain any fragment identifier!
503: ** The list of form data must be given as an association list where
504: ** the name is the field name and the value is the value of the field.
1.90 frystyk 505: ** Returns YES if request accepted, else NO
506: */
1.123 frystyk 507: PUBLIC BOOL HTGetFormAnchor (HTAssocList * formdata,
508: HTAnchor * anchor,
509: HTRequest * request)
510: {
511: BOOL status = NO;
512: if (formdata && anchor && request) {
513: char * base_url = HTAnchor_address((HTAnchor *) anchor);
514: status = HTGetFormAbsolute(formdata, base_url, request);
515: HT_FREE(base_url);
516: }
517: return status;
518: }
519:
520: PRIVATE int HTEntity_callback (HTRequest * request, HTStream * target)
521: {
522: HTParentAnchor * entity = HTRequest_entityAnchor(request);
1.124 frystyk 523: if (WWWTRACE) HTTrace("Posting Data from callback function\n");
1.123 frystyk 524: if (!request || !entity || !target) return HT_ERROR;
525: {
1.126 frystyk 526: BOOL chunking = NO;
1.123 frystyk 527: int status;
528: char * document = (char *) HTAnchor_document(entity);
529: int len = HTAnchor_length(entity);
1.126 frystyk 530: if (!document) {
531: if (PROT_TRACE) HTTrace("Posting Data No document\n");
532: return HT_ERROR;
533: }
534:
535: /*
536: ** If the length is unknown (-1) then see if the document is a text
537: ** type and in that case take the strlen. If not then we don't know
538: ** how much data we can write and must stop
539: */
540: if (len < 0) {
541: HTFormat actual = HTAnchor_format(entity);
542: HTFormat tmplate = HTAtom_for("text/*");
543: if (HTMIMEMatch(tmplate, actual)) {
544: len = strlen(document); /* Naive! */
545: chunking = YES;
546: } else {
547: if (PROT_TRACE)
548: HTTrace("Posting Data Must know the length of document %p\n",
549: document);
550: return HT_ERROR;
551: }
552: }
553:
554: /* Send the data down the pipe */
1.123 frystyk 555: status = (*target->isa->put_block)(target, document, len);
1.125 frystyk 556: if (status == HT_LOADED) {
557: if (PROT_TRACE) HTTrace("Posting Data Target is SAVED\n");
558: (*target->isa->flush)(target);
559: return HT_LOADED;
560: }
1.123 frystyk 561: if (status == HT_WOULD_BLOCK) {
1.124 frystyk 562: if (PROT_TRACE)HTTrace("Posting Data Target WOULD BLOCK\n");
1.123 frystyk 563: return HT_WOULD_BLOCK;
564: } else if (status == HT_PAUSE) {
1.126 frystyk 565: if (PROT_TRACE) HTTrace("Posting Data Target PAUSED\n");
1.123 frystyk 566: return HT_PAUSE;
1.126 frystyk 567: } else if (chunking && status == HT_OK) {
568: if (PROT_TRACE) HTTrace("Posting Data Target is SAVED using chunked\n");
569: return (*target->isa->put_block)(target, "", 0);
570: } else if (status > 0) { /* Stream specific return code */
1.123 frystyk 571: if (PROT_TRACE)
1.124 frystyk 572: HTTrace("Posting Data. Target returns %d\n", status);
1.123 frystyk 573: return status;
574: } else { /* we have a real error */
1.129 frystyk 575: if (PROT_TRACE) HTTrace("Posting Data Target ERROR %d\n", status);
1.123 frystyk 576: return status;
577: }
578: }
579: }
580:
581: /* Send a Form request using POST from absolute name
582: ** -------------------------------------------------
583: ** Request a document referencd by an absolute URL appended with the
584: ** formdata given. The URL can NOT contain any fragment identifier!
585: ** The list of form data must be given as an association list where
586: ** the name is the field name and the value is the value of the field.
587: */
588: PUBLIC HTParentAnchor * HTPostFormAbsolute (HTAssocList * formdata,
589: const char * base,
590: HTRequest * request)
591: {
592: if (formdata && base && request) {
593: HTAnchor * anchor = HTAnchor_findAddress(base);
594: return HTPostFormAnchor(formdata, anchor, request);
595: }
596: return NULL;
597: }
598:
599: /* Send a Form request using POST from relative name
600: ** -------------------------------------------------
601: ** Request a document referencd by a relative URL appended with the
602: ** formdata given. The URL can NOT contain any fragment identifier!
603: ** The list of form data must be given as an association list where
604: ** the name is the field name and the value is the value of the field.
605: */
606: PUBLIC HTParentAnchor * HTPostFormRelative (HTAssocList * formdata,
607: const char * relative,
608: HTParentAnchor * base,
609: HTRequest * request)
1.90 frystyk 610: {
1.123 frystyk 611: HTParentAnchor * postanchor = NULL;
612: if (formdata && relative && base && request) {
613: char * full_url = NULL;
614: char * base_url = HTAnchor_address((HTAnchor *) base);
615: full_url=HTParse(relative, base_url,
616: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
617: postanchor = HTPostFormAbsolute(formdata, full_url, request);
618: HT_FREE(full_url);
619: HT_FREE(base_url);
620: }
621: return postanchor;
622: }
623:
624: /* Send a Form request using POST from an anchor
625: ** ---------------------------------------------
626: ** Request a document referencd by an anchor object appended with the
627: ** formdata given. The URL can NOT contain any fragment identifier!
628: ** The list of form data must be given as an association list where
629: ** the name is the field name and the value is the value of the field.
630: */
631: PUBLIC HTParentAnchor * HTPostFormAnchor (HTAssocList * formdata,
632: HTAnchor * anchor,
633: HTRequest * request)
634: {
635: HTParentAnchor * postanchor = NULL;
636: if (formdata && anchor && request) {
637: HTUserProfile * up = HTRequest_userProfile(request);
638: char * tmpfile = HTGetTmpFileName(HTUserProfile_tmp(up));
639: char * tmpurl = HTParse(tmpfile, "file:", PARSE_ALL);
640: char * form_encoded = form_url_encode(NULL, formdata);
641: if (form_encoded) {
642:
643: /*
644: ** Now create a new anchor for the post data and set up
645: ** the rest of the metainformation we know about this anchor. The
646: ** tmp anchor may actually already exist from previous postings.
647: */
648: postanchor = (HTParentAnchor *) HTAnchor_findAddress(tmpurl);
649: HTAnchor_clearHeader(postanchor);
650: HTAnchor_setDocument(postanchor, form_encoded);
651: HTAnchor_setLength(postanchor, strlen(form_encoded));
652: HTAnchor_setFormat(postanchor, WWW_FORM);
653:
654: /*
655: ** Bind the temporary anchor to the anchor that will contain the
656: ** response
657: */
658: HTLink_removeAll((HTAnchor *) postanchor);
659: HTLink_add((HTAnchor *) postanchor, (HTAnchor *) anchor,
660: NULL, METHOD_POST);
661:
662: /* Set up the request object */
663: HTRequest_addGnHd(request, HT_G_DATE); /* Send date header */
664: HTRequest_setAnchor(request, anchor);
665: HTRequest_setEntityAnchor(request, postanchor);
666: HTRequest_setMethod(request, METHOD_POST);
667:
668: /* Add the post form callback function to provide the form data */
669: HTRequest_setPostCallback(request, HTEntity_callback);
670:
671: /* Now start the load normally */
1.124 frystyk 672: launch_request(request, NO);
1.123 frystyk 673: }
674: HT_FREE(tmpfile);
675: HT_FREE(tmpurl);
1.90 frystyk 676: }
1.123 frystyk 677: return postanchor;
1.57 howcome 678: }
679:
1.70 frystyk 680: /* --------------------------------------------------------------------------*/
1.124 frystyk 681: /* PUT A DOCUMENT */
682: /* --------------------------------------------------------------------------*/
1.125 frystyk 683: PRIVATE BOOL setup_anchors (HTRequest * request,
1.131 ! frystyk 684: HTParentAnchor * source, HTParentAnchor * dest,
! 685: HTMethod method)
1.124 frystyk 686: {
1.131 ! frystyk 687: if (!(method & (METHOD_PUT | METHOD_POST))) {
! 688: if (APP_TRACE) HTTrace("Posting..... Bad method\n");
! 689: return NO;
! 690: }
! 691:
1.124 frystyk 692: /*
1.127 frystyk 693: ** Check whether we know if it is possible to PUT to this destination.
694: ** We both check the local set of allowed methods in the anchor and any
695: ** site information that we may have about the location of the origin
696: ** server.
1.124 frystyk 697: */
698: {
1.131 ! frystyk 699: char * addr = HTAnchor_address((HTAnchor *) source);
! 700: char * hostname = HTParse(addr, "", PARSE_HOST);
! 701: HTHost * host = HTHost_find(hostname);
! 702: HTMethod public_methods = HTHost_publicMethods(host);
! 703: HTMethod private_methods = HTAnchor_methods(dest);
! 704: HT_FREE(hostname);
! 705: HT_FREE(addr);
! 706: if (!(method & (private_methods | public_methods))) {
1.124 frystyk 707: HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
708: if (prompt) {
709: if ((*prompt)(request, HT_A_CONFIRM, HT_MSG_METHOD,
710: NULL, NULL, NULL) != YES)
711: return NO;
712: }
713: }
714: }
715:
716: /*
717: ** Bind the source anchor to the dest anchor that will contain the
718: ** response. If link already exists then ask is we should do it again.
719: ** If so then remove the old link and replace it with a new one.
720: */
721: {
722: HTLink *link = HTLink_find((HTAnchor *) source, (HTAnchor *) dest);
723: if (link && HTLink_method(link) == METHOD_PUT) {
724: HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
725: if (prompt) {
726: if ((*prompt)(request, HT_A_CONFIRM, HT_MSG_REDO,
727: NULL, NULL, NULL) != YES)
728: return NO;
729: }
730: HTLink_remove((HTAnchor *) source, (HTAnchor *) dest);
731: }
732: HTLink_add((HTAnchor*) source, (HTAnchor*) dest, NULL, METHOD_PUT);
733: }
734: return YES;
735: }
736:
737: /* Send an Anchor using PUT from absolute name
738: ** -------------------------------------------
739: ** Upload a document referenced by an absolute URL appended.
740: ** The URL can NOT contain any fragment identifier!
741: ** The list of form data must be given as an association list where
742: ** the name is the field name and the value is the value of the field.
743: */
744: PUBLIC BOOL HTPutAbsolute (HTParentAnchor * source,
745: const char * destination,
746: HTRequest * request)
747: {
748: if (source && destination && request) {
749: HTAnchor * dest = HTAnchor_findAddress(destination);
750: return HTPutAnchor(source, dest, request);
751: }
752: return NO;
753: }
754:
755: /* Send an Anchor using PUT from relative name
756: ** -------------------------------------------
757: ** Upload a document referenced by a relative URL appended.
758: ** The URL can NOT contain any fragment identifier!
759: ** The list of form data must be given as an association list where
760: ** the name is the field name and the value is the value of the field.
761: */
762: PUBLIC BOOL HTPutRelative (HTParentAnchor * source,
763: const char * relative,
764: HTParentAnchor * destination_base,
765: HTRequest * request)
766: {
767: if (source && relative && destination_base && request) {
768: BOOL status;
769: char * full_url = NULL;
770: char * base_url = HTAnchor_address((HTAnchor *) destination_base);
771: full_url=HTParse(relative, base_url,
772: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
773: status = HTPutAbsolute(source, full_url, request);
774: HT_FREE(full_url);
775: HT_FREE(base_url);
776: return status;
777: }
778: return NO;
779: }
780:
781: /* Send an Anchor using PUT from an anchor
782: ** ---------------------------------------
783: ** Upload a document referenced by an anchor object appended
784: ** The URL can NOT contain any fragment identifier!
785: ** The list of form data must be given as an association list where
786: ** the name is the field name and the value is the value of the field.
787: */
788: PUBLIC BOOL HTPutAnchor (HTParentAnchor * source,
789: HTAnchor * destination,
790: HTRequest * request)
791: {
792: HTParentAnchor * dest = HTAnchor_parent(destination);
793: if (source && dest && request) {
1.131 ! frystyk 794: if (setup_anchors(request, source, dest, METHOD_PUT) == YES) {
1.124 frystyk 795:
796: /* Set up the request object */
797: HTRequest_addGnHd(request, HT_G_DATE);
798: HTRequest_setEntityAnchor(request, source);
799: HTRequest_setMethod(request, METHOD_PUT);
800: HTRequest_setAnchor(request, destination);
801:
802: /* Add the entity callback function to provide the form data */
803: HTRequest_setPostCallback(request, HTEntity_callback);
804:
805: /* Now start the load normally */
806: return launch_request(request, NO);
807: }
808: }
809: return NO;
810: }
811:
1.125 frystyk 812: /* Send an Anchor using POST from absolute name
813: ** -------------------------------------------
814: ** Upload a document referenced by an absolute URL appended.
815: ** The URL can NOT contain any fragment identifier!
816: ** The list of form data must be given as an association list where
817: ** the name is the field name and the value is the value of the field.
818: */
819: PUBLIC BOOL HTPostAbsolute (HTParentAnchor * source,
820: const char * destination,
821: HTRequest * request)
822: {
823: if (source && destination && request) {
824: HTAnchor * dest = HTAnchor_findAddress(destination);
825: return HTPostAnchor(source, dest, request);
826: }
827: return NO;
828: }
829:
830: /* Send an Anchor using POST from relative name
831: ** -------------------------------------------
832: ** Upload a document referenced by a relative URL appended.
833: ** The URL can NOT contain any fragment identifier!
834: ** The list of form data must be given as an association list where
835: ** the name is the field name and the value is the value of the field.
836: */
837: PUBLIC BOOL HTPostRelative (HTParentAnchor * source,
838: const char * relative,
839: HTParentAnchor * destination_base,
840: HTRequest * request)
841: {
842: if (source && relative && destination_base && request) {
843: BOOL status;
844: char * full_url = NULL;
845: char * base_url = HTAnchor_address((HTAnchor *) destination_base);
846: full_url=HTParse(relative, base_url,
847: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
848: status = HTPostAbsolute(source, full_url, request);
849: HT_FREE(full_url);
850: HT_FREE(base_url);
851: return status;
852: }
853: return NO;
854: }
855:
856: /* Send an Anchor using POST from an anchor
857: ** ---------------------------------------
858: ** Upload a document referenced by an anchor object appended
859: ** The URL can NOT contain any fragment identifier!
860: ** The list of form data must be given as an association list where
861: ** the name is the field name and the value is the value of the field.
862: */
863: PUBLIC BOOL HTPostAnchor (HTParentAnchor * source,
864: HTAnchor * destination,
865: HTRequest * request)
866: {
867: HTParentAnchor * dest = HTAnchor_parent(destination);
868: if (source && dest && request) {
1.131 ! frystyk 869: if (setup_anchors(request, source, dest, METHOD_POST) == YES) {
1.125 frystyk 870:
871: /* Set up the request object */
872: HTRequest_addGnHd(request, HT_G_DATE);
873: HTRequest_setEntityAnchor(request, source);
874: HTRequest_setMethod(request, METHOD_POST);
875: HTRequest_setAnchor(request, destination);
876:
877: /* Add the entity callback function to provide the form data */
878: HTRequest_setPostCallback(request, HTEntity_callback);
879:
880: /* Now start the load normally */
881: return launch_request(request, NO);
882: }
883: }
884: return NO;
885: }
886:
1.124 frystyk 887: /* Send an Anchor using PUT from absolute name
888: ** -------------------------------------------
889: ** Upload a document referenced by an absolute URL appended.
890: ** The URL can NOT contain any fragment identifier!
891: ** The list of form data must be given as an association list where
892: ** the name is the field name and the value is the value of the field.
893: */
894: PUBLIC BOOL HTPutStructuredAbsolute (HTParentAnchor * source,
895: const char * destination,
896: HTRequest * request,
897: HTPostCallback * input)
898: {
899: if (source && destination && request && input) {
900: HTAnchor * dest = HTAnchor_findAddress(destination);
901: return HTPutStructuredAnchor(source, dest, request, input);
902: }
903: return NO;
904: }
905:
906: /* Send an Anchor using PUT from relative name
907: ** -------------------------------------------
908: ** Upload a document referenced by a relative URL appended.
909: ** The URL can NOT contain any fragment identifier!
910: ** The list of form data must be given as an association list where
911: ** the name is the field name and the value is the value of the field.
912: */
913: PUBLIC BOOL HTPutStructuredRelative (HTParentAnchor * source,
914: const char * relative,
915: HTParentAnchor * destination_base,
916: HTRequest * request,
917: HTPostCallback * input)
918: {
919: if (source && relative && destination_base && request && input) {
920: BOOL status;
921: char * full_url = NULL;
922: char * base_url = HTAnchor_address((HTAnchor *) destination_base);
923: full_url=HTParse(relative, base_url,
924: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
925: status = HTPutStructuredAbsolute(source, full_url, request, input);
926: HT_FREE(full_url);
927: HT_FREE(base_url);
928: return status;
929: }
930: return NO;
931: }
932:
933: /* Send an Anchor using PUT from an anchor
934: ** ---------------------------------------
935: ** Upload a document referenced by an anchor object appended
936: ** The URL can NOT contain any fragment identifier!
937: ** The list of form data must be given as an association list where
938: ** the name is the field name and the value is the value of the field.
939: */
940: PUBLIC BOOL HTPutStructuredAnchor (HTParentAnchor * source,
941: HTAnchor * destination,
942: HTRequest * request,
943: HTPostCallback * input)
944: {
945: HTParentAnchor * dest = HTAnchor_parent(destination);
946: if (source && dest && request) {
1.131 ! frystyk 947: if (setup_anchors(request, source, dest, METHOD_PUT) == YES) {
1.124 frystyk 948:
949: /* Set up the request object */
950: HTRequest_addGnHd(request, HT_G_DATE);
951: HTRequest_setEntityAnchor(request, source);
952: HTRequest_setMethod(request, METHOD_PUT);
953: HTRequest_setAnchor(request, destination);
954:
955: /* Add the entity callback function to provide the form data */
956: HTRequest_setPostCallback(request, input);
957:
958: /* Now start the load normally */
959: return launch_request(request, NO);
960: }
961: }
962: return NO;
963: }
964:
965: /*
966: ** After filter for handling PUT of document. We should now have the
967: */
968: PRIVATE int HTSaveFilter (HTRequest * request, void * param, int status)
969: {
970: HTPutContext * me = (HTPutContext *) param;
971: if (APP_TRACE)
972: HTTrace("Save Filter. Using context %p with state %c\n",
973: me, me->state+0x30);
974:
975: /*
1.125 frystyk 976: ** Just ignore authentication in the hope that some other filter will
977: ** handle this.
978: */
979: if (status == HT_NO_ACCESS || status == HT_NO_PROXY_ACCESS) {
980: if (APP_TRACE) HTTrace("Save Filter. Waiting for authentication\n");
981: return HT_OK;
982: }
983:
984: /*
1.124 frystyk 985: ** If either the source or the destination has moved then ask the user
986: ** what to do. If there is no user then stop
987: */
988: if (status == HT_TEMP_REDIRECT || status == HT_PERM_REDIRECT) {
989: HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
990: HTAnchor * redirection = HTRequest_redirection(request);
991: if (prompt && redirection) {
1.125 frystyk 992: if (me->state == HT_LOAD_SOURCE) {
1.124 frystyk 993: if ((*prompt)(request, HT_A_CONFIRM, HT_MSG_SOURCE_MOVED,
994: NULL, NULL, NULL) == YES) {
995: me->source = HTAnchor_parent(redirection);
1.128 frystyk 996: } else {
997: /*
998: ** Make sure that the operation stops
999: */
1000: me->state = HT_ABORT_SAVE;
1.124 frystyk 1001: }
1002: } else {
1003: if ((*prompt)(request, HT_A_CONFIRM, HT_MSG_DESTINATION_MOVED,
1004: NULL, NULL, NULL) == YES) {
1005: me->destination = redirection;
1.128 frystyk 1006: } else {
1007: /*
1008: ** Make sure that the operation stops
1009: */
1010: me->state = HT_ABORT_SAVE;
1.124 frystyk 1011: }
1012: }
1013: }
1.128 frystyk 1014: return HT_OK;
1.124 frystyk 1015: }
1016:
1017: /*
1.125 frystyk 1018: ** If we succeeded getting the source then start the PUT itself. Otherwise
1019: ** cleanup the mess
1.124 frystyk 1020: */
1.125 frystyk 1021: if (me->state == HT_LOAD_SOURCE && status == HT_LOADED &&
1022: !HTError_hasSeverity(HTRequest_error(request), ERR_INFO)) {
1.124 frystyk 1023:
1024: /* Swap the document in the anchor with the new one */
1025: me->placeholder = HTAnchor_document(me->source);
1026: HTAnchor_setDocument(me->source, HTChunk_data(me->document));
1027:
1028: /* Set up the request object */
1029: HTRequest_addGnHd(request, HT_G_DATE);
1030: HTRequest_setEntityAnchor(request, me->source);
1031: HTRequest_setMethod(request, METHOD_PUT);
1032: HTRequest_setAnchor(request, me->destination);
1033: HTRequest_setOutputFormat(request, me->format);
1034: HTRequest_setOutputStream(request, me->target);
1035:
1.125 frystyk 1036: /* Turn progress notifications back on */
1037: HTRequest_setInternal(request, NO);
1038:
1.124 frystyk 1039: /* Add the entity callback function to provide the form data */
1040: HTRequest_setPostCallback(request, HTEntity_callback);
1041:
1042: /* Now start the load normally */
1043: me->state = launch_request(request, NO) ?
1.125 frystyk 1044: HT_SAVE_DEST : HT_LOAD_SOURCE;
1.124 frystyk 1045:
1046: /*
1047: ** By returning HT_ERROR we make sure that this is the last handler to
1048: ** be called. We do this as we don't want any other filter to delete
1049: ** the request object now when we have just started a new one
1050: ** ourselves
1051: */
1052: return HT_ERROR;
1053:
1054: } else {
1055: HTRequest_deleteAfter(request, HTSaveFilter);
1056: HTAnchor_setDocument(me->source, me->placeholder);
1057: HTChunk_delete(me->document);
1058: HT_FREE(me);
1059: }
1060: return HT_OK;
1061: }
1062:
1063: /* Send an Anchor using PUT from absolute name
1064: ** -------------------------------------------
1065: ** Upload a document referenced by an absolute URL appended.
1066: ** The URL can NOT contain any fragment identifier!
1067: ** The list of form data must be given as an association list where
1068: ** the name is the field name and the value is the value of the field.
1069: */
1070: PUBLIC BOOL HTPutDocumentAbsolute (HTParentAnchor * source,
1071: const char * destination,
1072: HTRequest * request)
1073: {
1074: if (source && destination && request) {
1075: HTAnchor * dest = HTAnchor_findAddress(destination);
1076: return HTPutDocumentAnchor(source, dest, request);
1077: }
1078: return NO;
1079: }
1080:
1081: /* Send an Anchor using PUT from relative name
1082: ** -------------------------------------------
1083: ** Upload a document referenced by a relative URL appended.
1084: ** The URL can NOT contain any fragment identifier!
1085: ** The list of form data must be given as an association list where
1086: ** the name is the field name and the value is the value of the field.
1087: */
1088: PUBLIC BOOL HTPutDocumentRelative (HTParentAnchor * source,
1089: const char * relative,
1090: HTParentAnchor * destination_base,
1091: HTRequest * request)
1092: {
1093: if (source && relative && destination_base && request) {
1094: BOOL status;
1095: char * full_url = NULL;
1096: char * base_url = HTAnchor_address((HTAnchor *) destination_base);
1097: full_url=HTParse(relative, base_url,
1098: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1099: status = HTPutDocumentAbsolute(source, full_url, request);
1100: HT_FREE(full_url);
1101: HT_FREE(base_url);
1102: return status;
1103: }
1104: return NO;
1105: }
1106:
1107: /* Send an Anchor using PUT from an anchor
1108: ** ---------------------------------------
1109: ** Upload a document referenced by an anchor object appended
1110: ** The URL can NOT contain any fragment identifier!
1111: ** The source document is first loaded into memory and then the PUT
1112: ** to the remote server is done using the memory version
1113: */
1114: PUBLIC BOOL HTPutDocumentAnchor (HTParentAnchor * source,
1115: HTAnchor * destination,
1116: HTRequest * request)
1117: {
1118: HTParentAnchor * dest = HTAnchor_parent(destination);
1119: if (source && dest && request) {
1.131 ! frystyk 1120: if (setup_anchors(request, source, dest, METHOD_PUT) == YES) {
1.124 frystyk 1121: HTPutContext * context = NULL;
1122:
1123: /*
1124: ** First we register an AFTER filter that can check the result
1125: ** of the source load if success then it can start the PUT
1126: ** operation to the destination.
1127: */
1128: if (!(context=(HTPutContext *) HT_CALLOC(1, sizeof(HTPutContext))))
1129: HT_OUTOFMEM("HTPutDocumentAnchor");
1130: context->source = source;
1131: context->destination = destination;
1132: HTRequest_addAfter(request, HTSaveFilter, context, HT_ALL, NO);
1.125 frystyk 1133:
1134: /* Turn off progress notifications */
1135: HTRequest_setInternal(request, YES);
1.124 frystyk 1136:
1137: /*
1138: ** We make sure that we are not using a memory cached element.
1139: ** It's OK to use a file cached element!
1140: */
1141: HTRequest_setReloadMode(request, HT_MEM_REFRESH);
1142:
1143: /*
1144: ** Now we load the source document into a chunk. We specify that
1145: ** we want the document ASIS from the source location.
1146: */
1147: context->format = HTRequest_outputFormat(request);
1148: context->target = HTRequest_outputStream(request);
1149: HTRequest_setOutputFormat(request, WWW_SOURCE);
1150: context->document = HTLoadAnchorToChunk((HTAnchor*)source,request);
1151: if (context->document == NULL) {
1152: if (APP_TRACE) HTTrace("Put Document No source\n");
1153: HT_FREE(context);
1154: return NO;
1155: }
1156: return YES;
1157: }
1158: }
1159: return NO;
1160: }
1161:
1162: /* ------------------------------------------------------------------------- */
1.70 frystyk 1163:
1.90 frystyk 1164: /* Copy an anchor
1.70 frystyk 1165: ** --------------
1.90 frystyk 1166: ** Fetch the URL (possibly local file URL) and send it using either PUT
1167: ** or POST to the remote destination using HTTP. The caller can decide the
1168: ** exact method used and which HTTP header fields to transmit by setting
1169: ** the user fields in the request structure.
1.92 frystyk 1170: ** If posting to NNTP then we can't dispatch at this level but must pass
1171: ** the source anchor to the news module that then takes all the refs
1172: ** to NNTP and puts into the "newsgroups" header
1.70 frystyk 1173: */
1.109 frystyk 1174: PUBLIC BOOL HTCopyAnchor (HTAnchor * src_anchor, HTRequest * main_dest)
1.80 frystyk 1175: {
1.106 frystyk 1176: HTRequest * src_req;
1177: HTList * cur;
1.109 frystyk 1178: if (!src_anchor || !main_dest) {
1.115 eric 1179: if (WWWTRACE) HTTrace("Copy........ BAD ARGUMENT\n");
1.90 frystyk 1180: return NO;
1.109 frystyk 1181: }
1.70 frystyk 1182:
1.112 frystyk 1183: /* Set the source anchor */
1184: main_dest->source_anchor = HTAnchor_parent(src_anchor);
1185:
1.80 frystyk 1186: /* Build the POST web if not already there */
1.109 frystyk 1187: if (!main_dest->source) {
1188: src_req = HTRequest_dupInternal(main_dest); /* Get a duplicate */
1.80 frystyk 1189: HTAnchor_clearHeader((HTParentAnchor *) src_anchor);
1.109 frystyk 1190: src_req->method = METHOD_GET;
1.85 frystyk 1191: src_req->reload = HT_MEM_REFRESH;
1.104 frystyk 1192: src_req->output_stream = NULL;
1.80 frystyk 1193: src_req->output_format = WWW_SOURCE; /* We want source (for now) */
1194:
1195: /* Set up the main link in the source anchor */
1196: {
1.106 frystyk 1197: HTLink * main_link = HTAnchor_mainLink((HTAnchor *) src_anchor);
1198: HTAnchor *main_anchor = HTLink_destination(main_link);
1199: HTMethod method = HTLink_method(main_link);
1.85 frystyk 1200: if (!main_link || method==METHOD_INVALID) {
1.91 frystyk 1201: if (WWWTRACE)
1.115 eric 1202: HTTrace("Copy Anchor. No destination found or unspecified method\n");
1.80 frystyk 1203: HTRequest_delete(src_req);
1.90 frystyk 1204: return NO;
1.80 frystyk 1205: }
1.109 frystyk 1206: main_dest->GenMask |= HT_G_DATE; /* Send date header */
1207: main_dest->reload = HT_CACHE_REFRESH;
1208: main_dest->method = method;
1209: main_dest->input_format = WWW_SOURCE;
1210: HTRequest_addDestination(src_req, main_dest);
1211: if (HTLoadAnchor(main_anchor, main_dest) == NO)
1212: return NO;
1.80 frystyk 1213: }
1.78 frystyk 1214:
1.80 frystyk 1215: /* For all other links in the source anchor */
1.106 frystyk 1216: if ((cur = HTAnchor_subLinks(src_anchor))) {
1217: HTLink * pres;
1.109 frystyk 1218: while ((pres = (HTLink *) HTList_nextObject(cur))) {
1.106 frystyk 1219: HTAnchor *dest = HTLink_destination(pres);
1220: HTMethod method = HTLink_method(pres);
1.80 frystyk 1221: HTRequest *dest_req;
1222: if (!dest || method==METHOD_INVALID) {
1.91 frystyk 1223: if (WWWTRACE)
1.115 eric 1224: HTTrace("Copy Anchor. Bad anchor setup %p\n",
1.80 frystyk 1225: dest);
1.90 frystyk 1226: return NO;
1.80 frystyk 1227: }
1.109 frystyk 1228: dest_req = HTRequest_dupInternal(main_dest);
1.107 frystyk 1229: dest_req->GenMask |= HT_G_DATE; /* Send date header */
1.85 frystyk 1230: dest_req->reload = HT_CACHE_REFRESH;
1.80 frystyk 1231: dest_req->method = method;
1.104 frystyk 1232: dest_req->output_stream = NULL;
1233: dest_req->output_format = WWW_SOURCE;
1.109 frystyk 1234: HTRequest_addDestination(src_req, dest_req);
1.104 frystyk 1235:
1.90 frystyk 1236: if (HTLoadAnchor(dest, dest_req) == NO)
1237: return NO;
1.80 frystyk 1238: }
1239: }
1240: } else { /* Use the existing Post Web and restart it */
1.109 frystyk 1241: src_req = main_dest->source;
1.80 frystyk 1242: if (src_req->mainDestination)
1.124 frystyk 1243: if (launch_request(main_dest, NO) == NO)
1.90 frystyk 1244: return NO;
1.80 frystyk 1245: if (src_req->destinations) {
1.106 frystyk 1246: HTRequest * pres;
1247: cur = HTAnchor_subLinks(src_anchor);
1.80 frystyk 1248: while ((pres = (HTRequest *) HTList_nextObject(cur)) != NULL) {
1.124 frystyk 1249: if (launch_request(pres, NO) == NO)
1.90 frystyk 1250: return NO;
1.80 frystyk 1251: }
1252: }
1.78 frystyk 1253: }
1254:
1.80 frystyk 1255: /* Now open the source */
1256: return HTLoadAnchor(src_anchor, src_req);
1.70 frystyk 1257: }
1258:
1.90 frystyk 1259: /* Upload an Anchor
1.70 frystyk 1260: ** ----------------
1.111 frystyk 1261: ** This function can be used to send data along with a request to a remote
1262: ** server. It can for example be used to POST form data to a remote HTTP
1263: ** server - or it can be used to post a newsletter to a NNTP server. In
1264: ** either case, you pass a callback function which the request calls when
1265: ** the remote destination is ready to accept data. In this callback
1266: ** you get the current request object and a stream into where you can
1267: ** write data. It is very important that you return the value returned
1268: ** by this stream to the Library so that it knows what to do next. The
1269: ** reason is that the outgoing stream might block or an error may
1270: ** occur and in that case the Library must know about it. The source
1271: ** anchor represents the data object in memory and it points to
1272: ** the destination anchor by using the POSTWeb method. The source anchor
1273: ** contains metainformation about the data object in memory and the
1274: ** destination anchor represents the reponse from the remote server.
1.90 frystyk 1275: ** Returns YES if request accepted, else NO
1276: */
1.111 frystyk 1277: PUBLIC BOOL HTUploadAnchor (HTAnchor * source_anchor,
1278: HTRequest * request,
1279: HTPostCallback * callback)
1280: {
1281: HTLink * link = HTAnchor_mainLink((HTAnchor *) source_anchor);
1282: HTAnchor * dest_anchor = HTLink_destination(link);
1283: HTMethod method = HTLink_method(link);
1284: if (!link || method==METHOD_INVALID || !callback) {
1285: if (WWWTRACE)
1.115 eric 1286: HTTrace("Upload...... No destination found or unspecified method\n");
1.90 frystyk 1287: return NO;
1.109 frystyk 1288: }
1.111 frystyk 1289: request->GenMask |= HT_G_DATE; /* Send date header */
1290: request->reload = HT_CACHE_REFRESH;
1291: request->method = method;
1292: request->source_anchor = HTAnchor_parent(source_anchor);
1293: request->PostCallback = callback;
1294: return HTLoadAnchor(dest_anchor, request);
1295: }
1296:
1297: /* POST Callback Handler
1298: ** ---------------------
1299: ** If you do not want to handle the stream interface on your own, you
1300: ** can use this function which writes the source anchor hyperdoc to the
1301: ** target stream for the anchor upload and also handles the return value
1302: ** from the stream. If you don't want to write the source anchor hyperdoc
1303: ** then you can register your own callback function that can get the data
1304: ** you want.
1305: */
1306: PUBLIC int HTUpload_callback (HTRequest * request, HTStream * target)
1307: {
1.115 eric 1308: if (WWWTRACE) HTTrace("Uploading... from callback function\n");
1.111 frystyk 1309: if (!request || !request->source_anchor || !target) return HT_ERROR;
1310: {
1311: int status;
1312: HTParentAnchor * source = request->source_anchor;
1313: char * document = (char *) HTAnchor_document(request->source_anchor);
1314: int len = HTAnchor_length(source);
1315: if (len < 0) {
1316: len = strlen(document);
1317: HTAnchor_setLength(source, len);
1318: }
1319: status = (*target->isa->put_block)(target, document, len);
1320: if (status == HT_OK)
1321: return (*target->isa->flush)(target);
1322: if (status == HT_WOULD_BLOCK) {
1.115 eric 1323: if (PROT_TRACE)HTTrace("POST Anchor. Target WOULD BLOCK\n");
1.111 frystyk 1324: return HT_WOULD_BLOCK;
1325: } else if (status == HT_PAUSE) {
1.115 eric 1326: if (PROT_TRACE) HTTrace("POST Anchor. Target PAUSED\n");
1.111 frystyk 1327: return HT_PAUSE;
1328: } else if (status > 0) { /* Stream specific return code */
1329: if (PROT_TRACE)
1.115 eric 1330: HTTrace("POST Anchor. Target returns %d\n", status);
1.111 frystyk 1331: return status;
1.120 eric 1332: } else { /* we have a real error */
1.115 eric 1333: if (PROT_TRACE) HTTrace("POST Anchor. Target ERROR\n");
1.111 frystyk 1334: return status;
1335: }
1.70 frystyk 1336: }
1.123 frystyk 1337: }
1338:
1339: /* ------------------------------------------------------------------------- */
1340: /* HEAD METHOD */
1341: /* ------------------------------------------------------------------------- */
1342:
1343: /* Request metainformation about a document from absolute name
1344: ** -----------------------------------------------------------
1345: ** Request a document referencd by an absolute URL.
1346: ** Returns YES if request accepted, else NO
1347: */
1348: PUBLIC BOOL HTHeadAbsolute (const char * url, HTRequest * request)
1349: {
1350: if (url && request) {
1351: HTAnchor * anchor = HTAnchor_findAddress(url);
1.124 frystyk 1352: return HTHeadAnchor(anchor, request);
1.123 frystyk 1353: }
1354: return NO;
1355: }
1356:
1357: /* Request metainformation about a document from relative name
1358: ** -----------------------------------------------------------
1359: ** Request a document referenced by a relative URL. The relative URL is
1360: ** made absolute by resolving it relative to the address of the 'base'
1361: ** anchor.
1362: ** Returns YES if request accepted, else NO
1363: */
1364: PUBLIC BOOL HTHeadRelative (const char * relative,
1365: HTParentAnchor * base,
1366: HTRequest * request)
1367: {
1368: BOOL status = NO;
1369: if (relative && base && request) {
1370: char * rel = NULL;
1371: char * full_url = NULL;
1372: char * base_url = HTAnchor_address((HTAnchor *) base);
1373: StrAllocCopy(rel, relative);
1374: full_url = HTParse(HTStrip(rel), base_url,
1375: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.124 frystyk 1376: status = HTHeadAbsolute(full_url, request);
1.123 frystyk 1377: HT_FREE(rel);
1378: HT_FREE(full_url);
1379: HT_FREE(base_url);
1380: }
1381: return status;
1382: }
1383:
1384: /* Request metainformation about an anchor
1385: ** --------------------------------------
1386: ** Request the document referenced by the anchor
1387: ** Returns YES if request accepted, else NO
1388: */
1389: PUBLIC BOOL HTHeadAnchor (HTAnchor * anchor, HTRequest * request)
1390: {
1391: if (anchor && request) {
1392: HTRequest_setAnchor(request, anchor);
1.130 frystyk 1393: HTRequest_setOutputFormat(request, WWW_DEBUG);
1.123 frystyk 1394: HTRequest_setMethod(request, METHOD_HEAD);
1.124 frystyk 1395: return launch_request(request, NO);
1.123 frystyk 1396: }
1397: return NO;
1398: }
1399:
1400: /* ------------------------------------------------------------------------- */
1401: /* DELETE METHOD */
1402: /* ------------------------------------------------------------------------- */
1403:
1404: /* Delete a document on a remote server
1405: ** ------------------------------------
1406: ** Request a document referencd by an absolute URL.
1407: ** Returns YES if request accepted, else NO
1408: */
1409: PUBLIC BOOL HTDeleteAbsolute (const char * url, HTRequest * request)
1410: {
1411: if (url && request) {
1412: HTAnchor * anchor = HTAnchor_findAddress(url);
1.124 frystyk 1413: return HTDeleteAnchor(anchor, request);
1.123 frystyk 1414: }
1415: return NO;
1416: }
1417:
1418: /* Request metainformation about a document from relative name
1419: ** -----------------------------------------------------------
1420: ** Request a document referenced by a relative URL. The relative URL is
1421: ** made absolute by resolving it relative to the address of the 'base'
1422: ** anchor.
1423: ** Returns YES if request accepted, else NO
1424: */
1425: PUBLIC BOOL HTDeleteRelative (const char * relative,
1426: HTParentAnchor * base,
1427: HTRequest * request)
1428: {
1429: BOOL status = NO;
1430: if (relative && base && request) {
1431: char * rel = NULL;
1432: char * full_url = NULL;
1433: char * base_url = HTAnchor_address((HTAnchor *) base);
1434: StrAllocCopy(rel, relative);
1435: full_url = HTParse(HTStrip(rel), base_url,
1436: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.124 frystyk 1437: status = HTDeleteAbsolute(full_url, request);
1.123 frystyk 1438: HT_FREE(rel);
1439: HT_FREE(full_url);
1440: HT_FREE(base_url);
1441: }
1442: return status;
1443: }
1444:
1445: /* Request metainformation about an anchor
1446: ** --------------------------------------
1447: ** Request the document referenced by the anchor
1448: ** Returns YES if request accepted, else NO
1449: */
1450: PUBLIC BOOL HTDeleteAnchor (HTAnchor * anchor, HTRequest * request)
1451: {
1452: if (anchor && request) {
1453: HTRequest_setAnchor(request, anchor);
1454: HTRequest_setMethod(request, METHOD_DELETE);
1.124 frystyk 1455: return launch_request(request, NO);
1456: }
1457: return NO;
1458: }
1459:
1460: /* ------------------------------------------------------------------------- */
1461: /* OPTIONS METHOD */
1462: /* ------------------------------------------------------------------------- */
1463:
1464: /* Options availeble for document from absolute name
1465: ** -------------------------------------------------
1466: ** Request a document referencd by an absolute URL.
1467: ** Returns YES if request accepted, else NO
1468: */
1469: PUBLIC BOOL HTOptionsAbsolute (const char * url, HTRequest * request)
1470: {
1471: if (url && request) {
1472: HTAnchor * anchor = HTAnchor_findAddress(url);
1473: return HTOptionsAnchor(anchor, request);
1474: }
1475: return NO;
1476: }
1477:
1478: /* Options available for document from relative name
1479: ** -------------------------------------------------
1480: ** Request a document referenced by a relative URL. The relative URL is
1481: ** made absolute by resolving it relative to the address of the 'base'
1482: ** anchor.
1483: ** Returns YES if request accepted, else NO
1484: */
1485: PUBLIC BOOL HTOptionsRelative (const char * relative,
1486: HTParentAnchor * base,
1487: HTRequest * request)
1488: {
1489: BOOL status = NO;
1490: if (relative && base && request) {
1491: char * rel = NULL;
1492: char * full_url = NULL;
1493: char * base_url = HTAnchor_address((HTAnchor *) base);
1494: StrAllocCopy(rel, relative);
1495: full_url = HTParse(HTStrip(rel), base_url,
1496: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1497: status = HTOptionsAbsolute(full_url, request);
1498: HT_FREE(rel);
1499: HT_FREE(full_url);
1500: HT_FREE(base_url);
1501: }
1502: return status;
1503: }
1504:
1505: /* Options available for document using Anchor
1506: ** -------------------------------------------
1507: ** Request the document referenced by the anchor
1508: ** Returns YES if request accepted, else NO
1509: */
1510: PUBLIC BOOL HTOptionsAnchor (HTAnchor * anchor, HTRequest * request)
1511: {
1512: if (anchor && request) {
1513: HTRequest_setAnchor(request, anchor);
1514: HTRequest_setMethod(request, METHOD_OPTIONS);
1515: return launch_request(request, NO);
1.123 frystyk 1516: }
1517: return NO;
1.1 timbl 1518: }
1.127 frystyk 1519:
1520: /* ------------------------------------------------------------------------- */
1521: /* TRACE METHOD */
1522: /* ------------------------------------------------------------------------- */
1523:
1524: /* Traces available for document from absolute name
1525: ** ------------------------------------------------
1526: ** Request a document referencd by an absolute URL.
1527: ** Returns YES if request accepted, else NO
1528: */
1529: PUBLIC BOOL HTTraceAbsolute (const char * url, HTRequest * request)
1530: {
1531: if (url && request) {
1532: HTAnchor * anchor = HTAnchor_findAddress(url);
1533: return HTTraceAnchor(anchor, request);
1534: }
1535: return NO;
1536: }
1537:
1538: /* Traces available for document from relative name
1539: ** ------------------------------------------------
1540: ** Request a document referenced by a relative URL. The relative URL is
1541: ** made absolute by resolving it relative to the address of the 'base'
1542: ** anchor.
1543: ** Returns YES if request accepted, else NO
1544: */
1545: PUBLIC BOOL HTTraceRelative (const char * relative,
1546: HTParentAnchor * base,
1547: HTRequest * request)
1548: {
1549: BOOL status = NO;
1550: if (relative && base && request) {
1551: char * rel = NULL;
1552: char * full_url = NULL;
1553: char * base_url = HTAnchor_address((HTAnchor *) base);
1554: StrAllocCopy(rel, relative);
1555: full_url = HTParse(HTStrip(rel), base_url,
1556: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1557: status = HTTraceAbsolute(full_url, request);
1558: HT_FREE(rel);
1559: HT_FREE(full_url);
1560: HT_FREE(base_url);
1561: }
1562: return status;
1563: }
1564:
1565: /* Trace available for document using Anchor
1566: ** -------------------------------------------
1567: ** Request the document referenced by the anchor
1568: ** Returns YES if request accepted, else NO
1569: */
1570: PUBLIC BOOL HTTraceAnchor (HTAnchor * anchor, HTRequest * request)
1571: {
1572: if (anchor && request) {
1573: HTRequest_setAnchor(request, anchor);
1574: HTRequest_setMethod(request, METHOD_TRACE);
1575: return launch_request(request, NO);
1576: }
1577: return NO;
1578: }
1579:
Webmaster