Annotation of libwww/Library/src/HTTPReq.c, revision 2.59
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.59 ! frystyk 6: ** @(#) $Id: HTTPReq.c,v 2.58 1999/01/27 13:55:25 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.58 frystyk 175: HTFormat format = HTRequest_outputFormat(request);
176:
2.37 frystyk 177: /*
178: ** If caller has specified a specific output format then use this.
179: ** Otherwise use all the registered converters to generate the
180: ** accept header
181: */
2.58 frystyk 182: if (format == WWW_PRESENT) {
2.37 frystyk 183: int list;
184: HTList *cur;
185: BOOL first=YES;
186: for (list=0; list<2; list++) {
187: if ((!list && ((cur = HTFormat_conversion()) != NULL)) ||
188: (list && ((cur = HTRequest_conversion(request))!=NULL))) {
189: HTPresentation * pres;
190: while ((pres=(HTPresentation *) HTList_nextObject(cur))) {
191: if (pres->rep_out==WWW_PRESENT && pres->quality<=1.0) {
192: if (first) {
193: PUTS("Accept: ");
194: first=NO;
195: } else
196: PUTC(',');
197: PUTS(HTAtom_name(pres->rep));
2.46 frystyk 198: if (pres->quality < 1.0 && pres->quality >= 0.0) {
2.37 frystyk 199: sprintf(qstr, ";q=%1.1f", pres->quality);
200: PUTS(qstr);
201: }
2.1 frystyk 202: }
203: }
204: }
205: }
2.37 frystyk 206: if (!first) PUTBLOCK(crlf, 2);
207: } else {
2.58 frystyk 208:
209: /*
210: ** If we have an explicit output format then only send
211: ** this one if not this is an internal libwww format
212: ** of type www/<star>
213: */
214: if (!HTMIMEMatch(WWW_INTERNAL, format)) {
215: PUTS("Accept: ");
216: PUTS(HTAtom_name(format));
217: PUTBLOCK(crlf, 2);
218: }
2.37 frystyk 219: }
2.1 frystyk 220: }
2.34 frystyk 221: if (request_mask & HT_C_ACCEPT_CHAR) {
2.4 frystyk 222: int list;
223: HTList *cur;
2.24 frystyk 224: BOOL first=YES;
2.4 frystyk 225: for (list=0; list<2; list++) {
2.14 frystyk 226: if ((!list && ((cur = HTFormat_charset()) != NULL)) ||
227: (list && ((cur = HTRequest_charset(request)) != NULL))) {
2.4 frystyk 228: HTAcceptNode *pres;
229: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 230: if (first) {
2.24 frystyk 231: PUTS("Accept-Charset: ");
2.5 frystyk 232: first=NO;
2.24 frystyk 233: } else
234: PUTC(',');
235: PUTS(HTAtom_name(pres->atom));
2.46 frystyk 236: if (pres->quality < 1.0 && pres->quality >= 0.0) {
237: sprintf(qstr, ";q=%1.1f", pres->quality);
238: PUTS(qstr);
239: }
2.4 frystyk 240: }
241: }
242: }
2.31 frystyk 243: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 244: }
2.34 frystyk 245: if (request_mask & HT_C_ACCEPT_ENC) {
2.4 frystyk 246: int list;
247: HTList *cur;
2.24 frystyk 248: BOOL first=YES;
2.4 frystyk 249: for (list=0; list<2; list++) {
2.33 frystyk 250: if ((!list && ((cur = HTFormat_contentCoding()) != NULL)) ||
2.14 frystyk 251: (list && ((cur = HTRequest_encoding(request)) != NULL))) {
2.33 frystyk 252: HTCoding * pres;
253: while ((pres = (HTCoding *) HTList_nextObject(cur))) {
2.46 frystyk 254: double quality = HTCoding_quality(pres);
2.5 frystyk 255: if (first) {
2.24 frystyk 256: PUTS("Accept-Encoding: ");
2.32 frystyk 257: first = NO;
2.24 frystyk 258: } else
259: PUTC(',');
2.33 frystyk 260: PUTS(HTCoding_name(pres));
2.46 frystyk 261: if (quality < 1.0 && quality >= 0.0) {
262: sprintf(qstr, ";q=%1.1f", quality);
263: PUTS(qstr);
264: }
265: }
266: }
267: }
268: if (!first) PUTBLOCK(crlf, 2);
269: }
270: if (request_mask & HT_C_ACCEPT_TE) {
271: int list;
272: HTList *cur;
273: BOOL first=YES;
274: for (list=0; list<2; list++) {
275: if ((!list && ((cur = HTFormat_transferCoding()) != NULL)) ||
276: (list && ((cur = HTRequest_transfer(request)) != NULL))) {
277: HTCoding * pres;
278: while ((pres = (HTCoding *) HTList_nextObject(cur))) {
279: double quality = HTCoding_quality(pres);
2.55 frystyk 280: const char * coding = HTCoding_name(pres);
2.46 frystyk 281: if (first) {
282: PUTS("TE: ");
283: first = NO;
284: } else
285: PUTC(',');
2.55 frystyk 286:
287: /* Special check for "chunked" which is translated to "trailers" */
288: if (!strcasecomp(coding, "chunked"))
289: PUTS("trailers");
290: else
291: PUTS(coding);
2.46 frystyk 292: if (quality < 1.0 && quality >= 0.0) {
293: sprintf(qstr, ";q=%1.1f", quality);
294: PUTS(qstr);
295: }
2.4 frystyk 296: }
297: }
298: }
2.31 frystyk 299: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 300: }
2.34 frystyk 301: if (request_mask & HT_C_ACCEPT_LAN) {
2.4 frystyk 302: int list;
303: HTList *cur;
2.24 frystyk 304: BOOL first=YES;
2.4 frystyk 305: for (list=0; list<2; list++) {
2.14 frystyk 306: if ((!list && ((cur = HTFormat_language()) != NULL)) ||
307: (list && ((cur = HTRequest_language(request)) != NULL))) {
2.4 frystyk 308: HTAcceptNode *pres;
309: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 310: if (first) {
2.24 frystyk 311: PUTS("Accept-Language: ");
2.5 frystyk 312: first=NO;
2.24 frystyk 313: } else
314: PUTC(',');
315: PUTS(HTAtom_name(pres->atom));
2.46 frystyk 316: if (pres->quality < 1.0 && pres->quality >= 0.0) {
2.24 frystyk 317: sprintf(qstr, ";q=%1.1f", pres->quality);
318: PUTS(qstr);
2.5 frystyk 319: }
2.4 frystyk 320: }
321: }
322: }
2.31 frystyk 323: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 324: }
2.36 frystyk 325: if (request_mask & HT_C_AUTH) {
2.34 frystyk 326: HTAssocList * cur = HTRequest_credentials(request);
327: if (cur) { /* Access authentication */
328: HTAssoc * pres;
329: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
330: PUTS(HTAssoc_name(pres));
331: PUTS(": ");
332: PUTS(HTAssoc_value(pres));
333: PUTBLOCK(crlf, 2);
334: }
2.28 frystyk 335: }
2.1 frystyk 336: }
2.46 frystyk 337: if (request_mask & HT_C_EXPECT) {
338: HTAssocList * cur = HTRequest_expect(request);
339: if (cur) {
340: BOOL first=YES;
341: HTAssoc * pres;
342: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
343: char * value = HTAssoc_value(pres);
344: if (first) {
345: PUTS("Expect: ");
346: first = NO;
347: } else
348: PUTC(',');
349:
350: /* Output the name */
351: PUTS(HTAssoc_name(pres));
352:
353: /* Only output the value if not empty string */
354: if (*value) {
355: PUTS("=");
356: PUTS(value);
357: }
358: }
359: PUTBLOCK(crlf, 2);
360: }
361: }
2.34 frystyk 362: if (request_mask & HT_C_FROM) {
363: HTUserProfile * up = HTRequest_userProfile(request);
364: const char * mailaddress = HTUserProfile_email(up);
2.1 frystyk 365: if (mailaddress) {
2.24 frystyk 366: PUTS("From: ");
367: PUTS(mailaddress);
368: PUTBLOCK(crlf, 2);
2.1 frystyk 369: }
370: }
2.34 frystyk 371: if (request_mask & HT_C_HOST) {
2.13 frystyk 372: char *orig = HTAnchor_address((HTAnchor *) anchor);
2.12 frystyk 373: char *host = HTParse(orig, "", PARSE_HOST);
2.34 frystyk 374: #if 0
375: /* Keep the port number for HTTP/1.1 compliance */
2.12 frystyk 376: char *ptr = strchr(host, ':'); /* Chop off port number */
377: if (ptr) *ptr = '\0';
2.34 frystyk 378: #endif
2.24 frystyk 379: PUTS("Host: ");
380: PUTS(host);
381: PUTBLOCK(crlf, 2);
2.26 frystyk 382: HT_FREE(orig);
383: HT_FREE(host);
2.39 frystyk 384: }
2.42 frystyk 385:
386: /*
387: ** In the "If-*" series of headers, the ones related to etags have higher
388: ** priority than the date relates ones. That is, if we have a etag then
2.45 frystyk 389: ** use that, otherwise use the date. First we check for range, match, and
390: ** unmodified-since.
2.42 frystyk 391: */
2.45 frystyk 392: if (request_mask & HT_C_IF_RANGE && etag) {
393: PUTS("If-Range: \"");
394: PUTS(etag);
395: PUTC('"');
396: PUTBLOCK(crlf, 2);
397: if (PROT_TRACE) HTTrace("HTTP........ If-Range using etag `%s\'\n", etag);
2.57 frystyk 398: } else if (request_mask & HT_C_IF_MATCH_ANY) {
2.56 frystyk 399: PUTS("If-Match: *");
400: PUTBLOCK(crlf, 2);
401: if (PROT_TRACE) HTTrace("HTTP........ If-Match using `*\'\n");
2.45 frystyk 402: } else if (request_mask & HT_C_IF_MATCH && etag) {
2.43 frystyk 403: PUTS("If-Match: \"");
404: PUTS(etag);
405: PUTC('"');
406: PUTBLOCK(crlf, 2);
407: if (PROT_TRACE) HTTrace("HTTP........ If-Match using etag `%s\'\n", etag);
408: } else if (request_mask & HT_C_IF_UNMOD_SINCE) {
2.42 frystyk 409: time_t lm = HTAnchor_lastModified(anchor);
410: if (lm > 0) {
2.43 frystyk 411: PUTS("If-Unmodified-Since: ");
2.42 frystyk 412: PUTS(HTDateTimeStr(&lm, NO));
413: PUTBLOCK(crlf, 2);
2.59 ! frystyk 414: if (PROT_TRACE)
! 415: HTTrace("HTTP........ If-Unmodified-Since `%s\'\n", HTDateTimeStr(&lm, NO));
2.42 frystyk 416: }
417: }
2.45 frystyk 418:
419: /*
420: ** If-None-Match and If-Modified-Since are equivalent except that the
421: ** first uses etags and the second uses dates. Etags have precedence over
422: ** dates.
423: */
2.57 frystyk 424: if (request_mask & HT_C_IF_NONE_MATCH_ANY) {
2.56 frystyk 425: PUTS("If-None-Match: *");
426: PUTBLOCK(crlf, 2);
427: if (PROT_TRACE) HTTrace("HTTP........ If-None-Match using `*\'\n");
428: } else if (request_mask & HT_C_IF_NONE_MATCH && etag) {
2.43 frystyk 429: PUTS("If-None-Match: \"");
430: PUTS(etag);
431: PUTC('"');
432: PUTBLOCK(crlf, 2);
2.46 frystyk 433: if (PROT_TRACE) HTTrace("HTTP........ If-None-Match `%s\'\n", etag);
434: }
435: if (request_mask & HT_C_IMS) {
2.42 frystyk 436: time_t lm = HTAnchor_lastModified(anchor);
437: if (lm > 0) {
2.43 frystyk 438: PUTS("If-Modified-Since: ");
2.42 frystyk 439: PUTS(HTDateTimeStr(&lm, NO));
440: PUTBLOCK(crlf, 2);
2.59 ! frystyk 441: if (PROT_TRACE)
! 442: HTTrace("HTTP........ If-Modified-Since `%s\'\n",HTDateTimeStr(&lm, NO));
2.42 frystyk 443: }
444: }
445:
2.45 frystyk 446: /*
447: ** Max forwards is mainly for TRACE where we want to be able to stop the
448: ** TRACE at a specific location un the message path.
449: */
2.39 frystyk 450: if (request_mask & HT_C_MAX_FORWARDS) {
451: int hops = HTRequest_maxForwards(request);
452: if (hops >= 0) {
453: sprintf(qstr, "%d", hops);
454: PUTS("Max-Forwards: ");
455: PUTS(qstr);
456: PUTBLOCK(crlf, 2);
457: }
2.42 frystyk 458: }
2.45 frystyk 459:
460: /*
461: ** Range requests. For now, we only take the first entry registered for
462: ** this request. This means that you can only send a single "unit" and
463: ** then a set of range within this unit. This is in accordance with
464: ** HTTP/1.1. Multiple units will go on multiple lines.
465: */
2.42 frystyk 466: if (request_mask & HT_C_RANGE) {
2.45 frystyk 467: HTAssocList * cur = HTRequest_range(request);
468: if (cur) { /* Range requests */
469: HTAssoc * pres;
470: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
471: PUTS("Range: ");
472: PUTS(HTAssoc_name(pres)); /* Unit */
473: PUTS("=");
474: PUTS(HTAssoc_value(pres)); /* Ranges within this unit */
475: PUTBLOCK(crlf, 2);
476: }
477: }
2.1 frystyk 478: }
2.34 frystyk 479: if (request_mask & HT_C_REFERER) {
480: HTParentAnchor * parent_anchor = HTRequest_parent(request);
481: if (parent_anchor) {
482: char * act = HTAnchor_address((HTAnchor *) anchor);
483: char * parent = HTAnchor_address((HTAnchor *) parent_anchor);
2.50 frystyk 484: #if 1
485: char * relative = HTRelative(parent, act);
486: #else
2.34 frystyk 487: char * relative = HTParse(parent, act,
488: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
2.50 frystyk 489: #endif
2.34 frystyk 490: if (relative && *relative) {
491: PUTS("Referer: ");
2.50 frystyk 492: PUTS(relative);
2.34 frystyk 493: PUTBLOCK(crlf, 2);
494: }
495: HT_FREE(act);
496: HT_FREE(parent);
497: HT_FREE(relative);
2.1 frystyk 498: }
499: }
2.34 frystyk 500: if (request_mask & HT_C_USER_AGENT) {
2.24 frystyk 501: PUTS("User-Agent: ");
502: PUTS(HTLib_appName());
503: PUTC('/');
504: PUTS(HTLib_appVersion());
505: PUTC(' ');
506: PUTS(HTLib_name());
507: PUTC('/');
508: PUTS(HTLib_version());
509: PUTBLOCK(crlf, 2);
2.1 frystyk 510: }
2.53 frystyk 511: if (PROT_TRACE) HTTrace("HTTP........ Generating HTTP/1.x Request Headers\n");
2.38 frystyk 512: return HT_OK;
2.1 frystyk 513: }
514:
2.29 frystyk 515: PRIVATE int HTTPRequest_put_block (HTStream * me, const char * b, int l)
2.1 frystyk 516: {
2.7 frystyk 517: if (!me->target) {
2.1 frystyk 518: return HT_WOULD_BLOCK;
2.7 frystyk 519: } else if (me->transparent)
2.11 frystyk 520: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 521: else {
2.38 frystyk 522: int status = HT_OK;
523: if (me->version == HTTP_09) {
524: status = HTTP09Request(me, me->request);
525: if (status != HT_OK) return status;
526: } else {
527: status = HTTPMakeRequest(me, me->request);
528: if (status != HT_OK) return status;
2.1 frystyk 529: me->transparent = YES;
2.11 frystyk 530: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 531: }
532: return status;
533: }
534: }
535:
2.16 frystyk 536: PRIVATE int HTTPRequest_put_character (HTStream * me, char c)
2.1 frystyk 537: {
2.11 frystyk 538: return HTTPRequest_put_block(me, &c, 1);
2.1 frystyk 539: }
540:
2.29 frystyk 541: PRIVATE int HTTPRequest_put_string (HTStream * me, const char * s)
2.1 frystyk 542: {
2.11 frystyk 543: return HTTPRequest_put_block(me, s, strlen(s));
2.1 frystyk 544: }
545:
546: /*
547: ** Flushes data but doesn't free stream object
548: */
2.16 frystyk 549: PRIVATE int HTTPRequest_flush (HTStream * me)
2.1 frystyk 550: {
2.13 frystyk 551: int status = HTTPRequest_put_block(me, NULL, 0);
552: return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
2.1 frystyk 553: }
554:
555: /*
556: ** Flushes data and frees stream object
557: */
2.16 frystyk 558: PRIVATE int HTTPRequest_free (HTStream * me)
2.1 frystyk 559: {
2.11 frystyk 560: int status = HTTPRequest_flush(me);
561: if (status != HT_WOULD_BLOCK) {
562: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
563: return HT_WOULD_BLOCK;
2.38 frystyk 564: HT_FREE(me->url);
2.26 frystyk 565: HT_FREE(me);
2.1 frystyk 566: }
2.7 frystyk 567: return status;
2.1 frystyk 568: }
569:
2.16 frystyk 570: PRIVATE int HTTPRequest_abort (HTStream * me, HTList * e)
2.1 frystyk 571: {
2.27 eric 572: if (PROT_TRACE) HTTrace("HTTPRequest. ABORTING...\n");
2.51 kahan 573: /* JK: Added protection against NULL pointers */
2.49 frystyk 574: if (me) {
2.51 kahan 575: if (me->target && me->target->isa)
576: (*me->target->isa->abort)(me->target, e);
577: if (me->url)
578: HT_FREE(me->url);
2.49 frystyk 579: HT_FREE(me);
580: }
2.1 frystyk 581: return HT_ERROR;
582: }
583:
584: /* HTTPRequest Stream
585: ** -----------------
586: */
2.29 frystyk 587: PRIVATE const HTStreamClass HTTPRequestClass =
2.1 frystyk 588: {
589: "HTTPRequest",
590: HTTPRequest_flush,
591: HTTPRequest_free,
592: HTTPRequest_abort,
593: HTTPRequest_put_character,
594: HTTPRequest_put_string,
595: HTTPRequest_put_block
596: };
597:
2.23 frystyk 598: PUBLIC HTStream * HTTPRequest_new (HTRequest * request, HTStream * target,
2.45 frystyk 599: BOOL endHeader, int version)
2.1 frystyk 600: {
2.26 frystyk 601: HTStream * me;
602: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
603: HT_OUTOFMEM("HTTPRequest_new");
2.1 frystyk 604: me->isa = &HTTPRequestClass;
605: me->target = target;
606: me->request = request;
2.45 frystyk 607: me->version = version;
2.1 frystyk 608: me->transparent = NO;
2.46 frystyk 609:
610: /*
611: ** If sending a body in the request then we want a 100 code!
612: */
613: if (HTMethod_hasEntity(HTRequest_method(request)))
614: HTRequest_addExpect(request, "100-continue", "");
615:
2.23 frystyk 616:
617: /* Return general HTTP header stream */
2.45 frystyk 618: return HTTPGen_new(request, me, endHeader, version);
2.1 frystyk 619: }
Webmaster