HTFormat.c
上传用户:zlh9724
上传日期:2007-01-04
资源大小:1991k
文件大小:17k
源码类别:

浏览器

开发平台:

Unix_Linux

  1. /*      HTFormat.c
  2. ** MANAGE DIFFERENT FILE FORMATS
  3. **
  4. ** (c) COPYRIGHT MIT 1995.
  5. ** Please first read the full copyright statement in the file COPYRIGH.
  6. **
  7. ** Bugs:
  8. ** Assumes the incoming stream is ASCII, rather than a local file
  9. ** format, and so ALWAYS converts from ASCII on non-ASCII machines.
  10. ** Therefore, non-ASCII machines can't read local files.
  11. **
  12. ** HISTORY:
  13. ** 8 Jul 94  FM Insulate free() from _free structure element.
  14. ** 8 Nov 94  HFN Changed a lot to make reentrant
  15. */
  16. /* Library Include files */
  17. #include "tcp.h"
  18. #include "HTUtils.h"
  19. #include "HTString.h"
  20. #include "HTTCP.h"
  21. #include "HTFWrite.h"
  22. #include "HTNetMan.h"
  23. #include "HTError.h"
  24. #include "HTReqMan.h"
  25. #include "HTFormat.h"  /* Implemented here */
  26. #define NO_VALUE_FOUND -1e30  /* Stream Stack Value if none found */
  27. PRIVATE HTList * HTConversions = NULL;
  28. PRIVATE HTList * HTCharsets = NULL;
  29. PRIVATE HTList * HTEncodings = NULL;
  30. PRIVATE HTList * HTLanguages = NULL;
  31. PRIVATE double HTMaxSecs = 1e10; /* No effective limit */
  32. struct _HTStream {
  33.     CONST HTStreamClass * isa;
  34. };
  35. /* ------------------------------------------------------------------------- */
  36. /*    ACCEPT LISTS OF CONVERSIONS, ENCODINGS, LANGUAGE, AND CHARSET      */
  37. /* ------------------------------------------------------------------------- */
  38. /*
  39. ** For all `accept lists' there is a local list and a global list. The
  40. ** local list is a part of the request structure and the global list is
  41. ** internal to the HTFormat module. The global lists can be used when
  42. ** specifying accept lists for ALL requests and the local list can be 
  43. ** used to add specific accept headers to the request.
  44. */
  45. /* Define a presentation system command for a content-type
  46. ** -------------------------------------------------------
  47. ** INPUT:
  48. ** conversions: The list of conveters and presenters
  49. ** representation: the MIME-style format name
  50. ** command: the MAILCAP-style command template
  51. ** quality: A degradation faction [0..1]
  52. ** maxbytes: A limit on the length acceptable as input (0 infinite)
  53. ** maxsecs: A limit on the time user will wait (0 for infinity)
  54. */
  55. PUBLIC void HTPresentation_add (HTList * conversions,
  56. CONST char * representation,
  57. CONST char * command,
  58. CONST char * test_command,
  59. double quality,
  60. double secs, 
  61. double secs_per_byte)
  62. {
  63.     HTPresentation * pres;
  64.     if ((pres = (HTPresentation  *) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
  65.         HT_OUTOFMEM("HTSetPresentation");
  66.     
  67.     pres->rep = HTAtom_for(representation);
  68.     pres->rep_out = WWW_PRESENT; /* Fixed for now ... :-) */
  69.     pres->converter = HTSaveAndExecute; /* Fixed for now ...     */
  70.     pres->quality = quality;
  71.     pres->secs = secs;
  72.     pres->secs_per_byte = secs_per_byte;
  73.     pres->rep = HTAtom_for(representation);
  74.     pres->command = NULL;
  75.     StrAllocCopy(pres->command, command);
  76.     pres->test_command = NULL;
  77.     StrAllocCopy(pres->test_command, test_command);
  78.     HTList_addObject(conversions, pres);
  79. }
  80. PUBLIC void HTPresentation_deleteAll (HTList * list)
  81. {
  82.     if (list) {
  83. HTList *cur = list;
  84. HTPresentation *pres;
  85. while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
  86.     HT_FREE(pres->command);
  87.     HT_FREE(pres);
  88. }
  89. HTList_delete(list);
  90.     }
  91. }
  92. /* Define a built-in function for a content-type
  93. ** ---------------------------------------------
  94. */
  95. PUBLIC void HTConversion_add (HTList * conversions,
  96.       CONST char * representation_in,
  97.       CONST char * representation_out,
  98.       HTConverter * converter,
  99.       double quality,
  100.       double secs, 
  101.       double secs_per_byte)
  102. {
  103.     HTPresentation * pres;
  104.     if ((pres = (HTPresentation  *) HT_CALLOC(1,sizeof(HTPresentation))) == NULL)
  105.         HT_OUTOFMEM("HTSetPresentation");
  106.     
  107.     pres->rep = HTAtom_for(representation_in);
  108.     pres->rep_out = HTAtom_for(representation_out);
  109.     pres->converter = converter;
  110.     pres->command = NULL; /* Fixed */
  111.     pres->test_command = NULL;
  112.     pres->quality = quality;
  113.     pres->secs = secs;
  114.     pres->secs_per_byte = secs_per_byte;
  115.     HTList_addObject(conversions, pres);
  116. }
  117. PUBLIC void HTConversion_deleteAll (HTList * list)
  118. {
  119.     HTPresentation_deleteAll(list);
  120. }
  121. PUBLIC void HTEncoding_add (HTList *  list,
  122.     CONST char * enc,
  123.     double quality)
  124. {
  125.     HTAcceptNode * node;
  126.     if (!list || !enc || !*enc) {
  127. if (WWWTRACE)
  128.     TTYPrint(TDEST, "Encodings... Bad argumentn");
  129. return;
  130.     }
  131.     if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
  132.         HT_OUTOFMEM("HTAcceptEncoding");
  133.     HTList_addObject(list, (void*)node);
  134.     node->atom = HTAtom_for(enc);
  135.     node->quality = quality;
  136. }
  137. PUBLIC void HTEncoding_deleteAll (HTList * list)
  138. {
  139.     if (list) {
  140. HTList *cur = list;
  141. HTAcceptNode *pres;
  142. while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
  143.     HT_FREE(pres);
  144. }
  145. HTList_delete(list);
  146.     }
  147. }
  148. PUBLIC void HTLanguage_add (HTList * list,
  149.     CONST char * lang,
  150.     double quality)
  151. {
  152.     HTAcceptNode * node;
  153.     if (!list || !lang || !*lang)  {
  154. if (WWWTRACE)
  155.     TTYPrint(TDEST, "Languages... Bad argumentn");
  156. return;
  157.     }
  158.     if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
  159.         HT_OUTOFMEM("HTAcceptLanguage");
  160.     HTList_addObject(list, (void*)node);
  161.     node->atom = HTAtom_for(lang);
  162.     node->quality = quality;
  163. }
  164. PUBLIC void HTLanguage_deleteAll (HTList * list)
  165. {
  166.     HTEncoding_deleteAll(list);
  167. }
  168. PUBLIC void HTCharset_add (HTList * list,
  169.    CONST char * charset,
  170.    double quality)
  171. {
  172.     HTAcceptNode * node;
  173.     if (!list || !charset || !*charset)  {
  174. if (WWWTRACE)
  175.     TTYPrint(TDEST, "Charset..... Bad argumentn");
  176. return;
  177.     }
  178.     if ((node = (HTAcceptNode *) HT_CALLOC(1, sizeof(HTAcceptNode))) == NULL)
  179.         HT_OUTOFMEM("HTAcceptCharsetuage");
  180.     HTList_addObject(list, (void*)node);
  181.     node->atom = HTAtom_for(charset);
  182.     node->quality = quality;
  183. }
  184. PUBLIC void HTCharset_deleteAll (HTList * list)
  185. {
  186.     HTEncoding_deleteAll(list);
  187. }
  188. /* ------------------------------------------------------------------------- */
  189. /*  GLOBAL LIST OF CONVERTERS ETC.      */
  190. /* ------------------------------------------------------------------------- */
  191. /*
  192. ** Global Accept Format Types Conversions
  193. ** list can be NULL
  194. */
  195. PUBLIC void HTFormat_setConversion (HTList * list)
  196. {
  197.     HTConversions = list;
  198. }
  199. PUBLIC HTList * HTFormat_conversion (void)
  200. {
  201.     return HTConversions;
  202. }
  203. /*
  204. ** Global Accept Encodings
  205. ** list can be NULL
  206. */
  207. PUBLIC void HTFormat_setEncoding (HTList *list)
  208. {
  209.     HTEncodings = list;
  210. }
  211. PUBLIC HTList * HTFormat_encoding (void)
  212. {
  213.     return HTEncodings;
  214. }
  215. /*
  216. ** Global Accept Languages
  217. ** list can be NULL
  218. */
  219. PUBLIC void HTFormat_setLanguage (HTList *list)
  220. {
  221.     HTLanguages = list;
  222. }
  223. PUBLIC HTList * HTFormat_language (void)
  224. {
  225.     return HTLanguages;
  226. }
  227. /*
  228. ** Global Accept Charsets
  229. ** list can be NULL
  230. */
  231. PUBLIC void HTFormat_setCharset (HTList *list)
  232. {
  233.     HTCharsets = list;
  234. }
  235. PUBLIC HTList * HTFormat_charset (void)
  236. {
  237.     return HTCharsets;
  238. }
  239. /*
  240. ** Convenience function to clean up
  241. */
  242. PUBLIC void HTFormat_deleteAll (void)
  243. {
  244.     if (HTConversions) {
  245. HTConversion_deleteAll(HTConversions);
  246. HTConversions = NULL;
  247.     }
  248.     if (HTLanguages) {
  249. HTLanguage_deleteAll(HTLanguages);
  250. HTLanguages = NULL;
  251.     }
  252.     if (HTEncodings) {
  253. HTEncoding_deleteAll(HTEncodings);
  254. HTEncodings = NULL;
  255.     }
  256.     if (HTCharsets) {
  257. HTCharset_deleteAll(HTCharsets);
  258. HTCharsets = NULL;
  259.     }
  260. }
  261. /* ------------------------------------------------------------------------- */
  262. /*  FORMAT NEGOTIATION      */
  263. /* ------------------------------------------------------------------------- */
  264. PRIVATE BOOL better_match (HTFormat f, HTFormat g)
  265. {
  266.     CONST char *p, *q;
  267.     if (f && g  &&  (p = HTAtom_name(f))  &&  (q = HTAtom_name(g))) {
  268. int i,j;
  269. for(i=0 ; *p; p++) if (*p == '*') i++;
  270. for(j=0 ; *q; q++) if (*q == '*') j++;
  271. if (i < j) return YES;
  272.     }
  273.     return NO;
  274. }
  275. PRIVATE BOOL wild_match (HTAtom * tmplate, HTAtom * actual)
  276. {
  277.     char *t, *a, *st, *sa;
  278.     BOOL match = NO;
  279.     if (tmplate && actual && (t = HTAtom_name(tmplate))) {
  280. if (!strcmp(t, "*"))
  281.     return YES;
  282. if (strchr(t, '*') &&
  283.     (a = HTAtom_name(actual)) &&
  284.     (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {
  285.     *sa = 0;
  286.     *st = 0;
  287.     if ((*(st-1)=='*' &&
  288.  (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
  289. (*(st+1)=='*' && !strcasecomp(t,a)))
  290. match = YES;
  291.     *sa = '/';
  292.     *st = '/';
  293. }    
  294.     }
  295.     return match;
  296. }
  297. /*
  298.  * Added by takada@seraph.ntt.jp (94/04/08)
  299.  */
  300. PRIVATE BOOL lang_match (HTAtom * tmplate, HTAtom * actual)
  301. {
  302.     char *t, *a, *st, *sa;
  303.     BOOL match = NO;
  304.     if (tmplate && actual &&
  305. (t = HTAtom_name(tmplate)) && (a = HTAtom_name(actual))) {
  306. st = strchr(t, '_');
  307. sa = strchr(a, '_');
  308. if ((st != NULL) && (sa != NULL)) {
  309.     if (!strcasecomp(t, a))
  310.       match = YES;
  311.     else
  312.       match = NO;
  313. }
  314. else {
  315.     if (st != NULL) *st = 0;
  316.     if (sa != NULL) *sa = 0;
  317.     if (!strcasecomp(t, a))
  318.       match = YES;
  319.     else
  320.       match = NO;
  321.     if (st != NULL) *st = '_';
  322.     if (sa != NULL) *sa = '_';
  323. }
  324.     }
  325.     return match;
  326. }
  327. /* end of addition */
  328. PRIVATE double type_value (HTAtom * content_type, HTList * accepted)
  329. {
  330.     HTList * cur = accepted;
  331.     HTPresentation * pres;
  332.     HTPresentation * wild = NULL;
  333.     if (!content_type || !accepted) return -1;
  334.     while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
  335. if (pres->rep == content_type)
  336.     return pres->quality;
  337. else if (wild_match(pres->rep, content_type))
  338.     wild = pres;
  339.     }
  340.     if (wild) return wild->quality;
  341.     else return -1;
  342. }
  343. PRIVATE double lang_value (HTAtom * language, HTList * accepted)
  344. {
  345.     HTList * cur = accepted;
  346.     HTAcceptNode * node;
  347.     HTAcceptNode * wild = NULL;
  348.     if (!language || !accepted || HTList_isEmpty(accepted)) {
  349. return 0.1;
  350.     }
  351.     while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
  352. if (node->atom == language) {
  353.     return node->quality;
  354. }
  355. /*
  356.  * patch by takada@seraph.ntt.jp (94/04/08)
  357.  * the original line was
  358.  * else if (wild_match(node->atom, language)) {
  359.  * and the new line is
  360.  */
  361. else if (lang_match(node->atom, language)) {
  362.     wild = node;
  363. }
  364.     }
  365.     if (wild) {
  366. return wild->quality;
  367.     }
  368.     else {
  369. return 0.1;
  370.     }
  371. }
  372. PRIVATE double encoding_value (HTAtom * encoding, HTList * accepted)
  373. {
  374.     HTList * cur = accepted;
  375.     HTAcceptNode * node;
  376.     HTAcceptNode * wild = NULL;
  377.     char * e;
  378.     if (!encoding || !accepted || HTList_isEmpty(accepted))
  379. return 1;
  380.     e = HTAtom_name(encoding);
  381.     if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
  382. return 1;
  383.     while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
  384. if (node->atom == encoding)
  385.     return node->quality;
  386. else if (wild_match(node->atom, encoding))
  387.     wild = node;
  388.     }
  389.     if (wild) return wild->quality;
  390.     else return 1;
  391. }
  392. PUBLIC BOOL HTRank (HTList * possibilities,
  393.     HTList * accepted_content_types,
  394.     HTList * accepted_languages,
  395.     HTList * accepted_encodings)
  396. {
  397.     int accepted_cnt = 0;
  398.     HTList * accepted;
  399.     HTList * sorted;
  400.     HTList * cur;
  401.     HTContentDescription * d;
  402.     if (!possibilities) return NO;
  403.     accepted = HTList_new();
  404.     cur = possibilities;
  405.     while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
  406. double tv = type_value(d->content_type, accepted_content_types);
  407. double lv = lang_value(d->content_language, accepted_languages);
  408. double ev = encoding_value(d->content_encoding, accepted_encodings);
  409. if (tv > 0) {
  410.     d->quality *= tv * lv * ev;
  411.     HTList_addObject(accepted, d);
  412.     accepted_cnt++;
  413. }
  414. else {
  415.     if (d->filename) HT_FREE(d->filename);
  416.     HT_FREE(d);
  417. }
  418.     }
  419.     if (PROT_TRACE) TTYPrint(TDEST, "Ranking.....n");
  420.     if (PROT_TRACE) TTYPrint(TDEST,
  421.    "nRANK QUALITY CONTENT-TYPE         LANGUAGE ENCODING    FILEn");
  422.     sorted = HTList_new();
  423.     while (accepted_cnt-- > 0) {
  424. HTContentDescription * worst = NULL;
  425. cur = accepted;
  426. while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
  427.     if (!worst || d->quality < worst->quality)
  428. worst = d;
  429. }
  430. if (worst) {
  431.     if (PROT_TRACE)
  432. TTYPrint(TDEST, "%d.   %.4f  %-20.20s %-8.8s %-10.10s %sn",
  433. accepted_cnt+1,
  434. worst->quality,
  435. (worst->content_type
  436.          ? HTAtom_name(worst->content_type)      : "-"),
  437. (worst->content_language
  438.          ? HTAtom_name(worst->content_language)  :"-"),
  439. (worst->content_encoding
  440.          ? HTAtom_name(worst->content_encoding)  :"-"),
  441. (worst->filename
  442.          ? worst->filename                       :"-"));
  443.     HTList_removeObject(accepted, (void*)worst);
  444.     HTList_addObject(sorted, (void*)worst);
  445. }
  446.     }
  447.     if (PROT_TRACE) TTYPrint(TDEST, "n");
  448.     HTList_delete(accepted);
  449.     HTList_delete(possibilities->next);
  450.     possibilities->next = sorted->next;
  451.     sorted->next = NULL;
  452.     HTList_delete(sorted);
  453.     if (!HTList_isEmpty(possibilities)) return YES;
  454.     else return NO;
  455. }
  456. /* Create a filter stack
  457. ** ---------------------
  458. **
  459. ** If a wildcard match is made, a temporary HTPresentation
  460. ** structure is made to hold the destination format while the
  461. ** new stack is generated. This is just to pass the out format to
  462. ** MIME so far.  Storing the format of a stream in the stream might
  463. ** be a lot neater.
  464. **
  465. ** The star/star format is special, in that if you can take
  466. ** that you can take anything.
  467. */
  468. PUBLIC HTStream * HTStreamStack (HTFormat rep_in,
  469.  HTFormat rep_out,
  470.  HTStream * output_stream,
  471.  HTRequest * request,
  472.  BOOL guess)
  473. {
  474.     HTList * conversion[2];
  475.     int which_list;
  476.     double best_quality = -1e30; /* Pretty bad! */
  477.     HTPresentation *pres, *best_match=NULL;
  478.     if (rep_out == WWW_RAW) {
  479. if (STREAM_TRACE) TTYPrint(TDEST,"StreamStack. Raw output...n");
  480. return output_stream ? output_stream : HTErrorStream();
  481.     }
  482.     if (rep_out == rep_in) {
  483. if (STREAM_TRACE)
  484.     TTYPrint(TDEST,"StreamStack. Identical input/output format (%s)n",
  485.      HTAtom_name(rep_out));
  486. return output_stream ? output_stream : HTErrorStream();
  487.     }
  488.     if (STREAM_TRACE) {
  489. char *p = HTAtom_name(rep_in);
  490. char *q = HTAtom_name(rep_out); 
  491. TTYPrint(TDEST,"StreamStack. Constructing stream stack for %s to %sn",
  492.  p ? p : "<NULL>", q ? q : "<NULL>");
  493.     }
  494.     conversion[0] = request->conversions;
  495.     conversion[1] = HTConversions;
  496.     for(which_list = 0; which_list<2; which_list++) {
  497. HTList * cur = conversion[which_list];
  498. while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
  499.     if ((pres->rep==rep_in || wild_match(pres->rep, rep_in)) &&
  500. (pres->rep_out==rep_out || wild_match(pres->rep_out,rep_out))){
  501. if (!best_match || better_match(pres->rep, best_match->rep) ||
  502.     (!better_match(best_match->rep, pres->rep) &&
  503.      pres->quality > best_quality)) {
  504. #ifdef GOT_SYSTEM
  505.     int result=0;
  506.     if (pres->test_command) {
  507. result = system(pres->test_command);
  508. if (STREAM_TRACE) 
  509.     TTYPrint(TDEST, "StreamStack. system(%s) returns %dn", pres->test_command, result);
  510.     }
  511.     if (!result) {
  512. best_match = pres;
  513. best_quality = pres->quality;
  514.     }
  515. #else
  516.     best_match = pres;
  517.     best_quality = pres->quality;
  518. #endif /* GOT_SYSTEM */
  519. }
  520.     }
  521. }
  522.     }
  523.     if (best_match) {
  524.   if (rep_out == WWW_SOURCE && best_match->rep_out != WWW_SOURCE) {
  525.     if (STREAM_TRACE) TTYPrint(TDEST,"StreamStack. Source outputn");
  526.     return output_stream ? output_stream : HTErrorStream();
  527. }
  528. return (*best_match->converter)(request, best_match->command,
  529. rep_in, rep_out, output_stream);
  530.     }
  531.     if (rep_out == WWW_SOURCE) {
  532. if (STREAM_TRACE) TTYPrint(TDEST,"StreamStack. Source outputn");
  533. return output_stream ? output_stream : HTErrorStream();
  534.     }
  535.     if (STREAM_TRACE)
  536. TTYPrint(TDEST,"StreamStack. No match found, dumping to local filen");
  537.     return HTSaveLocally(request, NULL, rep_in, rep_out, output_stream);
  538. }
  539. /* Find the cost of a filter stack
  540. ** -------------------------------
  541. **
  542. ** Must return the cost of the same stack which StreamStack would set up.
  543. **
  544. ** On entry,
  545. ** length The size of the data to be converted
  546. */
  547. PUBLIC double HTStackValue (HTList * theseConversions,
  548.     HTFormat rep_in,
  549.     HTFormat rep_out,
  550.     double initial_value,
  551.     long int length)
  552. {
  553.     int which_list;
  554.     HTList* conversion[2];
  555.     
  556.     if (STREAM_TRACE) {
  557. TTYPrint(TDEST, "StackValue.. Evaluating stream stack for %s worth %.3f to %sn",
  558. HTAtom_name(rep_in), initial_value,
  559. HTAtom_name(rep_out));
  560.     }
  561.     if (rep_out == WWW_SOURCE ||
  562.      rep_out == rep_in) return 0.0;
  563.     conversion[0] = theseConversions;
  564.     conversion[1] = HTConversions;
  565.     
  566.     for(which_list = 0; which_list<2; which_list++)
  567.      if (conversion[which_list]) {
  568.         HTList * cur = conversion[which_list];
  569. HTPresentation * pres;
  570. while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
  571.     if (pres->rep == rep_in &&
  572. (pres->rep_out == rep_out || wild_match(pres->rep_out, rep_out))) {
  573.         double value = initial_value * pres->quality;
  574. if (HTMaxSecs != 0.0)
  575.     value = value - (length*pres->secs_per_byte + pres->secs)
  576.                  /HTMaxSecs;
  577. return value;
  578.     }
  579. }
  580.     }
  581.     return NO_VALUE_FOUND; /* Really bad */
  582. }