Skip to content

Commit 8f58d74

Browse files
Added an option preferred encodings array (#59)
* Added an option preferred encodings array * fix: updated history.md --------- Co-authored-by: Wes Todd <wes@wesleytodd.com>
1 parent d3c7697 commit 8f58d74

File tree

5 files changed

+76
-9
lines changed

5 files changed

+76
-9
lines changed

HISTORY.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
unreleased
2+
==================
3+
4+
* Added an option preferred encodings array #59
5+
16
0.6.3 / 2022-01-22
27
==================
38

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ Returns the most preferred encoding from the client.
172172

173173
Returns the most preferred encoding from a list of available encodings.
174174

175+
##### encoding(availableEncodings, preferred)
176+
177+
Returns the most preferred encoding from a list of available encodings, while prioritizing based on `preferred` array between same-quality encodings.
178+
175179
##### encodings()
176180

177181
Returns an array of preferred encodings ordered by the client preference.
@@ -181,6 +185,11 @@ Returns an array of preferred encodings ordered by the client preference.
181185
Returns an array of preferred encodings ordered by priority from a list of
182186
available encodings.
183187

188+
##### encodings(availableEncodings, preferred)
189+
190+
Returns an array of preferred encodings ordered by priority from a list of
191+
available encodings, while prioritizing based on `preferred` array between same-quality encodings.
192+
184193
## See Also
185194

186195
The [accepts](https://npmjs.org/package/accepts#readme) module builds on

index.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ Negotiator.prototype.charsets = function charsets(available) {
4444
return preferredCharsets(this.request.headers['accept-charset'], available);
4545
};
4646

47-
Negotiator.prototype.encoding = function encoding(available) {
48-
var set = this.encodings(available);
47+
Negotiator.prototype.encoding = function encoding(available, preferred) {
48+
var set = this.encodings(available, preferred);
4949
return set && set[0];
5050
};
5151

52-
Negotiator.prototype.encodings = function encodings(available) {
53-
return preferredEncodings(this.request.headers['accept-encoding'], available);
52+
Negotiator.prototype.encodings = function encodings(available, preferred) {
53+
return preferredEncodings(this.request.headers['accept-encoding'], available, preferred);
5454
};
5555

5656
Negotiator.prototype.language = function language(available) {

lib/encoding.js

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ function parseEncoding(str, i) {
9696
*/
9797

9898
function getEncodingPriority(encoding, accepted, index) {
99-
var priority = {o: -1, q: 0, s: 0};
99+
var priority = {encoding: encoding, o: -1, q: 0, s: 0};
100100

101101
for (var i = 0; i < accepted.length; i++) {
102102
var spec = specify(encoding, accepted[i], index);
@@ -123,6 +123,7 @@ function specify(encoding, spec, index) {
123123
}
124124

125125
return {
126+
encoding: encoding,
126127
i: index,
127128
o: spec.i,
128129
q: spec.q,
@@ -135,14 +136,34 @@ function specify(encoding, spec, index) {
135136
* @public
136137
*/
137138

138-
function preferredEncodings(accept, provided) {
139+
function preferredEncodings(accept, provided, preferred) {
139140
var accepts = parseAcceptEncoding(accept || '');
140141

142+
var comparator = preferred ? function comparator (a, b) {
143+
if (a.q !== b.q) {
144+
return b.q - a.q // higher quality first
145+
}
146+
147+
var aPreferred = preferred.indexOf(a.encoding)
148+
var bPreferred = preferred.indexOf(b.encoding)
149+
150+
if (aPreferred === -1 && bPreferred === -1) {
151+
// consider the original specifity/order
152+
return (b.s - a.s) || (a.o - b.o) || (a.i - b.i)
153+
}
154+
155+
if (aPreferred !== -1 && bPreferred !== -1) {
156+
return aPreferred - bPreferred // consider the preferred order
157+
}
158+
159+
return aPreferred === -1 ? 1 : -1 // preferred first
160+
} : compareSpecs;
161+
141162
if (!provided) {
142163
// sorted list of all encodings
143164
return accepts
144165
.filter(isQuality)
145-
.sort(compareSpecs)
166+
.sort(comparator)
146167
.map(getFullEncoding);
147168
}
148169

@@ -151,7 +172,7 @@ function preferredEncodings(accept, provided) {
151172
});
152173

153174
// sorted list of accepted encodings
154-
return priorities.filter(isQuality).sort(compareSpecs).map(function getEncoding(priority) {
175+
return priorities.filter(isQuality).sort(comparator).map(function getEncoding(priority) {
155176
return provided[priorities.indexOf(priority)];
156177
});
157178
}
@@ -162,7 +183,7 @@ function preferredEncodings(accept, provided) {
162183
*/
163184

164185
function compareSpecs(a, b) {
165-
return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i) || 0;
186+
return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i);
166187
}
167188

168189
/**

test/encoding.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,14 @@ describe('negotiator.encoding(array)', function () {
190190
it('should return first client-preferred encoding', function () {
191191
assert.strictEqual(this.negotiator.encoding(['deflate', 'compress']), 'deflate')
192192
})
193+
194+
it('should return developer-preferred encodings', function () {
195+
assert.strictEqual(this.negotiator.encoding(['gzip', 'deflate'], ['deflate']), 'deflate')
196+
assert.strictEqual(this.negotiator.encoding(['deflate', 'gzip'], ['deflate']), 'deflate')
197+
assert.strictEqual(this.negotiator.encoding(['gzip', 'deflate'], ['gzip']), 'gzip')
198+
assert.strictEqual(this.negotiator.encoding(['deflate', 'gzip'], ['gzip']), 'gzip')
199+
assert.strictEqual(this.negotiator.encoding(['gzip'], ['gzip']), 'gzip')
200+
})
193201
})
194202

195203
whenAcceptEncoding('gzip;q=0.8, deflate', function () {
@@ -204,6 +212,14 @@ describe('negotiator.encoding(array)', function () {
204212
it('should return most client-preferred encoding', function () {
205213
assert.strictEqual(this.negotiator.encoding(['gzip']), 'gzip')
206214
assert.strictEqual(this.negotiator.encoding(['compress', 'identity']), 'identity')
215+
assert.strictEqual(this.negotiator.encoding(['gzip', 'deflate'], ['deflate']), 'gzip')
216+
assert.strictEqual(this.negotiator.encoding(['deflate', 'gzip'], ['deflate']), 'gzip')
217+
})
218+
219+
it('should return developer-preferred encodings', function () {
220+
assert.strictEqual(this.negotiator.encoding(['gzip', 'deflate'], ['gzip']), 'gzip')
221+
assert.strictEqual(this.negotiator.encoding(['deflate', 'gzip'], ['gzip']), 'gzip')
222+
assert.strictEqual(this.negotiator.encoding(['gzip'], ['gzip']), 'gzip')
207223
})
208224
})
209225
})
@@ -401,6 +417,14 @@ describe('negotiator.encodings(array)', function () {
401417
assert.deepEqual(this.negotiator.encodings(['deflate', 'gzip']), ['gzip', 'deflate'])
402418
assert.deepEqual(this.negotiator.encodings(['identity']), ['identity'])
403419
})
420+
421+
it('should return developer-preferred encodings', function () {
422+
assert.deepEqual(this.negotiator.encodings(['gzip', 'deflate'], ['deflate']), ['deflate', 'gzip'])
423+
assert.deepEqual(this.negotiator.encodings(['deflate', 'gzip'], ['deflate']), ['deflate', 'gzip'])
424+
assert.deepEqual(this.negotiator.encodings(['gzip', 'deflate'], ['gzip']), ['gzip', 'deflate'])
425+
assert.deepEqual(this.negotiator.encodings(['deflate', 'gzip'], ['gzip']), ['gzip', 'deflate'])
426+
assert.deepEqual(this.negotiator.encodings(['gzip'], ['gzip']), ['gzip'])
427+
})
404428
})
405429

406430
whenAcceptEncoding('gzip;q=0.8, deflate', function () {
@@ -415,6 +439,14 @@ describe('negotiator.encodings(array)', function () {
415439
it('should return client-preferred encodings', function () {
416440
assert.deepEqual(this.negotiator.encodings(['gzip']), ['gzip'])
417441
assert.deepEqual(this.negotiator.encodings(['identity', 'gzip', 'compress']), ['gzip', 'identity', 'compress'])
442+
assert.deepEqual(this.negotiator.encodings(['gzip', 'deflate'], ['deflate']), ['gzip', 'deflate'])
443+
assert.deepEqual(this.negotiator.encodings(['deflate', 'gzip'], ['deflate']), ['gzip', 'deflate'])
444+
})
445+
446+
it('should return developer-preferred encodings', function () {
447+
assert.deepEqual(this.negotiator.encodings(['gzip', 'deflate'], ['gzip']), ['gzip', 'deflate'])
448+
assert.deepEqual(this.negotiator.encodings(['deflate', 'gzip'], ['gzip']), ['gzip', 'deflate'])
449+
assert.deepEqual(this.negotiator.encodings(['gzip'], ['gzip']), ['gzip'])
418450
})
419451
})
420452
})

0 commit comments

Comments
 (0)