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

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

Webmaster