Annotation of libwww/Library/src/HTTPReq.c, revision 2.3
2.1 frystyk 1: /* HTTPReq.c
2: ** MULTITHREADED IMPLEMENTATION OF HTTP CLIENT
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:
12: /* Library Includes */
13: #include "tcp.h"
14: #include "HTUtils.h"
15: #include "HTString.h"
16: #include "HTParse.h"
17: #include "HTThread.h"
18: #include "HTTCP.h"
19: #include "HTWriter.h"
20: #include "HTChunk.h"
21: #include "HTTPReq.h" /* Implements */
22:
23: /* Type definitions and global variables etc. local to this module */
24: extern char * HTAppName; /* Application name: please supply */
25: extern char * HTAppVersion; /* Application version: please supply */
26: PUBLIC char * HTProxyHeaders = NULL; /* Headers to pass as-is */
27:
28: /* Macros and other defines */
29: #define HTTP_VERSION "HTTP/1.0"
30: #define MIME_VERSION "MIME/1.0"
31: #define PUTC(c) (*me->target->isa->put_character)(me->target, c)
32: #define PUTS(s) (*me->target->isa->put_string)(me->target, s)
33: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
34: #define FREE_TARGET (*me->target->isa->_free)(me->target)
35: #define ABORT_TARGET (*me->target->isa->abort)(me->target, e)
36:
37: /* Type definitions and global variables etc. local to this module */
38:
39: PRIVATE char linebuf[256]; /* @@@ */
40:
41: struct _HTStream {
42: CONST HTStreamClass * isa;
43: HTStream * target;
44: char * url;
45: HTRequest * request;
46: HTChunk * buffer;
47: BOOL transparent;
48: };
49:
50: /* ------------------------------------------------------------------------- */
51: /* HTTP Output Request Stream */
52: /* ------------------------------------------------------------------------- */
53:
54: /* HTTPMakeRequest
55: **
56: ** This function composes the HTTP request header.
57: */
58: PRIVATE void HTTPMakeRequest ARGS2(HTStream *, me, HTRequest *, request)
59: {
60: HTChunk *header = me->buffer;
61: HTParentAnchor *entity =
62: (request->CopyRequest && request->CopyRequest->anchor) ?
63: request->CopyRequest->anchor : request->anchor;
64:
65: /* Generate the HTTP/1.0 RequestLine */
66: if (request->method != METHOD_INVALID) {
67: HTChunkPuts(header, HTMethod_name(request->method));
68: HTChunkPutc(header, ' ');
69: } else
70: HTChunkPuts(header, "GET ");
71:
72: /* If we are using a proxy then only take the `path' info in the URL */
73: {
74: char *fullurl = HTParse(me->url, "", PARSE_PATH|PARSE_PUNCTUATION);
75: if (request->using_proxy) {
76: HTChunkPuts(header, fullurl+1);
77: } else {
78: HTChunkPuts(header, fullurl);
79: }
80: free(fullurl);
81: }
82: HTChunkPutc(header, ' ');
83: HTChunkPuts(header, HTTP_VERSION);
84: HTChunkPutc(header, CR);
85: HTChunkPutc(header, LF);
86:
87: /* Header Information */
88: if (request->HeaderMask & HT_DATE) {
89: time_t local = time(NULL);
90: sprintf(linebuf, "Date: %s%c%c", HTDateTimeStr(&local, NO), CR,LF);
91: HTChunkPuts(header, linebuf);
92: }
93: if (request->HeaderMask & HT_MESSAGE_ID) {
94: CONST char *msgid = HTMessageIdStr();
95: if (msgid) {
96: sprintf(linebuf, "Message-ID: %s%c%c", msgid, CR, LF);
97: HTChunkPuts(header, linebuf);
98: }
99: }
100: if (request->HeaderMask & HT_MIME) {
101: sprintf(linebuf, "MIME-Version: %s%c%c", MIME_VERSION, CR, LF);
102: HTChunkPuts(header, linebuf);
103: }
104:
105: /* Run through local and global list of conversions for `Accept' lines */
106: if (request->HeaderMask & HT_ACCEPT) {
107: int list;
108: HTList *cur;
109: for (list=0; list<2; list++) {
110: if ((!list && ((cur=HTConversions) != NULL)) ||
111: (list && ((cur=request->conversions) != NULL))) {
112: HTPresentation *pres;
113: while ((pres =(HTPresentation *) HTList_nextObject(cur))) {
114: if (pres->rep_out == WWW_PRESENT) {
115: if (pres->quality != 1.0) {
116: sprintf(linebuf, "Accept: %s; q=%1.1f%c%c",
117: HTAtom_name(pres->rep),
118: pres->quality, CR, LF);
119: } else {
120: sprintf(linebuf, "Accept: %s%c%c",
121: HTAtom_name(pres->rep), CR, LF);
122: }
123: HTChunkPuts(header, linebuf);
124: }
125: }
126: }
127: }
128: }
129:
130: /* Put out authorization */
131: if (request->authorization != NULL) {
132: sprintf(linebuf, "Authorization: %s%c%c", request->authorization,
133: CR, LF);
134: HTChunkPuts(header, linebuf);
135: }
136: if (request->HeaderMask & HT_FROM) {
137: CONST char *mailaddress = HTGetMailAddress();
138: if (mailaddress) {
139: sprintf(linebuf, "From: %s%c%c", mailaddress, CR, LF);
140: HTChunkPuts(header, linebuf);
141: }
142: }
143: if (request->HeaderMask & HT_PRAGMA) {
144: sprintf(linebuf, "Pragma: %s%c%c", "no-cache", CR, LF);
145: HTChunkPuts(header, linebuf);
146: }
147: if (request->HeaderMask & HT_REFERER && request->parentAnchor) {
148: char *act = HTAnchor_address((HTAnchor *) request->anchor);
149: char *parent = HTAnchor_address((HTAnchor *) request->parentAnchor);
150: char *relative = HTParse(parent, act,
151: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
152: if (relative && *relative) {
153: sprintf(linebuf, "Referer: %s%c%c", parent, CR, LF);
154: HTChunkPuts(header, linebuf);
155: }
156: free(act);
157: free(parent);
158: free(relative);
159: }
160: if (request->HeaderMask & HT_USER_AGENT) {
161: sprintf(linebuf, "User-Agent: %s/%s libwww/%s%c%c",
162: HTAppName ? HTAppName : "unknown",
163: HTAppVersion ? HTAppVersion : "0.0",
164: HTLibraryVersion, CR, LF);
165: HTChunkPuts(header, linebuf);
166: }
167:
168: /* Now put out entity headers if we are using PUT or POST. If we have a
169: ** PostAnchor then we take the information from this and uses the
170: ** destination anchor to contain the reply. Otherwise, we have created an
171: ** anchor (using internal editing etc) and we can use the destination
172: ** anchor directly.
173: */
174: if (request->method==METHOD_PUT || request->method==METHOD_POST) {
2.2 frystyk 175: if (request->EntityMask & HT_ALLOW) { /* @@@@@@@@@@ */
2.1 frystyk 176:
177: }
178: if (request->EntityMask & HT_CONTENT_ENCODING &&
179: entity->content_encoding) {
180: sprintf(linebuf, "Content-Encoding: %s%c%c",
181: HTAtom_name(entity->content_encoding), CR, LF);
182: HTChunkPuts(header, linebuf);
183: }
2.3 ! frystyk 184: if (request->EntityMask & HT_CONTENT_LANGUAGE) { /* @@@ LIST @@@ */
! 185: sprintf(linebuf, "Content-Language: %s%c%c",
! 186: HTAtom_name(entity->content_language), CR, LF);
! 187: HTChunkPuts(header, linebuf);
2.1 frystyk 188: }
189: if (request->EntityMask & HT_CONTENT_LENGTH) { /* Must be there!!! */
190: sprintf(linebuf, "Content-Length: %ld%c%c",
191: entity->content_length, CR, LF);
192: HTChunkPuts(header, linebuf);
193: }
194: if (request->EntityMask & HT_CTE && entity->cte) {
195: sprintf(linebuf, "Content-Transfer-Encoding: %s%c%c",
196: HTAtom_name(entity->cte), CR, LF);
197: HTChunkPuts(header, linebuf);
198: }
199: if (request->EntityMask & HT_CONTENT_TYPE && entity->content_type) {
2.2 frystyk 200: sprintf(linebuf, "Content-Type: %s",
201: HTAtom_name(entity->content_type));
202: if (entity->charset) {
203: strcat(linebuf, "; charset=");
204: strcat(linebuf, HTAtom_name(entity->charset));
205: }
206: if (entity->level) {
207: strcat(linebuf, "; level=");
208: strcat(linebuf, HTAtom_name(entity->level));
209: }
2.1 frystyk 210: HTChunkPuts(header, linebuf);
2.2 frystyk 211: HTChunkPutc(header, CR);
212: HTChunkPutc(header, LF);
2.1 frystyk 213: }
214: if (request->EntityMask & HT_DERIVED_FROM && entity->derived_from) {
215: sprintf(linebuf, "Derived-From: %s%c%c", entity->derived_from,
216: CR, LF);
217: HTChunkPuts(header, linebuf);
218: }
2.2 frystyk 219: if (request->EntityMask & HT_EXPIRES) { /* @@@@@@@@@@ */
2.1 frystyk 220:
221: }
2.2 frystyk 222: if (request->EntityMask & HT_LAST_MODIFIED) { /* @@@@@@@@@@ */
2.1 frystyk 223:
224: }
2.2 frystyk 225: if (request->EntityMask & HT_LINK) { /* @@@@@@@@@@ */
2.1 frystyk 226:
227: }
2.2 frystyk 228: if (request->EntityMask & HT_TITLE) { /* @@@@@@@@@@ */
2.1 frystyk 229:
230: }
2.2 frystyk 231: if (request->EntityMask & HT_URI) { /* @@@@@@@@@@ */
2.1 frystyk 232:
233: }
234: if (request->EntityMask & HT_VERSION && entity->version) {
235: sprintf(linebuf, "Version: %s%c%c", entity->version, CR, LF);
236: HTChunkPuts(header, linebuf);
237: }
238: }
239:
240: /* Put out extra information if any */
241: if (request->ExtraHeaders)
242: HTChunkPuts(header, request->ExtraHeaders);
243:
244: HTChunkPutc(header, CR); /* Blank line means "end" */
245: HTChunkPutc(header, LF);
246: HTChunkTerminate(header);
247: if (PROT_TRACE)
248: fprintf(TDEST, "HTTP Tx..... %s", header->data);
249: }
250:
251: PRIVATE int HTTPRequest_put_character ARGS2(HTStream *, me, char, c)
252: {
253: if (!me->target)
254: return HT_WOULD_BLOCK;
255: else if (me->transparent)
256: return PUTC(c);
257: else {
258: int status;
259: HTTPMakeRequest(me, me->request); /* Generate header */
260: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
261: me->transparent = YES;
262: return PUTC(c);
263: }
264: return status;
265: }
266: }
267:
268: PRIVATE int HTTPRequest_put_string ARGS2(HTStream *, me, CONST char*, s)
269: {
270: if (!me->target)
271: return HT_WOULD_BLOCK;
272: else if (me->transparent)
273: return PUTS(s);
274: else {
275: int status;
276: HTTPMakeRequest(me, me->request); /* Generate header */
277: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
278: me->transparent = YES;
279: return PUTS(s);
280: }
281: return status;
282: }
283: }
284:
285: PRIVATE int HTTPRequest_put_block ARGS3(HTStream *, me, CONST char*, b, int, l)
286: {
287: if (!me->target)
288: return HT_WOULD_BLOCK;
289: else if (me->transparent)
290: return PUTBLOCK(b, l);
291: else {
292: int status;
293: HTTPMakeRequest(me, me->request); /* Generate header */
294: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
295: me->transparent = YES;
296: return PUTBLOCK(b, l);
297: }
298: return status;
299: }
300: }
301:
302: /*
303: ** Flushes data but doesn't free stream object
304: */
305: PRIVATE int HTTPRequest_flush ARGS1(HTStream *, me)
306: {
307: if (!me->target)
308: return HT_WOULD_BLOCK;
309: else if (!me->transparent) {
310: int status;
311: HTTPMakeRequest(me, me->request); /* Generate header */
312: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK)
313: me->transparent = YES;
314: else
315: return status;
316: }
317: return HT_OK;
318: }
319:
320: /*
321: ** Flushes data and frees stream object
322: */
323: PRIVATE int HTTPRequest_free ARGS1(HTStream *, me)
324: {
325: if (!me->target)
326: return HT_WOULD_BLOCK;
327: else if (!me->transparent) {
328: int status;
329: HTTPMakeRequest(me, me->request); /* Generate header */
330: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK)
331: me->transparent = YES;
332: else
333: return status;
334: }
335: if (me->target)
336: FREE_TARGET;
337: HTChunkFree(me->buffer);
338: free(me);
339: return HT_OK;
340: }
341:
342: PRIVATE int HTTPRequest_abort ARGS2(HTStream *, me, HTError, e)
343: {
344: if (me->target)
345: ABORT_TARGET;
346: FREE(me->url);
347: HTChunkFree(me->buffer);
348: free(me);
349: if (PROT_TRACE)
350: fprintf(TDEST, "HTTPRequest. ABORTING...\n");
351: return HT_ERROR;
352: }
353:
354: /* HTTPRequest Stream
355: ** -----------------
356: */
357: PRIVATE CONST HTStreamClass HTTPRequestClass =
358: {
359: "HTTPRequest",
360: HTTPRequest_flush,
361: HTTPRequest_free,
362: HTTPRequest_abort,
363: HTTPRequest_put_character,
364: HTTPRequest_put_string,
365: HTTPRequest_put_block
366: };
367:
368: PUBLIC HTStream * HTTPRequest_new ARGS2(HTRequest *, request,
369: HTStream *, target)
370: {
371: HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
372: if (!me) outofmem(__FILE__, "HTTPRequest_new");
373: me->isa = &HTTPRequestClass;
374: me->target = target;
375: me->url = HTAnchor_physical(request->anchor);
376: me->request = request;
377: me->buffer = HTChunkCreate(512);
378: me->transparent = NO;
379: return me;
380: }
381:
382:
Webmaster