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

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.21    ! frystyk    26: #include "HTTPUtil.h"
2.1       frystyk    27: #include "HTTPReq.h"                                          /* Implements */
                     28: 
                     29: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
                     30: 
                     31: struct _HTStream {
                     32:     CONST HTStreamClass *      isa;
                     33:     HTStream *                 target;
                     34:     HTRequest *                        request;
2.18      frystyk    35:     SOCKET                     sockfd;
2.1       frystyk    36:     HTChunk *                          buffer;
2.11      frystyk    37:     int                                version;
2.1       frystyk    38:     BOOL                       transparent;
                     39: };
                     40: 
                     41: /* ------------------------------------------------------------------------- */
                     42: /*                         HTTP Output Request Stream                       */
                     43: /* ------------------------------------------------------------------------- */
                     44: 
2.11      frystyk    45: /*     HTTP09Request
                     46: **     -------------
                     47: **     Makes a HTTP/0.9 request
2.1       frystyk    48: */
2.11      frystyk    49: PRIVATE void HTTP09Request (HTStream * me, HTRequest * request)
                     50: {
                     51:     char *addr = HTAnchor_physical(request->anchor);
                     52:     char *fullurl = HTParse(addr, "", PARSE_PATH|PARSE_PUNCTUATION);
                     53:     HTChunk *header = me->buffer;
                     54:     HTChunkPuts(header, "GET ");
                     55:     HTChunkPuts(header, fullurl);
                     56:     HTChunkPutc(header, ' ');
                     57:     HTChunkPutc(header, CR);
                     58:     HTChunkPutc(header, LF);
2.15      frystyk    59:     if (PROT_TRACE) TTYPrint(TDEST, "HTTP Tx..... %s", HTChunkData(header));
2.11      frystyk    60: }
                     61: 
                     62: /*     HTTPMakeRequest
                     63: **     ---------------
                     64: **     Makes a HTTP/1.0-1.1 request header.
                     65: */
                     66: PRIVATE void HTTPMakeRequest (HTStream * me, HTRequest * request)
2.1       frystyk    67: {
2.13      frystyk    68:     char linebuf[256];                 /* @@@ */
2.1       frystyk    69:     HTChunk *header = me->buffer;
2.13      frystyk    70:     HTParentAnchor *anchor = HTRequest_anchor(request);
2.1       frystyk    71: 
                     72:     /* Generate the HTTP/1.0 RequestLine */
                     73:     if (request->method != METHOD_INVALID) {
                     74:        HTChunkPuts(header, HTMethod_name(request->method));
                     75:        HTChunkPutc(header, ' ');
                     76:     } else
                     77:        HTChunkPuts(header, "GET ");
                     78: 
                     79:     /* If we are using a proxy then only take the `path' info in the URL */
                     80:     {
2.13      frystyk    81:        char *addr = HTAnchor_physical(anchor);
2.6       frystyk    82:        char *fullurl = HTParse(addr, "", PARSE_PATH|PARSE_PUNCTUATION);
2.1       frystyk    83:        if (request->using_proxy) {
                     84:            HTChunkPuts(header, fullurl+1);
                     85:        } else {
                     86:            HTChunkPuts(header, fullurl);
                     87:        }
                     88:        free(fullurl);
                     89:     }
2.11      frystyk    90:     HTChunkPuts(header, " HTTP/1.0");
2.1       frystyk    91:     HTChunkPutc(header, CR);
                     92:     HTChunkPutc(header, LF);
                     93: 
2.4       frystyk    94:     /* Request Headers */
                     95:     if (request->RequestMask & HT_ACCEPT_TYPE) {
2.1       frystyk    96:        int list;
                     97:        HTList *cur;
                     98:        for (list=0; list<2; list++) {
2.14      frystyk    99:            if ((!list && ((cur = HTFormat_conversion()) != NULL)) ||
                    100:                (list && ((cur = HTRequest_conversion(request)) != NULL))) {
2.4       frystyk   101:                HTPresentation  *pres;
2.1       frystyk   102:                while ((pres =(HTPresentation *) HTList_nextObject(cur))) {
2.19      frystyk   103:                    if (pres->rep_out==WWW_PRESENT && pres->quality <= 1.0) {
2.1       frystyk   104:                        if (pres->quality != 1.0) {
                    105:                            sprintf(linebuf, "Accept: %s; q=%1.1f%c%c",
                    106:                                    HTAtom_name(pres->rep),
                    107:                                    pres->quality, CR, LF);
                    108:                        } else {
                    109:                            sprintf(linebuf, "Accept: %s%c%c",
                    110:                                    HTAtom_name(pres->rep), CR, LF);
                    111:                        }
                    112:                        HTChunkPuts(header, linebuf);
                    113:                    }
                    114:                }
                    115:            }
                    116:        }
                    117:     }
2.4       frystyk   118:     if (request->RequestMask & HT_ACCEPT_CHAR) {
                    119:        BOOL first=YES;
                    120:        int list;
                    121:        HTList *cur;
                    122:        for (list=0; list<2; list++) {
2.14      frystyk   123:            if ((!list && ((cur = HTFormat_charset()) != NULL)) ||
                    124:                (list && ((cur = HTRequest_charset(request)) != NULL))) {
2.4       frystyk   125:                HTAcceptNode *pres;
                    126:                while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5       frystyk   127:                    if (first) {
                    128:                        HTChunkPuts(header, "Accept-Charset: ");
                    129:                        first=NO;
                    130:                    }
2.4       frystyk   131:                    if (cur->next)
                    132:                        sprintf(linebuf, "%s,", HTAtom_name(pres->atom));
                    133:                    else
                    134:                        sprintf(linebuf, "%s%c%c", HTAtom_name(pres->atom),
                    135:                                CR, LF);
                    136:                    HTChunkPuts(header, linebuf);
                    137:                }
                    138:            }
                    139:        }
                    140:     }
                    141:     if (request->RequestMask & HT_ACCEPT_ENC) {
                    142:        BOOL first=YES;
                    143:        int list;
                    144:        HTList *cur;
                    145:        for (list=0; list<2; list++) {
2.14      frystyk   146:            if ((!list && ((cur = HTFormat_encoding()) != NULL)) ||
                    147:                (list && ((cur = HTRequest_encoding(request)) != NULL))) {
2.4       frystyk   148:                HTAcceptNode *pres;
                    149:                while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5       frystyk   150:                    if (first) {
                    151:                        HTChunkPuts(header, "Accept-Encoding: ");
                    152:                        first=NO;
                    153:                    }
2.4       frystyk   154:                    if (cur->next)
                    155:                        sprintf(linebuf, "%s,", HTAtom_name(pres->atom));
                    156:                    else
                    157:                        sprintf(linebuf, "%s%c%c", HTAtom_name(pres->atom),
                    158:                                CR, LF);
                    159:                    HTChunkPuts(header, linebuf);
                    160:                }
                    161:            }
                    162:        }
                    163:     }
                    164:     if (request->RequestMask & HT_ACCEPT_LAN) {
                    165:        BOOL first=YES;
                    166:        int list;
                    167:        HTList *cur;
                    168:        for (list=0; list<2; list++) {
2.14      frystyk   169:            if ((!list && ((cur = HTFormat_language()) != NULL)) ||
                    170:                (list && ((cur = HTRequest_language(request)) != NULL))) {
2.4       frystyk   171:                HTAcceptNode *pres;
                    172:                while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5       frystyk   173:                    if (first) {
                    174:                        HTChunkPuts(header, "Accept-Language: ");
                    175:                        first=NO;
                    176:                    }
2.4       frystyk   177:                    if (cur->next)
                    178:                        sprintf(linebuf, "%s,", HTAtom_name(pres->atom));
                    179:                    else
                    180:                        sprintf(linebuf, "%s%c%c", HTAtom_name(pres->atom),
                    181:                                CR, LF);
                    182:                    HTChunkPuts(header, linebuf);
                    183:                }
                    184:            }
                    185:        }
                    186:     }
                    187:     if (request->authorization != NULL) {          /* Put out authorization */
2.1       frystyk   188:        sprintf(linebuf, "Authorization: %s%c%c", request->authorization,
                    189:                CR, LF);
                    190:        HTChunkPuts(header, linebuf);
                    191:     }
2.4       frystyk   192:     if (request->RequestMask & HT_FROM) {
2.1       frystyk   193:        CONST char *mailaddress = HTGetMailAddress();
                    194:        if (mailaddress) {
                    195:            sprintf(linebuf, "From: %s%c%c", mailaddress, CR, LF);
                    196:            HTChunkPuts(header, linebuf);
                    197:        }
                    198:     }
2.8       frystyk   199:     if (request->RequestMask & HT_IMS) {
2.21    ! frystyk   200:        time_t lm = HTAnchor_lastModified(anchor);
        !           201:        if (lm != -1) {
2.8       frystyk   202:            sprintf(linebuf, "If-Modified-Since: %s%c%c",
2.21    ! frystyk   203:                    HTDateTimeStr(&lm, 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