From d691bf5ec87622382ebf3df14fb96c8b6672d34f Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Thu, 28 Nov 2024 13:57:40 -0800 Subject: [PATCH] cache override implementation --- runtime/fastly/builtins/cache-override.cpp | 92 ++++++++++++++++++++++ runtime/fastly/builtins/cache-override.h | 15 +++- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/runtime/fastly/builtins/cache-override.cpp b/runtime/fastly/builtins/cache-override.cpp index 5b06391e98..2f596c0a40 100644 --- a/runtime/fastly/builtins/cache-override.cpp +++ b/runtime/fastly/builtins/cache-override.cpp @@ -79,6 +79,26 @@ void CacheOverride::set_pci(JSObject *self, bool pci) { JS::SetReservedSlot(self, CacheOverride::Slots::PCI, JS::BooleanValue(pci)); } +JS::Value CacheOverride::beforeSend(JSObject *self) { + MOZ_ASSERT(is_instance(self)); + return JS::GetReservedSlot(self, Slots::BeforeSend); +} + +void CacheOverride::set_beforeSend(JSObject *self, JSObject *fn) { + MOZ_ASSERT(is_instance(self)); + JS::SetReservedSlot(self, Slots::BeforeSend, JS::ObjectValue(*fn)); +} + +JS::Value CacheOverride::afterSend(JSObject *self) { + MOZ_ASSERT(is_instance(self)); + return JS::GetReservedSlot(self, Slots::AfterSend); +} + +void CacheOverride::set_afterSend(JSObject *self, JSObject *fn) { + MOZ_ASSERT(is_instance(self)); + JS::SetReservedSlot(self, Slots::AfterSend, JS::ObjectValue(*fn)); +} + host_api::CacheOverrideTag CacheOverride::abi_tag(JSObject *self) { host_api::CacheOverrideTag tag; @@ -285,6 +305,64 @@ bool CacheOverride::pci_set(JSContext *cx, JS::HandleObject self, JS::HandleValu return true; } +bool CacheOverride::before_send_get(JSContext *cx, JS::HandleObject self, + JS::MutableHandleValue rval) { + if (self == proto_obj) { + return api::throw_error(cx, api::Errors::WrongReceiver, "beforeSend get", "CacheOverride"); + } + rval.set(CacheOverride::beforeSend(self)); + return true; +} + +bool CacheOverride::before_send_set(JSContext *cx, JS::HandleObject self, JS::HandleValue val, + JS::MutableHandleValue rval) { + if (self == proto_obj) { + return api::throw_error(cx, api::Errors::WrongReceiver, "beforeSend set", "CacheOverride"); + } + if (!CacheOverride::ensure_override(cx, self, "beforeSend")) + return false; + if (val.isUndefined()) { + JS::SetReservedSlot(self, Slots::BeforeSend, val); + } else if (!val.isObject() || !JS::IsCallable(&val.toObject())) { + JS_ReportErrorUTF8(cx, "CacheOverride: beforeSend must be a function"); + return false; + } else { + CacheOverride::set_beforeSend(self, &val.toObject()); + } + + rval.set(CacheOverride::beforeSend(self)); + return true; +} + +bool CacheOverride::after_send_get(JSContext *cx, JS::HandleObject self, + JS::MutableHandleValue rval) { + if (self == proto_obj) { + return api::throw_error(cx, api::Errors::WrongReceiver, "afterSend get", "CacheOverride"); + } + rval.set(CacheOverride::afterSend(self)); + return true; +} + +bool CacheOverride::after_send_set(JSContext *cx, JS::HandleObject self, JS::HandleValue val, + JS::MutableHandleValue rval) { + if (self == proto_obj) { + return api::throw_error(cx, api::Errors::WrongReceiver, "afterSend set", "CacheOverride"); + } + if (!CacheOverride::ensure_override(cx, self, "afterSend")) + return false; + if (val.isUndefined()) { + JS::SetReservedSlot(self, Slots::AfterSend, val); + } else if (!val.isObject() || !JS::IsCallable(&val.toObject())) { + JS_ReportErrorUTF8(cx, "CacheOverride: afterSend must be a function"); + return false; + } else { + CacheOverride::set_afterSend(self, &val.toObject()); + } + + rval.set(CacheOverride::afterSend(self)); + return true; +} + template bool CacheOverride::accessor_get(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(0) @@ -308,6 +386,10 @@ const JSPropertySpec CacheOverride::properties[] = { JS_PSGS("surrogateKey", accessor_get, accessor_set, JSPROP_ENUMERATE), JS_PSGS("pci", accessor_get, accessor_set, JSPROP_ENUMERATE), + JS_PSGS("beforeSend", accessor_get, accessor_set, + JSPROP_ENUMERATE), + JS_PSGS("afterSend", accessor_get, accessor_set, + JSPROP_ENUMERATE), JS_STRING_SYM_PS(toStringTag, "CacheOverride", JSPROP_READONLY), JS_PS_END}; @@ -345,6 +427,16 @@ bool CacheOverride::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { if (!JS_GetProperty(cx, override_init, "pci", &val) || !pci_set(cx, self, val, &val)) { return false; } + + if (!JS_GetProperty(cx, override_init, "beforeSend", &val) || + !before_send_set(cx, self, val, &val)) { + return false; + } + + if (!JS_GetProperty(cx, override_init, "afterSend", &val) || + !after_send_set(cx, self, val, &val)) { + return false; + } } args.rval().setObject(*self); diff --git a/runtime/fastly/builtins/cache-override.h b/runtime/fastly/builtins/cache-override.h index f519c4cf2d..b49992ee58 100644 --- a/runtime/fastly/builtins/cache-override.h +++ b/runtime/fastly/builtins/cache-override.h @@ -26,7 +26,10 @@ class CacheOverride : public builtins::BuiltinImpl { // // `PCI` is interpreted as a boolean, and a flag gets set in the hostcall's // `tag` parameter if `PCI` is true. - enum Slots { Mode, TTL, SWR, SurrogateKey, PCI, Count }; + // + // `BeforeSend` and `AfterSend` are function callbacks that can be set + // to execute before and after sending the request. + enum Slots { Mode, TTL, SWR, SurrogateKey, PCI, BeforeSend, AfterSend, Count }; enum class CacheOverrideMode { None, Pass, Override }; @@ -44,6 +47,10 @@ class CacheOverride : public builtins::BuiltinImpl { static JSObject *clone(JSContext *cx, JS::HandleObject self); static JS::Value pci(JSObject *self); static void set_pci(JSObject *self, bool pci); + static JS::Value beforeSend(JSObject *self); + static void set_beforeSend(JSObject *self, JSObject *fn); + static JS::Value afterSend(JSObject *self); + static void set_afterSend(JSObject *self, JSObject *fn); static CacheOverrideMode mode(JSObject *self); static void set_mode(JSObject *self, CacheOverride::CacheOverrideMode mode); static bool mode_get(JSContext *cx, JS::HandleObject self, JS::MutableHandleValue rval); @@ -61,6 +68,12 @@ class CacheOverride : public builtins::BuiltinImpl { static bool pci_get(JSContext *cx, JS::HandleObject self, JS::MutableHandleValue rval); static bool pci_set(JSContext *cx, JS::HandleObject self, JS::HandleValue val, JS::MutableHandleValue rval); + static bool before_send_get(JSContext *cx, JS::HandleObject self, JS::MutableHandleValue rval); + static bool before_send_set(JSContext *cx, JS::HandleObject self, JS::HandleValue val, + JS::MutableHandleValue rval); + static bool after_send_get(JSContext *cx, JS::HandleObject self, JS::MutableHandleValue rval); + static bool after_send_set(JSContext *cx, JS::HandleObject self, JS::HandleValue val, + JS::MutableHandleValue rval); template static bool accessor_get(JSContext *cx, unsigned argc, JS::Value *vp); template static bool accessor_set(JSContext *cx, unsigned argc, JS::Value *vp);