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