Annotation of libwww/Library/src/HTTPGen.c, revision 2.17
2.1 frystyk 1: /* HTTPGen.c
2: ** HTTP GENERAL HEADER GENERATION
3: **
2.5 frystyk 4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
2.17 ! frystyk 6: ** @(#) $Id: HTTPGen.c,v 2.16 1999/02/22 22:10:12 frystyk Exp $
2.5 frystyk 7: **
2.1 frystyk 8: ** This module implements the output stream for General HTTP headers
9: **
10: ** History:
11: ** Jan 96 HFN Written
12: */
13:
14: /* Library Includes */
2.13 frystyk 15: #include "wwwsys.h"
2.8 frystyk 16: #include "WWWUtil.h"
17: #include "WWWCore.h"
2.15 frystyk 18: #include "HTHeader.h"
2.10 frystyk 19: #include "HTTPUtil.h"
2.1 frystyk 20: #include "HTTPReq.h" /* Implements */
21:
22: #define MIME_VERSION "MIME/1.0"
2.8 frystyk 23:
24: #define PUTC(c) (*me->target->isa->put_character)(me->target, c)
25: #define PUTS(s) (*me->target->isa->put_string)(me->target, s)
2.1 frystyk 26: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
27:
28: struct _HTStream {
2.4 frystyk 29: const HTStreamClass * isa;
2.1 frystyk 30: HTStream * target;
31: HTRequest * request;
2.10 frystyk 32: int version;
2.1 frystyk 33: BOOL endHeader;
34: BOOL transparent;
35: };
36:
37: /* ------------------------------------------------------------------------- */
38: /* HTTP General Header Stream */
39: /* ------------------------------------------------------------------------- */
40:
41: /* HTTPGenMake
42: ** ------------
43: ** Makes a MIME/1.0 request header.
44: */
45: PRIVATE int HTTPGenMake (HTStream * me, HTRequest * request)
46: {
2.8 frystyk 47: char linebuf[256]; /* @@@ */
48: char crlf[3];
49: HTGnHd gen_mask = HTRequest_gnHd(request);
50: *crlf = CR; *(crlf+1) = LF; *(crlf+2) = '\0';
51: if (gen_mask & HT_G_CC) { /* Cache control */
52: HTAssocList * cur = HTRequest_cacheControl(request);
53: if (cur) {
54: BOOL first=YES;
55: HTAssoc * pres;
56: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
57: char * value = HTAssoc_value(pres);
58: if (first) {
59: PUTS("Cache-Control: ");
60: first = NO;
61: } else
62: PUTC(',');
63:
64: /* Output the name */
65: PUTS(HTAssoc_name(pres));
66:
67: /* Only output the value if not empty string */
68: if (*value) {
69: PUTS("=");
70: PUTS(value);
71: }
72: }
73: PUTBLOCK(crlf, 2);
74: }
75: }
76: if (gen_mask & HT_G_CONNECTION) {
2.10 frystyk 77: HTAssocList * cur = HTRequest_connection(request);
2.8 frystyk 78: if (cur) {
79: BOOL first=YES;
80: HTAssoc * pres;
81: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
82: char * value = HTAssoc_value(pres);
83: if (first) {
84: PUTS("Connection: ");
85: first = NO;
86: } else
87: PUTC(',');
88:
89: /* Output the name */
90: PUTS(HTAssoc_name(pres));
91:
92: /* Only output the value if not empty string */
93: if (*value) {
94: PUTS("=");
95: PUTS(value);
96: }
97: }
98: PUTBLOCK(crlf, 2);
99: }
100: }
101: if (gen_mask & HT_G_DATE) {
2.9 frystyk 102: time_t local = HTRequest_date(request);
2.1 frystyk 103: sprintf(linebuf, "Date: %s%c%c", HTDateTimeStr(&local, NO), CR,LF);
104: PUTBLOCK(linebuf, (int) strlen(linebuf));
105: }
2.8 frystyk 106: if (gen_mask & HT_G_FORWARDED) {
2.1 frystyk 107: /* @@@@@@ */
108: }
2.8 frystyk 109: if (gen_mask & HT_G_PRAGMA_NO_CACHE) {
110: sprintf(linebuf, "Pragma: %s%c%c", "no-cache", CR, LF);
111: PUTBLOCK(linebuf, (int) strlen(linebuf));
112: }
113: if (gen_mask & HT_G_MESSAGE_ID) {
2.6 frystyk 114: const char *msgid = HTMessageIdStr(HTRequest_userProfile(request));
2.1 frystyk 115: if (msgid) {
116: sprintf(linebuf, "Message-ID: %s%c%c", msgid, CR, LF);
117: PUTBLOCK(linebuf, (int) strlen(linebuf));
118: }
119: }
2.8 frystyk 120: if (gen_mask & HT_G_MIME) {
2.1 frystyk 121: sprintf(linebuf, "MIME-Version: %s%c%c", MIME_VERSION, CR, LF);
122: PUTBLOCK(linebuf, (int) strlen(linebuf));
123: }
124:
2.17 ! frystyk 125: /* Put out any extra association values as headers (if any) */
! 126: if (gen_mask & HT_G_EXTRA_HEADERS) {
! 127: HTAssocList * cur = HTRequest_extraHeader(request);
! 128: if (cur) {
! 129: HTAssoc * pres;
! 130: while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
! 131: char * name = HTAssoc_name(pres);
! 132: char * value = HTAssoc_value(pres);
! 133: if (name && *name) {
! 134: char * ptr = name;
! 135: while (*ptr) {
! 136: if (isspace(*ptr)) *ptr='_';
! 137: ptr++;
! 138: }
! 139: PUTS(name);
! 140: PUTS(": ");
! 141: if (value) {
! 142: ptr = value;
! 143: while (*ptr) {
! 144: if (isspace(*ptr)) *ptr=' ';
! 145: ptr++;
! 146: }
! 147: PUTS(value);
! 148: }
! 149: PUTBLOCK(crlf, 2);
! 150: }
! 151: }
! 152: }
! 153: }
! 154:
! 155: /* Put out extra information based on streams (if any) */
2.1 frystyk 156: {
157: HTList * list;
158: BOOL override;
159: if ((list = HTRequest_generator(request, &override))) {
160: HTList *local = list;
161: HTPostCallback *pres;
2.16 frystyk 162: HTTRACE(STREAM_TRACE, "HTTPGen..... Extra local\n");
2.1 frystyk 163: while ((pres = (HTPostCallback *) HTList_nextObject(local)))
164: (*pres)(request, me->target);
165: } else if (!override && (list = HTHeader_generator())) {
166: HTList *global = list;
167: HTPostCallback *pres;
2.16 frystyk 168: HTTRACE(STREAM_TRACE, "HTTPGen..... Extra global\n");
2.1 frystyk 169: while ((pres = (HTPostCallback *) HTList_nextObject(global)))
170: (*pres)(request, me->target);
171: }
172: }
2.17 ! frystyk 173:
! 174: /* Check to see if we are done */
2.1 frystyk 175: if (me->endHeader) {
176: sprintf(linebuf, "%c%c", CR, LF); /* Blank line means "end" */
177: PUTBLOCK(linebuf, (int) strlen(linebuf));
178: }
2.16 frystyk 179: HTTRACE(PROT_TRACE, "HTTP........ Generating General Headers\n");
2.1 frystyk 180: return HT_OK;
181: }
182:
2.4 frystyk 183: PRIVATE int HTTPGen_put_block (HTStream * me, const char * b, int l)
2.1 frystyk 184: {
185: if (me->transparent)
186: return b ? PUTBLOCK(b, l) : HT_OK;
187: else {
188: HTTPGenMake(me, me->request);
189: me->transparent = YES;
190: return b ? PUTBLOCK(b, l) : HT_OK;
191: }
192: }
193:
194: PRIVATE int HTTPGen_put_character (HTStream * me, char c)
195: {
196: return HTTPGen_put_block(me, &c, 1);
197: }
198:
2.4 frystyk 199: PRIVATE int HTTPGen_put_string (HTStream * me, const char * s)
2.1 frystyk 200: {
201: return HTTPGen_put_block(me, s, strlen(s));
202: }
203:
204: /*
205: ** Flushes header but doesn't free stream object
206: */
207: PRIVATE int HTTPGen_flush (HTStream * me)
208: {
209: int status = HTTPGen_put_block(me, NULL, 0);
210: return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
211: }
212:
213: /*
214: ** Flushes data and frees stream object
215: */
216: PRIVATE int HTTPGen_free (HTStream * me)
217: {
218: int status = HTTPGen_flush(me);
219: if (status != HT_WOULD_BLOCK) {
220: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
221: return HT_WOULD_BLOCK;
2.2 frystyk 222: HT_FREE(me);
2.1 frystyk 223: }
224: return status;
225: }
226:
227: PRIVATE int HTTPGen_abort (HTStream * me, HTList * e)
228: {
2.16 frystyk 229: HTTRACE(PROT_TRACE, "HTTPGen..... ABORTING...\n");
2.12 frystyk 230: if (me) {
231: if (me->target) (*me->target->isa->abort)(me->target, e);
232: HT_FREE(me);
233: }
2.1 frystyk 234: return HT_ERROR;
235: }
236:
237: /* HTTPGen Stream
238: ** -----------------
239: */
2.4 frystyk 240: PRIVATE const HTStreamClass HTTPGenClass =
2.1 frystyk 241: {
242: "HTTPGen",
243: HTTPGen_flush,
244: HTTPGen_free,
245: HTTPGen_abort,
246: HTTPGen_put_character,
247: HTTPGen_put_string,
248: HTTPGen_put_block
249: };
250:
251: PUBLIC HTStream * HTTPGen_new (HTRequest * request, HTStream * target,
2.10 frystyk 252: BOOL endHeader, int version)
2.1 frystyk 253: {
2.2 frystyk 254: HTStream * me;
255: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
256: HT_OUTOFMEM("HTTPGen_new");
2.1 frystyk 257: me->isa = &HTTPGenClass;
258: me->target = target;
259: me->request = request;
260: me->endHeader = endHeader;
261: me->transparent = NO;
2.10 frystyk 262:
263: /*
264: ** For backwards compatibility with HTTP applications that understand
265: ** Connection: Keep-Alive, we send it along. However, we do NOT send
2.14 frystyk 266: ** it to a proxy as it may confuse HTTP/1.0 proxies. Also we do not
267: ** send it if the app has set Connection: close
2.10 frystyk 268: */
269: me->version = version;
2.14 frystyk 270: if (me->version == HTTP_10 && HTRequest_proxy(request) == NULL) {
271: HTAssocList * alist = HTRequest_connection(request);
272: if (!(alist && HTAssocList_findObject(alist, "close")))
273: HTRequest_addConnection(request, "Keep-Alive", "");
274: }
2.11 frystyk 275:
276: /*
277: ** Check for any TE headers that are also hop-by-hop
278: */
279: if (HTFormat_transferCoding() != NULL || HTRequest_transfer(request) != NULL)
280: HTRequest_addConnection(request, "TE", "");
2.10 frystyk 281:
2.1 frystyk 282: return me;
283: }
Webmaster