Annotation of libwww/Library/src/HTTPReq.c, revision 2.3

2.1       frystyk     1: /*                                                                   HTTPReq.c
                      2: **     MULTITHREADED IMPLEMENTATION OF HTTP CLIENT
                      3: **
                      4: **     This module implements the output stream for HTTP used for sending
                      5: **     requests with or without a entity body.
                      6: **
                      7: ** History:
                      8: **     Jan 95 HFN      Written from scratch
                      9: **
                     10: */
                     11: 
                     12: /* Library Includes */
                     13: #include "tcp.h"
                     14: #include "HTUtils.h"
                     15: #include "HTString.h"
                     16: #include "HTParse.h"
                     17: #include "HTThread.h"
                     18: #include "HTTCP.h"
                     19: #include "HTWriter.h"
                     20: #include "HTChunk.h"
                     21: #include "HTTPReq.h"                                          /* Implements */
                     22: 
                     23: /* Type definitions and global variables etc. local to this module */ 
                     24: extern char * HTAppName;                 /* Application name: please supply */
                     25: extern char * HTAppVersion;           /* Application version: please supply */
                     26: PUBLIC char * HTProxyHeaders = NULL;               /* Headers to pass as-is */
                     27: 
                     28: /* Macros and other defines */
                     29: #define HTTP_VERSION   "HTTP/1.0"
                     30: #define MIME_VERSION   "MIME/1.0"
                     31: #define PUTC(c)                (*me->target->isa->put_character)(me->target, c)
                     32: #define PUTS(s)                (*me->target->isa->put_string)(me->target, s)
                     33: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
                     34: #define FREE_TARGET    (*me->target->isa->_free)(me->target)
                     35: #define ABORT_TARGET   (*me->target->isa->abort)(me->target, e)
                     36: 
                     37: /* Type definitions and global variables etc. local to this module */
                     38: 
                     39: PRIVATE char linebuf[256];     /* @@@ */
                     40: 
                     41: struct _HTStream {
                     42:     CONST HTStreamClass *      isa;
                     43:     HTStream *                 target;
                     44:     char *                     url;
                     45:     HTRequest *                        request;
                     46:     HTChunk *                          buffer;
                     47:     BOOL                       transparent;
                     48: };
                     49: 
                     50: /* ------------------------------------------------------------------------- */
                     51: /*                         HTTP Output Request Stream                       */
                     52: /* ------------------------------------------------------------------------- */
                     53: 
                     54: /*                                                              HTTPMakeRequest
                     55: **
                     56: **     This function composes the HTTP request header.
                     57: */
                     58: PRIVATE void HTTPMakeRequest ARGS2(HTStream *, me, HTRequest *, request)
                     59: {
                     60:     HTChunk *header = me->buffer;
                     61:     HTParentAnchor *entity =
                     62:        (request->CopyRequest && request->CopyRequest->anchor) ?
                     63:            request->CopyRequest->anchor : request->anchor;
                     64: 
                     65:     /* Generate the HTTP/1.0 RequestLine */
                     66:     if (request->method != METHOD_INVALID) {
                     67:        HTChunkPuts(header, HTMethod_name(request->method));
                     68:        HTChunkPutc(header, ' ');
                     69:     } else
                     70:        HTChunkPuts(header, "GET ");
                     71: 
                     72:     /* If we are using a proxy then only take the `path' info in the URL */
                     73:     {
                     74:        char *fullurl = HTParse(me->url, "", PARSE_PATH|PARSE_PUNCTUATION);
                     75:        if (request->using_proxy) {
                     76:            HTChunkPuts(header, fullurl+1);
                     77:        } else {
                     78:            HTChunkPuts(header, fullurl);
                     79:        }
                     80:        free(fullurl);
                     81:     }
                     82:     HTChunkPutc(header, ' ');
                     83:     HTChunkPuts(header, HTTP_VERSION);
                     84:     HTChunkPutc(header, CR);
                     85:     HTChunkPutc(header, LF);
                     86: 
                     87:     /* Header Information */
                     88:     if (request->HeaderMask & HT_DATE) {
                     89:        time_t local = time(NULL);
                     90:        sprintf(linebuf, "Date: %s%c%c", HTDateTimeStr(&local, NO), CR,LF);
                     91:        HTChunkPuts(header, linebuf);
                     92:     }
                     93:     if (request->HeaderMask & HT_MESSAGE_ID) {
                     94:        CONST char *msgid = HTMessageIdStr();
                     95:        if (msgid) {
                     96:            sprintf(linebuf, "Message-ID: %s%c%c", msgid, CR, LF);
                     97:            HTChunkPuts(header, linebuf);
                     98:        }
                     99:     }
                    100:     if (request->HeaderMask & HT_MIME) {
                    101:        sprintf(linebuf, "MIME-Version: %s%c%c", MIME_VERSION, CR, LF);
                    102:        HTChunkPuts(header, linebuf);
                    103:     }
                    104: 
                    105:     /* Run through local and global list of conversions for `Accept' lines */
                    106:     if (request->HeaderMask & HT_ACCEPT) {
                    107:        int list;
                    108:        HTList *cur;
                    109:        for (list=0; list<2; list++) {
                    110:            if ((!list && ((cur=HTConversions) != NULL)) ||
                    111:                (list && ((cur=request->conversions) != NULL))) {
                    112:                HTPresentation *pres;
                    113:                while ((pres =(HTPresentation *) HTList_nextObject(cur))) {
                    114:                    if (pres->rep_out == WWW_PRESENT) {
                    115:                        if (pres->quality != 1.0) {
                    116:                            sprintf(linebuf, "Accept: %s; q=%1.1f%c%c",
                    117:                                    HTAtom_name(pres->rep),
                    118:                                    pres->quality, CR, LF);
                    119:                        } else {
                    120:                            sprintf(linebuf, "Accept: %s%c%c",
                    121:                                    HTAtom_name(pres->rep), CR, LF);
                    122:                        }
                    123:                        HTChunkPuts(header, linebuf);
                    124:                    }
                    125:                }
                    126:            }
                    127:        }
                    128:     }
                    129: 
                    130:     /* Put out authorization */
                    131:     if (request->authorization != NULL) {
                    132:        sprintf(linebuf, "Authorization: %s%c%c", request->authorization,
                    133:                CR, LF);
                    134:        HTChunkPuts(header, linebuf);
                    135:     }
                    136:     if (request->HeaderMask & HT_FROM) {
                    137:        CONST char *mailaddress = HTGetMailAddress();
                    138:        if (mailaddress) {
                    139:            sprintf(linebuf, "From: %s%c%c", mailaddress, CR, LF);
                    140:            HTChunkPuts(header, linebuf);
                    141:        }
                    142:     }
                    143:     if (request->HeaderMask & HT_PRAGMA) {
                    144:        sprintf(linebuf, "Pragma: %s%c%c", "no-cache", CR, LF);
                    145:        HTChunkPuts(header, linebuf);
                    146:     }
                    147:     if (request->HeaderMask & HT_REFERER && request->parentAnchor) {
                    148:        char *act = HTAnchor_address((HTAnchor *) request->anchor);
                    149:        char *parent = HTAnchor_address((HTAnchor *) request->parentAnchor);
                    150:        char *relative = HTParse(parent, act,
                    151:                                 PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
                    152:        if (relative && *relative) {
                    153:            sprintf(linebuf, "Referer: %s%c%c", parent, CR, LF);
                    154:            HTChunkPuts(header, linebuf);
                    155:        }
                    156:        free(act);
                    157:        free(parent);
                    158:            free(relative);
                    159:     }
                    160:     if (request->HeaderMask & HT_USER_AGENT) {
                    161:        sprintf(linebuf, "User-Agent: %s/%s libwww/%s%c%c",
                    162:                HTAppName ? HTAppName : "unknown",
                    163:                HTAppVersion ? HTAppVersion : "0.0",
                    164:                HTLibraryVersion, CR, LF);
                    165:        HTChunkPuts(header, linebuf);
                    166:     }
                    167: 
                    168:     /* Now put out entity headers if we are using PUT or POST. If we have a
                    169:     ** PostAnchor then we take the information from this and uses the
                    170:     ** destination anchor to contain the reply. Otherwise, we have created an
                    171:     ** anchor (using internal editing etc) and we can use the destination
                    172:     ** anchor directly.
                    173:     */
                    174:     if (request->method==METHOD_PUT || request->method==METHOD_POST) {
2.2       frystyk   175:        if (request->EntityMask & HT_ALLOW) {           /* @@@@@@@@@@ */
2.1       frystyk   176: 
                    177:        }
                    178:        if (request->EntityMask & HT_CONTENT_ENCODING &&
                    179:            entity->content_encoding) {
                    180:            sprintf(linebuf, "Content-Encoding: %s%c%c",
                    181:                    HTAtom_name(entity->content_encoding), CR, LF);
                    182:            HTChunkPuts(header, linebuf);
                    183:        }
2.3     ! frystyk   184:        if (request->EntityMask & HT_CONTENT_LANGUAGE) {     /* @@@ LIST @@@ */
        !           185:            sprintf(linebuf, "Content-Language: %s%c%c",
        !           186:                    HTAtom_name(entity->content_language), CR, LF);
        !           187:            HTChunkPuts(header, linebuf);
2.1       frystyk   188:        }
                    189:        if (request->EntityMask & HT_CONTENT_LENGTH) {   /* Must be there!!! */
                    190:            sprintf(linebuf, "Content-Length: %ld%c%c",
                    191:                    entity->content_length, CR, LF);
                    192:            HTChunkPuts(header, linebuf);       
                    193:        }
                    194:        if (request->EntityMask & HT_CTE && entity->cte) {
                    195:            sprintf(linebuf, "Content-Transfer-Encoding: %s%c%c",
                    196:                    HTAtom_name(entity->cte), CR, LF);
                    197:            HTChunkPuts(header, linebuf);
                    198:        }
                    199:        if (request->EntityMask & HT_CONTENT_TYPE && entity->content_type) {
2.2       frystyk   200:            sprintf(linebuf, "Content-Type: %s",
                    201:                    HTAtom_name(entity->content_type));
                    202:            if (entity->charset) {
                    203:                strcat(linebuf, "; charset=");
                    204:                strcat(linebuf, HTAtom_name(entity->charset));
                    205:            }
                    206:            if (entity->level) {
                    207:                strcat(linebuf, "; level=");
                    208:                strcat(linebuf, HTAtom_name(entity->level));
                    209:            }
2.1       frystyk   210:            HTChunkPuts(header, linebuf);
2.2       frystyk   211:            HTChunkPutc(header, CR);
                    212:            HTChunkPutc(header, LF);
2.1       frystyk   213:        }
                    214:        if (request->EntityMask & HT_DERIVED_FROM && entity->derived_from) {
                    215:            sprintf(linebuf, "Derived-From: %s%c%c", entity->derived_from,
                    216:                    CR, LF);
                    217:            HTChunkPuts(header, linebuf);
                    218:        }
2.2       frystyk   219:        if (request->EntityMask & HT_EXPIRES) {         /* @@@@@@@@@@ */
2.1       frystyk   220: 
                    221:        }
2.2       frystyk   222:        if (request->EntityMask & HT_LAST_MODIFIED) {   /* @@@@@@@@@@ */
2.1       frystyk   223: 
                    224:        }
2.2       frystyk   225:        if (request->EntityMask & HT_LINK) {            /* @@@@@@@@@@ */
2.1       frystyk   226: 
                    227:        }
2.2       frystyk   228:        if (request->EntityMask & HT_TITLE) {           /* @@@@@@@@@@ */
2.1       frystyk   229: 
                    230:        }
2.2       frystyk   231:        if (request->EntityMask & HT_URI) {             /* @@@@@@@@@@ */
2.1       frystyk   232: 
                    233:        }
                    234:        if (request->EntityMask & HT_VERSION && entity->version) {
                    235:            sprintf(linebuf, "Version: %s%c%c", entity->version, CR, LF);
                    236:            HTChunkPuts(header, linebuf);
                    237:        }
                    238:     }
                    239: 
                    240:     /* Put out extra information if any */
                    241:     if (request->ExtraHeaders)
                    242:        HTChunkPuts(header, request->ExtraHeaders);
                    243:     
                    244:     HTChunkPutc(header, CR);                      /* Blank line means "end" */
                    245:     HTChunkPutc(header, LF);
                    246:     HTChunkTerminate(header);
                    247:     if (PROT_TRACE)
                    248:        fprintf(TDEST, "HTTP Tx..... %s", header->data);
                    249: }
                    250: 
                    251: PRIVATE int HTTPRequest_put_character ARGS2(HTStream *, me, char, c)
                    252: {
                    253:     if (!me->target)
                    254:        return HT_WOULD_BLOCK;
                    255:     else if (me->transparent)
                    256:        return PUTC(c);
                    257:     else {
                    258:        int status;
                    259:        HTTPMakeRequest(me, me->request);                 /* Generate header */
                    260:        if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
                    261:            me->transparent = YES;
                    262:            return PUTC(c);
                    263:        }
                    264:        return status;
                    265:     }
                    266: }
                    267: 
                    268: PRIVATE int HTTPRequest_put_string ARGS2(HTStream *, me, CONST char*, s)
                    269: {
                    270:     if (!me->target)
                    271:        return HT_WOULD_BLOCK;
                    272:     else if (me->transparent)
                    273:        return PUTS(s);
                    274:     else {
                    275:        int status;
                    276:        HTTPMakeRequest(me, me->request);                 /* Generate header */
                    277:        if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
                    278:            me->transparent = YES;
                    279:            return PUTS(s);
                    280:        }
                    281:        return status;
                    282:     }
                    283: }
                    284: 
                    285: PRIVATE int HTTPRequest_put_block ARGS3(HTStream *, me, CONST char*, b, int, l)
                    286: {
                    287:     if (!me->target)
                    288:        return HT_WOULD_BLOCK;
                    289:     else if (me->transparent)
                    290:        return PUTBLOCK(b, l);
                    291:     else {
                    292:        int status;
                    293:        HTTPMakeRequest(me, me->request);                 /* Generate header */
                    294:        if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
                    295:            me->transparent = YES;
                    296:            return PUTBLOCK(b, l);
                    297:        }
                    298:        return status;
                    299:     }
                    300: }
                    301: 
                    302: /*
                    303: **     Flushes data but doesn't free stream object
                    304: */
                    305: PRIVATE int HTTPRequest_flush ARGS1(HTStream *, me)
                    306: {
                    307:     if (!me->target)
                    308:        return HT_WOULD_BLOCK;
                    309:     else if (!me->transparent) {
                    310:        int status;
                    311:        HTTPMakeRequest(me, me->request);                 /* Generate header */
                    312:        if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK)
                    313:            me->transparent = YES;
                    314:        else
                    315:            return status;
                    316:     }
                    317:     return HT_OK;
                    318: }
                    319: 
                    320: /*
                    321: **     Flushes data and frees stream object
                    322: */
                    323: PRIVATE int HTTPRequest_free ARGS1(HTStream *, me)
                    324: {
                    325:     if (!me->target)
                    326:        return HT_WOULD_BLOCK;
                    327:     else if (!me->transparent) {
                    328:        int status;
                    329:        HTTPMakeRequest(me, me->request);                 /* Generate header */
                    330:        if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK)
                    331:            me->transparent = YES;
                    332:        else
                    333:            return status;
                    334:     }
                    335:     if (me->target)
                    336:        FREE_TARGET;
                    337:     HTChunkFree(me->buffer);
                    338:     free(me);
                    339:     return HT_OK;
                    340: }
                    341: 
                    342: PRIVATE int HTTPRequest_abort ARGS2(HTStream *, me, HTError, e)
                    343: {
                    344:     if (me->target)
                    345:        ABORT_TARGET;
                    346:     FREE(me->url);
                    347:     HTChunkFree(me->buffer);
                    348:     free(me);
                    349:     if (PROT_TRACE)
                    350:        fprintf(TDEST, "HTTPRequest. ABORTING...\n");
                    351:     return HT_ERROR;
                    352: }
                    353: 
                    354: /*     HTTPRequest Stream
                    355: **     -----------------
                    356: */
                    357: PRIVATE CONST HTStreamClass HTTPRequestClass =
                    358: {              
                    359:     "HTTPRequest",
                    360:     HTTPRequest_flush,
                    361:     HTTPRequest_free,
                    362:     HTTPRequest_abort,
                    363:     HTTPRequest_put_character,
                    364:     HTTPRequest_put_string,
                    365:     HTTPRequest_put_block
                    366: };
                    367: 
                    368: PUBLIC HTStream * HTTPRequest_new ARGS2(HTRequest *,   request,
                    369:                                        HTStream *,     target)
                    370: {
                    371:     HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
                    372:     if (!me) outofmem(__FILE__, "HTTPRequest_new");
                    373:     me->isa = &HTTPRequestClass;
                    374:     me->target = target;
                    375:     me->url = HTAnchor_physical(request->anchor);
                    376:     me->request = request;
                    377:     me->buffer = HTChunkCreate(512);
                    378:     me->transparent = NO;
                    379:     return me;
                    380: }
                    381: 
                    382: 

Webmaster