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