charset.js 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. module.exports = preferredCharsets;
  2. preferredCharsets.preferredCharsets = preferredCharsets;
  3. function parseAcceptCharset(accept) {
  4. return accept.split(',').map(function(e) {
  5. return parseCharset(e.trim());
  6. }).filter(function(e) {
  7. return e;
  8. });
  9. }
  10. function parseCharset(s) {
  11. var match = s.match(/^\s*(\S+?)\s*(?:;(.*))?$/);
  12. if (!match) return null;
  13. var charset = match[1];
  14. var q = 1;
  15. if (match[2]) {
  16. var params = match[2].split(';')
  17. for (var i = 0; i < params.length; i ++) {
  18. var p = params[i].trim().split('=');
  19. if (p[0] === 'q') {
  20. q = parseFloat(p[1]);
  21. break;
  22. }
  23. }
  24. }
  25. return {
  26. charset: charset,
  27. q: q
  28. };
  29. }
  30. function getCharsetPriority(charset, accepted) {
  31. return (accepted.map(function(a) {
  32. return specify(charset, a);
  33. }).filter(Boolean).sort(function (a, b) {
  34. if(a.s == b.s) {
  35. return a.q > b.q ? -1 : 1;
  36. } else {
  37. return a.s > b.s ? -1 : 1;
  38. }
  39. })[0] || {s: 0, q:0});
  40. }
  41. function specify(charset, spec) {
  42. var s = 0;
  43. if(spec.charset === charset){
  44. s |= 1;
  45. } else if (spec.charset !== '*' ) {
  46. return null
  47. }
  48. return {
  49. s: s,
  50. q: spec.q,
  51. }
  52. }
  53. function preferredCharsets(accept, provided) {
  54. // RFC 2616 sec 14.2: no header = *
  55. accept = parseAcceptCharset(accept === undefined ? '*' : accept || '');
  56. if (provided) {
  57. return provided.map(function(type) {
  58. return [type, getCharsetPriority(type, accept)];
  59. }).filter(function(pair) {
  60. return pair[1].q > 0;
  61. }).sort(function(a, b) {
  62. var pa = a[1];
  63. var pb = b[1];
  64. if(pa.q == pb.q) {
  65. return pa.s < pb.s ? 1 : -1;
  66. } else {
  67. return pa.q < pb.q ? 1 : -1;
  68. }
  69. }).map(function(pair) {
  70. return pair[0];
  71. });
  72. } else {
  73. return accept.sort(function (a, b) {
  74. // revsort
  75. return a.q < b.q ? 1 : -1;
  76. }).filter(function(type) {
  77. return type.q > 0;
  78. }).map(function(type) {
  79. return type.charset;
  80. });
  81. }
  82. }