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