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

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

Webmaster