second
[josuexyz/.git] / node_modules / negotiator / lib / encoding.js
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 }