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

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

Webmaster