Annotation of libwww/Library/src/HTMIME.c, revision 2.33
2.15 frystyk 1: /* HTMIME.c
2: ** MIME MESSAGE PARSE
3: **
2.22 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.15 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
2.1 timbl 6: **
7: ** This is RFC 1341-specific code.
8: ** The input stream pushed into this parser is assumed to be
9: ** stripped on CRs, ie lines end with LF, not CR LF.
10: ** (It is easy to change this except for the body part where
11: ** conversion can be slow.)
12: **
13: ** History:
14: ** Feb 92 Written Tim Berners-Lee, CERN
2.13 duns 15: ** 8 Jul 94 FM Insulate free() from _free structure element.
2.18 frystyk 16: ** 14 Mar 95 HFN Now using anchor for storing data. No more `\n',
17: ** static buffers etc.
2.1 timbl 18: */
2.17 frystyk 19:
20: /* Library include files */
21: #include "tcp.h"
22: #include "HTUtils.h"
23: #include "HTString.h"
2.9 luotonen 24: #include "HTFormat.h"
2.27 frystyk 25: #include "HTCache.h"
26: #include "HTAlert.h"
2.32 frystyk 27: #include "HTAnchor.h"
2.18 frystyk 28: #include "HTChunk.h"
2.26 frystyk 29: #include "HTMethod.h"
2.24 frystyk 30: #include "HTSocket.h"
2.17 frystyk 31: #include "HTFWrite.h"
2.32 frystyk 32: #include "HTNetMan.h"
2.31 frystyk 33: #include "HTReqMan.h"
2.14 frystyk 34: #include "HTMIME.h" /* Implemented here */
2.1 timbl 35:
36: /* MIME Object
37: ** -----------
38: */
39: typedef enum _MIME_state {
2.23 frystyk 40: BEGINNING_OF_LINE=0,
2.18 frystyk 41: CHECK, /* check against check_pointer */
42: UNKNOWN, /* Unknown header */
43: JUNK_LINE, /* Ignore rest of header */
44:
2.32 frystyk 45: CON, /* Intermediate states */
46: CONTENT,
2.18 frystyk 47: FIRSTLETTER_D,
48: FIRSTLETTER_L,
49: CONTENTLETTER_L,
50: CONTENTLETTER_T,
51:
52: ALLOW, /* Headers supported */
53: AUTHENTICATE,
2.32 frystyk 54: CONNECTION,
2.18 frystyk 55: CONTENT_ENCODING,
56: CONTENT_LANGUAGE,
57: CONTENT_LENGTH,
2.14 frystyk 58: CONTENT_TRANSFER_ENCODING,
59: CONTENT_TYPE,
2.23 frystyk 60: MIME_DATE,
2.18 frystyk 61: DERIVED_FROM,
62: EXPIRES,
63: LAST_MODIFIED,
64: LINK,
2.14 frystyk 65: LOCATION,
2.18 frystyk 66: PUBLIC_METHODS,
67: RETRY_AFTER,
68: TITLE,
69: URI_HEADER,
70: VERSION
2.1 timbl 71: } MIME_state;
72:
73: struct _HTStream {
2.18 frystyk 74: CONST HTStreamClass * isa;
75: HTRequest * request;
2.32 frystyk 76: HTNet * net;
77: HTParentAnchor * anchor;
2.18 frystyk 78: HTStream * target;
79: HTFormat target_format;
80: HTChunk * buffer;
81: HTSocketEOL EOLstate;
82: BOOL transparent;
2.1 timbl 83: };
84:
2.32 frystyk 85: PRIVATE HTMIMEHandler *HTMIMEUnknown = NULL; /* Unknown header handler */
86:
87: /* ------------------------------------------------------------------------- */
88: /* HANDLING UNKNOWN HEADERS */
89: /* ------------------------------------------------------------------------- */
90:
91: /* Register a unknown header handler
92: ** ---------------------------------
93: ** The application can register a handler that gets called when an
94: ** unknown header is found in the header
95: */
96: PUBLIC BOOL HTMIME_register (HTMIMEHandler * cbf)
97: {
98: return (HTMIMEUnknown = cbf) ? YES : NO;
99: }
100:
101: PUBLIC BOOL HTMIME_unRegister (void)
102: {
103: HTMIMEUnknown = NULL;
104: return YES;
105: }
106:
107: /* ------------------------------------------------------------------------- */
108: /* MIME PARSER */
2.18 frystyk 109: /* ------------------------------------------------------------------------- */
2.1 timbl 110:
2.18 frystyk 111: /*
2.1 timbl 112: ** This is a FSM parser which is tolerant as it can be of all
113: ** syntax errors. It ignores field names it does not understand,
114: ** and resynchronises on line beginnings.
115: */
2.27 frystyk 116: PRIVATE int parseheader ARGS3(HTStream *, me, HTRequest *, request,
117: HTParentAnchor *, anchor)
2.18 frystyk 118: {
119: MIME_state state = BEGINNING_OF_LINE;
120: MIME_state ok_state; /* got this state if match */
121: char *ptr = me->buffer->data-1; /* We dont change the data in length */
122: char *stop = ptr+me->buffer->size; /* When to stop */
123: char *header = ptr; /* For diagnostics */
124: CONST char * check_pointer; /* checking input */
125: char *value;
2.27 frystyk 126:
127: /* In case we get an empty header consisting of a CRLF, we fall thru */
2.18 frystyk 128: while (ptr < stop) {
129: switch (state) {
130: case BEGINNING_OF_LINE:
131: header = ++ptr;
132: switch (TOLOWER(*ptr)) {
133: case 'a':
134: check_pointer = "llow";
135: ok_state = ALLOW;
136: state = CHECK;
137: break;
138:
139: case 'c':
2.32 frystyk 140: check_pointer = "on";
141: ok_state = CON;
2.18 frystyk 142: state = CHECK;
143: break;
144:
145: case 'd':
146: state = FIRSTLETTER_D;
147: break;
148:
149: case 'e':
150: check_pointer = "xpires";
151: ok_state = EXPIRES;
152: state = CHECK;
153: break;
154:
2.32 frystyk 155: case 'k':
2.33 ! frystyk 156: check_pointer = "eep-alive";
! 157: ok_state = JUNK_LINE; /* We don't use this but recognize it */
! 158: state = CHECK;
2.32 frystyk 159: break;
160:
2.18 frystyk 161: case 'l':
162: state = FIRSTLETTER_L;
163: break;
164:
165: case 'm':
166: check_pointer = "ime-version";
167: ok_state = JUNK_LINE; /* We don't use this but recognize it */
168: state = CHECK;
169: break;
170:
171: case 'r':
172: check_pointer = "etry-after";
173: ok_state = RETRY_AFTER;
174: state = CHECK;
175: break;
176:
177: case 's':
178: check_pointer = "erver";
179: ok_state = JUNK_LINE; /* We don't use this but recognize it */
180: state = CHECK;
181: break;
2.1 timbl 182:
2.18 frystyk 183: case 't':
184: check_pointer = "itle";
185: ok_state = TITLE;
186: state = CHECK;
187: break;
188:
189: case 'u':
190: check_pointer = "ri";
191: ok_state = URI_HEADER;
192: state = CHECK;
193: break;
194:
195: case 'v':
196: check_pointer = "ersion";
197: ok_state = VERSION;
198: state = CHECK;
199: break;
200:
201: case 'w':
202: check_pointer = "ww-authenticate";
203: ok_state = AUTHENTICATE;
204: state = CHECK;
205: break;
2.1 timbl 206:
2.18 frystyk 207: default:
208: state = UNKNOWN;
209: break;
210: }
211: ptr++;
2.1 timbl 212: break;
213:
2.18 frystyk 214: case FIRSTLETTER_D:
215: switch (TOLOWER(*ptr)) {
216: case 'a':
217: check_pointer = "te";
2.23 frystyk 218: ok_state = MIME_DATE;
2.18 frystyk 219: state = CHECK;
220: break;
221:
222: case 'e':
223: check_pointer = "rived-from";
224: ok_state = DERIVED_FROM;
225: state = CHECK;
226: break;
227:
228: default:
229: state = UNKNOWN;
230: break;
231: }
232: ptr++;
233: break;
234:
235: case FIRSTLETTER_L:
236: switch (TOLOWER(*ptr)) {
237: case 'a':
238: check_pointer = "st-modified";
239: ok_state = LAST_MODIFIED;
240: state = CHECK;
241: break;
242:
243: case 'i':
244: check_pointer = "nk";
245: ok_state = LINK;
246: state = CHECK;
247: break;
248:
249: case 'o':
250: check_pointer = "cation";
251: ok_state = LOCATION;
252: state = CHECK;
253: break;
254:
255: default:
256: state = UNKNOWN;
257: break;
258: }
259: ptr++;
260: break;
261:
2.32 frystyk 262: case CON:
263: switch (TOLOWER(*ptr)) {
264: case 'n':
265: check_pointer = "ection";
266: ok_state = CONNECTION;
267: state = CHECK;
268: break;
269:
270: case 't':
271: check_pointer = "ent-";
272: ok_state = CONTENT;
273: state = CHECK;
274: break;
275:
276: default:
277: state = UNKNOWN;
278: break;
279: }
280: ptr++;
281: break;
282:
2.18 frystyk 283: case CONTENT:
284: switch (TOLOWER(*ptr)) {
285: case 'e':
286: check_pointer = "ncoding";
287: ok_state = CONTENT_ENCODING;
288: state = CHECK;
289: break;
290:
291: case 'l':
292: state = CONTENTLETTER_L;
293: break;
294:
295: case 't':
296: state = CONTENTLETTER_T;
297: break;
298:
299: default:
300: state = UNKNOWN;
301: break;
302: }
303: ptr++;
2.1 timbl 304: break;
2.14 frystyk 305:
2.18 frystyk 306: case CONTENTLETTER_L:
307: switch (TOLOWER(*ptr)) {
308: case 'a':
309: check_pointer = "nguage";
310: ok_state = CONTENT_LANGUAGE;
311: state = CHECK;
312: break;
313:
314: case 'e':
315: check_pointer = "ngth";
316: ok_state = CONTENT_LENGTH;
317: state = CHECK;
318: break;
319:
320: default:
321: state = UNKNOWN;
322: break;
323: }
324: ptr++;
2.14 frystyk 325: break;
326:
2.18 frystyk 327: case CONTENTLETTER_T:
328: switch (TOLOWER(*ptr)) {
329: case 'r':
330: check_pointer = "ansfer-encoding";
331: ok_state = CONTENT_TRANSFER_ENCODING;
332: state = CHECK;
333: break;
334:
335: case 'y':
336: check_pointer = "pe";
337: ok_state = CONTENT_TYPE;
338: state = CHECK;
339: break;
340:
341: default:
342: state = UNKNOWN;
343: break;
344: }
345: ptr++;
2.14 frystyk 346: break;
347:
2.18 frystyk 348: case CHECK: /* Check against string */
349: while (TOLOWER(*ptr) == *(check_pointer)++) ptr++;
350: if (!*--check_pointer) {
351: state = ok_state;
352: while (*ptr && (WHITE(*ptr) || *ptr==':')) /* Spool to value */
353: ptr++;
354: } else
355: state = UNKNOWN;
2.14 frystyk 356: break;
357:
2.18 frystyk 358: case ALLOW:
2.20 frystyk 359: while ((value = HTNextField(&ptr)) != NULL) {
360: HTMethod new_method;
2.26 frystyk 361: /* We treat them as case-insensitive! */
2.20 frystyk 362: if ((new_method = HTMethod_enum(value)) != METHOD_INVALID)
363: anchor->methods += new_method;
2.1 timbl 364: }
2.18 frystyk 365: if (STREAM_TRACE)
366: fprintf(TDEST, "MIMEParser.. Methods allowed: %d\n",
367: anchor->methods);
368: state = JUNK_LINE;
2.1 timbl 369: break;
2.18 frystyk 370:
371: case AUTHENTICATE:
372: if ((value = HTNextField(&ptr)) != NULL) {
373: StrAllocCopy(request->WWWAAScheme, value);
2.20 frystyk 374:
375: /* The parsing is done in HTSSUtils.c for the moment */
376: if (*ptr) StrAllocCopy(request->WWWAARealm, ptr);
2.1 timbl 377: }
2.18 frystyk 378: state = JUNK_LINE;
379: break;
380:
2.32 frystyk 381: case CONNECTION:
382: if ((value = HTNextField(&ptr)) != NULL) {
383: if (!strcasecomp(value, "keep-alive")) {
384: if (STREAM_TRACE)
385: fprintf(TDEST,"MIMEParser.. Persistent Connection!\n");
386: HTDNS_setSocket(me->net->dns, me->net->sockfd);
387: }
388: }
389: state = JUNK_LINE;
390: break;
391:
2.18 frystyk 392: case CONTENT_ENCODING:
393: if ((value = HTNextField(&ptr)) != NULL) {
394: char *lc = value;
2.20 frystyk 395: while ((*lc = TOLOWER(*lc))) lc++;
2.18 frystyk 396: anchor->content_encoding = HTAtom_for(value);
397: }
398: state = JUNK_LINE;
399: break;
400:
2.21 frystyk 401: case CONTENT_LANGUAGE: /* @@@ SHOULD BE A LIST @@@ */
402: if ((value = HTNextField(&ptr)) != NULL) {
403: char *lc = value;
404: while ((*lc = TOLOWER(*lc))) lc++;
405: anchor->content_language = HTAtom_for(value);
406: }
407: state = JUNK_LINE;
2.18 frystyk 408: break;
409:
410: case CONTENT_LENGTH:
411: if ((value = HTNextField(&ptr)) != NULL)
412: anchor->content_length = atol(value);
413: state = JUNK_LINE;
414: break;
415:
416: case CONTENT_TRANSFER_ENCODING:
417: if ((value = HTNextField(&ptr)) != NULL) {
418: char *lc = value;
2.20 frystyk 419: while ((*lc = TOLOWER(*lc))) lc++;
2.18 frystyk 420: anchor->cte = HTAtom_for(value);
421: }
422: state = JUNK_LINE;
423: break;
424:
425: case CONTENT_TYPE:
426: if ((value = HTNextField(&ptr)) != NULL) {
427: char *lc = value;
428: while ((*lc = TOLOWER(*lc))) lc++;
429: anchor->content_type = HTAtom_for(value);
2.20 frystyk 430: while ((value = HTNextField(&ptr)) != NULL) { /* Charset */
431: if (!strcasecomp(value, "charset")) {
432: if ((value = HTNextField(&ptr)) != NULL) {
433: lc = value;
434: while ((*lc = TOLOWER(*lc))) lc++;
435: anchor->charset = HTAtom_for(value);
436: }
437: } else if (!strcasecomp(value, "level")) { /* Level */
438: if ((value = HTNextField(&ptr)) != NULL) {
439: lc = value;
440: while ((*lc = TOLOWER(*lc))) lc++;
441: anchor->level = HTAtom_for(value);
442: }
443: }
444: }
2.1 timbl 445: }
2.20 frystyk 446: state = JUNK_LINE;
2.18 frystyk 447: break;
448:
2.23 frystyk 449: case MIME_DATE:
2.18 frystyk 450: anchor->date = HTParseTime(ptr);
451: state = JUNK_LINE;
452: break;
453:
454: case DERIVED_FROM:
455: if ((value = HTNextField(&ptr)) != NULL)
456: StrAllocCopy(anchor->derived_from, value);
457: state = JUNK_LINE;
458: break;
459:
460: case EXPIRES:
461: anchor->expires = HTParseTime(ptr);
462: state = JUNK_LINE;
463: break;
464:
465: case LAST_MODIFIED:
466: anchor->last_modified = HTParseTime(ptr);
467: state = JUNK_LINE;
468: break;
469:
470: case LINK:
2.20 frystyk 471: state = UNKNOWN; /* @@@@@@@@@@@ */
2.18 frystyk 472: break;
473:
474: case LOCATION:
2.31 frystyk 475: #if 0
476: /*
477: ** Doesn't work as a redirection header might contain a '='
478: ** Thanks to mitch@tam.net (Mitch DeShields)
479: */
2.18 frystyk 480: if ((value = HTNextField(&ptr)) != NULL)
481: StrAllocCopy(request->redirect, value);
2.31 frystyk 482: #endif
483: StrAllocCopy(request->redirect, ptr);
2.18 frystyk 484: state = JUNK_LINE;
485: break;
486:
487: case PUBLIC_METHODS:
2.20 frystyk 488: state = UNKNOWN; /* @@@@@@@@@@@ */
2.18 frystyk 489: break;
490:
491: case RETRY_AFTER:
2.19 frystyk 492: request->retry_after = HTParseTime(ptr);
493: state = JUNK_LINE;
2.18 frystyk 494: break;
495:
496: case TITLE: /* Can't reuse buffer as HTML version might differ */
497: if ((value = HTNextField(&ptr)) != NULL)
498: StrAllocCopy(anchor->title, value);
499: state = JUNK_LINE;
500: break;
501:
502: case URI_HEADER:
503: state = LOCATION; /* @@@ Need extended parsing */
504: break;
505:
506: case VERSION:
507: if ((value = HTNextField(&ptr)) != NULL)
508: StrAllocCopy(anchor->version, value);
509: state = JUNK_LINE;
510: break;
511:
512: case UNKNOWN:
513: if (STREAM_TRACE)
514: fprintf(TDEST,"MIMEParser.. Unknown header: `%s\'\n", header);
2.32 frystyk 515: if (HTMIMEUnknown && HTMIMEUnknown(request, header))
516: HTAnchor_addExtra(anchor, header);
2.18 frystyk 517:
518: /* Fall through */
519:
520: case JUNK_LINE:
521: while (*ptr) ptr++;
522: state = BEGINNING_OF_LINE;
523: break;
2.1 timbl 524: }
2.18 frystyk 525: }
526:
2.27 frystyk 527: /*
528: ** If coming from cache then check if the document has expired. We can
529: ** either ignore this or attempt a reload
530: */
531: {
532: char *msg;
2.31 frystyk 533: HTExpiresMode expire_mode = HTCache_expiresMode(&msg);
2.27 frystyk 534: if (expire_mode != HT_EXPIRES_IGNORE) {
535: time_t cur = time(NULL);
536: if (anchor->expires>0 && cur>0 && anchor->expires<cur) {
537: if (expire_mode == HT_EXPIRES_NOTIFY)
2.28 frystyk 538: HTAlert(request, msg);
2.31 frystyk 539: else if (HTRequest_retry(request)) {
2.27 frystyk 540: if (PROT_TRACE)
541: fprintf(TDEST, "MIMEParser.. Expired - auto reload\n");
542: if (anchor->cacheHit) {
2.31 frystyk 543: HTRequest_addRqHd(request, HT_IMS);
544: HTRequest_setReloadMode(request, HT_FORCE_RELOAD);
2.27 frystyk 545: anchor->cacheHit = NO; /* Don't want to loop */
546: }
547: return HT_RELOAD;
548: }
549: }
550: }
551: }
552:
2.30 frystyk 553: if (anchor->content_type != WWW_UNKNOWN) {
2.18 frystyk 554: if (STREAM_TRACE)
2.30 frystyk 555: fprintf(TDEST, "MIMEParser.. Media type %s is converted to %s\n",
556: HTAtom_name(anchor->content_type),
557: HTAtom_name(me->target_format));
558: if ((me->target=HTStreamStack(anchor->content_type, me->target_format,
559: me->target, request, YES)) == NULL) {
560: if (STREAM_TRACE)
561: fprintf(TDEST, "MIMEParser.. Can't convert media type\n");
562: me->target = HTBlackHole();
563: }
2.18 frystyk 564: }
565: anchor->header_parsed = YES;
2.27 frystyk 566: me->transparent = YES; /* Pump rest of data right through */
567: return HT_OK;
2.1 timbl 568: }
569:
570:
2.18 frystyk 571: /*
572: ** Header is terminated by CRCR, LFLF, CRLFLF, CRLFCRLF
573: ** Folding is either of CF LWS, LF LWS, CRLF LWS
574: */
575: PRIVATE int HTMIME_put_block ARGS3(HTStream *, me, CONST char *, b, int, l)
576: {
2.32 frystyk 577: int status = HT_OK;
2.18 frystyk 578: while (!me->transparent && l-- > 0) {
579: if (me->EOLstate == EOL_FCR) {
2.27 frystyk 580: if (*b == CR) { /* End of header */
2.32 frystyk 581: int status = parseheader(me, me->request, me->anchor);
582: me->net->bytes_read = l;
2.27 frystyk 583: if (status != HT_OK)
584: return status;
585: } else if (*b == LF) /* CRLF */
2.18 frystyk 586: me->EOLstate = EOL_FLF;
587: else if (WHITE(*b)) { /* Folding: CR SP */
588: me->EOLstate = EOL_BEGIN;
589: HTChunkPutc(me->buffer, ' ');
590: } else { /* New line */
591: me->EOLstate = EOL_BEGIN;
592: HTChunkPutc(me->buffer, '\0');
593: HTChunkPutc(me->buffer, *b);
594: }
595: } else if (me->EOLstate == EOL_FLF) {
596: if (*b == CR) /* LF CR or CR LF CR */
597: me->EOLstate = EOL_SCR;
2.27 frystyk 598: else if (*b == LF) { /* End of header */
2.32 frystyk 599: int status = parseheader(me, me->request, me->anchor);
600: me->net->bytes_read = l;
2.27 frystyk 601: if (status != HT_OK)
602: return status;
603: } else if (WHITE(*b)) { /* Folding: LF SP or CR LF SP */
2.18 frystyk 604: me->EOLstate = EOL_BEGIN;
605: HTChunkPutc(me->buffer, ' ');
606: } else { /* New line */
607: me->EOLstate = EOL_BEGIN;
608: HTChunkPutc(me->buffer, '\0');
609: HTChunkPutc(me->buffer, *b);
610: }
611: } else if (me->EOLstate == EOL_SCR) {
2.27 frystyk 612: if (*b==CR || *b==LF) { /* End of header */
2.32 frystyk 613: int status = parseheader(me, me->request, me->anchor);
614: me->net->bytes_read = l;
2.27 frystyk 615: if (status != HT_OK)
616: return status;
617: } else if (WHITE(*b)) { /* Folding: LF CR SP or CR LF CR SP */
2.18 frystyk 618: me->EOLstate = EOL_BEGIN;
619: HTChunkPutc(me->buffer, ' ');
620: } else { /* New line */
621: me->EOLstate = EOL_BEGIN;
622: HTChunkPutc(me->buffer, '\0');
623: HTChunkPutc(me->buffer, *b);
624: }
625: } else if (*b == CR) {
626: me->EOLstate = EOL_FCR;
627: } else if (*b == LF) {
628: me->EOLstate = EOL_FLF; /* Line found */
629: } else
630: HTChunkPutc(me->buffer, *b);
631: b++;
632: }
2.30 frystyk 633: #if 0
2.26 frystyk 634: if (me->target) { /* Is the stream set up? */
635: if (l > 0) /* Anything left? */
636: return (*me->target->isa->put_block)(me->target, b, l);
637: return HT_OK;
638: }
639: return HT_WOULD_BLOCK;
2.30 frystyk 640: #endif
2.32 frystyk 641:
642: /*
643: ** Put the rest down the stream without touching the data but make sure
644: ** that we get the correct content length of data
645: */
646: if (me->target && l > 0) {
647: int status = (*me->target->isa->put_block)(me->target, b, l);
648: if (status==HT_OK && me->net->bytes_read >=me->anchor->content_length){
649: return HT_LOADED;
650: }
651: }
652: return status;
2.18 frystyk 653: }
654:
655:
656: /* Character handling
657: ** ------------------
658: */
2.21 frystyk 659: PRIVATE int HTMIME_put_character ARGS2(HTStream *, me, char, c)
2.18 frystyk 660: {
661: return HTMIME_put_block(me, &c, 1);
662: }
663:
2.1 timbl 664:
665: /* String handling
666: ** ---------------
667: */
2.18 frystyk 668: PRIVATE int HTMIME_put_string ARGS2(HTStream *, me, CONST char *, s)
2.1 timbl 669: {
2.18 frystyk 670: return HTMIME_put_block(me, s, (int) strlen(s));
2.1 timbl 671: }
672:
673:
2.18 frystyk 674: /* Flush an stream object
675: ** ---------------------
2.1 timbl 676: */
2.18 frystyk 677: PRIVATE int HTMIME_flush ARGS1(HTStream *, me)
2.1 timbl 678: {
2.18 frystyk 679: return (*me->target->isa->flush)(me->target);
2.1 timbl 680: }
681:
2.18 frystyk 682: /* Free a stream object
683: ** --------------------
2.1 timbl 684: */
2.14 frystyk 685: PRIVATE int HTMIME_free ARGS1(HTStream *, me)
2.1 timbl 686: {
2.18 frystyk 687: int status = HT_OK;
2.25 frystyk 688: if (me->target) {
689: if ((status = (*me->target->isa->_free)(me->target))==HT_WOULD_BLOCK)
690: return HT_WOULD_BLOCK;
691: }
2.26 frystyk 692: if (PROT_TRACE)
693: fprintf(TDEST, "MIME........ FREEING....\n");
2.19 frystyk 694: HTChunkFree(me->buffer);
2.1 timbl 695: free(me);
2.18 frystyk 696: return status;
2.1 timbl 697: }
698:
699: /* End writing
700: */
2.14 frystyk 701: PRIVATE int HTMIME_abort ARGS2(HTStream *, me, HTError, e)
2.1 timbl 702: {
2.18 frystyk 703: int status = HT_ERROR;
704: if (me->target)
705: status = (*me->target->isa->abort)(me->target, e);
2.26 frystyk 706: if (PROT_TRACE)
707: fprintf(TDEST, "MIME........ ABORTING...\n");
708: HTChunkFree(me->buffer);
2.6 timbl 709: free(me);
2.18 frystyk 710: return status;
2.1 timbl 711: }
712:
713:
714:
715: /* Structured Object Class
716: ** -----------------------
717: */
2.6 timbl 718: PRIVATE CONST HTStreamClass HTMIME =
2.1 timbl 719: {
720: "MIMEParser",
2.18 frystyk 721: HTMIME_flush,
2.1 timbl 722: HTMIME_free,
2.6 timbl 723: HTMIME_abort,
724: HTMIME_put_character,
725: HTMIME_put_string,
2.18 frystyk 726: HTMIME_put_block
2.1 timbl 727: };
728:
729:
730: /* Subclass-specific Methods
731: ** -------------------------
732: */
2.7 timbl 733: PUBLIC HTStream* HTMIMEConvert ARGS5(
734: HTRequest *, request,
735: void *, param,
736: HTFormat, input_format,
737: HTFormat, output_format,
738: HTStream *, output_stream)
2.1 timbl 739: {
740: HTStream* me;
2.18 frystyk 741: if ((me=(HTStream *) calloc(1, sizeof(* me))) == NULL)
742: outofmem(__FILE__, "HTMIMEConvert");
2.1 timbl 743: me->isa = &HTMIME;
2.18 frystyk 744: me->request = request;
2.32 frystyk 745: me->anchor = request->anchor;
746: me->net = request->net;
2.18 frystyk 747: me->target = output_stream;
748: me->target_format = output_format;
749: me->buffer = HTChunkCreate(512);
750: me->EOLstate = EOL_BEGIN;
2.1 timbl 751: return me;
752: }
2.32 frystyk 753:
Webmaster