Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
20 changes: 19 additions & 1 deletion lib/interceptor/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,20 @@ class CacheHandler extends DecoratorHandler {
return super.onHeaders(statusCode, headers, resume)
}

if (cacheControlDirectives.private || cacheControlDirectives['no-store']) {
if (cacheControlDirectives['no-store']) {
return super.onHeaders(statusCode, headers, resume)
}

// Cache redirections even if private.
if (
cacheControlDirectives['private'] &&
statusCode !== 307 &&
statusCode !== 308 &&
statusCode !== 300 &&
statusCode !== 301 &&
statusCode !== 302 &&
statusCode !== 303
) {
return super.onHeaders(statusCode, headers, resume)
}
Comment thread
ronag marked this conversation as resolved.
Outdated

Expand Down Expand Up @@ -173,6 +186,7 @@ class CacheHandler extends DecoratorHandler {
etag: isEtagUsable(headers.etag) ? headers.etag : '',
vary,
cachedAt,
private: Boolean(cacheControlDirectives['private']),
// Handler state.
size: 0,
}
Expand Down Expand Up @@ -289,6 +303,10 @@ export default () => (dispatch) => (opts, handler) => {
}
}

if (entry?.private && !opts.cache.private) {
entry = null
}
Comment thread
ronag marked this conversation as resolved.
Comment on lines +309 to +311

// RFC 9111 Section 3.5: A shared cache must not use a cached response to a
// request with Authorization unless the response includes a public directive.
if (entry && opts.headers?.authorization && !entry.cacheControlDirectives?.public) {
Expand Down
22 changes: 16 additions & 6 deletions lib/sqlite-cache-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { DatabaseSync } from 'node:sqlite'
import { parseRangeHeader, getFastNow } from './utils.js'

// Bump version when the URL key format or schema changes to invalidate old caches.
const VERSION = 10
const VERSION = 11

/** @typedef {{ gc: () => void, clear: () => void } } */
const stores = new Set()
Expand Down Expand Up @@ -44,6 +44,7 @@ const stores = new Set()
* cacheControlDirectives?: string
* cachedAt: number
* deleteAt: number
* private: boolean
* }} SqliteStoreValue
Comment thread
ronag marked this conversation as resolved.
*/
export class SqliteCacheStore {
Expand Down Expand Up @@ -115,7 +116,8 @@ export class SqliteCacheStore {
cacheControlDirectives TEXT NULL,
etag TEXT NULL,
vary TEXT NULL,
cachedAt INTEGER NOT NULL
cachedAt INTEGER NOT NULL,
private BOOLEAN NOT NULL DEFAULT 0
);

CREATE INDEX IF NOT EXISTS idx_cacheInterceptorV${VERSION}_getValuesQuery ON cacheInterceptorV${VERSION}(url, method, start, deleteAt);
Expand All @@ -135,7 +137,8 @@ export class SqliteCacheStore {
etag,
cacheControlDirectives,
vary,
cachedAt
cachedAt,
private
FROM cacheInterceptorV${VERSION}
WHERE
url = ?
Expand All @@ -160,8 +163,9 @@ export class SqliteCacheStore {
etag,
cacheControlDirectives,
vary,
cachedAt
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
cachedAt,
private
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`)

this.#deleteExpiredValuesQuery = this.#db.prepare(
Expand Down Expand Up @@ -252,7 +256,7 @@ export class SqliteCacheStore {

/**
* @param {import('undici-types/cache-interceptor.d.ts').default.CacheKey} key
* @param {import('undici-types/cache-interceptor.d.ts').default.CacheValue & { body: null | Buffer | Array<Buffer>, start: number, end: number }} value
* @param {import('undici-types/cache-interceptor.d.ts').default.CacheValue & { body: null | Buffer | Array<Buffer>, start: number, end: number, private?: boolean }} value
*/
set(key, value) {
assertCacheKey(key)
Expand Down Expand Up @@ -313,6 +317,8 @@ export class SqliteCacheStore {
: null,
vary: value.vary ? JSON.stringify(value.vary) : null,
cachedAt: value.cachedAt,
// node:sqlite cannot bind a JS boolean; store as 0/1.
private: value.private ? 1 : 0,
})
}

Expand Down Expand Up @@ -343,6 +349,8 @@ export class SqliteCacheStore {
cacheControlDirectives,
vary,
cachedAt,
// 'private' is a reserved word — bind under a safe name.
private: isPrivate,
} = this.#insertBatch[n++]
this.#insertValueQuery.run(
url,
Expand All @@ -358,6 +366,7 @@ export class SqliteCacheStore {
cacheControlDirectives,
vary,
cachedAt,
isPrivate,
)
if (!final && (n & 0xf) === 0 && performance.now() - startTime > 10) {
break
Expand Down Expand Up @@ -580,6 +589,7 @@ function makeResult(value) {
? JSON.parse(value.cacheControlDirectives)
: undefined,
cachedAt: value.cachedAt,
private: Boolean(value.private),
deleteAt: value.deleteAt,
}
}
Expand Down