Annotation of libwww/Library/src/HTMIMERq.c, revision 2.40
2.1 frystyk 1: /* HTMIMERq.c
2.10 frystyk 2: ** MIME ENTITY HEADERS GENERATION
2.1 frystyk 3: **
2.15 frystyk 4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
2.40 ! frystyk 6: ** @(#) $Id: HTMIMERq.c,v 2.39 1998/07/22 19:18:58 frystyk Exp $
2.15 frystyk 7: **
2.1 frystyk 8: ** This module implements the output stream for MIME used for sending
2.10 frystyk 9: ** requests with a entity body to HTTP, NEWS, etc. or for generating
10: ** responses
2.1 frystyk 11: **
12: ** History:
13: ** Jan 95 HFN Written
14: */
15:
16: /* Library Includes */
2.36 frystyk 17: #include "wwwsys.h"
2.21 frystyk 18: #include "WWWUtil.h"
19: #include "WWWCore.h"
2.7 frystyk 20: #include "HTAncMan.h"
2.1 frystyk 21: #include "HTNetMan.h"
2.21 frystyk 22: #include "HTReqMan.h"
2.2 frystyk 23: #include "HTHeader.h"
2.21 frystyk 24: #include "HTMIMERq.h" /* Implements */
2.1 frystyk 25:
2.17 frystyk 26: #define PUTC(c) (*me->target->isa->put_character)(me->target, c)
27: #define PUTS(s) (*me->target->isa->put_string)(me->target, s)
2.1 frystyk 28: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
29:
30: struct _HTStream {
2.14 frystyk 31: const HTStreamClass * isa;
2.1 frystyk 32: HTStream * target;
33: HTRequest * request;
2.10 frystyk 34: BOOL endHeader;
2.1 frystyk 35: BOOL transparent;
36: };
37:
2.27 frystyk 38: #define HT_MAX_WAIT 8 /* Max number of secs to wait for PUT */
2.25 frystyk 39:
2.32 frystyk 40: PRIVATE int MIMERequest_put_block (HTStream * me, const char * b, int l);
41:
2.1 frystyk 42: /* ------------------------------------------------------------------------- */
43: /* MIME Output Request Stream */
44: /* ------------------------------------------------------------------------- */
45:
46: /* MIMEMakeRequest
47: ** ---------------
2.10 frystyk 48: ** Generates the BODY parts of a MIME message.
2.1 frystyk 49: */
2.2 frystyk 50: PRIVATE int MIMEMakeRequest (HTStream * me, HTRequest * request)
2.1 frystyk 51: {
2.17 frystyk 52: char crlf[3];
2.10 frystyk 53: char linebuf[256]; /* @@@ */
2.21 frystyk 54: HTParentAnchor * entity = HTRequest_entityAnchor(request);
55: HTEnHd EntityMask = HTRequest_enHd(request);
2.34 frystyk 56: BOOL transfer_coding = NO; /* We should get this from the Host object */
2.17 frystyk 57: *crlf = CR; *(crlf+1) = LF; *(crlf+2) = '\0';
2.1 frystyk 58:
2.21 frystyk 59: if (EntityMask & HT_E_ALLOW) {
2.34 frystyk 60: BOOL first = YES;
61: int cnt;
62: HTMethod methodset = HTAnchor_allow(entity);
63: for (cnt=0; cnt<sizeof(HTMethod)<<3 ; cnt++) {
64: if (methodset & (1<<cnt)) {
65: if (first) {
66: PUTS("Allow: ");
67: first = NO;
68: } else
69: PUTC(',');
70: PUTS(HTMethod_name(1<<cnt));
71: }
72: }
73: if (!first) PUTBLOCK(crlf, 2);
2.10 frystyk 74: }
2.35 frystyk 75: if (EntityMask & HT_E_CONTENT_ENCODING && entity->content_encoding) {
2.17 frystyk 76: BOOL first = YES;
77: HTList * cur = entity->content_encoding;
78: HTEncoding pres;
2.35 frystyk 79: while ((pres = (HTEncoding) HTList_nextObject(cur)) &&
80: !HTFormat_isUnityContent(pres)) {
2.17 frystyk 81: if (first) {
82: PUTS("Content-Encoding: ");
83: first = NO;
84: } else
85: PUTC(',');
86: PUTS(HTAtom_name(pres));
87: }
88: if (!first) PUTBLOCK(crlf, 2);
2.1 frystyk 89: }
2.34 frystyk 90: if (EntityMask & HT_E_CTE && entity->cte) {
91: HTEncoding cte = HTAnchor_contentTransferEncoding(entity);
92: if (!HTFormat_isUnityTransfer(cte)) {
93: sprintf(linebuf, "Content-Transfer-Encoding: %s%c%c",
94: HTAtom_name(cte), CR, LF);
95: PUTBLOCK(linebuf, (int) strlen(linebuf));
96: }
97: }
2.21 frystyk 98: if (EntityMask & HT_E_CONTENT_LANGUAGE && entity->content_language){
2.17 frystyk 99: BOOL first = YES;
100: HTList * cur = entity->content_language;
101: HTLanguage pres;
102: while ((pres = (HTLanguage) HTList_nextObject(cur))) {
103: if (first) {
104: PUTS("Content-Language: ");
105: first = NO;
106: } else
107: PUTC(',');
108: PUTS(HTAtom_name(pres));
109: }
110: if (!first) PUTBLOCK(crlf, 2);
2.1 frystyk 111: }
2.34 frystyk 112:
113: /* Only send out Content-Length if we don't have a transfer coding */
114: if (!HTRequest_transfer(request)) {
115: if (EntityMask & HT_E_CONTENT_LENGTH) {
116: if (entity->content_length >= 0) {
117: sprintf(linebuf, "Content-Length: %ld%c%c",
118: entity->content_length, CR, LF);
119: PUTBLOCK(linebuf, (int) strlen(linebuf));
120: } else {
121: transfer_coding = YES;
2.40 ! frystyk 122: sprintf(linebuf, "Transfer-Encoding: %s%c%c",
! 123: HTAtom_name(WWW_CODING_CHUNKED), CR, LF);
! 124: PUTBLOCK(linebuf, (int) strlen(linebuf));
2.34 frystyk 125: }
2.20 frystyk 126: }
2.1 frystyk 127: }
2.33 frystyk 128: if (EntityMask & HT_E_CONTENT_TYPE && entity->content_type) {
129: HTFormat format = entity->content_type != WWW_UNKNOWN ?
130: entity->content_type : WWW_BINARY;
2.19 frystyk 131: HTAssocList * parameters = HTAnchor_formatParam(entity);
132:
133: /* Output the content type */
134: PUTS("Content-Type: ");
2.33 frystyk 135: PUTS(HTAtom_name(format));
2.19 frystyk 136:
137: /* Add all parameters */
138: if (parameters) {
139: HTAssoc * pres;
140: while ((pres = (HTAssoc *) HTAssocList_nextObject(parameters))) {
141: PUTS(";");
142: PUTS(HTAssoc_name(pres));
143: PUTS("=");
144: PUTS(HTAssoc_value(pres));
145: }
146: }
147: PUTBLOCK(crlf, 2);
2.10 frystyk 148: }
2.21 frystyk 149: if (EntityMask & HT_E_DERIVED_FROM && entity->derived_from) {
2.10 frystyk 150: sprintf(linebuf, "Derived-From: %s%c%c", entity->derived_from,
151: CR, LF);
2.2 frystyk 152: PUTBLOCK(linebuf, (int) strlen(linebuf));
2.1 frystyk 153: }
2.21 frystyk 154: if (EntityMask & HT_E_EXPIRES) {
2.10 frystyk 155: if (entity->expires != -1) {
156: sprintf(linebuf, "Expires: %s%c%c",
157: HTDateTimeStr(&entity->expires, NO), CR,LF);
2.2 frystyk 158: PUTBLOCK(linebuf, (int) strlen(linebuf));
2.1 frystyk 159: }
2.10 frystyk 160: }
2.21 frystyk 161: if (EntityMask & HT_E_LAST_MODIFIED) {
2.10 frystyk 162: if (entity->last_modified != -1) {
163: sprintf(linebuf, "Last-Modified: %s%c%c",
164: HTDateTimeStr(&entity->last_modified, NO), CR,LF);
2.2 frystyk 165: PUTBLOCK(linebuf, (int) strlen(linebuf));
2.1 frystyk 166: }
2.10 frystyk 167: }
2.37 frystyk 168: if (EntityMask & HT_E_LINK) {
169: HTLink * link = HTAnchor_mainLink((HTAnchor *) entity);
170: HTList * sublinks = HTAnchor_subLinks((HTAnchor *) entity);
171: HTLinkType linktype = NULL;
172:
173: /* First look in the main link */
174: if (link && (linktype = HTLink_type(link))) {
2.38 frystyk 175: char * src = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
2.37 frystyk 176: HTParentAnchor * dest = HTAnchor_parent(HTLink_destination(link));
177: char * dst = HTAnchor_address((HTAnchor *) dest);
2.38 frystyk 178: char * rel_dst = HTRelative(dst, src);
2.37 frystyk 179: if (rel_dst) {
2.38 frystyk 180: PUTS("Link: \"");
2.37 frystyk 181: PUTS(rel_dst);
2.38 frystyk 182: PUTS("\"");
2.37 frystyk 183: sprintf(linebuf, ";rel=\"%s\"", HTAtom_name(linktype));
184: PUTBLOCK(linebuf, (int) strlen(linebuf));
185: HT_FREE(rel_dst);
186: HT_FREE(dst);
187: }
2.1 frystyk 188:
2.37 frystyk 189: /* ... and then in any sublinks */
190: if (sublinks) {
191: HTLink * pres;
192: while ((pres = (HTLink *) HTList_nextObject(sublinks))) {
193: if ((linktype = HTLink_type(pres))) {
194: dest = HTAnchor_parent(HTLink_destination(pres));
195: dst = HTAnchor_address((HTAnchor *) dest);
2.38 frystyk 196: rel_dst = HTRelative(dst, src);
2.37 frystyk 197: if (rel_dst) {
2.38 frystyk 198: PUTS(", \"");
2.37 frystyk 199: PUTS(rel_dst);
2.38 frystyk 200: PUTS("\"");
2.37 frystyk 201: sprintf(linebuf, ";rel=\"%s\"", HTAtom_name(linktype));
202: PUTBLOCK(linebuf, (int) strlen(linebuf));
203: HT_FREE(rel_dst);
204: HT_FREE(dst);
205: }
206: }
207: }
208: }
209: PUTBLOCK(crlf, 2);
210: HT_FREE(src);
211: }
2.10 frystyk 212: }
2.37 frystyk 213: if (EntityMask & HT_E_TITLE && entity->title) {
214: sprintf(linebuf, "Title: %s%c%c", entity->title, CR, LF);
215: PUTBLOCK(linebuf, (int) strlen(linebuf));
2.10 frystyk 216: }
2.21 frystyk 217: if (EntityMask & HT_E_URI) { /* @@@@@@@@@@ */
2.1 frystyk 218:
219: }
2.21 frystyk 220: if (EntityMask & HT_E_VERSION && entity->version) {
2.37 frystyk 221: sprintf(linebuf, "Content-Version: %s%c%c", entity->version, CR, LF);
2.10 frystyk 222: PUTBLOCK(linebuf, (int) strlen(linebuf));
223: }
224: if (me->endHeader) {
225: sprintf(linebuf, "%c%c", CR, LF); /* Blank line means "end" */
226: PUTBLOCK(linebuf, (int) strlen(linebuf));
2.2 frystyk 227: }
2.20 frystyk 228:
229: /*
2.34 frystyk 230: ** Handle any Transfer encoding. This is really a transport issue but
231: ** as it often pops up when we are sending an entity then we put it
232: ** here for now. A better place whould be in the HTTPGen stream.
233: ** the real problem is that the server doesn't have any mechanism of
234: ** telling the client what transports it can handle. The best we can
235: ** hope for is that the server understands "chunked" although we are
236: ** certainly capable of handling nested encodings :(
237: */
238: if (transfer_coding) {
239: HTStream * target = HTTransferCodingStack(WWW_CODING_CHUNKED,
240: me->target, request, NULL, NO);
241: if (STREAM_TRACE) HTTrace("Building.... Transfer-Encoding stack\n");
242: if (target == HTBlackHole()) {
243: if (me->target) (*me->target->isa->abort)(me->target, NULL);
244: me->target = HTErrorStream();
245: } else
246: me->target = target;
247: }
248:
249: #if 0
250: /*
251: ** We expect the anchor object already to have the right encoding and
252: ** we therefore should not set up extra streams for doing this.
2.20 frystyk 253: */
254:
2.34 frystyk 255: /* Handle any Content Transfer encoding */
2.20 frystyk 256: {
2.34 frystyk 257: HTEncoding cte = HTAnchor_contentTransferEncoding(entity);
258: if (!HTFormat_isUnityTransfer(cte)) {
2.20 frystyk 259: if (STREAM_TRACE) HTTrace("Building.... C-T-E stack\n");
2.34 frystyk 260: me->target = HTContentTransferCodingStack(cte, me->target,
261: request, NULL, YES);
2.20 frystyk 262: }
263: }
264:
2.34 frystyk 265: /* Handle any Content Encodings */
2.20 frystyk 266: {
267: HTList * cc = HTAnchor_encoding(entity);
268: if (cc) {
269: if (STREAM_TRACE) HTTrace("Building.... C-E stack\n");
2.33 frystyk 270: me->target = HTContentEncodingStack(cc, me->target, request, NULL);
2.20 frystyk 271: }
272: }
2.34 frystyk 273: #endif
2.20 frystyk 274:
2.13 eric 275: if (PROT_TRACE) HTTrace("MIME........ Generating Entity Headers\n");
2.2 frystyk 276: return HT_OK;
2.1 frystyk 277: }
278:
2.32 frystyk 279: /*
280: ** Flushes header but doesn't free stream object
281: */
282: PRIVATE int MIMERequest_flush (HTStream * me)
283: {
284: int status = MIMERequest_put_block(me, NULL, 0);
285: return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
286: }
287:
2.14 frystyk 288: PRIVATE int MIMERequest_put_block (HTStream * me, const char * b, int l)
2.1 frystyk 289: {
2.23 frystyk 290: HTNet * net = HTRequest_net(me->request);
2.32 frystyk 291: if (!me->transparent) {
2.1 frystyk 292: MIMEMakeRequest(me, me->request);
2.9 frystyk 293: me->transparent = YES;
2.22 frystyk 294:
295: /*
2.32 frystyk 296: ** First we only send the header
2.22 frystyk 297: */
298: if (HTMethod_hasEntity(HTRequest_method(me->request))) {
299: HTHost * host = HTNet_host(net);
300: char * class = HTHost_class(host);
2.23 frystyk 301: if (class && !strcmp(class, "http")) {
2.32 frystyk 302: MIMERequest_flush(me);
2.39 frystyk 303: HTNet_setHeaderBytesWritten(net, HTNet_bytesWritten(net));
2.32 frystyk 304: return HT_PAUSE;
2.22 frystyk 305: }
306: }
2.1 frystyk 307: }
2.32 frystyk 308:
2.23 frystyk 309: /* Check if we have written it all */
310: if (b) {
311: HTParentAnchor * entity = HTRequest_entityAnchor(me->request);
312: long cl = HTAnchor_length(entity);
2.39 frystyk 313: return (cl>=0 && HTNet_bytesWritten(net)-HTNet_headerBytesWritten(net) >= cl) ?
2.23 frystyk 314: HT_LOADED : PUTBLOCK(b, l);
315: }
316: return HT_OK;
2.1 frystyk 317: }
318:
319: PRIVATE int MIMERequest_put_character (HTStream * me, char c)
320: {
321: return MIMERequest_put_block(me, &c, 1);
322: }
323:
2.14 frystyk 324: PRIVATE int MIMERequest_put_string (HTStream * me, const char * s)
2.1 frystyk 325: {
326: return MIMERequest_put_block(me, s, strlen(s));
327: }
328:
329: /*
330: ** Flushes data and frees stream object
331: */
332: PRIVATE int MIMERequest_free (HTStream * me)
333: {
334: int status = MIMERequest_flush(me);
335: if (status != HT_WOULD_BLOCK) {
336: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
337: return HT_WOULD_BLOCK;
2.12 frystyk 338: HT_FREE(me);
2.1 frystyk 339: }
340: return status;
341: }
342:
2.4 frystyk 343: PRIVATE int MIMERequest_abort (HTStream * me, HTList * e)
2.1 frystyk 344: {
345: if (me->target) (*me->target->isa->abort)(me->target, e);
2.12 frystyk 346: HT_FREE(me);
2.13 eric 347: if (PROT_TRACE) HTTrace("MIMERequest. ABORTING...\n");
2.1 frystyk 348: return HT_ERROR;
349: }
350:
351: /* MIMERequest Stream
352: ** -----------------
353: */
2.14 frystyk 354: PRIVATE const HTStreamClass MIMERequestClass =
2.1 frystyk 355: {
356: "MIMERequest",
357: MIMERequest_flush,
358: MIMERequest_free,
359: MIMERequest_abort,
360: MIMERequest_put_character,
361: MIMERequest_put_string,
362: MIMERequest_put_block
363: };
364:
2.10 frystyk 365: PUBLIC HTStream * HTMIMERequest_new (HTRequest * request, HTStream * target,
366: BOOL endHeader)
2.1 frystyk 367: {
2.12 frystyk 368: HTStream * me;
369: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
370: HT_OUTOFMEM("HTMIMERequest_new");
2.1 frystyk 371: me->isa = &MIMERequestClass;
372: me->target = target;
373: me->request = request;
2.10 frystyk 374: me->endHeader = endHeader;
2.1 frystyk 375: me->transparent = NO;
376: return me;
377: }
Webmaster