Annotation of libwww/Library/src/HTTPReq.c, revision 2.31
2.1 frystyk 1: /* HTTPReq.c
2.23 frystyk 2: ** HTTP REQUEST GENERATION
2.1 frystyk 3: **
4: ** This module implements the output stream for HTTP used for sending
5: ** requests with or without a entity body.
6: **
7: ** History:
8: ** Jan 95 HFN Written from scratch
9: */
10:
11: /* Library Includes */
2.29 frystyk 12: #include "sysdep.h"
2.28 frystyk 13: #include "WWWUtil.h"
2.1 frystyk 14: #include "HTParse.h"
2.4 frystyk 15: #include "HTFormat.h"
2.11 frystyk 16: #include "HTNetMan.h"
17: #include "HTDNS.h"
2.1 frystyk 18: #include "HTTCP.h"
2.14 frystyk 19: #include "HTAccess.h"
2.17 frystyk 20: #include "HTWWWStr.h"
2.1 frystyk 21: #include "HTWriter.h"
2.10 frystyk 22: #include "HTReqMan.h"
2.23 frystyk 23: #include "HTTPGen.h"
2.21 frystyk 24: #include "HTTPUtil.h"
2.1 frystyk 25: #include "HTTPReq.h" /* Implements */
26:
2.24 frystyk 27: #define PUTC(c) (*me->target->isa->put_character)(me->target, c)
28: #define PUTS(s) (*me->target->isa->put_string)(me->target, s)
2.1 frystyk 29: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
30:
31: struct _HTStream {
2.29 frystyk 32: const HTStreamClass * isa;
2.1 frystyk 33: HTStream * target;
34: HTRequest * request;
2.18 frystyk 35: SOCKET sockfd;
2.11 frystyk 36: int version;
2.1 frystyk 37: BOOL transparent;
38: };
39:
40: /* ------------------------------------------------------------------------- */
41: /* HTTP Output Request Stream */
42: /* ------------------------------------------------------------------------- */
43:
2.11 frystyk 44: /* HTTP09Request
45: ** -------------
46: ** Makes a HTTP/0.9 request
2.1 frystyk 47: */
2.11 frystyk 48: PRIVATE void HTTP09Request (HTStream * me, HTRequest * request)
49: {
50: char *addr = HTAnchor_physical(request->anchor);
51: char *fullurl = HTParse(addr, "", PARSE_PATH|PARSE_PUNCTUATION);
2.24 frystyk 52: PUTS("GET ");
53: PUTS(fullurl);
54: PUTC(CR);
55: PUTC(LF);
2.11 frystyk 56: }
57:
58: /* HTTPMakeRequest
59: ** ---------------
60: ** Makes a HTTP/1.0-1.1 request header.
61: */
62: PRIVATE void HTTPMakeRequest (HTStream * me, HTRequest * request)
2.1 frystyk 63: {
2.24 frystyk 64: char crlf[3];
65: char qstr[10];
2.13 frystyk 66: HTParentAnchor *anchor = HTRequest_anchor(request);
2.24 frystyk 67: *crlf = CR; *(crlf+1) = LF; *(crlf+2) = '\0';
2.1 frystyk 68:
69: /* Generate the HTTP/1.0 RequestLine */
70: if (request->method != METHOD_INVALID) {
2.24 frystyk 71: PUTS(HTMethod_name(request->method));
72: PUTC(' ');
2.1 frystyk 73: } else
2.24 frystyk 74: PUTS("GET ");
2.1 frystyk 75:
76: /* If we are using a proxy then only take the `path' info in the URL */
77: {
2.13 frystyk 78: char *addr = HTAnchor_physical(anchor);
2.6 frystyk 79: char *fullurl = HTParse(addr, "", PARSE_PATH|PARSE_PUNCTUATION);
2.1 frystyk 80: if (request->using_proxy) {
2.24 frystyk 81: PUTS(fullurl+1);
2.1 frystyk 82: } else {
2.24 frystyk 83: PUTS(fullurl);
2.1 frystyk 84: }
2.26 frystyk 85: HT_FREE(fullurl);
2.1 frystyk 86: }
2.25 frystyk 87: PUTC(' ');
88: PUTS(HTTP_VERSION);
2.24 frystyk 89: PUTBLOCK(crlf, 2);
2.1 frystyk 90:
2.4 frystyk 91: /* Request Headers */
2.22 frystyk 92: if (request->RequestMask & HT_C_ACCEPT_TYPE) {
2.1 frystyk 93: int list;
94: HTList *cur;
2.24 frystyk 95: BOOL first=YES;
2.1 frystyk 96: for (list=0; list<2; list++) {
2.14 frystyk 97: if ((!list && ((cur = HTFormat_conversion()) != NULL)) ||
98: (list && ((cur = HTRequest_conversion(request)) != NULL))) {
2.4 frystyk 99: HTPresentation *pres;
2.24 frystyk 100: while ((pres = (HTPresentation *) HTList_nextObject(cur))) {
2.19 frystyk 101: if (pres->rep_out==WWW_PRESENT && pres->quality <= 1.0) {
2.24 frystyk 102: if (first) {
103: PUTS("Accept: ");
104: first=NO;
105: } else
106: PUTC(',');
107: PUTS(HTAtom_name(pres->rep));
2.1 frystyk 108: if (pres->quality != 1.0) {
2.24 frystyk 109: sprintf(qstr, ";q=%1.1f", pres->quality);
110: PUTS(qstr);
2.1 frystyk 111: }
112: }
113: }
114: }
115: }
2.31 ! frystyk 116: if (!first) PUTBLOCK(crlf, 2);
2.1 frystyk 117: }
2.22 frystyk 118: if (request->RequestMask & HT_C_ACCEPT_CHAR) {
2.4 frystyk 119: int list;
120: HTList *cur;
2.24 frystyk 121: BOOL first=YES;
2.4 frystyk 122: for (list=0; list<2; list++) {
2.14 frystyk 123: if ((!list && ((cur = HTFormat_charset()) != NULL)) ||
124: (list && ((cur = HTRequest_charset(request)) != NULL))) {
2.4 frystyk 125: HTAcceptNode *pres;
126: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 127: if (first) {
2.24 frystyk 128: PUTS("Accept-Charset: ");
2.5 frystyk 129: first=NO;
2.24 frystyk 130: } else
131: PUTC(',');
132: PUTS(HTAtom_name(pres->atom));
2.4 frystyk 133: }
134: }
135: }
2.31 ! frystyk 136: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 137: }
2.22 frystyk 138: if (request->RequestMask & HT_C_ACCEPT_ENC) {
2.4 frystyk 139: int list;
140: HTList *cur;
2.24 frystyk 141: BOOL first=YES;
2.4 frystyk 142: for (list=0; list<2; list++) {
2.14 frystyk 143: if ((!list && ((cur = HTFormat_encoding()) != NULL)) ||
144: (list && ((cur = HTRequest_encoding(request)) != NULL))) {
2.4 frystyk 145: HTAcceptNode *pres;
146: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 147: if (first) {
2.24 frystyk 148: PUTS("Accept-Encoding: ");
2.5 frystyk 149: first=NO;
2.24 frystyk 150: } else
151: PUTC(',');
152: PUTS(HTAtom_name(pres->atom));
153: if (pres->quality != 1.0) {
154: sprintf(qstr, ";q=%1.1f", pres->quality);
155: PUTS(qstr);
2.5 frystyk 156: }
2.4 frystyk 157: }
158: }
159: }
2.31 ! frystyk 160: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 161: }
2.22 frystyk 162: if (request->RequestMask & HT_C_ACCEPT_LAN) {
2.4 frystyk 163: int list;
164: HTList *cur;
2.24 frystyk 165: BOOL first=YES;
2.4 frystyk 166: for (list=0; list<2; list++) {
2.14 frystyk 167: if ((!list && ((cur = HTFormat_language()) != NULL)) ||
168: (list && ((cur = HTRequest_language(request)) != NULL))) {
2.4 frystyk 169: HTAcceptNode *pres;
170: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 171: if (first) {
2.24 frystyk 172: PUTS("Accept-Language: ");
2.5 frystyk 173: first=NO;
2.24 frystyk 174: } else
175: PUTC(',');
176: PUTS(HTAtom_name(pres->atom));
177: if (pres->quality != 1.0) {
178: sprintf(qstr, ";q=%1.1f", pres->quality);
179: PUTS(qstr);
2.5 frystyk 180: }
2.4 frystyk 181: }
182: }
183: }
2.31 ! frystyk 184: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 185: }
2.28 frystyk 186: if (request->credentials) { /* Access authentication */
187: HTAssocList * cur = request->credentials;
188: HTAssoc * pres;
189: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
190: PUTS(HTAssoc_name(pres));
191: PUTS(": ");
192: PUTS(HTAssoc_value(pres));
193: PUTBLOCK(crlf, 2);
194: }
2.1 frystyk 195: }
2.22 frystyk 196: if (request->RequestMask & HT_C_FROM) {
2.29 frystyk 197: const char *mailaddress = HTGetMailAddress();
2.1 frystyk 198: if (mailaddress) {
2.24 frystyk 199: PUTS("From: ");
200: PUTS(mailaddress);
201: PUTBLOCK(crlf, 2);
2.1 frystyk 202: }
203: }
2.22 frystyk 204: if (request->RequestMask & HT_C_IMS) {
2.21 frystyk 205: time_t lm = HTAnchor_lastModified(anchor);
2.24 frystyk 206: if (lm > 0) {
207: PUTS("If-Modified-Since: ");
208: PUTS(HTDateTimeStr(&lm, NO));
209: PUTBLOCK(crlf, 2);
2.8 frystyk 210: }
211: }
2.22 frystyk 212: if (request->RequestMask & HT_C_HOST) {
2.13 frystyk 213: char *orig = HTAnchor_address((HTAnchor *) anchor);
2.12 frystyk 214: char *host = HTParse(orig, "", PARSE_HOST);
215: char *ptr = strchr(host, ':'); /* Chop off port number */
216: if (ptr) *ptr = '\0';
2.24 frystyk 217: PUTS("Host: ");
218: PUTS(host);
219: PUTBLOCK(crlf, 2);
2.26 frystyk 220: HT_FREE(orig);
221: HT_FREE(host);
2.1 frystyk 222: }
2.22 frystyk 223: if (request->RequestMask & HT_C_REFERER && request->parentAnchor) {
2.13 frystyk 224: char *act = HTAnchor_address((HTAnchor *) anchor);
2.1 frystyk 225: char *parent = HTAnchor_address((HTAnchor *) request->parentAnchor);
226: char *relative = HTParse(parent, act,
227: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
228: if (relative && *relative) {
2.24 frystyk 229: PUTS("Referer: ");
230: PUTS(parent);
231: PUTBLOCK(crlf, 2);
2.1 frystyk 232: }
2.26 frystyk 233: HT_FREE(act);
234: HT_FREE(parent);
235: HT_FREE(relative);
2.1 frystyk 236: }
2.22 frystyk 237: if (request->RequestMask & HT_C_USER_AGENT) {
2.24 frystyk 238: PUTS("User-Agent: ");
239: PUTS(HTLib_appName());
240: PUTC('/');
241: PUTS(HTLib_appVersion());
242: PUTC(' ');
243: PUTS(HTLib_name());
244: PUTC('/');
245: PUTS(HTLib_version());
246: PUTBLOCK(crlf, 2);
2.1 frystyk 247: }
2.27 eric 248: if (PROT_TRACE)HTTrace("HTTP........ Generating Request Headers\n");
2.1 frystyk 249: }
250:
2.29 frystyk 251: PRIVATE int HTTPRequest_put_block (HTStream * me, const char * b, int l)
2.1 frystyk 252: {
2.7 frystyk 253: if (!me->target) {
2.1 frystyk 254: return HT_WOULD_BLOCK;
2.7 frystyk 255: } else if (me->transparent)
2.11 frystyk 256: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 257: else {
258: int status;
2.11 frystyk 259: if (me->version == HTTP_09)
260: HTTP09Request(me, me->request);
2.24 frystyk 261: else {
2.11 frystyk 262: HTTPMakeRequest(me, me->request); /* Generate header */
2.1 frystyk 263: me->transparent = YES;
2.11 frystyk 264: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 265: }
266: return status;
267: }
268: }
269:
2.16 frystyk 270: PRIVATE int HTTPRequest_put_character (HTStream * me, char c)
2.1 frystyk 271: {
2.11 frystyk 272: return HTTPRequest_put_block(me, &c, 1);
2.1 frystyk 273: }
274:
2.29 frystyk 275: PRIVATE int HTTPRequest_put_string (HTStream * me, const char * s)
2.1 frystyk 276: {
2.11 frystyk 277: return HTTPRequest_put_block(me, s, strlen(s));
2.1 frystyk 278: }
279:
280: /*
281: ** Flushes data but doesn't free stream object
282: */
2.16 frystyk 283: PRIVATE int HTTPRequest_flush (HTStream * me)
2.1 frystyk 284: {
2.13 frystyk 285: int status = HTTPRequest_put_block(me, NULL, 0);
286: return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
2.1 frystyk 287: }
288:
289: /*
290: ** Flushes data and frees stream object
291: */
2.16 frystyk 292: PRIVATE int HTTPRequest_free (HTStream * me)
2.1 frystyk 293: {
2.11 frystyk 294: int status = HTTPRequest_flush(me);
295: if (status != HT_WOULD_BLOCK) {
296: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
297: return HT_WOULD_BLOCK;
2.26 frystyk 298: HT_FREE(me);
2.1 frystyk 299: }
2.7 frystyk 300: return status;
2.1 frystyk 301: }
302:
2.16 frystyk 303: PRIVATE int HTTPRequest_abort (HTStream * me, HTList * e)
2.1 frystyk 304: {
2.13 frystyk 305: if (me->target) (*me->target->isa->abort)(me->target, e);
2.26 frystyk 306: HT_FREE(me);
2.27 eric 307: if (PROT_TRACE) HTTrace("HTTPRequest. ABORTING...\n");
2.1 frystyk 308: return HT_ERROR;
309: }
310:
311: /* HTTPRequest Stream
312: ** -----------------
313: */
2.29 frystyk 314: PRIVATE const HTStreamClass HTTPRequestClass =
2.1 frystyk 315: {
316: "HTTPRequest",
317: HTTPRequest_flush,
318: HTTPRequest_free,
319: HTTPRequest_abort,
320: HTTPRequest_put_character,
321: HTTPRequest_put_string,
322: HTTPRequest_put_block
323: };
324:
2.23 frystyk 325: PUBLIC HTStream * HTTPRequest_new (HTRequest * request, HTStream * target,
326: BOOL endHeader)
2.1 frystyk 327: {
2.11 frystyk 328: HTdns *dns = HTNet_dns(request->net);
2.26 frystyk 329: HTStream * me;
330: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
331: HT_OUTOFMEM("HTTPRequest_new");
2.1 frystyk 332: me->isa = &HTTPRequestClass;
333: me->target = target;
334: me->request = request;
2.11 frystyk 335: me->version = HTDNS_serverVersion(dns);
2.1 frystyk 336: me->transparent = NO;
2.23 frystyk 337:
338: /* Return general HTTP header stream */
339: return HTTPGen_new(request, me, endHeader);
2.1 frystyk 340: }
Webmaster