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

2.1       frystyk     1: /*                                                                   HTTPReq.c
2.23      frystyk     2: **     HTTP REQUEST 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.23      frystyk    25: #include "HTTPGen.h"
2.21      frystyk    26: #include "HTTPUtil.h"
2.1       frystyk    27: #include "HTTPReq.h"                                          /* Implements */
                     28: 
2.24      frystyk    29: #define PUTC(c)                (*me->target->isa->put_character)(me->target, c)
                     30: #define PUTS(s)                (*me->target->isa->put_string)(me->target, s)
2.1       frystyk    31: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
                     32: 
                     33: struct _HTStream {
                     34:     CONST HTStreamClass *      isa;
                     35:     HTStream *                 target;
                     36:     HTRequest *                        request;
2.18      frystyk    37:     SOCKET                     sockfd;
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);
2.24      frystyk    54:     PUTS("GET ");
                     55:     PUTS(fullurl);
                     56:     PUTC(CR);
                     57:     PUTC(LF);
2.11      frystyk    58: }
                     59: 
                     60: /*     HTTPMakeRequest
                     61: **     ---------------
                     62: **     Makes a HTTP/1.0-1.1 request header.
                     63: */
                     64: PRIVATE void HTTPMakeRequest (HTStream * me, HTRequest * request)
2.1       frystyk    65: {
2.24      frystyk    66:     char crlf[3];
                     67:     char qstr[10];
2.13      frystyk    68:     HTParentAnchor *anchor = HTRequest_anchor(request);
2.24      frystyk    69:     *crlf = CR; *(crlf+1) = LF; *(crlf+2) = '\0';
2.1       frystyk    70: 
                     71:     /* Generate the HTTP/1.0 RequestLine */
                     72:     if (request->method != METHOD_INVALID) {
2.24      frystyk    73:        PUTS(HTMethod_name(request->method));
                     74:        PUTC(' ');
2.1       frystyk    75:     } else
2.24      frystyk    76:        PUTS("GET ");
2.1       frystyk    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) {
2.24      frystyk    83:            PUTS(fullurl+1);
2.1       frystyk    84:        } else {
2.24      frystyk    85:            PUTS(fullurl);
2.1       frystyk    86:        }
                     87:        free(fullurl);
                     88:     }
2.25    ! frystyk    89:     PUTC(' ');
        !            90:     PUTS(HTTP_VERSION);
2.24      frystyk    91:     PUTBLOCK(crlf, 2);
2.1       frystyk    92: 
2.4       frystyk    93:     /* Request Headers */
2.22      frystyk    94:     if (request->RequestMask & HT_C_ACCEPT_TYPE) {
2.1       frystyk    95:        int list;
                     96:        HTList *cur;
2.24      frystyk    97:        BOOL first=YES;
2.1       frystyk    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.24      frystyk   102:                while ((pres = (HTPresentation *) HTList_nextObject(cur))) {
2.19      frystyk   103:                    if (pres->rep_out==WWW_PRESENT && pres->quality <= 1.0) {
2.24      frystyk   104:                        if (first) {
                    105:                            PUTS("Accept: ");
                    106:                            first=NO;
                    107:                        } else
                    108:                            PUTC(',');
                    109:                        PUTS(HTAtom_name(pres->rep));
2.1       frystyk   110:                        if (pres->quality != 1.0) {
2.24      frystyk   111:                            sprintf(qstr, ";q=%1.1f", pres->quality);
                    112:                            PUTS(qstr);
2.1       frystyk   113:                        }
                    114:                    }
                    115:                }
2.24      frystyk   116:                if (!first) PUTBLOCK(crlf, 2);
2.1       frystyk   117:            }
                    118:        }
                    119:     }
2.22      frystyk   120:     if (request->RequestMask & HT_C_ACCEPT_CHAR) {
2.4       frystyk   121:        int list;
                    122:        HTList *cur;
2.24      frystyk   123:        BOOL first=YES;
2.4       frystyk   124:        for (list=0; list<2; list++) {
2.14      frystyk   125:            if ((!list && ((cur = HTFormat_charset()) != NULL)) ||
                    126:                (list && ((cur = HTRequest_charset(request)) != NULL))) {
2.4       frystyk   127:                HTAcceptNode *pres;
                    128:                while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5       frystyk   129:                    if (first) {
2.24      frystyk   130:                        PUTS("Accept-Charset: ");
2.5       frystyk   131:                        first=NO;
2.24      frystyk   132:                    } else
                    133:                        PUTC(',');
                    134:                    PUTS(HTAtom_name(pres->atom));
2.4       frystyk   135:                }
2.24      frystyk   136:                if (!first) PUTBLOCK(crlf, 2);
2.4       frystyk   137:            }
                    138:        }
                    139:     }
2.22      frystyk   140:     if (request->RequestMask & HT_C_ACCEPT_ENC) {
2.4       frystyk   141:        int list;
                    142:        HTList *cur;
2.24      frystyk   143:        BOOL first=YES;
2.4       frystyk   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) {
2.24      frystyk   150:                        PUTS("Accept-Encoding: ");
2.5       frystyk   151:                        first=NO;
2.24      frystyk   152:                    } else
                    153:                        PUTC(',');
                    154:                    PUTS(HTAtom_name(pres->atom));
                    155:                    if (pres->quality != 1.0) {
                    156:                        sprintf(qstr, ";q=%1.1f", pres->quality);
                    157:                        PUTS(qstr);
2.5       frystyk   158:                    }
2.4       frystyk   159:                }
2.24      frystyk   160:                if (!first) PUTBLOCK(crlf, 2);
2.4       frystyk   161:            }
                    162:        }
                    163:     }
2.22      frystyk   164:     if (request->RequestMask & HT_C_ACCEPT_LAN) {
2.4       frystyk   165:        int list;
                    166:        HTList *cur;
2.24      frystyk   167:        BOOL first=YES;
2.4       frystyk   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) {
2.24      frystyk   174:                        PUTS("Accept-Language: ");
2.5       frystyk   175:                        first=NO;
2.24      frystyk   176:                    } else
                    177:                        PUTC(',');
                    178:                    PUTS(HTAtom_name(pres->atom));
                    179:                    if (pres->quality != 1.0) {
                    180:                        sprintf(qstr, ";q=%1.1f", pres->quality);
                    181:                        PUTS(qstr);
2.5       frystyk   182:                    }
2.4       frystyk   183:                }
2.24      frystyk   184:                if (!first) PUTBLOCK(crlf, 2);
2.4       frystyk   185:            }
                    186:        }
                    187:     }
                    188:     if (request->authorization != NULL) {          /* Put out authorization */
2.24      frystyk   189:        PUTS("Authorization: ");
                    190:        PUTS(request->authorization);
                    191:        PUTBLOCK(crlf, 2);
2.1       frystyk   192:     }
2.22      frystyk   193:     if (request->RequestMask & HT_C_FROM) {
2.1       frystyk   194:        CONST char *mailaddress = HTGetMailAddress();
                    195:        if (mailaddress) {
2.24      frystyk   196:            PUTS("From: ");
                    197:            PUTS(mailaddress);
                    198:            PUTBLOCK(crlf, 2);
2.1       frystyk   199:        }
                    200:     }
2.22      frystyk   201:     if (request->RequestMask & HT_C_IMS) {
2.21      frystyk   202:        time_t lm = HTAnchor_lastModified(anchor);
2.24      frystyk   203:        if (lm > 0) {
                    204:            PUTS("If-Modified-Since: ");
                    205:            PUTS(HTDateTimeStr(&lm, NO));
                    206:            PUTBLOCK(crlf, 2);
2.8       frystyk   207:        }
                    208:     }
2.22      frystyk   209:     if (request->RequestMask & HT_C_HOST) {
2.13      frystyk   210:        char *orig = HTAnchor_address((HTAnchor *) anchor);
2.12      frystyk   211:        char *host = HTParse(orig, "", PARSE_HOST);
                    212:        char *ptr = strchr(host, ':');               /* Chop off port number */
                    213:        if (ptr) *ptr = '\0';
2.24      frystyk   214:        PUTS("Host: ");
                    215:        PUTS(host);
                    216:        PUTBLOCK(crlf, 2);
2.9       frystyk   217:        free(orig);
2.12      frystyk   218:        free(host);
2.1       frystyk   219:     }
2.22      frystyk   220:     if (request->RequestMask & HT_C_REFERER && request->parentAnchor) {
2.13      frystyk   221:        char *act = HTAnchor_address((HTAnchor *) anchor);
2.1       frystyk   222:        char *parent = HTAnchor_address((HTAnchor *) request->parentAnchor);
                    223:        char *relative = HTParse(parent, act,
                    224:                                 PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
                    225:        if (relative && *relative) {
2.24      frystyk   226:            PUTS("Referer: ");
                    227:            PUTS(parent);
                    228:            PUTBLOCK(crlf, 2);
2.1       frystyk   229:        }
2.24      frystyk   230:        FREE(act);
                    231:        FREE(parent);
                    232:        FREE(relative);
2.1       frystyk   233:     }
2.22      frystyk   234:     if (request->RequestMask & HT_C_USER_AGENT) {
2.24      frystyk   235:        PUTS("User-Agent: ");
                    236:        PUTS(HTLib_appName());
                    237:        PUTC('/');
                    238:        PUTS(HTLib_appVersion());
                    239:        PUTC(' ');
                    240:        PUTS(HTLib_name());
                    241:        PUTC('/');
                    242:        PUTS(HTLib_version());
                    243:        PUTBLOCK(crlf, 2);
2.1       frystyk   244:     }
2.23      frystyk   245:     if (PROT_TRACE)TTYPrint(TDEST,"HTTP........ Generating Request Headers\n");
2.1       frystyk   246: }
                    247: 
2.16      frystyk   248: PRIVATE int HTTPRequest_put_block (HTStream * me, CONST char * b, int l)
2.1       frystyk   249: {
2.7       frystyk   250:     if (!me->target) {
2.1       frystyk   251:        return HT_WOULD_BLOCK;
2.7       frystyk   252:     } else if (me->transparent)
2.11      frystyk   253:        return b ? PUTBLOCK(b, l) : HT_OK;
2.1       frystyk   254:     else {
                    255:        int status;
2.11      frystyk   256:        if (me->version == HTTP_09)
                    257:            HTTP09Request(me, me->request);
2.24      frystyk   258:        else {
2.11      frystyk   259:            HTTPMakeRequest(me, me->request);             /* Generate header */
2.1       frystyk   260:            me->transparent = YES;
2.11      frystyk   261:            return b ? PUTBLOCK(b, l) : HT_OK;
2.1       frystyk   262:        }
                    263:        return status;
                    264:     }
                    265: }
                    266: 
2.16      frystyk   267: PRIVATE int HTTPRequest_put_character (HTStream * me, char c)
2.1       frystyk   268: {
2.11      frystyk   269:     return HTTPRequest_put_block(me, &c, 1);
2.1       frystyk   270: }
                    271: 
2.16      frystyk   272: PRIVATE int HTTPRequest_put_string (HTStream * me, CONST char * s)
2.1       frystyk   273: {
2.11      frystyk   274:     return HTTPRequest_put_block(me, s, strlen(s));
2.1       frystyk   275: }
                    276: 
                    277: /*
                    278: **     Flushes data but doesn't free stream object
                    279: */
2.16      frystyk   280: PRIVATE int HTTPRequest_flush (HTStream * me)
2.1       frystyk   281: {
2.13      frystyk   282:     int status = HTTPRequest_put_block(me, NULL, 0);
                    283:     return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
2.1       frystyk   284: }
                    285: 
                    286: /*
                    287: **     Flushes data and frees stream object
                    288: */
2.16      frystyk   289: PRIVATE int HTTPRequest_free (HTStream * me)
2.1       frystyk   290: {
2.11      frystyk   291:     int status = HTTPRequest_flush(me);
                    292:     if (status != HT_WOULD_BLOCK) {
                    293:        if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
                    294:            return HT_WOULD_BLOCK;
                    295:        free(me);
2.1       frystyk   296:     }
2.7       frystyk   297:     return status;
2.1       frystyk   298: }
                    299: 
2.16      frystyk   300: PRIVATE int HTTPRequest_abort (HTStream * me, HTList * e)
2.1       frystyk   301: {
2.13      frystyk   302:     if (me->target) (*me->target->isa->abort)(me->target, e);
2.1       frystyk   303:     free(me);
2.15      frystyk   304:     if (PROT_TRACE) TTYPrint(TDEST, "HTTPRequest. ABORTING...\n");
2.1       frystyk   305:     return HT_ERROR;
                    306: }
                    307: 
                    308: /*     HTTPRequest Stream
                    309: **     -----------------
                    310: */
                    311: PRIVATE CONST HTStreamClass HTTPRequestClass =
                    312: {              
                    313:     "HTTPRequest",
                    314:     HTTPRequest_flush,
                    315:     HTTPRequest_free,
                    316:     HTTPRequest_abort,
                    317:     HTTPRequest_put_character,
                    318:     HTTPRequest_put_string,
                    319:     HTTPRequest_put_block
                    320: };
                    321: 
2.23      frystyk   322: PUBLIC HTStream * HTTPRequest_new (HTRequest * request, HTStream * target,
                    323:                                   BOOL endHeader)
2.1       frystyk   324: {
                    325:     HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
2.11      frystyk   326:     HTdns *dns = HTNet_dns(request->net);
2.1       frystyk   327:     if (!me) outofmem(__FILE__, "HTTPRequest_new");
                    328:     me->isa = &HTTPRequestClass;
                    329:     me->target = target;
                    330:     me->request = request;
2.11      frystyk   331:     me->version = HTDNS_serverVersion(dns);
2.1       frystyk   332:     me->transparent = NO;
2.23      frystyk   333: 
                    334:     /* Return general HTTP header stream */
                    335:     return HTTPGen_new(request, me, endHeader);
2.1       frystyk   336: }

Webmaster