Annotation of libwww/Library/src/HTMIME.c, revision 2.44

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;
2.44    ! frystyk   530:     if (request->access || request->method == METHOD_HEAD) return HT_LOADED;
2.43      frystyk   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;
2.44    ! frystyk   567:                HTChunk_putc(me->buffer, ' ');
2.18      frystyk   568:            } else {                                             /* New line */
                    569:                me->EOLstate = EOL_BEGIN;
2.44    ! frystyk   570:                HTChunk_putc(me->buffer, '\0');
        !           571:                HTChunk_putc(me->buffer, *b);
2.18      frystyk   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;
2.44    ! frystyk   583:                HTChunk_putc(me->buffer, ' ');
2.18      frystyk   584:            } else {                                            /* New line */
                    585:                me->EOLstate = EOL_BEGIN;
2.44    ! frystyk   586:                HTChunk_putc(me->buffer, '\0');
        !           587:                HTChunk_putc(me->buffer, *b);
2.18      frystyk   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;
2.44    ! frystyk   597:                HTChunk_putc(me->buffer, ' ');
2.18      frystyk   598:            } else {                                            /* New line */
                    599:                me->EOLstate = EOL_BEGIN;
2.44    ! frystyk   600:                HTChunk_putc(me->buffer, '\0');
        !           601:                HTChunk_putc(me->buffer, *b);
2.18      frystyk   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
2.44    ! frystyk   608:            HTChunk_putc(me->buffer, *b);
2.18      frystyk   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.44    ! frystyk   672:     HTChunk_delete(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.44    ! frystyk   685:     HTChunk_delete(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;
2.44    ! frystyk   725:     me->buffer = HTChunk_new(512);
2.18      frystyk   726:     me->EOLstate = EOL_BEGIN;
2.1       timbl     727:     return me;
                    728: }
2.32      frystyk   729: 

Webmaster