Annotation of libwww/Library/src/HTTPReq.c, revision 2.58
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.58 ! frystyk 6: ** @(#) $Id: HTTPReq.c,v 2.57 1998/11/19 17:14:39 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.43 frystyk 414: if (PROT_TRACE) HTTrace("HTTP........ If-Unmodified-Since\n");
2.42 frystyk 415: }
416: }
2.45 frystyk 417:
418: /*
419: ** If-None-Match and If-Modified-Since are equivalent except that the
420: ** first uses etags and the second uses dates. Etags have precedence over
421: ** dates.
422: */
2.57 frystyk 423: if (request_mask & HT_C_IF_NONE_MATCH_ANY) {
2.56 frystyk 424: PUTS("If-None-Match: *");
425: PUTBLOCK(crlf, 2);
426: if (PROT_TRACE) HTTrace("HTTP........ If-None-Match using `*\'\n");
427: } else if (request_mask & HT_C_IF_NONE_MATCH && etag) {
2.43 frystyk 428: PUTS("If-None-Match: \"");
429: PUTS(etag);
430: PUTC('"');
431: PUTBLOCK(crlf, 2);
2.46 frystyk 432: if (PROT_TRACE) HTTrace("HTTP........ If-None-Match `%s\'\n", etag);
433: }
434: if (request_mask & HT_C_IMS) {
2.42 frystyk 435: time_t lm = HTAnchor_lastModified(anchor);
436: if (lm > 0) {
2.43 frystyk 437: PUTS("If-Modified-Since: ");
2.42 frystyk 438: PUTS(HTDateTimeStr(&lm, NO));
439: PUTBLOCK(crlf, 2);
2.43 frystyk 440: if (PROT_TRACE) HTTrace("HTTP........ If-Modified-Since\n");
2.42 frystyk 441: }
442: }
443:
2.45 frystyk 444: /*
445: ** Max forwards is mainly for TRACE where we want to be able to stop the
446: ** TRACE at a specific location un the message path.
447: */
2.39 frystyk 448: if (request_mask & HT_C_MAX_FORWARDS) {
449: int hops = HTRequest_maxForwards(request);
450: if (hops >= 0) {
451: sprintf(qstr, "%d", hops);
452: PUTS("Max-Forwards: ");
453: PUTS(qstr);
454: PUTBLOCK(crlf, 2);
455: }
2.42 frystyk 456: }
2.45 frystyk 457:
458: /*
459: ** Range requests. For now, we only take the first entry registered for
460: ** this request. This means that you can only send a single "unit" and
461: ** then a set of range within this unit. This is in accordance with
462: ** HTTP/1.1. Multiple units will go on multiple lines.
463: */
2.42 frystyk 464: if (request_mask & HT_C_RANGE) {
2.45 frystyk 465: HTAssocList * cur = HTRequest_range(request);
466: if (cur) { /* Range requests */
467: HTAssoc * pres;
468: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
469: PUTS("Range: ");
470: PUTS(HTAssoc_name(pres)); /* Unit */
471: PUTS("=");
472: PUTS(HTAssoc_value(pres)); /* Ranges within this unit */
473: PUTBLOCK(crlf, 2);
474: }
475: }
2.1 frystyk 476: }
2.34 frystyk 477: if (request_mask & HT_C_REFERER) {
478: HTParentAnchor * parent_anchor = HTRequest_parent(request);
479: if (parent_anchor) {
480: char * act = HTAnchor_address((HTAnchor *) anchor);
481: char * parent = HTAnchor_address((HTAnchor *) parent_anchor);
2.50 frystyk 482: #if 1
483: char * relative = HTRelative(parent, act);
484: #else
2.34 frystyk 485: char * relative = HTParse(parent, act,
486: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
2.50 frystyk 487: #endif
2.34 frystyk 488: if (relative && *relative) {
489: PUTS("Referer: ");
2.50 frystyk 490: PUTS(relative);
2.34 frystyk 491: PUTBLOCK(crlf, 2);
492: }
493: HT_FREE(act);
494: HT_FREE(parent);
495: HT_FREE(relative);
2.1 frystyk 496: }
497: }
2.34 frystyk 498: if (request_mask & HT_C_USER_AGENT) {
2.24 frystyk 499: PUTS("User-Agent: ");
500: PUTS(HTLib_appName());
501: PUTC('/');
502: PUTS(HTLib_appVersion());
503: PUTC(' ');
504: PUTS(HTLib_name());
505: PUTC('/');
506: PUTS(HTLib_version());
507: PUTBLOCK(crlf, 2);
2.1 frystyk 508: }
2.53 frystyk 509: if (PROT_TRACE) HTTrace("HTTP........ Generating HTTP/1.x Request Headers\n");
2.38 frystyk 510: return HT_OK;
2.1 frystyk 511: }
512:
2.29 frystyk 513: PRIVATE int HTTPRequest_put_block (HTStream * me, const char * b, int l)
2.1 frystyk 514: {
2.7 frystyk 515: if (!me->target) {
2.1 frystyk 516: return HT_WOULD_BLOCK;
2.7 frystyk 517: } else if (me->transparent)
2.11 frystyk 518: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 519: else {
2.38 frystyk 520: int status = HT_OK;
521: if (me->version == HTTP_09) {
522: status = HTTP09Request(me, me->request);
523: if (status != HT_OK) return status;
524: } else {
525: status = HTTPMakeRequest(me, me->request);
526: if (status != HT_OK) return status;
2.1 frystyk 527: me->transparent = YES;
2.11 frystyk 528: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 529: }
530: return status;
531: }
532: }
533:
2.16 frystyk 534: PRIVATE int HTTPRequest_put_character (HTStream * me, char c)
2.1 frystyk 535: {
2.11 frystyk 536: return HTTPRequest_put_block(me, &c, 1);
2.1 frystyk 537: }
538:
2.29 frystyk 539: PRIVATE int HTTPRequest_put_string (HTStream * me, const char * s)
2.1 frystyk 540: {
2.11 frystyk 541: return HTTPRequest_put_block(me, s, strlen(s));
2.1 frystyk 542: }
543:
544: /*
545: ** Flushes data but doesn't free stream object
546: */
2.16 frystyk 547: PRIVATE int HTTPRequest_flush (HTStream * me)
2.1 frystyk 548: {
2.13 frystyk 549: int status = HTTPRequest_put_block(me, NULL, 0);
550: return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
2.1 frystyk 551: }
552:
553: /*
554: ** Flushes data and frees stream object
555: */
2.16 frystyk 556: PRIVATE int HTTPRequest_free (HTStream * me)
2.1 frystyk 557: {
2.11 frystyk 558: int status = HTTPRequest_flush(me);
559: if (status != HT_WOULD_BLOCK) {
560: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
561: return HT_WOULD_BLOCK;
2.38 frystyk 562: HT_FREE(me->url);
2.26 frystyk 563: HT_FREE(me);
2.1 frystyk 564: }
2.7 frystyk 565: return status;
2.1 frystyk 566: }
567:
2.16 frystyk 568: PRIVATE int HTTPRequest_abort (HTStream * me, HTList * e)
2.1 frystyk 569: {
2.27 eric 570: if (PROT_TRACE) HTTrace("HTTPRequest. ABORTING...\n");
2.51 kahan 571: /* JK: Added protection against NULL pointers */
2.49 frystyk 572: if (me) {
2.51 kahan 573: if (me->target && me->target->isa)
574: (*me->target->isa->abort)(me->target, e);
575: if (me->url)
576: HT_FREE(me->url);
2.49 frystyk 577: HT_FREE(me);
578: }
2.1 frystyk 579: return HT_ERROR;
580: }
581:
582: /* HTTPRequest Stream
583: ** -----------------
584: */
2.29 frystyk 585: PRIVATE const HTStreamClass HTTPRequestClass =
2.1 frystyk 586: {
587: "HTTPRequest",
588: HTTPRequest_flush,
589: HTTPRequest_free,
590: HTTPRequest_abort,
591: HTTPRequest_put_character,
592: HTTPRequest_put_string,
593: HTTPRequest_put_block
594: };
595:
2.23 frystyk 596: PUBLIC HTStream * HTTPRequest_new (HTRequest * request, HTStream * target,
2.45 frystyk 597: BOOL endHeader, int version)
2.1 frystyk 598: {
2.26 frystyk 599: HTStream * me;
600: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
601: HT_OUTOFMEM("HTTPRequest_new");
2.1 frystyk 602: me->isa = &HTTPRequestClass;
603: me->target = target;
604: me->request = request;
2.45 frystyk 605: me->version = version;
2.1 frystyk 606: me->transparent = NO;
2.46 frystyk 607:
608: /*
609: ** If sending a body in the request then we want a 100 code!
610: */
611: if (HTMethod_hasEntity(HTRequest_method(request)))
612: HTRequest_addExpect(request, "100-continue", "");
613:
2.23 frystyk 614:
615: /* Return general HTTP header stream */
2.45 frystyk 616: return HTTPGen_new(request, me, endHeader, version);
2.1 frystyk 617: }
Webmaster