Skip to content

Commit 3d3c5cc

Browse files
alxndrsnDolan Halbrook
authored andcommitted
fix: cache: treat cache-control request header case-insensitively (nodejs#4131)
* fix: cache: treat cache-control request header case-insensitively Closes nodejs#3904 * lint; close server after test * call normaliseHeaders() once * revert unnecessary change --------- Co-authored-by: alxndrsn <alxndrsn>
1 parent bff0813 commit 3d3c5cc

File tree

3 files changed

+65
-4
lines changed

3 files changed

+65
-4
lines changed

lib/interceptor/cache.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ function handleResult (
233233
}
234234

235235
let headers = {
236-
...normaliseHeaders(opts),
236+
...opts.headers,
237237
'if-modified-since': new Date(result.cachedAt).toUTCString()
238238
}
239239

@@ -319,6 +319,11 @@ module.exports = (opts = {}) => {
319319
return dispatch(opts, handler)
320320
}
321321

322+
opts = {
323+
...opts,
324+
headers: normaliseHeaders(opts)
325+
}
326+
322327
const reqCacheControl = opts.headers?.['cache-control']
323328
? parseCacheControlHeader(opts.headers['cache-control'])
324329
: undefined

lib/util/cache.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@ function makeCacheKey (opts) {
1212
throw new Error('opts.origin is undefined')
1313
}
1414

15-
const headers = normaliseHeaders(opts)
16-
1715
return {
1816
origin: opts.origin.toString(),
1917
method: opts.method,
2018
path: opts.path,
21-
headers
19+
headers: opts.headers
2220
}
2321
}
2422

test/issue-3904.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
const { describe, test, after } = require('node:test')
2+
const assert = require('node:assert')
3+
const { createServer } = require('node:http')
4+
const { once } = require('node:events')
5+
const MemoryCacheStore = require('../lib/cache/memory-cache-store.js')
6+
const { Agent, interceptors, request, setGlobalDispatcher } = require('..')
7+
8+
describe('Cache with cache-control: no-store request header', () => {
9+
[
10+
'CACHE-CONTROL',
11+
'cache-control',
12+
'Cache-Control'
13+
].forEach(headerName => {
14+
test(`should not cache response for request with header: "${headerName}: no-store`, async () => {
15+
const store = new MemoryCacheStore()
16+
let requestCount = 0
17+
const server = createServer({ joinDuplicateHeaders: true }, (req, res) => {
18+
++requestCount
19+
res.setHeader('Vary', 'Accept-Encoding')
20+
res.setHeader('Cache-Control', 'max-age=60')
21+
res.end(`Request count: ${requestCount}`)
22+
})
23+
24+
after(async () => {
25+
server.close()
26+
27+
await once(server, 'close')
28+
})
29+
30+
await new Promise(resolve => server.listen(0, resolve))
31+
const { port } = server.address()
32+
const url = `http://localhost:${port}`
33+
34+
const agent = new Agent()
35+
setGlobalDispatcher(
36+
agent.compose(
37+
interceptors.cache({
38+
store,
39+
cacheByDefault: 1000,
40+
methods: ['GET']
41+
})
42+
)
43+
)
44+
45+
const res1 = await request(url, { headers: { [headerName]: 'no-store' } })
46+
const body1 = await res1.body.text()
47+
assert.strictEqual(body1, 'Request count: 1')
48+
assert.strictEqual(requestCount, 1)
49+
50+
const res2 = await request(url)
51+
const body2 = await res2.body.text()
52+
assert.strictEqual(body2, 'Request count: 2')
53+
assert.strictEqual(requestCount, 2)
54+
55+
await new Promise(resolve => server.close(resolve))
56+
})
57+
})
58+
})

0 commit comments

Comments
 (0)