Annotation of libwww/Library/src/HTMIME.c, revision 2.34
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.34 ! frystyk 527: #if 0
2.27 frystyk 528: /*
529: ** If coming from cache then check if the document has expired. We can
530: ** either ignore this or attempt a reload
531: */
532: {
533: char *msg;
2.31 frystyk 534: HTExpiresMode expire_mode = HTCache_expiresMode(&msg);
2.27 frystyk 535: if (expire_mode != HT_EXPIRES_IGNORE) {
536: time_t cur = time(NULL);
537: if (anchor->expires>0 && cur>0 && anchor->expires<cur) {
538: if (expire_mode == HT_EXPIRES_NOTIFY)
2.28 frystyk 539: HTAlert(request, msg);
2.31 frystyk 540: else if (HTRequest_retry(request)) {
2.27 frystyk 541: if (PROT_TRACE)
542: fprintf(TDEST, "MIMEParser.. Expired - auto reload\n");
543: if (anchor->cacheHit) {
2.31 frystyk 544: HTRequest_addRqHd(request, HT_IMS);
545: HTRequest_setReloadMode(request, HT_FORCE_RELOAD);
2.27 frystyk 546: anchor->cacheHit = NO; /* Don't want to loop */
547: }
548: return HT_RELOAD;
549: }
550: }
551: }
552: }
2.34 ! frystyk 553: #endif
2.27 frystyk 554:
2.34 ! frystyk 555: if (anchor->content_type!=WWW_UNKNOWN || anchor->content_length>0) {
2.18 frystyk 556: if (STREAM_TRACE)
2.34 ! frystyk 557: fprintf(TDEST, "MIMEParser.. Convert %s to %s\n",
2.30 frystyk 558: HTAtom_name(anchor->content_type),
559: HTAtom_name(me->target_format));
560: if ((me->target=HTStreamStack(anchor->content_type, me->target_format,
561: me->target, request, YES)) == NULL) {
562: if (STREAM_TRACE)
563: fprintf(TDEST, "MIMEParser.. Can't convert media type\n");
564: me->target = HTBlackHole();
565: }
2.18 frystyk 566: }
567: anchor->header_parsed = YES;
2.27 frystyk 568: me->transparent = YES; /* Pump rest of data right through */
569: return HT_OK;
2.1 timbl 570: }
571:
572:
2.18 frystyk 573: /*
574: ** Header is terminated by CRCR, LFLF, CRLFLF, CRLFCRLF
575: ** Folding is either of CF LWS, LF LWS, CRLF LWS
576: */
577: PRIVATE int HTMIME_put_block ARGS3(HTStream *, me, CONST char *, b, int, l)
578: {
579: while (!me->transparent && l-- > 0) {
580: if (me->EOLstate == EOL_FCR) {
2.27 frystyk 581: if (*b == CR) { /* End of header */
2.32 frystyk 582: int status = parseheader(me, me->request, me->anchor);
583: me->net->bytes_read = l;
2.27 frystyk 584: if (status != HT_OK)
585: return status;
586: } else if (*b == LF) /* CRLF */
2.18 frystyk 587: me->EOLstate = EOL_FLF;
588: else if (WHITE(*b)) { /* Folding: CR SP */
589: me->EOLstate = EOL_BEGIN;
590: HTChunkPutc(me->buffer, ' ');
591: } else { /* New line */
592: me->EOLstate = EOL_BEGIN;
593: HTChunkPutc(me->buffer, '\0');
594: HTChunkPutc(me->buffer, *b);
595: }
596: } else if (me->EOLstate == EOL_FLF) {
597: if (*b == CR) /* LF CR or CR LF CR */
598: me->EOLstate = EOL_SCR;
2.27 frystyk 599: else if (*b == LF) { /* End of header */
2.32 frystyk 600: int status = parseheader(me, me->request, me->anchor);
601: me->net->bytes_read = l;
2.27 frystyk 602: if (status != HT_OK)
603: return status;
604: } else if (WHITE(*b)) { /* Folding: LF SP or CR LF SP */
2.18 frystyk 605: me->EOLstate = EOL_BEGIN;
606: HTChunkPutc(me->buffer, ' ');
607: } else { /* New line */
608: me->EOLstate = EOL_BEGIN;
609: HTChunkPutc(me->buffer, '\0');
610: HTChunkPutc(me->buffer, *b);
611: }
612: } else if (me->EOLstate == EOL_SCR) {
2.27 frystyk 613: if (*b==CR || *b==LF) { /* End of header */
2.32 frystyk 614: int status = parseheader(me, me->request, me->anchor);
615: me->net->bytes_read = l;
2.27 frystyk 616: if (status != HT_OK)
617: return status;
618: } else if (WHITE(*b)) { /* Folding: LF CR SP or CR LF CR SP */
2.18 frystyk 619: me->EOLstate = EOL_BEGIN;
620: HTChunkPutc(me->buffer, ' ');
621: } else { /* New line */
622: me->EOLstate = EOL_BEGIN;
623: HTChunkPutc(me->buffer, '\0');
624: HTChunkPutc(me->buffer, *b);
625: }
626: } else if (*b == CR) {
627: me->EOLstate = EOL_FCR;
628: } else if (*b == LF) {
629: me->EOLstate = EOL_FLF; /* Line found */
630: } else
631: HTChunkPutc(me->buffer, *b);
632: b++;
633: }
2.32 frystyk 634:
635: /*
636: ** Put the rest down the stream without touching the data but make sure
637: ** that we get the correct content length of data
638: */
2.34 ! frystyk 639: if (l > 0) {
! 640: if (me->target) {
! 641: int status = (*me->target->isa->put_block)(me->target, b, l);
! 642: if (status == HT_OK)
! 643: return (me->net->bytes_read >= me->anchor->content_length) ?
! 644: HT_LOADED : HT_OK;
! 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.21 frystyk 657: PRIVATE int HTMIME_put_character ARGS2(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.18 frystyk 666: PRIVATE int HTMIME_put_string ARGS2(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.18 frystyk 675: PRIVATE int HTMIME_flush ARGS1(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.14 frystyk 683: PRIVATE int HTMIME_free ARGS1(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.14 frystyk 699: PRIVATE int HTMIME_abort ARGS2(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.7 timbl 731: PUBLIC HTStream* HTMIMEConvert ARGS5(
732: HTRequest *, request,
733: void *, param,
734: HTFormat, input_format,
735: HTFormat, output_format,
736: HTStream *, output_stream)
2.1 timbl 737: {
738: HTStream* me;
2.18 frystyk 739: if ((me=(HTStream *) calloc(1, sizeof(* me))) == NULL)
740: outofmem(__FILE__, "HTMIMEConvert");
2.1 timbl 741: me->isa = &HTMIME;
2.18 frystyk 742: me->request = request;
2.32 frystyk 743: me->anchor = request->anchor;
744: me->net = request->net;
2.18 frystyk 745: me->target = output_stream;
746: me->target_format = output_format;
747: me->buffer = HTChunkCreate(512);
748: me->EOLstate = EOL_BEGIN;
2.1 timbl 749: return me;
750: }
2.32 frystyk 751:
Webmaster