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

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) {
        !           175:        if (request->EntityMask & HT_ALLOW) {
        !           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:        }
        !           184:        if (request->EntityMask & HT_CONTENT_LANGUAGE) {
        !           185: 
        !           186:        }
        !           187:        if (request->EntityMask & HT_CONTENT_LENGTH) {   /* Must be there!!! */
        !           188:            sprintf(linebuf, "Content-Length: %ld%c%c",
        !           189:                    entity->content_length, CR, LF);
        !           190:            HTChunkPuts(header, linebuf);       
        !           191:        }
        !           192:        if (request->EntityMask & HT_CTE && entity->cte) {
        !           193:            sprintf(linebuf, "Content-Transfer-Encoding: %s%c%c",
        !           194:                    HTAtom_name(entity->cte), CR, LF);
        !           195:            HTChunkPuts(header, linebuf);
        !           196:        }
        !           197:        if (request->EntityMask & HT_CONTENT_TYPE && entity->content_type) {
        !           198:            sprintf(linebuf, "Content-Type: %s%c%c",
        !           199:                    HTAtom_name(entity->content_type), CR, LF);
        !           200:            HTChunkPuts(header, linebuf);
        !           201:        }
        !           202:        if (request->EntityMask & HT_DERIVED_FROM && entity->derived_from) {
        !           203:            sprintf(linebuf, "Derived-From: %s%c%c", entity->derived_from,
        !           204:                    CR, LF);
        !           205:            HTChunkPuts(header, linebuf);
        !           206:        }
        !           207:        if (request->EntityMask & HT_EXPIRES) {
        !           208: 
        !           209:        }
        !           210:        if (request->EntityMask & HT_LAST_MODIFIED) {
        !           211: 
        !           212:        }
        !           213:        if (request->EntityMask & HT_LINK) {
        !           214: 
        !           215:        }
        !           216:        if (request->EntityMask & HT_TITLE) {
        !           217: 
        !           218:        }
        !           219:        if (request->EntityMask & HT_URI) {
        !           220: 
        !           221:        }
        !           222:        if (request->EntityMask & HT_VERSION && entity->version) {
        !           223:            sprintf(linebuf, "Version: %s%c%c", entity->version, CR, LF);
        !           224:            HTChunkPuts(header, linebuf);
        !           225:        }
        !           226:     }
        !           227: 
        !           228:     /* Put out extra information if any */
        !           229:     if (request->ExtraHeaders)
        !           230:        HTChunkPuts(header, request->ExtraHeaders);
        !           231:     
        !           232:     HTChunkPutc(header, CR);                      /* Blank line means "end" */
        !           233:     HTChunkPutc(header, LF);
        !           234:     HTChunkTerminate(header);
        !           235:     if (PROT_TRACE)
        !           236:        fprintf(TDEST, "HTTP Tx..... %s", header->data);
        !           237: }
        !           238: 
        !           239: PRIVATE int HTTPRequest_put_character ARGS2(HTStream *, me, char, c)
        !           240: {
        !           241:     if (!me->target)
        !           242:        return HT_WOULD_BLOCK;
        !           243:     else if (me->transparent)
        !           244:        return PUTC(c);
        !           245:     else {
        !           246:        int status;
        !           247:        HTTPMakeRequest(me, me->request);                 /* Generate header */
        !           248:        if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
        !           249:            me->transparent = YES;
        !           250:            return PUTC(c);
        !           251:        }
        !           252:        return status;
        !           253:     }
        !           254: }
        !           255: 
        !           256: PRIVATE int HTTPRequest_put_string ARGS2(HTStream *, me, CONST char*, s)
        !           257: {
        !           258:     if (!me->target)
        !           259:        return HT_WOULD_BLOCK;
        !           260:     else if (me->transparent)
        !           261:        return PUTS(s);
        !           262:     else {
        !           263:        int status;
        !           264:        HTTPMakeRequest(me, me->request);                 /* Generate header */
        !           265:        if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
        !           266:            me->transparent = YES;
        !           267:            return PUTS(s);
        !           268:        }
        !           269:        return status;
        !           270:     }
        !           271: }
        !           272: 
        !           273: PRIVATE int HTTPRequest_put_block ARGS3(HTStream *, me, CONST char*, b, int, l)
        !           274: {
        !           275:     if (!me->target)
        !           276:        return HT_WOULD_BLOCK;
        !           277:     else if (me->transparent)
        !           278:        return PUTBLOCK(b, l);
        !           279:     else {
        !           280:        int status;
        !           281:        HTTPMakeRequest(me, me->request);                 /* Generate header */
        !           282:        if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
        !           283:            me->transparent = YES;
        !           284:            return PUTBLOCK(b, l);
        !           285:        }
        !           286:        return status;
        !           287:     }
        !           288: }
        !           289: 
        !           290: /*
        !           291: **     Flushes data but doesn't free stream object
        !           292: */
        !           293: PRIVATE int HTTPRequest_flush ARGS1(HTStream *, me)
        !           294: {
        !           295:     if (!me->target)
        !           296:        return HT_WOULD_BLOCK;
        !           297:     else if (!me->transparent) {
        !           298:        int status;
        !           299:        HTTPMakeRequest(me, me->request);                 /* Generate header */
        !           300:        if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK)
        !           301:            me->transparent = YES;
        !           302:        else
        !           303:            return status;
        !           304:     }
        !           305:     return HT_OK;
        !           306: }
        !           307: 
        !           308: /*
        !           309: **     Flushes data and frees stream object
        !           310: */
        !           311: PRIVATE int HTTPRequest_free ARGS1(HTStream *, me)
        !           312: {
        !           313:     if (!me->target)
        !           314:        return HT_WOULD_BLOCK;
        !           315:     else if (!me->transparent) {
        !           316:        int status;
        !           317:        HTTPMakeRequest(me, me->request);                 /* Generate header */
        !           318:        if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK)
        !           319:            me->transparent = YES;
        !           320:        else
        !           321:            return status;
        !           322:     }
        !           323:     if (me->target)
        !           324:        FREE_TARGET;
        !           325:     HTChunkFree(me->buffer);
        !           326:     free(me);
        !           327:     return HT_OK;
        !           328: }
        !           329: 
        !           330: PRIVATE int HTTPRequest_abort ARGS2(HTStream *, me, HTError, e)
        !           331: {
        !           332:     if (me->target)
        !           333:        ABORT_TARGET;
        !           334:     FREE(me->url);
        !           335:     HTChunkFree(me->buffer);
        !           336:     free(me);
        !           337:     if (PROT_TRACE)
        !           338:        fprintf(TDEST, "HTTPRequest. ABORTING...\n");
        !           339:     return HT_ERROR;
        !           340: }
        !           341: 
        !           342: /*     HTTPRequest Stream
        !           343: **     -----------------
        !           344: */
        !           345: PRIVATE CONST HTStreamClass HTTPRequestClass =
        !           346: {              
        !           347:     "HTTPRequest",
        !           348:     HTTPRequest_flush,
        !           349:     HTTPRequest_free,
        !           350:     HTTPRequest_abort,
        !           351:     HTTPRequest_put_character,
        !           352:     HTTPRequest_put_string,
        !           353:     HTTPRequest_put_block
        !           354: };
        !           355: 
        !           356: PUBLIC HTStream * HTTPRequest_new ARGS2(HTRequest *,   request,
        !           357:                                        HTStream *,     target)
        !           358: {
        !           359:     HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
        !           360:     if (!me) outofmem(__FILE__, "HTTPRequest_new");
        !           361:     me->isa = &HTTPRequestClass;
        !           362:     me->target = target;
        !           363:     me->url = HTAnchor_physical(request->anchor);
        !           364:     me->request = request;
        !           365:     me->buffer = HTChunkCreate(512);
        !           366:     me->transparent = NO;
        !           367:     return me;
        !           368: }
        !           369: 
        !           370: 

Webmaster