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