Annotation of libwww/Library/src/HTTPReq.c, revision 2.55
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.55 ! frystyk 6: ** @(#) $Id: HTTPReq.c,v 2.54 1998/07/24 15:37: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.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);
2.55 ! frystyk 270: const char * coding = HTCoding_name(pres);
2.46 frystyk 271: if (first) {
272: PUTS("TE: ");
273: first = NO;
274: } else
275: PUTC(',');
2.55 ! frystyk 276:
! 277: /* Special check for "chunked" which is translated to "trailers" */
! 278: if (!strcasecomp(coding, "chunked"))
! 279: PUTS("trailers");
! 280: else
! 281: PUTS(coding);
2.46 frystyk 282: if (quality < 1.0 && quality >= 0.0) {
283: sprintf(qstr, ";q=%1.1f", quality);
284: PUTS(qstr);
285: }
2.4 frystyk 286: }
287: }
288: }
2.31 frystyk 289: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 290: }
2.34 frystyk 291: if (request_mask & HT_C_ACCEPT_LAN) {
2.4 frystyk 292: int list;
293: HTList *cur;
2.24 frystyk 294: BOOL first=YES;
2.4 frystyk 295: for (list=0; list<2; list++) {
2.14 frystyk 296: if ((!list && ((cur = HTFormat_language()) != NULL)) ||
297: (list && ((cur = HTRequest_language(request)) != NULL))) {
2.4 frystyk 298: HTAcceptNode *pres;
299: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 300: if (first) {
2.24 frystyk 301: PUTS("Accept-Language: ");
2.5 frystyk 302: first=NO;
2.24 frystyk 303: } else
304: PUTC(',');
305: PUTS(HTAtom_name(pres->atom));
2.46 frystyk 306: if (pres->quality < 1.0 && pres->quality >= 0.0) {
2.24 frystyk 307: sprintf(qstr, ";q=%1.1f", pres->quality);
308: PUTS(qstr);
2.5 frystyk 309: }
2.4 frystyk 310: }
311: }
312: }
2.31 frystyk 313: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 314: }
2.36 frystyk 315: if (request_mask & HT_C_AUTH) {
2.34 frystyk 316: HTAssocList * cur = HTRequest_credentials(request);
317: if (cur) { /* Access authentication */
318: HTAssoc * pres;
319: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
320: PUTS(HTAssoc_name(pres));
321: PUTS(": ");
322: PUTS(HTAssoc_value(pres));
323: PUTBLOCK(crlf, 2);
324: }
2.28 frystyk 325: }
2.1 frystyk 326: }
2.46 frystyk 327: if (request_mask & HT_C_EXPECT) {
328: HTAssocList * cur = HTRequest_expect(request);
329: if (cur) {
330: BOOL first=YES;
331: HTAssoc * pres;
332: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
333: char * value = HTAssoc_value(pres);
334: if (first) {
335: PUTS("Expect: ");
336: first = NO;
337: } else
338: PUTC(',');
339:
340: /* Output the name */
341: PUTS(HTAssoc_name(pres));
342:
343: /* Only output the value if not empty string */
344: if (*value) {
345: PUTS("=");
346: PUTS(value);
347: }
348: }
349: PUTBLOCK(crlf, 2);
350: }
351: }
2.34 frystyk 352: if (request_mask & HT_C_FROM) {
353: HTUserProfile * up = HTRequest_userProfile(request);
354: const char * mailaddress = HTUserProfile_email(up);
2.1 frystyk 355: if (mailaddress) {
2.24 frystyk 356: PUTS("From: ");
357: PUTS(mailaddress);
358: PUTBLOCK(crlf, 2);
2.1 frystyk 359: }
360: }
2.34 frystyk 361: if (request_mask & HT_C_HOST) {
2.13 frystyk 362: char *orig = HTAnchor_address((HTAnchor *) anchor);
2.12 frystyk 363: char *host = HTParse(orig, "", PARSE_HOST);
2.34 frystyk 364: #if 0
365: /* Keep the port number for HTTP/1.1 compliance */
2.12 frystyk 366: char *ptr = strchr(host, ':'); /* Chop off port number */
367: if (ptr) *ptr = '\0';
2.34 frystyk 368: #endif
2.24 frystyk 369: PUTS("Host: ");
370: PUTS(host);
371: PUTBLOCK(crlf, 2);
2.26 frystyk 372: HT_FREE(orig);
373: HT_FREE(host);
2.39 frystyk 374: }
2.42 frystyk 375:
376: /*
377: ** In the "If-*" series of headers, the ones related to etags have higher
378: ** priority than the date relates ones. That is, if we have a etag then
2.45 frystyk 379: ** use that, otherwise use the date. First we check for range, match, and
380: ** unmodified-since.
2.42 frystyk 381: */
2.45 frystyk 382: if (request_mask & HT_C_IF_RANGE && etag) {
383: PUTS("If-Range: \"");
384: PUTS(etag);
385: PUTC('"');
386: PUTBLOCK(crlf, 2);
387: if (PROT_TRACE) HTTrace("HTTP........ If-Range using etag `%s\'\n", etag);
388: } else if (request_mask & HT_C_IF_MATCH && etag) {
2.43 frystyk 389: PUTS("If-Match: \"");
390: PUTS(etag);
391: PUTC('"');
392: PUTBLOCK(crlf, 2);
393: if (PROT_TRACE) HTTrace("HTTP........ If-Match using etag `%s\'\n", etag);
394: } else if (request_mask & HT_C_IF_UNMOD_SINCE) {
2.42 frystyk 395: time_t lm = HTAnchor_lastModified(anchor);
396: if (lm > 0) {
2.43 frystyk 397: PUTS("If-Unmodified-Since: ");
2.42 frystyk 398: PUTS(HTDateTimeStr(&lm, NO));
399: PUTBLOCK(crlf, 2);
2.43 frystyk 400: if (PROT_TRACE) HTTrace("HTTP........ If-Unmodified-Since\n");
2.42 frystyk 401: }
402: }
2.45 frystyk 403:
404: /*
405: ** If-None-Match and If-Modified-Since are equivalent except that the
406: ** first uses etags and the second uses dates. Etags have precedence over
407: ** dates.
408: */
2.43 frystyk 409: if (request_mask & HT_C_IF_NONE_MATCH && etag) {
410: PUTS("If-None-Match: \"");
411: PUTS(etag);
412: PUTC('"');
413: PUTBLOCK(crlf, 2);
2.46 frystyk 414: if (PROT_TRACE) HTTrace("HTTP........ If-None-Match `%s\'\n", etag);
415: }
416: if (request_mask & HT_C_IMS) {
2.42 frystyk 417: time_t lm = HTAnchor_lastModified(anchor);
418: if (lm > 0) {
2.43 frystyk 419: PUTS("If-Modified-Since: ");
2.42 frystyk 420: PUTS(HTDateTimeStr(&lm, NO));
421: PUTBLOCK(crlf, 2);
2.43 frystyk 422: if (PROT_TRACE) HTTrace("HTTP........ If-Modified-Since\n");
2.42 frystyk 423: }
424: }
425:
2.45 frystyk 426: /*
427: ** Max forwards is mainly for TRACE where we want to be able to stop the
428: ** TRACE at a specific location un the message path.
429: */
2.39 frystyk 430: if (request_mask & HT_C_MAX_FORWARDS) {
431: int hops = HTRequest_maxForwards(request);
432: if (hops >= 0) {
433: sprintf(qstr, "%d", hops);
434: PUTS("Max-Forwards: ");
435: PUTS(qstr);
436: PUTBLOCK(crlf, 2);
437: }
2.42 frystyk 438: }
2.45 frystyk 439:
440: /*
441: ** Range requests. For now, we only take the first entry registered for
442: ** this request. This means that you can only send a single "unit" and
443: ** then a set of range within this unit. This is in accordance with
444: ** HTTP/1.1. Multiple units will go on multiple lines.
445: */
2.42 frystyk 446: if (request_mask & HT_C_RANGE) {
2.45 frystyk 447: HTAssocList * cur = HTRequest_range(request);
448: if (cur) { /* Range requests */
449: HTAssoc * pres;
450: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
451: PUTS("Range: ");
452: PUTS(HTAssoc_name(pres)); /* Unit */
453: PUTS("=");
454: PUTS(HTAssoc_value(pres)); /* Ranges within this unit */
455: PUTBLOCK(crlf, 2);
456: }
457: }
2.1 frystyk 458: }
2.34 frystyk 459: if (request_mask & HT_C_REFERER) {
460: HTParentAnchor * parent_anchor = HTRequest_parent(request);
461: if (parent_anchor) {
462: char * act = HTAnchor_address((HTAnchor *) anchor);
463: char * parent = HTAnchor_address((HTAnchor *) parent_anchor);
2.50 frystyk 464: #if 1
465: char * relative = HTRelative(parent, act);
466: #else
2.34 frystyk 467: char * relative = HTParse(parent, act,
468: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
2.50 frystyk 469: #endif
2.34 frystyk 470: if (relative && *relative) {
471: PUTS("Referer: ");
2.50 frystyk 472: PUTS(relative);
2.34 frystyk 473: PUTBLOCK(crlf, 2);
474: }
475: HT_FREE(act);
476: HT_FREE(parent);
477: HT_FREE(relative);
2.1 frystyk 478: }
479: }
2.34 frystyk 480: if (request_mask & HT_C_USER_AGENT) {
2.24 frystyk 481: PUTS("User-Agent: ");
482: PUTS(HTLib_appName());
483: PUTC('/');
484: PUTS(HTLib_appVersion());
485: PUTC(' ');
486: PUTS(HTLib_name());
487: PUTC('/');
488: PUTS(HTLib_version());
489: PUTBLOCK(crlf, 2);
2.1 frystyk 490: }
2.53 frystyk 491: if (PROT_TRACE) HTTrace("HTTP........ Generating HTTP/1.x Request Headers\n");
2.38 frystyk 492: return HT_OK;
2.1 frystyk 493: }
494:
2.29 frystyk 495: PRIVATE int HTTPRequest_put_block (HTStream * me, const char * b, int l)
2.1 frystyk 496: {
2.7 frystyk 497: if (!me->target) {
2.1 frystyk 498: return HT_WOULD_BLOCK;
2.7 frystyk 499: } else if (me->transparent)
2.11 frystyk 500: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 501: else {
2.38 frystyk 502: int status = HT_OK;
503: if (me->version == HTTP_09) {
504: status = HTTP09Request(me, me->request);
505: if (status != HT_OK) return status;
506: } else {
507: status = HTTPMakeRequest(me, me->request);
508: if (status != HT_OK) return status;
2.1 frystyk 509: me->transparent = YES;
2.11 frystyk 510: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 511: }
512: return status;
513: }
514: }
515:
2.16 frystyk 516: PRIVATE int HTTPRequest_put_character (HTStream * me, char c)
2.1 frystyk 517: {
2.11 frystyk 518: return HTTPRequest_put_block(me, &c, 1);
2.1 frystyk 519: }
520:
2.29 frystyk 521: PRIVATE int HTTPRequest_put_string (HTStream * me, const char * s)
2.1 frystyk 522: {
2.11 frystyk 523: return HTTPRequest_put_block(me, s, strlen(s));
2.1 frystyk 524: }
525:
526: /*
527: ** Flushes data but doesn't free stream object
528: */
2.16 frystyk 529: PRIVATE int HTTPRequest_flush (HTStream * me)
2.1 frystyk 530: {
2.13 frystyk 531: int status = HTTPRequest_put_block(me, NULL, 0);
532: return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
2.1 frystyk 533: }
534:
535: /*
536: ** Flushes data and frees stream object
537: */
2.16 frystyk 538: PRIVATE int HTTPRequest_free (HTStream * me)
2.1 frystyk 539: {
2.11 frystyk 540: int status = HTTPRequest_flush(me);
541: if (status != HT_WOULD_BLOCK) {
542: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
543: return HT_WOULD_BLOCK;
2.38 frystyk 544: HT_FREE(me->url);
2.26 frystyk 545: HT_FREE(me);
2.1 frystyk 546: }
2.7 frystyk 547: return status;
2.1 frystyk 548: }
549:
2.16 frystyk 550: PRIVATE int HTTPRequest_abort (HTStream * me, HTList * e)
2.1 frystyk 551: {
2.27 eric 552: if (PROT_TRACE) HTTrace("HTTPRequest. ABORTING...\n");
2.51 kahan 553: /* JK: Added protection against NULL pointers */
2.49 frystyk 554: if (me) {
2.51 kahan 555: if (me->target && me->target->isa)
556: (*me->target->isa->abort)(me->target, e);
557: if (me->url)
558: HT_FREE(me->url);
2.49 frystyk 559: HT_FREE(me);
560: }
2.1 frystyk 561: return HT_ERROR;
562: }
563:
564: /* HTTPRequest Stream
565: ** -----------------
566: */
2.29 frystyk 567: PRIVATE const HTStreamClass HTTPRequestClass =
2.1 frystyk 568: {
569: "HTTPRequest",
570: HTTPRequest_flush,
571: HTTPRequest_free,
572: HTTPRequest_abort,
573: HTTPRequest_put_character,
574: HTTPRequest_put_string,
575: HTTPRequest_put_block
576: };
577:
2.23 frystyk 578: PUBLIC HTStream * HTTPRequest_new (HTRequest * request, HTStream * target,
2.45 frystyk 579: BOOL endHeader, int version)
2.1 frystyk 580: {
2.26 frystyk 581: HTStream * me;
582: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
583: HT_OUTOFMEM("HTTPRequest_new");
2.1 frystyk 584: me->isa = &HTTPRequestClass;
585: me->target = target;
586: me->request = request;
2.45 frystyk 587: me->version = version;
2.1 frystyk 588: me->transparent = NO;
2.46 frystyk 589:
590: /*
591: ** If sending a body in the request then we want a 100 code!
592: */
593: if (HTMethod_hasEntity(HTRequest_method(request)))
594: HTRequest_addExpect(request, "100-continue", "");
595:
2.23 frystyk 596:
597: /* Return general HTTP header stream */
2.45 frystyk 598: return HTTPGen_new(request, me, endHeader, version);
2.1 frystyk 599: }
Webmaster