Annotation of libwww/Library/src/HTTPReq.c, revision 2.6
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"
2.4 frystyk 17: #include "HTFormat.h"
2.1 frystyk 18: #include "HTThread.h"
19: #include "HTTCP.h"
20: #include "HTWriter.h"
21: #include "HTChunk.h"
22: #include "HTTPReq.h" /* Implements */
23:
24: /* Type definitions and global variables etc. local to this module */
25: extern char * HTAppName; /* Application name: please supply */
26: extern char * HTAppVersion; /* Application version: please supply */
27: PUBLIC char * HTProxyHeaders = NULL; /* Headers to pass as-is */
28:
29: /* Macros and other defines */
30: #define HTTP_VERSION "HTTP/1.0"
31: #define MIME_VERSION "MIME/1.0"
32: #define PUTC(c) (*me->target->isa->put_character)(me->target, c)
33: #define PUTS(s) (*me->target->isa->put_string)(me->target, s)
34: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
35: #define FREE_TARGET (*me->target->isa->_free)(me->target)
36: #define ABORT_TARGET (*me->target->isa->abort)(me->target, e)
37:
38: /* Type definitions and global variables etc. local to this module */
39:
40: PRIVATE char linebuf[256]; /* @@@ */
41:
42: struct _HTStream {
43: CONST HTStreamClass * isa;
44: HTStream * target;
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: {
2.6 ! frystyk 74: char *addr = HTAnchor_physical(request->anchor);
! 75: char *fullurl = HTParse(addr, "", PARSE_PATH|PARSE_PUNCTUATION);
2.1 frystyk 76: if (request->using_proxy) {
77: HTChunkPuts(header, fullurl+1);
78: } else {
79: HTChunkPuts(header, fullurl);
80: }
81: free(fullurl);
82: }
83: HTChunkPutc(header, ' ');
84: HTChunkPuts(header, HTTP_VERSION);
85: HTChunkPutc(header, CR);
86: HTChunkPutc(header, LF);
87:
2.4 frystyk 88: /* General Headers */
89: if (request->GenMask & HT_DATE) {
2.1 frystyk 90: time_t local = time(NULL);
91: sprintf(linebuf, "Date: %s%c%c", HTDateTimeStr(&local, NO), CR,LF);
92: HTChunkPuts(header, linebuf);
93: }
2.4 frystyk 94: if (request->GenMask & HT_FORWARDED) { /* @@@@@@ */
95: }
96: if (request->GenMask & HT_MESSAGE_ID) {
2.1 frystyk 97: CONST char *msgid = HTMessageIdStr();
98: if (msgid) {
99: sprintf(linebuf, "Message-ID: %s%c%c", msgid, CR, LF);
100: HTChunkPuts(header, linebuf);
101: }
102: }
2.4 frystyk 103: if (request->GenMask & HT_MIME) {
2.1 frystyk 104: sprintf(linebuf, "MIME-Version: %s%c%c", MIME_VERSION, CR, LF);
105: HTChunkPuts(header, linebuf);
106: }
107:
2.4 frystyk 108: /* Request Headers */
109: if (request->RequestMask & HT_ACCEPT_TYPE) {
2.1 frystyk 110: int list;
111: HTList *cur;
112: for (list=0; list<2; list++) {
113: if ((!list && ((cur=HTConversions) != NULL)) ||
114: (list && ((cur=request->conversions) != NULL))) {
2.4 frystyk 115: HTPresentation *pres;
2.1 frystyk 116: while ((pres =(HTPresentation *) HTList_nextObject(cur))) {
117: if (pres->rep_out == WWW_PRESENT) {
118: if (pres->quality != 1.0) {
119: sprintf(linebuf, "Accept: %s; q=%1.1f%c%c",
120: HTAtom_name(pres->rep),
121: pres->quality, CR, LF);
122: } else {
123: sprintf(linebuf, "Accept: %s%c%c",
124: HTAtom_name(pres->rep), CR, LF);
125: }
126: HTChunkPuts(header, linebuf);
127: }
128: }
129: }
130: }
131: }
2.4 frystyk 132: if (request->RequestMask & HT_ACCEPT_CHAR) {
133: BOOL first=YES;
134: int list;
135: HTList *cur;
136: for (list=0; list<2; list++) {
137: if ((!list && ((cur=HTCharsets) != NULL)) ||
138: (list && ((cur=request->charsets) != NULL))) {
139: HTAcceptNode *pres;
140: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 141: if (first) {
142: HTChunkPuts(header, "Accept-Charset: ");
143: first=NO;
144: }
2.4 frystyk 145: if (cur->next)
146: sprintf(linebuf, "%s,", HTAtom_name(pres->atom));
147: else
148: sprintf(linebuf, "%s%c%c", HTAtom_name(pres->atom),
149: CR, LF);
150: HTChunkPuts(header, linebuf);
151: }
152: }
153: }
154: }
155: if (request->RequestMask & HT_ACCEPT_ENC) {
156: BOOL first=YES;
157: int list;
158: HTList *cur;
159: for (list=0; list<2; list++) {
160: if ((!list && ((cur=HTEncodings) != NULL)) ||
161: (list && ((cur=request->encodings) != NULL))) {
162: HTAcceptNode *pres;
163: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 164: if (first) {
165: HTChunkPuts(header, "Accept-Encoding: ");
166: first=NO;
167: }
2.4 frystyk 168: if (cur->next)
169: sprintf(linebuf, "%s,", HTAtom_name(pres->atom));
170: else
171: sprintf(linebuf, "%s%c%c", HTAtom_name(pres->atom),
172: CR, LF);
173: HTChunkPuts(header, linebuf);
174: }
175: }
176: }
177: }
178: if (request->RequestMask & HT_ACCEPT_LAN) {
179: BOOL first=YES;
180: int list;
181: HTList *cur;
182: for (list=0; list<2; list++) {
183: if ((!list && ((cur=HTLanguages) != NULL)) ||
184: (list && ((cur=request->languages) != NULL))) {
185: HTAcceptNode *pres;
186: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 187: if (first) {
188: HTChunkPuts(header, "Accept-Language: ");
189: first=NO;
190: }
2.4 frystyk 191: if (cur->next)
192: sprintf(linebuf, "%s,", HTAtom_name(pres->atom));
193: else
194: sprintf(linebuf, "%s%c%c", HTAtom_name(pres->atom),
195: CR, LF);
196: HTChunkPuts(header, linebuf);
197: }
198: }
199: }
200: }
201: if (request->authorization != NULL) { /* Put out authorization */
2.1 frystyk 202: sprintf(linebuf, "Authorization: %s%c%c", request->authorization,
203: CR, LF);
204: HTChunkPuts(header, linebuf);
205: }
2.4 frystyk 206: if (request->RequestMask & HT_FROM) {
2.1 frystyk 207: CONST char *mailaddress = HTGetMailAddress();
208: if (mailaddress) {
209: sprintf(linebuf, "From: %s%c%c", mailaddress, CR, LF);
210: HTChunkPuts(header, linebuf);
211: }
212: }
2.4 frystyk 213: if (request->RequestMask & HT_PRAGMA) {
2.1 frystyk 214: sprintf(linebuf, "Pragma: %s%c%c", "no-cache", CR, LF);
215: HTChunkPuts(header, linebuf);
216: }
2.4 frystyk 217: if (request->RequestMask & HT_REFERER && request->parentAnchor) {
2.1 frystyk 218: char *act = HTAnchor_address((HTAnchor *) request->anchor);
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: }
237:
238: /* Now put out entity headers if we are using PUT or POST. If we have a
239: ** PostAnchor then we take the information from this and uses the
240: ** destination anchor to contain the reply. Otherwise, we have created an
241: ** anchor (using internal editing etc) and we can use the destination
242: ** anchor directly.
243: */
244: if (request->method==METHOD_PUT || request->method==METHOD_POST) {
2.2 frystyk 245: if (request->EntityMask & HT_ALLOW) { /* @@@@@@@@@@ */
2.1 frystyk 246:
247: }
248: if (request->EntityMask & HT_CONTENT_ENCODING &&
249: entity->content_encoding) {
250: sprintf(linebuf, "Content-Encoding: %s%c%c",
251: HTAtom_name(entity->content_encoding), CR, LF);
252: HTChunkPuts(header, linebuf);
253: }
2.6 ! frystyk 254:
! 255: /* @@@ SHOULD BE A LIST @@@ */
! 256: if (request->EntityMask & HT_CONTENT_LANGUAGE &&
! 257: entity->content_language) {
2.3 frystyk 258: sprintf(linebuf, "Content-Language: %s%c%c",
259: HTAtom_name(entity->content_language), CR, LF);
260: HTChunkPuts(header, linebuf);
2.1 frystyk 261: }
262: if (request->EntityMask & HT_CONTENT_LENGTH) { /* Must be there!!! */
263: sprintf(linebuf, "Content-Length: %ld%c%c",
264: entity->content_length, CR, LF);
265: HTChunkPuts(header, linebuf);
266: }
267: if (request->EntityMask & HT_CTE && entity->cte) {
268: sprintf(linebuf, "Content-Transfer-Encoding: %s%c%c",
269: HTAtom_name(entity->cte), CR, LF);
270: HTChunkPuts(header, linebuf);
271: }
272: if (request->EntityMask & HT_CONTENT_TYPE && entity->content_type) {
2.2 frystyk 273: sprintf(linebuf, "Content-Type: %s",
274: HTAtom_name(entity->content_type));
275: if (entity->charset) {
276: strcat(linebuf, "; charset=");
277: strcat(linebuf, HTAtom_name(entity->charset));
278: }
279: if (entity->level) {
280: strcat(linebuf, "; level=");
281: strcat(linebuf, HTAtom_name(entity->level));
282: }
2.1 frystyk 283: HTChunkPuts(header, linebuf);
2.2 frystyk 284: HTChunkPutc(header, CR);
285: HTChunkPutc(header, LF);
2.1 frystyk 286: }
287: if (request->EntityMask & HT_DERIVED_FROM && entity->derived_from) {
288: sprintf(linebuf, "Derived-From: %s%c%c", entity->derived_from,
289: CR, LF);
290: HTChunkPuts(header, linebuf);
291: }
2.2 frystyk 292: if (request->EntityMask & HT_EXPIRES) { /* @@@@@@@@@@ */
2.1 frystyk 293:
294: }
2.2 frystyk 295: if (request->EntityMask & HT_LAST_MODIFIED) { /* @@@@@@@@@@ */
2.1 frystyk 296:
297: }
2.2 frystyk 298: if (request->EntityMask & HT_LINK) { /* @@@@@@@@@@ */
2.1 frystyk 299:
300: }
2.2 frystyk 301: if (request->EntityMask & HT_TITLE) { /* @@@@@@@@@@ */
2.1 frystyk 302:
303: }
2.2 frystyk 304: if (request->EntityMask & HT_URI) { /* @@@@@@@@@@ */
2.1 frystyk 305:
306: }
307: if (request->EntityMask & HT_VERSION && entity->version) {
308: sprintf(linebuf, "Version: %s%c%c", entity->version, CR, LF);
309: HTChunkPuts(header, linebuf);
310: }
311: }
312:
313: /* Put out extra information if any */
314: if (request->ExtraHeaders)
315: HTChunkPuts(header, request->ExtraHeaders);
316:
317: HTChunkPutc(header, CR); /* Blank line means "end" */
318: HTChunkPutc(header, LF);
319: HTChunkTerminate(header);
320: if (PROT_TRACE)
321: fprintf(TDEST, "HTTP Tx..... %s", header->data);
322: }
323:
324: PRIVATE int HTTPRequest_put_character ARGS2(HTStream *, me, char, c)
325: {
326: if (!me->target)
327: return HT_WOULD_BLOCK;
328: else if (me->transparent)
329: return PUTC(c);
330: else {
331: int status;
332: HTTPMakeRequest(me, me->request); /* Generate header */
333: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
334: me->transparent = YES;
335: return PUTC(c);
336: }
337: return status;
338: }
339: }
340:
341: PRIVATE int HTTPRequest_put_string ARGS2(HTStream *, me, CONST char*, s)
342: {
343: if (!me->target)
344: return HT_WOULD_BLOCK;
345: else if (me->transparent)
346: return PUTS(s);
347: else {
348: int status;
349: HTTPMakeRequest(me, me->request); /* Generate header */
350: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
351: me->transparent = YES;
352: return PUTS(s);
353: }
354: return status;
355: }
356: }
357:
358: PRIVATE int HTTPRequest_put_block ARGS3(HTStream *, me, CONST char*, b, int, l)
359: {
360: if (!me->target)
361: return HT_WOULD_BLOCK;
362: else if (me->transparent)
363: return PUTBLOCK(b, l);
364: else {
365: int status;
366: HTTPMakeRequest(me, me->request); /* Generate header */
367: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
368: me->transparent = YES;
369: return PUTBLOCK(b, l);
370: }
371: return status;
372: }
373: }
374:
375: /*
376: ** Flushes data but doesn't free stream object
377: */
378: PRIVATE int HTTPRequest_flush ARGS1(HTStream *, me)
379: {
380: if (!me->target)
381: return HT_WOULD_BLOCK;
382: else if (!me->transparent) {
383: int status;
384: HTTPMakeRequest(me, me->request); /* Generate header */
385: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK)
386: me->transparent = YES;
387: else
388: return status;
389: }
390: return HT_OK;
391: }
392:
393: /*
394: ** Flushes data and frees stream object
395: */
396: PRIVATE int HTTPRequest_free ARGS1(HTStream *, me)
397: {
398: if (!me->target)
399: return HT_WOULD_BLOCK;
2.6 ! frystyk 400: if (!me->transparent) {
2.1 frystyk 401: int status;
402: HTTPMakeRequest(me, me->request); /* Generate header */
2.6 ! frystyk 403: if ((status = PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK)
2.1 frystyk 404: me->transparent = YES;
405: else
406: return status;
407: }
2.6 ! frystyk 408: if (FREE_TARGET == HT_WOULD_BLOCK)
! 409: return HT_WOULD_BLOCK;
2.1 frystyk 410: HTChunkFree(me->buffer);
411: free(me);
412: return HT_OK;
413: }
414:
415: PRIVATE int HTTPRequest_abort ARGS2(HTStream *, me, HTError, e)
416: {
417: if (me->target)
418: ABORT_TARGET;
419: HTChunkFree(me->buffer);
420: free(me);
421: if (PROT_TRACE)
422: fprintf(TDEST, "HTTPRequest. ABORTING...\n");
423: return HT_ERROR;
424: }
425:
426: /* HTTPRequest Stream
427: ** -----------------
428: */
429: PRIVATE CONST HTStreamClass HTTPRequestClass =
430: {
431: "HTTPRequest",
432: HTTPRequest_flush,
433: HTTPRequest_free,
434: HTTPRequest_abort,
435: HTTPRequest_put_character,
436: HTTPRequest_put_string,
437: HTTPRequest_put_block
438: };
439:
440: PUBLIC HTStream * HTTPRequest_new ARGS2(HTRequest *, request,
441: HTStream *, target)
442: {
443: HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
444: if (!me) outofmem(__FILE__, "HTTPRequest_new");
445: me->isa = &HTTPRequestClass;
446: me->target = target;
447: me->request = request;
448: me->buffer = HTChunkCreate(512);
449: me->transparent = NO;
450: return me;
451: }
452:
453:
Webmaster