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