Annotation of libwww/Library/src/HTMIMImp.c, revision 2.23

2.1       frystyk     1: /*
2.8       frystyk     2: **     DEFAULT MIME HEADER PARSERS
2.1       frystyk     3: **
                      4: **     (c) COPYRIGHT MIT 1995.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
2.23    ! kahan       6: **     @(#) $Id: HTMIMImp.c,v 1.3 1998/12/15 12:50:21 cvs Exp $
2.1       frystyk     7: **
                      8: **     This module contains the default MIME header parsers for the MIME
                      9: **     parser in HTMIME.c. They are all initialized at run time and can hence
                     10: **     be replaced or extended with your own set.
                     11: **
                     12: ** History:
                     13: **        Jun 96  HFN  Written
2.23    ! kahan      14: **         Dec 98  JKO  Added support for message-digest authentication
2.1       frystyk    15: */
                     16: 
                     17: /* Library include files */
2.21      frystyk    18: #include "wwwsys.h"
2.1       frystyk    19: #include "WWWUtil.h"
                     20: #include "WWWCore.h"
                     21: #include "HTHeader.h"
2.10      frystyk    22: #include "HTTPUtil.h"
2.1       frystyk    23: #include "HTMIMImp.h"                                   /* Implemented here */
                     24: 
                     25: /* ------------------------------------------------------------------------- */
                     26: 
2.8       frystyk    27: PUBLIC int HTMIME_accept (HTRequest * request, HTResponse * response,
                     28:                          char * token, char * value)
2.1       frystyk    29: {
                     30: 
                     31:     return HT_OK;
                     32: }
                     33: 
2.8       frystyk    34: PUBLIC int HTMIME_acceptCharset (HTRequest * request, HTResponse * response,
                     35:                                 char * token, char * value)
2.1       frystyk    36: {
                     37: 
                     38:     return HT_OK;
                     39: }
                     40: 
2.8       frystyk    41: PUBLIC int HTMIME_acceptEncoding (HTRequest * request, HTResponse * response,
                     42:                                  char * token, char * value)
2.1       frystyk    43: {
                     44: 
                     45:     return HT_OK;
                     46: }
                     47: 
2.8       frystyk    48: PUBLIC int HTMIME_acceptLanguage (HTRequest * request, HTResponse * response,
                     49:                                  char * token, char * value)
2.1       frystyk    50: {
                     51: 
                     52:     return HT_OK;
                     53: }
                     54: 
2.8       frystyk    55: PUBLIC int HTMIME_acceptRanges (HTRequest * request, HTResponse * response,
                     56:                                char * token, char * value)
2.1       frystyk    57: {
2.8       frystyk    58:     if (value) {
                     59:        HTNet * net = HTRequest_net(request);
                     60:        HTHost * host = HTNet_host(net);
                     61:        HTHost_setRangeUnits(host, value);
2.1       frystyk    62:     }
                     63:     return HT_OK;
                     64: }
                     65: 
2.8       frystyk    66: PUBLIC int HTMIME_authenticate (HTRequest * request, HTResponse * response,
                     67:                                char * token, char * value)
2.3       frystyk    68: {    
                     69:     char * scheme = HTNextField(&value);
2.4       frystyk    70:     if (scheme) {
2.8       frystyk    71:        HTResponse_addChallenge(response, scheme, value);
                     72:        HTResponse_setScheme(response, scheme);
2.4       frystyk    73:     }
2.3       frystyk    74:     return HT_OK;
                     75: }
                     76: 
2.23    ! kahan      77: /* @@@ WARNING: The following function hasn't been thoroughly tested yet */
        !            78: PUBLIC int HTMIME_authenticationInfo (HTRequest * request, 
        !            79:                                      HTResponse * response,
        !            80:                                       char * token, char * value)
        !            81: {
        !            82:   /* deal here with the next nonce, the qop, and the digest response (mutual
        !            83:      authentication  */  
        !            84:   if (value) {
        !            85:     if (PROT_TRACE)
        !            86:       HTTrace("Protocol.... Authentication-Info: `%s\', value: `%s\'\n",
        !            87:              value);
        !            88:     HTDigest_refresh (request, response, FALSE, value);
        !            89:   }    
        !            90:   return HT_OK;
        !            91: }
        !            92: 
2.8       frystyk    93: PUBLIC int HTMIME_authorization (HTRequest * request, HTResponse * response,
                     94:                                 char * token, char * value)
2.1       frystyk    95: {
                     96: 
                     97:     return HT_OK;
                     98: }
                     99: 
2.8       frystyk   100: PUBLIC int HTMIME_cacheControl (HTRequest * request, HTResponse * response,
                    101:                                char * token, char * value)
2.1       frystyk   102: {
2.7       frystyk   103:     /*
                    104:     **  Walk through the set of cache-control directives and add them to the
                    105:     **  response association list for cache control directives
                    106:     */
                    107:     char * name_val;
                    108:     while ((name_val = HTNextPair(&value)) != NULL) {
                    109:        char * name = HTNextField(&name_val);
                    110:        char * val = HTNextField(&name_val);
2.8       frystyk   111:        if (name) HTResponse_addCacheControl(response, name, val ? val : "");
2.7       frystyk   112:     }
2.1       frystyk   113:     return HT_OK;
                    114: }
                    115: 
2.8       frystyk   116: PUBLIC int HTMIME_connection (HTRequest * request, HTResponse * response,
                    117:                              char * token, char * value)
2.1       frystyk   118: {
2.7       frystyk   119:     /*
                    120:     **  Walk through the set of connection directives and add them to the
                    121:     **  response association list for connection directives
                    122:     */
                    123:     char * name_val;
                    124:     while ((name_val = HTNextPair(&value)) != NULL) {
                    125:        char * name = HTNextField(&name_val);
                    126:        char * val = HTNextField(&name_val);
                    127: 
                    128:        /*
                    129:        **  If we have a name then look if it is concerning persistent
                    130:        **  connections. If so, then we handle it here, otherwise we leave it
                    131:        **  to somebody else by simply adding it to the list of connection
                    132:        **  tokens.
                    133:        */
                    134:        if (name) {
2.15      frystyk   135:            HTNet * net = HTRequest_net(request);
                    136:            HTHost * host = HTNet_host(net);
2.7       frystyk   137:            if (!strcasecomp(name, "close")) {                   /* HTTP/1.1 */
2.11      frystyk   138:                if (STREAM_TRACE) HTTrace("MIMEParser.. Close received...\n");
2.15      frystyk   139:                HTHost_setCloseNotification(host, YES);
2.7       frystyk   140:            } else if (!strcasecomp(name, "keep-alive")) {       /* HTTP/1.0 */
2.10      frystyk   141: 
                    142:                /*
                    143:                **  In case this is an HTTP/1.1 server sending keep-alive then
                    144:                **  ignore it.
                    145:                */
                    146:                if (HTHost_version(host) < HTTP_11) {
                    147:                    HTNet_setPersistent(net, YES, HT_TP_SINGLE);
                    148:                    if (STREAM_TRACE) HTTrace("MIMEParser.. HTTP/1.0 Keep Alive\n");
                    149:                } else 
                    150:                    if (STREAM_TRACE) HTTrace("MIMEParser.. HTTP/1.0 Keep Alive ignored\n");
2.7       frystyk   151:            } else
2.8       frystyk   152:                HTResponse_addConnection(response, name, val ? val : "");
2.1       frystyk   153:        }
                    154:     }
                    155:     return HT_OK;
                    156: }
                    157: 
2.8       frystyk   158: PUBLIC int HTMIME_contentEncoding (HTRequest * request, HTResponse * response,
                    159:                                   char * token, char * value)
2.1       frystyk   160: {
                    161:     char * field;
                    162:     while ((field = HTNextField(&value)) != NULL) {
                    163:         char * lc = field;
                    164:        while ((*lc = TOLOWER(*lc))) lc++;
2.8       frystyk   165:        HTResponse_addEncoding(response, HTAtom_for(field));
2.1       frystyk   166:     }
                    167:     return HT_OK;
                    168: }
                    169: 
2.8       frystyk   170: PUBLIC int HTMIME_contentLength (HTRequest * request, HTResponse * response,
                    171:                                 char * token, char * value)
2.1       frystyk   172: {
                    173:     char * field;
                    174:     if ((field = HTNextField(&value)) != NULL)
2.8       frystyk   175:         HTResponse_setLength(response, atol(field));
2.1       frystyk   176:     return HT_OK;
                    177: }
                    178: 
2.8       frystyk   179: PUBLIC int HTMIME_contentRange (HTRequest * request, HTResponse * response,
                    180:                                char * token, char * value)
2.1       frystyk   181: {
2.2       frystyk   182:     char * field;
2.8       frystyk   183:     if ((field = HTNextField(&value)))
                    184:        HTResponse_addRange(response, field, value);
2.1       frystyk   185:     return HT_OK;
                    186: }
                    187: 
2.8       frystyk   188: PUBLIC int HTMIME_contentTransferEncoding (HTRequest * request, HTResponse * response,
                    189:                                           char * token, char * value)
2.1       frystyk   190: {
                    191:     char * field;
                    192:     if ((field = HTNextField(&value)) != NULL) {
                    193:         char *lc = field;
                    194:        while ((*lc = TOLOWER(*lc))) lc++;
2.20      frystyk   195:        HTResponse_setContentTransferEncoding(response, HTAtom_for(field));
2.1       frystyk   196:     }
                    197:     return HT_OK;
                    198: }
                    199: 
2.8       frystyk   200: PUBLIC int HTMIME_contentType (HTRequest * request, HTResponse * response,
                    201:                               char * token, char * value)
2.1       frystyk   202: {
                    203:     char * field;
                    204:     if ((field = HTNextField(&value)) != NULL) {
2.2       frystyk   205: 
                    206:        /* Get the Content-Type */
2.1       frystyk   207:         char *lc = field;
                    208:        while ((*lc = TOLOWER(*lc))) lc++; 
2.8       frystyk   209:        HTResponse_setFormat(response, HTAtom_for(field));
2.2       frystyk   210: 
                    211:        /* Get all the parameters to the Content-Type */
                    212:        {
                    213:            char * param;
                    214:            while ((field = HTNextField(&value)) != NULL &&
                    215:                   (param = HTNextField(&value)) != NULL) {
                    216:                lc = field;
                    217:                while ((*lc = TOLOWER(*lc))) lc++;
                    218:                lc = param;
                    219:                while ((*lc = TOLOWER(*lc))) lc++;
2.8       frystyk   220:                HTResponse_addFormatParam(response, field, param);
2.1       frystyk   221:            }
                    222:        }
2.12      eric      223:     }
                    224:     return HT_OK;
                    225: }
                    226: 
2.19      frystyk   227: #if 0
2.17      frystyk   228: PRIVATE int HTFindInt(char * haystack, char * needle, int deflt)
2.12      eric      229: {
                    230:     char * start = strstr(haystack, needle);
                    231:     int value = deflt;
                    232:     if (start != NULL) {
                    233:        start += strlen(needle);
                    234:        while isspace(*start) start++;
                    235:        if (isdigit(*start)) {
                    236:            char * end = start + 1;
                    237:            char save;
                    238:            while (isdigit(*end)) end++;
                    239:            save = *end;
                    240:            *end = 0;
                    241:            value = atoi(start);
                    242:            *end = save;
                    243:        }
                    244:     }
                    245:     return value;
                    246: }
2.19      frystyk   247: #endif
2.12      eric      248: 
                    249: PUBLIC int HTMIME_keepAlive (HTRequest * request, HTResponse * response,
                    250:                             char * token, char * value)
                    251: {
2.17      frystyk   252:     char * name_val;
                    253:     HTNet * net = HTRequest_net(request);
                    254:     HTHost * host = HTNet_host(net);
                    255:     while ((name_val = HTNextPair(&value)) != NULL) {
                    256:        char * name = HTNextField(&name_val);
                    257:        char * val = HTNextField(&name_val);
                    258:        if (!strcasecomp(name, "max") && val) {
                    259:            int max = atoi(val);
                    260:            if (STREAM_TRACE) HTTrace("MIMEParser.. Max %d requests pr connection\n", max);
                    261:            HTHost_setReqsPerConnection(host, max);
                    262:        } else if (!strcasecomp(name, "timeout") && val) {
                    263:            int timeout = atoi(val);
                    264:            if (STREAM_TRACE) HTTrace("MIMEParser.. Timeout after %d secs\n", timeout);
                    265:        }
2.1       frystyk   266:     }
                    267:     return HT_OK;
                    268: }
                    269: 
2.8       frystyk   270: PUBLIC int HTMIME_link (HTRequest * request, HTResponse * response,
                    271:                        char * token, char * value)
2.1       frystyk   272: {
                    273: 
                    274:     return HT_OK;
                    275: }
                    276: 
2.8       frystyk   277: PUBLIC int HTMIME_location (HTRequest * request, HTResponse * response,
                    278:                            char * token, char * value)
2.1       frystyk   279: {
2.18      frystyk   280:     HTAnchor * redirection = NULL;
                    281:     char * location = HTStrip(value);
                    282: 
                    283:     /*
                    284:     **  If not absolute URI (Error) then find the base
                    285:     */
                    286:     if (!HTURL_isAbsolute(location)) {
                    287:        char * base = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
                    288:        location = HTParse(location, base, PARSE_ALL);
                    289:        redirection = HTAnchor_findAddress(location);
                    290:        HT_FREE(base);
                    291:        HT_FREE(location);
                    292:     } else {
                    293:        redirection = HTAnchor_findAddress(location);
                    294:     }
2.8       frystyk   295:     HTResponse_setRedirection(response, redirection);
2.1       frystyk   296:     return HT_OK;
                    297: }
                    298: 
2.8       frystyk   299: PUBLIC int HTMIME_maxForwards (HTRequest * request, HTResponse * response,
                    300:                               char * token, char * value)
2.1       frystyk   301: {
                    302: 
2.6       frystyk   303:     return HT_OK;
                    304: }
                    305: 
2.8       frystyk   306: PUBLIC int HTMIME_messageDigest (HTRequest * request, HTResponse * response,
                    307:                                 char * token, char * value)
2.1       frystyk   308: {
2.8       frystyk   309:     HTResponse_addChallenge(response, "Digest-MessageDigest", value);
2.1       frystyk   310:     return HT_OK;
                    311: }
                    312: 
2.8       frystyk   313: PUBLIC int HTMIME_pragma (HTRequest * request, HTResponse * response,
                    314:                          char * token, char * value)
2.1       frystyk   315: {
2.8       frystyk   316:     /*
                    317:     **  Walk through the set of pragma directives and search for one that may
                    318:     **  affect the cachability of this object
2.2       frystyk   319:     */
2.8       frystyk   320:     char * name_val;
                    321:     while ((name_val = HTNextPair(&value)) != NULL) {
                    322:        char * name = HTNextField(&name_val);
                    323:        if (name) {
                    324:            if (!strcasecomp(name, "no-cache")) {
2.22      frystyk   325:                HTResponse_setCachable(response, HT_NO_CACHE);
2.8       frystyk   326:                if (STREAM_TRACE) HTTrace("MIMEParser.. No-Cache Pragma\n");
                    327:            }
                    328:        }
                    329:     }
2.1       frystyk   330:     return HT_OK;
                    331: }
                    332: 
2.8       frystyk   333: PUBLIC int HTMIME_protocol (HTRequest * request, HTResponse * response,
                    334:                            char * token, char * value)
2.1       frystyk   335: {
2.8       frystyk   336:     char * param = NULL;
                    337:     char * protocol = HTNextSExp(&value, &param);
                    338:     if (protocol) {
                    339:        if (PROT_TRACE)
                    340:            HTTrace("Protocol.... Name: `%s\', value: `%s\'\n",
                    341:                    protocol, param);
                    342:        HTResponse_addProtocol(response, protocol, param);
                    343:     }
2.6       frystyk   344:     return HT_OK;
                    345: }
                    346: 
2.8       frystyk   347: PUBLIC int HTMIME_protocolInfo (HTRequest * request, HTResponse * response,
                    348:                                char * token, char * value)
2.6       frystyk   349: {
2.8       frystyk   350:     char * param = NULL;
                    351:     char * info = HTNextSExp(&value, &param);
                    352:     if (info) {
                    353:        if (PROT_TRACE)
                    354:            HTTrace("Protocol.... Info: `%s\', value: `%s\'\n",
                    355:                    info, param);
                    356:        HTResponse_addProtocolInfo(response, info, param);
                    357:     }
2.1       frystyk   358:     return HT_OK;
                    359: }
                    360: 
2.8       frystyk   361: PUBLIC int HTMIME_protocolRequest (HTRequest * request, HTResponse * response,
                    362:                                   char * token, char * value)
2.1       frystyk   363: {
2.8       frystyk   364:     char * param = NULL;
                    365:     char * preq = HTNextSExp(&value, &param);
                    366:     if (preq) {
                    367:        if (PROT_TRACE)
                    368:            HTTrace("Protocol.... Request: `%s\', value: `%s\'\n",
                    369:                    preq, param);
                    370:        HTResponse_addProtocolRequest(response, preq, param);
2.7       frystyk   371:     }
2.1       frystyk   372:     return HT_OK;
                    373: }
                    374: 
2.8       frystyk   375: PUBLIC int HTMIME_proxyAuthorization (HTRequest * request, HTResponse * response,
                    376:                                      char * token, char * value)
2.1       frystyk   377: {
                    378: 
                    379:     return HT_OK;
2.23    ! kahan     380: }
        !           381: 
        !           382: 
        !           383: /* @@@ WARNING: The following function hasn't been thoroughly tested yet */
        !           384: PUBLIC int HTMIME_proxyAuthenticationInfo (HTRequest * request, 
        !           385:                                      HTResponse * response,
        !           386:                                       char * token, char * value)
        !           387: {
        !           388:   /* deal here with the next nonce, the qop, and the digest response (mutual
        !           389:      authentication  */  
        !           390:   if (value) {
        !           391:     if (PROT_TRACE)
        !           392:       HTTrace("Protocol.... Proxy-Authentication-Info: `%s\', value: `%s\'\n",
        !           393:              value);
        !           394:     HTDigest_refresh (request, response, TRUE, value);
        !           395:   }    
        !           396:   return HT_OK;
2.1       frystyk   397: }
                    398: 
2.8       frystyk   399: PUBLIC int HTMIME_public (HTRequest * request, HTResponse * response,
                    400:                          char * token, char * value)
2.1       frystyk   401: {
2.2       frystyk   402:     char * field;
                    403:     HTNet * net = HTRequest_net(request);
                    404:     HTHost * host = HTNet_host(net);
                    405:     while ((field = HTNextField(&value)) != NULL) {
                    406:         HTMethod new_method;
                    407:        /* We treat them as case-insensitive! */
                    408:        if ((new_method = HTMethod_enum(field)) != METHOD_INVALID)
                    409:            HTHost_appendPublicMethods(host, new_method);
                    410:     }
                    411:     if (STREAM_TRACE)
                    412:         HTTrace("MIMEParser.. Public methods: %d\n",
                    413:                HTHost_publicMethods(host));
2.1       frystyk   414:     return HT_OK;
                    415: }
                    416: 
2.8       frystyk   417: PUBLIC int HTMIME_range (HTRequest * request, HTResponse * response,
                    418:                         char * token, char * value)
2.1       frystyk   419: {
                    420: 
                    421:     return HT_OK;
                    422: }
                    423: 
2.8       frystyk   424: PUBLIC int HTMIME_referer (HTRequest * request, HTResponse * response,
                    425:                           char * token, char * value)
2.1       frystyk   426: {
                    427: 
                    428:     return HT_OK;
                    429: }
                    430: 
2.8       frystyk   431: PUBLIC int HTMIME_retryAfter (HTRequest * request, HTResponse * response,
                    432:                              char * token, char * value)
2.1       frystyk   433: {
2.8       frystyk   434:     HTUserProfile * up = HTRequest_userProfile(request);
                    435:     HTResponse_setRetryTime(response, HTParseTime(value, up, YES));
2.1       frystyk   436:     return HT_OK;
                    437: }
                    438: 
2.8       frystyk   439: PUBLIC int HTMIME_server (HTRequest * request, HTResponse * response,
                    440:                          char * token, char * value)
2.2       frystyk   441: {
                    442:     char * field;
                    443:     HTNet * net = HTRequest_net(request);
                    444:     HTHost * host = HTNet_host(net);
                    445:     if ((field = HTNextField(&value)) != NULL)
                    446:         HTHost_setServer(host, field);
2.16      frystyk   447:     return HT_OK;
                    448: }
2.20      frystyk   449: 
                    450: PUBLIC int HTMIME_transferEncoding (HTRequest * request, HTResponse * response,
                    451:                                    char * token, char * value)
                    452: {
                    453:     char * field;
                    454:     while ((field = HTNextField(&value)) != NULL) {
                    455:         char * lc = field;
                    456:        while ((*lc = TOLOWER(*lc))) lc++;
                    457:        HTResponse_addTransfer(response, HTAtom_for(field));
                    458:     }
                    459:     return HT_OK;
                    460: }
                    461: 
2.16      frystyk   462: 
                    463: PUBLIC int HTMIME_trailer (HTRequest * request, HTResponse * response,
                    464:                           char * token, char * value)
                    465: {
                    466:     /*
                    467:     **  Walk through the set of trailer directives and add them to the
                    468:     **  response association list for trailer directives
                    469:     */
                    470:     char * name_val;
                    471:     while ((name_val = HTNextPair(&value)) != NULL) {
                    472:        char * name = HTNextField(&name_val);
                    473:        char * val = HTNextField(&name_val);
                    474:        if (name) HTResponse_addTrailer(response, name, val ? val : "");
                    475:     }
2.2       frystyk   476:     return HT_OK;
                    477: }
                    478: 
2.8       frystyk   479: PUBLIC int HTMIME_upgrade (HTRequest * request, HTResponse * response,
                    480:                           char * token, char * value)
2.1       frystyk   481: {
                    482: 
                    483:     return HT_OK;
                    484: }
                    485: 
2.8       frystyk   486: PUBLIC int HTMIME_userAgent (HTRequest * request, HTResponse * response,
                    487:                             char * token, char * value)
2.1       frystyk   488: {
2.2       frystyk   489:     char * field;
                    490:     HTNet * net = HTRequest_net(request);
                    491:     HTHost * host = HTNet_host(net);
                    492:     if ((field = HTNextField(&value)) != NULL)
                    493:         HTHost_setUserAgent(host, field);
2.1       frystyk   494:     return HT_OK;
                    495: }
                    496: 
2.8       frystyk   497: PUBLIC int HTMIME_vary (HTRequest * request, HTResponse * response,
                    498:                        char * token, char * value)
2.1       frystyk   499: {
2.19      frystyk   500:     /*
                    501:     **  Walk through the set of vary directives and add them to the
                    502:     **  response association list for vary directives
                    503:     */
                    504:     char * name_val;
                    505:     while ((name_val = HTNextPair(&value)) != NULL) {
                    506:        char * name = HTNextField(&name_val);
                    507:        char * val = HTNextField(&name_val);
                    508:        if (name) HTResponse_addVariant(response, name, val ? val : "");
                    509:     }
2.1       frystyk   510:     return HT_OK;
                    511: }
                    512: 
2.8       frystyk   513: PUBLIC int HTMIME_via (HTRequest * request, HTResponse * response,
                    514:                       char * token, char * value)
2.1       frystyk   515: {
                    516: 
                    517:     return HT_OK;
                    518: }
                    519: 
2.8       frystyk   520: PUBLIC int HTMIME_warning (HTRequest * request, HTResponse * response,
                    521:                           char * token, char * value)
2.1       frystyk   522: {
2.2       frystyk   523:     char * codestr = HTNextField(&value);
                    524:     char * agent = HTNextField(&value);
                    525:     if (codestr && agent) {
                    526:        int code = atoi(codestr);
                    527:        int idx;
                    528:        char * ptr;
                    529:        if (code==10) idx=HTERR_STALE; else
                    530:            if (code==11) idx=HTERR_REVALIDATION_FAILED; else
                    531:                if (code==12) idx=HTERR_DISCONNECTED_CACHE; else
                    532:                    if (code==13) idx=HTERR_HEURISTIC_EXPIRATION; else
                    533:                        if (code==14) idx=HTERR_TRANSFORMED; else
                    534:                            idx=HTERR_CACHE;
                    535:        if ((ptr = strchr(agent, '\r')) != NULL)          /* Strip \r and \n */
                    536:            *ptr = '\0';
                    537:        else if ((ptr = strchr(agent, '\n')) != NULL)
                    538:            *ptr = '\0';
                    539:        HTRequest_addError(request, ERR_WARN, NO, idx, agent,
                    540:                           (int) strlen(agent), "HTMIME_warning");
                    541:     } else {
                    542:        if (STREAM_TRACE) HTTrace("MIMEParser.. Invalid warning\n");
                    543:     }
2.1       frystyk   544:     return HT_OK;
                    545: }

Webmaster