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

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: 
                     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;
2.22      frystyk    54:     HTChunk_puts(header, "GET ");
                     55:     HTChunk_puts(header, fullurl);
                     56:     HTChunk_putc(header, ' ');
                     57:     HTChunk_putc(header, CR);
                     58:     HTChunk_putc(header, LF);
                     59:     if (PROT_TRACE) TTYPrint(TDEST, "HTTP Tx..... %s", HTChunk_data(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) {
2.22      frystyk    74:        HTChunk_puts(header, HTMethod_name(request->method));
                     75:        HTChunk_putc(header, ' ');
2.1       frystyk    76:     } else
2.22      frystyk    77:        HTChunk_puts(header, "GET ");
2.1       frystyk    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) {
2.22      frystyk    84:            HTChunk_puts(header, fullurl+1);
2.1       frystyk    85:        } else {
2.22      frystyk    86:            HTChunk_puts(header, fullurl);
2.1       frystyk    87:        }
                     88:        free(fullurl);
                     89:     }
2.22      frystyk    90:     HTChunk_puts(header, " HTTP/1.0");
                     91:     HTChunk_putc(header, CR);
                     92:     HTChunk_putc(header, LF);
2.1       frystyk    93: 
2.4       frystyk    94:     /* Request Headers */
2.22      frystyk    95:     if (request->RequestMask & HT_C_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:                        }
2.22      frystyk   112:                        HTChunk_puts(header, linebuf);
2.1       frystyk   113:                    }
                    114:                }
                    115:            }
                    116:        }
                    117:     }
2.22      frystyk   118:     if (request->RequestMask & HT_C_ACCEPT_CHAR) {
2.4       frystyk   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) {
2.22      frystyk   128:                        HTChunk_puts(header, "Accept-Charset: ");
2.5       frystyk   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);
2.22      frystyk   136:                    HTChunk_puts(header, linebuf);
2.4       frystyk   137:                }
                    138:            }
                    139:        }
                    140:     }
2.22      frystyk   141:     if (request->RequestMask & HT_C_ACCEPT_ENC) {
2.4       frystyk   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) {
2.22      frystyk   151:                        HTChunk_puts(header, "Accept-Encoding: ");
2.5       frystyk   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);
2.22      frystyk   159:                    HTChunk_puts(header, linebuf);
2.4       frystyk   160:                }
                    161:            }
                    162:        }
                    163:     }
2.22      frystyk   164:     if (request->RequestMask & HT_C_ACCEPT_LAN) {
2.4       frystyk   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) {
2.22      frystyk   174:                        HTChunk_puts(header, "Accept-Language: ");
2.5       frystyk   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);
2.22      frystyk   182:                    HTChunk_puts(header, linebuf);
2.4       frystyk   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);
2.22      frystyk   190:        HTChunk_puts(header, linebuf);
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) {
                    195:            sprintf(linebuf, "From: %s%c%c", mailaddress, CR, LF);
2.22      frystyk   196:            HTChunk_puts(header, linebuf);
2.1       frystyk   197:        }
                    198:     }
2.22      frystyk   199:     if (request->RequestMask & HT_C_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.22      frystyk   204:            HTChunk_puts(header, linebuf);
2.8       frystyk   205:        }
                    206:     }
2.22      frystyk   207:     if (request->RequestMask & HT_C_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);
2.22      frystyk   213:        HTChunk_puts(header, linebuf);
2.9       frystyk   214:        free(orig);
2.12      frystyk   215:        free(host);
2.1       frystyk   216:     }
2.22      frystyk   217:     if (request->RequestMask & HT_C_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) {
2.23    ! frystyk   223:            HTChunk_puts(header, "Referer: ");
        !           224:            HTChunk_puts(header, parent);
        !           225:            HTChunk_putc(header, CR);
        !           226:            HTChunk_putc(header, LF);
2.1       frystyk   227:        }
                    228:        free(act);
                    229:        free(parent);
                    230:            free(relative);
                    231:     }
2.22      frystyk   232:     if (request->RequestMask & HT_C_USER_AGENT) {
2.17      frystyk   233:        sprintf(linebuf, "User-Agent: %s/%s %s/%s%c%c",
                    234:                HTLib_appName(), HTLib_appVersion(),
                    235:                HTLib_name(), HTLib_version(), CR, LF);
2.22      frystyk   236:        HTChunk_puts(header, linebuf);
2.1       frystyk   237:     }
2.23    ! frystyk   238:     if (PROT_TRACE)TTYPrint(TDEST,"HTTP........ Generating Request Headers\n");
2.1       frystyk   239: }
                    240: 
2.16      frystyk   241: PRIVATE int HTTPRequest_put_block (HTStream * me, CONST char * b, int l)
2.1       frystyk   242: {
2.7       frystyk   243:     if (!me->target) {
2.1       frystyk   244:        return HT_WOULD_BLOCK;
2.7       frystyk   245:     } else if (me->transparent)
2.11      frystyk   246:        return b ? PUTBLOCK(b, l) : HT_OK;
2.1       frystyk   247:     else {
                    248:        int status;
2.11      frystyk   249:        if (me->version == HTTP_09)
                    250:            HTTP09Request(me, me->request);
                    251:        else
                    252:            HTTPMakeRequest(me, me->request);             /* Generate header */
2.22      frystyk   253:        if ((status = PUTBLOCK(HTChunk_data(me->buffer),
                    254:                               HTChunk_size(me->buffer))) == HT_OK) {
2.1       frystyk   255:            me->transparent = YES;
2.11      frystyk   256:            return b ? PUTBLOCK(b, l) : HT_OK;
2.1       frystyk   257:        }
                    258:        return status;
                    259:     }
                    260: }
                    261: 
2.16      frystyk   262: PRIVATE int HTTPRequest_put_character (HTStream * me, char c)
2.1       frystyk   263: {
2.11      frystyk   264:     return HTTPRequest_put_block(me, &c, 1);
2.1       frystyk   265: }
                    266: 
2.16      frystyk   267: PRIVATE int HTTPRequest_put_string (HTStream * me, CONST char * s)
2.1       frystyk   268: {
2.11      frystyk   269:     return HTTPRequest_put_block(me, s, strlen(s));
2.1       frystyk   270: }
                    271: 
                    272: /*
                    273: **     Flushes data but doesn't free stream object
                    274: */
2.16      frystyk   275: PRIVATE int HTTPRequest_flush (HTStream * me)
2.1       frystyk   276: {
2.13      frystyk   277:     int status = HTTPRequest_put_block(me, NULL, 0);
                    278:     return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
2.1       frystyk   279: }
                    280: 
                    281: /*
                    282: **     Flushes data and frees stream object
                    283: */
2.16      frystyk   284: PRIVATE int HTTPRequest_free (HTStream * me)
2.1       frystyk   285: {
2.11      frystyk   286:     int status = HTTPRequest_flush(me);
                    287:     if (status != HT_WOULD_BLOCK) {
                    288:        if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
                    289:            return HT_WOULD_BLOCK;
2.22      frystyk   290:        HTChunk_delete(me->buffer);
2.11      frystyk   291:        free(me);
2.1       frystyk   292:     }
2.7       frystyk   293:     return status;
2.1       frystyk   294: }
                    295: 
2.16      frystyk   296: PRIVATE int HTTPRequest_abort (HTStream * me, HTList * e)
2.1       frystyk   297: {
2.13      frystyk   298:     if (me->target) (*me->target->isa->abort)(me->target, e);
2.22      frystyk   299:     HTChunk_delete(me->buffer);
2.1       frystyk   300:     free(me);
2.15      frystyk   301:     if (PROT_TRACE) TTYPrint(TDEST, "HTTPRequest. ABORTING...\n");
2.1       frystyk   302:     return HT_ERROR;
                    303: }
                    304: 
                    305: /*     HTTPRequest Stream
                    306: **     -----------------
                    307: */
                    308: PRIVATE CONST HTStreamClass HTTPRequestClass =
                    309: {              
                    310:     "HTTPRequest",
                    311:     HTTPRequest_flush,
                    312:     HTTPRequest_free,
                    313:     HTTPRequest_abort,
                    314:     HTTPRequest_put_character,
                    315:     HTTPRequest_put_string,
                    316:     HTTPRequest_put_block
                    317: };
                    318: 
2.23    ! frystyk   319: PUBLIC HTStream * HTTPRequest_new (HTRequest * request, HTStream * target,
        !           320:                                   BOOL endHeader)
2.1       frystyk   321: {
                    322:     HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
2.11      frystyk   323:     HTdns *dns = HTNet_dns(request->net);
2.1       frystyk   324:     if (!me) outofmem(__FILE__, "HTTPRequest_new");
                    325:     me->isa = &HTTPRequestClass;
                    326:     me->target = target;
                    327:     me->request = request;
2.22      frystyk   328:     me->buffer = HTChunk_new(512);
2.11      frystyk   329:     me->version = HTDNS_serverVersion(dns);
2.1       frystyk   330:     me->transparent = NO;
2.23    ! frystyk   331: 
        !           332:     /* Return general HTTP header stream */
        !           333:     return HTTPGen_new(request, me, endHeader);
2.1       frystyk   334: }

Webmaster