Annotation of libwww/Library/src/HTFormat.c, revision 1.89

1.55      frystyk     1: /*                                                                  HTFormat.c
                      2: **     MANAGE DIFFERENT FILE FORMATS
                      3: **
1.62      frystyk     4: **     (c) COPYRIGHT MIT 1995.
1.55      frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
1.89    ! eric        6: **     @(#) $Id: HTFormat.c,v 1.88 1996/04/15 21:05:51 frystyk Exp $
1.1       timbl       7: **
                      8: ** Bugs:
                      9: **     Assumes the incoming stream is ASCII, rather than a local file
                     10: **     format, and so ALWAYS converts from ASCII on non-ASCII machines.
                     11: **     Therefore, non-ASCII machines can't read local files.
1.2       timbl      12: **
1.45      duns       13: ** HISTORY:
1.86      frystyk    14: **     8 Jul 94  FM    Insulate free from _free structure element.
1.52      frystyk    15: **     8 Nov 94  HFN   Changed a lot to make reentrant
1.2       timbl      16: */
                     17: 
1.58      frystyk    18: /* Library Include files */
1.85      frystyk    19: #include "sysdep.h"
1.87      frystyk    20: #include "WWWUtil.h"
                     21: #include "HTStream.h"
1.58      frystyk    22: #include "HTFWrite.h"
1.52      frystyk    23: #include "HTError.h"
                     24: #include "HTFormat.h"                                   /* Implemented here */
1.2       timbl      25: 
1.72      frystyk    26: #define NO_VALUE_FOUND -1e30            /* Stream Stack Value if none found */
1.63      frystyk    27: 
1.87      frystyk    28: PRIVATE HTList * HTConversions = NULL;                     /* Content types */
1.88      frystyk    29: PRIVATE HTList * HTContentCoders = NULL;                  /* Content coders */
                     30: PRIVATE HTList * HTTransferCoders = NULL;        /* Content transfer coders */
1.72      frystyk    31: PRIVATE HTList * HTCharsets = NULL;
                     32: PRIVATE HTList * HTLanguages = NULL;
1.63      frystyk    33: 
                     34: PRIVATE double HTMaxSecs = 1e10;               /* No effective limit */
1.17      luotonen   35: 
1.60      frystyk    36: struct _HTStream {
1.85      frystyk    37:     const HTStreamClass *      isa;
1.60      frystyk    38: };
                     39: 
1.88      frystyk    40: struct _HTCoding {
                     41:     HTEncoding         encoding;
                     42:     HTCoder *          encoder;
                     43:     HTCoder *          decoder;
1.87      frystyk    44:     double             quality;
                     45: };
                     46: 
1.52      frystyk    47: /* ------------------------------------------------------------------------- */
1.87      frystyk    48: /*                             BASIC CONVERTERS                             */
                     49: /* ------------------------------------------------------------------------- */
                     50: 
                     51: PUBLIC HTStream * HTBlackHoleConverter (HTRequest *    request,
                     52:                                        void *          param,
                     53:                                        HTFormat        input_format,
                     54:                                        HTFormat        output_format,
                     55:                                        HTStream *      output_stream)
                     56: {
                     57:     return HTBlackHole();
                     58: }
                     59: /*     HTThroughLine
                     60: **     -------------
                     61: **
                     62: ** This function is a dummy function that returns the same output stream
                     63: ** as given as a parameter. Henrik 01/03-94
                     64: */
                     65: PUBLIC HTStream* HTThroughLine (HTRequest *    request,
                     66:                                void *          param,
                     67:                                HTFormat        input_format,
                     68:                                HTFormat        output_format,
                     69:                                HTStream *      output_stream)
                     70: {
                     71:     return output_stream;
                     72: }
                     73: 
1.52      frystyk    74: /*
1.63      frystyk    75: **     For all `accept lists' there is a local list and a global list. The
                     76: **     local list is a part of the request structure and the global list is
                     77: **     internal to the HTFormat module. The global lists can be used when
                     78: **     specifying accept lists for ALL requests and the local list can be 
                     79: **     used to add specific accept headers to the request.
                     80: */
                     81: 
1.88      frystyk    82: /* ------------------------------------------------------------------------- */
                     83: /*                             CONTENT TYPES                                */
                     84: /* ------------------------------------------------------------------------- */
1.61      frystyk    85: 
1.2       timbl      86: /*     Define a presentation system command for a content-type
                     87: **     -------------------------------------------------------
1.52      frystyk    88: ** INPUT:
                     89: **     conversions:    The list of conveters and presenters
                     90: **     representation: the MIME-style format name
                     91: **     command:        the MAILCAP-style command template
                     92: **     quality:        A degradation faction [0..1]
                     93: **     maxbytes:       A limit on the length acceptable as input (0 infinite)
                     94: **     maxsecs:        A limit on the time user will wait (0 for infinity)
1.2       timbl      95: */
1.72      frystyk    96: PUBLIC void HTPresentation_add (HTList *       conversions,
1.85      frystyk    97:                                const char *    representation,
                     98:                                const char *    command,
                     99:                                const char *    test_command,
1.72      frystyk   100:                                double          quality,
                    101:                                double          secs, 
                    102:                                double          secs_per_byte)
1.52      frystyk   103: {
1.83      frystyk   104:     HTPresentation * pres;
                    105:     if ((pres = (HTPresentation  *) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
                    106:         HT_OUTOFMEM("HTSetPresentation");
1.2       timbl     107:     
                    108:     pres->rep = HTAtom_for(representation);
                    109:     pres->rep_out = WWW_PRESENT;               /* Fixed for now ... :-) */
                    110:     pres->converter = HTSaveAndExecute;                /* Fixed for now ...     */
                    111:     pres->quality = quality;
                    112:     pres->secs = secs;
                    113:     pres->secs_per_byte = secs_per_byte;
                    114:     pres->rep = HTAtom_for(representation);
1.49      howcome   115:     pres->command = NULL;
1.2       timbl     116:     StrAllocCopy(pres->command, command);
1.49      howcome   117:     pres->test_command = NULL;
                    118:     StrAllocCopy(pres->test_command, test_command);
1.12      timbl     119:     HTList_addObject(conversions, pres);
1.2       timbl     120: }
                    121: 
1.73      frystyk   122: PUBLIC void HTPresentation_deleteAll (HTList * list)
                    123: {
                    124:     if (list) {
                    125:        HTList *cur = list;
                    126:        HTPresentation *pres;
                    127:        while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
1.83      frystyk   128:            HT_FREE(pres->command);
                    129:            HT_FREE(pres);
1.73      frystyk   130:        }
                    131:        HTList_delete(list);
                    132:     }
                    133: }
1.2       timbl     134: 
                    135: /*     Define a built-in function for a content-type
                    136: **     ---------------------------------------------
                    137: */
1.72      frystyk   138: PUBLIC void HTConversion_add (HTList *         conversions,
1.85      frystyk   139:                              const char *      representation_in,
                    140:                              const char *      representation_out,
1.72      frystyk   141:                              HTConverter *     converter,
                    142:                              double            quality,
                    143:                              double            secs, 
                    144:                              double            secs_per_byte)
1.52      frystyk   145: {
1.83      frystyk   146:     HTPresentation * pres;
1.87      frystyk   147:     if ((pres = (HTPresentation*) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
1.83      frystyk   148:         HT_OUTOFMEM("HTSetPresentation");
1.2       timbl     149:     pres->rep = HTAtom_for(representation_in);
                    150:     pres->rep_out = HTAtom_for(representation_out);
                    151:     pres->converter = converter;
                    152:     pres->command = NULL;              /* Fixed */
1.49      howcome   153:     pres->test_command = NULL;
1.2       timbl     154:     pres->quality = quality;
                    155:     pres->secs = secs;
                    156:     pres->secs_per_byte = secs_per_byte;
1.12      timbl     157:     HTList_addObject(conversions, pres);
1.56      frystyk   158: }
                    159: 
1.73      frystyk   160: PUBLIC void HTConversion_deleteAll (HTList * list)
                    161: {
                    162:     HTPresentation_deleteAll(list);
                    163: }
                    164: 
1.88      frystyk   165: /* ------------------------------------------------------------------------- */
                    166: /*             CONTENT ENCODING AND CONTENT TRANSFER ENCODING               */
                    167: /* ------------------------------------------------------------------------- */
                    168: 
                    169: PUBLIC BOOL HTCoding_add (HTList *     list,
                    170:                          const char *  encoding,
                    171:                          HTCoder *     encoder,
                    172:                          HTCoder *     decoder,
                    173:                          double        quality)
1.73      frystyk   174: {
1.88      frystyk   175:     if (list && encoding && (encoder || decoder)) {
                    176:        HTCoding * me;
                    177:        if ((me = (HTCoding *) HT_CALLOC(1, sizeof(HTCoding))) == NULL)
                    178:            HT_OUTOFMEM("HTCoding_add");
                    179:        me->encoding = HTAtom_for(encoding);
1.87      frystyk   180:        me->encoder = encoder;
                    181:        me->decoder = decoder;
                    182:        me->quality = quality;
                    183:        if (CORE_TRACE)
                    184:            HTTrace("Codings..... Adding %s with quality %.2f\n",
1.88      frystyk   185:                    encoding, quality);
1.87      frystyk   186:        return HTList_addObject(list, (void *) me);
1.73      frystyk   187:     }
1.87      frystyk   188:     if (CORE_TRACE) HTTrace("Codings..... Bad argument\n");
                    189:     return NO;
1.73      frystyk   190: }
                    191: 
1.88      frystyk   192: PUBLIC void HTCoding_deleteAll (HTList * list)
1.73      frystyk   193: {
                    194:     if (list) {
1.87      frystyk   195:        HTList * cur = list;
1.88      frystyk   196:        HTCoding * pres;
                    197:        while ((pres = (HTCoding *) HTList_nextObject(cur)))
1.83      frystyk   198:            HT_FREE(pres);
1.73      frystyk   199:        HTList_delete(list);
                    200:     }
                    201: }
                    202: 
1.88      frystyk   203: PUBLIC const char * HTCoding_name (HTCoding * me)
1.87      frystyk   204: {
1.88      frystyk   205:     return me ? HTAtom_name(me->encoding) : NULL;
1.87      frystyk   206: }
                    207: 
1.88      frystyk   208: /* ------------------------------------------------------------------------- */
                    209: /*                             CONTENT LANGUAGE                             */
                    210: /* ------------------------------------------------------------------------- */
                    211: 
1.73      frystyk   212: PUBLIC void HTLanguage_add (HTList *           list,
1.85      frystyk   213:                            const char *        lang,
1.73      frystyk   214:                            double              quality)
                    215: {
                    216:     HTAcceptNode * node;
                    217:     if (!list || !lang || !*lang)  {
1.87      frystyk   218:        if (CORE_TRACE)
1.84      eric      219:            HTTrace("Languages... Bad argument\n");
1.73      frystyk   220:        return;
                    221:     }
1.83      frystyk   222:     if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
                    223:         HT_OUTOFMEM("HTAcceptLanguage");
1.73      frystyk   224: 
                    225:     HTList_addObject(list, (void*)node);
                    226:     node->atom = HTAtom_for(lang);
                    227:     node->quality = quality;
                    228: }
                    229: 
                    230: PUBLIC void HTLanguage_deleteAll (HTList * list)
                    231: {
1.87      frystyk   232:     if (list) {
                    233:        HTList *cur = list;
                    234:        HTAcceptNode *pres;
                    235:        while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
                    236:            HT_FREE(pres);
                    237:        }
                    238:        HTList_delete(list);
                    239:     }
1.73      frystyk   240: }
                    241: 
1.88      frystyk   242: /* ------------------------------------------------------------------------- */
                    243: /*                             CONTENT CHARSET                              */
                    244: /* ------------------------------------------------------------------------- */
                    245: 
1.73      frystyk   246: PUBLIC void HTCharset_add (HTList *            list,
1.85      frystyk   247:                           const char *         charset,
1.73      frystyk   248:                           double               quality)
                    249: {
                    250:     HTAcceptNode * node;
                    251:     if (!list || !charset || !*charset)  {
1.87      frystyk   252:        if (CORE_TRACE)
1.84      eric      253:            HTTrace("Charset..... Bad argument\n");
1.73      frystyk   254:        return;
                    255:     }
1.83      frystyk   256:     if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
                    257:         HT_OUTOFMEM("HTAcceptCharsetuage");
1.73      frystyk   258: 
                    259:     HTList_addObject(list, (void*)node);
                    260:     node->atom = HTAtom_for(charset);
                    261:     node->quality = quality;
                    262: }
                    263: 
                    264: PUBLIC void HTCharset_deleteAll (HTList * list)
                    265: {
1.87      frystyk   266:     if (list) {
                    267:        HTList *cur = list;
                    268:        HTAcceptNode *pres;
                    269:        while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
                    270:            HT_FREE(pres);
                    271:        }
                    272:        HTList_delete(list);
                    273:     }
1.73      frystyk   274: }
                    275: 
                    276: /* ------------------------------------------------------------------------- */
                    277: /*                     GLOBAL LIST OF CONVERTERS ETC.                       */
                    278: /* ------------------------------------------------------------------------- */
                    279: 
1.72      frystyk   280: /*
                    281: **     Global Accept Format Types Conversions
                    282: **     list can be NULL
                    283: */
1.73      frystyk   284: PUBLIC void HTFormat_setConversion (HTList * list)
1.72      frystyk   285: {
                    286:     HTConversions = list;
                    287: }
                    288: 
                    289: PUBLIC HTList * HTFormat_conversion (void)
                    290: {
                    291:     return HTConversions;
                    292: }
                    293: 
                    294: /*
1.88      frystyk   295: **     Global list of Content Encodings
1.72      frystyk   296: **     list can be NULL
                    297: */
1.88      frystyk   298: PUBLIC void HTFormat_setContentCoding (HTList *list)
1.72      frystyk   299: {
1.88      frystyk   300:     HTContentCoders = list;
1.72      frystyk   301: }
                    302: 
1.88      frystyk   303: PUBLIC HTList * HTFormat_contentCoding (void)
1.72      frystyk   304: {
1.88      frystyk   305:     return HTContentCoders;
1.72      frystyk   306: }
                    307: 
                    308: /*
1.88      frystyk   309: **     Global list of Content Transfer Encodings
                    310: **     list can be NULL
                    311: */
                    312: PUBLIC void HTFormat_setTransferCoding (HTList *list)
                    313: {
                    314:     HTTransferCoders = list;
                    315: }
                    316: 
                    317: PUBLIC HTList * HTFormat_transferCoding (void)
                    318: {
                    319:     return HTTransferCoders;
                    320: }
                    321: 
                    322: /*
1.72      frystyk   323: **     Global Accept Languages
                    324: **     list can be NULL
                    325: */
                    326: PUBLIC void HTFormat_setLanguage (HTList *list)
                    327: {
                    328:     HTLanguages = list;
                    329: }
                    330: 
                    331: PUBLIC HTList * HTFormat_language (void)
                    332: {
                    333:     return HTLanguages;
                    334: }
                    335: 
                    336: /*
                    337: **     Global Accept Charsets
                    338: **     list can be NULL
                    339: */
                    340: PUBLIC void HTFormat_setCharset (HTList *list)
                    341: {
                    342:     HTCharsets = list;
                    343: }
                    344: 
                    345: PUBLIC HTList * HTFormat_charset (void)
                    346: {
                    347:     return HTCharsets;
                    348: }
1.56      frystyk   349: 
1.73      frystyk   350: /*
                    351: **     Convenience function to clean up
                    352: */
                    353: PUBLIC void HTFormat_deleteAll (void)
1.17      luotonen  354: {
1.73      frystyk   355:     if (HTConversions) {
                    356:        HTConversion_deleteAll(HTConversions);
                    357:        HTConversions = NULL;
                    358:     }
                    359:     if (HTLanguages) {
                    360:        HTLanguage_deleteAll(HTLanguages);
                    361:        HTLanguages = NULL;
1.63      frystyk   362:     }
1.88      frystyk   363:     if (HTContentCoders) {
                    364:        HTCoding_deleteAll(HTContentCoders);
                    365:        HTContentCoders = NULL;
1.63      frystyk   366:     }
1.88      frystyk   367:     if (HTTransferCoders) {
                    368:        HTCoding_deleteAll(HTTransferCoders);
                    369:        HTTransferCoders = NULL;
                    370:     }
1.73      frystyk   371:     if (HTCharsets) {
                    372:        HTCharset_deleteAll(HTCharsets);
                    373:        HTCharsets = NULL;
1.63      frystyk   374:     }
1.17      luotonen  375: }
                    376: 
1.63      frystyk   377: /* ------------------------------------------------------------------------- */
                    378: /*                             FORMAT NEGOTIATION                           */
                    379: /* ------------------------------------------------------------------------- */
                    380: 
1.77      frystyk   381: PRIVATE BOOL better_match (HTFormat f, HTFormat g)
1.63      frystyk   382: {
1.85      frystyk   383:     const char *p, *q;
1.63      frystyk   384: 
                    385:     if (f && g  &&  (p = HTAtom_name(f))  &&  (q = HTAtom_name(g))) {
                    386:        int i,j;
                    387:        for(i=0 ; *p; p++) if (*p == '*') i++;
                    388:        for(j=0 ; *q; q++) if (*q == '*') j++;
                    389:        if (i < j) return YES;
                    390:     }
                    391:     return NO;
                    392: }
                    393: 
                    394: 
1.77      frystyk   395: PRIVATE BOOL wild_match (HTAtom * tmplate, HTAtom * actual)
1.17      luotonen  396: {
1.89    ! eric      397:     const char *t, *a;
        !           398:     char *st, *sa;
1.17      luotonen  399:     BOOL match = NO;
                    400: 
1.48      frystyk   401:     if (tmplate && actual && (t = HTAtom_name(tmplate))) {
1.22      luotonen  402:        if (!strcmp(t, "*"))
                    403:            return YES;
1.17      luotonen  404: 
1.22      luotonen  405:        if (strchr(t, '*') &&
                    406:            (a = HTAtom_name(actual)) &&
                    407:            (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {
1.17      luotonen  408: 
1.22      luotonen  409:            *sa = 0;
                    410:            *st = 0;
                    411: 
                    412:            if ((*(st-1)=='*' &&
                    413:                 (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
                    414:                (*(st+1)=='*' && !strcasecomp(t,a)))
                    415:                match = YES;
                    416: 
                    417:            *sa = '/';
                    418:            *st = '/';
                    419:        }    
                    420:     }
1.23      luotonen  421:     return match;
1.17      luotonen  422: }
                    423: 
1.36      luotonen  424: /*
                    425:  * Added by takada@seraph.ntt.jp (94/04/08)
                    426:  */
1.77      frystyk   427: PRIVATE BOOL lang_match (HTAtom * tmplate, HTAtom * actual)
1.36      luotonen  428: {
1.89    ! eric      429:     const char *t, *a;
        !           430:     char *st, *sa;
1.36      luotonen  431:     BOOL match = NO;
                    432: 
1.48      frystyk   433:     if (tmplate && actual &&
                    434:        (t = HTAtom_name(tmplate)) && (a = HTAtom_name(actual))) {
1.36      luotonen  435:        st = strchr(t, '_');
                    436:        sa = strchr(a, '_');
                    437:        if ((st != NULL) && (sa != NULL)) {
                    438:            if (!strcasecomp(t, a))
                    439:              match = YES;
                    440:            else
                    441:              match = NO;
                    442:        }
                    443:        else {
                    444:            if (st != NULL) *st = 0;
                    445:            if (sa != NULL) *sa = 0;
                    446:            if (!strcasecomp(t, a))
                    447:              match = YES;
                    448:            else
                    449:              match = NO;
                    450:            if (st != NULL) *st = '_';
                    451:            if (sa != NULL) *sa = '_';
                    452:        }
                    453:     }
                    454:     return match;
                    455: }
                    456: /* end of addition */
                    457: 
                    458: 
1.17      luotonen  459: 
1.77      frystyk   460: PRIVATE double type_value (HTAtom * content_type, HTList * accepted)
1.17      luotonen  461: {
                    462:     HTList * cur = accepted;
                    463:     HTPresentation * pres;
                    464:     HTPresentation * wild = NULL;
                    465: 
                    466:     if (!content_type || !accepted) return -1;
                    467: 
                    468:     while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
                    469:        if (pres->rep == content_type)
                    470:            return pres->quality;
                    471:        else if (wild_match(pres->rep, content_type))
                    472:            wild = pres;
                    473:     }
                    474:     if (wild) return wild->quality;
                    475:     else return -1;
                    476: }
                    477: 
                    478: 
1.77      frystyk   479: PRIVATE double lang_value (HTAtom * language, HTList * accepted)
1.17      luotonen  480: {
                    481:     HTList * cur = accepted;
                    482:     HTAcceptNode * node;
                    483:     HTAcceptNode * wild = NULL;
                    484: 
                    485:     if (!language || !accepted || HTList_isEmpty(accepted)) {
                    486:        return 0.1;
                    487:     }
                    488: 
                    489:     while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
                    490:        if (node->atom == language) {
                    491:            return node->quality;
                    492:        }
1.36      luotonen  493:        /*
                    494:         * patch by takada@seraph.ntt.jp (94/04/08)
                    495:         * the original line was
                    496:         * else if (wild_match(node->atom, language)) {
                    497:         * and the new line is
                    498:         */
                    499:        else if (lang_match(node->atom, language)) {
1.17      luotonen  500:            wild = node;
                    501:        }
                    502:     }
                    503: 
                    504:     if (wild) {
                    505:        return wild->quality;
                    506:     }
                    507:     else {
                    508:        return 0.1;
                    509:     }
                    510: }
                    511: 
                    512: 
1.77      frystyk   513: PRIVATE double encoding_value (HTAtom * encoding, HTList * accepted)
1.17      luotonen  514: {
                    515:     HTList * cur = accepted;
                    516:     HTAcceptNode * node;
                    517:     HTAcceptNode * wild = NULL;
1.89    ! eric      518:     const char * e;
1.17      luotonen  519: 
                    520:     if (!encoding || !accepted || HTList_isEmpty(accepted))
                    521:        return 1;
                    522: 
                    523:     e = HTAtom_name(encoding);
                    524:     if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
                    525:        return 1;
                    526: 
                    527:     while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
                    528:        if (node->atom == encoding)
                    529:            return node->quality;
                    530:        else if (wild_match(node->atom, encoding))
                    531:            wild = node;
                    532:     }
                    533:     if (wild) return wild->quality;
                    534:     else return 1;
                    535: }
                    536: 
                    537: 
1.77      frystyk   538: PUBLIC BOOL HTRank (HTList * possibilities,
                    539:                    HTList * accepted_content_types,
                    540:                    HTList * accepted_languages,
                    541:                    HTList * accepted_encodings)
1.17      luotonen  542: {
                    543:     int accepted_cnt = 0;
                    544:     HTList * accepted;
                    545:     HTList * sorted;
                    546:     HTList * cur;
                    547:     HTContentDescription * d;
                    548: 
                    549:     if (!possibilities) return NO;
                    550: 
                    551:     accepted = HTList_new();
                    552:     cur = possibilities;
                    553:     while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
1.59      frystyk   554:        double tv = type_value(d->content_type, accepted_content_types);
                    555:        double lv = lang_value(d->content_language, accepted_languages);
                    556:        double ev = encoding_value(d->content_encoding, accepted_encodings);
1.17      luotonen  557: 
                    558:        if (tv > 0) {
                    559:            d->quality *= tv * lv * ev;
                    560:            HTList_addObject(accepted, d);
                    561:            accepted_cnt++;
                    562:        }
1.18      luotonen  563:        else {
1.86      frystyk   564:            HT_FREE(d->filename);
1.83      frystyk   565:            HT_FREE(d);
1.18      luotonen  566:        }
1.17      luotonen  567:     }
                    568: 
1.87      frystyk   569:     if (CORE_TRACE) HTTrace("Ranking.....\n");
                    570:     if (CORE_TRACE) HTTrace(
1.18      luotonen  571:           "\nRANK QUALITY CONTENT-TYPE         LANGUAGE ENCODING    FILE\n");
1.17      luotonen  572: 
                    573:     sorted = HTList_new();
                    574:     while (accepted_cnt-- > 0) {
                    575:        HTContentDescription * worst = NULL;
                    576:        cur = accepted;
                    577:        while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
                    578:            if (!worst || d->quality < worst->quality)
                    579:                worst = d;
                    580:        }
                    581:        if (worst) {
1.87      frystyk   582:            if (CORE_TRACE)
1.84      eric      583:                HTTrace("%d.   %.4f  %-20.20s %-8.8s %-10.10s %s\n",
1.58      frystyk   584:                        accepted_cnt+1,
                    585:                        worst->quality,
                    586:                        (worst->content_type
1.17      luotonen  587:                         ? HTAtom_name(worst->content_type)      : "-"),
1.58      frystyk   588:                        (worst->content_language
1.17      luotonen  589:                         ? HTAtom_name(worst->content_language)  :"-"),
1.58      frystyk   590:                        (worst->content_encoding
1.17      luotonen  591:                         ? HTAtom_name(worst->content_encoding)  :"-"),
1.58      frystyk   592:                        (worst->filename
1.17      luotonen  593:                         ? worst->filename                       :"-"));
                    594:            HTList_removeObject(accepted, (void*)worst);
                    595:            HTList_addObject(sorted, (void*)worst);
                    596:        }
                    597:     }
1.87      frystyk   598:     if (CORE_TRACE) HTTrace("\n");
1.17      luotonen  599:     HTList_delete(accepted);
                    600:     HTList_delete(possibilities->next);
                    601:     possibilities->next = sorted->next;
                    602:     sorted->next = NULL;
                    603:     HTList_delete(sorted);
                    604: 
                    605:     if (!HTList_isEmpty(possibilities)) return YES;
                    606:     else return NO;
                    607: }
                    608: 
                    609: 
1.87      frystyk   610: /*     Create a Content Type filter stack
                    611: **     ----------------------------------
1.7       secret    612: **     If a wildcard match is made, a temporary HTPresentation
1.2       timbl     613: **     structure is made to hold the destination format while the
                    614: **     new stack is generated. This is just to pass the out format to
                    615: **     MIME so far.  Storing the format of a stream in the stream might
                    616: **     be a lot neater.
1.10      timbl     617: **
1.29      frystyk   618: **     The star/star format is special, in that if you can take
1.40      frystyk   619: **     that you can take anything.
1.2       timbl     620: */
1.77      frystyk   621: PUBLIC HTStream * HTStreamStack (HTFormat      rep_in,
                    622:                                 HTFormat       rep_out,
                    623:                                 HTStream *     output_stream,
                    624:                                 HTRequest *    request,
                    625:                                 BOOL           guess)
1.2       timbl     626: {
1.14      timbl     627:     HTList * conversion[2];
                    628:     int which_list;
1.59      frystyk   629:     double best_quality = -1e30;               /* Pretty bad! */
1.65      frystyk   630:     HTPresentation *pres, *best_match=NULL;
1.80      frystyk   631:     if (rep_out == WWW_RAW) {
1.87      frystyk   632:        if (CORE_TRACE) HTTrace("StreamStack. Raw output...\n");
1.81      frystyk   633:        return output_stream ? output_stream : HTErrorStream();
1.34      luotonen  634:     }
1.79      frystyk   635: 
1.80      frystyk   636:     if (rep_out == rep_in) {
1.87      frystyk   637:        if (CORE_TRACE)
1.84      eric      638:            HTTrace("StreamStack. Identical input/output format (%s)\n",
1.80      frystyk   639:                     HTAtom_name(rep_out));
1.81      frystyk   640:        return output_stream ? output_stream : HTErrorStream();
1.74      frystyk   641:     }
1.87      frystyk   642:     if (CORE_TRACE) {
1.89    ! eric      643:        const char *p = HTAtom_name(rep_in);
        !           644:        const char *q = HTAtom_name(rep_out); 
1.84      eric      645:        HTTrace("StreamStack. Constructing stream stack for %s to %s\n",
1.82      frystyk   646:                 p ? p : "<NULL>", q ? q : "<NULL>");
1.47      frystyk   647:     }
1.2       timbl     648: 
1.88      frystyk   649:     conversion[0] = HTRequest_conversion(request);
1.14      timbl     650:     conversion[1] = HTConversions;
1.17      luotonen  651: 
1.15      luotonen  652:     for(which_list = 0; which_list<2; which_list++) {
                    653:        HTList * cur = conversion[which_list];
                    654:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.65      frystyk   655:            if ((pres->rep==rep_in || wild_match(pres->rep, rep_in)) &&
                    656:                (pres->rep_out==rep_out || wild_match(pres->rep_out,rep_out))){
                    657:                if (!best_match || better_match(pres->rep, best_match->rep) ||
1.33      luotonen  658:                    (!better_match(best_match->rep, pres->rep) &&
                    659:                     pres->quality > best_quality)) {
1.85      frystyk   660: #ifdef HAVE_SYSTEM
1.65      frystyk   661:                    int result=0;
                    662:                    if (pres->test_command) {
                    663:                        result = system(pres->test_command);
1.87      frystyk   664:                        if (CORE_TRACE) 
1.84      eric      665:                            HTTrace("StreamStack. system(%s) returns %d\n", pres->test_command, result);
1.65      frystyk   666:                    }
                    667:                    if (!result) {
1.49      howcome   668:                        best_match = pres;
                    669:                        best_quality = pres->quality;
                    670:                    }
1.65      frystyk   671: #else
                    672:                    best_match = pres;
                    673:                    best_quality = pres->quality;
1.85      frystyk   674: #endif /* HAVE_SYSTEM */
1.10      timbl     675:                }
                    676:            }
1.2       timbl     677:        }
                    678:     }
1.80      frystyk   679: 
                    680:     if (best_match) {
                    681:        if (rep_out == WWW_SOURCE && best_match->rep_out != WWW_SOURCE) {
1.87      frystyk   682:            if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81      frystyk   683:            return output_stream ? output_stream : HTErrorStream();
1.80      frystyk   684:        }
1.65      frystyk   685:        return (*best_match->converter)(request, best_match->command,
                    686:                                        rep_in, rep_out, output_stream);
1.80      frystyk   687:     }
                    688:     if (rep_out == WWW_SOURCE) {
1.87      frystyk   689:        if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81      frystyk   690:        return output_stream ? output_stream : HTErrorStream();
1.80      frystyk   691:     }
                    692: 
1.87      frystyk   693:     if (CORE_TRACE)
1.84      eric      694:        HTTrace("StreamStack. No match found, dumping to local file\n");
1.65      frystyk   695:     return HTSaveLocally(request, NULL, rep_in, rep_out, output_stream);
1.2       timbl     696: }
                    697:        
                    698: 
                    699: /*             Find the cost of a filter stack
                    700: **             -------------------------------
                    701: **
                    702: **     Must return the cost of the same stack which StreamStack would set up.
                    703: **
                    704: ** On entry,
                    705: **     length  The size of the data to be converted
                    706: */
1.77      frystyk   707: PUBLIC double HTStackValue (HTList *   theseConversions,
                    708:                            HTFormat    rep_in,
                    709:                            HTFormat    rep_out,
                    710:                            double      initial_value,
                    711:                            long int    length)
1.2       timbl     712: {
1.14      timbl     713:     int which_list;
                    714:     HTList* conversion[2];
                    715:     
1.87      frystyk   716:     if (CORE_TRACE) {
1.84      eric      717:        HTTrace("StackValue.. Evaluating stream stack for %s worth %.3f to %s\n",
1.65      frystyk   718:                HTAtom_name(rep_in),    initial_value,
                    719:                HTAtom_name(rep_out));
                    720:     }
1.2       timbl     721:     if (rep_out == WWW_SOURCE ||
1.10      timbl     722:        rep_out == rep_in) return 0.0;
1.2       timbl     723: 
1.14      timbl     724:     conversion[0] = theseConversions;
                    725:     conversion[1] = HTConversions;
                    726:     
                    727:     for(which_list = 0; which_list<2; which_list++)
                    728:      if (conversion[which_list]) {
1.15      luotonen  729:         HTList * cur = conversion[which_list];
1.2       timbl     730:        HTPresentation * pres;
1.15      luotonen  731:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
                    732:            if (pres->rep == rep_in &&
1.17      luotonen  733:                (pres->rep_out == rep_out || wild_match(pres->rep_out, rep_out))) {
1.59      frystyk   734:                double value = initial_value * pres->quality;
1.2       timbl     735:                if (HTMaxSecs != 0.0)
1.15      luotonen  736:                    value = value - (length*pres->secs_per_byte + pres->secs)
1.2       timbl     737:                                         /HTMaxSecs;
                    738:                return value;
                    739:            }
                    740:        }
                    741:     }
1.63      frystyk   742:     return NO_VALUE_FOUND;             /* Really bad */
1.1       timbl     743: }
1.2       timbl     744: 
1.87      frystyk   745: /*     Create a new coder and insert it into stream chain
                    746: **     --------------------------------------------------
                    747: **     Creating the content decoding stack is not based on quality factors as
                    748: **     we don't have the freedom as with content types. Specify whether you
1.88      frystyk   749: **     you want encoding or decoding using the BOOL "encode" flag.
1.87      frystyk   750: */
1.88      frystyk   751: PUBLIC HTStream * HTContentCodingStack (HTEncoding     encoding,
                    752:                                        HTStream *      target,
                    753:                                        HTRequest *     request,
                    754:                                        void *          param,
                    755:                                        BOOL            encode)
1.87      frystyk   756: {
                    757:     HTList * coders[2];
                    758:     HTStream * top = target;
1.88      frystyk   759:     HTCoding * pres = NULL;
1.87      frystyk   760:     int cnt;
1.88      frystyk   761:     if (!encoding || !request) {
1.87      frystyk   762:        if (CORE_TRACE) HTTrace("Codings... Nothing applied...\n");
                    763:        return target ? target : HTErrorStream();
                    764:     }
1.88      frystyk   765:     coders[0] = HTRequest_encoding(request);
                    766:     coders[1] = HTContentCoders;
1.87      frystyk   767:     if (CORE_TRACE)
1.88      frystyk   768:        HTTrace("Codings..... Looking for %s\n", HTAtom_name(encoding));
1.87      frystyk   769:     for (cnt=0; cnt < 2; cnt++) {
                    770:        HTList * cur = coders[cnt];
1.88      frystyk   771:        while ((pres = (HTCoding *) HTList_nextObject(cur))) {
                    772:            if (pres->encoding == encoding) {
1.87      frystyk   773:                if (CORE_TRACE) HTTrace("Codings..... Found...\n");
1.88      frystyk   774:                if (encode) {
1.87      frystyk   775:                    if (pres->encoder)
1.88      frystyk   776:                        top = (*pres->encoder)(request, param, encoding, top);
1.87      frystyk   777:                    break;
                    778:                } else if (pres->decoder) {
1.88      frystyk   779:                    top = (*pres->decoder)(request, param, encoding, top);
1.87      frystyk   780:                    break;
                    781:                }
                    782:            }
                    783:        }
                    784:     }
                    785:     return top;
                    786: }
1.10      timbl     787: 
1.87      frystyk   788: /*
                    789: **  Here you can provide a complete list instead of a single token.
                    790: **  The list has to filled up in the order the _encodings_ are to be applied
                    791: */
1.88      frystyk   792: PUBLIC HTStream * HTContentEncodingStack (HTList *     encodings,
                    793:                                          HTStream *    target,
                    794:                                          HTRequest *   request,
                    795:                                          void *        param)
1.87      frystyk   796: {
                    797:     if (encodings) {
                    798:        HTList * cur = encodings;
                    799:        HTEncoding pres;
                    800:        HTStream * top = target;
                    801:        while ((pres = (HTEncoding) HTList_nextObject(cur)))
1.88      frystyk   802:            top = HTContentCodingStack(pres, top, request, param, YES);
1.87      frystyk   803:        return top;
                    804:     }
                    805:     return HTErrorStream();
                    806: }
                    807: 
                    808: /*
                    809: **  Here you can provide a complete list instead of a single token.
                    810: **  The list has to be in the order the _encodings_ were applied - that
                    811: **  is, the same way that _encodings_ are to be applied. This is all consistent
                    812: **  with the order of the Content-Encoding header.
                    813: */
1.88      frystyk   814: PUBLIC HTStream * HTContentDecodingStack (HTList *     encodings,
                    815:                                          HTStream *    target,
                    816:                                          HTRequest *   request,
                    817:                                          void *        param)
1.87      frystyk   818: {
                    819:     if (encodings) {
                    820:        HTEncoding pres;
                    821:        int cnt = HTList_count(encodings);
                    822:        HTStream * top = target;
                    823:        while (cnt > 0) {
                    824:            pres = (HTEncoding) HTList_objectAt(encodings, --cnt);
1.88      frystyk   825:            top = HTContentCodingStack(pres, top, request, param, NO);
1.87      frystyk   826:        }
                    827:        return top;
                    828:     }
                    829:     return HTErrorStream();
                    830: }
1.88      frystyk   831: 
                    832: /*     Create a new transfer coder and insert it into stream chain
                    833: **     -----------------------------------------------------------
                    834: **     Creating the content decoding stack is not based on quality factors as
                    835: **     we don't have the freedom as with content types. Specify whether you
                    836: **     you want encoding or decoding using the BOOL "encode" flag.
                    837: */
                    838: PUBLIC HTStream * HTTransferCodingStack (HTEncoding    encoding,
                    839:                                         HTStream *     target,
                    840:                                         HTRequest *    request,
                    841:                                         void *         param,
                    842:                                         BOOL           encode)
                    843: {
                    844:     HTList * coders[2];
                    845:     HTStream * top = target;
                    846:     HTCoding * pres = NULL;
                    847:     int cnt;
                    848:     if (!encoding || !request) {
                    849:        if (CORE_TRACE) HTTrace("C-T-E..... Nothing applied...\n");
                    850:        return target ? target : HTErrorStream();
                    851:     }
                    852:     coders[0] = HTRequest_transfer(request);
                    853:     coders[1] = HTTransferCoders;
                    854:     if (CORE_TRACE)
                    855:        HTTrace("C-T-E....... Looking for %s\n", HTAtom_name(encoding));
                    856:     for (cnt=0; cnt < 2; cnt++) {
                    857:        HTList * cur = coders[cnt];
                    858:        while ((pres = (HTCoding *) HTList_nextObject(cur))) {
                    859:            if (pres->encoding == encoding) {
                    860:                if (CORE_TRACE) HTTrace("C-T-E....... Found...\n");
                    861:                if (encode) {
                    862:                    if (pres->encoder)
                    863:                        top = (*pres->encoder)(request, param, encoding, top);
                    864:                    break;
                    865:                } else if (pres->decoder) {
                    866:                    top = (*pres->decoder)(request, param, encoding, top);
                    867:                    break;
                    868:                }
                    869:            }
                    870:        }
                    871:     }
                    872:     return top;
                    873: }
                    874: 

Webmaster