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

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;
2.41    ! frystyk   711:     if (me->target) status = (*me->target->isa->abort)(me->target, e);
2.26      frystyk   712:     if (PROT_TRACE)
2.37      frystyk   713:        TTYPrint(TDEST, "MIME........ ABORTING...\n");
2.26      frystyk   714:     HTChunkFree(me->buffer);
2.6       timbl     715:     free(me);
2.18      frystyk   716:     return status;
2.1       timbl     717: }
                    718: 
                    719: 
                    720: 
                    721: /*     Structured Object Class
                    722: **     -----------------------
                    723: */
2.6       timbl     724: PRIVATE CONST HTStreamClass HTMIME =
2.1       timbl     725: {              
                    726:        "MIMEParser",
2.18      frystyk   727:        HTMIME_flush,
2.1       timbl     728:        HTMIME_free,
2.6       timbl     729:        HTMIME_abort,
                    730:        HTMIME_put_character,
                    731:        HTMIME_put_string,
2.18      frystyk   732:        HTMIME_put_block
2.1       timbl     733: }; 
                    734: 
                    735: 
                    736: /*     Subclass-specific Methods
                    737: **     -------------------------
                    738: */
2.36      frystyk   739: PUBLIC HTStream* HTMIMEConvert (HTRequest *    request,
                    740:                                void *          param,
                    741:                                HTFormat        input_format,
                    742:                                HTFormat        output_format,
                    743:                                HTStream *      output_stream)
2.1       timbl     744: {
                    745:     HTStream* me;
2.18      frystyk   746:     if ((me=(HTStream *) calloc(1, sizeof(* me))) == NULL)
                    747:        outofmem(__FILE__, "HTMIMEConvert");
2.1       timbl     748:     me->isa = &HTMIME;       
2.18      frystyk   749:     me->request = request;
2.32      frystyk   750:     me->anchor = request->anchor;
                    751:     me->net = request->net;
2.18      frystyk   752:     me->target = output_stream;
                    753:     me->target_format = output_format;
                    754:     me->buffer = HTChunkCreate(512);
                    755:     me->EOLstate = EOL_BEGIN;
2.1       timbl     756:     return me;
                    757: }
2.32      frystyk   758: 

Webmaster