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