Skip to content
3 changes: 2 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,14 @@ fastify.listen(3000, (err) => {
for a *cache-response-directive* as defined by RFC 2616.
+ `expiresIn` (Default: `undefined`): a value, in seconds, for the *max-age* the
resource may be cached. When this is set, and `privacy` is not set to `no-cache`,
then `', max-age=<value>'` will be appended to the `cache-control` header.
then `', max-age=<value>'` will be appended to the `cache-control` header.
+ `cache` (Default: `abstract-cache.memclient`): an [abstract-cache][acache]
protocol compliant cache object. Note: the plugin requires a cache instance to
properly support the ETag mechanism. Therefore, if a falsy value is supplied
the default will be used.
+ `cacheSegment` (Default: `'fastify-caching'`): segment identifier to use when
communicating with the cache.
+ `serverExpiresIn` (Default: `undefined`): a value, in seconds, for the length of time the resource is fresh and may be held in a shared cache (e.g. a CDN). Shared caches will ignore max-age when this is specified, though browsers will continue to use max-age. Should be used with expiresIn, not in place of it. When this is set, and `privacy` is set to `public`, then `', s-maxage=<value>'` will be appended to the `cache-control` header.

[acache]: https://www.npmjs.com/package/abstract-cache

Expand Down
5 changes: 5 additions & 0 deletions plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const abstractCache = require('abstract-cache')

const defaultOptions = {
expiresIn: undefined,
serverExpiresIn: undefined,
privacy: undefined,
cache: undefined,
cacheSegment: 'fastify-caching'
Expand Down Expand Up @@ -69,6 +70,10 @@ function fastifyCachingPlugin (instance, options, next) {
value = `${_options.privacy}, max-age=${_options.expiresIn}`
}

if (_options.privacy !== undefined && _options.privacy.toLowerCase() === 'public' && _options.serverExpiresIn) {
value += `, s-maxage=${_options.serverExpiresIn}`
}

instance.addHook('onRequest', (req, res, next) => {
res.header('Cache-control', value)
next()
Expand Down
74 changes: 74 additions & 0 deletions test/headers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,80 @@ test('sets private with max-age header', (t) => {
})
})

test('sets public with max-age and s-maxage header', (t) => {
t.plan(2)
const instance = fastify()
const opts = {
privacy: plugin.privacy.PUBLIC,
expiresIn: 300,
serverExpiresIn: 12345
}
instance.register(plugin, opts)
instance.get('/', (req, reply) => {
reply.send({ hello: 'world' })
})
instance.listen(0, (err) => {
if (err) t.threw(err)
instance.server.unref()
const portNum = instance.server.address().port
const address = `http://127.0.0.1:${portNum}`

http.get(address, (res) => {
t.ok(res.headers['cache-control'])
t.equal(res.headers['cache-control'], 'public, max-age=300, s-maxage=12345')
}).on('error', (err) => t.threw(err))
})
})

test('only sets max-age and ignores s-maxage with private header', (t) => {
t.plan(2)
const instance = fastify()
const opts = {
privacy: plugin.privacy.PRIVATE,
expiresIn: 300,
serverExpiresIn: 12345
}
instance.register(plugin, opts)
instance.get('/', (req, reply) => {
reply.send({ hello: 'world' })
})
instance.listen(0, (err) => {
if (err) t.threw(err)
instance.server.unref()
const portNum = instance.server.address().port
const address = `http://127.0.0.1:${portNum}`

http.get(address, (res) => {
t.ok(res.headers['cache-control'])
t.equal(res.headers['cache-control'], 'private, max-age=300')
}).on('error', (err) => t.threw(err))
})
})

test('s-maxage is optional with public header', (t) => {
t.plan(2)
const instance = fastify()
const opts = {
privacy: plugin.privacy.PUBLIC,
expiresIn: 300
}
instance.register(plugin, opts)
instance.get('/', (req, reply) => {
reply.send({ hello: 'world' })
})
instance.listen(0, (err) => {
if (err) t.threw(err)
instance.server.unref()
const portNum = instance.server.address().port
const address = `http://127.0.0.1:${portNum}`

http.get(address, (res) => {
t.ok(res.headers['cache-control'])
t.equal(res.headers['cache-control'], 'public, max-age=300')
}).on('error', (err) => t.threw(err))
})
})

test('sets no-store with max-age header', (t) => {
t.plan(2)
const instance = fastify()
Expand Down