Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ function fastifyCaching (instance, options, next) {

instance.addHook('onSend', function cachingSetCacheControlHeader (_req, reply, _payload, next) {
if (!reply.hasHeader('Cache-control')) {
// Only apply the caching value to successful (2xx) responses.
// Only apply the caching value to successful (2xx) and 304 Not Modified responses.
// Error responses must not be cached, otherwise browsers may serve
// a stale 4xx/5xx for the duration of max-age.
if (reply.statusCode >= 200 && reply.statusCode < 300) {
if ((reply.statusCode >= 200 && reply.statusCode < 300) || reply.statusCode === 304) {
reply.header('Cache-control', value)
} else {
reply.header('Cache-control', 'no-store')
Expand Down
60 changes: 60 additions & 0 deletions test/headers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,66 @@ test('does not override a Cache-control header set upstream on error responses',
t.assert.strictEqual(response.headers['cache-control'], 'private, max-age=10')
})

test('sets configured Cache-control header on 304 Not Modified responses', async (t) => {
t.plan(2)

const opts = {
privacy: plugin.privacy.PRIVATE,
expiresIn: 300
}

const fastify = Fastify()
await fastify.register(plugin, opts)

fastify.get('/', (_req, reply) => {
reply.code(304).send()
})

await fastify.ready()

const response = await fastify.inject({
method: 'GET',
path: '/'
})
t.assert.strictEqual(response.statusCode, 304)
t.assert.strictEqual(response.headers['cache-control'], 'private, max-age=300')
})

test('sets configured Cache-control header on conditional 304 etag hit responses', async (t) => {
t.plan(4)

const opts = {
privacy: plugin.privacy.PUBLIC,
expiresIn: 300
}

const fastify = Fastify()
await fastify.register(plugin, opts)

fastify.get('/', (_req, reply) => {
reply.etag('123456').send({ hello: 'world' })
})

await fastify.ready()

const first = await fastify.inject({
method: 'GET',
path: '/'
})
t.assert.strictEqual(first.statusCode, 200)
t.assert.strictEqual(first.headers['cache-control'], 'public, max-age=300')

const second = await fastify.inject({
method: 'GET',
path: '/',
headers: {
'if-none-match': '123456'
}
})
t.assert.strictEqual(second.statusCode, 304)
t.assert.strictEqual(second.headers['cache-control'], 'public, max-age=300')
})

test('sets the expires header', async (t) => {
t.plan(2)

Expand Down