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