Annotation of libwww/Library/src/HTTPReq.c, revision 2.46
2.1 frystyk 1: /* HTTPReq.c
2.23 frystyk 2: ** HTTP REQUEST GENERATION
2.1 frystyk 3: **
2.32 frystyk 4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
2.46 ! frystyk 6: ** @(#) $Id: HTTPReq.c,v 2.45 1996/10/07 02:05:26 frystyk Exp $
2.32 frystyk 7: **
2.1 frystyk 8: ** This module implements the output stream for HTTP used for sending
9: ** requests with or without a entity body.
10: **
11: ** History:
12: ** Jan 95 HFN Written from scratch
13: */
14:
15: /* Library Includes */
2.29 frystyk 16: #include "sysdep.h"
2.28 frystyk 17: #include "WWWUtil.h"
2.32 frystyk 18: #include "WWWCore.h"
19:
2.23 frystyk 20: #include "HTTPGen.h"
2.21 frystyk 21: #include "HTTPUtil.h"
2.1 frystyk 22: #include "HTTPReq.h" /* Implements */
23:
2.24 frystyk 24: #define PUTC(c) (*me->target->isa->put_character)(me->target, c)
25: #define PUTS(s) (*me->target->isa->put_string)(me->target, s)
2.1 frystyk 26: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
27:
28: struct _HTStream {
2.29 frystyk 29: const HTStreamClass * isa;
2.1 frystyk 30: HTStream * target;
31: HTRequest * request;
2.18 frystyk 32: SOCKET sockfd;
2.11 frystyk 33: int version;
2.38 frystyk 34: int state;
35: char * url;
2.1 frystyk 36: BOOL transparent;
37: };
38:
39: /* ------------------------------------------------------------------------- */
40: /* HTTP Output Request Stream */
41: /* ------------------------------------------------------------------------- */
42:
2.11 frystyk 43: /* HTTP09Request
44: ** -------------
45: ** Makes a HTTP/0.9 request
2.1 frystyk 46: */
2.38 frystyk 47: PRIVATE int HTTP09Request (HTStream * me, HTRequest * request)
2.11 frystyk 48: {
2.34 frystyk 49: HTParentAnchor * anchor = HTRequest_anchor(request);
50: char * addr = HTAnchor_physical(anchor);
2.38 frystyk 51: if (!me->url) me->url = HTParse(addr, "", PARSE_PATH|PARSE_PUNCTUATION);
52: if (me->state == 0) {
53: PUTS("GET ");
54: me->state++;
55: }
56: if (me->state == 1) {
57: int status = PUTS(me->url);
58: if (status != HT_OK) return status;
59: me->state++;
60: }
2.24 frystyk 61: PUTC(CR);
62: PUTC(LF);
2.38 frystyk 63: return HT_OK;
2.11 frystyk 64: }
65:
66: /* HTTPMakeRequest
67: ** ---------------
68: ** Makes a HTTP/1.0-1.1 request header.
69: */
2.38 frystyk 70: PRIVATE int HTTPMakeRequest (HTStream * me, HTRequest * request)
2.1 frystyk 71: {
2.39 frystyk 72: HTMethod method = HTRequest_method(request);
73: HTRqHd request_mask = HTRequest_rqHd(request);
74: HTParentAnchor * anchor = HTRequest_anchor(request);
2.43 frystyk 75: char * etag = HTAnchor_etag(anchor);
2.24 frystyk 76: char crlf[3];
77: char qstr[10];
78: *crlf = CR; *(crlf+1) = LF; *(crlf+2) = '\0';
2.1 frystyk 79:
2.41 frystyk 80: /* Generate the HTTP/1.x RequestLine */
2.38 frystyk 81: if (me->state == 0) {
2.34 frystyk 82: if (method != METHOD_INVALID) {
83: PUTS(HTMethod_name(method));
84: PUTC(' ');
85: } else
86: PUTS("GET ");
2.38 frystyk 87: me->state++;
2.34 frystyk 88: }
2.1 frystyk 89:
2.39 frystyk 90: /*
2.45 frystyk 91: ** Generate the Request URI. If we are using full request URI then it's
92: ** easy. Otherwise we must filter out the path part of the URI.
93: ** In case it's a OPTIONS request then if there is no pathinfo then use
94: ** a * instead. If we use a method different from GET or HEAD then use
95: ** the content-location if available.
2.39 frystyk 96: */
2.45 frystyk 97: if (me->state == 1) {
98: char * abs_location = NULL;
2.38 frystyk 99: char * addr = HTAnchor_physical(anchor);
2.45 frystyk 100:
101: /*
102: ** If we are using a method different from HEAD and GET then use
103: ** the Content-Location if available, else the Request-URI.
104: */
105: if (!HTMethod_isSafe(method)) {
106: char * location = HTAnchor_location(anchor);
107: if (location) {
108: if (HTURL_isAbsolute(location))
109: addr = location;
110: else {
111: /*
112: ** We have a content-location but it is relative and
113: ** must expand it either to the content-base or to
114: ** the Request-URI itself.
115: */
116: char * base = HTAnchor_base(anchor);
117: abs_location = HTParse(location, base, PARSE_ALL);
118: addr = abs_location;
119: }
120: }
121: }
122:
123: /*
124: ** If we are using a proxy or newer versions of HTTP then we can
125: ** send the full URL. Otherwise we only send the path.
126: */
127: if (HTRequest_fullURI(request))
128: StrAllocCopy(me->url, addr);
129: else {
130: me->url = HTParse(addr, "", PARSE_PATH | PARSE_PUNCTUATION);
2.39 frystyk 131: if (method == METHOD_OPTIONS) {
132: /*
133: ** We don't preserve the final slash or lack of same through
134: ** out the code. This is mainly for optimization reasons
2.44 frystyk 135: ** but it gives a problem OPTIONS. We can either send a "*"
136: ** or a "/" but not both. For now we send a "*".
2.39 frystyk 137: */
2.45 frystyk 138: if (!strcmp(me->url, "/")) *me->url = '*';
2.39 frystyk 139: }
2.1 frystyk 140: }
2.45 frystyk 141: HT_FREE(abs_location);
142: me->state++;
143: }
144:
145: /*
146: ** Now send the URL that we have put together
147: */
148: if (me->state == 2) {
149: int status = HT_OK;
150: if ((status = PUTS(me->url)) != HT_OK) return status;
2.38 frystyk 151: me->state++;
2.1 frystyk 152: }
2.25 frystyk 153: PUTC(' ');
2.41 frystyk 154:
155: /*
156: ** Send out the version number. If we know it is a HTTP/1.0 server we
157: ** are talking to then use HTTP/1.0, else use HTTP/1.1 as default version
158: ** number
159: */
160: if (me->version == HTTP_10)
161: PUTS(HTTP_VERSION_10);
162: else
163: PUTS(HTTP_VERSION);
2.24 frystyk 164: PUTBLOCK(crlf, 2);
2.1 frystyk 165:
2.4 frystyk 166: /* Request Headers */
2.34 frystyk 167: if (request_mask & HT_C_ACCEPT_TYPE) {
2.37 frystyk 168: /*
169: ** If caller has specified a specific output format then use this.
170: ** Otherwise use all the registered converters to generate the
171: ** accept header
172: */
173: if (HTRequest_outputFormat(request) == WWW_PRESENT) {
174: int list;
175: HTList *cur;
176: BOOL first=YES;
177: for (list=0; list<2; list++) {
178: if ((!list && ((cur = HTFormat_conversion()) != NULL)) ||
179: (list && ((cur = HTRequest_conversion(request))!=NULL))) {
180: HTPresentation * pres;
181: while ((pres=(HTPresentation *) HTList_nextObject(cur))) {
182: if (pres->rep_out==WWW_PRESENT && pres->quality<=1.0) {
183: if (first) {
184: PUTS("Accept: ");
185: first=NO;
186: } else
187: PUTC(',');
188: PUTS(HTAtom_name(pres->rep));
2.46 ! frystyk 189: if (pres->quality < 1.0 && pres->quality >= 0.0) {
2.37 frystyk 190: sprintf(qstr, ";q=%1.1f", pres->quality);
191: PUTS(qstr);
192: }
2.1 frystyk 193: }
194: }
195: }
196: }
2.37 frystyk 197: if (!first) PUTBLOCK(crlf, 2);
198: } else {
199: PUTS("Accept: ");
200: PUTS(HTAtom_name(HTRequest_outputFormat(request)));
201: PUTBLOCK(crlf, 2);
202: }
2.1 frystyk 203: }
2.34 frystyk 204: if (request_mask & HT_C_ACCEPT_CHAR) {
2.4 frystyk 205: int list;
206: HTList *cur;
2.24 frystyk 207: BOOL first=YES;
2.4 frystyk 208: for (list=0; list<2; list++) {
2.14 frystyk 209: if ((!list && ((cur = HTFormat_charset()) != NULL)) ||
210: (list && ((cur = HTRequest_charset(request)) != NULL))) {
2.4 frystyk 211: HTAcceptNode *pres;
212: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 213: if (first) {
2.24 frystyk 214: PUTS("Accept-Charset: ");
2.5 frystyk 215: first=NO;
2.24 frystyk 216: } else
217: PUTC(',');
218: PUTS(HTAtom_name(pres->atom));
2.46 ! frystyk 219: if (pres->quality < 1.0 && pres->quality >= 0.0) {
! 220: sprintf(qstr, ";q=%1.1f", pres->quality);
! 221: PUTS(qstr);
! 222: }
2.4 frystyk 223: }
224: }
225: }
2.31 frystyk 226: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 227: }
2.34 frystyk 228: if (request_mask & HT_C_ACCEPT_ENC) {
2.4 frystyk 229: int list;
230: HTList *cur;
2.24 frystyk 231: BOOL first=YES;
2.4 frystyk 232: for (list=0; list<2; list++) {
2.33 frystyk 233: if ((!list && ((cur = HTFormat_contentCoding()) != NULL)) ||
2.14 frystyk 234: (list && ((cur = HTRequest_encoding(request)) != NULL))) {
2.33 frystyk 235: HTCoding * pres;
236: while ((pres = (HTCoding *) HTList_nextObject(cur))) {
2.46 ! frystyk 237: double quality = HTCoding_quality(pres);
2.5 frystyk 238: if (first) {
2.24 frystyk 239: PUTS("Accept-Encoding: ");
2.32 frystyk 240: first = NO;
2.24 frystyk 241: } else
242: PUTC(',');
2.33 frystyk 243: PUTS(HTCoding_name(pres));
2.46 ! frystyk 244: if (quality < 1.0 && quality >= 0.0) {
! 245: sprintf(qstr, ";q=%1.1f", quality);
! 246: PUTS(qstr);
! 247: }
! 248: }
! 249: }
! 250: }
! 251: if (!first) PUTBLOCK(crlf, 2);
! 252: }
! 253: if (request_mask & HT_C_ACCEPT_TE) {
! 254: int list;
! 255: HTList *cur;
! 256: BOOL first=YES;
! 257: for (list=0; list<2; list++) {
! 258: if ((!list && ((cur = HTFormat_transferCoding()) != NULL)) ||
! 259: (list && ((cur = HTRequest_transfer(request)) != NULL))) {
! 260: HTCoding * pres;
! 261: while ((pres = (HTCoding *) HTList_nextObject(cur))) {
! 262: double quality = HTCoding_quality(pres);
! 263: if (first) {
! 264: PUTS("TE: ");
! 265: first = NO;
! 266: } else
! 267: PUTC(',');
! 268: PUTS(HTCoding_name(pres));
! 269: if (quality < 1.0 && quality >= 0.0) {
! 270: sprintf(qstr, ";q=%1.1f", quality);
! 271: PUTS(qstr);
! 272: }
2.4 frystyk 273: }
274: }
275: }
2.31 frystyk 276: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 277: }
2.34 frystyk 278: if (request_mask & HT_C_ACCEPT_LAN) {
2.4 frystyk 279: int list;
280: HTList *cur;
2.24 frystyk 281: BOOL first=YES;
2.4 frystyk 282: for (list=0; list<2; list++) {
2.14 frystyk 283: if ((!list && ((cur = HTFormat_language()) != NULL)) ||
284: (list && ((cur = HTRequest_language(request)) != NULL))) {
2.4 frystyk 285: HTAcceptNode *pres;
286: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 287: if (first) {
2.24 frystyk 288: PUTS("Accept-Language: ");
2.5 frystyk 289: first=NO;
2.24 frystyk 290: } else
291: PUTC(',');
292: PUTS(HTAtom_name(pres->atom));
2.46 ! frystyk 293: if (pres->quality < 1.0 && pres->quality >= 0.0) {
2.24 frystyk 294: sprintf(qstr, ";q=%1.1f", pres->quality);
295: PUTS(qstr);
2.5 frystyk 296: }
2.4 frystyk 297: }
298: }
299: }
2.31 frystyk 300: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 301: }
2.36 frystyk 302: if (request_mask & HT_C_AUTH) {
2.34 frystyk 303: HTAssocList * cur = HTRequest_credentials(request);
304: if (cur) { /* Access authentication */
305: HTAssoc * pres;
306: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
307: PUTS(HTAssoc_name(pres));
308: PUTS(": ");
309: PUTS(HTAssoc_value(pres));
310: PUTBLOCK(crlf, 2);
311: }
2.28 frystyk 312: }
2.1 frystyk 313: }
2.46 ! frystyk 314: if (request_mask & HT_C_EXPECT) {
! 315: HTAssocList * cur = HTRequest_expect(request);
! 316: if (cur) {
! 317: BOOL first=YES;
! 318: HTAssoc * pres;
! 319: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
! 320: char * value = HTAssoc_value(pres);
! 321: if (first) {
! 322: PUTS("Expect: ");
! 323: first = NO;
! 324: } else
! 325: PUTC(',');
! 326:
! 327: /* Output the name */
! 328: PUTS(HTAssoc_name(pres));
! 329:
! 330: /* Only output the value if not empty string */
! 331: if (*value) {
! 332: PUTS("=");
! 333: PUTS(value);
! 334: }
! 335: }
! 336: PUTBLOCK(crlf, 2);
! 337: }
! 338: }
2.34 frystyk 339: if (request_mask & HT_C_FROM) {
340: HTUserProfile * up = HTRequest_userProfile(request);
341: const char * mailaddress = HTUserProfile_email(up);
2.1 frystyk 342: if (mailaddress) {
2.24 frystyk 343: PUTS("From: ");
344: PUTS(mailaddress);
345: PUTBLOCK(crlf, 2);
2.1 frystyk 346: }
347: }
2.34 frystyk 348: if (request_mask & HT_C_HOST) {
2.13 frystyk 349: char *orig = HTAnchor_address((HTAnchor *) anchor);
2.12 frystyk 350: char *host = HTParse(orig, "", PARSE_HOST);
2.34 frystyk 351: #if 0
352: /* Keep the port number for HTTP/1.1 compliance */
2.12 frystyk 353: char *ptr = strchr(host, ':'); /* Chop off port number */
354: if (ptr) *ptr = '\0';
2.34 frystyk 355: #endif
2.24 frystyk 356: PUTS("Host: ");
357: PUTS(host);
358: PUTBLOCK(crlf, 2);
2.26 frystyk 359: HT_FREE(orig);
360: HT_FREE(host);
2.39 frystyk 361: }
2.42 frystyk 362:
363: /*
364: ** In the "If-*" series of headers, the ones related to etags have higher
365: ** priority than the date relates ones. That is, if we have a etag then
2.45 frystyk 366: ** use that, otherwise use the date. First we check for range, match, and
367: ** unmodified-since.
2.42 frystyk 368: */
2.45 frystyk 369: if (request_mask & HT_C_IF_RANGE && etag) {
370: PUTS("If-Range: \"");
371: PUTS(etag);
372: PUTC('"');
373: PUTBLOCK(crlf, 2);
374: if (PROT_TRACE) HTTrace("HTTP........ If-Range using etag `%s\'\n", etag);
375: } else if (request_mask & HT_C_IF_MATCH && etag) {
2.43 frystyk 376: PUTS("If-Match: \"");
377: PUTS(etag);
378: PUTC('"');
379: PUTBLOCK(crlf, 2);
380: if (PROT_TRACE) HTTrace("HTTP........ If-Match using etag `%s\'\n", etag);
381: } else if (request_mask & HT_C_IF_UNMOD_SINCE) {
2.42 frystyk 382: time_t lm = HTAnchor_lastModified(anchor);
383: if (lm > 0) {
2.43 frystyk 384: PUTS("If-Unmodified-Since: ");
2.42 frystyk 385: PUTS(HTDateTimeStr(&lm, NO));
386: PUTBLOCK(crlf, 2);
2.43 frystyk 387: if (PROT_TRACE) HTTrace("HTTP........ If-Unmodified-Since\n");
2.42 frystyk 388: }
389: }
2.45 frystyk 390:
391: /*
392: ** If-None-Match and If-Modified-Since are equivalent except that the
393: ** first uses etags and the second uses dates. Etags have precedence over
394: ** dates.
395: */
2.43 frystyk 396: if (request_mask & HT_C_IF_NONE_MATCH && etag) {
397: PUTS("If-None-Match: \"");
398: PUTS(etag);
399: PUTC('"');
400: PUTBLOCK(crlf, 2);
2.46 ! frystyk 401: if (PROT_TRACE) HTTrace("HTTP........ If-None-Match `%s\'\n", etag);
! 402: }
! 403: if (request_mask & HT_C_IMS) {
2.42 frystyk 404: time_t lm = HTAnchor_lastModified(anchor);
405: if (lm > 0) {
2.43 frystyk 406: PUTS("If-Modified-Since: ");
2.42 frystyk 407: PUTS(HTDateTimeStr(&lm, NO));
408: PUTBLOCK(crlf, 2);
2.43 frystyk 409: if (PROT_TRACE) HTTrace("HTTP........ If-Modified-Since\n");
2.42 frystyk 410: }
411: }
412:
2.45 frystyk 413: /*
414: ** Max forwards is mainly for TRACE where we want to be able to stop the
415: ** TRACE at a specific location un the message path.
416: */
2.39 frystyk 417: if (request_mask & HT_C_MAX_FORWARDS) {
418: int hops = HTRequest_maxForwards(request);
419: if (hops >= 0) {
420: sprintf(qstr, "%d", hops);
421: PUTS("Max-Forwards: ");
422: PUTS(qstr);
423: PUTBLOCK(crlf, 2);
424: }
2.42 frystyk 425: }
2.45 frystyk 426:
427: /*
428: ** Range requests. For now, we only take the first entry registered for
429: ** this request. This means that you can only send a single "unit" and
430: ** then a set of range within this unit. This is in accordance with
431: ** HTTP/1.1. Multiple units will go on multiple lines.
432: */
2.42 frystyk 433: if (request_mask & HT_C_RANGE) {
2.45 frystyk 434: HTAssocList * cur = HTRequest_range(request);
435: if (cur) { /* Range requests */
436: HTAssoc * pres;
437: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
438: PUTS("Range: ");
439: PUTS(HTAssoc_name(pres)); /* Unit */
440: PUTS("=");
441: PUTS(HTAssoc_value(pres)); /* Ranges within this unit */
442: PUTBLOCK(crlf, 2);
443: }
444: }
2.1 frystyk 445: }
2.34 frystyk 446: if (request_mask & HT_C_REFERER) {
447: HTParentAnchor * parent_anchor = HTRequest_parent(request);
448: if (parent_anchor) {
449: char * act = HTAnchor_address((HTAnchor *) anchor);
450: char * parent = HTAnchor_address((HTAnchor *) parent_anchor);
451: char * relative = HTParse(parent, act,
452: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
453: if (relative && *relative) {
454: PUTS("Referer: ");
455: PUTS(parent);
456: PUTBLOCK(crlf, 2);
457: }
458: HT_FREE(act);
459: HT_FREE(parent);
460: HT_FREE(relative);
2.1 frystyk 461: }
462: }
2.34 frystyk 463: if (request_mask & HT_C_USER_AGENT) {
2.24 frystyk 464: PUTS("User-Agent: ");
465: PUTS(HTLib_appName());
466: PUTC('/');
467: PUTS(HTLib_appVersion());
468: PUTC(' ');
469: PUTS(HTLib_name());
470: PUTC('/');
471: PUTS(HTLib_version());
472: PUTBLOCK(crlf, 2);
2.1 frystyk 473: }
2.27 eric 474: if (PROT_TRACE)HTTrace("HTTP........ Generating Request Headers\n");
2.38 frystyk 475: return HT_OK;
2.1 frystyk 476: }
477:
2.29 frystyk 478: PRIVATE int HTTPRequest_put_block (HTStream * me, const char * b, int l)
2.1 frystyk 479: {
2.7 frystyk 480: if (!me->target) {
2.1 frystyk 481: return HT_WOULD_BLOCK;
2.7 frystyk 482: } else if (me->transparent)
2.11 frystyk 483: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 484: else {
2.38 frystyk 485: int status = HT_OK;
486: if (me->version == HTTP_09) {
487: status = HTTP09Request(me, me->request);
488: if (status != HT_OK) return status;
489: } else {
490: status = HTTPMakeRequest(me, me->request);
491: if (status != HT_OK) return status;
2.1 frystyk 492: me->transparent = YES;
2.11 frystyk 493: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 494: }
495: return status;
496: }
497: }
498:
2.16 frystyk 499: PRIVATE int HTTPRequest_put_character (HTStream * me, char c)
2.1 frystyk 500: {
2.11 frystyk 501: return HTTPRequest_put_block(me, &c, 1);
2.1 frystyk 502: }
503:
2.29 frystyk 504: PRIVATE int HTTPRequest_put_string (HTStream * me, const char * s)
2.1 frystyk 505: {
2.11 frystyk 506: return HTTPRequest_put_block(me, s, strlen(s));
2.1 frystyk 507: }
508:
509: /*
510: ** Flushes data but doesn't free stream object
511: */
2.16 frystyk 512: PRIVATE int HTTPRequest_flush (HTStream * me)
2.1 frystyk 513: {
2.13 frystyk 514: int status = HTTPRequest_put_block(me, NULL, 0);
515: return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
2.1 frystyk 516: }
517:
518: /*
519: ** Flushes data and frees stream object
520: */
2.16 frystyk 521: PRIVATE int HTTPRequest_free (HTStream * me)
2.1 frystyk 522: {
2.11 frystyk 523: int status = HTTPRequest_flush(me);
524: if (status != HT_WOULD_BLOCK) {
525: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
526: return HT_WOULD_BLOCK;
2.38 frystyk 527: HT_FREE(me->url);
2.26 frystyk 528: HT_FREE(me);
2.1 frystyk 529: }
2.7 frystyk 530: return status;
2.1 frystyk 531: }
532:
2.16 frystyk 533: PRIVATE int HTTPRequest_abort (HTStream * me, HTList * e)
2.1 frystyk 534: {
2.13 frystyk 535: if (me->target) (*me->target->isa->abort)(me->target, e);
2.38 frystyk 536: HT_FREE(me->url);
2.26 frystyk 537: HT_FREE(me);
2.27 eric 538: if (PROT_TRACE) HTTrace("HTTPRequest. ABORTING...\n");
2.1 frystyk 539: return HT_ERROR;
540: }
541:
542: /* HTTPRequest Stream
543: ** -----------------
544: */
2.29 frystyk 545: PRIVATE const HTStreamClass HTTPRequestClass =
2.1 frystyk 546: {
547: "HTTPRequest",
548: HTTPRequest_flush,
549: HTTPRequest_free,
550: HTTPRequest_abort,
551: HTTPRequest_put_character,
552: HTTPRequest_put_string,
553: HTTPRequest_put_block
554: };
555:
2.23 frystyk 556: PUBLIC HTStream * HTTPRequest_new (HTRequest * request, HTStream * target,
2.45 frystyk 557: BOOL endHeader, int version)
2.1 frystyk 558: {
2.26 frystyk 559: HTStream * me;
560: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
561: HT_OUTOFMEM("HTTPRequest_new");
2.1 frystyk 562: me->isa = &HTTPRequestClass;
563: me->target = target;
564: me->request = request;
2.45 frystyk 565: me->version = version;
2.1 frystyk 566: me->transparent = NO;
2.46 ! frystyk 567:
! 568: /*
! 569: ** If sending a body in the request then we want a 100 code!
! 570: */
! 571: if (HTMethod_hasEntity(HTRequest_method(request)))
! 572: HTRequest_addExpect(request, "100-continue", "");
! 573:
2.23 frystyk 574:
575: /* Return general HTTP header stream */
2.45 frystyk 576: return HTTPGen_new(request, me, endHeader, version);
2.1 frystyk 577: }
Webmaster