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

2.1       frystyk     1: /*                                                                   HTTPReq.c
2.13      frystyk     2: **     HTTP MESSAGES GENERATION
2.1       frystyk     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: /* Library Includes */
                     12: #include "tcp.h"
                     13: #include "HTUtils.h"
                     14: #include "HTString.h"
                     15: #include "HTParse.h"
2.4       frystyk    16: #include "HTFormat.h"
2.11      frystyk    17: #include "HTNetMan.h"
                     18: #include "HTDNS.h"
2.1       frystyk    19: #include "HTTCP.h"
2.14      frystyk    20: #include "HTAccess.h"
2.17      frystyk    21: #include "HTWWWStr.h"
2.1       frystyk    22: #include "HTWriter.h"
2.10      frystyk    23: #include "HTReqMan.h"
2.1       frystyk    24: #include "HTChunk.h"
2.13      frystyk    25: #include "HTMIMERq.h"
2.1       frystyk    26: #include "HTTPReq.h"                                          /* Implements */
                     27: 
                     28: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
                     29: 
                     30: struct _HTStream {
                     31:     CONST HTStreamClass *      isa;
                     32:     HTStream *                 target;
                     33:     HTRequest *                        request;
2.18      frystyk    34:     SOCKET                     sockfd;
2.1       frystyk    35:     HTChunk *                          buffer;
2.11      frystyk    36:     int                                version;
2.1       frystyk    37:     BOOL                       transparent;
                     38: };
                     39: 
                     40: /* ------------------------------------------------------------------------- */
                     41: /*                         HTTP Output Request Stream                       */
                     42: /* ------------------------------------------------------------------------- */
                     43: 
2.11      frystyk    44: /*     HTTP09Request
                     45: **     -------------
                     46: **     Makes a HTTP/0.9 request
2.1       frystyk    47: */
2.11      frystyk    48: PRIVATE void HTTP09Request (HTStream * me, HTRequest * request)
                     49: {
                     50:     char *addr = HTAnchor_physical(request->anchor);
                     51:     char *fullurl = HTParse(addr, "", PARSE_PATH|PARSE_PUNCTUATION);
                     52:     HTChunk *header = me->buffer;
                     53:     HTChunkPuts(header, "GET ");
                     54:     HTChunkPuts(header, fullurl);
                     55:     HTChunkPutc(header, ' ');
                     56:     HTChunkPutc(header, CR);
                     57:     HTChunkPutc(header, LF);
2.15      frystyk    58:     if (PROT_TRACE) TTYPrint(TDEST, "HTTP Tx..... %s", HTChunkData(header));
2.11      frystyk    59: }
                     60: 
                     61: /*     HTTPMakeRequest
                     62: **     ---------------
                     63: **     Makes a HTTP/1.0-1.1 request header.
                     64: */
                     65: PRIVATE void HTTPMakeRequest (HTStream * me, HTRequest * request)
2.1       frystyk    66: {
2.13      frystyk    67:     char linebuf[256];                 /* @@@ */
2.1       frystyk    68:     HTChunk *header = me->buffer;
2.13      frystyk    69:     HTParentAnchor *anchor = HTRequest_anchor(request);
2.1       frystyk    70: 
                     71:     /* Generate the HTTP/1.0 RequestLine */
                     72:     if (request->method != METHOD_INVALID) {
                     73:        HTChunkPuts(header, HTMethod_name(request->method));
                     74:        HTChunkPutc(header, ' ');
                     75:     } else
                     76:        HTChunkPuts(header, "GET ");
                     77: 
                     78:     /* If we are using a proxy then only take the `path' info in the URL */
                     79:     {
2.13      frystyk    80:        char *addr = HTAnchor_physical(anchor);
2.6       frystyk    81:        char *fullurl = HTParse(addr, "", PARSE_PATH|PARSE_PUNCTUATION);
2.1       frystyk    82:        if (request->using_proxy) {
                     83:            HTChunkPuts(header, fullurl+1);
                     84:        } else {
                     85:            HTChunkPuts(header, fullurl);
                     86:        }
                     87:        free(fullurl);
                     88:     }
2.11      frystyk    89:     HTChunkPuts(header, " HTTP/1.0");
2.1       frystyk    90:     HTChunkPutc(header, CR);
                     91:     HTChunkPutc(header, LF);
                     92: 
2.4       frystyk    93:     /* Request Headers */
                     94:     if (request->RequestMask & HT_ACCEPT_TYPE) {
2.1       frystyk    95:        int list;
                     96:        HTList *cur;
                     97:        for (list=0; list<2; list++) {
2.14      frystyk    98:            if ((!list && ((cur = HTFormat_conversion()) != NULL)) ||
                     99:                (list && ((cur = HTRequest_conversion(request)) != NULL))) {
2.4       frystyk   100:                HTPresentation  *pres;
2.1       frystyk   101:                while ((pres =(HTPresentation *) HTList_nextObject(cur))) {
2.19      frystyk   102:                    if (pres->rep_out==WWW_PRESENT && pres->quality <= 1.0) {
2.1       frystyk   103:                        if (pres->quality != 1.0) {
                    104:                            sprintf(linebuf, "Accept: %s; q=%1.1f%c%c",
                    105:                                    HTAtom_name(pres->rep),
                    106:                                    pres->quality, CR, LF);
                    107:                        } else {
                    108:                            sprintf(linebuf, "Accept: %s%c%c",
                    109:                                    HTAtom_name(pres->rep), CR, LF);
                    110:                        }
                    111:                        HTChunkPuts(header, linebuf);
                    112:                    }
                    113:                }
                    114:            }
                    115:        }
                    116:     }
2.4       frystyk   117:     if (request->RequestMask & HT_ACCEPT_CHAR) {
                    118:        BOOL first=YES;
                    119:        int list;
                    120:        HTList *cur;
                    121:        for (list=0; list<2; list++) {
2.14      frystyk   122:            if ((!list && ((cur = HTFormat_charset()) != NULL)) ||
                    123:                (list && ((cur = HTRequest_charset(request)) != NULL))) {
2.4       frystyk   124:                HTAcceptNode *pres;
                    125:                while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5       frystyk   126:                    if (first) {
                    127:                        HTChunkPuts(header, "Accept-Charset: ");
                    128:                        first=NO;
                    129:                    }
2.4       frystyk   130:                    if (cur->next)
                    131:                        sprintf(linebuf, "%s,", HTAtom_name(pres->atom));
                    132:                    else
                    133:                        sprintf(linebuf, "%s%c%c", HTAtom_name(pres->atom),
                    134:                                CR, LF);
                    135:                    HTChunkPuts(header, linebuf);
                    136:                }
                    137:            }
                    138:        }
                    139:     }
                    140:     if (request->RequestMask & HT_ACCEPT_ENC) {
                    141:        BOOL first=YES;
                    142:        int list;
                    143:        HTList *cur;
                    144:        for (list=0; list<2; list++) {
2.14      frystyk   145:            if ((!list && ((cur = HTFormat_encoding()) != NULL)) ||
                    146:                (list && ((cur = HTRequest_encoding(request)) != NULL))) {
2.4       frystyk   147:                HTAcceptNode *pres;
                    148:                while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5       frystyk   149:                    if (first) {
                    150:                        HTChunkPuts(header, "Accept-Encoding: ");
                    151:                        first=NO;
                    152:                    }
2.4       frystyk   153:                    if (cur->next)
                    154:                        sprintf(linebuf, "%s,", HTAtom_name(pres->atom));
                    155:                    else
                    156:                        sprintf(linebuf, "%s%c%c", HTAtom_name(pres->atom),
                    157:                                CR, LF);
                    158:                    HTChunkPuts(header, linebuf);
                    159:                }
                    160:            }
                    161:        }
                    162:     }
                    163:     if (request->RequestMask & HT_ACCEPT_LAN) {
                    164:        BOOL first=YES;
                    165:        int list;
                    166:        HTList *cur;
                    167:        for (list=0; list<2; list++) {
2.14      frystyk   168:            if ((!list && ((cur = HTFormat_language()) != NULL)) ||
                    169:                (list && ((cur = HTRequest_language(request)) != NULL))) {
2.4       frystyk   170:                HTAcceptNode *pres;
                    171:                while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5       frystyk   172:                    if (first) {
                    173:                        HTChunkPuts(header, "Accept-Language: ");
                    174:                        first=NO;
                    175:                    }
2.4       frystyk   176:                    if (cur->next)
                    177:                        sprintf(linebuf, "%s,", HTAtom_name(pres->atom));
                    178:                    else
                    179:                        sprintf(linebuf, "%s%c%c", HTAtom_name(pres->atom),
                    180:                                CR, LF);
                    181:                    HTChunkPuts(header, linebuf);
                    182:                }
                    183:            }
                    184:        }
                    185:     }
                    186:     if (request->authorization != NULL) {          /* Put out authorization */
2.1       frystyk   187:        sprintf(linebuf, "Authorization: %s%c%c", request->authorization,
                    188:                CR, LF);
                    189:        HTChunkPuts(header, linebuf);
                    190:     }
2.4       frystyk   191:     if (request->RequestMask & HT_FROM) {
2.1       frystyk   192:        CONST char *mailaddress = HTGetMailAddress();
                    193:        if (mailaddress) {
                    194:            sprintf(linebuf, "From: %s%c%c", mailaddress, CR, LF);
                    195:            HTChunkPuts(header, linebuf);
                    196:        }
                    197:     }
2.8       frystyk   198:     if (request->RequestMask & HT_IMS) {
2.13      frystyk   199:        if (anchor->last_modified != -1) {
2.8       frystyk   200:            sprintf(linebuf, "If-Modified-Since: %s%c%c",
2.13      frystyk   201:                    HTDateTimeStr(&anchor->last_modified, NO), CR, LF);
2.8       frystyk   202:            HTChunkPuts(header, linebuf);
                    203:        }
                    204:     }
2.12      frystyk   205:     if (request->RequestMask & HT_HOST) {
2.13      frystyk   206:        char *orig = HTAnchor_address((HTAnchor *) anchor);
2.12      frystyk   207:        char *host = HTParse(orig, "", PARSE_HOST);
                    208:        char *ptr = strchr(host, ':');               /* Chop off port number */
                    209:        if (ptr) *ptr = '\0';
                    210:        sprintf(linebuf, "Host: %s%c%c", host, CR, LF);
                    211:        HTChunkPuts(header, linebuf);
2.9       frystyk   212:        free(orig);
2.12      frystyk   213:        free(host);
2.1       frystyk   214:     }
2.4       frystyk   215:     if (request->RequestMask & HT_REFERER && request->parentAnchor) {
2.13      frystyk   216:        char *act = HTAnchor_address((HTAnchor *) anchor);
2.1       frystyk   217:        char *parent = HTAnchor_address((HTAnchor *) request->parentAnchor);
                    218:        char *relative = HTParse(parent, act,
                    219:                                 PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
                    220:        if (relative && *relative) {
                    221:            sprintf(linebuf, "Referer: %s%c%c", parent, CR, LF);
                    222:            HTChunkPuts(header, linebuf);
                    223:        }
                    224:        free(act);
                    225:        free(parent);
                    226:            free(relative);
                    227:     }
2.4       frystyk   228:     if (request->RequestMask & HT_USER_AGENT) {
2.17      frystyk   229:        sprintf(linebuf, "User-Agent: %s/%s %s/%s%c%c",
                    230:                HTLib_appName(), HTLib_appVersion(),
                    231:                HTLib_name(), HTLib_version(), CR, LF);
2.1       frystyk   232:        HTChunkPuts(header, linebuf);
                    233:     }
2.15      frystyk   234:     if (PROT_TRACE) TTYPrint(TDEST, "HTTP Tx..... %s", header->data);
2.1       frystyk   235: }
                    236: 
2.16      frystyk   237: PRIVATE int HTTPRequest_put_block (HTStream * me, CONST char * b, int l)
2.1       frystyk   238: {
2.7       frystyk   239:     if (!me->target) {
2.1       frystyk   240:        return HT_WOULD_BLOCK;
2.7       frystyk   241:     } else if (me->transparent)
2.11      frystyk   242:        return b ? PUTBLOCK(b, l) : HT_OK;
2.1       frystyk   243:     else {
                    244:        int status;
2.11      frystyk   245:        if (me->version == HTTP_09)
                    246:            HTTP09Request(me, me->request);
                    247:        else
                    248:            HTTPMakeRequest(me, me->request);             /* Generate header */
2.13      frystyk   249:        if ((status = PUTBLOCK(HTChunkData(me->buffer),
                    250:                               HTChunkSize(me->buffer))) == HT_OK) {
2.1       frystyk   251:            me->transparent = YES;
2.11      frystyk   252:            return b ? PUTBLOCK(b, l) : HT_OK;
2.1       frystyk   253:        }
                    254:        return status;
                    255:     }
                    256: }
                    257: 
2.16      frystyk   258: PRIVATE int HTTPRequest_put_character (HTStream * me, char c)
2.1       frystyk   259: {
2.11      frystyk   260:     return HTTPRequest_put_block(me, &c, 1);
2.1       frystyk   261: }
                    262: 
2.16      frystyk   263: PRIVATE int HTTPRequest_put_string (HTStream * me, CONST char * s)
2.1       frystyk   264: {
2.11      frystyk   265:     return HTTPRequest_put_block(me, s, strlen(s));
2.1       frystyk   266: }
                    267: 
                    268: /*
                    269: **     Flushes data but doesn't free stream object
                    270: */
2.16      frystyk   271: PRIVATE int HTTPRequest_flush (HTStream * me)
2.1       frystyk   272: {
2.13      frystyk   273:     int status = HTTPRequest_put_block(me, NULL, 0);
                    274:     return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
2.1       frystyk   275: }
                    276: 
                    277: /*
                    278: **     Flushes data and frees stream object
                    279: */
2.16      frystyk   280: PRIVATE int HTTPRequest_free (HTStream * me)
2.1       frystyk   281: {
2.11      frystyk   282:     int status = HTTPRequest_flush(me);
                    283:     if (status != HT_WOULD_BLOCK) {
                    284:        if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
                    285:            return HT_WOULD_BLOCK;
                    286:        HTChunkFree(me->buffer);
                    287:        free(me);
2.1       frystyk   288:     }
2.7       frystyk   289:     return status;
2.1       frystyk   290: }
                    291: 
2.16      frystyk   292: PRIVATE int HTTPRequest_abort (HTStream * me, HTList * e)
2.1       frystyk   293: {
2.13      frystyk   294:     if (me->target) (*me->target->isa->abort)(me->target, e);
2.1       frystyk   295:     HTChunkFree(me->buffer);
                    296:     free(me);
2.15      frystyk   297:     if (PROT_TRACE) TTYPrint(TDEST, "HTTPRequest. ABORTING...\n");
2.1       frystyk   298:     return HT_ERROR;
                    299: }
                    300: 
                    301: /*     HTTPRequest Stream
                    302: **     -----------------
                    303: */
                    304: PRIVATE CONST HTStreamClass HTTPRequestClass =
                    305: {              
                    306:     "HTTPRequest",
                    307:     HTTPRequest_flush,
                    308:     HTTPRequest_free,
                    309:     HTTPRequest_abort,
                    310:     HTTPRequest_put_character,
                    311:     HTTPRequest_put_string,
                    312:     HTTPRequest_put_block
                    313: };
                    314: 
2.16      frystyk   315: PUBLIC HTStream * HTTPRequest_new (HTRequest * request,
                    316:                                   HTStream *   target)
2.1       frystyk   317: {
                    318:     HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
2.11      frystyk   319:     HTdns *dns = HTNet_dns(request->net);
2.1       frystyk   320:     if (!me) outofmem(__FILE__, "HTTPRequest_new");
                    321:     me->isa = &HTTPRequestClass;
                    322:     me->target = target;
                    323:     me->request = request;
                    324:     me->buffer = HTChunkCreate(512);
2.11      frystyk   325:     me->version = HTDNS_serverVersion(dns);
2.1       frystyk   326:     me->transparent = NO;
2.13      frystyk   327:     return HTMIMERequest_new(request, me);             /* @@@ */
2.1       frystyk   328: }

Webmaster