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