| import { describe, it } from 'node:test'; |
| import assert from 'node:assert/strict'; |
| import { readFileSync } from 'node:fs'; |
| import { fileURLToPath } from 'node:url'; |
| import { dirname, join } from 'node:path'; |
|
|
| const __dirname = dirname(fileURLToPath(import.meta.url)); |
| const REPO_ROOT = join(__dirname, '..'); |
|
|
| |
| |
| |
| |
| |
| |
|
|
| function readSrc(rel) { |
| return readFileSync(join(REPO_ROOT, rel), 'utf-8'); |
| } |
|
|
| describe('HTTP Cache-Control: no-store on per-request responses (issue #97)', () => { |
| it('json() helper in server.js sets Cache-Control: no-store', () => { |
| const src = readSrc('src/server.js'); |
| const helper = src.match(/function json\(res, status, body\) \{[\s\S]*?\n\}/); |
| assert.ok(helper, 'json() helper not found'); |
| assert.match(helper[0], /'Cache-Control':\s*'no-store'/, 'json() must set Cache-Control: no-store'); |
| assert.doesNotMatch(helper[0], /'Cache-Control':\s*'no-cache'/, 'json() must not use no-cache (cacheable by spec)'); |
| }); |
|
|
| it('chat.js stream headers set Cache-Control: no-store', () => { |
| const src = readSrc('src/handlers/chat.js'); |
| |
| const block = src.match(/'Content-Type':\s*'text\/event-stream',[\s\S]*?'X-Accel-Buffering':\s*'no'/); |
| assert.ok(block, 'chat stream header block not found'); |
| assert.match(block[0], /'Cache-Control':\s*'no-store'/); |
| assert.doesNotMatch(block[0], /'Cache-Control':\s*'no-cache'/); |
| }); |
|
|
| it('messages.js stream headers set Cache-Control: no-store', () => { |
| const src = readSrc('src/handlers/messages.js'); |
| const block = src.match(/'Content-Type':\s*'text\/event-stream',[\s\S]*?'X-Accel-Buffering':\s*'no'/); |
| assert.ok(block, 'messages stream header block not found'); |
| assert.match(block[0], /'Cache-Control':\s*'no-store'/); |
| assert.doesNotMatch(block[0], /'Cache-Control':\s*'no-cache'/); |
| }); |
|
|
| it('responses.js stream headers set Cache-Control: no-store', () => { |
| const src = readSrc('src/handlers/responses.js'); |
| const block = src.match(/'Content-Type':\s*'text\/event-stream',[\s\S]*?'X-Accel-Buffering':\s*'no'/); |
| assert.ok(block, 'responses stream header block not found'); |
| assert.match(block[0], /'Cache-Control':\s*'no-store'/); |
| assert.doesNotMatch(block[0], /'Cache-Control':\s*'no-cache'/); |
| }); |
|
|
| it('json() actually emits Cache-Control: no-store on the wire', async () => { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| const http = await import('node:http'); |
| const { startServer } = await import('../src/server.js'); |
| const { config } = await import('../src/config.js'); |
| |
| |
| const prevPort = config.port; |
| const prevApiKey = config.apiKey; |
| config.port = 0; |
| config.apiKey = 'test-key-no-store'; |
| let server; |
| try { |
| server = startServer(); |
| await new Promise((resolve) => { |
| const tries = setInterval(() => { |
| const addr = server.address?.(); |
| if (addr && typeof addr === 'object') { clearInterval(tries); resolve(); } |
| }, 10); |
| }); |
| const port = server.address().port; |
| const res = await new Promise((resolve, reject) => { |
| const req = http.request({ host: '127.0.0.1', port, path: '/v1/models', method: 'GET' }, resolve); |
| req.on('error', reject); |
| req.end(); |
| }); |
| assert.equal(res.statusCode, 401, 'expected 401 without auth'); |
| assert.equal(res.headers['cache-control'], 'no-store', |
| `expected Cache-Control: no-store, got: ${res.headers['cache-control']}`); |
| |
| await new Promise((resolve) => { res.on('data', () => {}); res.on('end', resolve); }); |
| } finally { |
| config.port = prevPort; |
| config.apiKey = prevApiKey; |
| if (server) await new Promise((resolve) => server.close(resolve)); |
| } |
| }); |
| }); |
|
|