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