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

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

Webmaster