🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Book a DemoInstallSign in
Socket

express-static-gzip

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

express-static-gzip - npm Package Compare versions

Comparing version

to
1.1.0

10

index.js
let serveStatic = require('serve-static');
let parseOptions = require('./util/options').parseOptions;
let sanitizeOptions = require('./util/options').sanitizeOptions;
let findEncoding = require('./util/encoding-selection').findEncoding;

@@ -13,3 +13,3 @@ let mime = serveStatic.mime;

* @param {string} rootFolder: folder to staticly serve files from
* @param {{enableBrotli?:boolean, customCompressions?:[{encodingName:string,fileExtension:string}], index?: boolean}} options: options to change module behaviour
* @param {{enableBrotli?:boolean, customCompressions?:{encodingName:string,fileExtension:string}[], orderPreference: string[], index?: boolean}} options: options to change module behaviour
* @returns express middleware function

@@ -19,4 +19,4 @@ */

// strip away unnecessary options
let opts = parseOptions(options);
let opts = sanitizeOptions(options);
//create a express.static middleware to handle serving files

@@ -48,3 +48,3 @@ let defaultStatic = serveStatic(rootFolder, options);

//use the first matching compression to serve a compresed file
var compression = findEncoding(acceptEncoding, matchedFile.compressions);
var compression = findEncoding(acceptEncoding, matchedFile.compressions, opts.orderPreference);
if (compression) {

@@ -51,0 +51,0 @@ convertToCompressedRequest(req, res, compression);

{
"name": "express-static-gzip",
"version": "1.0.0",
"version": "1.1.0",
"description": "simple wrapper on top of express.static, that allows serving pre-gziped files",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -64,2 +64,3 @@ # express-static-gzip

If not set to false, any request to '/' or 'somepath/' will be answered with the file '/index.html' or 'somepath/index.html' in an accepted compression
* **`indexFromEmptyFile`** (**deprecated**, see `index` option)

@@ -71,3 +72,5 @@

* **`orderPreference`**: string[]
This options allows overwriting the client's requested encoding preference (see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding)) with a server side preference. Any encoding listed in `orderPreference` will be used first (if supported by the client) before falling back to the client's supported encodings. The order of entries in `orderPreference` is taken into account.

@@ -84,2 +87,3 @@ # Behavior warning

Because this middleware was developed for a static production server use case, to maximize performance, it is designed to look up and cache the compressed files corresponding to uncompressed file names on startup. This means that it will not be aware of compressed files being added or removed later on.

@@ -86,0 +90,0 @@ # Example

@@ -59,3 +59,3 @@ const expect = require('chai').expect;

it('should not serve brotli', function () {
it('should not serve brotli if not enabled', function () {
setupServer();

@@ -137,2 +137,28 @@

it('should use server\'s prefered encoding', function () {
setupServer({
customCompressions: [{ encodingName: 'deflate', fileExtension: 'zz' }],
enableBrotli: true,
orderPreference: ['br']
});
return requestFile('/index.html', { 'accept-encoding': 'gzip, deflate, br' }).then(resp => {
expect(resp.statusCode).to.equal(200);
expect(resp.body).to.equal('index.html.br');
});
});
it('should use client\'s prefered encoding, when server\'s not available', function () {
setupServer({
customCompressions: [{ encodingName: 'deflate', fileExtension: 'zz' }],
enableBrotli: true,
orderPreference: ['br']
});
return requestFile('/index.html', { 'accept-encoding': 'gzip, deflate' }).then(resp => {
expect(resp.statusCode).to.equal(200);
expect(resp.body).to.equal('index.html.gz');
});
});
/**

@@ -139,0 +165,0 @@ *

@@ -6,3 +6,4 @@ const expect = require('chai').expect;

const GZIP = { encodingName: "gzip", fileExtension: 'gz' };
const BROTLI = { encodingName: "brotli", fileExtension: 'br' };
const BROTLI = { encodingName: "br", fileExtension: 'br' };
const DEFLATE = { encodingName: "deflate", fileExtension: 'deflate' };

@@ -25,3 +26,3 @@ it('should handle empty accepted-encoding', function () {

it('should select by order', function () {
const result = findEncoding('gzip, brotli', [GZIP, BROTLI]);
const result = findEncoding('gzip, br', [GZIP, BROTLI]);
expect(result).to.be.deep.equal(GZIP);

@@ -31,3 +32,3 @@ });

it('should select by different order', function () {
const result = findEncoding('brotli, gzip', [GZIP, BROTLI]);
const result = findEncoding('br, gzip', [GZIP, BROTLI]);
expect(result).to.be.deep.equal(BROTLI);

@@ -37,3 +38,3 @@ });

it('should select by quality', function () {
const result = findEncoding('brotli;q=0.5, gzip;q=1.0', [GZIP, BROTLI]);
const result = findEncoding('br;q=0.5, gzip;q=1.0', [GZIP, BROTLI]);
expect(result).to.be.deep.equal(GZIP);

@@ -43,3 +44,3 @@ });

it('should handle strange formating', function () {
const result = findEncoding('brotli ; q=0.5 , gzip ; q=1.0', [GZIP, BROTLI]);
const result = findEncoding('br ; q=0.5 , gzip ; q=1.0', [GZIP, BROTLI]);
expect(result).to.be.deep.equal(GZIP);

@@ -49,5 +50,25 @@ });

it('should handle wildcard', function () {
const result = findEncoding('brotli ; q=0.5 , * ; q=1.0', [GZIP]);
const result = findEncoding('br ; q=0.5 , * ; q=1.0', [GZIP]);
expect(result).to.be.deep.equal(GZIP);
});
it('should favour server preference over client order', function () {
const result = findEncoding('gzip, deflate, br', [GZIP, BROTLI, DEFLATE], ['br']);
expect(result).to.be.deep.equal(BROTLI);
});
it('should work with multiple server preferences', function () {
const result = findEncoding('deflate, gzip', [GZIP, BROTLI, DEFLATE], ['br', 'gzip']);
expect(result).to.be.deep.equal(GZIP);
});
it('should use client order, when server preference not available', function () {
const result = findEncoding('deflate, gzip', [GZIP, BROTLI, DEFLATE], ['br']);
expect(result).to.be.deep.equal(DEFLATE);
});
it('should use server preference with quality', function () {
const result = findEncoding('gzip; q=0.6, deflate; q=1, br;q=0.5', [GZIP, BROTLI, DEFLATE], ['br']);
expect(result).to.be.deep.equal(BROTLI);
});
});
const expect = require('chai').expect;
const { parseOptions } = require('../util/options');
const { sanitizeOptions } = require('../util/options');
describe('option', function () {
it('should handle no options provided', function () {
const res = parseOptions();
const res = sanitizeOptions();
expect(res).to.deep.equal({ index: true });

@@ -11,6 +11,6 @@ });

it('should parse index options', function () {
let res = parseOptions({ index: true });
let res = sanitizeOptions({ index: true });
expect(res).to.deep.equal({ index: true });
res = parseOptions({ index: false });
res = sanitizeOptions({ index: false });
expect(res).to.deep.equal({ index: false });

@@ -20,6 +20,6 @@ });

it('should parse indexFromEmptyFile options', function () {
let res = parseOptions({ indexFromEmptyFile: true });
let res = sanitizeOptions({ indexFromEmptyFile: true });
expect(res).to.deep.equal({ index: true });
res = parseOptions({ indexFromEmptyFile: false });
res = sanitizeOptions({ indexFromEmptyFile: false });
expect(res).to.deep.equal({ index: false });

@@ -29,6 +29,6 @@ });

it('should parse enableBrotli option', function () {
let res = parseOptions({ enableBrotli: true });
let res = sanitizeOptions({ enableBrotli: true });
expect(res).to.deep.equal({ enableBrotli: true, index: true });
res = parseOptions({ enableBrotli: 'true' });
res = sanitizeOptions({ enableBrotli: 'true' });
expect(res).to.deep.equal({ enableBrotli: true, index: true });

@@ -39,3 +39,3 @@ });

const compression = { encodingName: 'brotli', fileExtension: 'br' };
const res = parseOptions({ customCompressions: [compression] });
const res = sanitizeOptions({ customCompressions: [compression] });
expect(res).to.deep.equal({ customCompressions: [compression], index: true });

@@ -45,3 +45,3 @@ });

it('should parse empty customCompressions', function () {
const res = parseOptions({ customCompressions: [] });
const res = sanitizeOptions({ customCompressions: [] });
expect(res).to.deep.equal({ customCompressions: [], index: true });

@@ -51,3 +51,3 @@ });

it('should ignore bad customCompressions', function () {
const res = parseOptions({ customCompressions: true });
const res = sanitizeOptions({ customCompressions: true });
expect(res).to.deep.equal({ index: true });

@@ -57,5 +57,10 @@ });

it('should strip additional options', function () {
const res = parseOptions({ index: true, test: 'value' });
const res = sanitizeOptions({ index: true, test: 'value' });
expect(res).to.deep.equal({ index: true });
});
it('should parse orderPreference', function () {
const res = sanitizeOptions({ orderPreference: ['br'] });
expect(res).to.deep.equal({ index: true, orderPreference: ['br'] });
});
});

@@ -7,6 +7,8 @@ // see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding

* @param {{encodingName: string, fileExtension: string}[]} availableCompressions
* @param {{string[]} preference
*/
function findEncoding(acceptEncoding, availableCompressions) {
function findEncoding(acceptEncoding, availableCompressions, preference) {
if (acceptEncoding) {
let sortedEncodingList = parseEncoding(acceptEncoding);
sortedEncodingList = takePreferenceIntoAccount(sortedEncodingList, preference);
return findFirstMatchingCompression(sortedEncodingList, availableCompressions);

@@ -21,3 +23,3 @@ }

for (let i = 0; i < availableCompressions.length; i++) {
if (encoding.name === '*' || encoding.name === availableCompressions[i].encodingName) {
if (encoding === '*' || encoding === availableCompressions[i].encodingName) {
return availableCompressions[i];

@@ -32,2 +34,25 @@ }

*
* @param {string[]} sortedEncodingList
* @param {string[]} preferences
*/
function takePreferenceIntoAccount(sortedEncodingList, preferences) {
if (!preferences || preferences.length === 0) {
return sortedEncodingList;
}
for (let i = preferences.length; i >= 0; i--) {
let pref = preferences[i];
let matchIdx = sortedEncodingList.indexOf(pref);
if (matchIdx >= 0) {
sortedEncodingList.splice(matchIdx, 1);
sortedEncodingList.splice(0, 0, pref);
}
}
return sortedEncodingList;
}
/**
*
* @param {string} acceptedEncoding

@@ -38,3 +63,4 @@ */

.map(encoding => parseQuality(encoding))
.sort((encodingA, encodingB) => encodingB.q - encodingA.q);
.sort((encodingA, encodingB) => encodingB.q - encodingA.q)
.map(encoding => encoding.name);
}

@@ -41,0 +67,0 @@

@@ -7,3 +7,3 @@

*/
function parseOptions(userOptions) {
function sanitizeOptions(userOptions) {
userOptions = userOptions || {};

@@ -28,2 +28,6 @@

if (typeof (userOptions.orderPreference) === "object" ) {
options.orderPreference = userOptions.orderPreference;
}
return options;

@@ -43,3 +47,3 @@ }

module.exports = {
parseOptions: parseOptions
sanitizeOptions: sanitizeOptions
};