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