Skip to content

Commit 58cafc1

Browse files
authoredMar 17, 2025
fix: add more measures to prevent using data-cache for blob operations (#2775)
1 parent 5d65c92 commit 58cafc1

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed
 

‎src/run/handlers/server.ts

+3
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@ import {
1313
setCacheTagsHeaders,
1414
setVaryHeaders,
1515
} from '../headers.js'
16+
import { setFetchBeforeNextPatchedIt } from '../regional-blob-store.cjs'
1617
import { nextResponseProxy } from '../revalidate.js'
1718

1819
import { getLogger, type RequestContext } from './request-context.cjs'
1920
import { getTracer } from './tracer.cjs'
2021
import { setupWaitUntil } from './wait-until.cjs'
2122

23+
setFetchBeforeNextPatchedIt(globalThis.fetch)
24+
2225
const nextImportPromise = import('../next.cjs')
2326

2427
setupWaitUntil()

‎src/run/regional-blob-store.cts

+53-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,62 @@
11
import { getDeployStore, GetWithMetadataOptions, Store } from '@netlify/blobs'
22

3-
const fetchBeforeNextPatchedIt = globalThis.fetch
3+
const FETCH_BEFORE_NEXT_PATCHED_IT = Symbol.for('nf-not-patched-fetch')
4+
const extendedGlobalThis = globalThis as typeof globalThis & {
5+
[FETCH_BEFORE_NEXT_PATCHED_IT]?: typeof globalThis.fetch
6+
}
7+
8+
/**
9+
* Attempt to extract original fetch in case it was patched by Next.js already
10+
*
11+
* @see github.com/vercel/next.js/blob/fa214c74c1d8023098c0e94e57f917ef9f1afd1a/packages/next/src/server/lib/patch-fetch.ts#L986
12+
*/
13+
function attemptToGetOriginalFetch(
14+
fetch: typeof globalThis.fetch & {
15+
_nextOriginalFetch?: typeof globalThis.fetch
16+
},
17+
) {
18+
return fetch._nextOriginalFetch ?? fetch
19+
}
20+
21+
function forceOptOutOfUsingDataCache(fetch: typeof globalThis.fetch): typeof globalThis.fetch {
22+
return (input, init) => {
23+
return fetch(input, {
24+
...init,
25+
next: {
26+
...init?.next,
27+
// setting next.internal = true should prevent from trying to use data cache
28+
// https://github.com/vercel/next.js/blob/fa214c74c1d8023098c0e94e57f917ef9f1afd1a/packages/next/src/server/lib/patch-fetch.ts#L174
29+
// https://github.com/vercel/next.js/blob/fa214c74c1d8023098c0e94e57f917ef9f1afd1a/packages/next/src/server/lib/patch-fetch.ts#L210-L213
30+
// this is last line of defense in case we didn't manage to get unpatched fetch that will not affect
31+
// fetch if it's unpatched so it should be safe to apply always if we aren't sure if we use patched fetch
32+
33+
// @ts-expect-error - this is an internal field that Next.js doesn't add to its global
34+
// type overrides for RequestInit type (like `next.revalidate` or `next.tags`)
35+
internal: true,
36+
},
37+
})
38+
}
39+
}
40+
41+
export const setFetchBeforeNextPatchedIt = (fetch: typeof globalThis.fetch) => {
42+
// we store in globalThis in case we have multiple copies of this module
43+
// just as precaution
44+
45+
extendedGlobalThis[FETCH_BEFORE_NEXT_PATCHED_IT] = forceOptOutOfUsingDataCache(
46+
attemptToGetOriginalFetch(fetch),
47+
)
48+
}
49+
50+
const fetchBeforeNextPatchedItFallback = forceOptOutOfUsingDataCache(
51+
attemptToGetOriginalFetch(globalThis.fetch),
52+
)
53+
const getFetchBeforeNextPatchedIt = () =>
54+
extendedGlobalThis[FETCH_BEFORE_NEXT_PATCHED_IT] ?? fetchBeforeNextPatchedItFallback
455

556
export const getRegionalBlobStore = (args: GetWithMetadataOptions = {}): Store => {
657
return getDeployStore({
758
...args,
8-
fetch: fetchBeforeNextPatchedIt,
59+
fetch: getFetchBeforeNextPatchedIt(),
960
region: process.env.USE_REGIONAL_BLOBS?.toUpperCase() === 'TRUE' ? undefined : 'us-east-2',
1061
})
1162
}

0 commit comments

Comments
 (0)
Please sign in to comment.