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