Annotation of libwww/Library/src/HTTPReq.c, revision 2.13
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"
20: #include "HTWriter.h"
2.10 frystyk 21: #include "HTReqMan.h"
2.1 frystyk 22: #include "HTChunk.h"
2.13 ! frystyk 23: #include "HTMIMERq.h"
2.1 frystyk 24: #include "HTTPReq.h" /* Implements */
25:
26: extern char * HTAppName; /* Application name: please supply */
27: extern char * HTAppVersion; /* Application version: please supply */
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.7 frystyk 36: SOCKFD 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.13 ! frystyk 60: if (PROT_TRACE) fprintf(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++) {
100: if ((!list && ((cur=HTConversions) != NULL)) ||
101: (list && ((cur=request->conversions) != NULL))) {
2.4 frystyk 102: HTPresentation *pres;
2.1 frystyk 103: while ((pres =(HTPresentation *) HTList_nextObject(cur))) {
104: if (pres->rep_out == WWW_PRESENT) {
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++) {
124: if ((!list && ((cur=HTCharsets) != NULL)) ||
125: (list && ((cur=request->charsets) != NULL))) {
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++) {
147: if ((!list && ((cur=HTEncodings) != NULL)) ||
148: (list && ((cur=request->encodings) != NULL))) {
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++) {
170: if ((!list && ((cur=HTLanguages) != NULL)) ||
171: (list && ((cur=request->languages) != NULL))) {
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.1 frystyk 231: sprintf(linebuf, "User-Agent: %s/%s libwww/%s%c%c",
232: HTAppName ? HTAppName : "unknown",
233: HTAppVersion ? HTAppVersion : "0.0",
234: HTLibraryVersion, CR, LF);
235: HTChunkPuts(header, linebuf);
236: }
2.13 ! frystyk 237: if (PROT_TRACE) fprintf(TDEST, "HTTP Tx..... %s", header->data);
2.1 frystyk 238: }
239:
2.11 frystyk 240: PRIVATE int HTTPRequest_put_block ARGS3(HTStream *, me, CONST char*, b, int, l)
2.1 frystyk 241: {
2.7 frystyk 242: if (!me->target) {
2.1 frystyk 243: return HT_WOULD_BLOCK;
2.7 frystyk 244: } else if (me->transparent)
2.11 frystyk 245: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 246: else {
247: int status;
2.11 frystyk 248: if (me->version == HTTP_09)
249: HTTP09Request(me, me->request);
250: else
251: HTTPMakeRequest(me, me->request); /* Generate header */
2.13 ! frystyk 252: if ((status = PUTBLOCK(HTChunkData(me->buffer),
! 253: HTChunkSize(me->buffer))) == HT_OK) {
2.1 frystyk 254: me->transparent = YES;
2.11 frystyk 255: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 256: }
257: return status;
258: }
259: }
260:
2.11 frystyk 261: PRIVATE int HTTPRequest_put_character ARGS2(HTStream *, me, char, c)
2.1 frystyk 262: {
2.11 frystyk 263: return HTTPRequest_put_block(me, &c, 1);
2.1 frystyk 264: }
265:
2.11 frystyk 266: PRIVATE int HTTPRequest_put_string ARGS2(HTStream *, me, CONST char*, s)
2.1 frystyk 267: {
2.11 frystyk 268: return HTTPRequest_put_block(me, s, strlen(s));
2.1 frystyk 269: }
270:
271: /*
272: ** Flushes data but doesn't free stream object
273: */
274: PRIVATE int HTTPRequest_flush ARGS1(HTStream *, me)
275: {
2.13 ! frystyk 276: int status = HTTPRequest_put_block(me, NULL, 0);
! 277: return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
2.1 frystyk 278: }
279:
280: /*
281: ** Flushes data and frees stream object
282: */
283: PRIVATE int HTTPRequest_free ARGS1(HTStream *, me)
284: {
2.11 frystyk 285: int status = HTTPRequest_flush(me);
286: if (status != HT_WOULD_BLOCK) {
287: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
288: return HT_WOULD_BLOCK;
289: HTChunkFree(me->buffer);
290: free(me);
2.1 frystyk 291: }
2.7 frystyk 292: return status;
2.1 frystyk 293: }
294:
295: PRIVATE int HTTPRequest_abort ARGS2(HTStream *, me, HTError, e)
296: {
2.13 ! frystyk 297: if (me->target) (*me->target->isa->abort)(me->target, e);
2.1 frystyk 298: HTChunkFree(me->buffer);
299: free(me);
2.13 ! frystyk 300: if (PROT_TRACE) fprintf(TDEST, "HTTPRequest. ABORTING...\n");
2.1 frystyk 301: return HT_ERROR;
302: }
303:
304: /* HTTPRequest Stream
305: ** -----------------
306: */
307: PRIVATE CONST HTStreamClass HTTPRequestClass =
308: {
309: "HTTPRequest",
310: HTTPRequest_flush,
311: HTTPRequest_free,
312: HTTPRequest_abort,
313: HTTPRequest_put_character,
314: HTTPRequest_put_string,
315: HTTPRequest_put_block
316: };
317:
318: PUBLIC HTStream * HTTPRequest_new ARGS2(HTRequest *, request,
319: HTStream *, target)
320: {
321: HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
2.11 frystyk 322: HTdns *dns = HTNet_dns(request->net);
2.1 frystyk 323: if (!me) outofmem(__FILE__, "HTTPRequest_new");
324: me->isa = &HTTPRequestClass;
325: me->target = target;
326: me->request = request;
327: me->buffer = HTChunkCreate(512);
2.11 frystyk 328: me->version = HTDNS_serverVersion(dns);
2.1 frystyk 329: me->transparent = NO;
2.13 ! frystyk 330: return HTMIMERequest_new(request, me); /* @@@ */
2.1 frystyk 331: }
Webmaster