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

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

Webmaster