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

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

Webmaster