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

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

Webmaster