Skip to content

Commit

Permalink
initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
guybedford committed Dec 31, 2024
1 parent 39159e7 commit ed4e25f
Show file tree
Hide file tree
Showing 16 changed files with 560 additions and 180 deletions.
30 changes: 3 additions & 27 deletions integration-tests/js-compute/fixtures/app/src/cache-override.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,6 @@ import { isRunningLocally, routes } from './routes.js';
);
},
);
// https://tc39.es/ecma262/#sec-tostring
routes.set(
'/cache-override/constructor/parameter-calls-7.1.17-ToString',
async () => {
let sentinel;
const test = () => {
sentinel = Symbol();
const name = {
toString() {
throw sentinel;
},
};
new CacheOverride(name);
};
assertThrows(test);
try {
test();
} catch (thrownError) {
assert(thrownError, sentinel, 'thrownError === sentinel');
}
assertThrows(
() => new CacheOverride(Symbol()),
TypeError,
`can't convert symbol to string`,
);
},
);
routes.set('/cache-override/constructor/empty-parameter', async () => {
assertThrows(
() => {
Expand Down Expand Up @@ -80,6 +53,9 @@ import { isRunningLocally, routes } from './routes.js';
assertDoesNotThrow(() => {
new CacheOverride('override', {});
});
assertDoesNotThrow(() => {
new CacheOverride({});
});
});
}
// Using CacheOverride
Expand Down
2 changes: 0 additions & 2 deletions integration-tests/js-compute/fixtures/app/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import './cache-simple.js';
import './client.js';
import './compute.js';
import './config-store.js';
import './console.js';
import './crypto.js';
import './device.js';
import './dictionary.js';
Expand All @@ -25,7 +24,6 @@ import './fastly-global.js';
import './fetch-errors.js';
import './geoip.js';
import './headers.js';
import './http-cache.js';
import './include-bytes.js';
import './logger.js';
import './manual-framing-headers.js';
Expand Down
74 changes: 0 additions & 74 deletions integration-tests/js-compute/fixtures/app/tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
}
},
"GET /cache-override/constructor/called-as-regular-function": {},
"GET /cache-override/constructor/parameter-calls-7.1.17-ToString": {},
"GET /cache-override/constructor/empty-parameter": {},
"GET /cache-override/constructor/invalid-mode": {},
"GET /cache-override/constructor/valid-mode": {},
Expand Down Expand Up @@ -317,53 +316,6 @@
"GET /client/tlsCipherOpensslName": {},
"GET /client/tlsProtocol": {},
"GET /config-store": {},
"GET /console": {
"environments": ["viceroy"],
"logs": [
"stdout :: Log: Happy birthday Aki and Yuki!",
"stdout :: Log: Map: Map(2) { { a: 1, b: { c: 2 } } => 2, [ function foo() {\n }] => {} }",
"stdout :: Log: Set: Set(3) { { a: 1, b: { c: 2 } }, 2, 3 }",
"stdout :: Log: Array: [1, 2, 3, [], 5]",
"stdout :: Log: Object: { a: 1, b: 2, c: 3, d: [ d() {\n }], f: [Getter], g: [ function bar() {\n}], h: [ function from() {\n[native code]\n}] }",
"stdout :: Log: function: [ function() {\n }]",
"stdout :: Log: boolean: true",
"stdout :: Log: undefined: undefined",
"stdout :: Log: null: null",
"stdout :: Log: proxy: { a: 21 }",
"stdout :: Log: Infinity: Infinity",
"stdout :: Log: NaN: NaN",
"stdout :: Log: Symbol: Symbol(\"wow\")",
"stdout :: Log: Error: (new Error(\"uh oh\", \"<stdin>\", 7644))",
"stdout :: Log: Number: 1",
"stdout :: Log: Number: 1.111",
"stdout :: Log: BigInt: 10n",
"stdout :: Log: Date: new Date(1660816667120)",
"stdout :: Log: string: cake",
"stdout :: Log: RegExp: /magic/",
"stdout :: Log: Int8Array: Int8Array [1, 3, 4, 2, 5, 6, -97]",
"stdout :: Log: Uint8Array: Uint8Array [1, 3, 4, 2, 5, 6, 159]",
"stdout :: Log: Uint8ClampedArray: Uint8ClampedArray [1, 3, 4, 2, 5, 6, 255]",
"stdout :: Log: Int16Array: Int16Array [1, 3, 4, 2, 5, 6, -31073]",
"stdout :: Log: Uint16Array: Uint16Array [1, 3, 4, 2, 5, 6, 34463]",
"stdout :: Log: Int32Array: Int32Array [1, 3, 4, 2, 5, 6, 99999]",
"stdout :: Log: Uint32Array: Uint32Array [1, 3, 4, 2, 5, 6, 99999]",
"stdout :: Log: Float32Array: Float32Array [1, 3, 4, 2, 5, 6, 99999]",
"stdout :: Log: Float64Array: Float64Array [1, 3, 4, 2, 5, 6, 99999]",
"stdout :: Log: BigInt64Array: BigInt64Array [1n, 3n, 4n, 2n, 5n, 6n, 99999n]",
"stdout :: Log: BigUint64Array: BigUint64Array [1n, 3n, 4n, 2n, 5n, 6n, 99999n]",
"stdout :: Log: WeakMap: WeakMap { <items unknown> }",
"stdout :: Log: WeakSet: WeakSet { <items unknown> }",
"stdout :: Log: Promise: Promise { <pending> }",
"stdout :: Log: resolved promise: Promise { 9 }",
"stdout :: Log: rejected promise: Promise { <rejected> (new Error(\"oops\", \"<stdin>\", 7689)) }",
"stdout :: Log: Response: Response { redirected: false, type: \"default\", url: \"\", status: 200, ok: true, statusText: \"\", version: 2, headers: Headers {}, body: ReadableStream { locked: false }, bodyUsed: false }",
"stdout :: Log: Request: Request { method: \"POST\", url: \"https://www.fastly.com/\", version: 2, headers: Headers {}, backend: undefined, body: null, bodyUsed: false }",
"stdout :: Log: ReadableStream: ReadableStream { locked: false }",
"stdout :: Log: TransformStream: TransformStream { readable: ReadableStream { locked: false }, writable: WritableStream {} }",
"stdout :: Log: WritableStream: WritableStream {}",
"stdout :: Log: URL: URL { hash: \"\", host: \"www.test.com:123\", hostname: \"www.test.com\", href: \"https://www.test.com:123/asdf?some&params=val\", origin: \"https://www.test.com:123\", password: \"\", pathname: \"/asdf\", port: \"123\", protocol: \"https:\", search: \"?some&params=val\", searchParams: URLSearchParams {}, username: \"\" }"
]
},
"GET /crypto": {
"downstream_response": {
"status": 200,
Expand Down Expand Up @@ -1332,32 +1284,6 @@
"headers": [["cuStom", "test"]]
}
},
"GET /http-cache/invalid-properties": {},
"GET /http-cache/invalid-transform": {},
"GET /http-cache/hook-errors": {},
"GET /http-cache/readonly-properties": {},
"GET /http-cache/property-errors": {},
"GET /http-cache/property-access-errors": {},
"GET /http-cache/after-send-edge-cache": {},
"GET /http-cache/after-send-browser-cache": {},
"GET /http-cache/before-send": {},
"GET /http-cache/request-mutation": {},
"GET /http-cache/request-mutation-order": {},
"GET /http-cache/response-mutations": {},
"GET /http-cache/cacheability": {},
"GET /http-cache/stale-responses": {},
"GET /http-cache/body-transform": {},
"GET /http-cache/body-transform-error": {},
"GET /http-cache/body-transform-invalid-chunk": {},
"GET /http-cache/body-transform-write-after-close": {},
"GET /http-cache/body-transform-cancel": {},
"GET /http-cache/body-transform-backpressure": {},
"GET /http-cache/request-collapsing-options": {},
"GET /http-cache/request-collapsing-uncacheable": {},
"GET /http-cache/request-collapsing-vary": {},
"GET /http-cache/concurrent-modifications": {},
"GET /http-cache/concurrent-transforms": {},
"GET /http-cache/revalidation-updates": {},
"GET /FastlyBody/interface": {
"environments": ["compute"],
"downstream_response": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/* eslint-env serviceworker */
import { strictEqual, assertRejects } from './assertions.js';
import { routes } from './routes.js';
import { allowDynamicBackends } from 'fastly:experimental';
allowDynamicBackends(true);
import { CacheOverride } from 'fastly:cache-override';

// generate a unique URL everytime so that we never work on a populated cache
const getTestUrl = () =>
Expand Down Expand Up @@ -283,6 +282,20 @@ const getTestUrl = () =>
strictEqual(res.headers.get('Cache-Control'), 'max-age=3600');
});

routes.set('/http-cache/after-send-res-no-body-error', async () => {
let afterSendRes;
const cacheOverride = new CacheOverride({
afterSend(res) {
afterSendRes = res;
},
});
await fetch(url, { cacheOverride });
strictEqual(typeof afterSendRes, 'object');
// this should throw -> reading a body of a candidate response is not supported
// since revalidations have no body
return res;
});

routes.set('/http-cache/before-send', async () => {
let calledBeforeSend = false;
const cacheOverride = new CacheOverride({
Expand Down Expand Up @@ -854,4 +867,4 @@ const getTestUrl = () =>

// Testing TODO:
// - new properties
// - body transform
// - body transform (and not being called for revalidations)
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import { routes } from './routes.js';
import { env } from 'fastly:env';

import './console.js';
import './dynamic-backend.js';
import './hello-world.js';
import './hono.js';
import './http-cache.js';
import './kv-store.js';

addEventListener('fetch', (event) => {
Expand Down
73 changes: 73 additions & 0 deletions integration-tests/js-compute/fixtures/module-mode/tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,53 @@
"GET /backend/port-ip-defined": {},
"GET /backend/port-ip-cached": {},
"GET /backend/props": {},
"GET /console": {
"environments": ["viceroy"],
"logs": [
"stdout :: Log: Happy birthday Aki and Yuki!",
"stdout :: Log: Map: Map(2) { { a: 1, b: { c: 2 } } => 2, [ function foo() {\n }] => {} }",
"stdout :: Log: Set: Set(3) { { a: 1, b: { c: 2 } }, 2, 3 }",
"stdout :: Log: Array: [1, 2, 3, [], 5]",
"stdout :: Log: Object: { a: 1, b: 2, c: 3, d: [ d() {\n }], f: [Getter], g: [ function bar() {\n}], h: [ function from() {\n[native code]\n}] }",
"stdout :: Log: function: [ function() {\n }]",
"stdout :: Log: boolean: true",
"stdout :: Log: undefined: undefined",
"stdout :: Log: null: null",
"stdout :: Log: proxy: { a: 21 }",
"stdout :: Log: Infinity: Infinity",
"stdout :: Log: NaN: NaN",
"stdout :: Log: Symbol: Symbol(\"wow\")",
"stdout :: Log: Error: (new Error(\"uh oh\", \"<stdin>\", 7644))",
"stdout :: Log: Number: 1",
"stdout :: Log: Number: 1.111",
"stdout :: Log: BigInt: 10n",
"stdout :: Log: Date: new Date(1660816667120)",
"stdout :: Log: string: cake",
"stdout :: Log: RegExp: /magic/",
"stdout :: Log: Int8Array: Int8Array [1, 3, 4, 2, 5, 6, -97]",
"stdout :: Log: Uint8Array: Uint8Array [1, 3, 4, 2, 5, 6, 159]",
"stdout :: Log: Uint8ClampedArray: Uint8ClampedArray [1, 3, 4, 2, 5, 6, 255]",
"stdout :: Log: Int16Array: Int16Array [1, 3, 4, 2, 5, 6, -31073]",
"stdout :: Log: Uint16Array: Uint16Array [1, 3, 4, 2, 5, 6, 34463]",
"stdout :: Log: Int32Array: Int32Array [1, 3, 4, 2, 5, 6, 99999]",
"stdout :: Log: Uint32Array: Uint32Array [1, 3, 4, 2, 5, 6, 99999]",
"stdout :: Log: Float32Array: Float32Array [1, 3, 4, 2, 5, 6, 99999]",
"stdout :: Log: Float64Array: Float64Array [1, 3, 4, 2, 5, 6, 99999]",
"stdout :: Log: BigInt64Array: BigInt64Array [1n, 3n, 4n, 2n, 5n, 6n, 99999n]",
"stdout :: Log: BigUint64Array: BigUint64Array [1n, 3n, 4n, 2n, 5n, 6n, 99999n]",
"stdout :: Log: WeakMap: WeakMap { <items unknown> }",
"stdout :: Log: WeakSet: WeakSet { <items unknown> }",
"stdout :: Log: Promise: Promise { <pending> }",
"stdout :: Log: resolved promise: Promise { 9 }",
"stdout :: Log: rejected promise: Promise { <rejected> (new Error(\"oops\", \"<stdin>\", 7689)) }",
"stdout :: Log: Response: Response { redirected: false, type: \"default\", url: \"\", status: 200, ok: true, statusText: \"\", version: 2, headers: Headers {}, body: ReadableStream { locked: false }, bodyUsed: false }",
"stdout :: Log: Request: Request { method: \"POST\", url: \"https://www.fastly.com/\", version: 2, headers: Headers {}, backend: undefined, body: null, bodyUsed: false }",
"stdout :: Log: ReadableStream: ReadableStream { locked: false }",
"stdout :: Log: TransformStream: TransformStream { readable: ReadableStream { locked: false }, writable: WritableStream {} }",
"stdout :: Log: WritableStream: WritableStream {}",
"stdout :: Log: URL: URL { hash: \"\", host: \"www.test.com:123\", hostname: \"www.test.com\", href: \"https://www.test.com:123/asdf?some&params=val\", origin: \"https://www.test.com:123\", password: \"\", pathname: \"/asdf\", port: \"123\", protocol: \"https:\", search: \"?some&params=val\", searchParams: URLSearchParams {}, username: \"\" }"
]
},
"GET /hello-world": {
"downstream_response": {
"status": 200,
Expand All @@ -102,6 +149,32 @@
"body_prefix": "{\n \"args\": {},"
}
},
"GET /http-cache/invalid-properties": {},
"GET /http-cache/invalid-transform": {},
"GET /http-cache/hook-errors": {},
"GET /http-cache/readonly-properties": {},
"GET /http-cache/property-errors": {},
"GET /http-cache/property-access-errors": {},
"GET /http-cache/after-send-edge-cache": {},
"GET /http-cache/after-send-browser-cache": {},
"GET /http-cache/before-send": {},
"GET /http-cache/request-mutation": {},
"GET /http-cache/request-mutation-order": {},
"GET /http-cache/response-mutations": {},
"GET /http-cache/cacheability": {},
"GET /http-cache/stale-responses": {},
"GET /http-cache/body-transform": {},
"GET /http-cache/body-transform-error": {},
"GET /http-cache/body-transform-invalid-chunk": {},
"GET /http-cache/body-transform-write-after-close": {},
"GET /http-cache/body-transform-cancel": {},
"GET /http-cache/body-transform-backpressure": {},
"GET /http-cache/request-collapsing-options": {},
"GET /http-cache/request-collapsing-uncacheable": {},
"GET /http-cache/request-collapsing-vary": {},
"GET /http-cache/concurrent-modifications": {},
"GET /http-cache/concurrent-transforms": {},
"GET /http-cache/revalidation-updates": {},
"GET /kv-store-e2e/list": {},
"GET /kv-store/exposed-as-global": {},
"GET /kv-store/interface": {},
Expand Down
21 changes: 15 additions & 6 deletions runtime/fastly/builtins/cache-override.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ bool CacheOverride::ensure_override(JSContext *cx, JS::HandleObject self, const
}

bool CacheOverride::mode_set(JSContext *cx, JS::HandleObject self, JS::HandleValue val,
JS::MutableHandleValue rval) {
JS::MutableHandleValue ret) {
if (self == proto_obj) {
return api::throw_error(cx, api::Errors::WrongReceiver, "mode get", "CacheOverride");
}
Expand Down Expand Up @@ -399,17 +399,27 @@ bool CacheOverride::constructor(JSContext *cx, unsigned argc, JS::Value *vp) {
JS::RootedObject self(cx, JS_NewObjectForConstructor(cx, &class_, args));

JS::RootedValue val(cx);
if (!mode_set(cx, self, args[0], &val))
return false;

JS::RootedValue init(cx);
if (args[0].isObject()) {
init.setObject(args[0].toObject());
CacheOverride::set_mode(self, CacheOverrideMode::Override);
} else {
if (!mode_set(cx, self, args[0], &val))
return false;
if (args.length() > 1) {
init.set(args[1]);
}
}

if (CacheOverride::mode(self) == CacheOverride::CacheOverrideMode::Override) {
if (!args.get(1).isObject()) {
if (!init.isObject()) {
JS_ReportErrorUTF8(cx, "Creating a CacheOverride object with mode \"override\" requires "
"an init object for the override parameters as the second argument");
return false;
}

JS::RootedObject override_init(cx, &args[1].toObject());
JS::RootedObject override_init(cx, &init.toObject());

if (!JS_GetProperty(cx, override_init, "ttl", &val) || !ttl_set(cx, self, val, &val)) {
return false;
Expand Down Expand Up @@ -457,7 +467,6 @@ JSObject *CacheOverride::clone(JSContext *cx, JS::HandleObject self) {

for (size_t i = 0; i < Slots::Count; i++) {
JS::Value val = JS::GetReservedSlot(self, i);
MOZ_ASSERT(!val.isObject());
JS::SetReservedSlot(result, i, val);
}

Expand Down
Loading

0 comments on commit ed4e25f

Please sign in to comment.