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

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

Webmaster