Annotation of libwww/Library/src/HTMIMERq.c, revision 2.34
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.34 ! frystyk 6: ** @(#) $Id: HTMIMERq.c,v 2.33 1998/03/04 15:46:23 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.14 frystyk 17: #include "sysdep.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.21 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;
79: while ((pres = (HTEncoding) HTList_nextObject(cur))) {
80: if (first) {
81: PUTS("Content-Encoding: ");
82: first = NO;
83: } else
84: PUTC(',');
85: PUTS(HTAtom_name(pres));
86: }
87: if (!first) PUTBLOCK(crlf, 2);
2.1 frystyk 88: }
2.34 ! frystyk 89: if (EntityMask & HT_E_CTE && entity->cte) {
! 90: HTEncoding cte = HTAnchor_contentTransferEncoding(entity);
! 91: if (!HTFormat_isUnityTransfer(cte)) {
! 92: sprintf(linebuf, "Content-Transfer-Encoding: %s%c%c",
! 93: HTAtom_name(cte), CR, LF);
! 94: PUTBLOCK(linebuf, (int) strlen(linebuf));
! 95: }
! 96: }
2.21 frystyk 97: if (EntityMask & HT_E_CONTENT_LANGUAGE && entity->content_language){
2.17 frystyk 98: BOOL first = YES;
99: HTList * cur = entity->content_language;
100: HTLanguage pres;
101: while ((pres = (HTLanguage) HTList_nextObject(cur))) {
102: if (first) {
103: PUTS("Content-Language: ");
104: first = NO;
105: } else
106: PUTC(',');
107: PUTS(HTAtom_name(pres));
108: }
109: if (!first) PUTBLOCK(crlf, 2);
2.1 frystyk 110: }
2.34 ! frystyk 111:
! 112: /* Only send out Content-Length if we don't have a transfer coding */
! 113: if (!HTRequest_transfer(request)) {
! 114: if (EntityMask & HT_E_CONTENT_LENGTH) {
! 115: if (entity->content_length >= 0) {
! 116: sprintf(linebuf, "Content-Length: %ld%c%c",
! 117: entity->content_length, CR, LF);
! 118: PUTBLOCK(linebuf, (int) strlen(linebuf));
! 119: } else {
! 120: transfer_coding = YES;
! 121: }
2.20 frystyk 122: }
2.1 frystyk 123: }
2.33 frystyk 124: if (EntityMask & HT_E_CONTENT_TYPE && entity->content_type) {
125: HTFormat format = entity->content_type != WWW_UNKNOWN ?
126: entity->content_type : WWW_BINARY;
2.19 frystyk 127: HTAssocList * parameters = HTAnchor_formatParam(entity);
128:
129: /* Output the content type */
130: PUTS("Content-Type: ");
2.33 frystyk 131: PUTS(HTAtom_name(format));
2.19 frystyk 132:
133: /* Add all parameters */
134: if (parameters) {
135: HTAssoc * pres;
136: while ((pres = (HTAssoc *) HTAssocList_nextObject(parameters))) {
137: PUTS(";");
138: PUTS(HTAssoc_name(pres));
139: PUTS("=");
140: PUTS(HTAssoc_value(pres));
141: }
142: }
143: PUTBLOCK(crlf, 2);
2.10 frystyk 144: }
2.21 frystyk 145: if (EntityMask & HT_E_DERIVED_FROM && entity->derived_from) {
2.10 frystyk 146: sprintf(linebuf, "Derived-From: %s%c%c", entity->derived_from,
147: CR, LF);
2.2 frystyk 148: PUTBLOCK(linebuf, (int) strlen(linebuf));
2.1 frystyk 149: }
2.21 frystyk 150: if (EntityMask & HT_E_EXPIRES) {
2.10 frystyk 151: if (entity->expires != -1) {
152: sprintf(linebuf, "Expires: %s%c%c",
153: HTDateTimeStr(&entity->expires, NO), CR,LF);
2.2 frystyk 154: PUTBLOCK(linebuf, (int) strlen(linebuf));
2.1 frystyk 155: }
2.10 frystyk 156: }
2.21 frystyk 157: if (EntityMask & HT_E_LAST_MODIFIED) {
2.10 frystyk 158: if (entity->last_modified != -1) {
159: sprintf(linebuf, "Last-Modified: %s%c%c",
160: HTDateTimeStr(&entity->last_modified, NO), CR,LF);
2.2 frystyk 161: PUTBLOCK(linebuf, (int) strlen(linebuf));
2.1 frystyk 162: }
2.10 frystyk 163: }
2.21 frystyk 164: if (EntityMask & HT_E_LINK) { /* @@@@@@@@@@ */
2.1 frystyk 165:
2.10 frystyk 166: }
2.21 frystyk 167: if (EntityMask & HT_E_TITLE) { /* @@@@@@@@@@ */
2.1 frystyk 168:
2.10 frystyk 169: }
2.21 frystyk 170: if (EntityMask & HT_E_URI) { /* @@@@@@@@@@ */
2.1 frystyk 171:
172: }
2.21 frystyk 173: if (EntityMask & HT_E_VERSION && entity->version) {
2.10 frystyk 174: sprintf(linebuf, "Version: %s%c%c", entity->version, CR, LF);
175: PUTBLOCK(linebuf, (int) strlen(linebuf));
176: }
177: if (me->endHeader) {
178: sprintf(linebuf, "%c%c", CR, LF); /* Blank line means "end" */
179: PUTBLOCK(linebuf, (int) strlen(linebuf));
2.2 frystyk 180: }
2.20 frystyk 181:
182: /*
2.34 ! frystyk 183: ** Handle any Transfer encoding. This is really a transport issue but
! 184: ** as it often pops up when we are sending an entity then we put it
! 185: ** here for now. A better place whould be in the HTTPGen stream.
! 186: ** the real problem is that the server doesn't have any mechanism of
! 187: ** telling the client what transports it can handle. The best we can
! 188: ** hope for is that the server understands "chunked" although we are
! 189: ** certainly capable of handling nested encodings :(
! 190: */
! 191: if (transfer_coding) {
! 192: HTStream * target = HTTransferCodingStack(WWW_CODING_CHUNKED,
! 193: me->target, request, NULL, NO);
! 194: if (STREAM_TRACE) HTTrace("Building.... Transfer-Encoding stack\n");
! 195: if (target == HTBlackHole()) {
! 196: if (me->target) (*me->target->isa->abort)(me->target, NULL);
! 197: me->target = HTErrorStream();
! 198: } else
! 199: me->target = target;
! 200: }
! 201:
! 202: #if 0
! 203: /*
! 204: ** We expect the anchor object already to have the right encoding and
! 205: ** we therefore should not set up extra streams for doing this.
2.20 frystyk 206: */
207:
2.34 ! frystyk 208: /* Handle any Content Transfer encoding */
2.20 frystyk 209: {
2.34 ! frystyk 210: HTEncoding cte = HTAnchor_contentTransferEncoding(entity);
! 211: if (!HTFormat_isUnityTransfer(cte)) {
2.20 frystyk 212: if (STREAM_TRACE) HTTrace("Building.... C-T-E stack\n");
2.34 ! frystyk 213: me->target = HTContentTransferCodingStack(cte, me->target,
! 214: request, NULL, YES);
2.20 frystyk 215: }
216: }
217:
2.34 ! frystyk 218: /* Handle any Content Encodings */
2.20 frystyk 219: {
220: HTList * cc = HTAnchor_encoding(entity);
221: if (cc) {
222: if (STREAM_TRACE) HTTrace("Building.... C-E stack\n");
2.33 frystyk 223: me->target = HTContentEncodingStack(cc, me->target, request, NULL);
2.20 frystyk 224: }
225: }
2.34 ! frystyk 226: #endif
2.20 frystyk 227:
2.13 eric 228: if (PROT_TRACE) HTTrace("MIME........ Generating Entity Headers\n");
2.2 frystyk 229: return HT_OK;
2.1 frystyk 230: }
231:
2.32 frystyk 232: /*
233: ** Flushes header but doesn't free stream object
234: */
235: PRIVATE int MIMERequest_flush (HTStream * me)
236: {
237: int status = MIMERequest_put_block(me, NULL, 0);
238: return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
239: }
240:
2.14 frystyk 241: PRIVATE int MIMERequest_put_block (HTStream * me, const char * b, int l)
2.1 frystyk 242: {
2.23 frystyk 243: HTNet * net = HTRequest_net(me->request);
2.32 frystyk 244: if (!me->transparent) {
2.1 frystyk 245: MIMEMakeRequest(me, me->request);
2.9 frystyk 246: me->transparent = YES;
2.22 frystyk 247:
248: /*
2.32 frystyk 249: ** First we only send the header
2.22 frystyk 250: */
251: if (HTMethod_hasEntity(HTRequest_method(me->request))) {
252: HTHost * host = HTNet_host(net);
253: char * class = HTHost_class(host);
2.23 frystyk 254: if (class && !strcmp(class, "http")) {
2.32 frystyk 255: MIMERequest_flush(me);
256: return HT_PAUSE;
2.22 frystyk 257: }
258: }
2.1 frystyk 259: }
2.32 frystyk 260:
2.23 frystyk 261: /* Check if we have written it all */
262: if (b) {
263: HTParentAnchor * entity = HTRequest_entityAnchor(me->request);
264: long cl = HTAnchor_length(entity);
265: return (cl>=0 && HTNet_bytesWritten(net) >= cl) ?
266: HT_LOADED : PUTBLOCK(b, l);
267: }
268: return HT_OK;
2.1 frystyk 269: }
270:
271: PRIVATE int MIMERequest_put_character (HTStream * me, char c)
272: {
273: return MIMERequest_put_block(me, &c, 1);
274: }
275:
2.14 frystyk 276: PRIVATE int MIMERequest_put_string (HTStream * me, const char * s)
2.1 frystyk 277: {
278: return MIMERequest_put_block(me, s, strlen(s));
279: }
280:
281: /*
282: ** Flushes data and frees stream object
283: */
284: PRIVATE int MIMERequest_free (HTStream * me)
285: {
286: int status = MIMERequest_flush(me);
287: if (status != HT_WOULD_BLOCK) {
288: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
289: return HT_WOULD_BLOCK;
2.12 frystyk 290: HT_FREE(me);
2.1 frystyk 291: }
292: return status;
293: }
294:
2.4 frystyk 295: PRIVATE int MIMERequest_abort (HTStream * me, HTList * e)
2.1 frystyk 296: {
297: if (me->target) (*me->target->isa->abort)(me->target, e);
2.12 frystyk 298: HT_FREE(me);
2.13 eric 299: if (PROT_TRACE) HTTrace("MIMERequest. ABORTING...\n");
2.1 frystyk 300: return HT_ERROR;
301: }
302:
303: /* MIMERequest Stream
304: ** -----------------
305: */
2.14 frystyk 306: PRIVATE const HTStreamClass MIMERequestClass =
2.1 frystyk 307: {
308: "MIMERequest",
309: MIMERequest_flush,
310: MIMERequest_free,
311: MIMERequest_abort,
312: MIMERequest_put_character,
313: MIMERequest_put_string,
314: MIMERequest_put_block
315: };
316:
2.10 frystyk 317: PUBLIC HTStream * HTMIMERequest_new (HTRequest * request, HTStream * target,
318: BOOL endHeader)
2.1 frystyk 319: {
2.12 frystyk 320: HTStream * me;
321: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
322: HT_OUTOFMEM("HTMIMERequest_new");
2.1 frystyk 323: me->isa = &MIMERequestClass;
324: me->target = target;
325: me->request = request;
2.10 frystyk 326: me->endHeader = endHeader;
2.1 frystyk 327: me->transparent = NO;
328: return me;
329: }
Webmaster