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