Skip to content

Commit bae42f7

Browse files
authored
Add cache: reload as experimental (#4875)
1 parent 115ff1b commit bae42f7

File tree

7 files changed

+70
-17
lines changed

7 files changed

+70
-17
lines changed

src/workerd/api/http-test-ts.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ export const cacheMode = {
7171
if (env.NO_CACHE_ENABLED) {
7272
enabledCacheModes.add('no-cache');
7373
}
74+
if (env.RELOAD_ENABLED) {
75+
enabledCacheModes.add('reload');
76+
}
7477

7578
const failureCacheModes = allowedCacheModes.difference(enabledCacheModes);
7679
for (const cacheMode of failureCacheModes) {

src/workerd/api/http-test-ts.ts-wd-test

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const unitTests :Workerd.Config = (
1111
( name = "SERVICE", service = "http-test" ),
1212
( name = "CACHE_ENABLED", json = "false" ),
1313
( name = "NO_CACHE_ENABLED", json = "false" ),
14+
( name = "RELOAD_ENABLED", json = "false" ),
1415
],
1516
compatibilityDate = "2023-08-01",
1617
compatibilityFlags = ["nodejs_compat", "service_binding_extra_handlers", "cache_option_disabled"],
@@ -25,6 +26,7 @@ const unitTests :Workerd.Config = (
2526
( name = "SERVICE", service = "http-test-cache-option-enabled" ),
2627
( name = "CACHE_ENABLED", json = "true" ),
2728
( name = "NO_CACHE_ENABLED", json = "false" ),
29+
( name = "RELOAD_ENABLED", json = "false" ),
2830
],
2931
compatibilityDate = "2024-11-11",
3032
compatibilityFlags = ["nodejs_compat", "service_binding_extra_handlers"],
@@ -39,10 +41,27 @@ const unitTests :Workerd.Config = (
3941
( name = "SERVICE", service = "http-test-cache-no-cache" ),
4042
( name = "CACHE_ENABLED", json = "true" ),
4143
( name = "NO_CACHE_ENABLED", json = "true" ),
44+
( name = "RELOAD_ENABLED", json = "false" ),
4245
],
4346
compatibilityDate = "2024-11-11",
4447
compatibilityFlags = ["nodejs_compat", "service_binding_extra_handlers", "cache_no_cache_enabled"],
4548
)
4649
),
50+
( name = "http-test-cache-reload",
51+
worker = (
52+
modules = [
53+
( name = "worker-reload", esModule = embed "http-test-ts.js" )
54+
],
55+
bindings = [
56+
( name = "SERVICE", service = "http-test-cache-reload" ),
57+
( name = "CACHE_ENABLED", json = "true" ),
58+
( name = "NO_CACHE_ENABLED", json = "true" ),
59+
( name = "RELOAD_ENABLED", json = "true" ),
60+
],
61+
compatibilityDate = "2024-11-11",
62+
compatibilityFlags = ["nodejs_compat", "service_binding_extra_handlers",
63+
"cache_no_cache_enabled", "cache_reload_enabled"],
64+
)
65+
),
4766
],
4867
);

src/workerd/api/http.c++

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ void requireValidHeaderValue(kj::StringPtr value) {
123123
Request::CacheMode getCacheModeFromName(kj::StringPtr value) {
124124
if (value == "no-store") return Request::CacheMode::NOSTORE;
125125
if (value == "no-cache") return Request::CacheMode::NOCACHE;
126+
if (value == "reload") return Request::CacheMode::RELOAD;
126127
JSG_FAIL_REQUIRE(TypeError, kj::str("Unsupported cache mode: ", value));
127128
}
128129

@@ -134,6 +135,8 @@ jsg::Optional<kj::StringPtr> getCacheModeName(Request::CacheMode mode) {
134135
return "no-cache"_kj;
135136
case (Request::CacheMode::NOSTORE):
136137
return "no-store"_kj;
138+
case (Request::CacheMode::RELOAD):
139+
return "reload"_kj;
137140
}
138141
KJ_UNREACHABLE;
139142
}
@@ -1241,19 +1244,20 @@ kj::Maybe<kj::String> Request::serializeCfBlobJson(jsg::Lock& js) {
12411244
}
12421245
auto obj = KJ_ASSERT_NONNULL(clone.get(js));
12431246

1244-
int ttl = 2;
1247+
constexpr int NOCACHE_TTL = -1;
12451248
switch (cacheMode) {
12461249
case CacheMode::NOSTORE:
1247-
ttl = -1;
1248-
obj.set(js, "cacheLevel", js.str("bypass"_kjc));
12491250
if (obj.has(js, "cacheTtl")) {
12501251
jsg::JsValue oldTtl = obj.get(js, "cacheTtl");
1251-
JSG_REQUIRE(oldTtl == js.num(ttl), TypeError,
1252+
JSG_REQUIRE(oldTtl == js.num(NOCACHE_TTL), TypeError,
12521253
kj::str("CacheTtl: ", oldTtl, ", is not compatible with cache: ",
12531254
getCacheModeName(cacheMode).orDefault("none"_kj), " header."));
12541255
} else {
1255-
obj.set(js, "cacheTtl", js.num(ttl));
1256+
obj.set(js, "cacheTtl", js.num(NOCACHE_TTL));
12561257
}
1258+
KJ_FALLTHROUGH;
1259+
case CacheMode::RELOAD:
1260+
obj.set(js, "cacheLevel", js.str("bypass"_kjc));
12571261
break;
12581262
case CacheMode::NOCACHE:
12591263
obj.set(js, "cacheForceRevalidate", js.boolean(true));
@@ -1274,10 +1278,12 @@ void RequestInitializerDict::validate(jsg::Lock& js) {
12741278
// Validate that the cache type is valid
12751279
auto cacheMode = getCacheModeFromName(c);
12761280

1277-
if (!FeatureFlags::get(js).getCacheNoCache()) {
1278-
JSG_REQUIRE(cacheMode != Request::CacheMode::NOCACHE, TypeError,
1279-
kj::str("Unsupported cache mode: ", c));
1280-
}
1281+
bool invalidNoCache =
1282+
!FeatureFlags::get(js).getCacheNoCache() && (cacheMode == Request::CacheMode::NOCACHE);
1283+
bool invalidReload =
1284+
!FeatureFlags::get(js).getCacheReload() && (cacheMode == Request::CacheMode::RELOAD);
1285+
JSG_REQUIRE(
1286+
!invalidNoCache && !invalidReload, TypeError, kj::str("Unsupported cache mode: ", c));
12811287
}
12821288

12831289
KJ_IF_SOME(e, encodeResponseBody) {
@@ -1901,11 +1907,12 @@ jsg::Promise<jsg::Ref<Response>> fetchImplNoOutputLock(jsg::Lock& js,
19011907
jsRequest->shallowCopyHeadersTo(headers);
19021908

19031909
// If the jsRequest has a CacheMode, we need to handle that here.
1904-
// Currently, the only cache mode we support is undefined and no-store (behind an autogate),
1905-
// but we will soon support no-cache.
1910+
// Currently, the only cache mode we support is undefined and no-store, no-cache, and reload
19061911
auto headerIds = ioContext.getHeaderIds();
19071912
const auto cacheMode = jsRequest->getCacheMode();
19081913
switch (cacheMode) {
1914+
case Request::CacheMode::RELOAD:
1915+
KJ_FALLTHROUGH;
19091916
case Request::CacheMode::NOSTORE:
19101917
KJ_FALLTHROUGH;
19111918
case Request::CacheMode::NOCACHE:

src/workerd/api/http.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,16 @@ struct RequestInitializerDict {
800800
JSG_STRUCT(method, headers, body, redirect, fetcher, cf, cache, integrity, signal, encodeResponseBody);
801801
JSG_STRUCT_TS_OVERRIDE_DYNAMIC(CompatibilityFlags::Reader flags) {
802802
if(flags.getCacheOptionEnabled()) {
803-
if(flags.getCacheNoCache()) {
803+
if(flags.getCacheReload()) {
804+
JSG_TS_OVERRIDE(RequestInit<Cf = CfProperties> {
805+
headers?: HeadersInit;
806+
body?: BodyInit | null;
807+
cache?: 'no-store' | 'no-cache' | 'reload';
808+
cf?: Cf;
809+
encodeResponseBody?: "automatic" | "manual";
810+
});
811+
812+
} else if(flags.getCacheNoCache()) {
804813
JSG_TS_OVERRIDE(RequestInit<Cf = CfProperties> {
805814
headers?: HeadersInit;
806815
body?: BodyInit | null;
@@ -848,6 +857,7 @@ class Request final: public Body {
848857
NONE,
849858
NOSTORE,
850859
NOCACHE,
860+
RELOAD,
851861
};
852862

853863
Request(jsg::Lock& js, kj::HttpMethod method, kj::StringPtr url, Redirect redirect,
@@ -994,7 +1004,14 @@ class Request final: public Body {
9941004
JSG_READONLY_PROTOTYPE_PROPERTY(keepalive, getKeepalive);
9951005
if(flags.getCacheOptionEnabled()) {
9961006
JSG_READONLY_PROTOTYPE_PROPERTY(cache, getCache);
997-
if(flags.getCacheNoCache()) {
1007+
if(flags.getCacheReload()) {
1008+
JSG_TS_OVERRIDE(<CfHostMetadata = unknown, Cf = CfProperties<CfHostMetadata>> {
1009+
constructor(input: RequestInfo<CfProperties> | URL, init?: RequestInit<Cf>);
1010+
clone(): Request<CfHostMetadata, Cf>;
1011+
cache?: "no-store" | "no-cache" | "reload";
1012+
get cf(): Cf | undefined;
1013+
});
1014+
} else if(flags.getCacheNoCache()) {
9981015
JSG_TS_OVERRIDE(<CfHostMetadata = unknown, Cf = CfProperties<CfHostMetadata>> {
9991016
constructor(input: RequestInfo<CfProperties> | URL, init?: RequestInit<Cf>);
10001017
clone(): Request<CfHostMetadata, Cf>;

src/workerd/io/compatibility-date.capnp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,6 +1187,7 @@ struct CompatibilityFlags @0x8f8c1b68151b6cef {
11871187
enableCtxExports @139 :Bool
11881188
$compatEnableFlag("enable_ctx_exports");
11891189
# Enable the ctx.exports API.
1190+
11901191
pythonExternalSDK @140 :Bool
11911192
$compatEnableFlag("enable_python_external_sdk")
11921193
$compatDisableFlag("disable_python_external_sdk")
@@ -1201,4 +1202,10 @@ struct CompatibilityFlags @0x8f8c1b68151b6cef {
12011202
# However, optional fields will be explicitly set to undefined rather than
12021203
# being omitted, which is an observable behavior change.
12031204
# TODO(soon): Once proven in production, add a default on date
1205+
1206+
cacheReload @142 :Bool
1207+
$compatEnableFlag("cache_reload_enabled")
1208+
$compatDisableFlag("cache_reload_disabled")
1209+
$experimental;
1210+
# Enables the use of cache: reload in the fetch api.
12041211
}

types/generated-snapshot/experimental/index.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2128,7 +2128,7 @@ interface Request<CfHostMetadata = unknown, Cf = CfProperties<CfHostMetadata>>
21282128
*
21292129
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/cache)
21302130
*/
2131-
cache?: "no-store" | "no-cache";
2131+
cache?: "no-store" | "no-cache" | "reload";
21322132
}
21332133
interface RequestInit<Cf = CfProperties> {
21342134
/* A string to set request's method. */
@@ -2142,7 +2142,7 @@ interface RequestInit<Cf = CfProperties> {
21422142
fetcher?: Fetcher | null;
21432143
cf?: Cf;
21442144
/* A string indicating how the request will interact with the browser's cache to set request's cache. */
2145-
cache?: "no-store" | "no-cache";
2145+
cache?: "no-store" | "no-cache" | "reload";
21462146
/* A cryptographic hash of the resource to be fetched by request. Sets request's integrity. */
21472147
integrity?: string;
21482148
/* An AbortSignal to set request's signal. */

types/generated-snapshot/experimental/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,7 +2136,7 @@ export interface Request<
21362136
*
21372137
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/cache)
21382138
*/
2139-
cache?: "no-store" | "no-cache";
2139+
cache?: "no-store" | "no-cache" | "reload";
21402140
}
21412141
export interface RequestInit<Cf = CfProperties> {
21422142
/* A string to set request's method. */
@@ -2150,7 +2150,7 @@ export interface RequestInit<Cf = CfProperties> {
21502150
fetcher?: Fetcher | null;
21512151
cf?: Cf;
21522152
/* A string indicating how the request will interact with the browser's cache to set request's cache. */
2153-
cache?: "no-store" | "no-cache";
2153+
cache?: "no-store" | "no-cache" | "reload";
21542154
/* A cryptographic hash of the resource to be fetched by request. Sets request's integrity. */
21552155
integrity?: string;
21562156
/* An AbortSignal to set request's signal. */

0 commit comments

Comments
 (0)