Skip to content

Commit 737193c

Browse files
idehaoxin
authored and
haoxin
committedApr 26, 2017
Add support for Cache-Control: immutable with a new "immutable" option
More browsers are starting to support Cache-Control: immutable (see: https://hacks.mozilla.org/2017/01/using-immutable-caching-to-speed-up-the-web/). This commit adds support for an "immutable" option to add this directive to the Cache-Control header. Test Plan: Added unit tests to verify that the "immutable" directive is added only when the option is specified and when the response is successful. closes #75
1 parent 1045a22 commit 737193c

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed
 

‎Readme.md

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ $ npm install koa-send
1919
## Options
2020

2121
- `maxage` Browser cache max-age in milliseconds. (defaults to `0`)
22+
- `immutable` Tell the browser the resource is immutable and can be cached indefinitely (defaults to `false`)
2223
- `hidden` Allow transfer of hidden files. (defaults to `false`)
2324
- [`root`](#root-path) Root directory to restrict file access
2425
- `gzip` Try to serve the gzipped version of a file automatically when `gzip` is supported by a client and if the requested file with `.gz` extension exists. defaults to true.

‎index.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ async function send(ctx, path, opts = {}) {
4545
path = path.substr(parse(path).root.length);
4646
const index = opts.index;
4747
const maxage = opts.maxage || opts.maxAge || 0;
48+
const immutable = opts.immutable || false;
4849
const hidden = opts.hidden || false;
4950
const format = opts.format === false ? false : true;
5051
const extensions = Array.isArray(opts.extensions) ? opts.extensions : false;
@@ -125,7 +126,13 @@ async function send(ctx, path, opts = {}) {
125126
// stream
126127
ctx.set('Content-Length', stats.size);
127128
if (!ctx.response.get('Last-Modified')) ctx.set('Last-Modified', stats.mtime.toUTCString());
128-
if (!ctx.response.get('Cache-Control')) ctx.set('Cache-Control', 'max-age=' + (maxage / 1000 | 0));
129+
if (!ctx.response.get('Cache-Control')) {
130+
const directives = ['max-age=' + (maxage / 1000 | 0)];
131+
if (opts.immutable) {
132+
directives.push('immutable');
133+
}
134+
ctx.set('Cache-Control', directives.join(','));
135+
}
129136
ctx.type = type(path);
130137
ctx.body = fs.createReadStream(path);
131138

‎test/index.js

+37
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,44 @@ describe('send(ctx, file)', function(){
493493
.expect(200, done);
494494
})
495495
})
496+
497+
describe('and immutable is specified', function(){
498+
it('should set the immutable directive', function(done){
499+
const app = new Koa();
500+
501+
app.use(async (ctx) => {
502+
const p = '/test/fixtures/user.json';
503+
const sent = await send(ctx, p, { immutable: true, maxage: 31536000000 });
504+
assert.equal(sent, path.resolve(__dirname + '/fixtures/user.json'));
505+
});
506+
507+
request(app.listen())
508+
.get('/')
509+
.expect('Cache-Control', 'max-age=31536000,immutable')
510+
.expect(200, done);
511+
})
512+
})
496513
})
514+
515+
describe('.immutable option', function(){
516+
describe('when trying to get a non-existent file', function(){
517+
it('should not set the Cache-Control header', function(done){
518+
const app = new Koa();
519+
520+
app.use(async (ctx) => {
521+
await send(ctx, 'test/fixtures/does-not-exist.json', { immutable: true });
522+
});
523+
524+
request(app.listen())
525+
.get('/')
526+
.expect((res) => {
527+
assert.equal(res.header['cache-control'], undefined)
528+
})
529+
.expect(404, done);
530+
})
531+
})
532+
})
533+
497534
describe('.hidden option', function(){
498535
describe('when trying to get a hidden file', function(){
499536
it('should 404', function(done){

0 commit comments

Comments
 (0)
Please sign in to comment.