twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

encoding.js (3506B)


      1 /**
      2  * negotiator
      3  * Copyright(c) 2012 Isaac Z. Schlueter
      4  * Copyright(c) 2014 Federico Romero
      5  * Copyright(c) 2014-2015 Douglas Christopher Wilson
      6  * MIT Licensed
      7  */
      8 
      9 'use strict';
     10 
     11 /**
     12  * Module exports.
     13  * @public
     14  */
     15 
     16 module.exports = preferredEncodings;
     17 module.exports.preferredEncodings = preferredEncodings;
     18 
     19 /**
     20  * Module variables.
     21  * @private
     22  */
     23 
     24 var simpleEncodingRegExp = /^\s*([^\s;]+)\s*(?:;(.*))?$/;
     25 
     26 /**
     27  * Parse the Accept-Encoding header.
     28  * @private
     29  */
     30 
     31 function parseAcceptEncoding(accept) {
     32   var accepts = accept.split(',');
     33   var hasIdentity = false;
     34   var minQuality = 1;
     35 
     36   for (var i = 0, j = 0; i < accepts.length; i++) {
     37     var encoding = parseEncoding(accepts[i].trim(), i);
     38 
     39     if (encoding) {
     40       accepts[j++] = encoding;
     41       hasIdentity = hasIdentity || specify('identity', encoding);
     42       minQuality = Math.min(minQuality, encoding.q || 1);
     43     }
     44   }
     45 
     46   if (!hasIdentity) {
     47     /*
     48      * If identity doesn't explicitly appear in the accept-encoding header,
     49      * it's added to the list of acceptable encoding with the lowest q
     50      */
     51     accepts[j++] = {
     52       encoding: 'identity',
     53       q: minQuality,
     54       i: i
     55     };
     56   }
     57 
     58   // trim accepts
     59   accepts.length = j;
     60 
     61   return accepts;
     62 }
     63 
     64 /**
     65  * Parse an encoding from the Accept-Encoding header.
     66  * @private
     67  */
     68 
     69 function parseEncoding(str, i) {
     70   var match = simpleEncodingRegExp.exec(str);
     71   if (!match) return null;
     72 
     73   var encoding = match[1];
     74   var q = 1;
     75   if (match[2]) {
     76     var params = match[2].split(';');
     77     for (var j = 0; j < params.length; j++) {
     78       var p = params[j].trim().split('=');
     79       if (p[0] === 'q') {
     80         q = parseFloat(p[1]);
     81         break;
     82       }
     83     }
     84   }
     85 
     86   return {
     87     encoding: encoding,
     88     q: q,
     89     i: i
     90   };
     91 }
     92 
     93 /**
     94  * Get the priority of an encoding.
     95  * @private
     96  */
     97 
     98 function getEncodingPriority(encoding, accepted, index) {
     99   var priority = {o: -1, q: 0, s: 0};
    100 
    101   for (var i = 0; i < accepted.length; i++) {
    102     var spec = specify(encoding, accepted[i], index);
    103 
    104     if (spec && (priority.s - spec.s || priority.q - spec.q || priority.o - spec.o) < 0) {
    105       priority = spec;
    106     }
    107   }
    108 
    109   return priority;
    110 }
    111 
    112 /**
    113  * Get the specificity of the encoding.
    114  * @private
    115  */
    116 
    117 function specify(encoding, spec, index) {
    118   var s = 0;
    119   if(spec.encoding.toLowerCase() === encoding.toLowerCase()){
    120     s |= 1;
    121   } else if (spec.encoding !== '*' ) {
    122     return null
    123   }
    124 
    125   return {
    126     i: index,
    127     o: spec.i,
    128     q: spec.q,
    129     s: s
    130   }
    131 };
    132 
    133 /**
    134  * Get the preferred encodings from an Accept-Encoding header.
    135  * @public
    136  */
    137 
    138 function preferredEncodings(accept, provided) {
    139   var accepts = parseAcceptEncoding(accept || '');
    140 
    141   if (!provided) {
    142     // sorted list of all encodings
    143     return accepts
    144       .filter(isQuality)
    145       .sort(compareSpecs)
    146       .map(getFullEncoding);
    147   }
    148 
    149   var priorities = provided.map(function getPriority(type, index) {
    150     return getEncodingPriority(type, accepts, index);
    151   });
    152 
    153   // sorted list of accepted encodings
    154   return priorities.filter(isQuality).sort(compareSpecs).map(function getEncoding(priority) {
    155     return provided[priorities.indexOf(priority)];
    156   });
    157 }
    158 
    159 /**
    160  * Compare two specs.
    161  * @private
    162  */
    163 
    164 function compareSpecs(a, b) {
    165   return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i) || 0;
    166 }
    167 
    168 /**
    169  * Get full encoding string.
    170  * @private
    171  */
    172 
    173 function getFullEncoding(spec) {
    174   return spec.encoding;
    175 }
    176 
    177 /**
    178  * Check if a spec has any quality.
    179  * @private
    180  */
    181 
    182 function isQuality(spec) {
    183   return spec.q > 0;
    184 }