Skip to content

Commit

Permalink
use negotiator
Browse files Browse the repository at this point in the history
  • Loading branch information
bjohansebas committed Oct 19, 2024
1 parent 25b68b8 commit 3d30ab0
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 71 deletions.
73 changes: 13 additions & 60 deletions encoding_negotiator.js
Original file line number Diff line number Diff line change
@@ -1,77 +1,30 @@
var zlib = require('zlib')
var Negotiator = require('negotiator')

/**
* @const
* whether current node version has brotli support
*/
var hasBrotliSupport = 'createBrotliCompress' in zlib

var supportedEncodings = hasBrotliSupport
? ['br', 'gzip', 'deflate', 'identity']
: ['gzip', 'deflate', 'identity']
function negotiateEncoding (req, encodings_) {
var negotiator = new Negotiator(req)
var encodings = encodings_

var preferredEncodings = hasBrotliSupport
? ['br', 'gzip']
: ['gzip']

function negotiateEncoding (header) {
header = header || ''

var insts = header.split(',')
var decoded = []

for (var i = 0; i < insts.length; i++) {
var inst = insts[i].match(/^\s*?([^\s;]+?)\s*?(?:;(.*))?$/)
if (!inst) continue

var encoding = inst[1]
if (supportedEncodings.indexOf(encoding) === -1) {
continue
// support flattened arguments
if (encodings && !Array.isArray(encodings)) {
encodings = new Array(arguments.length)
for (var i = 0; i < encodings.length; i++) {
encodings[i] = arguments[i]
}

var q = 1
if (inst[2]) {
var params = inst[2].split(';')
for (var j = 0; j < params.length; j++) {
var p = params[j].trim().split('=')
if (p[0] === 'q') {
q = parseFloat(p[1])
break
}
}
}

if (q < 0 || q > 1) { // invalid
continue
}

decoded.push({ encoding: encoding, q: q, i: i })
}

decoded.sort(function (a, b) {
if (a.q !== b.q) {
return b.q - a.q // higher quality first
}

var aPreferred = preferredEncodings.indexOf(a.encoding)
var bPreferred = preferredEncodings.indexOf(b.encoding)

if (aPreferred === -1 && bPreferred === -1) {
return a.i - b.i // consider the original order
}

if (aPreferred !== -1 && bPreferred !== -1) {
return aPreferred - bPreferred // consider the preferred order
}

return aPreferred === -1 ? 1 : -1 // preferred first
})

if (decoded.length > 0) {
return decoded[0].encoding
// no encodings, return all requested encodings
if (!encodings || encodings.length === 0) {
return negotiator.encodings()
}

return null
return negotiator.encodings(encodings, hasBrotliSupport ? ['br'] : ['gzip'])[0] || false
}

module.exports.hasBrotliSupport = hasBrotliSupport
Expand Down
9 changes: 7 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,15 @@ function compression (options) {
}

// compression method
var method = negotiateEncoding(req.headers['accept-encoding']) || 'identity'
var method = negotiateEncoding(req, ['br', 'gzip', 'deflate', 'identity'])

// we really don't prefer deflate
if (method === 'deflate' && negotiateEncoding(req, ['gzip'])) {
method = negotiateEncoding(req, ['br', 'gzip', 'identity'])
}

// negotiation failed
if (method === 'identity') {
if (!method || method === 'identity') {
nocompress('not acceptable')
return
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"license": "MIT",
"repository": "expressjs/compression",
"dependencies": {
"accepts": "~1.3.8",
"negotiator": "0.6.4",
"bytes": "3.0.0",
"compressible": "~2.0.18",
"debug": "2.6.9",
Expand Down
9 changes: 1 addition & 8 deletions test/compression.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var compression = require('..')
* whether current node version has brotli support
*/
var hasBrotliSupport = 'createBrotliCompress' in zlib
var brotlit = hasBrotliSupport ? it : it.skip

describe('compression()', function () {
it('should skip HEAD', function (done) {
Expand Down Expand Up @@ -472,7 +473,6 @@ describe('compression()', function () {
})

describe('when "Accept-Encoding: br"', function () {
var brotlit = hasBrotliSupport ? it : it.skip
brotlit('should respond with br', function (done) {
var server = createServer({ threshold: 0 }, function (req, res) {
res.setHeader('Content-Type', 'text/plain')
Expand All @@ -487,7 +487,6 @@ describe('compression()', function () {
})

describe('when "Accept-Encoding: br" and passing compression level', function () {
var brotlit = hasBrotliSupport ? it : it.skip
brotlit('should respond with br', function (done) {
var params = {}
params[zlib.constants.BROTLI_PARAM_QUALITY] = 11
Expand Down Expand Up @@ -548,7 +547,6 @@ describe('compression()', function () {
})

describe('when "Accept-Encoding: deflate, gzip, br"', function () {
var brotlit = hasBrotliSupport ? it : it.skip
brotlit('should respond with br', function (done) {
var server = createServer({ threshold: 0 }, function (req, res) {
res.setHeader('Content-Type', 'text/plain')
Expand All @@ -563,7 +561,6 @@ describe('compression()', function () {
})

describe('when "Accept-Encoding: gzip;q=1, br;q=0.3"', function () {
var brotlit = hasBrotliSupport ? it : it.skip
brotlit('should respond with gzip', function (done) {
var server = createServer({ threshold: 0 }, function (req, res) {
res.setHeader('Content-Type', 'text/plain')
Expand All @@ -578,7 +575,6 @@ describe('compression()', function () {
})

describe('when "Accept-Encoding: gzip, br;q=0.8"', function () {
var brotlit = hasBrotliSupport ? it : it.skip
brotlit('should respond with gzip', function (done) {
var server = createServer({ threshold: 0 }, function (req, res) {
res.setHeader('Content-Type', 'text/plain')
Expand All @@ -593,7 +589,6 @@ describe('compression()', function () {
})

describe('when "Accept-Encoding: gzip;q=0.001"', function () {
var brotlit = hasBrotliSupport ? it : it.skip
brotlit('should respond with gzip', function (done) {
var server = createServer({ threshold: 0 }, function (req, res) {
res.setHeader('Content-Type', 'text/plain')
Expand All @@ -608,7 +603,6 @@ describe('compression()', function () {
})

describe('when "Accept-Encoding: deflate, br"', function () {
var brotlit = hasBrotliSupport ? it : it.skip
brotlit('should respond with br', function (done) {
var server = createServer({ threshold: 0 }, function (req, res) {
res.setHeader('Content-Type', 'text/plain')
Expand Down Expand Up @@ -760,7 +754,6 @@ describe('compression()', function () {
.end()
})

var brotlit = hasBrotliSupport ? it : it.skip
brotlit('should flush small chunks for brotli', function (done) {
var chunks = 0
var next
Expand Down

0 comments on commit 3d30ab0

Please sign in to comment.