Annotation of libwww/Library/src/HTAccess.c, revision 1.153
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.153 ! frystyk 6: ** @(#) $Id: HTAccess.c,v 1.152 1998/12/15 05:34:27 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);
1.147 frystyk 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: ** Load a Rule File without asking the user
292: ** ----------------------------------------
293: ** Load a rule find with the URL specified and add the set of rules to
294: ** the existing set. We don't ask the user as she would have to call this
295: ** method explicitly anyway.
296: */
297: PUBLIC BOOL HTLoadRulesAutomatically (const char * url)
298: {
299: BOOL status = NO;
300: if (url) {
301: HTList * list = HTList_new();
302: HTRequest * request = HTRequest_new();
303:
304: /*
305: ** Stop all other loads and concentrate on this one
306: */
307: HTRequest_setPreemptive(request, YES);
308:
309: /*
310: ** Add the rules parsing stream for this particular request only.
311: */
312: HTConversion_add(list, "application/x-www-rules", "*/*",
313: HTRules_parseAutomatically,
314: 1.0, 0.0, 0.0);
315:
1.123 frystyk 316: HTRequest_setConversion(request, list, YES);
317: status = HTLoadAbsolute(url, request);
318: HTConversion_deleteAll(list);
319: HTRequest_delete(request);
320: }
321: return status;
322: }
323:
324: /* --------------------------------------------------------------------------*/
325: /* GET WITH KEYWORDS (SEARCH) */
326: /* --------------------------------------------------------------------------*/
327:
328: /*
329: ** This function creates a URL with a searh part as defined by RFC 1866
330: ** Both the baseurl and the keywords must be escaped.
331: **
332: ** 1. The form field names and values are escaped: space
333: ** characters are replaced by `+', and then reserved characters
334: ** are escaped as per [URL]; that is, non-alphanumeric
335: ** characters are replaced by `%HH', a percent sign and two
336: ** hexadecimal digits representing the ASCII code of the
337: ** character. Line breaks, as in multi-line text field values,
338: ** are represented as CR LF pairs, i.e. `%0D%0A'.
339: **
340: ** 2. The fields are listed in the order they appear in the
341: ** document with the name separated from the value by `=' and
342: ** the pairs separated from each other by `&'. Fields with null
343: ** values may be omitted. In particular, unselected radio
344: ** buttons and checkboxes should not appear in the encoded
345: ** data, but hidden fields with VALUE attributes present
346: ** should.
347: **
348: ** NOTE - The URI from a query form submission can be
349: ** used in a normal anchor style hyperlink.
350: ** Unfortunately, the use of the `&' character to
351: ** separate form fields interacts with its use in SGML
352: ** attribute values as an entity reference delimiter.
353: ** For example, the URI `http://host/?x=1&y=2' must be
354: ** written `<a href="http://host/?x=1&y=2"' or `<a
355: ** href="http://host/?x=1&y=2">'.
356: **
357: ** HTTP server implementors, and in particular, CGI
358: ** implementors are encouraged to support the use of
359: ** `;' in place of `&' to save users the trouble of
360: ** escaping `&' characters this way.
361: */
362: PRIVATE char * query_url_encode (const char * baseurl, HTChunk * keywords)
363: {
364: char * fullurl = NULL;
365: if (baseurl && keywords && HTChunk_size(keywords)) {
366: int len = strlen(baseurl);
367: fullurl = (char *) HT_MALLOC(len + HTChunk_size(keywords) + 2);
368: sprintf(fullurl, "%s?%s", baseurl, HTChunk_data(keywords));
369: {
370: char * ptr = fullurl+len;
371: while (*ptr) {
372: if (*ptr == ' ') *ptr = '+';
373: ptr++;
374: }
375: }
376: }
377: return fullurl;
378: }
379:
380: PRIVATE char * form_url_encode (const char * baseurl, HTAssocList * formdata)
381: {
382: if (formdata) {
383: BOOL first = YES;
384: int cnt = HTList_count((HTList *) formdata);
385: HTChunk * fullurl = HTChunk_new(128);
386: HTAssoc * pres;
1.124 frystyk 387: if (baseurl) {
388: HTChunk_puts(fullurl, baseurl);
389: HTChunk_putc(fullurl, '?');
390: }
1.123 frystyk 391: while (cnt > 0) {
392: pres = (HTAssoc *) HTList_objectAt((HTList *) formdata, --cnt);
393: if (first)
394: first = NO;
395: else
396: HTChunk_putc(fullurl, '&'); /* Could use ';' instead */
397: HTChunk_puts(fullurl, HTAssoc_name(pres));
398: HTChunk_putc(fullurl, '=');
399: HTChunk_puts(fullurl, HTAssoc_value(pres));
400: }
401: return HTChunk_toCString(fullurl);
402: }
403: return NULL;
404: }
405:
406: /* Search a document from absolute name
407: ** ------------------------------------
408: ** Request a document referencd by an absolute URL appended with the
409: ** keywords given. The URL can NOT contain any fragment identifier!
410: ** The list of keywords must be a space-separated list and spaces will
411: ** be converted to '+' before the request is issued.
412: ** Returns YES if request accepted, else NO
413: */
414: PUBLIC BOOL HTSearchAbsolute (HTChunk * keywords,
415: const char * base,
416: HTRequest * request)
417: {
418: if (keywords && base && request) {
419: char * full = query_url_encode(base, keywords);
420: if (full) {
421: HTAnchor * anchor = HTAnchor_findAddress(full);
422: HTRequest_setAnchor(request, anchor);
423: HT_FREE(full);
1.124 frystyk 424: return launch_request(request, NO);
1.123 frystyk 425: }
426: }
427: return NO;
428: }
429:
430: /* Search a document from relative name
431: ** -------------------------------------
432: ** Request a document referenced by a relative URL. The relative URL is
433: ** made absolute by resolving it relative to the address of the 'base'
434: ** anchor.
435: ** Returns YES if request accepted, else NO
436: */
437: PUBLIC BOOL HTSearchRelative (HTChunk * keywords,
438: const char * relative,
439: HTParentAnchor * base,
440: HTRequest * request)
441: {
442: BOOL status = NO;
443: if (keywords && relative && base && request) {
444: char * full_url = NULL;
445: char * base_url = HTAnchor_address((HTAnchor *) base);
446: full_url = HTParse(relative, base_url,
447: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
448: status = HTSearchAbsolute(keywords, full_url, request);
449: HT_FREE(full_url);
450: HT_FREE(base_url);
451: }
452: return status;
453: }
454:
455: /*
456: ** Search a string
457: ** ---------------
458: ** This is the same as HTSearchAbsolute but instead of using a chunk
459: ** you can pass a string.
460: */
461: PUBLIC BOOL HTSearchString (const char * keywords,
462: HTAnchor * anchor,
463: HTRequest * request)
464: {
465: BOOL status = NO;
466: if (keywords && anchor && request) {
467: char * base_url = HTAnchor_address((HTAnchor *) anchor);
468: HTChunk * chunk = HTChunk_new(strlen(keywords)+2);
469: HTChunk_puts(chunk, keywords);
470: status = HTSearchAbsolute(chunk, base_url, request);
471: HT_FREE(base_url);
472: HTChunk_delete(chunk);
473: }
474: return status;
475: }
476:
1.90 frystyk 477: /* Search an Anchor
478: ** ----------------
479: ** Performs a keyword search on word given by the user. Adds the keyword
480: ** to the end of the current address and attempts to open the new address.
481: ** The list of keywords must be a space-separated list and spaces will
482: ** be converted to '+' before the request is issued.
483: ** Search can also be performed by HTLoadAbsolute() etc.
484: ** Returns YES if request accepted, else NO
485: */
1.123 frystyk 486: PUBLIC BOOL HTSearchAnchor (HTChunk * keywords,
487: HTAnchor * anchor,
488: HTRequest * request)
1.90 frystyk 489: {
1.99 frystyk 490: BOOL status = NO;
1.123 frystyk 491: if (keywords && anchor && request) {
492: char * base_url = HTAnchor_address(anchor);
493: status = HTSearchAbsolute(keywords, base_url, request);
1.114 frystyk 494: HT_FREE(base_url);
1.90 frystyk 495: }
1.99 frystyk 496: return status;
1.2 timbl 497: }
498:
1.123 frystyk 499: /* --------------------------------------------------------------------------*/
500: /* HANDLING FORMS USING GET AND POST */
501: /* --------------------------------------------------------------------------*/
1.2 timbl 502:
1.123 frystyk 503: /* Send a Form request using GET from absolute name
504: ** ------------------------------------------------
1.90 frystyk 505: ** Request a document referencd by an absolute URL appended with the
1.123 frystyk 506: ** formdata given. The URL can NOT contain any fragment identifier!
507: ** The list of form data must be given as an association list where
508: ** the name is the field name and the value is the value of the field.
509: ** Returns YES if request accepted, else NO
510: */
511: PUBLIC BOOL HTGetFormAbsolute (HTAssocList * formdata,
512: const char * base,
513: HTRequest * request)
514: {
515: if (formdata && base && request) {
516: char * full = form_url_encode(base, formdata);
517: if (full) {
518: HTAnchor * anchor = HTAnchor_findAddress(full);
519: HTRequest_setAnchor(request, anchor);
520: HT_FREE(full);
1.124 frystyk 521: return launch_request(request, NO);
1.123 frystyk 522: }
523: }
524: return NO;
525: }
526:
527: /* Send a Form request using GET from relative name
528: ** ------------------------------------------------
529: ** Request a document referencd by a relative URL appended with the
530: ** formdata given. The URL can NOT contain any fragment identifier!
531: ** The list of form data must be given as an association list where
532: ** the name is the field name and the value is the value of the field.
533: ** Returns YES if request accepted, else NO
534: */
535: PUBLIC BOOL HTGetFormRelative (HTAssocList * formdata,
536: const char * relative,
537: HTParentAnchor * base,
538: HTRequest * request)
539: {
540: BOOL status = NO;
541: if (formdata && relative && base && request) {
542: char * full_url = NULL;
543: char * base_url = HTAnchor_address((HTAnchor *) base);
544: full_url=HTParse(relative, base_url,
545: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
546: status = HTGetFormAbsolute(formdata, full_url, request);
547: HT_FREE(full_url);
548: HT_FREE(base_url);
549: }
550: return status;
551: }
552:
553: /* Send a Form request using GET from an anchor
554: ** --------------------------------------------
555: ** Request a document referencd by an anchor object appended with the
556: ** formdata given. The URL can NOT contain any fragment identifier!
557: ** The list of form data must be given as an association list where
558: ** the name is the field name and the value is the value of the field.
1.90 frystyk 559: ** Returns YES if request accepted, else NO
560: */
1.123 frystyk 561: PUBLIC BOOL HTGetFormAnchor (HTAssocList * formdata,
562: HTAnchor * anchor,
563: HTRequest * request)
564: {
565: BOOL status = NO;
566: if (formdata && anchor && request) {
567: char * base_url = HTAnchor_address((HTAnchor *) anchor);
568: status = HTGetFormAbsolute(formdata, base_url, request);
569: HT_FREE(base_url);
570: }
571: return status;
572: }
573:
574: PRIVATE int HTEntity_callback (HTRequest * request, HTStream * target)
575: {
576: HTParentAnchor * entity = HTRequest_entityAnchor(request);
1.153 ! frystyk 577: if (APP_TRACE) HTTrace("Posting Data from callback function\n");
1.123 frystyk 578: if (!request || !entity || !target) return HT_ERROR;
579: {
1.126 frystyk 580: BOOL chunking = NO;
1.123 frystyk 581: int status;
582: char * document = (char *) HTAnchor_document(entity);
583: int len = HTAnchor_length(entity);
1.126 frystyk 584: if (!document) {
585: if (PROT_TRACE) HTTrace("Posting Data No document\n");
586: return HT_ERROR;
587: }
588:
589: /*
590: ** If the length is unknown (-1) then see if the document is a text
591: ** type and in that case take the strlen. If not then we don't know
592: ** how much data we can write and must stop
593: */
594: if (len < 0) {
595: HTFormat actual = HTAnchor_format(entity);
596: HTFormat tmplate = HTAtom_for("text/*");
597: if (HTMIMEMatch(tmplate, actual)) {
598: len = strlen(document); /* Naive! */
599: chunking = YES;
600: } else {
601: if (PROT_TRACE)
602: HTTrace("Posting Data Must know the length of document %p\n",
603: document);
604: return HT_ERROR;
605: }
606: }
607:
608: /* Send the data down the pipe */
1.123 frystyk 609: status = (*target->isa->put_block)(target, document, len);
610: if (status == HT_WOULD_BLOCK) {
1.124 frystyk 611: if (PROT_TRACE)HTTrace("Posting Data Target WOULD BLOCK\n");
1.123 frystyk 612: return HT_WOULD_BLOCK;
613: } else if (status == HT_PAUSE) {
1.126 frystyk 614: if (PROT_TRACE) HTTrace("Posting Data Target PAUSED\n");
1.123 frystyk 615: return HT_PAUSE;
1.126 frystyk 616: } else if (chunking && status == HT_OK) {
617: if (PROT_TRACE) HTTrace("Posting Data Target is SAVED using chunked\n");
618: return (*target->isa->put_block)(target, "", 0);
1.136 frystyk 619: } else if (status == HT_LOADED || status == HT_OK) {
620: if (PROT_TRACE) HTTrace("Posting Data Target is SAVED\n");
621: (*target->isa->flush)(target);
622: return HT_LOADED;
623: } else if (status > 0) { /* Stream specific return code */
624: if (PROT_TRACE) HTTrace("Posting Data. Target returns %d\n", status);
1.123 frystyk 625: return status;
626: } else { /* we have a real error */
1.129 frystyk 627: if (PROT_TRACE) HTTrace("Posting Data Target ERROR %d\n", status);
1.123 frystyk 628: return status;
629: }
630: }
631: }
632:
633: /* Send a Form request using POST from absolute name
634: ** -------------------------------------------------
635: ** Request a document referencd by an absolute URL appended with the
636: ** formdata given. The URL can NOT contain any fragment identifier!
637: ** The list of form data must be given as an association list where
638: ** the name is the field name and the value is the value of the field.
639: */
640: PUBLIC HTParentAnchor * HTPostFormAbsolute (HTAssocList * formdata,
641: const char * base,
642: HTRequest * request)
643: {
644: if (formdata && base && request) {
645: HTAnchor * anchor = HTAnchor_findAddress(base);
646: return HTPostFormAnchor(formdata, anchor, request);
647: }
648: return NULL;
649: }
650:
651: /* Send a Form request using POST from relative name
652: ** -------------------------------------------------
653: ** Request a document referencd by a relative URL appended with the
654: ** formdata given. The URL can NOT contain any fragment identifier!
655: ** The list of form data must be given as an association list where
656: ** the name is the field name and the value is the value of the field.
657: */
658: PUBLIC HTParentAnchor * HTPostFormRelative (HTAssocList * formdata,
659: const char * relative,
660: HTParentAnchor * base,
661: HTRequest * request)
1.90 frystyk 662: {
1.123 frystyk 663: HTParentAnchor * postanchor = NULL;
664: if (formdata && relative && base && request) {
665: char * full_url = NULL;
666: char * base_url = HTAnchor_address((HTAnchor *) base);
667: full_url=HTParse(relative, base_url,
668: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
669: postanchor = HTPostFormAbsolute(formdata, full_url, request);
670: HT_FREE(full_url);
671: HT_FREE(base_url);
672: }
673: return postanchor;
674: }
675:
676: /* Send a Form request using POST from an anchor
677: ** ---------------------------------------------
678: ** Request a document referencd by an anchor object appended with the
679: ** formdata given. The URL can NOT contain any fragment identifier!
680: ** The list of form data must be given as an association list where
681: ** the name is the field name and the value is the value of the field.
682: */
683: PUBLIC HTParentAnchor * HTPostFormAnchor (HTAssocList * formdata,
684: HTAnchor * anchor,
685: HTRequest * request)
686: {
687: HTParentAnchor * postanchor = NULL;
688: if (formdata && anchor && request) {
689: HTUserProfile * up = HTRequest_userProfile(request);
690: char * tmpfile = HTGetTmpFileName(HTUserProfile_tmp(up));
691: char * tmpurl = HTParse(tmpfile, "file:", PARSE_ALL);
692: char * form_encoded = form_url_encode(NULL, formdata);
693: if (form_encoded) {
694:
695: /*
696: ** Now create a new anchor for the post data and set up
697: ** the rest of the metainformation we know about this anchor. The
698: ** tmp anchor may actually already exist from previous postings.
699: */
700: postanchor = (HTParentAnchor *) HTAnchor_findAddress(tmpurl);
701: HTAnchor_clearHeader(postanchor);
702: HTAnchor_setDocument(postanchor, form_encoded);
703: HTAnchor_setLength(postanchor, strlen(form_encoded));
704: HTAnchor_setFormat(postanchor, WWW_FORM);
705:
706: /*
707: ** Bind the temporary anchor to the anchor that will contain the
708: ** response
709: */
710: HTLink_removeAll((HTAnchor *) postanchor);
711: HTLink_add((HTAnchor *) postanchor, (HTAnchor *) anchor,
712: NULL, METHOD_POST);
713:
714: /* Set up the request object */
715: HTRequest_addGnHd(request, HT_G_DATE); /* Send date header */
716: HTRequest_setAnchor(request, anchor);
717: HTRequest_setEntityAnchor(request, postanchor);
718: HTRequest_setMethod(request, METHOD_POST);
719:
720: /* Add the post form callback function to provide the form data */
721: HTRequest_setPostCallback(request, HTEntity_callback);
722:
723: /* Now start the load normally */
1.124 frystyk 724: launch_request(request, NO);
1.123 frystyk 725: }
726: HT_FREE(tmpfile);
727: HT_FREE(tmpurl);
1.90 frystyk 728: }
1.123 frystyk 729: return postanchor;
1.57 howcome 730: }
1.146 frystyk 731:
732: /*
733: ** POST a URL and save the response in a mem buffer
734: ** ------------------------------------------------
735: ** Returns chunk if OK - else NULL
736: */
737: PUBLIC HTChunk * HTPostFormAnchorToChunk (HTAssocList * formdata,
738: HTAnchor * anchor,
739: HTRequest * request)
740: {
741: if (formdata && anchor && request) {
742: HTChunk * chunk = NULL;
743: HTStream * target = HTStreamToChunk(request, &chunk, 0);
744: HTRequest_setOutputStream(request, target);
745: if (HTPostFormAnchor(formdata, anchor, request) != NULL)
746: return chunk;
747: else {
748: HTChunk_delete(chunk);
749: return NULL;
750: }
751: }
752: return NULL;
753: }
754:
1.57 howcome 755:
1.70 frystyk 756: /* --------------------------------------------------------------------------*/
1.124 frystyk 757: /* PUT A DOCUMENT */
758: /* --------------------------------------------------------------------------*/
1.149 frystyk 759:
760: /*
761: ** If we use our persistent cache then we can protect
762: ** against the lost update problem by saving the etag
763: ** or last modified date in the cache and use it on all
764: ** our PUT operations.
765: */
1.151 frystyk 766: PRIVATE BOOL set_preconditions (HTRequest * request)
1.149 frystyk 767: {
768: if (request) {
769: HTPreconditions precons = HTRequest_preconditions(request);
1.151 frystyk 770: HTRqHd if_headers = HTRequest_rqHd (request);
771: HTRqHd all_if_headers =
772: (HT_C_IF_MATCH | HT_C_IF_MATCH_ANY |
773: HT_C_IF_NONE_MATCH | HT_C_IF_NONE_MATCH_ANY |
774: HT_C_IMS | HT_C_IF_UNMOD_SINCE);
775: switch (precons) {
1.150 frystyk 776: case HT_NO_MATCH:
1.151 frystyk 777: if_headers &= ~(all_if_headers);
1.150 frystyk 778: break;
779:
1.149 frystyk 780: case HT_MATCH_THIS:
1.151 frystyk 781: if_headers &= ~(all_if_headers);
782: if_headers |= (HT_C_IF_MATCH | HT_C_IF_UNMOD_SINCE);
1.149 frystyk 783: break;
784:
785: case HT_MATCH_ANY:
1.151 frystyk 786: if_headers &= ~(all_if_headers);
787: if_headers |= (HT_C_IF_MATCH_ANY);
1.149 frystyk 788: break;
789:
790: case HT_DONT_MATCH_THIS:
1.151 frystyk 791: if_headers &= ~(all_if_headers);
792: if_headers |= (HT_C_IF_NONE_MATCH | HT_C_IMS);
1.149 frystyk 793: break;
794:
795: case HT_DONT_MATCH_ANY:
1.151 frystyk 796: if_headers &= ~(all_if_headers);
797: if_headers |= (HT_C_IF_NONE_MATCH_ANY);
1.149 frystyk 798: break;
1.150 frystyk 799:
800: default:
801: if (APP_TRACE) HTTrace("Precondition %d not understood\n", precons);
802:
1.149 frystyk 803: }
1.151 frystyk 804:
805: /* Set the if-* bit flag */
806: HTRequest_setRqHd(request, if_headers);
807:
808: return YES;
1.149 frystyk 809: }
810: return NO;
811: }
812:
1.125 frystyk 813: PRIVATE BOOL setup_anchors (HTRequest * request,
1.131 frystyk 814: HTParentAnchor * source, HTParentAnchor * dest,
815: HTMethod method)
1.124 frystyk 816: {
1.131 frystyk 817: if (!(method & (METHOD_PUT | METHOD_POST))) {
818: if (APP_TRACE) HTTrace("Posting..... Bad method\n");
819: return NO;
820: }
821:
1.124 frystyk 822: /*
1.127 frystyk 823: ** Check whether we know if it is possible to PUT to this destination.
824: ** We both check the local set of allowed methods in the anchor and any
825: ** site information that we may have about the location of the origin
826: ** server.
1.124 frystyk 827: */
828: {
1.131 frystyk 829: char * addr = HTAnchor_address((HTAnchor *) source);
830: char * hostname = HTParse(addr, "", PARSE_HOST);
1.142 frystyk 831: #if 0
1.131 frystyk 832: HTHost * host = HTHost_find(hostname);
833: HTMethod public_methods = HTHost_publicMethods(host);
1.134 frystyk 834: HTMethod private_methods = HTAnchor_allow(dest);
1.141 frystyk 835: #endif
1.131 frystyk 836: HT_FREE(hostname);
837: HT_FREE(addr);
1.141 frystyk 838:
839: #if 0
840: /*
841: ** Again, this may be too cautios for normal operations
842: */
1.131 frystyk 843: if (!(method & (private_methods | public_methods))) {
1.124 frystyk 844: HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
845: if (prompt) {
846: if ((*prompt)(request, HT_A_CONFIRM, HT_MSG_METHOD,
847: NULL, NULL, NULL) != YES)
848: return NO;
849: }
850: }
1.141 frystyk 851: #endif
1.124 frystyk 852: }
853:
854: /*
855: ** Bind the source anchor to the dest anchor that will contain the
856: ** response. If link already exists then ask is we should do it again.
857: ** If so then remove the old link and replace it with a new one.
858: */
859: {
860: HTLink *link = HTLink_find((HTAnchor *) source, (HTAnchor *) dest);
861: if (link && HTLink_method(link) == METHOD_PUT) {
862: HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
863: if (prompt) {
864: if ((*prompt)(request, HT_A_CONFIRM, HT_MSG_REDO,
865: NULL, NULL, NULL) != YES)
866: return NO;
867: }
868: HTLink_remove((HTAnchor *) source, (HTAnchor *) dest);
869: }
870: HTLink_add((HTAnchor*) source, (HTAnchor*) dest, NULL, METHOD_PUT);
871: }
872: return YES;
873: }
874:
875: /* Send an Anchor using PUT from absolute name
876: ** -------------------------------------------
877: ** Upload a document referenced by an absolute URL appended.
878: ** The URL can NOT contain any fragment identifier!
879: ** The list of form data must be given as an association list where
880: ** the name is the field name and the value is the value of the field.
881: */
882: PUBLIC BOOL HTPutAbsolute (HTParentAnchor * source,
883: const char * destination,
884: HTRequest * request)
885: {
886: if (source && destination && request) {
887: HTAnchor * dest = HTAnchor_findAddress(destination);
888: return HTPutAnchor(source, dest, request);
889: }
890: return NO;
891: }
892:
893: /* Send an Anchor using PUT from relative name
894: ** -------------------------------------------
895: ** Upload a document referenced by a relative URL appended.
896: ** The URL can NOT contain any fragment identifier!
897: ** The list of form data must be given as an association list where
898: ** the name is the field name and the value is the value of the field.
899: */
900: PUBLIC BOOL HTPutRelative (HTParentAnchor * source,
901: const char * relative,
902: HTParentAnchor * destination_base,
903: HTRequest * request)
904: {
905: if (source && relative && destination_base && request) {
906: BOOL status;
907: char * full_url = NULL;
908: char * base_url = HTAnchor_address((HTAnchor *) destination_base);
909: full_url=HTParse(relative, base_url,
910: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
911: status = HTPutAbsolute(source, full_url, request);
912: HT_FREE(full_url);
913: HT_FREE(base_url);
914: return status;
915: }
916: return NO;
917: }
918:
919: /* Send an Anchor using PUT from an anchor
920: ** ---------------------------------------
921: ** Upload a document referenced by an anchor object appended
922: ** The URL can NOT contain any fragment identifier!
923: ** The list of form data must be given as an association list where
924: ** the name is the field name and the value is the value of the field.
925: */
926: PUBLIC BOOL HTPutAnchor (HTParentAnchor * source,
927: HTAnchor * destination,
928: HTRequest * request)
929: {
930: HTParentAnchor * dest = HTAnchor_parent(destination);
931: if (source && dest && request) {
1.131 frystyk 932: if (setup_anchors(request, source, dest, METHOD_PUT) == YES) {
1.124 frystyk 933:
934: /* Set up the request object */
935: HTRequest_addGnHd(request, HT_G_DATE);
936: HTRequest_setEntityAnchor(request, source);
937: HTRequest_setMethod(request, METHOD_PUT);
938: HTRequest_setAnchor(request, destination);
939:
1.151 frystyk 940: /* Setup preconditions */
941: set_preconditions(request);
942:
1.124 frystyk 943: /* Add the entity callback function to provide the form data */
944: HTRequest_setPostCallback(request, HTEntity_callback);
945:
946: /* Now start the load normally */
947: return launch_request(request, NO);
948: }
949: }
950: return NO;
951: }
952:
1.125 frystyk 953: /* Send an Anchor using POST from absolute name
954: ** -------------------------------------------
955: ** Upload a document referenced by an absolute URL appended.
956: ** The URL can NOT contain any fragment identifier!
957: ** The list of form data must be given as an association list where
958: ** the name is the field name and the value is the value of the field.
959: */
960: PUBLIC BOOL HTPostAbsolute (HTParentAnchor * source,
961: const char * destination,
962: HTRequest * request)
963: {
964: if (source && destination && request) {
965: HTAnchor * dest = HTAnchor_findAddress(destination);
966: return HTPostAnchor(source, dest, request);
967: }
968: return NO;
969: }
970:
971: /* Send an Anchor using POST from relative name
972: ** -------------------------------------------
973: ** Upload a document referenced by a relative URL appended.
974: ** The URL can NOT contain any fragment identifier!
975: ** The list of form data must be given as an association list where
976: ** the name is the field name and the value is the value of the field.
977: */
978: PUBLIC BOOL HTPostRelative (HTParentAnchor * source,
979: const char * relative,
980: HTParentAnchor * destination_base,
981: HTRequest * request)
982: {
983: if (source && relative && destination_base && request) {
984: BOOL status;
985: char * full_url = NULL;
986: char * base_url = HTAnchor_address((HTAnchor *) destination_base);
987: full_url=HTParse(relative, base_url,
988: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
989: status = HTPostAbsolute(source, full_url, request);
990: HT_FREE(full_url);
991: HT_FREE(base_url);
992: return status;
993: }
994: return NO;
995: }
996:
997: /* Send an Anchor using POST from an anchor
998: ** ---------------------------------------
999: ** Upload a document referenced by an anchor object appended
1000: ** The URL can NOT contain any fragment identifier!
1001: ** The list of form data must be given as an association list where
1002: ** the name is the field name and the value is the value of the field.
1003: */
1004: PUBLIC BOOL HTPostAnchor (HTParentAnchor * source,
1005: HTAnchor * destination,
1006: HTRequest * request)
1007: {
1008: HTParentAnchor * dest = HTAnchor_parent(destination);
1009: if (source && dest && request) {
1.131 frystyk 1010: if (setup_anchors(request, source, dest, METHOD_POST) == YES) {
1.125 frystyk 1011:
1012: /* Set up the request object */
1013: HTRequest_addGnHd(request, HT_G_DATE);
1014: HTRequest_setEntityAnchor(request, source);
1015: HTRequest_setMethod(request, METHOD_POST);
1016: HTRequest_setAnchor(request, destination);
1017:
1018: /* Add the entity callback function to provide the form data */
1019: HTRequest_setPostCallback(request, HTEntity_callback);
1020:
1021: /* Now start the load normally */
1022: return launch_request(request, NO);
1023: }
1024: }
1025: return NO;
1026: }
1027:
1.124 frystyk 1028: /* Send an Anchor using PUT from absolute name
1029: ** -------------------------------------------
1030: ** Upload a document referenced by an absolute URL appended.
1031: ** The URL can NOT contain any fragment identifier!
1032: ** The list of form data must be given as an association list where
1033: ** the name is the field name and the value is the value of the field.
1034: */
1035: PUBLIC BOOL HTPutStructuredAbsolute (HTParentAnchor * source,
1036: const char * destination,
1037: HTRequest * request,
1038: HTPostCallback * input)
1039: {
1040: if (source && destination && request && input) {
1041: HTAnchor * dest = HTAnchor_findAddress(destination);
1042: return HTPutStructuredAnchor(source, dest, request, input);
1043: }
1044: return NO;
1045: }
1046:
1047: /* Send an Anchor using PUT from relative name
1048: ** -------------------------------------------
1049: ** Upload a document referenced by a relative URL appended.
1050: ** The URL can NOT contain any fragment identifier!
1051: ** The list of form data must be given as an association list where
1052: ** the name is the field name and the value is the value of the field.
1053: */
1054: PUBLIC BOOL HTPutStructuredRelative (HTParentAnchor * source,
1055: const char * relative,
1056: HTParentAnchor * destination_base,
1057: HTRequest * request,
1058: HTPostCallback * input)
1059: {
1060: if (source && relative && destination_base && request && input) {
1061: BOOL status;
1062: char * full_url = NULL;
1063: char * base_url = HTAnchor_address((HTAnchor *) destination_base);
1064: full_url=HTParse(relative, base_url,
1065: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1066: status = HTPutStructuredAbsolute(source, full_url, request, input);
1067: HT_FREE(full_url);
1068: HT_FREE(base_url);
1069: return status;
1070: }
1071: return NO;
1072: }
1073:
1074: /* Send an Anchor using PUT from an anchor
1075: ** ---------------------------------------
1076: ** Upload a document referenced by an anchor object appended
1077: ** The URL can NOT contain any fragment identifier!
1078: ** The list of form data must be given as an association list where
1079: ** the name is the field name and the value is the value of the field.
1080: */
1081: PUBLIC BOOL HTPutStructuredAnchor (HTParentAnchor * source,
1082: HTAnchor * destination,
1083: HTRequest * request,
1084: HTPostCallback * input)
1085: {
1086: HTParentAnchor * dest = HTAnchor_parent(destination);
1087: if (source && dest && request) {
1.131 frystyk 1088: if (setup_anchors(request, source, dest, METHOD_PUT) == YES) {
1.124 frystyk 1089:
1090: /* Set up the request object */
1091: HTRequest_addGnHd(request, HT_G_DATE);
1092: HTRequest_setEntityAnchor(request, source);
1093: HTRequest_setMethod(request, METHOD_PUT);
1094: HTRequest_setAnchor(request, destination);
1095:
1.151 frystyk 1096: /* Setup preconditions */
1097: set_preconditions(request);
1098:
1.124 frystyk 1099: /* Add the entity callback function to provide the form data */
1100: HTRequest_setPostCallback(request, input);
1101:
1102: /* Now start the load normally */
1103: return launch_request(request, NO);
1104: }
1105: }
1106: return NO;
1107: }
1108:
1109: /*
1.144 frystyk 1110: ** After filter for handling PUT of document.
1.124 frystyk 1111: */
1.134 frystyk 1112: PRIVATE int HTSaveFilter (HTRequest * request, HTResponse * response,
1113: void * param, int status)
1.124 frystyk 1114: {
1115: HTPutContext * me = (HTPutContext *) param;
1116: if (APP_TRACE)
1117: HTTrace("Save Filter. Using context %p with state %c\n",
1118: me, me->state+0x30);
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.125 frystyk 1126: if (APP_TRACE) HTTrace("Save Filter. Waiting for authentication\n");
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
1165: if (APP_TRACE) HTTrace("Save Filter. Destination hae moved!\n");
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) {
1331: if (APP_TRACE) HTTrace("Put Document No source\n");
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.153 ! frystyk 1358: if (APP_TRACE) HTTrace("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.153 ! frystyk 1380: if (APP_TRACE)
1.115 eric 1381: HTTrace("Copy Anchor. No destination found or unspecified method\n");
1.80 frystyk 1382: HTRequest_delete(src_req);
1.90 frystyk 1383: return NO;
1.80 frystyk 1384: }
1.109 frystyk 1385: main_dest->GenMask |= HT_G_DATE; /* Send date header */
1.133 frystyk 1386: main_dest->reload = HT_CACHE_VALIDATE;
1.109 frystyk 1387: main_dest->method = method;
1388: main_dest->input_format = WWW_SOURCE;
1389: HTRequest_addDestination(src_req, main_dest);
1390: if (HTLoadAnchor(main_anchor, main_dest) == NO)
1391: return NO;
1.80 frystyk 1392: }
1.78 frystyk 1393:
1.80 frystyk 1394: /* For all other links in the source anchor */
1.106 frystyk 1395: if ((cur = HTAnchor_subLinks(src_anchor))) {
1396: HTLink * pres;
1.109 frystyk 1397: while ((pres = (HTLink *) HTList_nextObject(cur))) {
1.106 frystyk 1398: HTAnchor *dest = HTLink_destination(pres);
1399: HTMethod method = HTLink_method(pres);
1.80 frystyk 1400: HTRequest *dest_req;
1401: if (!dest || method==METHOD_INVALID) {
1.153 ! frystyk 1402: if (APP_TRACE)
1.115 eric 1403: HTTrace("Copy Anchor. Bad anchor setup %p\n",
1.80 frystyk 1404: dest);
1.90 frystyk 1405: return NO;
1.80 frystyk 1406: }
1.109 frystyk 1407: dest_req = HTRequest_dupInternal(main_dest);
1.107 frystyk 1408: dest_req->GenMask |= HT_G_DATE; /* Send date header */
1.133 frystyk 1409: dest_req->reload = HT_CACHE_VALIDATE;
1.80 frystyk 1410: dest_req->method = method;
1.104 frystyk 1411: dest_req->output_stream = NULL;
1412: dest_req->output_format = WWW_SOURCE;
1.109 frystyk 1413: HTRequest_addDestination(src_req, dest_req);
1.104 frystyk 1414:
1.90 frystyk 1415: if (HTLoadAnchor(dest, dest_req) == NO)
1416: return NO;
1.80 frystyk 1417: }
1418: }
1419: } else { /* Use the existing Post Web and restart it */
1.109 frystyk 1420: src_req = main_dest->source;
1.80 frystyk 1421: if (src_req->mainDestination)
1.124 frystyk 1422: if (launch_request(main_dest, NO) == NO)
1.90 frystyk 1423: return NO;
1.80 frystyk 1424: if (src_req->destinations) {
1.106 frystyk 1425: HTRequest * pres;
1426: cur = HTAnchor_subLinks(src_anchor);
1.80 frystyk 1427: while ((pres = (HTRequest *) HTList_nextObject(cur)) != NULL) {
1.124 frystyk 1428: if (launch_request(pres, NO) == NO)
1.90 frystyk 1429: return NO;
1.80 frystyk 1430: }
1431: }
1.78 frystyk 1432: }
1433:
1.80 frystyk 1434: /* Now open the source */
1435: return HTLoadAnchor(src_anchor, src_req);
1.70 frystyk 1436: }
1437:
1.90 frystyk 1438: /* Upload an Anchor
1.70 frystyk 1439: ** ----------------
1.111 frystyk 1440: ** This function can be used to send data along with a request to a remote
1441: ** server. It can for example be used to POST form data to a remote HTTP
1442: ** server - or it can be used to post a newsletter to a NNTP server. In
1443: ** either case, you pass a callback function which the request calls when
1444: ** the remote destination is ready to accept data. In this callback
1445: ** you get the current request object and a stream into where you can
1446: ** write data. It is very important that you return the value returned
1447: ** by this stream to the Library so that it knows what to do next. The
1448: ** reason is that the outgoing stream might block or an error may
1449: ** occur and in that case the Library must know about it. The source
1450: ** anchor represents the data object in memory and it points to
1451: ** the destination anchor by using the POSTWeb method. The source anchor
1452: ** contains metainformation about the data object in memory and the
1453: ** destination anchor represents the reponse from the remote server.
1.90 frystyk 1454: ** Returns YES if request accepted, else NO
1455: */
1.111 frystyk 1456: PUBLIC BOOL HTUploadAnchor (HTAnchor * source_anchor,
1457: HTRequest * request,
1458: HTPostCallback * callback)
1459: {
1460: HTLink * link = HTAnchor_mainLink((HTAnchor *) source_anchor);
1461: HTAnchor * dest_anchor = HTLink_destination(link);
1462: HTMethod method = HTLink_method(link);
1463: if (!link || method==METHOD_INVALID || !callback) {
1.153 ! frystyk 1464: if (APP_TRACE)
1.115 eric 1465: HTTrace("Upload...... No destination found or unspecified method\n");
1.90 frystyk 1466: return NO;
1.109 frystyk 1467: }
1.111 frystyk 1468: request->GenMask |= HT_G_DATE; /* Send date header */
1.133 frystyk 1469: request->reload = HT_CACHE_VALIDATE;
1.111 frystyk 1470: request->method = method;
1471: request->source_anchor = HTAnchor_parent(source_anchor);
1472: request->PostCallback = callback;
1473: return HTLoadAnchor(dest_anchor, request);
1474: }
1475:
1476: /* POST Callback Handler
1477: ** ---------------------
1478: ** If you do not want to handle the stream interface on your own, you
1479: ** can use this function which writes the source anchor hyperdoc to the
1480: ** target stream for the anchor upload and also handles the return value
1481: ** from the stream. If you don't want to write the source anchor hyperdoc
1482: ** then you can register your own callback function that can get the data
1483: ** you want.
1484: */
1485: PUBLIC int HTUpload_callback (HTRequest * request, HTStream * target)
1486: {
1.153 ! frystyk 1487: if (APP_TRACE) HTTrace("Uploading... from callback function\n");
1.111 frystyk 1488: if (!request || !request->source_anchor || !target) return HT_ERROR;
1489: {
1490: int status;
1491: HTParentAnchor * source = request->source_anchor;
1492: char * document = (char *) HTAnchor_document(request->source_anchor);
1493: int len = HTAnchor_length(source);
1494: if (len < 0) {
1495: len = strlen(document);
1496: HTAnchor_setLength(source, len);
1497: }
1498: status = (*target->isa->put_block)(target, document, len);
1499: if (status == HT_OK)
1500: return (*target->isa->flush)(target);
1501: if (status == HT_WOULD_BLOCK) {
1.115 eric 1502: if (PROT_TRACE)HTTrace("POST Anchor. Target WOULD BLOCK\n");
1.111 frystyk 1503: return HT_WOULD_BLOCK;
1504: } else if (status == HT_PAUSE) {
1.115 eric 1505: if (PROT_TRACE) HTTrace("POST Anchor. Target PAUSED\n");
1.111 frystyk 1506: return HT_PAUSE;
1507: } else if (status > 0) { /* Stream specific return code */
1508: if (PROT_TRACE)
1.115 eric 1509: HTTrace("POST Anchor. Target returns %d\n", status);
1.111 frystyk 1510: return status;
1.120 eric 1511: } else { /* we have a real error */
1.115 eric 1512: if (PROT_TRACE) HTTrace("POST Anchor. Target ERROR\n");
1.111 frystyk 1513: return status;
1514: }
1.70 frystyk 1515: }
1.123 frystyk 1516: }
1517:
1518: /* ------------------------------------------------------------------------- */
1519: /* HEAD METHOD */
1520: /* ------------------------------------------------------------------------- */
1521:
1522: /* Request metainformation about a document from absolute name
1523: ** -----------------------------------------------------------
1524: ** Request a document referencd by an absolute URL.
1525: ** Returns YES if request accepted, else NO
1526: */
1527: PUBLIC BOOL HTHeadAbsolute (const char * url, HTRequest * request)
1528: {
1529: if (url && request) {
1530: HTAnchor * anchor = HTAnchor_findAddress(url);
1.124 frystyk 1531: return HTHeadAnchor(anchor, request);
1.123 frystyk 1532: }
1533: return NO;
1534: }
1535:
1536: /* Request metainformation about a document from relative name
1537: ** -----------------------------------------------------------
1538: ** Request a document referenced by a relative URL. The relative URL is
1539: ** made absolute by resolving it relative to the address of the 'base'
1540: ** anchor.
1541: ** Returns YES if request accepted, else NO
1542: */
1543: PUBLIC BOOL HTHeadRelative (const char * relative,
1544: HTParentAnchor * base,
1545: HTRequest * request)
1546: {
1547: BOOL status = NO;
1548: if (relative && base && request) {
1549: char * rel = NULL;
1550: char * full_url = NULL;
1551: char * base_url = HTAnchor_address((HTAnchor *) base);
1552: StrAllocCopy(rel, relative);
1553: full_url = HTParse(HTStrip(rel), base_url,
1554: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.124 frystyk 1555: status = HTHeadAbsolute(full_url, request);
1.123 frystyk 1556: HT_FREE(rel);
1557: HT_FREE(full_url);
1558: HT_FREE(base_url);
1559: }
1560: return status;
1561: }
1562:
1563: /* Request metainformation about an anchor
1564: ** --------------------------------------
1565: ** Request the document referenced by the anchor
1566: ** Returns YES if request accepted, else NO
1567: */
1568: PUBLIC BOOL HTHeadAnchor (HTAnchor * anchor, HTRequest * request)
1569: {
1570: if (anchor && request) {
1571: HTRequest_setAnchor(request, anchor);
1572: HTRequest_setMethod(request, METHOD_HEAD);
1.124 frystyk 1573: return launch_request(request, NO);
1.123 frystyk 1574: }
1575: return NO;
1576: }
1577:
1578: /* ------------------------------------------------------------------------- */
1579: /* DELETE METHOD */
1580: /* ------------------------------------------------------------------------- */
1581:
1582: /* Delete a document on a remote server
1583: ** ------------------------------------
1584: ** Request a document referencd by an absolute URL.
1585: ** Returns YES if request accepted, else NO
1586: */
1587: PUBLIC BOOL HTDeleteAbsolute (const char * url, HTRequest * request)
1588: {
1589: if (url && request) {
1590: HTAnchor * anchor = HTAnchor_findAddress(url);
1.124 frystyk 1591: return HTDeleteAnchor(anchor, request);
1.123 frystyk 1592: }
1593: return NO;
1594: }
1595:
1596: /* Request metainformation about a document from relative name
1597: ** -----------------------------------------------------------
1598: ** Request a document referenced by a relative URL. The relative URL is
1599: ** made absolute by resolving it relative to the address of the 'base'
1600: ** anchor.
1601: ** Returns YES if request accepted, else NO
1602: */
1603: PUBLIC BOOL HTDeleteRelative (const char * relative,
1604: HTParentAnchor * base,
1605: HTRequest * request)
1606: {
1607: BOOL status = NO;
1608: if (relative && base && request) {
1609: char * rel = NULL;
1610: char * full_url = NULL;
1611: char * base_url = HTAnchor_address((HTAnchor *) base);
1612: StrAllocCopy(rel, relative);
1613: full_url = HTParse(HTStrip(rel), base_url,
1614: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1.124 frystyk 1615: status = HTDeleteAbsolute(full_url, request);
1.123 frystyk 1616: HT_FREE(rel);
1617: HT_FREE(full_url);
1618: HT_FREE(base_url);
1619: }
1620: return status;
1621: }
1622:
1623: /* Request metainformation about an anchor
1624: ** --------------------------------------
1625: ** Request the document referenced by the anchor
1626: ** Returns YES if request accepted, else NO
1627: */
1628: PUBLIC BOOL HTDeleteAnchor (HTAnchor * anchor, HTRequest * request)
1629: {
1630: if (anchor && request) {
1631: HTRequest_setAnchor(request, anchor);
1632: HTRequest_setMethod(request, METHOD_DELETE);
1.124 frystyk 1633: return launch_request(request, NO);
1634: }
1635: return NO;
1636: }
1637:
1638: /* ------------------------------------------------------------------------- */
1639: /* OPTIONS METHOD */
1640: /* ------------------------------------------------------------------------- */
1641:
1642: /* Options availeble for document from absolute name
1643: ** -------------------------------------------------
1644: ** Request a document referencd by an absolute URL.
1645: ** Returns YES if request accepted, else NO
1646: */
1647: PUBLIC BOOL HTOptionsAbsolute (const char * url, HTRequest * request)
1648: {
1649: if (url && request) {
1650: HTAnchor * anchor = HTAnchor_findAddress(url);
1651: return HTOptionsAnchor(anchor, request);
1652: }
1653: return NO;
1654: }
1655:
1656: /* Options available for document from relative name
1657: ** -------------------------------------------------
1658: ** Request a document referenced by a relative URL. The relative URL is
1659: ** made absolute by resolving it relative to the address of the 'base'
1660: ** anchor.
1661: ** Returns YES if request accepted, else NO
1662: */
1663: PUBLIC BOOL HTOptionsRelative (const char * relative,
1664: HTParentAnchor * base,
1665: HTRequest * request)
1666: {
1667: BOOL status = NO;
1668: if (relative && base && request) {
1669: char * rel = NULL;
1670: char * full_url = NULL;
1671: char * base_url = HTAnchor_address((HTAnchor *) base);
1672: StrAllocCopy(rel, relative);
1673: full_url = HTParse(HTStrip(rel), base_url,
1674: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1675: status = HTOptionsAbsolute(full_url, request);
1676: HT_FREE(rel);
1677: HT_FREE(full_url);
1678: HT_FREE(base_url);
1679: }
1680: return status;
1681: }
1682:
1683: /* Options available for document using Anchor
1684: ** -------------------------------------------
1685: ** Request the document referenced by the anchor
1686: ** Returns YES if request accepted, else NO
1687: */
1688: PUBLIC BOOL HTOptionsAnchor (HTAnchor * anchor, HTRequest * request)
1689: {
1690: if (anchor && request) {
1691: HTRequest_setAnchor(request, anchor);
1692: HTRequest_setMethod(request, METHOD_OPTIONS);
1693: return launch_request(request, NO);
1.123 frystyk 1694: }
1695: return NO;
1.1 timbl 1696: }
1.127 frystyk 1697:
1698: /* ------------------------------------------------------------------------- */
1699: /* TRACE METHOD */
1700: /* ------------------------------------------------------------------------- */
1701:
1702: /* Traces available for document from absolute name
1703: ** ------------------------------------------------
1704: ** Request a document referencd by an absolute URL.
1705: ** Returns YES if request accepted, else NO
1706: */
1707: PUBLIC BOOL HTTraceAbsolute (const char * url, HTRequest * request)
1708: {
1709: if (url && request) {
1710: HTAnchor * anchor = HTAnchor_findAddress(url);
1711: return HTTraceAnchor(anchor, request);
1712: }
1713: return NO;
1714: }
1715:
1716: /* Traces available for document from relative name
1717: ** ------------------------------------------------
1718: ** Request a document referenced by a relative URL. The relative URL is
1719: ** made absolute by resolving it relative to the address of the 'base'
1720: ** anchor.
1721: ** Returns YES if request accepted, else NO
1722: */
1723: PUBLIC BOOL HTTraceRelative (const char * relative,
1724: HTParentAnchor * base,
1725: HTRequest * request)
1726: {
1727: BOOL status = NO;
1728: if (relative && base && request) {
1729: char * rel = NULL;
1730: char * full_url = NULL;
1731: char * base_url = HTAnchor_address((HTAnchor *) base);
1732: StrAllocCopy(rel, relative);
1733: full_url = HTParse(HTStrip(rel), base_url,
1734: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
1735: status = HTTraceAbsolute(full_url, request);
1736: HT_FREE(rel);
1737: HT_FREE(full_url);
1738: HT_FREE(base_url);
1739: }
1740: return status;
1741: }
1742:
1743: /* Trace available for document using Anchor
1744: ** -------------------------------------------
1745: ** Request the document referenced by the anchor
1746: ** Returns YES if request accepted, else NO
1747: */
1748: PUBLIC BOOL HTTraceAnchor (HTAnchor * anchor, HTRequest * request)
1749: {
1750: if (anchor && request) {
1751: HTRequest_setAnchor(request, anchor);
1752: HTRequest_setMethod(request, METHOD_TRACE);
1753: return launch_request(request, NO);
1754: }
1755: return NO;
1756: }
1757:
1.152 frystyk 1758:
1759: /* ------------------------------------------------------------------------- */
1760: /* SERVER METHODS */
1761: /* ------------------------------------------------------------------------- */
1762:
1763: PRIVATE BOOL launch_server (HTRequest * request, BOOL recursive)
1764: {
1765: if (PROT_TRACE) {
1766: HTParentAnchor *anchor = HTRequest_anchor(request);
1767: char * full_address = HTAnchor_address((HTAnchor *) anchor);
1768: HTTrace("HTAccess.... Serving %s\n", full_address);
1769: HT_FREE(full_address);
1770: }
1771: return HTServe(request, recursive);
1772: }
1773:
1774: /* Serving a request
1775: ** -----------------
1776: ** Returns YES if request accepted, else NO
1777: */
1778: PUBLIC BOOL HTServeAbsolute (const char * url, HTRequest * request)
1779: {
1780: if (url && request) {
1781: HTAnchor * anchor = HTAnchor_findAddress(url);
1782: HTRequest_setAnchor(request, anchor);
1783: return launch_server(request, NO);
1784: }
1785: return NO;
1786: }
Webmaster