Annotation of libwww/Library/src/HTMIME.c, revision 2.38
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)
2.37 frystyk 351: TTYPrint(TDEST, "MIMEParser.. Methods allowed: %d\n",
2.18 frystyk 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)
2.37 frystyk 370: TTYPrint(TDEST,"MIMEParser.. Persistent Connection!\n");
2.32 frystyk 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.38 ! frystyk 415: while ((value = HTNextField(&ptr)) != NULL) {
2.20 frystyk 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: }
2.38 ! frystyk 422: } else if (!strcasecomp(value, "level")) {
2.20 frystyk 423: if ((value = HTNextField(&ptr)) != NULL) {
424: lc = value;
425: while ((*lc = TOLOWER(*lc))) lc++;
426: anchor->level = HTAtom_for(value);
427: }
2.38 ! frystyk 428: } else if (!strcasecomp(value, "boundary")) {
! 429: if ((value = HTNextField(&ptr)) != NULL) {
! 430: StrAllocCopy(request->boundary, value);
! 431: }
2.20 frystyk 432: }
433: }
2.1 timbl 434: }
2.20 frystyk 435: state = JUNK_LINE;
2.18 frystyk 436: break;
437:
2.23 frystyk 438: case MIME_DATE:
2.18 frystyk 439: anchor->date = HTParseTime(ptr);
440: state = JUNK_LINE;
441: break;
442:
443: case DERIVED_FROM:
444: if ((value = HTNextField(&ptr)) != NULL)
445: StrAllocCopy(anchor->derived_from, value);
446: state = JUNK_LINE;
447: break;
448:
449: case EXPIRES:
450: anchor->expires = HTParseTime(ptr);
451: state = JUNK_LINE;
452: break;
453:
454: case LAST_MODIFIED:
455: anchor->last_modified = HTParseTime(ptr);
456: state = JUNK_LINE;
457: break;
458:
459: case LINK:
2.20 frystyk 460: state = UNKNOWN; /* @@@@@@@@@@@ */
2.18 frystyk 461: break;
462:
463: case LOCATION:
2.31 frystyk 464: #if 0
465: /*
466: ** Doesn't work as a redirection header might contain a '='
467: ** Thanks to mitch@tam.net (Mitch DeShields)
468: */
2.18 frystyk 469: if ((value = HTNextField(&ptr)) != NULL)
470: StrAllocCopy(request->redirect, value);
2.31 frystyk 471: #endif
472: StrAllocCopy(request->redirect, ptr);
2.18 frystyk 473: state = JUNK_LINE;
474: break;
475:
476: case PUBLIC_METHODS:
2.20 frystyk 477: state = UNKNOWN; /* @@@@@@@@@@@ */
2.18 frystyk 478: break;
479:
480: case RETRY_AFTER:
2.19 frystyk 481: request->retry_after = HTParseTime(ptr);
482: state = JUNK_LINE;
2.18 frystyk 483: break;
484:
485: case TITLE: /* Can't reuse buffer as HTML version might differ */
486: if ((value = HTNextField(&ptr)) != NULL)
487: StrAllocCopy(anchor->title, value);
488: state = JUNK_LINE;
489: break;
490:
491: case URI_HEADER:
492: state = LOCATION; /* @@@ Need extended parsing */
493: break;
494:
495: case VERSION:
496: if ((value = HTNextField(&ptr)) != NULL)
497: StrAllocCopy(anchor->version, value);
498: state = JUNK_LINE;
499: break;
500:
501: case UNKNOWN:
2.36 frystyk 502: if ((value = HTNextField(&ptr)) != NULL) {
503: HTList * list;
504: HTParserCallback *cbf;
505: int status;
506: BOOL override;
507: if (STREAM_TRACE)
2.38 ! frystyk 508: TTYPrint(TDEST,"MIMEParser.. Unknown `%s\'\n", header);
2.36 frystyk 509: if ((list = HTRequest_parser(request, &override)) &&
510: (cbf = HTParser_find(list, value)) &&
511: (status = (*cbf)(request, value) != HT_OK)) {
512: return status;
513: } else if (!override &&
514: (list = HTHeader_parser()) &&
515: (cbf = HTParser_find(list, value)) &&
516: (status = (*cbf)(request, value) != HT_OK)) {
517: return status;
518: }
519: }
2.18 frystyk 520:
521: case JUNK_LINE:
522: while (*ptr) ptr++;
523: state = BEGINNING_OF_LINE;
524: break;
2.1 timbl 525: }
2.18 frystyk 526: }
527:
2.34 frystyk 528: #if 0
2.27 frystyk 529: /*
530: ** If coming from cache then check if the document has expired. We can
531: ** either ignore this or attempt a reload
532: */
533: {
534: char *msg;
2.31 frystyk 535: HTExpiresMode expire_mode = HTCache_expiresMode(&msg);
2.27 frystyk 536: if (expire_mode != HT_EXPIRES_IGNORE) {
537: time_t cur = time(NULL);
538: if (anchor->expires>0 && cur>0 && anchor->expires<cur) {
539: if (expire_mode == HT_EXPIRES_NOTIFY)
2.28 frystyk 540: HTAlert(request, msg);
2.31 frystyk 541: else if (HTRequest_retry(request)) {
2.27 frystyk 542: if (PROT_TRACE)
2.37 frystyk 543: TTYPrint(TDEST, "MIMEParser.. Expired - auto reload\n");
2.27 frystyk 544: if (anchor->cacheHit) {
2.31 frystyk 545: HTRequest_addRqHd(request, HT_IMS);
546: HTRequest_setReloadMode(request, HT_FORCE_RELOAD);
2.27 frystyk 547: anchor->cacheHit = NO; /* Don't want to loop */
548: }
549: return HT_RELOAD;
550: }
551: }
552: }
553: }
2.34 frystyk 554: #endif
2.27 frystyk 555:
2.35 frystyk 556: /* News server almost never send content type or content length */
557: if (anchor->content_type != WWW_UNKNOWN || me->nntp) {
2.18 frystyk 558: if (STREAM_TRACE)
2.37 frystyk 559: TTYPrint(TDEST, "MIMEParser.. Convert %s to %s\n",
2.30 frystyk 560: HTAtom_name(anchor->content_type),
561: HTAtom_name(me->target_format));
562: if ((me->target=HTStreamStack(anchor->content_type, me->target_format,
563: me->target, request, YES)) == NULL) {
564: if (STREAM_TRACE)
2.37 frystyk 565: TTYPrint(TDEST, "MIMEParser.. Can't convert media type\n");
2.30 frystyk 566: me->target = HTBlackHole();
567: }
2.18 frystyk 568: }
569: anchor->header_parsed = YES;
2.27 frystyk 570: me->transparent = YES; /* Pump rest of data right through */
571: return HT_OK;
2.1 timbl 572: }
573:
574:
2.18 frystyk 575: /*
576: ** Header is terminated by CRCR, LFLF, CRLFLF, CRLFCRLF
577: ** Folding is either of CF LWS, LF LWS, CRLF LWS
578: */
2.36 frystyk 579: PRIVATE int HTMIME_put_block (HTStream * me, CONST char * b, int l)
2.18 frystyk 580: {
581: while (!me->transparent && l-- > 0) {
582: if (me->EOLstate == EOL_FCR) {
2.27 frystyk 583: if (*b == CR) { /* End of header */
2.32 frystyk 584: int status = parseheader(me, me->request, me->anchor);
585: me->net->bytes_read = l;
2.27 frystyk 586: if (status != HT_OK)
587: return status;
588: } else if (*b == LF) /* CRLF */
2.18 frystyk 589: me->EOLstate = EOL_FLF;
590: else if (WHITE(*b)) { /* Folding: CR SP */
591: me->EOLstate = EOL_BEGIN;
592: HTChunkPutc(me->buffer, ' ');
593: } else { /* New line */
594: me->EOLstate = EOL_BEGIN;
595: HTChunkPutc(me->buffer, '\0');
596: HTChunkPutc(me->buffer, *b);
597: }
598: } else if (me->EOLstate == EOL_FLF) {
599: if (*b == CR) /* LF CR or CR LF CR */
600: me->EOLstate = EOL_SCR;
2.27 frystyk 601: else if (*b == LF) { /* End of header */
2.32 frystyk 602: int status = parseheader(me, me->request, me->anchor);
603: me->net->bytes_read = l;
2.27 frystyk 604: if (status != HT_OK)
605: return status;
606: } else if (WHITE(*b)) { /* Folding: LF SP or CR LF SP */
2.18 frystyk 607: me->EOLstate = EOL_BEGIN;
608: HTChunkPutc(me->buffer, ' ');
609: } else { /* New line */
610: me->EOLstate = EOL_BEGIN;
611: HTChunkPutc(me->buffer, '\0');
612: HTChunkPutc(me->buffer, *b);
613: }
614: } else if (me->EOLstate == EOL_SCR) {
2.27 frystyk 615: if (*b==CR || *b==LF) { /* End of header */
2.32 frystyk 616: int status = parseheader(me, me->request, me->anchor);
617: me->net->bytes_read = l;
2.27 frystyk 618: if (status != HT_OK)
619: return status;
620: } else if (WHITE(*b)) { /* Folding: LF CR SP or CR LF CR SP */
2.18 frystyk 621: me->EOLstate = EOL_BEGIN;
622: HTChunkPutc(me->buffer, ' ');
623: } else { /* New line */
624: me->EOLstate = EOL_BEGIN;
625: HTChunkPutc(me->buffer, '\0');
626: HTChunkPutc(me->buffer, *b);
627: }
628: } else if (*b == CR) {
629: me->EOLstate = EOL_FCR;
630: } else if (*b == LF) {
631: me->EOLstate = EOL_FLF; /* Line found */
632: } else
633: HTChunkPutc(me->buffer, *b);
634: b++;
635: }
2.32 frystyk 636:
637: /*
638: ** Put the rest down the stream without touching the data but make sure
639: ** that we get the correct content length of data
640: */
2.34 frystyk 641: if (l > 0) {
642: if (me->target) {
643: int status = (*me->target->isa->put_block)(me->target, b, l);
644: if (status == HT_OK)
2.36 frystyk 645: /* Check is CL at all - thanks to jwei@hal.com (John Wei) */
646: return (me->anchor->content_length &&
647: me->net->bytes_read >= me->anchor->content_length) ?
648: HT_LOADED : HT_OK;
2.34 frystyk 649: else
650: return status;
651: } else
652: return HT_WOULD_BLOCK;
2.32 frystyk 653: }
2.34 frystyk 654: return HT_OK;
2.18 frystyk 655: }
656:
657:
658: /* Character handling
659: ** ------------------
660: */
2.36 frystyk 661: PRIVATE int HTMIME_put_character (HTStream * me, char c)
2.18 frystyk 662: {
663: return HTMIME_put_block(me, &c, 1);
664: }
665:
2.1 timbl 666:
667: /* String handling
668: ** ---------------
669: */
2.36 frystyk 670: PRIVATE int HTMIME_put_string (HTStream * me, CONST char * s)
2.1 timbl 671: {
2.18 frystyk 672: return HTMIME_put_block(me, s, (int) strlen(s));
2.1 timbl 673: }
674:
675:
2.18 frystyk 676: /* Flush an stream object
677: ** ---------------------
2.1 timbl 678: */
2.36 frystyk 679: PRIVATE int HTMIME_flush (HTStream * me)
2.1 timbl 680: {
2.18 frystyk 681: return (*me->target->isa->flush)(me->target);
2.1 timbl 682: }
683:
2.18 frystyk 684: /* Free a stream object
685: ** --------------------
2.1 timbl 686: */
2.36 frystyk 687: PRIVATE int HTMIME_free (HTStream * me)
2.1 timbl 688: {
2.18 frystyk 689: int status = HT_OK;
2.25 frystyk 690: if (me->target) {
691: if ((status = (*me->target->isa->_free)(me->target))==HT_WOULD_BLOCK)
692: return HT_WOULD_BLOCK;
693: }
2.26 frystyk 694: if (PROT_TRACE)
2.37 frystyk 695: TTYPrint(TDEST, "MIME........ FREEING....\n");
2.19 frystyk 696: HTChunkFree(me->buffer);
2.1 timbl 697: free(me);
2.18 frystyk 698: return status;
2.1 timbl 699: }
700:
701: /* End writing
702: */
2.38 ! frystyk 703: PRIVATE int HTMIME_abort (HTStream * me, HTList * e)
2.1 timbl 704: {
2.18 frystyk 705: int status = HT_ERROR;
706: if (me->target)
707: status = (*me->target->isa->abort)(me->target, e);
2.26 frystyk 708: if (PROT_TRACE)
2.37 frystyk 709: TTYPrint(TDEST, "MIME........ ABORTING...\n");
2.26 frystyk 710: HTChunkFree(me->buffer);
2.6 timbl 711: free(me);
2.18 frystyk 712: return status;
2.1 timbl 713: }
714:
715:
716:
717: /* Structured Object Class
718: ** -----------------------
719: */
2.6 timbl 720: PRIVATE CONST HTStreamClass HTMIME =
2.1 timbl 721: {
722: "MIMEParser",
2.18 frystyk 723: HTMIME_flush,
2.1 timbl 724: HTMIME_free,
2.6 timbl 725: HTMIME_abort,
726: HTMIME_put_character,
727: HTMIME_put_string,
2.18 frystyk 728: HTMIME_put_block
2.1 timbl 729: };
730:
731:
732: /* Subclass-specific Methods
733: ** -------------------------
734: */
2.36 frystyk 735: PUBLIC HTStream* HTMIMEConvert (HTRequest * request,
736: void * param,
737: HTFormat input_format,
738: HTFormat output_format,
739: HTStream * output_stream)
2.1 timbl 740: {
741: HTStream* me;
2.18 frystyk 742: if ((me=(HTStream *) calloc(1, sizeof(* me))) == NULL)
743: outofmem(__FILE__, "HTMIMEConvert");
2.1 timbl 744: me->isa = &HTMIME;
2.18 frystyk 745: me->request = request;
2.32 frystyk 746: me->anchor = request->anchor;
747: me->net = request->net;
2.18 frystyk 748: me->target = output_stream;
749: me->target_format = output_format;
750: me->buffer = HTChunkCreate(512);
751: me->EOLstate = EOL_BEGIN;
2.1 timbl 752: return me;
753: }
2.32 frystyk 754:
Webmaster