From eb36d5db4f58a9c9a534d6e14e249e707deb0a0a Mon Sep 17 00:00:00 2001 From: Daniel Cohen Gindi Date: Sat, 19 Dec 2020 20:33:35 +0200 Subject: [PATCH 1/2] Added an option preferred encodings array --- README.md | 9 +++++++++ index.js | 8 ++++---- lib/encoding.js | 31 ++++++++++++++++++++++++++----- test/encoding.js | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 82915e5..c5c60b3 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,10 @@ Returns the most preferred encoding from the client. Returns the most preferred encoding from a list of available encodings. +##### encoding(availableEncodings, preferred) + +Returns the most preferred encoding from a list of available encodings, while prioritizing based on `preferred` array between same-quality encodings. + ##### encodings() 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. Returns an array of preferred encodings ordered by priority from a list of available encodings. +##### encodings(availableEncodings, preferred) + +Returns an array of preferred encodings ordered by priority from a list of +available encodings, while prioritizing based on `preferred` array between same-quality encodings. + ## See Also The [accepts](https://npmjs.org/package/accepts#readme) module builds on diff --git a/index.js b/index.js index 4788264..7df0b0a 100644 --- a/index.js +++ b/index.js @@ -44,13 +44,13 @@ Negotiator.prototype.charsets = function charsets(available) { return preferredCharsets(this.request.headers['accept-charset'], available); }; -Negotiator.prototype.encoding = function encoding(available) { - var set = this.encodings(available); +Negotiator.prototype.encoding = function encoding(available, preferred) { + var set = this.encodings(available, preferred); return set && set[0]; }; -Negotiator.prototype.encodings = function encodings(available) { - return preferredEncodings(this.request.headers['accept-encoding'], available); +Negotiator.prototype.encodings = function encodings(available, preferred) { + return preferredEncodings(this.request.headers['accept-encoding'], available, preferred); }; Negotiator.prototype.language = function language(available) { diff --git a/lib/encoding.js b/lib/encoding.js index 8432cd7..9ebb633 100644 --- a/lib/encoding.js +++ b/lib/encoding.js @@ -96,7 +96,7 @@ function parseEncoding(str, i) { */ function getEncodingPriority(encoding, accepted, index) { - var priority = {o: -1, q: 0, s: 0}; + var priority = {encoding: encoding, o: -1, q: 0, s: 0}; for (var i = 0; i < accepted.length; i++) { var spec = specify(encoding, accepted[i], index); @@ -123,6 +123,7 @@ function specify(encoding, spec, index) { } return { + encoding: encoding, i: index, o: spec.i, q: spec.q, @@ -135,14 +136,34 @@ function specify(encoding, spec, index) { * @public */ -function preferredEncodings(accept, provided) { +function preferredEncodings(accept, provided, preferred) { var accepts = parseAcceptEncoding(accept || ''); + var comparator = preferred ? function comparator (a, b) { + if (a.q !== b.q) { + return b.q - a.q // higher quality first + } + + var aPreferred = preferred.indexOf(a.encoding) + var bPreferred = preferred.indexOf(b.encoding) + + if (aPreferred === -1 && bPreferred === -1) { + // consider the original specifity/order + return (b.s - a.s) || (a.o - b.o) || (a.i - b.i) + } + + if (aPreferred !== -1 && bPreferred !== -1) { + return aPreferred - bPreferred // consider the preferred order + } + + return aPreferred === -1 ? 1 : -1 // preferred first + } : compareSpecs; + if (!provided) { // sorted list of all encodings return accepts .filter(isQuality) - .sort(compareSpecs) + .sort(comparator) .map(getFullEncoding); } @@ -151,7 +172,7 @@ function preferredEncodings(accept, provided) { }); // sorted list of accepted encodings - return priorities.filter(isQuality).sort(compareSpecs).map(function getEncoding(priority) { + return priorities.filter(isQuality).sort(comparator).map(function getEncoding(priority) { return provided[priorities.indexOf(priority)]; }); } @@ -162,7 +183,7 @@ function preferredEncodings(accept, provided) { */ function compareSpecs(a, b) { - return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i) || 0; + return (b.q - a.q) || (b.s - a.s) || (a.o - b.o) || (a.i - b.i); } /** diff --git a/test/encoding.js b/test/encoding.js index d3da621..007a17e 100644 --- a/test/encoding.js +++ b/test/encoding.js @@ -190,6 +190,14 @@ describe('negotiator.encoding(array)', function () { it('should return first client-preferred encoding', function () { assert.strictEqual(this.negotiator.encoding(['deflate', 'compress']), 'deflate') }) + + it('should return developer-preferred encodings', function () { + assert.strictEqual(this.negotiator.encoding(['gzip', 'deflate'], ['deflate']), 'deflate') + assert.strictEqual(this.negotiator.encoding(['deflate', 'gzip'], ['deflate']), 'deflate') + assert.strictEqual(this.negotiator.encoding(['gzip', 'deflate'], ['gzip']), 'gzip') + assert.strictEqual(this.negotiator.encoding(['deflate', 'gzip'], ['gzip']), 'gzip') + assert.strictEqual(this.negotiator.encoding(['gzip'], ['gzip']), 'gzip') + }) }) whenAcceptEncoding('gzip;q=0.8, deflate', function () { @@ -204,6 +212,14 @@ describe('negotiator.encoding(array)', function () { it('should return most client-preferred encoding', function () { assert.strictEqual(this.negotiator.encoding(['gzip']), 'gzip') assert.strictEqual(this.negotiator.encoding(['compress', 'identity']), 'identity') + assert.strictEqual(this.negotiator.encoding(['gzip', 'deflate'], ['deflate']), 'gzip') + assert.strictEqual(this.negotiator.encoding(['deflate', 'gzip'], ['deflate']), 'gzip') + }) + + it('should return developer-preferred encodings', function () { + assert.strictEqual(this.negotiator.encoding(['gzip', 'deflate'], ['gzip']), 'gzip') + assert.strictEqual(this.negotiator.encoding(['deflate', 'gzip'], ['gzip']), 'gzip') + assert.strictEqual(this.negotiator.encoding(['gzip'], ['gzip']), 'gzip') }) }) }) @@ -401,6 +417,14 @@ describe('negotiator.encodings(array)', function () { assert.deepEqual(this.negotiator.encodings(['deflate', 'gzip']), ['gzip', 'deflate']) assert.deepEqual(this.negotiator.encodings(['identity']), ['identity']) }) + + it('should return developer-preferred encodings', function () { + assert.deepEqual(this.negotiator.encodings(['gzip', 'deflate'], ['deflate']), ['deflate', 'gzip']) + assert.deepEqual(this.negotiator.encodings(['deflate', 'gzip'], ['deflate']), ['deflate', 'gzip']) + assert.deepEqual(this.negotiator.encodings(['gzip', 'deflate'], ['gzip']), ['gzip', 'deflate']) + assert.deepEqual(this.negotiator.encodings(['deflate', 'gzip'], ['gzip']), ['gzip', 'deflate']) + assert.deepEqual(this.negotiator.encodings(['gzip'], ['gzip']), ['gzip']) + }) }) whenAcceptEncoding('gzip;q=0.8, deflate', function () { @@ -415,6 +439,14 @@ describe('negotiator.encodings(array)', function () { it('should return client-preferred encodings', function () { assert.deepEqual(this.negotiator.encodings(['gzip']), ['gzip']) assert.deepEqual(this.negotiator.encodings(['identity', 'gzip', 'compress']), ['gzip', 'identity', 'compress']) + assert.deepEqual(this.negotiator.encodings(['gzip', 'deflate'], ['deflate']), ['gzip', 'deflate']) + assert.deepEqual(this.negotiator.encodings(['deflate', 'gzip'], ['deflate']), ['gzip', 'deflate']) + }) + + it('should return developer-preferred encodings', function () { + assert.deepEqual(this.negotiator.encodings(['gzip', 'deflate'], ['gzip']), ['gzip', 'deflate']) + assert.deepEqual(this.negotiator.encodings(['deflate', 'gzip'], ['gzip']), ['gzip', 'deflate']) + assert.deepEqual(this.negotiator.encodings(['gzip'], ['gzip']), ['gzip']) }) }) }) From d48e9707b4e714219285da454d0a739e046ff2cc Mon Sep 17 00:00:00 2001 From: Wes Todd Date: Sat, 31 Aug 2024 09:46:28 -0500 Subject: [PATCH 2/2] fix: updated history.md --- HISTORY.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index a9a5449..e1929ab 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,8 @@ +unreleased +================== + + * Added an option preferred encodings array #59 + 0.6.3 / 2022-01-22 ==================