🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
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
2.0.0

index.d.ts

8

index.js

@@ -13,3 +13,3 @@ let serveStatic = require('serve-static');

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

@@ -22,3 +22,3 @@ */

//create a express.static middleware to handle serving files
let defaultStatic = serveStatic(rootFolder, options);
let defaultStatic = serveStatic(rootFolder, opts.serveStatic || null);
let compressions = [];

@@ -35,3 +35,3 @@ let files = {};

return function middleware(req, res, next) {
return function expressStaticGzip(req, res, next) {
changeUrlFromEmptyToIndexHtml(req);

@@ -105,3 +105,3 @@

if (opts.index && req.url.endsWith("/")) {
req.url += "index.html";
req.url += opts.index;
}

@@ -108,0 +108,0 @@ }

@@ -0,0 +0,0 @@ MIT License

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

@@ -22,3 +22,3 @@ "main": "index.js",

"dependencies": {
"serve-static": "^1.12.3"
"serve-static": "^1.14.1"
},

@@ -25,0 +25,0 @@ "devDependencies": {

@@ -0,7 +1,12 @@

# express-static-gzip
Provides a small layer on top of *serve-static*, which allows to serve pre-gzipped files. Supports *brotli* and any other compressions as well.
[![npm][npm-version-image]][npm-url]
[![npm][npm-downloads-image]][npm-url]
Provides a small layer on top of *serve-static*, which allows to serve pre-gzipped files. Supports *brotli* and allows configuring any other compression you can think of as well.
# Requirements
For the express-static-gzip middleware to work properly you need to first ensure that you have all files gzipped (or compressed with your desired algorithm), which you want to serve as a compressed version to the browser.
Simplest use case is to either have a folder with only .gz files, or you have a folder with the .gz files next to the original files. Some goes for other compressions.
Simplest use case is to either have a folder with only .gz files, or you have a folder with the .gz files next to the original files. Same goes for other compressions.

@@ -14,2 +19,24 @@ # Install

# Changelog for v2.0.0
* Even so this is mayor release, this should be fully backwards compatible and should not have any breaking change to v1.1.3.
* Moves all options for `serverStatic` in it's own section, to prevent collisions when setting up your static fileserving middleware.
* For backwards compatibility all properties in the root options object will be copied to the new `serverStatic` section, except if you have set values there already. Here is a small example of this behaviour:
```JavaScript
{
enableBrotli: true, // not a serverStatic option, will not be moved
maxAge: 123, // not copied, as already present.
index: 'main.js', // copied to serveStatic section
serveStatic: {
maxAge: 234, // will be kept
cacheControl: false // will be kept as well
}
}
```
In the above scenario serveStatic will use `cacheControl`: false, `index`: 'main.js', `maxAge`:234.
# Usage

@@ -62,10 +89,8 @@ In case you just want to serve gzipped files only, this simple example would do:

This will enable brotli compression in addition to gzip
Enables support for the brotli compression, using file extension 'br' (e.g. 'index.html.br').
* **`index`**: boolean (default: **true**)
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
By default this module will send "index.html" files in response to a request on a directory. To disable this set false or to supply a new index pass a string.
* **`indexFromEmptyFile`** (**deprecated**, see `index` option)
* **`customCompressions`**: [{encodingName: string, fileExtension: string}]

@@ -79,2 +104,6 @@

* **`serveStatic`**: [ServeStaticOptions](https://github.com/expressjs/serve-static#options)
This will be forwarded to the underlying `serveStatic` instance used by `expressStaticGzip`
# Behavior warning

@@ -111,1 +140,6 @@

> GET /main.js >>> /my/rootFolder/main.js
[npm-url]: https://www.npmjs.com/package/express-static-gzip
[npm-downloads-image]: https://img.shields.io/npm/dw/express-static-gzip
[npm-version-image]: https://img.shields.io/npm/v/express-static-gzip

@@ -41,2 +41,11 @@ const expect = require('chai').expect;

it('should handle index option false, serveStatic.index overwritten', function () {
setupServer({ index: false, serveStatic: { index: "index.html" } });
return requestFile('/').then(resp => {
expect(resp.statusCode).to.equal(200);
expect(resp.body).to.equal("index.html")
});
});
it('should handle index option default', function () {

@@ -51,8 +60,8 @@ setupServer();

it('should handle index option true', function () {
setupServer({ index: true });
it('should handle index option set', function () {
setupServer({ index: 'main.js', enableBrotli: true });
return requestFile('/', { 'accept-encoding': 'gzip' }).then(resp => {
return requestFile('/', { 'accept-encoding': 'br' }).then(resp => {
expect(resp.statusCode).to.equal(200);
expect(resp.body).to.equal('index.html.gz');
expect(resp.body).to.equal('main.js.br');
});

@@ -164,6 +173,6 @@ });

it('should handle foldername with dot', function(){
it('should handle foldername with dot', function () {
setupServer(null, 'wwwroot.gzipped');
return requestFile("/index.html", { 'accept-encoding': 'gzip'}).then(resp => {
return requestFile("/index.html", { 'accept-encoding': 'gzip' }).then(resp => {
expect(resp.statusCode).to.equal(200);

@@ -174,6 +183,6 @@ expect(resp.body).to.equal('index.html.gz');

it('should handle url encoded path', function(){
it('should handle url encoded path', function () {
setupServer();
return requestFile("/filename with spaces.txt", { 'accept-encoding': 'gzip'}).then(resp => {
return requestFile("/filename with spaces.txt", { 'accept-encoding': 'gzip' }).then(resp => {
expect(resp.statusCode).to.equal(200);

@@ -184,2 +193,22 @@ expect(resp.body).to.equal('"filename with spaces.txt.gz"');

it('should use serveStatic options', function () {
setupServer({ serveStatic: { setHeaders: (res) => { res.setHeader('Test-X', 'Value-Y') } } });
return requestFile('/index.html').then(resp => {
expect(resp.statusCode).to.equal(200);
expect(resp.headers['test-x']).to.equal('Value-Y');
expect(resp.headers['test-y']).to.be.undefined;
});
});
it('should use serveStatic options set in root options', function () {
setupServer({ setHeaders: (res) => { res.setHeader('Test-X', 'Value-Y') } });
return requestFile('/index.html').then(resp => {
expect(resp.statusCode).to.equal(200);
expect(resp.headers['test-x']).to.equal('Value-Y');
expect(resp.headers['test-y']).to.be.undefined;
});
});
/**

@@ -206,3 +235,3 @@ *

*
* @param {{enableBrotli?:boolean, customCompressions?:[{encodingName:string,fileExtension:string}], index?: boolean}} options
* @param {expressStaticGzip.ExpressStaticGzipOptions} options
*/

@@ -209,0 +238,0 @@ function setupServer(options, dir) {

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

@@ -7,27 +7,40 @@ const expect = require('chai').expect;

const res = sanitizeOptions();
expect(res).to.deep.equal({ index: true });
expect(res).to.deep.equal({ index: 'index.html' });
});
it('should parse index options', function () {
let res = sanitizeOptions({ index: true });
expect(res).to.deep.equal({ index: true });
let res = sanitizeOptions({ index: 'main.js' });
expect(res).to.deep.equal({ index: 'main.js', serveStatic: { index: 'main.js' } });
res = sanitizeOptions({ index: false });
expect(res).to.deep.equal({ index: false });
expect(res).to.haveOwnProperty("index");
expect(res.index).to.equal(false);
});
it('should parse indexFromEmptyFile options', function () {
let res = sanitizeOptions({ indexFromEmptyFile: true });
expect(res).to.deep.equal({ index: true });
let res = sanitizeOptions({ indexFromEmptyFile: 'main.js' });
expect(res).to.deep.equal({ index: 'main.js' });
res = sanitizeOptions({ indexFromEmptyFile: false });
expect(res).to.deep.equal({ index: false });
expect(res).to.haveOwnProperty("index");
expect(res.index).to.equal(false);
});
it('should keep serveStatic options', function () {
const res = sanitizeOptions({ serveStatic: { index: 'main.js' } });
expect(res).to.deep.equal({ index: 'index.html', serveStatic: { index: 'main.js' } });
});
it('should not overwrite serverStatic.index when already set', function () {
const res = sanitizeOptions({ index: false, serveStatic: { index: 'index.html' } });
expect(res).to.deep.equal({ index: false, serveStatic: { index: 'index.html' } });
});
it('should parse enableBrotli option', function () {
let res = sanitizeOptions({ enableBrotli: true });
expect(res).to.deep.equal({ enableBrotli: true, index: true });
expect(res).to.deep.equal({ enableBrotli: true, index: 'index.html' });
res = sanitizeOptions({ enableBrotli: 'true' });
expect(res).to.deep.equal({ enableBrotli: true, index: true });
expect(res).to.deep.equal({ enableBrotli: true, index: 'index.html' });
});

@@ -38,3 +51,3 @@

const res = sanitizeOptions({ customCompressions: [compression] });
expect(res).to.deep.equal({ customCompressions: [compression], index: true });
expect(res).to.deep.equal({ customCompressions: [compression], index: 'index.html' });
});

@@ -44,3 +57,3 @@

const res = sanitizeOptions({ customCompressions: [] });
expect(res).to.deep.equal({ customCompressions: [], index: true });
expect(res).to.deep.equal({ customCompressions: [], index: 'index.html' });
});

@@ -50,8 +63,8 @@

const res = sanitizeOptions({ customCompressions: true });
expect(res).to.deep.equal({ index: true });
expect(res).to.deep.equal({ index: 'index.html' });
});
it('should strip additional options', function () {
const res = sanitizeOptions({ index: true, test: 'value' });
expect(res).to.deep.equal({ index: true });
const res = sanitizeOptions({ index: 'main.js', test: 'value' });
expect(res).to.deep.equal({ index: 'main.js', serveStatic: { index: 'main.js' } });
});

@@ -61,4 +74,23 @@

const res = sanitizeOptions({ orderPreference: ['br'] });
expect(res).to.deep.equal({ index: true, orderPreference: ['br'] });
expect(res).to.deep.equal({ index: 'index.html', orderPreference: ['br'] });
});
it('should copy serveStatic options from root', function () {
const res = sanitizeOptions({ fallthrough: false });
expect(res.serveStatic.fallthrough).to.equal(false);
const res2 = sanitizeOptions({ setHeaders: () => 'test' });
expect(res2.serveStatic.setHeaders()).to.equal('test');
});
it('should copy serveStatic options from root, while keeping other serveStatic options', function () {
const options = sanitizeOptions({ fallthrough: false, serveStatic: { maxAge: 234 } });
expect(options.serveStatic).to.deep.equal({ fallthrough: false, maxAge: 234 });
});
it('should not overwrite serveStatic options with options from root', function () {
const options = sanitizeOptions({ maxAge: 123, serveStatic: { maxAge: 234 } });
expect(options.serveStatic).to.deep.equal({ maxAge: 234 });
});
});

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

@@ -0,1 +1,4 @@

module.exports = {
sanitizeOptions: sanitizeOptions
};

@@ -5,3 +8,4 @@ /**

* Removes problematic options from the input options object.
* @param {{enableBrotli?:boolean, customCompressions?:[{encodingName:string,fileExtension:string}], indexFromEmptyFile?:boolean, index?: boolean}} userOptions
* @param {expressStaticGzip.ExpressStaticGzipOptions} userOptions
* @returns {expressStaticGzip.ExpressStaticGzipOptions}
*/

@@ -11,38 +15,82 @@ function sanitizeOptions(userOptions) {

let options = {
/**
* @type {expressStaticGzip.ExpressStaticGzipOptions}
*/
let sanitizedOptions = {
index: getIndexValue(userOptions)
}
if(userOptions.index){
// required to not interfere with serve-static
delete userOptions.index;
if (typeof (userOptions.enableBrotli) !== "undefined") {
sanitizedOptions.enableBrotli = !!userOptions.enableBrotli;
}
if (typeof (userOptions.enableBrotli) !== "undefined") {
options.enableBrotli = !!userOptions.enableBrotli;
if (typeof (userOptions.customCompressions) === "object") {
sanitizedOptions.customCompressions = userOptions.customCompressions;
}
if (typeof (userOptions.customCompressions) === "object" ) {
options.customCompressions = userOptions.customCompressions;
if (typeof (userOptions.orderPreference) === "object") {
sanitizedOptions.orderPreference = userOptions.orderPreference;
}
if (typeof (userOptions.orderPreference) === "object" ) {
options.orderPreference = userOptions.orderPreference;
prepareServeStaticOptions(userOptions, sanitizedOptions);
return sanitizedOptions;
}
/**
*
* @param {expressStaticGzip.ExpressStaticGzipOptions} userOptions
* @param {expressStaticGzip.ExpressStaticGzipOptions} sanitizedOptions
*/
function prepareServeStaticOptions(userOptions, sanitizedOptions) {
if (typeof (userOptions.serveStatic) !== 'undefined') {
sanitizedOptions.serveStatic = userOptions.serveStatic;
}
return options;
copyServeStaticOptions(userOptions, sanitizedOptions);
}
function getIndexValue(opts) {
if (typeof (opts.indexFromEmptyFile) === "undefined" && typeof (opts.index) !== "undefined") {
return opts.index;
} else if (typeof (opts.index) === "undefined" && typeof (opts.indexFromEmptyFile) !== "undefined") {
return opts.indexFromEmptyFile;
} else {
return true;
/**
* Used to be backwards compatible by copying options in root level to the serveStatic options property.
* @param {expressStaticGzip.ExpressStaticGzipOptions} userOptions
* @param {expressStaticGzip.ExpressStaticGzipOptions} sanitizedOptions
*/
function copyServeStaticOptions(userOptions, sanitizedOptions) {
var staticGzipOptionsProperties = ['cacheControl', 'dotfiles', 'etag', 'extensions', 'index', 'fallthrough', 'immutable', 'lastModified', 'maxAge', 'redirect', 'setHeaders'];
for (var propertyIdx in staticGzipOptionsProperties) {
var property = staticGzipOptionsProperties[propertyIdx];
if (typeof (userOptions[property]) !== 'undefined' && (!sanitizedOptions.serveStatic || typeof (sanitizedOptions.serveStatic[property]) === 'undefined')) {
setStaticGzipOptionsProperty(sanitizedOptions, property, userOptions[property]);
}
}
}
module.exports = {
sanitizeOptions: sanitizeOptions
};
/**
*
* @param {expressStaticGzip.ExpressStaticGzipOptions} sanitizedOptions
* @param {string} property
* @param {any} value
*/
function setStaticGzipOptionsProperty(sanitizedOptions, property, value) {
if (typeof (sanitizedOptions.serveStatic) !== 'object') {
sanitizedOptions.serveStatic = {};
}
sanitizedOptions.serveStatic[property] = value;
}
/**
* Takes care of retrieving the index value, by also checking the deprecated `indexFromEmptyFile`
* @param {expressStaticGzip.ExpressStaticGzipOptions} options
*/
function getIndexValue(options) {
if (typeof (options.indexFromEmptyFile) === "undefined" && typeof (options.index) !== "undefined") {
return options.index;
} else if (typeof (options.index) === "undefined" && typeof (options.indexFromEmptyFile) !== "undefined") {
return options.indexFromEmptyFile;
} else {
return 'index.html';
}
}