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