Annotation of libwww/Library/src/HTMIMERq.c, revision 2.30
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.30 ! frystyk 6: ** @(#) $Id: HTMIMERq.c,v 2.29 1996/11/30 23:31:36 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.23 frystyk 34: BOOL put_fix;
2.10 frystyk 35: BOOL endHeader;
2.1 frystyk 36: BOOL transparent;
37: };
38:
2.27 frystyk 39: #define HT_MAX_WAIT 8 /* Max number of secs to wait for PUT */
2.25 frystyk 40:
2.1 frystyk 41: /* ------------------------------------------------------------------------- */
42: /* MIME Output Request Stream */
43: /* ------------------------------------------------------------------------- */
44:
45: /* MIMEMakeRequest
46: ** ---------------
2.10 frystyk 47: ** Generates the BODY parts of a MIME message.
2.1 frystyk 48: */
2.2 frystyk 49: PRIVATE int MIMEMakeRequest (HTStream * me, HTRequest * request)
2.1 frystyk 50: {
2.17 frystyk 51: char crlf[3];
2.10 frystyk 52: char linebuf[256]; /* @@@ */
2.21 frystyk 53: HTParentAnchor * entity = HTRequest_entityAnchor(request);
54: HTEnHd EntityMask = HTRequest_enHd(request);
2.17 frystyk 55: *crlf = CR; *(crlf+1) = LF; *(crlf+2) = '\0';
2.1 frystyk 56:
2.21 frystyk 57: if (EntityMask & HT_E_ALLOW) {
2.10 frystyk 58: /* @@@@@@@@@@ */
59: }
2.21 frystyk 60: if (EntityMask & HT_E_CONTENT_ENCODING && entity->content_encoding){
2.17 frystyk 61: BOOL first = YES;
62: HTList * cur = entity->content_encoding;
63: HTEncoding pres;
64: while ((pres = (HTEncoding) HTList_nextObject(cur))) {
65: if (first) {
66: PUTS("Content-Encoding: ");
67: first = NO;
68: } else
69: PUTC(',');
70: PUTS(HTAtom_name(pres));
71: }
72: if (!first) PUTBLOCK(crlf, 2);
2.1 frystyk 73: }
2.10 frystyk 74:
2.21 frystyk 75: if (EntityMask & HT_E_CONTENT_LANGUAGE && entity->content_language){
2.17 frystyk 76: BOOL first = YES;
77: HTList * cur = entity->content_language;
78: HTLanguage pres;
79: while ((pres = (HTLanguage) HTList_nextObject(cur))) {
80: if (first) {
81: PUTS("Content-Language: ");
82: first = NO;
83: } else
84: PUTC(',');
85: PUTS(HTAtom_name(pres));
86: }
87: if (!first) PUTBLOCK(crlf, 2);
2.1 frystyk 88: }
2.21 frystyk 89: if (EntityMask & HT_E_CONTENT_LENGTH) {
2.20 frystyk 90: if (entity->content_length >= 0) {
91: sprintf(linebuf, "Content-Length: %ld%c%c",
92: entity->content_length, CR, LF);
93: PUTBLOCK(linebuf, (int) strlen(linebuf));
94: } else {
95: HTEncoding chunked = HTAtom_for("chunked");
96: HTAnchor_setTransfer(entity, chunked);
97: }
2.10 frystyk 98: }
2.21 frystyk 99: if (EntityMask & HT_E_CTE && entity->transfer) {
2.20 frystyk 100: HTEncoding transfer = HTAnchor_transfer(entity);
101: if (!HTFormat_isUnityTransfer(transfer)) {
102: sprintf(linebuf, "Transfer-Encoding: %s%c%c",
103: HTAtom_name(transfer), CR, LF);
104: PUTBLOCK(linebuf, (int) strlen(linebuf));
105: }
2.1 frystyk 106: }
2.21 frystyk 107: if (EntityMask & HT_E_CONTENT_TYPE && entity->content_type &&
2.19 frystyk 108: entity->content_type != WWW_UNKNOWN) {
109: HTAssocList * parameters = HTAnchor_formatParam(entity);
110:
111: /* Output the content type */
112: PUTS("Content-Type: ");
113: PUTS(HTAtom_name(entity->content_type));
114:
115: /* Add all parameters */
116: if (parameters) {
117: HTAssoc * pres;
118: while ((pres = (HTAssoc *) HTAssocList_nextObject(parameters))) {
119: PUTS(";");
120: PUTS(HTAssoc_name(pres));
121: PUTS("=");
122: PUTS(HTAssoc_value(pres));
123: }
124: }
125: PUTBLOCK(crlf, 2);
126: #if 0
2.10 frystyk 127: if (entity->charset) {
128: strcat(linebuf, "; charset=");
129: strcat(linebuf, HTAtom_name(entity->charset));
130: }
131: if (entity->level) {
132: strcat(linebuf, "; level=");
133: strcat(linebuf, HTAtom_name(entity->level));
134: }
135: len = strlen(linebuf);
136: *(linebuf+len) = CR;
137: *(linebuf+len+1) = LF;
138: *(linebuf+len+2) = '\0';
139: PUTBLOCK(linebuf, (int) len+2);
2.19 frystyk 140: #endif
2.10 frystyk 141: }
2.21 frystyk 142: if (EntityMask & HT_E_DERIVED_FROM && entity->derived_from) {
2.10 frystyk 143: sprintf(linebuf, "Derived-From: %s%c%c", entity->derived_from,
144: CR, LF);
2.2 frystyk 145: PUTBLOCK(linebuf, (int) strlen(linebuf));
2.1 frystyk 146: }
2.21 frystyk 147: if (EntityMask & HT_E_EXPIRES) {
2.10 frystyk 148: if (entity->expires != -1) {
149: sprintf(linebuf, "Expires: %s%c%c",
150: HTDateTimeStr(&entity->expires, NO), CR,LF);
2.2 frystyk 151: PUTBLOCK(linebuf, (int) strlen(linebuf));
2.1 frystyk 152: }
2.10 frystyk 153: }
2.21 frystyk 154: if (EntityMask & HT_E_LAST_MODIFIED) {
2.10 frystyk 155: if (entity->last_modified != -1) {
156: sprintf(linebuf, "Last-Modified: %s%c%c",
157: HTDateTimeStr(&entity->last_modified, 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_LINK) { /* @@@@@@@@@@ */
2.1 frystyk 162:
2.10 frystyk 163: }
2.21 frystyk 164: if (EntityMask & HT_E_TITLE) { /* @@@@@@@@@@ */
2.1 frystyk 165:
2.10 frystyk 166: }
2.21 frystyk 167: if (EntityMask & HT_E_URI) { /* @@@@@@@@@@ */
2.1 frystyk 168:
169: }
2.21 frystyk 170: if (EntityMask & HT_E_VERSION && entity->version) {
2.10 frystyk 171: sprintf(linebuf, "Version: %s%c%c", entity->version, CR, LF);
172: PUTBLOCK(linebuf, (int) strlen(linebuf));
173: }
174: if (me->endHeader) {
175: sprintf(linebuf, "%c%c", CR, LF); /* Blank line means "end" */
176: PUTBLOCK(linebuf, (int) strlen(linebuf));
2.2 frystyk 177: }
2.20 frystyk 178:
179: /*
180: ** Now make sure that the body has the right format
181: */
182:
183: /* Handle any Transfer encoding */
184: {
185: HTEncoding transfer = HTAnchor_transfer(entity);
186: if (!HTFormat_isUnityTransfer(transfer)) {
187: if (STREAM_TRACE) HTTrace("Building.... C-T-E stack\n");
188: me->target = HTTransferCodingStack(transfer, me->target,
189: request, NULL, YES);
190: }
191: }
192:
193: /* Handle any Content Encoding */
194: {
195: HTList * cc = HTAnchor_encoding(entity);
196: if (cc) {
197: if (STREAM_TRACE) HTTrace("Building.... C-E stack\n");
198: me->target = HTContentDecodingStack(cc, me->target, request, NULL);
199: }
200: }
201:
2.13 eric 202: if (PROT_TRACE) HTTrace("MIME........ Generating Entity Headers\n");
2.2 frystyk 203: return HT_OK;
2.1 frystyk 204: }
205:
2.14 frystyk 206: PRIVATE int MIMERequest_put_block (HTStream * me, const char * b, int l)
2.1 frystyk 207: {
2.23 frystyk 208: HTNet * net = HTRequest_net(me->request);
209: if (me->transparent) {
210: if (me->put_fix) {
211: HTNet * net = HTRequest_net(me->request);
2.29 frystyk 212: HTEvent_unregister(HTNet_socket(net), HTEvent_READ);
213: HTEvent_unregister(HTNet_socket(net), HTEvent_WRITE);
2.23 frystyk 214: me->put_fix = NO;
215: }
216: } else {
2.1 frystyk 217: MIMEMakeRequest(me, me->request);
2.9 frystyk 218: if (HTRequest_isDestination(me->request)) {
2.21 frystyk 219: HTNet * net = HTRequest_net(me->request);
220: HTNet_setBytesWritten(net, 0);
2.1 frystyk 221: }
2.9 frystyk 222: me->transparent = YES;
2.22 frystyk 223:
224: /*
225: ** If we know we are talking to an HTTP 1.1 server and we are sending
226: ** an entity body then wait until we have received a 100 response
227: */
228: if (HTMethod_hasEntity(HTRequest_method(me->request))) {
229: HTHost * host = HTNet_host(net);
230: char * class = HTHost_class(host);
2.23 frystyk 231: if (class && !strcmp(class, "http")) {
232:
233: /*
234: ** If this is a HTTP/1.1 or later then wait for 100 code. If
235: ** it is a HTTP/1.0 server then wait a bit and hope the best.
236: */
237: if (HTHost_version(host) >= 3) {
238: if (STREAM_TRACE)
239: HTTrace("MIME........ Waiting for 100...\n");
2.30 ! frystyk 240: if (HTRequest_flush(me->request)) /* @@@ Ignore return value@@@ */
! 241: HTHost_forceFlush(host);
! 242: else
! 243: (*me->target->isa->flush)(me->target);
2.23 frystyk 244: return HT_PAUSE;
245: } else {
246: HTNet * net = HTRequest_net(me->request);
247: int zzzz = HTRequest_retrys(me->request);
248: zzzz = zzzz ? zzzz * 2 : 2;
2.25 frystyk 249: if (zzzz > HT_MAX_WAIT) zzzz = HT_MAX_WAIT;
2.30 ! frystyk 250: if (HTRequest_flush(me->request)) /* @@@ Ignore return value@@@ */
! 251: HTHost_forceFlush(host);
! 252: else
! 253: (*me->target->isa->flush)(me->target);
! 254: if (STREAM_TRACE)
! 255: HTTrace("MIME........ Sleeping for %d secs\n", zzzz);
! 256: HTHost_register(HTNet_host(net), net, HTEvent_READ);
! 257: HTHost_register(HTNet_host(net), net, HTEvent_WRITE);
2.23 frystyk 258: SLEEP(zzzz);
259: me->put_fix = YES;
260: return HT_WOULD_BLOCK;
261: }
2.22 frystyk 262: }
263: }
2.1 frystyk 264: }
2.23 frystyk 265:
266: /* Check if we have written it all */
267: if (b) {
268: HTParentAnchor * entity = HTRequest_entityAnchor(me->request);
269: long cl = HTAnchor_length(entity);
270: return (cl>=0 && HTNet_bytesWritten(net) >= cl) ?
271: HT_LOADED : PUTBLOCK(b, l);
272: }
273: return HT_OK;
2.1 frystyk 274: }
275:
276: PRIVATE int MIMERequest_put_character (HTStream * me, char c)
277: {
278: return MIMERequest_put_block(me, &c, 1);
279: }
280:
2.14 frystyk 281: PRIVATE int MIMERequest_put_string (HTStream * me, const char * s)
2.1 frystyk 282: {
283: return MIMERequest_put_block(me, s, strlen(s));
284: }
285:
286: /*
287: ** Flushes header but doesn't free stream object
288: */
289: PRIVATE int MIMERequest_flush (HTStream * me)
290: {
291: int status = MIMERequest_put_block(me, NULL, 0);
292: return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
293: }
294:
295: /*
296: ** Flushes data and frees stream object
297: */
298: PRIVATE int MIMERequest_free (HTStream * me)
299: {
300: int status = MIMERequest_flush(me);
301: if (status != HT_WOULD_BLOCK) {
302: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
303: return HT_WOULD_BLOCK;
2.12 frystyk 304: HT_FREE(me);
2.1 frystyk 305: }
306: return status;
307: }
308:
2.4 frystyk 309: PRIVATE int MIMERequest_abort (HTStream * me, HTList * e)
2.1 frystyk 310: {
311: if (me->target) (*me->target->isa->abort)(me->target, e);
2.12 frystyk 312: HT_FREE(me);
2.13 eric 313: if (PROT_TRACE) HTTrace("MIMERequest. ABORTING...\n");
2.1 frystyk 314: return HT_ERROR;
315: }
316:
317: /* MIMERequest Stream
318: ** -----------------
319: */
2.14 frystyk 320: PRIVATE const HTStreamClass MIMERequestClass =
2.1 frystyk 321: {
322: "MIMERequest",
323: MIMERequest_flush,
324: MIMERequest_free,
325: MIMERequest_abort,
326: MIMERequest_put_character,
327: MIMERequest_put_string,
328: MIMERequest_put_block
329: };
330:
2.10 frystyk 331: PUBLIC HTStream * HTMIMERequest_new (HTRequest * request, HTStream * target,
332: BOOL endHeader)
2.1 frystyk 333: {
2.12 frystyk 334: HTStream * me;
335: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
336: HT_OUTOFMEM("HTMIMERequest_new");
2.1 frystyk 337: me->isa = &MIMERequestClass;
338: me->target = target;
339: me->request = request;
2.10 frystyk 340: me->endHeader = endHeader;
2.1 frystyk 341: me->transparent = NO;
342: return me;
343: }
Webmaster