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

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

Webmaster