Annotation of libwww/Library/src/HTTPReq.c, revision 2.41
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.41 ! frystyk 6: ** @(#) $Id: HTTPReq.c,v 2.40 1996/08/13 02:17:17 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) {
53: PUTS("GET ");
54: me->state++;
55: }
56: if (me->state == 1) {
57: int status = PUTS(me->url);
58: if (status != HT_OK) return status;
59: me->state++;
60: }
2.24 frystyk 61: PUTC(CR);
62: PUTC(LF);
2.38 frystyk 63: return HT_OK;
2.11 frystyk 64: }
65:
66: /* HTTPMakeRequest
67: ** ---------------
68: ** Makes a HTTP/1.0-1.1 request header.
69: */
2.38 frystyk 70: PRIVATE int HTTPMakeRequest (HTStream * me, HTRequest * request)
2.1 frystyk 71: {
2.39 frystyk 72: HTMethod method = HTRequest_method(request);
73: HTRqHd request_mask = HTRequest_rqHd(request);
74: HTParentAnchor * anchor = HTRequest_anchor(request);
2.24 frystyk 75: char crlf[3];
76: char qstr[10];
77: *crlf = CR; *(crlf+1) = LF; *(crlf+2) = '\0';
2.1 frystyk 78:
2.41 ! frystyk 79: /* Generate the HTTP/1.x RequestLine */
2.38 frystyk 80: if (me->state == 0) {
2.34 frystyk 81: if (method != METHOD_INVALID) {
82: PUTS(HTMethod_name(method));
83: PUTC(' ');
84: } else
85: PUTS("GET ");
2.38 frystyk 86: me->state++;
2.34 frystyk 87: }
2.1 frystyk 88:
2.39 frystyk 89: /*
90: ** Generate the Request URI. If we are using full request URI then it's
91: ** easy. Otherwise we must filter out the path part of the URI.
92: ** In case it's a OPTIONS request then if there is no pathinfo then use
93: ** a * instead.
94: */
95: if (me->state == 1) {
2.38 frystyk 96: char * addr = HTAnchor_physical(anchor);
2.39 frystyk 97: int status = HT_OK;
2.35 frystyk 98: if (HTRequest_fullURI(request)) {
2.40 frystyk 99: status = PUTS(addr);
2.1 frystyk 100: } else {
2.39 frystyk 101: if (method == METHOD_OPTIONS) {
102: /*
103: ** We don't preserve the final slash or lack of same through
104: ** out the code. This is mainly for optimization reasons
105: ** but it gives a problem OPTIONS
106: */
107: if (!me->url) me->url = HTParse(addr, "", PARSE_PATH);
108: if (!*me->url) StrAllocCopy(me->url, "*");
109: status = PUTS(me->url);
110: } else {
111: if (!me->url)
112: me->url = HTParse(addr, "", PARSE_PATH|PARSE_PUNCTUATION);
113: status = PUTS(me->url);
114: }
2.1 frystyk 115: }
2.38 frystyk 116: if (status != HT_OK) return status;
117: me->state++;
2.1 frystyk 118: }
2.25 frystyk 119: PUTC(' ');
2.41 ! frystyk 120:
! 121: /*
! 122: ** Send out the version number. If we know it is a HTTP/1.0 server we
! 123: ** are talking to then use HTTP/1.0, else use HTTP/1.1 as default version
! 124: ** number
! 125: */
! 126: if (me->version == HTTP_10)
! 127: PUTS(HTTP_VERSION_10);
! 128: else
! 129: PUTS(HTTP_VERSION);
2.24 frystyk 130: PUTBLOCK(crlf, 2);
2.1 frystyk 131:
2.4 frystyk 132: /* Request Headers */
2.34 frystyk 133: if (request_mask & HT_C_ACCEPT_TYPE) {
2.37 frystyk 134: /*
135: ** If caller has specified a specific output format then use this.
136: ** Otherwise use all the registered converters to generate the
137: ** accept header
138: */
139: if (HTRequest_outputFormat(request) == WWW_PRESENT) {
140: int list;
141: HTList *cur;
142: BOOL first=YES;
143: for (list=0; list<2; list++) {
144: if ((!list && ((cur = HTFormat_conversion()) != NULL)) ||
145: (list && ((cur = HTRequest_conversion(request))!=NULL))) {
146: HTPresentation * pres;
147: while ((pres=(HTPresentation *) HTList_nextObject(cur))) {
148: if (pres->rep_out==WWW_PRESENT && pres->quality<=1.0) {
149: if (first) {
150: PUTS("Accept: ");
151: first=NO;
152: } else
153: PUTC(',');
154: PUTS(HTAtom_name(pres->rep));
155: if (pres->quality != 1.0) {
156: sprintf(qstr, ";q=%1.1f", pres->quality);
157: PUTS(qstr);
158: }
2.1 frystyk 159: }
160: }
161: }
162: }
2.37 frystyk 163: if (!first) PUTBLOCK(crlf, 2);
164: } else {
165: PUTS("Accept: ");
166: PUTS(HTAtom_name(HTRequest_outputFormat(request)));
167: PUTBLOCK(crlf, 2);
168: }
2.1 frystyk 169: }
2.34 frystyk 170: if (request_mask & HT_C_ACCEPT_CHAR) {
2.4 frystyk 171: int list;
172: HTList *cur;
2.24 frystyk 173: BOOL first=YES;
2.4 frystyk 174: for (list=0; list<2; list++) {
2.14 frystyk 175: if ((!list && ((cur = HTFormat_charset()) != NULL)) ||
176: (list && ((cur = HTRequest_charset(request)) != NULL))) {
2.4 frystyk 177: HTAcceptNode *pres;
178: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 179: if (first) {
2.24 frystyk 180: PUTS("Accept-Charset: ");
2.5 frystyk 181: first=NO;
2.24 frystyk 182: } else
183: PUTC(',');
184: PUTS(HTAtom_name(pres->atom));
2.4 frystyk 185: }
186: }
187: }
2.31 frystyk 188: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 189: }
2.34 frystyk 190: if (request_mask & HT_C_ACCEPT_ENC) {
2.4 frystyk 191: int list;
192: HTList *cur;
2.24 frystyk 193: BOOL first=YES;
2.4 frystyk 194: for (list=0; list<2; list++) {
2.33 frystyk 195: if ((!list && ((cur = HTFormat_contentCoding()) != NULL)) ||
2.14 frystyk 196: (list && ((cur = HTRequest_encoding(request)) != NULL))) {
2.33 frystyk 197: HTCoding * pres;
198: while ((pres = (HTCoding *) HTList_nextObject(cur))) {
2.5 frystyk 199: if (first) {
2.24 frystyk 200: PUTS("Accept-Encoding: ");
2.32 frystyk 201: first = NO;
2.24 frystyk 202: } else
203: PUTC(',');
2.33 frystyk 204: PUTS(HTCoding_name(pres));
2.4 frystyk 205: }
206: }
207: }
2.31 frystyk 208: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 209: }
2.34 frystyk 210: if (request_mask & HT_C_ACCEPT_LAN) {
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_language()) != NULL)) ||
216: (list && ((cur = HTRequest_language(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-Language: ");
2.5 frystyk 221: first=NO;
2.24 frystyk 222: } else
223: PUTC(',');
224: PUTS(HTAtom_name(pres->atom));
225: if (pres->quality != 1.0) {
226: sprintf(qstr, ";q=%1.1f", pres->quality);
227: PUTS(qstr);
2.5 frystyk 228: }
2.4 frystyk 229: }
230: }
231: }
2.31 frystyk 232: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 233: }
2.36 frystyk 234: if (request_mask & HT_C_AUTH) {
2.34 frystyk 235: HTAssocList * cur = HTRequest_credentials(request);
236: if (cur) { /* Access authentication */
237: HTAssoc * pres;
238: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
239: PUTS(HTAssoc_name(pres));
240: PUTS(": ");
241: PUTS(HTAssoc_value(pres));
242: PUTBLOCK(crlf, 2);
243: }
2.28 frystyk 244: }
2.1 frystyk 245: }
2.34 frystyk 246: if (request_mask & HT_C_FROM) {
247: HTUserProfile * up = HTRequest_userProfile(request);
248: const char * mailaddress = HTUserProfile_email(up);
2.1 frystyk 249: if (mailaddress) {
2.24 frystyk 250: PUTS("From: ");
251: PUTS(mailaddress);
252: PUTBLOCK(crlf, 2);
2.1 frystyk 253: }
254: }
2.34 frystyk 255: if (request_mask & HT_C_IMS) {
2.21 frystyk 256: time_t lm = HTAnchor_lastModified(anchor);
2.24 frystyk 257: if (lm > 0) {
258: PUTS("If-Modified-Since: ");
259: PUTS(HTDateTimeStr(&lm, NO));
260: PUTBLOCK(crlf, 2);
2.8 frystyk 261: }
262: }
2.34 frystyk 263: if (request_mask & HT_C_HOST) {
2.13 frystyk 264: char *orig = HTAnchor_address((HTAnchor *) anchor);
2.12 frystyk 265: char *host = HTParse(orig, "", PARSE_HOST);
2.34 frystyk 266: #if 0
267: /* Keep the port number for HTTP/1.1 compliance */
2.12 frystyk 268: char *ptr = strchr(host, ':'); /* Chop off port number */
269: if (ptr) *ptr = '\0';
2.34 frystyk 270: #endif
2.24 frystyk 271: PUTS("Host: ");
272: PUTS(host);
273: PUTBLOCK(crlf, 2);
2.26 frystyk 274: HT_FREE(orig);
275: HT_FREE(host);
2.39 frystyk 276: }
277: if (request_mask & HT_C_MAX_FORWARDS) {
278: int hops = HTRequest_maxForwards(request);
279: if (hops >= 0) {
280: sprintf(qstr, "%d", hops);
281: PUTS("Max-Forwards: ");
282: PUTS(qstr);
283: PUTBLOCK(crlf, 2);
284: }
2.1 frystyk 285: }
2.34 frystyk 286: if (request_mask & HT_C_REFERER) {
287: HTParentAnchor * parent_anchor = HTRequest_parent(request);
288: if (parent_anchor) {
289: char * act = HTAnchor_address((HTAnchor *) anchor);
290: char * parent = HTAnchor_address((HTAnchor *) parent_anchor);
291: char * relative = HTParse(parent, act,
292: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
293: if (relative && *relative) {
294: PUTS("Referer: ");
295: PUTS(parent);
296: PUTBLOCK(crlf, 2);
297: }
298: HT_FREE(act);
299: HT_FREE(parent);
300: HT_FREE(relative);
2.1 frystyk 301: }
302: }
2.34 frystyk 303: if (request_mask & HT_C_USER_AGENT) {
2.24 frystyk 304: PUTS("User-Agent: ");
305: PUTS(HTLib_appName());
306: PUTC('/');
307: PUTS(HTLib_appVersion());
308: PUTC(' ');
309: PUTS(HTLib_name());
310: PUTC('/');
311: PUTS(HTLib_version());
312: PUTBLOCK(crlf, 2);
2.1 frystyk 313: }
2.27 eric 314: if (PROT_TRACE)HTTrace("HTTP........ Generating Request Headers\n");
2.38 frystyk 315: return HT_OK;
2.1 frystyk 316: }
317:
2.29 frystyk 318: PRIVATE int HTTPRequest_put_block (HTStream * me, const char * b, int l)
2.1 frystyk 319: {
2.7 frystyk 320: if (!me->target) {
2.1 frystyk 321: return HT_WOULD_BLOCK;
2.7 frystyk 322: } else if (me->transparent)
2.11 frystyk 323: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 324: else {
2.38 frystyk 325: int status = HT_OK;
326: if (me->version == HTTP_09) {
327: status = HTTP09Request(me, me->request);
328: if (status != HT_OK) return status;
329: } else {
330: status = HTTPMakeRequest(me, me->request);
331: if (status != HT_OK) return status;
2.1 frystyk 332: me->transparent = YES;
2.11 frystyk 333: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 334: }
335: return status;
336: }
337: }
338:
2.16 frystyk 339: PRIVATE int HTTPRequest_put_character (HTStream * me, char c)
2.1 frystyk 340: {
2.11 frystyk 341: return HTTPRequest_put_block(me, &c, 1);
2.1 frystyk 342: }
343:
2.29 frystyk 344: PRIVATE int HTTPRequest_put_string (HTStream * me, const char * s)
2.1 frystyk 345: {
2.11 frystyk 346: return HTTPRequest_put_block(me, s, strlen(s));
2.1 frystyk 347: }
348:
349: /*
350: ** Flushes data but doesn't free stream object
351: */
2.16 frystyk 352: PRIVATE int HTTPRequest_flush (HTStream * me)
2.1 frystyk 353: {
2.13 frystyk 354: int status = HTTPRequest_put_block(me, NULL, 0);
355: return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
2.1 frystyk 356: }
357:
358: /*
359: ** Flushes data and frees stream object
360: */
2.16 frystyk 361: PRIVATE int HTTPRequest_free (HTStream * me)
2.1 frystyk 362: {
2.11 frystyk 363: int status = HTTPRequest_flush(me);
364: if (status != HT_WOULD_BLOCK) {
365: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
366: return HT_WOULD_BLOCK;
2.38 frystyk 367: HT_FREE(me->url);
2.26 frystyk 368: HT_FREE(me);
2.1 frystyk 369: }
2.7 frystyk 370: return status;
2.1 frystyk 371: }
372:
2.16 frystyk 373: PRIVATE int HTTPRequest_abort (HTStream * me, HTList * e)
2.1 frystyk 374: {
2.13 frystyk 375: if (me->target) (*me->target->isa->abort)(me->target, e);
2.38 frystyk 376: HT_FREE(me->url);
2.26 frystyk 377: HT_FREE(me);
2.27 eric 378: if (PROT_TRACE) HTTrace("HTTPRequest. ABORTING...\n");
2.1 frystyk 379: return HT_ERROR;
380: }
381:
382: /* HTTPRequest Stream
383: ** -----------------
384: */
2.29 frystyk 385: PRIVATE const HTStreamClass HTTPRequestClass =
2.1 frystyk 386: {
387: "HTTPRequest",
388: HTTPRequest_flush,
389: HTTPRequest_free,
390: HTTPRequest_abort,
391: HTTPRequest_put_character,
392: HTTPRequest_put_string,
393: HTTPRequest_put_block
394: };
395:
2.23 frystyk 396: PUBLIC HTStream * HTTPRequest_new (HTRequest * request, HTStream * target,
397: BOOL endHeader)
2.1 frystyk 398: {
2.34 frystyk 399: HTNet * net = HTRequest_net(request);
400: HTHost * host = HTNet_host(net);
2.26 frystyk 401: HTStream * me;
402: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
403: HT_OUTOFMEM("HTTPRequest_new");
2.1 frystyk 404: me->isa = &HTTPRequestClass;
405: me->target = target;
406: me->request = request;
2.32 frystyk 407: me->version = HTHost_version(host);
2.1 frystyk 408: me->transparent = NO;
2.23 frystyk 409:
410: /* Return general HTTP header stream */
411: return HTTPGen_new(request, me, endHeader);
2.1 frystyk 412: }
Webmaster