Annotation of libwww/Library/src/HTFormat.c, revision 1.88
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.88 ! frystyk 6: ** @(#) $Id: HTFormat.c,v 1.87 1996/04/12 17:47:00 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: {
397: char *t, *a, *st, *sa;
398: BOOL match = NO;
399:
1.48 frystyk 400: if (tmplate && actual && (t = HTAtom_name(tmplate))) {
1.22 luotonen 401: if (!strcmp(t, "*"))
402: return YES;
1.17 luotonen 403:
1.22 luotonen 404: if (strchr(t, '*') &&
405: (a = HTAtom_name(actual)) &&
406: (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {
1.17 luotonen 407:
1.22 luotonen 408: *sa = 0;
409: *st = 0;
410:
411: if ((*(st-1)=='*' &&
412: (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
413: (*(st+1)=='*' && !strcasecomp(t,a)))
414: match = YES;
415:
416: *sa = '/';
417: *st = '/';
418: }
419: }
1.23 luotonen 420: return match;
1.17 luotonen 421: }
422:
1.36 luotonen 423: /*
424: * Added by takada@seraph.ntt.jp (94/04/08)
425: */
1.77 frystyk 426: PRIVATE BOOL lang_match (HTAtom * tmplate, HTAtom * actual)
1.36 luotonen 427: {
428: char *t, *a, *st, *sa;
429: BOOL match = NO;
430:
1.48 frystyk 431: if (tmplate && actual &&
432: (t = HTAtom_name(tmplate)) && (a = HTAtom_name(actual))) {
1.36 luotonen 433: st = strchr(t, '_');
434: sa = strchr(a, '_');
435: if ((st != NULL) && (sa != NULL)) {
436: if (!strcasecomp(t, a))
437: match = YES;
438: else
439: match = NO;
440: }
441: else {
442: if (st != NULL) *st = 0;
443: if (sa != NULL) *sa = 0;
444: if (!strcasecomp(t, a))
445: match = YES;
446: else
447: match = NO;
448: if (st != NULL) *st = '_';
449: if (sa != NULL) *sa = '_';
450: }
451: }
452: return match;
453: }
454: /* end of addition */
455:
456:
1.17 luotonen 457:
1.77 frystyk 458: PRIVATE double type_value (HTAtom * content_type, HTList * accepted)
1.17 luotonen 459: {
460: HTList * cur = accepted;
461: HTPresentation * pres;
462: HTPresentation * wild = NULL;
463:
464: if (!content_type || !accepted) return -1;
465:
466: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
467: if (pres->rep == content_type)
468: return pres->quality;
469: else if (wild_match(pres->rep, content_type))
470: wild = pres;
471: }
472: if (wild) return wild->quality;
473: else return -1;
474: }
475:
476:
1.77 frystyk 477: PRIVATE double lang_value (HTAtom * language, HTList * accepted)
1.17 luotonen 478: {
479: HTList * cur = accepted;
480: HTAcceptNode * node;
481: HTAcceptNode * wild = NULL;
482:
483: if (!language || !accepted || HTList_isEmpty(accepted)) {
484: return 0.1;
485: }
486:
487: while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
488: if (node->atom == language) {
489: return node->quality;
490: }
1.36 luotonen 491: /*
492: * patch by takada@seraph.ntt.jp (94/04/08)
493: * the original line was
494: * else if (wild_match(node->atom, language)) {
495: * and the new line is
496: */
497: else if (lang_match(node->atom, language)) {
1.17 luotonen 498: wild = node;
499: }
500: }
501:
502: if (wild) {
503: return wild->quality;
504: }
505: else {
506: return 0.1;
507: }
508: }
509:
510:
1.77 frystyk 511: PRIVATE double encoding_value (HTAtom * encoding, HTList * accepted)
1.17 luotonen 512: {
513: HTList * cur = accepted;
514: HTAcceptNode * node;
515: HTAcceptNode * wild = NULL;
516: char * e;
517:
518: if (!encoding || !accepted || HTList_isEmpty(accepted))
519: return 1;
520:
521: e = HTAtom_name(encoding);
522: if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
523: return 1;
524:
525: while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
526: if (node->atom == encoding)
527: return node->quality;
528: else if (wild_match(node->atom, encoding))
529: wild = node;
530: }
531: if (wild) return wild->quality;
532: else return 1;
533: }
534:
535:
1.77 frystyk 536: PUBLIC BOOL HTRank (HTList * possibilities,
537: HTList * accepted_content_types,
538: HTList * accepted_languages,
539: HTList * accepted_encodings)
1.17 luotonen 540: {
541: int accepted_cnt = 0;
542: HTList * accepted;
543: HTList * sorted;
544: HTList * cur;
545: HTContentDescription * d;
546:
547: if (!possibilities) return NO;
548:
549: accepted = HTList_new();
550: cur = possibilities;
551: while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
1.59 frystyk 552: double tv = type_value(d->content_type, accepted_content_types);
553: double lv = lang_value(d->content_language, accepted_languages);
554: double ev = encoding_value(d->content_encoding, accepted_encodings);
1.17 luotonen 555:
556: if (tv > 0) {
557: d->quality *= tv * lv * ev;
558: HTList_addObject(accepted, d);
559: accepted_cnt++;
560: }
1.18 luotonen 561: else {
1.86 frystyk 562: HT_FREE(d->filename);
1.83 frystyk 563: HT_FREE(d);
1.18 luotonen 564: }
1.17 luotonen 565: }
566:
1.87 frystyk 567: if (CORE_TRACE) HTTrace("Ranking.....\n");
568: if (CORE_TRACE) HTTrace(
1.18 luotonen 569: "\nRANK QUALITY CONTENT-TYPE LANGUAGE ENCODING FILE\n");
1.17 luotonen 570:
571: sorted = HTList_new();
572: while (accepted_cnt-- > 0) {
573: HTContentDescription * worst = NULL;
574: cur = accepted;
575: while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
576: if (!worst || d->quality < worst->quality)
577: worst = d;
578: }
579: if (worst) {
1.87 frystyk 580: if (CORE_TRACE)
1.84 eric 581: HTTrace("%d. %.4f %-20.20s %-8.8s %-10.10s %s\n",
1.58 frystyk 582: accepted_cnt+1,
583: worst->quality,
584: (worst->content_type
1.17 luotonen 585: ? HTAtom_name(worst->content_type) : "-"),
1.58 frystyk 586: (worst->content_language
1.17 luotonen 587: ? HTAtom_name(worst->content_language) :"-"),
1.58 frystyk 588: (worst->content_encoding
1.17 luotonen 589: ? HTAtom_name(worst->content_encoding) :"-"),
1.58 frystyk 590: (worst->filename
1.17 luotonen 591: ? worst->filename :"-"));
592: HTList_removeObject(accepted, (void*)worst);
593: HTList_addObject(sorted, (void*)worst);
594: }
595: }
1.87 frystyk 596: if (CORE_TRACE) HTTrace("\n");
1.17 luotonen 597: HTList_delete(accepted);
598: HTList_delete(possibilities->next);
599: possibilities->next = sorted->next;
600: sorted->next = NULL;
601: HTList_delete(sorted);
602:
603: if (!HTList_isEmpty(possibilities)) return YES;
604: else return NO;
605: }
606:
607:
1.87 frystyk 608: /* Create a Content Type filter stack
609: ** ----------------------------------
1.7 secret 610: ** If a wildcard match is made, a temporary HTPresentation
1.2 timbl 611: ** structure is made to hold the destination format while the
612: ** new stack is generated. This is just to pass the out format to
613: ** MIME so far. Storing the format of a stream in the stream might
614: ** be a lot neater.
1.10 timbl 615: **
1.29 frystyk 616: ** The star/star format is special, in that if you can take
1.40 frystyk 617: ** that you can take anything.
1.2 timbl 618: */
1.77 frystyk 619: PUBLIC HTStream * HTStreamStack (HTFormat rep_in,
620: HTFormat rep_out,
621: HTStream * output_stream,
622: HTRequest * request,
623: BOOL guess)
1.2 timbl 624: {
1.14 timbl 625: HTList * conversion[2];
626: int which_list;
1.59 frystyk 627: double best_quality = -1e30; /* Pretty bad! */
1.65 frystyk 628: HTPresentation *pres, *best_match=NULL;
1.80 frystyk 629: if (rep_out == WWW_RAW) {
1.87 frystyk 630: if (CORE_TRACE) HTTrace("StreamStack. Raw output...\n");
1.81 frystyk 631: return output_stream ? output_stream : HTErrorStream();
1.34 luotonen 632: }
1.79 frystyk 633:
1.80 frystyk 634: if (rep_out == rep_in) {
1.87 frystyk 635: if (CORE_TRACE)
1.84 eric 636: HTTrace("StreamStack. Identical input/output format (%s)\n",
1.80 frystyk 637: HTAtom_name(rep_out));
1.81 frystyk 638: return output_stream ? output_stream : HTErrorStream();
1.74 frystyk 639: }
1.87 frystyk 640: if (CORE_TRACE) {
1.82 frystyk 641: char *p = HTAtom_name(rep_in);
642: char *q = HTAtom_name(rep_out);
1.84 eric 643: HTTrace("StreamStack. Constructing stream stack for %s to %s\n",
1.82 frystyk 644: p ? p : "<NULL>", q ? q : "<NULL>");
1.47 frystyk 645: }
1.2 timbl 646:
1.88 ! frystyk 647: conversion[0] = HTRequest_conversion(request);
1.14 timbl 648: conversion[1] = HTConversions;
1.17 luotonen 649:
1.15 luotonen 650: for(which_list = 0; which_list<2; which_list++) {
651: HTList * cur = conversion[which_list];
652: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.65 frystyk 653: if ((pres->rep==rep_in || wild_match(pres->rep, rep_in)) &&
654: (pres->rep_out==rep_out || wild_match(pres->rep_out,rep_out))){
655: if (!best_match || better_match(pres->rep, best_match->rep) ||
1.33 luotonen 656: (!better_match(best_match->rep, pres->rep) &&
657: pres->quality > best_quality)) {
1.85 frystyk 658: #ifdef HAVE_SYSTEM
1.65 frystyk 659: int result=0;
660: if (pres->test_command) {
661: result = system(pres->test_command);
1.87 frystyk 662: if (CORE_TRACE)
1.84 eric 663: HTTrace("StreamStack. system(%s) returns %d\n", pres->test_command, result);
1.65 frystyk 664: }
665: if (!result) {
1.49 howcome 666: best_match = pres;
667: best_quality = pres->quality;
668: }
1.65 frystyk 669: #else
670: best_match = pres;
671: best_quality = pres->quality;
1.85 frystyk 672: #endif /* HAVE_SYSTEM */
1.10 timbl 673: }
674: }
1.2 timbl 675: }
676: }
1.80 frystyk 677:
678: if (best_match) {
679: if (rep_out == WWW_SOURCE && best_match->rep_out != WWW_SOURCE) {
1.87 frystyk 680: if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81 frystyk 681: return output_stream ? output_stream : HTErrorStream();
1.80 frystyk 682: }
1.65 frystyk 683: return (*best_match->converter)(request, best_match->command,
684: rep_in, rep_out, output_stream);
1.80 frystyk 685: }
686: if (rep_out == WWW_SOURCE) {
1.87 frystyk 687: if (CORE_TRACE) HTTrace("StreamStack. Source output\n");
1.81 frystyk 688: return output_stream ? output_stream : HTErrorStream();
1.80 frystyk 689: }
690:
1.87 frystyk 691: if (CORE_TRACE)
1.84 eric 692: HTTrace("StreamStack. No match found, dumping to local file\n");
1.65 frystyk 693: return HTSaveLocally(request, NULL, rep_in, rep_out, output_stream);
1.2 timbl 694: }
695:
696:
697: /* Find the cost of a filter stack
698: ** -------------------------------
699: **
700: ** Must return the cost of the same stack which StreamStack would set up.
701: **
702: ** On entry,
703: ** length The size of the data to be converted
704: */
1.77 frystyk 705: PUBLIC double HTStackValue (HTList * theseConversions,
706: HTFormat rep_in,
707: HTFormat rep_out,
708: double initial_value,
709: long int length)
1.2 timbl 710: {
1.14 timbl 711: int which_list;
712: HTList* conversion[2];
713:
1.87 frystyk 714: if (CORE_TRACE) {
1.84 eric 715: HTTrace("StackValue.. Evaluating stream stack for %s worth %.3f to %s\n",
1.65 frystyk 716: HTAtom_name(rep_in), initial_value,
717: HTAtom_name(rep_out));
718: }
1.2 timbl 719: if (rep_out == WWW_SOURCE ||
1.10 timbl 720: rep_out == rep_in) return 0.0;
1.2 timbl 721:
1.14 timbl 722: conversion[0] = theseConversions;
723: conversion[1] = HTConversions;
724:
725: for(which_list = 0; which_list<2; which_list++)
726: if (conversion[which_list]) {
1.15 luotonen 727: HTList * cur = conversion[which_list];
1.2 timbl 728: HTPresentation * pres;
1.15 luotonen 729: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
730: if (pres->rep == rep_in &&
1.17 luotonen 731: (pres->rep_out == rep_out || wild_match(pres->rep_out, rep_out))) {
1.59 frystyk 732: double value = initial_value * pres->quality;
1.2 timbl 733: if (HTMaxSecs != 0.0)
1.15 luotonen 734: value = value - (length*pres->secs_per_byte + pres->secs)
1.2 timbl 735: /HTMaxSecs;
736: return value;
737: }
738: }
739: }
1.63 frystyk 740: return NO_VALUE_FOUND; /* Really bad */
1.1 timbl 741: }
1.2 timbl 742:
1.87 frystyk 743: /* Create a new coder and insert it into stream chain
744: ** --------------------------------------------------
745: ** Creating the content decoding stack is not based on quality factors as
746: ** we don't have the freedom as with content types. Specify whether you
1.88 ! frystyk 747: ** you want encoding or decoding using the BOOL "encode" flag.
1.87 frystyk 748: */
1.88 ! frystyk 749: PUBLIC HTStream * HTContentCodingStack (HTEncoding encoding,
! 750: HTStream * target,
! 751: HTRequest * request,
! 752: void * param,
! 753: BOOL encode)
1.87 frystyk 754: {
755: HTList * coders[2];
756: HTStream * top = target;
1.88 ! frystyk 757: HTCoding * pres = NULL;
1.87 frystyk 758: int cnt;
1.88 ! frystyk 759: if (!encoding || !request) {
1.87 frystyk 760: if (CORE_TRACE) HTTrace("Codings... Nothing applied...\n");
761: return target ? target : HTErrorStream();
762: }
1.88 ! frystyk 763: coders[0] = HTRequest_encoding(request);
! 764: coders[1] = HTContentCoders;
1.87 frystyk 765: if (CORE_TRACE)
1.88 ! frystyk 766: HTTrace("Codings..... Looking for %s\n", HTAtom_name(encoding));
1.87 frystyk 767: for (cnt=0; cnt < 2; cnt++) {
768: HTList * cur = coders[cnt];
1.88 ! frystyk 769: while ((pres = (HTCoding *) HTList_nextObject(cur))) {
! 770: if (pres->encoding == encoding) {
1.87 frystyk 771: if (CORE_TRACE) HTTrace("Codings..... Found...\n");
1.88 ! frystyk 772: if (encode) {
1.87 frystyk 773: if (pres->encoder)
1.88 ! frystyk 774: top = (*pres->encoder)(request, param, encoding, top);
1.87 frystyk 775: break;
776: } else if (pres->decoder) {
1.88 ! frystyk 777: top = (*pres->decoder)(request, param, encoding, top);
1.87 frystyk 778: break;
779: }
780: }
781: }
782: }
783: return top;
784: }
1.10 timbl 785:
1.87 frystyk 786: /*
787: ** Here you can provide a complete list instead of a single token.
788: ** The list has to filled up in the order the _encodings_ are to be applied
789: */
1.88 ! frystyk 790: PUBLIC HTStream * HTContentEncodingStack (HTList * encodings,
! 791: HTStream * target,
! 792: HTRequest * request,
! 793: void * param)
1.87 frystyk 794: {
795: if (encodings) {
796: HTList * cur = encodings;
797: HTEncoding pres;
798: HTStream * top = target;
799: while ((pres = (HTEncoding) HTList_nextObject(cur)))
1.88 ! frystyk 800: top = HTContentCodingStack(pres, top, request, param, YES);
1.87 frystyk 801: return top;
802: }
803: return HTErrorStream();
804: }
805:
806: /*
807: ** Here you can provide a complete list instead of a single token.
808: ** The list has to be in the order the _encodings_ were applied - that
809: ** is, the same way that _encodings_ are to be applied. This is all consistent
810: ** with the order of the Content-Encoding header.
811: */
1.88 ! frystyk 812: PUBLIC HTStream * HTContentDecodingStack (HTList * encodings,
! 813: HTStream * target,
! 814: HTRequest * request,
! 815: void * param)
1.87 frystyk 816: {
817: if (encodings) {
818: HTEncoding pres;
819: int cnt = HTList_count(encodings);
820: HTStream * top = target;
821: while (cnt > 0) {
822: pres = (HTEncoding) HTList_objectAt(encodings, --cnt);
1.88 ! frystyk 823: top = HTContentCodingStack(pres, top, request, param, NO);
1.87 frystyk 824: }
825: return top;
826: }
827: return HTErrorStream();
828: }
1.88 ! frystyk 829:
! 830: /* Create a new transfer coder and insert it into stream chain
! 831: ** -----------------------------------------------------------
! 832: ** Creating the content decoding stack is not based on quality factors as
! 833: ** we don't have the freedom as with content types. Specify whether you
! 834: ** you want encoding or decoding using the BOOL "encode" flag.
! 835: */
! 836: PUBLIC HTStream * HTTransferCodingStack (HTEncoding encoding,
! 837: HTStream * target,
! 838: HTRequest * request,
! 839: void * param,
! 840: BOOL encode)
! 841: {
! 842: HTList * coders[2];
! 843: HTStream * top = target;
! 844: HTCoding * pres = NULL;
! 845: int cnt;
! 846: if (!encoding || !request) {
! 847: if (CORE_TRACE) HTTrace("C-T-E..... Nothing applied...\n");
! 848: return target ? target : HTErrorStream();
! 849: }
! 850: coders[0] = HTRequest_transfer(request);
! 851: coders[1] = HTTransferCoders;
! 852: if (CORE_TRACE)
! 853: HTTrace("C-T-E....... Looking for %s\n", HTAtom_name(encoding));
! 854: for (cnt=0; cnt < 2; cnt++) {
! 855: HTList * cur = coders[cnt];
! 856: while ((pres = (HTCoding *) HTList_nextObject(cur))) {
! 857: if (pres->encoding == encoding) {
! 858: if (CORE_TRACE) HTTrace("C-T-E....... Found...\n");
! 859: if (encode) {
! 860: if (pres->encoder)
! 861: top = (*pres->encoder)(request, param, encoding, top);
! 862: break;
! 863: } else if (pres->decoder) {
! 864: top = (*pres->decoder)(request, param, encoding, top);
! 865: break;
! 866: }
! 867: }
! 868: }
! 869: }
! 870: return top;
! 871: }
! 872:
Webmaster