Annotation of libwww/Library/src/HTAccess.c, revision 1.139

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

Webmaster