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