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

1.120     eric        1: /*                                                                  htaccess.c
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.123   ! frystyk     6: **     @(#) $Id: HTAccess.c,v 1.122 1996/06/28 16:30:48 frystyk Exp $
1.1       timbl       7: **
                      8: ** Authors
1.79      frystyk     9: **     TBL     Tim Berners-Lee timbl@w3.org
1.4       timbl      10: **     JFG     Jean-Francois Groff jfg@dxcern.cern.ch
1.1       timbl      11: **     DD      Denis DeLaRoca (310) 825-4580  <CSP1DWD@mvs.oac.ucla.edu>
1.122     frystyk    12: **     HFN     Henrik Frystyk, frystyk@w3.org
1.1       timbl      13: ** History
                     14: **       8 Jun 92 Telnet hopping prohibited as telnet is not secure TBL
                     15: **     26 Jun 92 When over DECnet, suppressed FTP, Gopher and News. JFG
1.42      frystyk    16: **      6 Oct 92 Moved HTClientHost and HTlogfile into here. TBL
1.1       timbl      17: **     17 Dec 92 Tn3270 added, bug fix. DD
1.2       timbl      18: **      4 Feb 93 Access registration, Search escapes bad chars TBL
1.9       timbl      19: **               PARAMETERS TO HTSEARCH AND HTLOADRELATIVE CHANGED
                     20: **     28 May 93 WAIS gateway explicit if no WAIS library linked in.
1.19      timbl      21: **        Dec 93 Bug change around, more reentrant, etc
1.42      frystyk    22: **     09 May 94 logfile renamed to HTlogfile to avoid clash with WAIS
1.114     frystyk    23: **      8 Jul 94 Insulate HT_FREE();
1.88      frystyk    24: **        Sep 95 Rewritten, HFN
1.1       timbl      25: */
                     26: 
1.67      frystyk    27: /* Library include files */
1.122     frystyk    28: #include "WWWUtil.h"
                     29: #include "WWWCore.h"
                     30: #include "WWWStream.h"
1.123   ! frystyk    31: #include "WWWRules.h"
1.93      frystyk    32: #include "HTReqMan.h"
                     33: #include "HTAccess.h"                                   /* Implemented here */
1.88      frystyk    34: 
1.111     frystyk    35: #define PUTBLOCK(b, l) (*target->isa->put_block)(target, b, l)
                     36: 
                     37: struct _HTStream {
                     38:     HTStreamClass * isa;
                     39: };
                     40: 
1.123   ! frystyk    41: /* --------------------------------------------------------------------------*/
        !            42: /*                             THE GET METHOD                               */
        !            43: /* --------------------------------------------------------------------------*/
1.33      luotonen   44: 
1.90      frystyk    45: /*     Request a document
                     46: **     -----------------
                     47: **     Private version that requests a document from the request manager
                     48: **     Returns YES if request accepted, else NO
1.88      frystyk    49: */
1.101     frystyk    50: PRIVATE BOOL HTLoadDocument (HTRequest * request, BOOL recursive)
1.88      frystyk    51: {
                     52:     if (PROT_TRACE) {
1.90      frystyk    53:        HTParentAnchor *anchor = HTRequest_anchor(request);
                     54:        char * full_address = HTAnchor_address((HTAnchor *) anchor);
1.115     eric       55:        HTTrace("HTAccess.... Accessing document %s\n", full_address);
1.114     frystyk    56:        HT_FREE(full_address);
1.88      frystyk    57:     }
1.96      frystyk    58:     return HTLoad(request, recursive);
1.58      frystyk    59: }
1.1       timbl      60: 
1.90      frystyk    61: /*     Request a document from absolute name
                     62: **     -------------------------------------
                     63: **     Request a document referencd by an absolute URL.
                     64: **     Returns YES if request accepted, else NO
                     65: */
1.122     frystyk    66: PUBLIC BOOL HTLoadAbsolute (const char * url, HTRequest * request)
1.90      frystyk    67: {
                     68:     if (url && request) {
                     69:        HTAnchor * anchor = HTAnchor_findAddress(url);
                     70:        HTRequest_setAnchor(request, anchor);
                     71:        return HTLoadDocument(request, NO);
                     72:     }
                     73:     return NO;
                     74: }
                     75: 
1.123   ! frystyk    76: /*     Request a document from relative name
        !            77: **     -------------------------------------
        !            78: **     Request a document referenced by a relative URL. The relative URL is 
        !            79: **     made absolute by resolving it relative to the address of the 'base' 
        !            80: **     anchor.
        !            81: **     Returns YES if request accepted, else NO
        !            82: */
        !            83: PUBLIC BOOL HTLoadRelative (const char *       relative,
        !            84:                            HTParentAnchor *    base,
        !            85:                            HTRequest *         request)
        !            86: {
        !            87:     BOOL status = NO;
        !            88:     if (relative && base && request) {
        !            89:        char * full_url = NULL;
        !            90:        char * base_url = HTAnchor_address((HTAnchor *) base);
        !            91:        full_url = HTParse(relative, base_url,
        !            92:                         PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
        !            93:        status = HTLoadAbsolute(full_url, request);
        !            94:        HT_FREE(full_url);
        !            95:        HT_FREE(base_url);
        !            96:     }
        !            97:     return status;
        !            98: }
1.90      frystyk    99: 
                    100: /*     Request a document from absolute name to stream
                    101: **     -----------------------------------------------
                    102: **     Request a document referencd by an absolute URL and sending the data
1.123   ! frystyk   103: **     down a stream.
        !           104: **     Returns YES if request accepted, else NO
        !           105: */
        !           106: PUBLIC BOOL HTLoadToStream (const char * url, HTStream * output,
        !           107:                            HTRequest * request)
        !           108: {
        !           109:     if (url && output && request) {
        !           110:        HTRequest_setOutputStream(request, output);
        !           111:        return HTLoadAbsolute(url, request);
        !           112:     }
        !           113:     return NO;
        !           114: }
        !           115: 
        !           116: /*     Load a document and save it ASIS in a local file
        !           117: **     ------------------------------------------------
1.90      frystyk   118: **     Returns YES if request accepted, else NO
                    119: */
1.123   ! frystyk   120: PUBLIC BOOL HTLoadToFile (const char * url, HTRequest * request,
        !           121:                          const char * filename)
1.90      frystyk   122: {
1.123   ! frystyk   123:     if (url && filename && request) {
        !           124:        FILE * fp = NULL;
        !           125:        
        !           126:        /* Check if file exists. If so then ask user if we can replace it */
        !           127:        if (access(filename, F_OK) != -1) {
        !           128:            HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
        !           129:            if (prompt) {
        !           130:                if ((*prompt)(request, HT_A_CONFIRM, HT_MSG_FILE_REPLACE, NULL,
        !           131:                              NULL, NULL) != YES)
        !           132:                    return NO;
        !           133:            }
        !           134:        }
        !           135: 
        !           136:        /* If replace then open the file */
        !           137:        if ((fp = fopen(filename, "wb")) == NULL) {
        !           138:            HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE, 
        !           139:                               (char *) filename, strlen(filename),
        !           140:                               "HTLoadToFile"); 
        !           141:            return NO;
        !           142:        }
        !           143: 
        !           144:        /* Set the output stream and start the request */
        !           145:        HTRequest_setOutputFormat(request, WWW_SOURCE);
        !           146:        HTRequest_setOutputStream(request, HTFWriter_new(request, fp, NO));
        !           147:        return HTLoadAbsolute(url, request);
        !           148:     }
        !           149:     return NO;
1.90      frystyk   150: }
                    151: 
1.122     frystyk   152: /*
                    153: **     Load a URL to a mem buffer
                    154: **     --------------------------
                    155: **     Load a request and store the result in a memory buffer.
                    156: **     Returns chunk if OK - else NULL
                    157: */
                    158: PUBLIC HTChunk * HTLoadToChunk (const char * url, HTRequest * request)
                    159: {
                    160:     if (url && request) {
                    161:        HTChunk * chunk = NULL;
                    162:        HTStream * target = HTStreamToChunk(request, &chunk, 0);
                    163:        HTAnchor * anchor = HTAnchor_findAddress(url);
                    164:        HTRequest_setAnchor(request, anchor);
                    165:        HTRequest_setOutputStream(request, target);
                    166:        if (HTLoadDocument(request, NO) == YES)
                    167:            return chunk;
                    168:        else {
                    169:            HTChunk_delete(chunk);
                    170:            return NULL;
                    171:        }
                    172:     }
                    173:     return NULL;
                    174: }
1.90      frystyk   175: 
                    176: /*     Request an anchor
                    177: **     -----------------
                    178: **     Request the document referenced by the anchor
                    179: **     Returns YES if request accepted, else NO
                    180: */
                    181: PUBLIC BOOL HTLoadAnchor (HTAnchor * anchor, HTRequest * request)
                    182: {
                    183:     if (anchor && request) {
                    184:        HTRequest_setAnchor(request, anchor);
                    185:        return HTLoadDocument(request, NO);
                    186:     }
                    187:     return NO;
                    188: }
                    189: 
                    190: /*     Request an anchor
                    191: **     -----------------
                    192: **     Same as HTLoadAnchor but any information in the Error Stack in the 
                    193: **     request object is kept, so that any error messages in one 
1.52      frystyk   194: **     This function is almost identical to HTLoadAnchor, but it doesn't
                    195: **     clear the error stack so that the information in there is kept.
1.90      frystyk   196: **     Returns YES if request accepted, else NO
                    197: */
                    198: PUBLIC BOOL HTLoadAnchorRecursive (HTAnchor * anchor, HTRequest * request)
                    199: {
                    200:     if (anchor && request) {
                    201:        HTRequest_setAnchor(request, anchor);
                    202:         return HTLoadDocument(request, YES);
                    203:     }
                    204:     return NO;
                    205: }
                    206: 
1.122     frystyk   207: /*
                    208: **     Load a URL to a mem buffer
                    209: **     --------------------------
                    210: **     Load a request and store the result in a memory buffer.
                    211: **     Returns chunk if OK - else NULL
                    212: */
                    213: PUBLIC HTChunk * HTLoadAnchorToChunk (HTAnchor * anchor, HTRequest * request)
                    214: {
                    215:     if (anchor && request) {
                    216:        HTChunk * chunk = NULL;
                    217:        HTStream * target = HTStreamToChunk(request, &chunk, 0);
                    218:        HTRequest_setAnchor(request, anchor);
                    219:        HTRequest_setOutputStream(request, target);
                    220:        if (HTLoadDocument(request, NO) == YES)
                    221:            return chunk;
                    222:        else {
                    223:            HTChunk_delete(chunk);
                    224:            return NULL;
                    225:        }
                    226:     }
                    227:     return NULL;
                    228: }
1.90      frystyk   229: 
1.123   ! frystyk   230: /*
        !           231: **     Load a Rule File
        !           232: **     ----------------
        !           233: **     Load a rule find with the URL specified and add the set of rules to
        !           234: **     the existing set.
        !           235: */
        !           236: PUBLIC BOOL HTLoadRules (const char * url)
        !           237: {
        !           238:     BOOL status = NO;
        !           239:     if (url) {
        !           240:        HTList * list = HTList_new();
        !           241:        HTRequest * request = HTRequest_new();
        !           242:        HTRequest_setPreemptive(request, YES);
        !           243:        HTAlert_setInteractive(NO);
        !           244:        HTConversion_add(list, "application/x-www-rules", "*/*", HTRules,
        !           245:                         1.0, 0.0, 0.0);
        !           246:        HTRequest_setConversion(request, list, YES);
        !           247:        status = HTLoadAbsolute(url, request);
        !           248:        HTConversion_deleteAll(list);
        !           249:        HTRequest_delete(request);
        !           250:     }
        !           251:     return status;
        !           252: }
        !           253: 
        !           254: /* --------------------------------------------------------------------------*/
        !           255: /*                      GET WITH KEYWORDS (SEARCH)                          */
        !           256: /* --------------------------------------------------------------------------*/
        !           257: 
        !           258: /*
        !           259: **     This function creates a URL with a searh part as defined by RFC 1866
        !           260: **     Both the baseurl and the keywords must be escaped.
        !           261: **
        !           262: **     1. The form field names and values are escaped: space
        !           263: **     characters are replaced by `+', and then reserved characters
        !           264: **     are escaped as per [URL]; that is, non-alphanumeric
        !           265: **     characters are replaced by `%HH', a percent sign and two
        !           266: **     hexadecimal digits representing the ASCII code of the
        !           267: **     character. Line breaks, as in multi-line text field values,
        !           268: **     are represented as CR LF pairs, i.e. `%0D%0A'.
        !           269: **
        !           270: **     2. The fields are listed in the order they appear in the
        !           271: **     document with the name separated from the value by `=' and
        !           272: **     the pairs separated from each other by `&'. Fields with null
        !           273: **     values may be omitted. In particular, unselected radio
        !           274: **     buttons and checkboxes should not appear in the encoded
        !           275: **     data, but hidden fields with VALUE attributes present
        !           276: **     should.
        !           277: **
        !           278: **         NOTE - The URI from a query form submission can be
        !           279: **         used in a normal anchor style hyperlink.
        !           280: **         Unfortunately, the use of the `&' character to
        !           281: **         separate form fields interacts with its use in SGML
        !           282: **         attribute values as an entity reference delimiter.
        !           283: **         For example, the URI `http://host/?x=1&y=2' must be
        !           284: **         written `<a href="http://host/?x=1&#38;y=2"' or `<a
        !           285: **         href="http://host/?x=1&amp;y=2">'.
        !           286: **
        !           287: **         HTTP server implementors, and in particular, CGI
        !           288: **         implementors are encouraged to support the use of
        !           289: **         `;' in place of `&' to save users the trouble of
        !           290: **         escaping `&' characters this way.
        !           291: */
        !           292: PRIVATE char * query_url_encode (const char * baseurl, HTChunk * keywords)
        !           293: {
        !           294:     char * fullurl = NULL;
        !           295:     if (baseurl && keywords && HTChunk_size(keywords)) {
        !           296:        int len = strlen(baseurl);
        !           297:        fullurl = (char *) HT_MALLOC(len + HTChunk_size(keywords) + 2);
        !           298:        sprintf(fullurl, "%s?%s", baseurl, HTChunk_data(keywords));
        !           299:        {
        !           300:            char * ptr = fullurl+len;
        !           301:            while (*ptr) {
        !           302:                if (*ptr == ' ') *ptr = '+';
        !           303:                ptr++;
        !           304:            }
        !           305:        }
        !           306:     }
        !           307:     return fullurl;
        !           308: }
        !           309: 
        !           310: PRIVATE char * form_url_encode (const char * baseurl, HTAssocList * formdata)
        !           311: {
        !           312:     if (formdata) {
        !           313:        BOOL first = YES;
        !           314:        int cnt = HTList_count((HTList *) formdata);
        !           315:        HTChunk * fullurl = HTChunk_new(128);
        !           316:        HTAssoc * pres;
        !           317:        if (baseurl) HTChunk_puts(fullurl, baseurl);
        !           318:        while (cnt > 0) {
        !           319:            pres = (HTAssoc *) HTList_objectAt((HTList *) formdata, --cnt);
        !           320:            if (first)
        !           321:                first = NO;
        !           322:            else
        !           323:                HTChunk_putc(fullurl, '&');         /* Could use ';' instead */
        !           324:            HTChunk_puts(fullurl, HTAssoc_name(pres));
        !           325:            HTChunk_putc(fullurl, '=');
        !           326:            HTChunk_puts(fullurl, HTAssoc_value(pres));
        !           327:        }
        !           328:        return HTChunk_toCString(fullurl);
        !           329:     }
        !           330:     return NULL;
        !           331: }
        !           332: 
        !           333: /*     Search a document from absolute name
        !           334: **     ------------------------------------
        !           335: **     Request a document referencd by an absolute URL appended with the
        !           336: **     keywords given. The URL can NOT contain any fragment identifier!
        !           337: **     The list of keywords must be a space-separated list and spaces will
        !           338: **     be converted to '+' before the request is issued.
        !           339: **     Returns YES if request accepted, else NO
        !           340: */
        !           341: PUBLIC BOOL HTSearchAbsolute (HTChunk *                keywords,
        !           342:                              const char *      base,
        !           343:                              HTRequest *       request)
        !           344: {
        !           345:     if (keywords && base && request) {
        !           346:        char * full = query_url_encode(base, keywords);
        !           347:        if (full) {
        !           348:            HTAnchor * anchor = HTAnchor_findAddress(full);
        !           349:            HTRequest_setAnchor(request, anchor);
        !           350:            HT_FREE(full);
        !           351:            return HTLoadDocument(request, NO);
        !           352:        }
        !           353:     }
        !           354:     return NO;
        !           355: }
        !           356: 
        !           357: /*     Search a document from relative name
        !           358: **     -------------------------------------
        !           359: **     Request a document referenced by a relative URL. The relative URL is 
        !           360: **     made absolute by resolving it relative to the address of the 'base' 
        !           361: **     anchor.
        !           362: **     Returns YES if request accepted, else NO
        !           363: */
        !           364: PUBLIC BOOL HTSearchRelative (HTChunk *        keywords,
        !           365:                              const char *      relative,
        !           366:                              HTParentAnchor *  base,
        !           367:                              HTRequest *       request)
        !           368: {
        !           369:     BOOL status = NO;
        !           370:     if (keywords && relative && base && request) {
        !           371:        char * full_url = NULL;
        !           372:        char * base_url = HTAnchor_address((HTAnchor *) base);
        !           373:        full_url = HTParse(relative, base_url,
        !           374:                         PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
        !           375:        status = HTSearchAbsolute(keywords, full_url, request);
        !           376:        HT_FREE(full_url);
        !           377:        HT_FREE(base_url);
        !           378:     }
        !           379:     return status;
        !           380: }
        !           381: 
        !           382: /*
        !           383: **     Search a string
        !           384: **     ---------------
        !           385: **     This is the same as HTSearchAbsolute but instead of using a chunk
        !           386: **     you can pass a string.
        !           387: */
        !           388: PUBLIC BOOL HTSearchString (const char *       keywords,
        !           389:                            HTAnchor *          anchor,
        !           390:                            HTRequest *         request)
        !           391: {
        !           392:     BOOL status = NO;
        !           393:     if (keywords && anchor && request) {       
        !           394:        char * base_url = HTAnchor_address((HTAnchor *) anchor);
        !           395:        HTChunk * chunk = HTChunk_new(strlen(keywords)+2);
        !           396:        HTChunk_puts(chunk, keywords);
        !           397:        status = HTSearchAbsolute(chunk, base_url, request);    
        !           398:        HT_FREE(base_url);
        !           399:        HTChunk_delete(chunk);
        !           400:     }
        !           401:     return status;
        !           402: }      
        !           403: 
1.90      frystyk   404: /*     Search an Anchor
                    405: **     ----------------
                    406: **     Performs a keyword search on word given by the user. Adds the keyword
                    407: **     to the end of the current address and attempts to open the new address.
                    408: **     The list of keywords must be a space-separated list and spaces will
                    409: **     be converted to '+' before the request is issued.
                    410: **     Search can also be performed by HTLoadAbsolute() etc.
                    411: **     Returns YES if request accepted, else NO
                    412: */
1.123   ! frystyk   413: PUBLIC BOOL HTSearchAnchor (HTChunk *          keywords,
        !           414:                            HTAnchor *          anchor,
        !           415:                            HTRequest *         request)
1.90      frystyk   416: {
1.99      frystyk   417:     BOOL status = NO;
1.123   ! frystyk   418:     if (keywords && anchor && request) {
        !           419:        char * base_url = HTAnchor_address(anchor);
        !           420:        status = HTSearchAbsolute(keywords, base_url, request); 
1.114     frystyk   421:        HT_FREE(base_url);
1.90      frystyk   422:     }
1.99      frystyk   423:     return status;
1.2       timbl     424: }
                    425: 
1.123   ! frystyk   426: /* --------------------------------------------------------------------------*/
        !           427: /*                      HANDLING FORMS USING GET AND POST                   */
        !           428: /* --------------------------------------------------------------------------*/
1.2       timbl     429: 
1.123   ! frystyk   430: /*     Send a Form request using GET from absolute name
        !           431: **     ------------------------------------------------
1.90      frystyk   432: **     Request a document referencd by an absolute URL appended with the
1.123   ! frystyk   433: **     formdata given. The URL can NOT contain any fragment identifier!
        !           434: **     The list of form data must be given as an association list where 
        !           435: **     the name is the field name and the value is the value of the field.
        !           436: **     Returns YES if request accepted, else NO
        !           437: */
        !           438: PUBLIC BOOL HTGetFormAbsolute (HTAssocList *   formdata,
        !           439:                               const char *     base,
        !           440:                               HTRequest *      request)
        !           441: {
        !           442:     if (formdata && base && request) {
        !           443:        char * full = form_url_encode(base, formdata);
        !           444:        if (full) {
        !           445:            HTAnchor * anchor = HTAnchor_findAddress(full);
        !           446:            HTRequest_setAnchor(request, anchor);
        !           447:            HT_FREE(full);
        !           448:            return HTLoadDocument(request, NO);
        !           449:        }
        !           450:     }
        !           451:     return NO;
        !           452: }
        !           453: 
        !           454: /*     Send a Form request using GET from relative name
        !           455: **     ------------------------------------------------
        !           456: **     Request a document referencd by a relative URL appended with the
        !           457: **     formdata given. The URL can NOT contain any fragment identifier!
        !           458: **     The list of form data must be given as an association list where 
        !           459: **     the name is the field name and the value is the value of the field.
        !           460: **     Returns YES if request accepted, else NO
        !           461: */
        !           462: PUBLIC BOOL HTGetFormRelative (HTAssocList *   formdata,
        !           463:                               const char *     relative,
        !           464:                               HTParentAnchor * base,
        !           465:                               HTRequest *      request)
        !           466: {
        !           467:     BOOL status = NO;
        !           468:     if (formdata && relative && base && request) {
        !           469:        char * full_url = NULL;
        !           470:        char * base_url = HTAnchor_address((HTAnchor *) base);
        !           471:        full_url=HTParse(relative, base_url,
        !           472:                         PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
        !           473:        status = HTGetFormAbsolute(formdata, full_url, request);
        !           474:        HT_FREE(full_url);
        !           475:        HT_FREE(base_url);
        !           476:     }
        !           477:     return status;
        !           478: }
        !           479: 
        !           480: /*     Send a Form request using GET from an anchor
        !           481: **     --------------------------------------------
        !           482: **     Request a document referencd by an anchor object appended with the
        !           483: **     formdata given. The URL can NOT contain any fragment identifier!
        !           484: **     The list of form data must be given as an association list where 
        !           485: **     the name is the field name and the value is the value of the field.
1.90      frystyk   486: **     Returns YES if request accepted, else NO
                    487: */
1.123   ! frystyk   488: PUBLIC BOOL HTGetFormAnchor (HTAssocList *     formdata,
        !           489:                             HTAnchor *         anchor,
        !           490:                             HTRequest *        request)
        !           491: {
        !           492:     BOOL status = NO;
        !           493:     if (formdata && anchor && request) {
        !           494:        char * base_url = HTAnchor_address((HTAnchor *) anchor);
        !           495:        status = HTGetFormAbsolute(formdata, base_url, request);        
        !           496:        HT_FREE(base_url);
        !           497:     }
        !           498:     return status;
        !           499: }
        !           500: 
        !           501: PRIVATE int HTEntity_callback (HTRequest * request, HTStream * target)
        !           502: {
        !           503:     HTParentAnchor * entity = HTRequest_entityAnchor(request);
        !           504:     if (WWWTRACE) HTTrace("Posting Form from callback function\n");
        !           505:     if (!request || !entity || !target) return HT_ERROR;
        !           506:     {
        !           507:        int status;
        !           508:        char * document = (char *) HTAnchor_document(entity);
        !           509:        int len = HTAnchor_length(entity);
        !           510:        status = (*target->isa->put_block)(target, document, len);
        !           511:        if (status == HT_OK)
        !           512:            return (*target->isa->flush)(target);
        !           513:        if (status == HT_WOULD_BLOCK) {
        !           514:            if (PROT_TRACE)HTTrace("Posting Form Target WOULD BLOCK\n");
        !           515:            return HT_WOULD_BLOCK;
        !           516:        } else if (status == HT_PAUSE) {
        !           517:            if (PROT_TRACE) HTTrace("Posting Form. Target PAUSED\n");
        !           518:            return HT_PAUSE;
        !           519:        } else if (status > 0) {              /* Stream specific return code */
        !           520:            if (PROT_TRACE)
        !           521:                HTTrace("Posting Form. Target returns %d\n", status);
        !           522:            return status;
        !           523:        } else {                                     /* we have a real error */
        !           524:            if (PROT_TRACE) HTTrace("Posting Form Target ERROR\n");
        !           525:            return status;
        !           526:        }
        !           527:     }
        !           528: }
        !           529: 
        !           530: /*     Send a Form request using POST from absolute name
        !           531: **     -------------------------------------------------
        !           532: **     Request a document referencd by an absolute URL appended with the
        !           533: **     formdata given. The URL can NOT contain any fragment identifier!
        !           534: **     The list of form data must be given as an association list where 
        !           535: **     the name is the field name and the value is the value of the field.
        !           536: */
        !           537: PUBLIC HTParentAnchor * HTPostFormAbsolute (HTAssocList *      formdata,
        !           538:                                            const char *        base,
        !           539:                                            HTRequest *         request)
        !           540: {
        !           541:     if (formdata && base && request) {
        !           542:        HTAnchor * anchor = HTAnchor_findAddress(base);
        !           543:        return HTPostFormAnchor(formdata, anchor, request);
        !           544:     }
        !           545:     return NULL;
        !           546: }
        !           547: 
        !           548: /*     Send a Form request using POST from relative name
        !           549: **     -------------------------------------------------
        !           550: **     Request a document referencd by a relative URL appended with the
        !           551: **     formdata given. The URL can NOT contain any fragment identifier!
        !           552: **     The list of form data must be given as an association list where 
        !           553: **     the name is the field name and the value is the value of the field.
        !           554: */
        !           555: PUBLIC HTParentAnchor * HTPostFormRelative (HTAssocList *      formdata,
        !           556:                                            const char *        relative,
        !           557:                                            HTParentAnchor *    base,
        !           558:                                            HTRequest *         request)
1.90      frystyk   559: {
1.123   ! frystyk   560:     HTParentAnchor * postanchor = NULL;
        !           561:     if (formdata && relative && base && request) {
        !           562:        char * full_url = NULL;
        !           563:        char * base_url = HTAnchor_address((HTAnchor *) base);
        !           564:        full_url=HTParse(relative, base_url,
        !           565:                         PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
        !           566:        postanchor = HTPostFormAbsolute(formdata, full_url, request);
        !           567:        HT_FREE(full_url);
        !           568:        HT_FREE(base_url);
        !           569:     }
        !           570:     return postanchor;
        !           571: }
        !           572: 
        !           573: /*     Send a Form request using POST from an anchor
        !           574: **     ---------------------------------------------
        !           575: **     Request a document referencd by an anchor object appended with the
        !           576: **     formdata given. The URL can NOT contain any fragment identifier!
        !           577: **     The list of form data must be given as an association list where 
        !           578: **     the name is the field name and the value is the value of the field.
        !           579: */
        !           580: PUBLIC HTParentAnchor * HTPostFormAnchor (HTAssocList *        formdata,
        !           581:                                          HTAnchor *    anchor,
        !           582:                                          HTRequest *   request)
        !           583: {
        !           584:     HTParentAnchor * postanchor = NULL;
        !           585:     if (formdata && anchor && request) {
        !           586:        HTUserProfile * up = HTRequest_userProfile(request);
        !           587:        char * tmpfile = HTGetTmpFileName(HTUserProfile_tmp(up));
        !           588:        char * tmpurl = HTParse(tmpfile, "file:", PARSE_ALL);
        !           589:        char * form_encoded = form_url_encode(NULL, formdata);
        !           590:        if (form_encoded) {
        !           591: 
        !           592:            /*
        !           593:            **  Now create a new anchor for the post data and set up
        !           594:            **  the rest of the metainformation we know about this anchor. The
        !           595:            **  tmp anchor may actually already exist from previous postings.
        !           596:            */
        !           597:            postanchor = (HTParentAnchor *) HTAnchor_findAddress(tmpurl);
        !           598:            HTAnchor_clearHeader(postanchor);
        !           599:            HTAnchor_setDocument(postanchor, form_encoded);
        !           600:            HTAnchor_setLength(postanchor, strlen(form_encoded));
        !           601:            HTAnchor_setFormat(postanchor, WWW_FORM);
        !           602: 
        !           603:            /*
        !           604:            **  Bind the temporary anchor to the anchor that will contain the
        !           605:            **  response 
        !           606:            */
        !           607:            HTLink_removeAll((HTAnchor *) postanchor);
        !           608:            HTLink_add((HTAnchor *) postanchor, (HTAnchor *) anchor, 
        !           609:                       NULL, METHOD_POST);
        !           610: 
        !           611:            /* Set up the request object */
        !           612:            HTRequest_addGnHd(request, HT_G_DATE);       /* Send date header */
        !           613:            HTRequest_setAnchor(request, anchor);
        !           614:            HTRequest_setEntityAnchor(request, postanchor);
        !           615:            HTRequest_setMethod(request, METHOD_POST);
        !           616: 
        !           617:            /* Add the post form callback function to provide the form data */
        !           618:            HTRequest_setPostCallback(request, HTEntity_callback);
        !           619: 
        !           620:            /* Now start the load normally */
        !           621:            HTLoadDocument(request, NO);
        !           622:        }
        !           623:        HT_FREE(tmpfile);
        !           624:        HT_FREE(tmpurl);
1.90      frystyk   625:     }
1.123   ! frystyk   626:     return postanchor;
1.57      howcome   627: }
                    628: 
1.70      frystyk   629: /* --------------------------------------------------------------------------*/
1.123   ! frystyk   630: /*                             PUT AND POST METHODS                         */
1.70      frystyk   631: /* --------------------------------------------------------------------------*/
                    632: 
1.90      frystyk   633: /*     Copy an anchor
1.70      frystyk   634: **     --------------
1.90      frystyk   635: **     Fetch the URL (possibly local file URL) and send it using either PUT
                    636: **     or POST to the remote destination using HTTP. The caller can decide the
                    637: **     exact method used and which HTTP header fields to transmit by setting
                    638: **     the user fields in the request structure.
1.92      frystyk   639: **     If posting to NNTP then we can't dispatch at this level but must pass
                    640: **     the source anchor to the news module that then takes all the refs
                    641: **     to NNTP and puts into the "newsgroups" header
1.70      frystyk   642: */
1.109     frystyk   643: PUBLIC BOOL HTCopyAnchor (HTAnchor * src_anchor, HTRequest * main_dest)
1.80      frystyk   644: { 
1.106     frystyk   645:     HTRequest * src_req;
                    646:     HTList * cur;
1.109     frystyk   647:     if (!src_anchor || !main_dest) {
1.115     eric      648:        if (WWWTRACE) HTTrace("Copy........ BAD ARGUMENT\n");
1.90      frystyk   649:        return NO;
1.109     frystyk   650:     }
1.70      frystyk   651: 
1.112     frystyk   652:     /* Set the source anchor */
                    653:     main_dest->source_anchor = HTAnchor_parent(src_anchor);
                    654: 
1.80      frystyk   655:     /* Build the POST web if not already there */
1.109     frystyk   656:     if (!main_dest->source) {
                    657:        src_req = HTRequest_dupInternal(main_dest);       /* Get a duplicate */
1.80      frystyk   658:        HTAnchor_clearHeader((HTParentAnchor *) src_anchor);
1.109     frystyk   659:        src_req->method = METHOD_GET;
1.85      frystyk   660:        src_req->reload = HT_MEM_REFRESH;
1.104     frystyk   661:        src_req->output_stream = NULL;
1.80      frystyk   662:        src_req->output_format = WWW_SOURCE;     /* We want source (for now) */
                    663: 
                    664:        /* Set up the main link in the source anchor */
                    665:        {
1.106     frystyk   666:            HTLink * main_link = HTAnchor_mainLink((HTAnchor *) src_anchor);
                    667:            HTAnchor *main_anchor = HTLink_destination(main_link);
                    668:            HTMethod method = HTLink_method(main_link);
1.85      frystyk   669:            if (!main_link || method==METHOD_INVALID) {
1.91      frystyk   670:                if (WWWTRACE)
1.115     eric      671:                    HTTrace("Copy Anchor. No destination found or unspecified method\n");
1.80      frystyk   672:                HTRequest_delete(src_req);
1.90      frystyk   673:                return NO;
1.80      frystyk   674:            }
1.109     frystyk   675:            main_dest->GenMask |= HT_G_DATE;             /* Send date header */
                    676:            main_dest->reload = HT_CACHE_REFRESH;
                    677:            main_dest->method = method;
                    678:            main_dest->input_format = WWW_SOURCE;
                    679:            HTRequest_addDestination(src_req, main_dest);
                    680:            if (HTLoadAnchor(main_anchor, main_dest) == NO)
                    681:                return NO;
1.80      frystyk   682:        }
1.78      frystyk   683: 
1.80      frystyk   684:        /* For all other links in the source anchor */
1.106     frystyk   685:        if ((cur = HTAnchor_subLinks(src_anchor))) {
                    686:            HTLink * pres;
1.109     frystyk   687:            while ((pres = (HTLink *) HTList_nextObject(cur))) {
1.106     frystyk   688:                HTAnchor *dest = HTLink_destination(pres);
                    689:                HTMethod method = HTLink_method(pres);
1.80      frystyk   690:                HTRequest *dest_req;
                    691:                if (!dest || method==METHOD_INVALID) {
1.91      frystyk   692:                    if (WWWTRACE)
1.115     eric      693:                        HTTrace("Copy Anchor. Bad anchor setup %p\n",
1.80      frystyk   694:                                dest);
1.90      frystyk   695:                    return NO;
1.80      frystyk   696:                }
1.109     frystyk   697:                dest_req = HTRequest_dupInternal(main_dest);
1.107     frystyk   698:                dest_req->GenMask |= HT_G_DATE;          /* Send date header */
1.85      frystyk   699:                dest_req->reload = HT_CACHE_REFRESH;
1.80      frystyk   700:                dest_req->method = method;
1.104     frystyk   701:                dest_req->output_stream = NULL;
                    702:                dest_req->output_format = WWW_SOURCE;
1.109     frystyk   703:                HTRequest_addDestination(src_req, dest_req);
1.104     frystyk   704: 
1.90      frystyk   705:                if (HTLoadAnchor(dest, dest_req) == NO)
                    706:                    return NO;
1.80      frystyk   707:            }
                    708:        }
                    709:     } else {                    /* Use the existing Post Web and restart it */
1.109     frystyk   710:        src_req = main_dest->source;
1.80      frystyk   711:        if (src_req->mainDestination)
1.109     frystyk   712:            if (HTLoadDocument(main_dest, NO) == NO)
1.90      frystyk   713:                return NO;
1.80      frystyk   714:        if (src_req->destinations) {
1.106     frystyk   715:            HTRequest * pres;
                    716:            cur = HTAnchor_subLinks(src_anchor);
1.80      frystyk   717:            while ((pres = (HTRequest *) HTList_nextObject(cur)) != NULL) {
1.90      frystyk   718:                if (HTLoadDocument(pres, NO) == NO)
                    719:                    return NO;
1.80      frystyk   720:            }
                    721:        }
1.78      frystyk   722:     }
                    723: 
1.80      frystyk   724:     /* Now open the source */
                    725:     return HTLoadAnchor(src_anchor, src_req);
1.70      frystyk   726: }
                    727: 
1.90      frystyk   728: /*     Upload an Anchor
1.70      frystyk   729: **     ----------------
1.111     frystyk   730: **     This function can be used to send data along with a request to a remote
                    731: **     server. It can for example be used to POST form data to a remote HTTP
                    732: **     server - or it can be used to post a newsletter to a NNTP server. In
                    733: **     either case, you pass a callback function which the request calls when
                    734: **     the remote destination is ready to accept data. In this callback
                    735: **     you get the current request object and a stream into where you can 
                    736: **     write data. It is very important that you return the value returned
                    737: **     by this stream to the Library so that it knows what to do next. The
                    738: **     reason is that the outgoing stream might block or an error may
                    739: **     occur and in that case the Library must know about it. The source
                    740: **     anchor represents the data object in memory and it points to 
                    741: **     the destination anchor by using the POSTWeb method. The source anchor
                    742: **     contains metainformation about the data object in memory and the 
                    743: **     destination anchor represents the reponse from the remote server.
1.90      frystyk   744: **     Returns YES if request accepted, else NO
                    745: */
1.111     frystyk   746: PUBLIC BOOL HTUploadAnchor (HTAnchor *         source_anchor,
                    747:                            HTRequest *         request,
                    748:                            HTPostCallback *    callback)
                    749: {
                    750:     HTLink * link = HTAnchor_mainLink((HTAnchor *) source_anchor);
                    751:     HTAnchor * dest_anchor = HTLink_destination(link);
                    752:     HTMethod method = HTLink_method(link);
                    753:     if (!link || method==METHOD_INVALID || !callback) {
                    754:        if (WWWTRACE)
1.115     eric      755:            HTTrace("Upload...... No destination found or unspecified method\n");
1.90      frystyk   756:        return NO;
1.109     frystyk   757:     }
1.111     frystyk   758:     request->GenMask |= HT_G_DATE;                      /* Send date header */
                    759:     request->reload = HT_CACHE_REFRESH;
                    760:     request->method = method;
                    761:     request->source_anchor = HTAnchor_parent(source_anchor);
                    762:     request->PostCallback = callback;
                    763:     return HTLoadAnchor(dest_anchor, request);
                    764: }
                    765: 
                    766: /*     POST Callback Handler
                    767: **     ---------------------
                    768: **     If you do not want to handle the stream interface on your own, you
                    769: **     can use this function which writes the source anchor hyperdoc to the
                    770: **     target stream for the anchor upload and also handles the return value
                    771: **     from the stream. If you don't want to write the source anchor hyperdoc
                    772: **     then you can register your own callback function that can get the data
                    773: **     you want.
                    774: */
                    775: PUBLIC int HTUpload_callback (HTRequest * request, HTStream * target)
                    776: {
1.115     eric      777:     if (WWWTRACE) HTTrace("Uploading... from callback function\n");
1.111     frystyk   778:     if (!request || !request->source_anchor || !target) return HT_ERROR;
                    779:     {
                    780:        int status;
                    781:        HTParentAnchor * source = request->source_anchor;
                    782:        char * document = (char *) HTAnchor_document(request->source_anchor);
                    783:        int len = HTAnchor_length(source);
                    784:        if (len < 0) {
                    785:            len = strlen(document);
                    786:            HTAnchor_setLength(source, len);
                    787:        }
                    788:        status = (*target->isa->put_block)(target, document, len);
                    789:        if (status == HT_OK)
                    790:            return (*target->isa->flush)(target);
                    791:        if (status == HT_WOULD_BLOCK) {
1.115     eric      792:            if (PROT_TRACE)HTTrace("POST Anchor. Target WOULD BLOCK\n");
1.111     frystyk   793:            return HT_WOULD_BLOCK;
                    794:        } else if (status == HT_PAUSE) {
1.115     eric      795:            if (PROT_TRACE) HTTrace("POST Anchor. Target PAUSED\n");
1.111     frystyk   796:            return HT_PAUSE;
                    797:        } else if (status > 0) {              /* Stream specific return code */
                    798:            if (PROT_TRACE)
1.115     eric      799:                HTTrace("POST Anchor. Target returns %d\n", status);
1.111     frystyk   800:            return status;
1.120     eric      801:        } else {                                     /* we have a real error */
1.115     eric      802:            if (PROT_TRACE) HTTrace("POST Anchor. Target ERROR\n");
1.111     frystyk   803:            return status;
                    804:        }
1.70      frystyk   805:     }
1.123   ! frystyk   806: }
        !           807: 
        !           808: /* ------------------------------------------------------------------------- */
        !           809: /*                             HEAD METHOD                                  */
        !           810: /* ------------------------------------------------------------------------- */
        !           811: 
        !           812: /*     Request metainformation about a document from absolute name
        !           813: **     -----------------------------------------------------------
        !           814: **     Request a document referencd by an absolute URL.
        !           815: **     Returns YES if request accepted, else NO
        !           816: */
        !           817: PUBLIC BOOL HTHeadAbsolute (const char * url, HTRequest * request)
        !           818: {
        !           819:     if (url && request) {
        !           820:        HTAnchor * anchor = HTAnchor_findAddress(url);
        !           821:        HTRequest_setAnchor(request, anchor);
        !           822:        HTRequest_setMethod(request, METHOD_HEAD);
        !           823:        return HTLoadDocument(request, NO);
        !           824:     }
        !           825:     return NO;
        !           826: }
        !           827: 
        !           828: /*     Request metainformation about a document from relative name
        !           829: **     -----------------------------------------------------------
        !           830: **     Request a document referenced by a relative URL. The relative URL is 
        !           831: **     made absolute by resolving it relative to the address of the 'base' 
        !           832: **     anchor.
        !           833: **     Returns YES if request accepted, else NO
        !           834: */
        !           835: PUBLIC BOOL HTHeadRelative (const char *       relative,
        !           836:                            HTParentAnchor *    base,
        !           837:                            HTRequest *         request)
        !           838: {
        !           839:     BOOL status = NO;
        !           840:     if (relative && base && request) {
        !           841:        char * rel = NULL;
        !           842:        char * full_url = NULL;
        !           843:        char * base_url = HTAnchor_address((HTAnchor *) base);
        !           844:        StrAllocCopy(rel, relative);
        !           845:        full_url = HTParse(HTStrip(rel), base_url,
        !           846:                         PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
        !           847:        HTRequest_setMethod(request, METHOD_HEAD);
        !           848:        status = HTLoadAbsolute(full_url, request);
        !           849:        HT_FREE(rel);
        !           850:        HT_FREE(full_url);
        !           851:        HT_FREE(base_url);
        !           852:     }
        !           853:     return status;
        !           854: }
        !           855: 
        !           856: /*     Request metainformation about an anchor
        !           857: **     --------------------------------------
        !           858: **     Request the document referenced by the anchor
        !           859: **     Returns YES if request accepted, else NO
        !           860: */
        !           861: PUBLIC BOOL HTHeadAnchor (HTAnchor * anchor, HTRequest * request)
        !           862: {
        !           863:     if (anchor && request) {
        !           864:        HTRequest_setAnchor(request, anchor);
        !           865:        HTRequest_setMethod(request, METHOD_HEAD);
        !           866:        return HTLoadDocument(request, NO);
        !           867:     }
        !           868:     return NO;
        !           869: }
        !           870: 
        !           871: /* ------------------------------------------------------------------------- */
        !           872: /*                             DELETE METHOD                                */
        !           873: /* ------------------------------------------------------------------------- */
        !           874: 
        !           875: /*     Delete a document on a remote server
        !           876: **     ------------------------------------
        !           877: **     Request a document referencd by an absolute URL.
        !           878: **     Returns YES if request accepted, else NO
        !           879: */
        !           880: PUBLIC BOOL HTDeleteAbsolute (const char * url, HTRequest * request)
        !           881: {
        !           882:     if (url && request) {
        !           883:        HTAnchor * anchor = HTAnchor_findAddress(url);
        !           884:        HTRequest_setAnchor(request, anchor);
        !           885:        HTRequest_setMethod(request, METHOD_DELETE);
        !           886:        return HTLoadDocument(request, NO);
        !           887:     }
        !           888:     return NO;
        !           889: }
        !           890: 
        !           891: /*     Request metainformation about a document from relative name
        !           892: **     -----------------------------------------------------------
        !           893: **     Request a document referenced by a relative URL. The relative URL is 
        !           894: **     made absolute by resolving it relative to the address of the 'base' 
        !           895: **     anchor.
        !           896: **     Returns YES if request accepted, else NO
        !           897: */
        !           898: PUBLIC BOOL HTDeleteRelative (const char *     relative,
        !           899:                            HTParentAnchor *    base,
        !           900:                            HTRequest *         request)
        !           901: {
        !           902:     BOOL status = NO;
        !           903:     if (relative && base && request) {
        !           904:        char * rel = NULL;
        !           905:        char * full_url = NULL;
        !           906:        char * base_url = HTAnchor_address((HTAnchor *) base);
        !           907:        StrAllocCopy(rel, relative);
        !           908:        full_url = HTParse(HTStrip(rel), base_url,
        !           909:                         PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
        !           910:        HTRequest_setMethod(request, METHOD_DELETE);
        !           911:        status = HTLoadAbsolute(full_url, request);
        !           912:        HT_FREE(rel);
        !           913:        HT_FREE(full_url);
        !           914:        HT_FREE(base_url);
        !           915:     }
        !           916:     return status;
        !           917: }
        !           918: 
        !           919: /*     Request metainformation about an anchor
        !           920: **     --------------------------------------
        !           921: **     Request the document referenced by the anchor
        !           922: **     Returns YES if request accepted, else NO
        !           923: */
        !           924: PUBLIC BOOL HTDeleteAnchor (HTAnchor * anchor, HTRequest * request)
        !           925: {
        !           926:     if (anchor && request) {
        !           927:        HTRequest_setAnchor(request, anchor);
        !           928:        HTRequest_setMethod(request, METHOD_DELETE);
        !           929:        return HTLoadDocument(request, NO);
        !           930:     }
        !           931:     return NO;
1.1       timbl     932: }

Webmaster