Annotation of libwww/Library/src/HTMIME.c, revision 2.40
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.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.37 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: #if 0
2.36 frystyk 504: if ((value = HTNextField(&ptr)) != NULL) {
2.40 ! frystyk 505: #else
! 506: {
! 507: #endif
2.36 frystyk 508: HTList * list;
509: HTParserCallback *cbf;
510: int status;
511: BOOL override;
512: if (STREAM_TRACE)
2.38 frystyk 513: TTYPrint(TDEST,"MIMEParser.. Unknown `%s\'\n", header);
2.36 frystyk 514: if ((list = HTRequest_parser(request, &override)) &&
2.40 ! frystyk 515: (cbf = HTParser_find(list, header)) &&
! 516: (status = (*cbf)(request, header) != HT_OK)) {
2.36 frystyk 517: return status;
518: } else if (!override &&
519: (list = HTHeader_parser()) &&
2.40 ! frystyk 520: (cbf = HTParser_find(list, header)) &&
! 521: (status = (*cbf)(request, header) != HT_OK)) {
2.36 frystyk 522: return status;
523: }
524: }
2.18 frystyk 525:
526: case JUNK_LINE:
527: while (*ptr) ptr++;
528: state = BEGINNING_OF_LINE;
529: break;
2.1 timbl 530: }
2.18 frystyk 531: }
532:
2.34 frystyk 533: #if 0
2.27 frystyk 534: /*
535: ** If coming from cache then check if the document has expired. We can
536: ** either ignore this or attempt a reload
537: */
538: {
539: char *msg;
2.31 frystyk 540: HTExpiresMode expire_mode = HTCache_expiresMode(&msg);
2.27 frystyk 541: if (expire_mode != HT_EXPIRES_IGNORE) {
542: time_t cur = time(NULL);
543: if (anchor->expires>0 && cur>0 && anchor->expires<cur) {
544: if (expire_mode == HT_EXPIRES_NOTIFY)
2.28 frystyk 545: HTAlert(request, msg);
2.31 frystyk 546: else if (HTRequest_retry(request)) {
2.27 frystyk 547: if (PROT_TRACE)
2.37 frystyk 548: TTYPrint(TDEST, "MIMEParser.. Expired - auto reload\n");
2.27 frystyk 549: if (anchor->cacheHit) {
2.31 frystyk 550: HTRequest_addRqHd(request, HT_IMS);
551: HTRequest_setReloadMode(request, HT_FORCE_RELOAD);
2.27 frystyk 552: anchor->cacheHit = NO; /* Don't want to loop */
553: }
554: return HT_RELOAD;
555: }
556: }
557: }
558: }
2.34 frystyk 559: #endif
2.27 frystyk 560:
2.35 frystyk 561: /* News server almost never send content type or content length */
562: if (anchor->content_type != WWW_UNKNOWN || me->nntp) {
2.18 frystyk 563: if (STREAM_TRACE)
2.37 frystyk 564: TTYPrint(TDEST, "MIMEParser.. Convert %s to %s\n",
2.30 frystyk 565: HTAtom_name(anchor->content_type),
566: HTAtom_name(me->target_format));
567: if ((me->target=HTStreamStack(anchor->content_type, me->target_format,
568: me->target, request, YES)) == NULL) {
569: if (STREAM_TRACE)
2.37 frystyk 570: TTYPrint(TDEST, "MIMEParser.. Can't convert media type\n");
2.30 frystyk 571: me->target = HTBlackHole();
572: }
2.18 frystyk 573: }
574: anchor->header_parsed = YES;
2.27 frystyk 575: me->transparent = YES; /* Pump rest of data right through */
576: return HT_OK;
2.1 timbl 577: }
578:
579:
2.18 frystyk 580: /*
581: ** Header is terminated by CRCR, LFLF, CRLFLF, CRLFCRLF
582: ** Folding is either of CF LWS, LF LWS, CRLF LWS
583: */
2.36 frystyk 584: PRIVATE int HTMIME_put_block (HTStream * me, CONST char * b, int l)
2.18 frystyk 585: {
586: while (!me->transparent && l-- > 0) {
587: if (me->EOLstate == EOL_FCR) {
2.27 frystyk 588: if (*b == CR) { /* End of header */
2.32 frystyk 589: int status = parseheader(me, me->request, me->anchor);
590: me->net->bytes_read = l;
2.27 frystyk 591: if (status != HT_OK)
592: return status;
593: } else if (*b == LF) /* CRLF */
2.18 frystyk 594: me->EOLstate = EOL_FLF;
595: else if (WHITE(*b)) { /* Folding: CR SP */
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 (me->EOLstate == EOL_FLF) {
604: if (*b == CR) /* LF CR or CR LF CR */
605: me->EOLstate = EOL_SCR;
2.27 frystyk 606: else if (*b == LF) { /* End of header */
2.32 frystyk 607: int status = parseheader(me, me->request, me->anchor);
608: me->net->bytes_read = l;
2.27 frystyk 609: if (status != HT_OK)
610: return status;
611: } else if (WHITE(*b)) { /* Folding: LF SP or CR LF SP */
2.18 frystyk 612: me->EOLstate = EOL_BEGIN;
613: HTChunkPutc(me->buffer, ' ');
614: } else { /* New line */
615: me->EOLstate = EOL_BEGIN;
616: HTChunkPutc(me->buffer, '\0');
617: HTChunkPutc(me->buffer, *b);
618: }
619: } else if (me->EOLstate == EOL_SCR) {
2.27 frystyk 620: if (*b==CR || *b==LF) { /* End of header */
2.32 frystyk 621: int status = parseheader(me, me->request, me->anchor);
622: me->net->bytes_read = l;
2.27 frystyk 623: if (status != HT_OK)
624: return status;
625: } else if (WHITE(*b)) { /* Folding: LF CR SP or CR LF CR SP */
2.18 frystyk 626: me->EOLstate = EOL_BEGIN;
627: HTChunkPutc(me->buffer, ' ');
628: } else { /* New line */
629: me->EOLstate = EOL_BEGIN;
630: HTChunkPutc(me->buffer, '\0');
631: HTChunkPutc(me->buffer, *b);
632: }
633: } else if (*b == CR) {
634: me->EOLstate = EOL_FCR;
635: } else if (*b == LF) {
636: me->EOLstate = EOL_FLF; /* Line found */
637: } else
638: HTChunkPutc(me->buffer, *b);
639: b++;
640: }
2.32 frystyk 641:
642: /*
643: ** Put the rest down the stream without touching the data but make sure
644: ** that we get the correct content length of data
645: */
2.34 frystyk 646: if (l > 0) {
647: if (me->target) {
648: int status = (*me->target->isa->put_block)(me->target, b, l);
649: if (status == HT_OK)
2.39 frystyk 650: /* Check if CL at all - thanks to jwei@hal.com (John Wei) */
651: return (me->anchor->content_length >= 0 &&
2.36 frystyk 652: me->net->bytes_read >= me->anchor->content_length) ?
653: HT_LOADED : HT_OK;
2.34 frystyk 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.36 frystyk 666: PRIVATE int HTMIME_put_character (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.36 frystyk 675: PRIVATE int HTMIME_put_string (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.36 frystyk 684: PRIVATE int HTMIME_flush (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.36 frystyk 692: PRIVATE int HTMIME_free (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)
2.37 frystyk 700: TTYPrint(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.38 frystyk 708: PRIVATE int HTMIME_abort (HTStream * me, HTList * 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)
2.37 frystyk 714: TTYPrint(TDEST, "MIME........ ABORTING...\n");
2.26 frystyk 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.36 frystyk 740: PUBLIC HTStream* HTMIMEConvert (HTRequest * request,
741: void * param,
742: HTFormat input_format,
743: HTFormat output_format,
744: HTStream * output_stream)
2.1 timbl 745: {
746: HTStream* me;
2.18 frystyk 747: if ((me=(HTStream *) calloc(1, sizeof(* me))) == NULL)
748: outofmem(__FILE__, "HTMIMEConvert");
2.1 timbl 749: me->isa = &HTMIME;
2.18 frystyk 750: me->request = request;
2.32 frystyk 751: me->anchor = request->anchor;
752: me->net = request->net;
2.18 frystyk 753: me->target = output_stream;
754: me->target_format = output_format;
755: me->buffer = HTChunkCreate(512);
756: me->EOLstate = EOL_BEGIN;
2.1 timbl 757: return me;
758: }
2.32 frystyk 759:
Webmaster