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