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