charset.js 2.2 KB

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