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