Skip to content

Commit

Permalink
Support glob matching for cache headers (cloudhead#183)
Browse files Browse the repository at this point in the history
* Keep backwards compatibility with previous cache options
* Add tests to ensure glob matching with defined cache values
* Updated README with instructions for new cache feature
  • Loading branch information
lightswitch05 authored and Zarel committed Aug 10, 2021
1 parent 55012ad commit 2bd53c7
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 20 deletions.
4 changes: 3 additions & 1 deletion README.md
Expand Up @@ -146,10 +146,12 @@ With this method, you don't have to explicitly send the response back, in case o

Sets the `Cache-Control` header.

example: `{ cache: 7200 }`
example: `{ cache: 7200 }` will set the max-age for all files to 7200 seconds
example: `{ cache: {'**/*.css': 300}}` will set the max-age for all CSS files to 5 minutes.

Passing a number will set the cache duration to that number of seconds.
Passing `false` will disable the `Cache-Control` header.
Passing a object with [minimatch glob pattern](https://github.com/isaacs/minimatch) keys and number values will set cache max-age for any matching paths.

> Defaults to `3600`
Expand Down
33 changes: 26 additions & 7 deletions lib/node-static.js
Expand Up @@ -6,7 +6,8 @@ const fs = require('fs')
, http = require('http')
, path = require('path')
, mime = require('mime')
, util = require('./node-static/util');
, util = require('./node-static/util')
, minimatch = require('minimatch');

// Current version
const version = [0, 7, 9];
Expand All @@ -25,7 +26,7 @@ const Server = function (root, options) {
// resolve() doesn't normalize (to lowercase) drive letters on Windows
this.root = path.normalize(path.resolve(root || '.'));
this.options = options || {};
this.cache = 3600;
this.cache = {'**': 3600};

this.defaultHeaders = {};
this.options.headers = this.options.headers || {};
Expand All @@ -34,9 +35,11 @@ const Server = function (root, options) {

if ('cache' in this.options) {
if (typeof(this.options.cache) === 'number') {
this.cache = {'**': this.options.cache};
} else if (typeof(this.options.cache) === 'object') {
this.cache = this.options.cache;
} else if (! this.options.cache) {
this.cache = false;
this.cache = {};
}
}

Expand All @@ -56,10 +59,6 @@ const Server = function (root, options) {
this.defaultHeaders['server'] = this.serverInfo;
}

if (this.cache !== false) {
this.defaultHeaders['cache-control'] = 'max-age=' + this.cache;
}

for (const k in this.defaultHeaders) {
this.options.headers[k] = this.options.headers[k] ||
this.defaultHeaders[k];
Expand Down Expand Up @@ -376,6 +375,7 @@ Server.prototype.respond = function (pathname, status, _headers, files, stat, re
const contentType = _headers['Content-Type'] ||
mime.getType(files[0]) ||
'application/octet-stream';
_headers = this.setCacheHeaders(_headers, req);

if(this.options.gzip) {
this.respondGzip(pathname, status, contentType, _headers, files, stat, req, res, finish);
Expand Down Expand Up @@ -417,6 +417,25 @@ Server.prototype.stream = function (pathname, files, length, startByte, res, cal
})(files.slice(0), 0);
};

Server.prototype.setCacheHeaders = function(_headers, req) {
const maxAge = this.getMaxAge(req.url);
if (typeof(maxAge) === 'number') {
_headers['cache-control'] = 'max-age=' + maxAge;
}
return _headers;
};

Server.prototype.getMaxAge = function(requestUrl) {
if (this.cache) {
for (const pattern in this.cache) {
if (minimatch(requestUrl, pattern)) {
return this.cache[pattern];
}
}
}
return false;
};

// Exports
exports.Server = Server;
exports.version = version;
Expand Down
17 changes: 5 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -30,6 +30,7 @@
"dependencies": {
"colors": "^1.4.0",
"mime": "^2.5.2",
"minimatch": "^3.0.3",
"neodoc": "^2.0.2"
},
"devDependencies": {
Expand Down
61 changes: 61 additions & 0 deletions test/integration/node-static-test.js
Expand Up @@ -324,6 +324,9 @@ suite.addBatch({
},
'should respond with text/html': function(error, response, body){
assert.equal(response.headers['content-type'], 'text/html');
},
'should respond with cache-control': function(error, response, body){
assert.equal(response.headers['cache-control'], 'max-age=3600');
}
}
}).addBatch({
Expand Down Expand Up @@ -567,6 +570,64 @@ suite.addBatch({
assert.equal(body, '');
}
}
}).addBatch({
'once an http server is listening with custom cache configuration': {
topic: function () {
server.close();

fileServer = new statik.Server(__dirname + '/../fixtures', {
cache: {
'**/*.txt': 100,
'**/': 300
}
});

server = require('http').createServer(function (request, response) {
fileServer.serve(request, response);
}).listen(TEST_PORT, this.callback)
},
'should be listening' : function(){
/* This test is necessary to ensure the topic execution.
* A topic without tests will be not executed */
assert.isTrue(true);
}
}
}).addBatch({
'requesting custom cache index file': {
topic : function(){
request.get(TEST_SERVER + '/', this.callback);
},
'should respond with 200' : function(error, response, body){
assert.equal(response.statusCode, 200);
},
'should respond with cache-control': function(error, response, body){
assert.equal(response.headers['cache-control'], 'max-age=300');
}
}
}).addBatch({
'requesting custom cache text file': {
topic : function(){
request.get(TEST_SERVER + '/hello.txt', this.callback);
},
'should respond with 200' : function(error, response, body){
assert.equal(response.statusCode, 200);
},
'should respond with cache-control': function(error, response, body){
assert.equal(response.headers['cache-control'], 'max-age=100');
}
}
}).addBatch({
'requesting custom cache un-cached file': {
topic : function(){
request.get(TEST_SERVER + '/empty.css', this.callback);
},
'should respond with 200' : function(error, response, body){
assert.equal(response.statusCode, 200);
},
'should not respond with cache-control': function(error, response, body){
assert.equal(response.headers['cache-control'], undefined);
}
}
}).addBatch({
'terminate server': {
topic: function() {
Expand Down

0 comments on commit 2bd53c7

Please sign in to comment.