Annotation of libwww/Library/src/HTTPReq.c, revision 2.21
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.21 ! frystyk 26: #include "HTTPUtil.h"
2.1 frystyk 27: #include "HTTPReq.h" /* Implements */
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.18 frystyk 35: SOCKET 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.15 frystyk 59: if (PROT_TRACE) TTYPrint(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))) {
2.19 frystyk 103: if (pres->rep_out==WWW_PRESENT && pres->quality <= 1.0) {
2.1 frystyk 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.21 ! frystyk 200: time_t lm = HTAnchor_lastModified(anchor);
! 201: if (lm != -1) {
2.8 frystyk 202: sprintf(linebuf, "If-Modified-Since: %s%c%c",
2.21 ! frystyk 203: HTDateTimeStr(&lm, 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