Skip to content

Commit

Permalink
Added an option preferred encodings array
Browse files Browse the repository at this point in the history
  • Loading branch information
danielgindi authored and wesleytodd committed Aug 31, 2024
1 parent d3c7697 commit eb36d5d
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 9 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
8 changes: 4 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
31 changes: 26 additions & 5 deletions lib/encoding.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -123,6 +123,7 @@ function specify(encoding, spec, index) {
}

return {
encoding: encoding,
i: index,
o: spec.i,
q: spec.q,
Expand All @@ -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);
}

Expand All @@ -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)];
});
}
Expand All @@ -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);
}

/**
Expand Down
32 changes: 32 additions & 0 deletions test/encoding.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand All @@ -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')
})
})
})
Expand Down Expand Up @@ -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 () {
Expand All @@ -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'])
})
})
})
Expand Down

0 comments on commit eb36d5d

Please sign in to comment.