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