diff --git a/.clang-format b/.clang-format index 8c779d46044..26906b2f5dc 100644 --- a/.clang-format +++ b/.clang-format @@ -1,3 +1,7 @@ +Language: Cpp +Standard: c++20 +ColumnLimit: 100 + WhitespaceSensitiveMacros: # clang format doesn't understand TypeScript, so make sure it doesn't mangle # overrides and additional definitions @@ -5,6 +9,99 @@ WhitespaceSensitiveMacros: - JSG_TS_DEFINE - JSG_STRUCT_TS_OVERRIDE - JSG_STRUCT_TS_DEFINE -PointerAlignment: Left -ColumnLimit: 100 AllowShortFunctionsOnASingleLine: Empty + +# We should have "true" here but adding an include header would result in too many changed lines. +# Once we turn this on we should use IncludeCategories so that things are consistently sorted. +# For example, to protect against brittle headers (a header not including everything its using +# because existing users happened to include a dependency for it), one could use the following +# order: +# local folder files +# project files +# 3p dependency includes +# standard language headers (put kj/ here?) +# system headers +# While this would be ideal it's also important to note that this isn't the (non-documented) style +# that KJ uses, so it may be worth documenting the style & making it consistent. +SortIncludes: false + +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true + +IndentWidth: 2 +IndentCaseBlocks: false +IndentCaseLabels: true +PointerAlignment: Left +DerivePointerAlignment: true + +# Really "Attach" but empty braces aren't split. +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false + +Cpp11BracedListStyle: true + +AlignAfterOpenBracket: DontAlign +AlignOperands: DontAlign +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BreakStringLiterals: false +BinPackArguments: true +BinPackParameters: false +BracedInitializerIndentWidth: 2 +BreakInheritanceList: BeforeColon +ContinuationIndentWidth: 4 +IfMacros: + [ + "KJ_SWITCH_ONEOF", + "KJ_CASE_ONEOF", + "KJ_IF_MAYBE", + "KJ_IF_SOME", + "CFJS_RESOURCE_TYPE", + ] +LambdaBodyIndentation: OuterScope +Macros: + - "KJ_MAP(x,y)=[y](auto x)" + - "JSG_VISITABLE_LAMBDA(x,y,z)=[x,y](z)" + # The WhitespaceSensitiveMacros solution is flaky, adding the following ensures no formatting: + - "JSG_TS_OVERRIDE(x)=enum class" + - "JSG_TS_DEFINE(x)=enum class" + - "JSG_STRUCT_TS_OVERRIDE(x)=enum class" + - "JSG_STRUCT_TS_DEFINE(x)=enum class" +PenaltyReturnTypeOnItsOwnLine: 1000 +PackConstructorInitializers: CurrentLine +ReflowComments: false +SpaceBeforeCtorInitializerColon: false +SpaceBeforeInheritanceColon: false +SpaceBeforeParens: ControlStatementsExceptControlMacros +SpaceBeforeRangeBasedForLoopColon: false +SpacesBeforeTrailingComments: 2 +--- +# Some files with embedded typescript are incorrectly recognized by clang-format as Objective-C +# This is because the C/C++ macro expansion step happens after the language recognition step, so +# when trying to parse the file, the c++ parser fails with incorrect syntax and a fallback to +# the Objective-C parser is used. +# This is a workaround to hide the warning. +# TODO: Remove this once we have a better solution. +Language: ObjC +DisableFormat: true diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index d99b84fff59..d5ec17e6100 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,2 +1,5 @@ # Apply prettier to the project 0523bf8b36a937348f1bb79eceda2463a5c220b5 + +# Apply clang-format to the project. +5e8537a77e760c160ace3dfe23ee8c76ee5aeeb3 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 29cce9f9836..5a8e6aa895e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -5,7 +5,7 @@ on: push: branches: - main - + jobs: lint: runs-on: ubuntu-24.04 diff --git a/docs/development.md b/docs/development.md index 7d010f14a9e..f46c30cd063 100644 --- a/docs/development.md +++ b/docs/development.md @@ -21,3 +21,11 @@ just prepare ```sh just compile-commands ``` + +## Code Formatting + +workerd code is automatically formatted by clang-format. Run `python ./tools/cross/format.py` to reformat the code +or use the appropriate IDE extension. +While workerd generally requires llvm 15, formatting requires clang-format-18. + +Code formatting is checked before check-in and during `Linting` CI build. diff --git a/githooks/pre-commit b/githooks/pre-commit index 7a25f8f38de..c92f190e0f2 100755 --- a/githooks/pre-commit +++ b/githooks/pre-commit @@ -10,3 +10,43 @@ then echo -e "To commit anyway, use --no-verify\n" exit 1 fi + +clang_format_check() { + source "$(dirname -- $BASH_SOURCE)/../tools/unix/find-python3.sh" + PYTHON_PATH=$(get_python3) + if [[ -z "$PYTHON_PATH" ]]; then + echo + echo "python3 is required for formatting and was not found" + echo + echo "ERROR: you must either install python3 and try pushing again or run `git push` with `--no-verify`" + return 1 + fi + + set +e + $PYTHON_PATH "$(dirname -- $BASH_SOURCE)/../tools/cross/format.py" --check git --staged + EXIT_CODE=$? + set -e + case $EXIT_CODE in + 0) + # No lint. + return 0 + ;; + 1) + echo + echo "ERROR: changes staged for commit have lint. Pass '--no-verify' or '-n' to skip." + echo + echo "To fix lint:" + echo " python3 ./tools/cross/format.py" + echo + return 1 + ;; + 2) + echo + echo "ERROR: failed to run format.py, Pass '--no-verify' or '-n' to skip." + echo + return 1 + ;; + esac +} + +clang_format_check diff --git a/src/workerd/api/actor-state-iocontext-test.c++ b/src/workerd/api/actor-state-iocontext-test.c++ index a8002181014..712f37f56b4 100644 --- a/src/workerd/api/actor-state-iocontext-test.c++ +++ b/src/workerd/api/actor-state-iocontext-test.c++ @@ -17,13 +17,13 @@ namespace { using workerd::TestFixture; bool contains(kj::StringPtr haystack, kj::StringPtr needle) { - return std::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()) - != haystack.end(); + return std::search(haystack.begin(), haystack.end(), needle.begin(), needle.end()) != + haystack.end(); } -class MockActorId : public ActorIdFactory::ActorId { +class MockActorId: public ActorIdFactory::ActorId { public: - MockActorId(kj::String id) : id(kj::mv(id)) {} + MockActorId(kj::String id): id(kj::mv(id)) {} kj::String toString() const override { return kj::str("MockActorId<", id, ">"); } @@ -41,6 +41,7 @@ public: } virtual ~MockActorId() {}; + private: kj::String id; }; @@ -63,9 +64,9 @@ void runBadDeserialization(jsg::Lock& lock, kj::StringPtr expectedId) { void runBadDeserializationInIoContext(TestFixture& fixture, kj::StringPtr expectedId) { fixture.runInIoContext( - [expectedId](const workerd::TestFixture::Environment& env) -> kj::Promise { - runBadDeserialization(env.lock, expectedId); - return kj::READY_NOW; + [expectedId](const workerd::TestFixture::Environment& env) -> kj::Promise { + runBadDeserialization(env.lock, expectedId); + return kj::READY_NOW; }); } @@ -88,10 +89,10 @@ KJ_TEST("actor specified with ActorId object") { kj::Own mockActorId = kj::heap(kj::str("testActorId")); Worker::Actor::Id id = kj::mv(mockActorId); TestFixture fixture(TestFixture::SetupParams{ - .actorId = kj::mv(id), + .actorId = kj::mv(id), }); runBadDeserializationInIoContext(fixture, "actorId = MockActorId;"_kj); } -} // namespace -} // namespace workerd::api +} // namespace +} // namespace workerd::api diff --git a/src/workerd/api/actor-state-test.c++ b/src/workerd/api/actor-state-test.c++ index 3db232d3c45..829b02c930d 100644 --- a/src/workerd/api/actor-state-test.c++ +++ b/src/workerd/api/actor-state-test.c++ @@ -25,8 +25,7 @@ namespace { jsg::V8System v8System; struct ActorStateContext: public jsg::Object, public jsg::ContextGlobal { - JSG_RESOURCE_TYPE(ActorStateContext) { - } + JSG_RESOURCE_TYPE(ActorStateContext) {} }; JSG_DECLARE_ISOLATE_TYPE(ActorStateIsolate, ActorStateContext); @@ -34,8 +33,7 @@ KJ_TEST("v8 serialization version tag hasn't changed") { jsg::test::Evaluator e(v8System); e.getIsolate().runInLockScope([&](ActorStateIsolate::Lock& isolateLock) { JSG_WITHIN_CONTEXT_SCOPE(isolateLock, - isolateLock.newContext().getHandle(isolateLock), - [&](jsg::Lock& js) { + isolateLock.newContext().getHandle(isolateLock), [&](jsg::Lock& js) { auto buf = serializeV8Value(isolateLock, isolateLock.boolean(true)); // Confirm that a version header is appropriately written and that it contains the expected @@ -43,7 +41,7 @@ KJ_TEST("v8 serialization version tag hasn't changed") { // to continue writing data at the old version so that we can do a rolling upgrade without // any bugs caused by old processes failing to read data written by new ones. KJ_EXPECT(buf[0] == 0xFF); - KJ_EXPECT(buf[1] == 0x0F); // v8 serializer version + KJ_EXPECT(buf[1] == 0x0F); // v8 serializer version // And this just confirms that the deserializer agrees on the version. v8::ValueDeserializer deserializer(isolateLock.v8Isolate, buf.begin(), buf.size()); @@ -61,15 +59,14 @@ KJ_TEST("we support deserializing up to v15") { jsg::test::Evaluator e(v8System); e.getIsolate().runInLockScope([&](ActorStateIsolate::Lock& isolateLock) { JSG_WITHIN_CONTEXT_SCOPE(isolateLock, - isolateLock.newContext().getHandle(isolateLock), - [&](jsg::Lock& js) { + isolateLock.newContext().getHandle(isolateLock), [&](jsg::Lock& js) { kj::Vector testCases; testCases.add("54"); testCases.add("FF0D54"); testCases.add("FF0E54"); testCases.add("FF0F54"); - for (const auto& hexStr : testCases) { + for (const auto& hexStr: testCases) { auto dataIn = kj::decodeHex(hexStr.asArray()); KJ_EXPECT(deserializeV8Value(isolateLock, "some-key"_kj, dataIn).isTrue()); } @@ -104,8 +101,7 @@ KJ_TEST("wire format version does not change deserialization behavior on real da jsg::test::Evaluator e(v8System); e.getIsolate().runInLockScope([&](ActorStateIsolate::Lock& isolateLock) { JSG_WITHIN_CONTEXT_SCOPE(isolateLock, - isolateLock.newContext().getHandle(isolateLock), - [&](jsg::Lock& js) { + isolateLock.newContext().getHandle(isolateLock), [&](jsg::Lock& js) { // Read in data line by line and verify that it round trips (serializes and // then deserializes) back to the exact same data as the input. std::string hexStr; diff --git a/src/workerd/api/actor-state.c++ b/src/workerd/api/actor-state.c++ index 03fd3cd28cf..d1e293a0e27 100644 --- a/src/workerd/api/actor-state.c++ +++ b/src/workerd/api/actor-state.c++ @@ -23,13 +23,11 @@ namespace { constexpr size_t BILLING_UNIT = 4096; -enum class BillAtLeastOne { - NO, YES -}; +enum class BillAtLeastOne { NO, YES }; uint32_t billingUnits(size_t bytes, BillAtLeastOne billAtLeastOne = BillAtLeastOne::YES) { if (billAtLeastOne == BillAtLeastOne::YES && bytes == 0) { - return 1; // always bill for at least 1 billing unit + return 1; // always bill for at least 1 billing unit } return bytes / BILLING_UNIT + (bytes % BILLING_UNIT != 0); } @@ -45,8 +43,9 @@ jsg::JsValue deserializeMaybeV8Value( template auto transformCacheResult(jsg::Lock& js, - kj::OneOf> input, const Options& options, Func&& func) - -> jsg::Promise()))> { + kj::OneOf> input, + const Options& options, + Func&& func) -> jsg::Promise()))> { KJ_SWITCH_ONEOF(input) { KJ_CASE_ONEOF(value, T) { return js.resolvedPromise(func(js, kj::mv(value))); @@ -54,13 +53,13 @@ auto transformCacheResult(jsg::Lock& js, KJ_CASE_ONEOF(promise, kj::Promise) { auto& context = IoContext::current(); if (options.allowConcurrency.orDefault(false)) { - return context.awaitIo(js, kj::mv(promise), - [func = kj::fwd(func)](jsg::Lock& js, T&& value) mutable { + return context.awaitIo( + js, kj::mv(promise), [func = kj::fwd(func)](jsg::Lock& js, T&& value) mutable { return func(js, kj::mv(value)); }); } else { - return context.awaitIoWithInputLock(js, kj::mv(promise), - [func = kj::fwd(func)](jsg::Lock& js, T&& value) mutable { + return context.awaitIoWithInputLock( + js, kj::mv(promise), [func = kj::fwd(func)](jsg::Lock& js, T&& value) mutable { return func(js, kj::mv(value)); }); } @@ -70,9 +69,10 @@ auto transformCacheResult(jsg::Lock& js, } template -auto transformCacheResultWithCacheStatus( - jsg::Lock& js, kj::OneOf> input, const Options& options, Func&& func) - -> jsg::Promise(), kj::instance()))> { +auto transformCacheResultWithCacheStatus(jsg::Lock& js, + kj::OneOf> input, + const Options& options, + Func&& func) -> jsg::Promise(), kj::instance()))> { KJ_SWITCH_ONEOF(input) { KJ_CASE_ONEOF(value, T) { return js.resolvedPromise(func(js, kj::mv(value), true)); @@ -80,13 +80,13 @@ auto transformCacheResultWithCacheStatus( KJ_CASE_ONEOF(promise, kj::Promise) { auto& context = IoContext::current(); if (options.allowConcurrency.orDefault(false)) { - return context.awaitIo(js, kj::mv(promise), - [func = kj::fwd(func)](jsg::Lock& js, T&& value) mutable { + return context.awaitIo( + js, kj::mv(promise), [func = kj::fwd(func)](jsg::Lock& js, T&& value) mutable { return func(js, kj::mv(value), false); }); } else { - return context.awaitIoWithInputLock(js, kj::mv(promise), - [func = kj::fwd(func)](jsg::Lock& js, T&& value) mutable { + return context.awaitIoWithInputLock( + js, kj::mv(promise), [func = kj::fwd(func)](jsg::Lock& js, T&& value) mutable { return func(js, kj::mv(value), false); }); } @@ -97,8 +97,7 @@ auto transformCacheResultWithCacheStatus( template jsg::Promise transformMaybeBackpressure( - jsg::Lock& js, const Options& options, - kj::Maybe> maybeBackpressure) { + jsg::Lock& js, const Options& options, kj::Maybe> maybeBackpressure) { KJ_IF_SOME(backpressure, maybeBackpressure) { // Note: In practice `allowConcurrency` will have no effect on a backpressure promise since // backpressure blocks everything anyway, but we pass the option through for consistency in @@ -118,16 +117,15 @@ ActorObserver& currentActorMetrics() { return IoContext::current().getActorOrThrow().getMetrics(); } -jsg::JsRef listResultsToMap(jsg::Lock& js, - ActorCacheOps::GetResultList value, - bool completelyCached) { +jsg::JsRef listResultsToMap( + jsg::Lock& js, ActorCacheOps::GetResultList value, bool completelyCached) { return js.withinHandleScope([&] { auto map = js.map(); size_t cachedReadBytes = 0; size_t uncachedReadBytes = 0; for (auto entry: value) { - auto& bytesRef = entry.status == ActorCacheOps::CacheStatus::CACHED - ? cachedReadBytes : uncachedReadBytes; + auto& bytesRef = + entry.status == ActorCacheOps::CacheStatus::CACHED ? cachedReadBytes : uncachedReadBytes; bytesRef += entry.key.size() + entry.value.size(); map.set(js, entry.key, deserializeV8Value(js, entry.key, entry.value)); } @@ -155,16 +153,15 @@ jsg::JsRef listResultsToMap(jsg::Lock& js, } kj::Function(jsg::Lock&, ActorCacheOps::GetResultList)> -getMultipleResultsToMap( - size_t numInputKeys) { +getMultipleResultsToMap(size_t numInputKeys) { return [numInputKeys](jsg::Lock& js, ActorCacheOps::GetResultList value) mutable { return js.withinHandleScope([&] { auto map = js.map(); uint32_t cachedUnits = 0; uint32_t uncachedUnits = 0; for (auto entry: value) { - auto& unitsRef = entry.status == ActorCacheOps::CacheStatus::CACHED - ? cachedUnits : uncachedUnits; + auto& unitsRef = + entry.status == ActorCacheOps::CacheStatus::CACHED ? cachedUnits : uncachedUnits; unitsRef += billingUnits(entry.key.size() + entry.value.size()); map.set(js, entry.key, deserializeV8Value(js, entry.key, entry.value)); } @@ -192,18 +189,16 @@ getMultipleResultsToMap( }; } -kj::Promise updateStorageWriteUnit(IoContext& context, - ActorObserver& metrics, - uint32_t units) { +kj::Promise updateStorageWriteUnit( + IoContext& context, ActorObserver& metrics, uint32_t units) { // The ActorObserver& reference here is guaranteed to outlive this task, so // accessing it after the co_await here is safe. co_await context.waitForOutputLocks(); metrics.addStorageWriteUnits(units); } -kj::Promise updateStorageDeletes(IoContext& context, - ActorObserver& metrics, - kj::Promise promise) { +kj::Promise updateStorageDeletes( + IoContext& context, ActorObserver& metrics, kj::Promise promise) { // The ActorObserver& reference here is guaranteed to outlive this task, so // accessing it after the co_await here is safe. auto deleted = co_await promise; @@ -217,12 +212,12 @@ kj::Maybe getCurrentActorId() { IoContext& ioContext = IoContext::current(); KJ_IF_SOME(actor, ioContext.getActor()) { KJ_SWITCH_ONEOF(actor.getId()) { - KJ_CASE_ONEOF(s, kj::String) { - return kj::heapString(s); - } - KJ_CASE_ONEOF(actorId, kj::Own) { - return actorId->toString(); - } + KJ_CASE_ONEOF(s, kj::String) { + return kj::heapString(s); + } + KJ_CASE_ONEOF(actorId, kj::Own) { + return actorId->toString(); + } } KJ_UNREACHABLE; } @@ -232,8 +227,7 @@ kj::Maybe getCurrentActorId() { } // namespace -jsg::Promise> DurableObjectStorageOperations::get( - jsg::Lock& js, +jsg::Promise> DurableObjectStorageOperations::get(jsg::Lock& js, kj::OneOf> keys, jsg::Optional maybeOptions) { auto options = configureOptions(kj::mv(maybeOptions).orDefault(GetOptions{})); @@ -273,19 +267,16 @@ jsg::Promise> DurableObjectStorageOperations::getAlarm( jsg::Lock& js, jsg::Optional maybeOptions) { // Even if we do not have an alarm handler, we might once have had one. It's fine to return // whatever a previous alarm setting or a falsy result. - auto options = configureOptions(maybeOptions.map([](auto& o) { - return GetOptions { - .allowConcurrency = o.allowConcurrency, - .noCache = false - }; + auto options = configureOptions(maybeOptions + .map([](auto& o) { + return GetOptions{.allowConcurrency = o.allowConcurrency, .noCache = false}; }).orDefault(GetOptions{})); auto result = getCache(OP_GET_ALARM).getAlarm(options); - return transformCacheResult(js, kj::mv(result), options, - [](jsg::Lock&, kj::Maybe date) { - return date.map([](auto& date) { - return static_cast((date - kj::UNIX_EPOCH) / kj::MILLISECONDS); - }); + return transformCacheResult( + js, kj::mv(result), options, [](jsg::Lock&, kj::Maybe date) { + return date.map( + [](auto& date) { return static_cast((date - kj::UNIX_EPOCH) / kj::MILLISECONDS); }); }); } @@ -296,14 +287,13 @@ jsg::Promise> DurableObjectStorageOperations::list( bool reverse = false; kj::Maybe limit; - auto makeEmptyResult = [&]() { - return js.resolvedPromise(jsg::JsValue(js.map()).addRef(js)); - }; + auto makeEmptyResult = [&]() { return js.resolvedPromise(jsg::JsValue(js.map()).addRef(js)); }; KJ_IF_SOME(o, maybeOptions) { KJ_IF_SOME(s, o.start) { if (o.startAfter != kj::none) { - KJ_FAIL_REQUIRE("jsg.TypeError: list() cannot be called with both start and startAfter values."); + KJ_FAIL_REQUIRE( + "jsg.TypeError: list() cannot be called with both start and startAfter values."); } start = kj::mv(s); } @@ -318,10 +308,10 @@ jsg::Promise> DurableObjectStorageOperations::list( // Add one additional null byte to set the new start as the key immediately // after startAfter. This looks a little sketchy to be doing with strings rather // than arrays, but kj::String explicitly allows for NULL bytes inside of strings. - startAfterKey[startAfterKey.size()-2] = '\0'; + startAfterKey[startAfterKey.size() - 2] = '\0'; // kj::String automatically reads the last NULL as string termination, so we need to add it twice // to make it stick in the final string. - startAfterKey[startAfterKey.size()-1] = '\0'; + startAfterKey[startAfterKey.size() - 1] = '\0'; start = kj::String(kj::mv(startAfterKey)); } KJ_IF_SOME(e, o.end) { @@ -395,12 +385,10 @@ jsg::Promise> DurableObjectStorageOperations::list( auto result = reverse ? getCache(OP_LIST).listReverse(kj::mv(start), kj::mv(end), limit, readOptions) : getCache(OP_LIST).list(kj::mv(start), kj::mv(end), limit, readOptions); - return transformCacheResultWithCacheStatus(js, kj::mv(result), - options, &listResultsToMap); + return transformCacheResultWithCacheStatus(js, kj::mv(result), options, &listResultsToMap); } -jsg::Promise DurableObjectStorageOperations::put( - jsg::Lock& js, +jsg::Promise DurableObjectStorageOperations::put(jsg::Lock& js, kj::OneOf> keyOrEntries, jsg::Optional value, jsg::Optional maybeOptions, @@ -422,8 +410,7 @@ jsg::Promise DurableObjectStorageOperations::put( KJ_IF_SOME(opt, optionsTypeHandler.tryUnwrap(js, v)) { return putMultiple(js, kj::mv(o), configureOptions(kj::mv(opt))); } else { - JSG_FAIL_REQUIRE( - TypeError, + JSG_FAIL_REQUIRE(TypeError, "put() may only be called with a single key-value pair and optional options as put(key, value, options) or with multiple key-value pairs and optional options as put(entries, options)"); } } else { @@ -434,13 +421,10 @@ jsg::Promise DurableObjectStorageOperations::put( KJ_UNREACHABLE; } - jsg::Promise DurableObjectStorageOperations::setAlarm( - jsg::Lock& js, - kj::Date scheduledTime, - jsg::Optional maybeOptions) { + jsg::Lock& js, kj::Date scheduledTime, jsg::Optional maybeOptions) { JSG_REQUIRE(scheduledTime > kj::origin(), TypeError, - "setAlarm() cannot be called with an alarm time <= 0"); + "setAlarm() cannot be called with an alarm time <= 0"); auto& context = IoContext::current(); // This doesn't check if we have an alarm handler per say. It checks if we have an initialized @@ -449,12 +433,11 @@ jsg::Promise DurableObjectStorageOperations::setAlarm( // is better than throwing even if we do have an alarm handler. context.getActorOrThrow().assertCanSetAlarm(); - auto options = configureOptions(maybeOptions.map([](auto& o) { - return PutOptions { - .allowConcurrency = o.allowConcurrency, + auto options = configureOptions(maybeOptions + .map([](auto& o) { + return PutOptions{.allowConcurrency = o.allowConcurrency, .allowUnconfirmed = o.allowUnconfirmed, - .noCache = false - }; + .noCache = false}; }).orDefault(PutOptions{})); // We fudge times set in the past to Date.now() to ensure that any one user can't DDOS the alarm @@ -462,11 +445,10 @@ jsg::Promise DurableObjectStorageOperations::setAlarm( // This also ensures uniqueness of alarm times (which is required for correctness), // in the situation where customers use a constant date in the past to indicate // they want immediate execution. - kj::Date dateNowKjDate = - static_cast(dateNow()) * kj::MILLISECONDS + kj::UNIX_EPOCH; + kj::Date dateNowKjDate = static_cast(dateNow()) * kj::MILLISECONDS + kj::UNIX_EPOCH; - auto maybeBackpressure = transformMaybeBackpressure(js, options, - getCache(OP_PUT_ALARM).setAlarm(kj::max(scheduledTime, dateNowKjDate), options)); + auto maybeBackpressure = transformMaybeBackpressure( + js, options, getCache(OP_PUT_ALARM).setAlarm(kj::max(scheduledTime, dateNowKjDate), options)); // setAlarm() is billed as a single write unit. context.addTask(updateStorageWriteUnit(context, currentActorMetrics(), 1)); @@ -475,10 +457,7 @@ jsg::Promise DurableObjectStorageOperations::setAlarm( } jsg::Promise DurableObjectStorageOperations::putOne( - jsg::Lock& js, - kj::String key, - jsg::JsValue value, - const PutOptions& options) { + jsg::Lock& js, kj::String key, jsg::JsValue value, const PutOptions& options) { ActorStorageLimits::checkMaxKeySize(key); kj::Array buffer = serializeV8Value(js, value); @@ -486,8 +465,8 @@ jsg::Promise DurableObjectStorageOperations::putOne( auto units = billingUnits(key.size() + buffer.size()); - jsg::Promise maybeBackpressure = transformMaybeBackpressure(js, options, - getCache(OP_PUT).put(kj::mv(key), kj::mv(buffer), options)); + jsg::Promise maybeBackpressure = transformMaybeBackpressure( + js, options, getCache(OP_PUT).put(kj::mv(key), kj::mv(buffer), options)); auto& context = IoContext::current(); context.addTask(updateStorageWriteUnit(context, currentActorMetrics(), units)); @@ -515,16 +494,15 @@ jsg::Promise DurableObjectStorageOperations::deleteAlarm( jsg::Lock& js, jsg::Optional maybeOptions) { // Even if we do not have an alarm handler, we might once have had one. It's fine to remove that // alarm or noop on the absence of one. - auto options = configureOptions(maybeOptions.map([](auto& o) { - return PutOptions { - .allowConcurrency = o.allowConcurrency, + auto options = configureOptions(maybeOptions + .map([](auto& o) { + return PutOptions{.allowConcurrency = o.allowConcurrency, .allowUnconfirmed = o.allowUnconfirmed, - .noCache = false - }; + .noCache = false}; }).orDefault(PutOptions{})); - return transformMaybeBackpressure(js, options, - getCache(OP_DELETE_ALARM).setAlarm(kj::none, options)); + return transformMaybeBackpressure( + js, options, getCache(OP_DELETE_ALARM).setAlarm(kj::none, options)); } jsg::Promise DurableObjectStorage::deleteAll( @@ -547,33 +525,29 @@ jsg::Promise DurableObjectStorageOperations::deleteOne( jsg::Lock& js, kj::String key, const PutOptions& options) { ActorStorageLimits::checkMaxKeySize(key); - return transformCacheResult(js, getCache(OP_DELETE).delete_(kj::mv(key), options), options, - [](jsg::Lock&, bool value) { + return transformCacheResult( + js, getCache(OP_DELETE).delete_(kj::mv(key), options), options, [](jsg::Lock&, bool value) { currentActorMetrics().addStorageDeletes(1); return value; }); } jsg::Promise> DurableObjectStorageOperations::getMultiple( - jsg::Lock& js, - kj::Array keys, - const GetOptions& options) { + jsg::Lock& js, kj::Array keys, const GetOptions& options) { ActorStorageLimits::checkMaxPairsCount(keys.size()); auto numKeys = keys.size(); - return transformCacheResult(js, getCache(OP_GET).get(kj::mv(keys), options), - options, getMultipleResultsToMap(numKeys)); + return transformCacheResult( + js, getCache(OP_GET).get(kj::mv(keys), options), options, getMultipleResultsToMap(numKeys)); } jsg::Promise DurableObjectStorageOperations::putMultiple( - jsg::Lock& js, - jsg::Dict entries, - const PutOptions& options) { + jsg::Lock& js, jsg::Dict entries, const PutOptions& options) { kj::Vector kvs(entries.fields.size()); uint32_t units = 0; - for (auto& field : entries.fields) { + for (auto& field: entries.fields) { if (field.value.isUndefined()) continue; // We silently drop fields with value=undefined in putMultiple. There aren't many good options here, as // deleting an undefined field is confusing, throwing could break otherwise working code, and @@ -586,11 +560,11 @@ jsg::Promise DurableObjectStorageOperations::putMultiple( units += billingUnits(field.name.size() + buffer.size()); - kvs.add(ActorCacheOps::KeyValuePair { kj::mv(field.name), kj::mv(buffer) }); + kvs.add(ActorCacheOps::KeyValuePair{kj::mv(field.name), kj::mv(buffer)}); } - jsg::Promise maybeBackpressure = transformMaybeBackpressure(js, options, - getCache(OP_PUT).put(kvs.releaseAsArray(), options)); + jsg::Promise maybeBackpressure = + transformMaybeBackpressure(js, options, getCache(OP_PUT).put(kvs.releaseAsArray(), options)); auto& context = IoContext::current(); context.addTask(updateStorageWriteUnit(context, currentActorMetrics(), units)); @@ -618,8 +592,8 @@ ActorCacheOps& DurableObjectStorage::getCache(OpName op) { } jsg::Promise> DurableObjectStorage::transaction(jsg::Lock& js, - jsg::Function>( - jsg::Ref)> callback, + jsg::Function>(jsg::Ref)> + callback, jsg::Optional options) { auto& context = IoContext::current(); @@ -628,9 +602,10 @@ jsg::Promise> DurableObjectStorage::transaction(jsg::Lo bool isError; }; - return context.blockConcurrencyWhile(js, - [callback = kj::mv(callback), &context, &cache = *cache] - (jsg::Lock& js) mutable -> jsg::Promise { + return context + .blockConcurrencyWhile(js, + [callback = kj::mv(callback), &context, &cache = *cache]( + jsg::Lock& js) mutable -> jsg::Promise { // Note that the call to `startTransaction()` is when the SQLite-backed implementation will // actually invoke `BEGIN TRANSACTION`, so it's important that we're inside the // blockConcurrencyWhile block before that point so we don't accidentally catch some other @@ -651,19 +626,16 @@ jsg::Promise> DurableObjectStorage::transaction(jsg::Lo // IoContext::current() again here, rather than capture it in the lambda. auto& context = IoContext::current(); return context.awaitIoWithInputLock(js, txn->maybeCommit(), - [value = kj::mv(value)](jsg::Lock&) mutable { - return TxnResult { kj::mv(value), false }; - }); + [value = kj::mv(value)](jsg::Lock&) mutable { return TxnResult{kj::mv(value), false}; }); }, [txn = txn.addRef()](jsg::Lock& js, jsg::Value exception) mutable { // The transaction callback threw an exception. We don't actually want to reset the object, // we only want to roll back the transaction and propagate the exception. So, we carefully // pack the exception away into a value. txn->maybeRollback(); - return js.resolvedPromise(TxnResult { + return js.resolvedPromise(TxnResult{ // TODO(cleanup): Simplify this once exception is passed using jsg::JsRef instead // of jsg::V8Ref - jsg::JsValue(exception.getHandle(js)).addRef(js), true - }); + jsg::JsValue(exception.getHandle(js)).addRef(js), true}); }); }).then(js, [](jsg::Lock& js, TxnResult result) -> jsg::JsRef { if (result.isError) { @@ -675,8 +647,7 @@ jsg::Promise> DurableObjectStorage::transaction(jsg::Lo } jsg::JsRef DurableObjectStorage::transactionSync( - jsg::Lock& js, - jsg::Function()> callback) { + jsg::Lock& js, jsg::Function()> callback) { KJ_IF_SOME(sqlite, cache->getSqliteDatabase()) { // SAVEPOINT is a readonly statement, but we need to trigger an outer TRANSACTION sqlite.notifyWrite(); @@ -738,13 +709,13 @@ ActorCacheOps& DurableObjectTransaction::getCache(OpName op) { JSG_REQUIRE(!rolledBack, Error, kj::str("Cannot ", op, " on rolled back transaction")); auto& result = *JSG_REQUIRE_NONNULL(cacheTxn, Error, kj::str("Cannot call ", op, - " on transaction that has already committed: did you move `txn` outside of the closure?")); + " on transaction that has already committed: did you move `txn` outside of the closure?")); return result; } void DurableObjectTransaction::rollback() { if (rolledBack) return; // allow multiple calls to rollback() - getCache(OP_ROLLBACK); // just for the checks + getCache(OP_ROLLBACK); // just for the checks KJ_IF_SOME(t, cacheTxn) { auto prom = t->rollback(); IoContext::current().addWaitUntil(kj::mv(prom).attach(kj::mv(cacheTxn))); @@ -771,8 +742,8 @@ void DurableObjectTransaction::maybeRollback() { } ActorState::ActorState(Worker::Actor::Id actorId, - kj::Maybe> transient, - kj::Maybe> persistent) + kj::Maybe> transient, + kj::Maybe> persistent) : id(kj::mv(actorId)), transient(kj::mv(transient)), persistent(kj::mv(persistent)) {} @@ -789,9 +760,10 @@ kj::OneOf, kj::StringPtr> ActorState::getId() { KJ_UNREACHABLE; } -DurableObjectState::DurableObjectState(Worker::Actor::Id actorId, - kj::Maybe> storage) - : id(kj::mv(actorId)), storage(kj::mv(storage)) {} +DurableObjectState::DurableObjectState( + Worker::Actor::Id actorId, kj::Maybe> storage) + : id(kj::mv(actorId)), + storage(kj::mv(storage)) {} void DurableObjectState::waitUntil(kj::Promise promise) { IoContext::current().addWaitUntil(kj::mv(promise)); @@ -809,17 +781,18 @@ kj::OneOf, kj::StringPtr> DurableObjectState::getId() KJ_UNREACHABLE; } -jsg::Promise> DurableObjectState::blockConcurrencyWhile(jsg::Lock& js, - jsg::Function>()> callback) { +jsg::Promise> DurableObjectState::blockConcurrencyWhile( + jsg::Lock& js, jsg::Function>()> callback) { return IoContext::current().blockConcurrencyWhile(js, kj::mv(callback)); } void DurableObjectState::abort(jsg::Optional reason) { - kj::String description = kj::mv(reason).map([](kj::String&& text) { + kj::String description = kj::mv(reason) + .map([](kj::String&& text) { return kj::str("broken.outputGateBroken; jsg.Error: ", text); }).orDefault([]() { return kj::str("broken.outputGateBroken; jsg.Error: Application called abort() to reset " - "Durable Object."); + "Durable Object."); }); kj::Exception error(kj::Exception::Type::FAILED, __FILE__, __LINE__, kj::mv(description)); @@ -835,7 +808,8 @@ void DurableObjectState::abort(jsg::Optional reason) { kj::throwFatalException(kj::mv(error)); } -Worker::Actor::HibernationManager& DurableObjectState::maybeInitHibernationManager(Worker::Actor& actor) { +Worker::Actor::HibernationManager& DurableObjectState::maybeInitHibernationManager( + Worker::Actor& actor) { if (actor.getHibernationManager() == kj::none) { // If there's no hibernation manager created yet, we should create one. actor.setHibernationManager(kj::refcounted( @@ -845,12 +819,11 @@ Worker::Actor::HibernationManager& DurableObjectState::maybeInitHibernationManag } void DurableObjectState::acceptWebSocket( - jsg::Ref ws, - jsg::Optional> tags) { + jsg::Ref ws, jsg::Optional> tags) { JSG_ASSERT(!ws->isAccepted(), Error, "Cannot call `acceptWebSocket()` if the WebSocket was already accepted via `accept()`"); JSG_ASSERT(ws->peerIsAwaitingCoupling(), Error, - "Cannot call `acceptWebSocket()` on this WebSocket because its pair has already been "\ + "Cannot call `acceptWebSocket()` on this WebSocket because its pair has already been " "accepted or used in a Response."); // We need to get a HibernationManager to give the websocket to. @@ -865,8 +838,7 @@ void DurableObjectState::acceptWebSocket( for (auto tag = t.begin(); tag < t.end(); tag++) { JSG_REQUIRE(distinctTagCount < MAX_TAGS_PER_CONNECTION, Error, "a Hibernatable WebSocket cannot have more than ", MAX_TAGS_PER_CONNECTION, " tags"); - JSG_REQUIRE(tag->size() <= MAX_TAG_LENGTH, Error, - "\"", *tag, "\" ", + JSG_REQUIRE(tag->size() <= MAX_TAG_LENGTH, Error, "\"", *tag, "\" ", "is longer than the max tag length (", MAX_TAG_LENGTH, " characters)."); if (!seen.contains(*tag)) { seen.insert(kj::mv(*tag)); @@ -882,18 +854,16 @@ void DurableObjectState::acceptWebSocket( } kj::Array> DurableObjectState::getWebSockets( - jsg::Lock& js, - jsg::Optional tag) { + jsg::Lock& js, jsg::Optional tag) { auto& a = KJ_REQUIRE_NONNULL(IoContext::current().getActor()); KJ_IF_SOME(manager, a.getHibernationManager()) { - return manager.getWebSockets( - js, tag.map([](kj::StringPtr t) { return t; })).releaseAsArray(); + return manager.getWebSockets(js, tag.map([](kj::StringPtr t) { return t; })).releaseAsArray(); } return kj::Array>(); } void DurableObjectState::setWebSocketAutoResponse( - jsg::Optional> maybeReqResp) { + jsg::Optional> maybeReqResp) { auto& a = KJ_REQUIRE_NONNULL(IoContext::current().getActor()); if (maybeReqResp == kj::none) { @@ -908,19 +878,20 @@ void DurableObjectState::setWebSocketAutoResponse( auto reqResp = KJ_REQUIRE_NONNULL(kj::mv(maybeReqResp)); auto maxRequestOrResponseSize = 2048; - JSG_REQUIRE(reqResp->getRequest().size() <= maxRequestOrResponseSize, RangeError, kj::str( - "Request cannot be larger than ", maxRequestOrResponseSize, " bytes. ", - "A request of size ", reqResp->getRequest().size(), " was provided.")); + JSG_REQUIRE(reqResp->getRequest().size() <= maxRequestOrResponseSize, RangeError, + kj::str("Request cannot be larger than ", maxRequestOrResponseSize, " bytes. ", + "A request of size ", reqResp->getRequest().size(), " was provided.")); - JSG_REQUIRE(reqResp->getResponse().size() <= maxRequestOrResponseSize, RangeError, kj::str( - "Response cannot be larger than ", maxRequestOrResponseSize, " bytes. ", - "A response of size ", reqResp->getResponse().size(), " was provided.")); + JSG_REQUIRE(reqResp->getResponse().size() <= maxRequestOrResponseSize, RangeError, + kj::str("Response cannot be larger than ", maxRequestOrResponseSize, " bytes. ", + "A response of size ", reqResp->getResponse().size(), " was provided.")); - maybeInitHibernationManager(a).setWebSocketAutoResponse(reqResp->getRequest(), - reqResp->getResponse()); + maybeInitHibernationManager(a).setWebSocketAutoResponse( + reqResp->getRequest(), reqResp->getResponse()); } -kj::Maybe> DurableObjectState::getWebSocketAutoResponse() { +kj::Maybe> DurableObjectState:: + getWebSocketAutoResponse() { auto& a = KJ_REQUIRE_NONNULL(IoContext::current().getActor()); KJ_IF_SOME(manager, a.getHibernationManager()) { // If there's no hibernation manager created yet, there's nothing to do here. @@ -967,18 +938,18 @@ kj::Array DurableObjectState::getTags(jsg::Lock& js, jsg::Ref serializeV8Value(jsg::Lock& js, const jsg::JsValue& value) { - jsg::Serializer serializer(js, jsg::Serializer::Options { - .version = 15, - .omitHeader = false, - }); + jsg::Serializer serializer(js, + jsg::Serializer::Options{ + .version = 15, + .omitHeader = false, + }); serializer.write(js, value); auto released = serializer.release(); return kj::mv(released.data); } -jsg::JsValue deserializeV8Value(jsg::Lock& js, - kj::ArrayPtr key, - kj::ArrayPtr buf) { +jsg::JsValue deserializeV8Value( + jsg::Lock& js, kj::ArrayPtr key, kj::ArrayPtr buf) { KJ_ASSERT(buf.size() > 0, "unexpectedly empty value buffer", key); try { @@ -987,7 +958,7 @@ jsg::JsValue deserializeV8Value(jsg::Lock& js, // terminal for the isolate, causing exception to be rethrown, in which case // we throw a kj::Exception wrapping a jsg.Error. return js.tryCatch([&]() -> jsg::JsValue { - jsg::Deserializer::Options options {}; + jsg::Deserializer::Options options{}; if (buf[0] != 0xFF) { // When Durable Objects was first released, it did not properly write headers when serializing // to storage. If we find that the header is missing (as indicated by the first byte not being @@ -1007,18 +978,18 @@ jsg::JsValue deserializeV8Value(jsg::Lock& js, // length of the value, and the first three bytes of the value (which is just the v8-internal // version header and the tag that indicates the type of the value, but not its contents). kj::String actorId = getCurrentActorId().orDefault([]() { return kj::str(); }); - KJ_FAIL_ASSERT("actor storage deserialization failed", - "failed to deserialize stored value", - actorId, exception.getHandle(js), key, buf.size(), - buf.slice(0, std::min(static_cast(3), buf.size()))); + KJ_FAIL_ASSERT("actor storage deserialization failed", "failed to deserialize stored value", + actorId, exception.getHandle(js), key, buf.size(), + buf.slice(0, std::min(static_cast(3), buf.size()))); }); } catch (jsg::JsExceptionThrown&) { // We can occasionally hit an isolate termination here -- we prefix the error with jsg to avoid // counting it against our internal storage error metrics but also throw a KJ exception rather // than a jsExceptionThrown error to avoid confusing the normal termination handling code. // We don't expect users to ever actually see this error. - JSG_FAIL_REQUIRE(Error, "isolate terminated while deserializing value from Durable Object " - "storage; contact us if you're wondering why you're seeing this"); + JSG_FAIL_REQUIRE(Error, + "isolate terminated while deserializing value from Durable Object " + "storage; contact us if you're wondering why you're seeing this"); } } diff --git a/src/workerd/api/actor-state.h b/src/workerd/api/actor-state.h index 0e21628ae0b..e3352893a5f 100644 --- a/src/workerd/api/actor-state.h +++ b/src/workerd/api/actor-state.h @@ -34,17 +34,14 @@ class DurableObjectStorageOperations { jsg::Optional noCache; inline operator ActorCacheOps::ReadOptions() const { - return { - .noCache = noCache.orDefault(false) - }; + return {.noCache = noCache.orDefault(false)}; } JSG_STRUCT(allowConcurrency, noCache); - JSG_STRUCT_TS_OVERRIDE(DurableObjectGetOptions); // Rename from DurableObjectStorageOperationsGetOptions + JSG_STRUCT_TS_OVERRIDE(DurableObjectGetOptions); // Rename from DurableObjectStorageOperationsGetOptions }; - jsg::Promise> get( - jsg::Lock& js, + jsg::Promise> get(jsg::Lock& js, kj::OneOf> keys, jsg::Optional options); @@ -52,7 +49,7 @@ class DurableObjectStorageOperations { jsg::Optional allowConcurrency; JSG_STRUCT(allowConcurrency); - JSG_STRUCT_TS_OVERRIDE(DurableObjectGetAlarmOptions); // Rename from DurableObjectStorageOperationsGetAlarmOptions + JSG_STRUCT_TS_OVERRIDE(DurableObjectGetAlarmOptions); // Rename from DurableObjectStorageOperationsGetAlarmOptions }; jsg::Promise> getAlarm(jsg::Lock& js, jsg::Optional options); @@ -69,13 +66,11 @@ class DurableObjectStorageOperations { jsg::Optional noCache; inline operator ActorCacheOps::ReadOptions() const { - return { - .noCache = noCache.orDefault(false) - }; + return {.noCache = noCache.orDefault(false)}; } JSG_STRUCT(start, startAfter, end, prefix, reverse, limit, allowConcurrency, noCache); - JSG_STRUCT_TS_OVERRIDE(DurableObjectListOptions); // Rename from DurableObjectStorageOperationsListOptions + JSG_STRUCT_TS_OVERRIDE(DurableObjectListOptions); // Rename from DurableObjectStorageOperationsListOptions }; jsg::Promise> list(jsg::Lock& js, jsg::Optional options); @@ -87,23 +82,20 @@ class DurableObjectStorageOperations { inline operator ActorCacheOps::WriteOptions() const { return { - .allowUnconfirmed = allowUnconfirmed.orDefault(false), - .noCache = noCache.orDefault(false) - }; + .allowUnconfirmed = allowUnconfirmed.orDefault(false), .noCache = noCache.orDefault(false)}; } JSG_STRUCT(allowConcurrency, allowUnconfirmed, noCache); - JSG_STRUCT_TS_OVERRIDE(DurableObjectPutOptions); // Rename from DurableObjectStorageOperationsPutOptions + JSG_STRUCT_TS_OVERRIDE(DurableObjectPutOptions); // Rename from DurableObjectStorageOperationsPutOptions }; jsg::Promise put(jsg::Lock& js, - kj::OneOf> keyOrEntries, - jsg::Optional value, - jsg::Optional options, - const jsg::TypeHandler& optionsTypeHandler); + kj::OneOf> keyOrEntries, + jsg::Optional value, + jsg::Optional options, + const jsg::TypeHandler& optionsTypeHandler); - kj::OneOf, jsg::Promise> delete_( - jsg::Lock& js, + kj::OneOf, jsg::Promise> delete_(jsg::Lock& js, kj::OneOf> keys, jsg::Optional options); @@ -119,12 +111,11 @@ class DurableObjectStorageOperations { } JSG_STRUCT(allowConcurrency, allowUnconfirmed); - JSG_STRUCT_TS_OVERRIDE(DurableObjectSetAlarmOptions); // Rename from DurableObjectStorageOperationsSetAlarmOptions + JSG_STRUCT_TS_OVERRIDE(DurableObjectSetAlarmOptions); // Rename from DurableObjectStorageOperationsSetAlarmOptions }; - jsg::Promise setAlarm(jsg::Lock& js, - kj::Date scheduledTime, - jsg::Optional options); + jsg::Promise setAlarm( + jsg::Lock& js, kj::Date scheduledTime, jsg::Optional options); jsg::Promise deleteAlarm(jsg::Lock& js, jsg::Optional options); protected: @@ -160,34 +151,30 @@ class DurableObjectStorageOperations { } private: - jsg::Promise> getOne(jsg::Lock& js, - kj::String key, - const GetOptions& options); - jsg::Promise> getMultiple(jsg::Lock& js, - kj::Array keys, - const GetOptions& options); - - jsg::Promise putOne(jsg::Lock& js, - kj::String key, - jsg::JsValue value, - const PutOptions& options); - jsg::Promise putMultiple(jsg::Lock& js, jsg::Dict entries, - const PutOptions& options); + jsg::Promise> getOne( + jsg::Lock& js, kj::String key, const GetOptions& options); + jsg::Promise> getMultiple( + jsg::Lock& js, kj::Array keys, const GetOptions& options); + + jsg::Promise putOne( + jsg::Lock& js, kj::String key, jsg::JsValue value, const PutOptions& options); + jsg::Promise putMultiple( + jsg::Lock& js, jsg::Dict entries, const PutOptions& options); jsg::Promise deleteOne(jsg::Lock& js, kj::String key, const PutOptions& options); - jsg::Promise deleteMultiple(jsg::Lock& js, - kj::Array keys, - const PutOptions& options); + jsg::Promise deleteMultiple( + jsg::Lock& js, kj::Array keys, const PutOptions& options); }; class DurableObjectTransaction; class DurableObjectStorage: public jsg::Object, public DurableObjectStorageOperations { public: - DurableObjectStorage(IoPtr cache) - : cache(kj::mv(cache)) {} + DurableObjectStorage(IoPtr cache): cache(kj::mv(cache)) {} - ActorCacheInterface& getActorCacheInterface() { return *cache; } + ActorCacheInterface& getActorCacheInterface() { + return *cache; + } struct TransactionOptions { jsg::Optional asOfTime; @@ -198,15 +185,13 @@ class DurableObjectStorage: public jsg::Object, public DurableObjectStorageOpera // Omit from definitions }; - jsg::Promise> transaction( - jsg::Lock& js, - jsg::Function>( - jsg::Ref)> closure, + jsg::Promise> transaction(jsg::Lock& js, + jsg::Function>(jsg::Ref)> + closure, jsg::Optional options); jsg::JsRef transactionSync( - jsg::Lock& js, - jsg::Function()> callback); + jsg::Lock& js, jsg::Function()> callback); jsg::Promise deleteAll(jsg::Lock& js, jsg::Optional options); @@ -287,7 +272,7 @@ class DurableObjectStorage: public jsg::Object, public DurableObjectStorageOpera class DurableObjectTransaction final: public jsg::Object, public DurableObjectStorageOperations { public: DurableObjectTransaction(IoOwn cacheTxn) - : cacheTxn(kj::mv(cacheTxn)) {} + : cacheTxn(kj::mv(cacheTxn)) {} // Called from C++, not JS, after the transaction callback has completed (successfully or not). // These methods do nothing if the transaction is already committed / rolled back. @@ -352,8 +337,8 @@ class ActorState: public jsg::Object { // TODO(cleanup): Remove getPersistent method that isn't supported for colo-local actors anymore. public: ActorState(Worker::Actor::Id actorId, - kj::Maybe> transient, - kj::Maybe> persistent); + kj::Maybe> transient, + kj::Maybe> persistent); kj::OneOf, kj::StringPtr> getId(); @@ -397,14 +382,20 @@ class ActorState: public jsg::Object { class WebSocketRequestResponsePair: public jsg::Object { public: WebSocketRequestResponsePair(kj::String request, kj::String response) - : request(kj::mv(request)), response(kj::mv(response)) {}; + : request(kj::mv(request)), + response(kj::mv(response)) {}; - static jsg::Ref constructor(kj::String request, kj::String response) { - return jsg::alloc(kj::mv(request),kj::mv(response)); + static jsg::Ref constructor( + kj::String request, kj::String response) { + return jsg::alloc(kj::mv(request), kj::mv(response)); }; - kj::StringPtr getRequest() { return request.asPtr(); } - kj::StringPtr getResponse() { return response.asPtr(); } + kj::StringPtr getRequest() { + return request.asPtr(); + } + kj::StringPtr getResponse() { + return response.asPtr(); + } JSG_RESOURCE_TYPE(WebSocketRequestResponsePair) { JSG_READONLY_PROTOTYPE_PROPERTY(request, getRequest); @@ -435,8 +426,7 @@ class DurableObjectState: public jsg::Object { } jsg::Promise> blockConcurrencyWhile( - jsg::Lock& js, - jsg::Function>()> callback); + jsg::Lock& js, jsg::Function>()> callback); // Reset the object, including breaking the output gate and canceling any writes that haven't // been committed yet. @@ -475,7 +465,8 @@ class DurableObjectState: public jsg::Object { // reply to the request with the matching response, then store the timestamp at which // the request was received. // If maybeReqResp is not set, we consider it as unset and remove any set request response pair. - void setWebSocketAutoResponse(jsg::Optional> maybeReqResp); + void setWebSocketAutoResponse( + jsg::Optional> maybeReqResp); // Gets the currently set object-wide websocket auto response. kj::Maybe> getWebSocketAutoResponse(); @@ -548,17 +539,13 @@ class DurableObjectState: public jsg::Object { const size_t MAX_TAG_LENGTH = 256; }; -#define EW_ACTOR_STATE_ISOLATE_TYPES \ - api::ActorState, \ - api::DurableObjectState, \ - api::DurableObjectTransaction, \ - api::DurableObjectStorage, \ - api::DurableObjectStorage::TransactionOptions, \ - api::DurableObjectStorageOperations::ListOptions, \ - api::DurableObjectStorageOperations::GetOptions, \ - api::DurableObjectStorageOperations::GetAlarmOptions, \ - api::DurableObjectStorageOperations::PutOptions, \ - api::DurableObjectStorageOperations::SetAlarmOptions, \ - api::WebSocketRequestResponsePair +#define EW_ACTOR_STATE_ISOLATE_TYPES \ + api::ActorState, api::DurableObjectState, api::DurableObjectTransaction, \ + api::DurableObjectStorage, api::DurableObjectStorage::TransactionOptions, \ + api::DurableObjectStorageOperations::ListOptions, \ + api::DurableObjectStorageOperations::GetOptions, \ + api::DurableObjectStorageOperations::GetAlarmOptions, \ + api::DurableObjectStorageOperations::PutOptions, \ + api::DurableObjectStorageOperations::SetAlarmOptions, api::WebSocketRequestResponsePair } // namespace workerd::api diff --git a/src/workerd/api/actor.c++ b/src/workerd/api/actor.c++ index d96520751df..66f799f3ba8 100644 --- a/src/workerd/api/actor.c++ +++ b/src/workerd/api/actor.c++ @@ -17,8 +17,8 @@ namespace workerd::api { class LocalActorOutgoingFactory final: public Fetcher::OutgoingFactory { public: LocalActorOutgoingFactory(uint channelId, kj::String actorId) - : channelId(channelId), - actorId(kj::mv(actorId)) {} + : channelId(channelId), + actorId(kj::mv(actorId)) {} kj::Own newSingleUseClient(kj::Maybe cfStr) override { auto& context = IoContext::current(); @@ -34,15 +34,12 @@ public: actorChannel = context.getColoLocalActorChannel(channelId, actorId, span); } - return KJ_REQUIRE_NONNULL(actorChannel)->startRequest({ - .cfBlobJson = kj::mv(cfStr), - .parentSpan = span - }); - }, { - .inHouse = true, - .wrapMetrics = true, - .operationName = kj::ConstString("actor_subrequest"_kjc) - })); + return KJ_REQUIRE_NONNULL(actorChannel) + ->startRequest({.cfBlobJson = kj::mv(cfStr), .parentSpan = span}); + }, + {.inHouse = true, + .wrapMetrics = true, + .operationName = kj::ConstString("actor_subrequest"_kjc)})); } private: @@ -53,15 +50,14 @@ private: class GlobalActorOutgoingFactory final: public Fetcher::OutgoingFactory { public: - GlobalActorOutgoingFactory( - uint channelId, + GlobalActorOutgoingFactory(uint channelId, jsg::Ref id, kj::Maybe locationHint, ActorGetMode mode) - : channelId(channelId), - id(kj::mv(id)), - locationHint(kj::mv(locationHint)), - mode(mode) {} + : channelId(channelId), + id(kj::mv(id)), + locationHint(kj::mv(locationHint)), + mode(mode) {} kj::Own newSingleUseClient(kj::Maybe cfStr) override { auto& context = IoContext::current(); @@ -74,19 +70,16 @@ public: // Lazily initialize actorChannel if (actorChannel == kj::none) { - actorChannel = context.getGlobalActorChannel(channelId, id->getInner(), kj::mv(locationHint), - mode, span); + actorChannel = context.getGlobalActorChannel( + channelId, id->getInner(), kj::mv(locationHint), mode, span); } - return KJ_REQUIRE_NONNULL(actorChannel)->startRequest({ - .cfBlobJson = kj::mv(cfStr), - .parentSpan = span - }); - }, { - .inHouse = true, - .wrapMetrics = true, - .operationName = kj::ConstString("actor_subrequest"_kjc) - })); + return KJ_REQUIRE_NONNULL(actorChannel) + ->startRequest({.cfBlobJson = kj::mv(cfStr), .parentSpan = span}); + }, + {.inHouse = true, + .wrapMetrics = true, + .operationName = kj::ConstString("actor_subrequest"_kjc)})); } private: @@ -103,8 +96,8 @@ jsg::Ref ColoLocalActorNamespace::get(kj::String actorId) { auto& context = IoContext::current(); - kj::Own factory = kj::heap( - channel, kj::mv(actorId)); + kj::Own factory = + kj::heap(channel, kj::mv(actorId)); auto outgoingFactory = context.addObject(kj::mv(factory)); bool isInHouse = true; @@ -132,21 +125,16 @@ jsg::Ref DurableObjectNamespace::idFromString(kj::String id) { } jsg::Ref DurableObjectNamespace::get( - jsg::Lock& js, - jsg::Ref id, - jsg::Optional options) { + jsg::Lock& js, jsg::Ref id, jsg::Optional options) { return getImpl(js, ActorGetMode::GET_OR_CREATE, kj::mv(id), kj::mv(options)); } jsg::Ref DurableObjectNamespace::getExisting( - jsg::Lock& js, - jsg::Ref id, - jsg::Optional options) { + jsg::Lock& js, jsg::Ref id, jsg::Optional options) { return getImpl(js, ActorGetMode::GET_EXISTING, kj::mv(id), kj::mv(options)); } -jsg::Ref DurableObjectNamespace::getImpl( - jsg::Lock& js, +jsg::Ref DurableObjectNamespace::getImpl(jsg::Lock& js, ActorGetMode mode, jsg::Ref id, jsg::Optional options) { @@ -168,8 +156,8 @@ jsg::Ref DurableObjectNamespace::getImpl( } jsg::Ref DurableObjectNamespace::jurisdiction(kj::String jurisdiction) { - return jsg::alloc(channel, - idFactory->cloneWithJurisdiction(jurisdiction)); + return jsg::alloc( + channel, idFactory->cloneWithJurisdiction(jurisdiction)); } } // namespace workerd::api diff --git a/src/workerd/api/actor.h b/src/workerd/api/actor.h index e101d87a01d..569e1e83daf 100644 --- a/src/workerd/api/actor.h +++ b/src/workerd/api/actor.h @@ -17,7 +17,8 @@ #include namespace workerd { - template class IoOwn; +template +class IoOwn; } namespace workerd::api { @@ -25,8 +26,7 @@ namespace workerd::api { // A capability to an ephemeral Actor namespace. class ColoLocalActorNamespace: public jsg::Object { public: - ColoLocalActorNamespace(uint channel) - : channel(channel) {} + ColoLocalActorNamespace(uint channel): channel(channel) {} jsg::Ref get(kj::String actorId); @@ -45,7 +45,9 @@ class DurableObjectId: public jsg::Object { public: DurableObjectId(kj::Own id): id(kj::mv(id)) {} - const ActorIdFactory::ActorId& getInner() { return *id; } + const ActorIdFactory::ActorId& getInner() { + return *id; + } // --------------------------------------------------------------------------- // JS API @@ -53,10 +55,14 @@ class DurableObjectId: public jsg::Object { // Converts to a string which can be passed back to the constructor to reproduce the same ID. kj::String toString(); - inline bool equals(DurableObjectId& other) { return id->equals(*other.id); } + inline bool equals(DurableObjectId& other) { + return id->equals(*other.id); + } // Get the name, if known. - inline jsg::Optional getName() { return id->getName(); } + inline jsg::Optional getName() { + return id->getName(); + } JSG_RESOURCE_TYPE(DurableObjectId) { JSG_METHOD(toString); @@ -78,13 +84,18 @@ class DurableObjectId: public jsg::Object { class DurableObject final: public Fetcher { public: - DurableObject(jsg::Ref id, IoOwn outgoingFactory, - RequiresHostAndProtocol requiresHost) - : Fetcher(kj::mv(outgoingFactory), requiresHost, true /* isInHouse */), - id(kj::mv(id)) {} - - jsg::Ref getId() { return id.addRef(); }; - jsg::Optional getName() { return id->getName(); } + DurableObject(jsg::Ref id, + IoOwn outgoingFactory, + RequiresHostAndProtocol requiresHost) + : Fetcher(kj::mv(outgoingFactory), requiresHost, true /* isInHouse */), + id(kj::mv(id)) {} + + jsg::Ref getId() { + return id.addRef(); + }; + jsg::Optional getName() { + return id->getName(); + } JSG_RESOURCE_TYPE(DurableObject) { JSG_INHERIT(Fetcher); @@ -128,10 +139,11 @@ class DurableObjectNamespace: public jsg::Object { public: DurableObjectNamespace(uint channel, kj::Own idFactory) - : channel(channel), idFactory(kj::mv(idFactory)) {} + : channel(channel), + idFactory(kj::mv(idFactory)) {} struct NewUniqueIdOptions { - // Restricts the new unique ID to a set of colos within a jurisdiction. + // Restricts the new unique ID to a set of colos within a jurisdiction. jsg::Optional jurisdiction; JSG_STRUCT(jurisdiction); @@ -171,16 +183,12 @@ class DurableObjectNamespace: public jsg::Object { // Gets a durable object by ID or creates it if it doesn't already exist. jsg::Ref get( - jsg::Lock& js, - jsg::Ref id, - jsg::Optional options); + jsg::Lock& js, jsg::Ref id, jsg::Optional options); // Experimental. Gets a durable object by ID if it already exists. Currently, gated for use // by cloudflare only. jsg::Ref getExisting( - jsg::Lock& js, - jsg::Ref id, - jsg::Optional options); + jsg::Lock& js, jsg::Ref id, jsg::Optional options); // Creates a subnamespace with the jurisdiction hardcoded. jsg::Ref jurisdiction(kj::String jurisdiction); @@ -214,19 +222,15 @@ class DurableObjectNamespace: public jsg::Object { uint channel; kj::Own idFactory; - jsg::Ref getImpl( - jsg::Lock& js, + jsg::Ref getImpl(jsg::Lock& js, ActorGetMode mode, jsg::Ref id, jsg::Optional options); }; -#define EW_ACTOR_ISOLATE_TYPES \ - api::ColoLocalActorNamespace, \ - api::DurableObject, \ - api::DurableObjectId, \ - api::DurableObjectNamespace, \ - api::DurableObjectNamespace::NewUniqueIdOptions, \ - api::DurableObjectNamespace::GetDurableObjectOptions +#define EW_ACTOR_ISOLATE_TYPES \ + api::ColoLocalActorNamespace, api::DurableObject, api::DurableObjectId, \ + api::DurableObjectNamespace, api::DurableObjectNamespace::NewUniqueIdOptions, \ + api::DurableObjectNamespace::GetDurableObjectOptions } // namespace workerd::api diff --git a/src/workerd/api/analytics-engine-impl.h b/src/workerd/api/analytics-engine-impl.h index 7e9a75ea3a1..52dabce5457 100644 --- a/src/workerd/api/analytics-engine-impl.h +++ b/src/workerd/api/analytics-engine-impl.h @@ -14,10 +14,9 @@ constexpr uint MAX_ARRAY_MEMBERS = 20; constexpr size_t MAX_CUMULATIVE_BYTES_IN_BLOBS = 256 * MAX_ARRAY_MEMBERS; template -void setDoubles(Message msg, kj::ArrayPtr arr, - kj::StringPtr errorPrefix) { - JSG_REQUIRE(arr.size() <= MAX_ARRAY_MEMBERS, TypeError, errorPrefix, - "Maximum of ", MAX_ARRAY_MEMBERS, " doubles supported."); +void setDoubles(Message msg, kj::ArrayPtr arr, kj::StringPtr errorPrefix) { + JSG_REQUIRE(arr.size() <= MAX_ARRAY_MEMBERS, TypeError, errorPrefix, "Maximum of ", + MAX_ARRAY_MEMBERS, " doubles supported."); uint index = 1; for (auto& item: arr) { @@ -88,12 +87,11 @@ void setDoubles(Message msg, kj::ArrayPtr arr, } template -void setBlobs( - Message msg, +void setBlobs(Message msg, kj::ArrayPtr, kj::String>>> arr, kj::StringPtr errorPrefix) { - JSG_REQUIRE(arr.size() <= MAX_ARRAY_MEMBERS, TypeError, errorPrefix, - "Maximum of ", MAX_ARRAY_MEMBERS, " blobs supported."); + JSG_REQUIRE(arr.size() <= MAX_ARRAY_MEMBERS, TypeError, errorPrefix, "Maximum of ", + MAX_ARRAY_MEMBERS, " blobs supported."); kj::ArrayPtr value; uint index = 1; size_t sizeSum = 0; @@ -108,9 +106,8 @@ void setBlobs( } } sizeSum += value.size(); - JSG_REQUIRE(sizeSum <= MAX_CUMULATIVE_BYTES_IN_BLOBS, TypeError, - errorPrefix, "Cumulative size of blobs exceeds ", - MAX_CUMULATIVE_BYTES_IN_BLOBS, " bytes)."); + JSG_REQUIRE(sizeSum <= MAX_CUMULATIVE_BYTES_IN_BLOBS, TypeError, errorPrefix, + "Cumulative size of blobs exceeds ", MAX_CUMULATIVE_BYTES_IN_BLOBS, " bytes)."); switch (index) { case 1: msg.setBlob1(value); @@ -179,12 +176,11 @@ void setBlobs( } template -void setIndexes( - Message msg, +void setIndexes(Message msg, kj::ArrayPtr, kj::String>>> arr, kj::StringPtr errorPrefix) { - JSG_REQUIRE(arr.size() <= MAX_INDEXES_LENGTH, TypeError, errorPrefix, - "Maximum of ", MAX_INDEXES_LENGTH, " indexes supported."); + JSG_REQUIRE(arr.size() <= MAX_INDEXES_LENGTH, TypeError, errorPrefix, "Maximum of ", + MAX_INDEXES_LENGTH, " indexes supported."); if (arr.size() == 0) { return; } @@ -199,9 +195,8 @@ void setIndexes( value = val.asBytes(); } } - JSG_REQUIRE(value.size() <= MAX_INDEX_SIZE_IN_BYTES, TypeError, - errorPrefix, "Size of indexes[0] exceeds ", - MAX_INDEX_SIZE_IN_BYTES, " bytes)."); + JSG_REQUIRE(value.size() <= MAX_INDEX_SIZE_IN_BYTES, TypeError, errorPrefix, + "Size of indexes[0] exceeds ", MAX_INDEX_SIZE_IN_BYTES, " bytes)."); msg.setIndex1(value); } } diff --git a/src/workerd/api/analytics-engine.c++ b/src/workerd/api/analytics-engine.c++ index 9778f7415ea..d7508a7eba9 100644 --- a/src/workerd/api/analytics-engine.c++ +++ b/src/workerd/api/analytics-engine.c++ @@ -7,8 +7,8 @@ namespace workerd::api { -void AnalyticsEngine::writeDataPoint(jsg::Lock& js, - jsg::Optional event) { +void AnalyticsEngine::writeDataPoint( + jsg::Lock& js, jsg::Optional event) { auto& context = IoContext::current(); context.getLimitEnforcer().newAnalyticsEngineRequest(); diff --git a/src/workerd/api/analytics-engine.h b/src/workerd/api/analytics-engine.h index 318d22b55d5..83ec16adb09 100644 --- a/src/workerd/api/analytics-engine.h +++ b/src/workerd/api/analytics-engine.h @@ -26,10 +26,12 @@ namespace workerd::api { // https://blog.cloudflare.com/workers-analytics-engine/ class AnalyticsEngine: public jsg::Object { public: - explicit AnalyticsEngine(uint logfwdrChannel, kj::String dataset, - int64_t version, uint32_t ownerId) - : logfwdrChannel(logfwdrChannel), dataset(kj::mv(dataset)), - version(version), ownerId(ownerId) {} + explicit AnalyticsEngine( + uint logfwdrChannel, kj::String dataset, int64_t version, uint32_t ownerId) + : logfwdrChannel(logfwdrChannel), + dataset(kj::mv(dataset)), + version(version), + ownerId(ownerId) {} struct AnalyticsEngineEvent { // An array of values for the user-defined indexes, that provide a way for // users to improve the efficiency of common queries. In addition, by @@ -50,8 +52,8 @@ class AnalyticsEngine: public jsg::Object { // Send an Analytics Engine-compatible event to the configured logfwdr socket. // Like logfwdr itself, `writeDataPoint` makes no delivery guarantees. - void writeDataPoint(jsg::Lock& js, - jsg::Optional event); + void writeDataPoint( + jsg::Lock& js, jsg::Optional event); JSG_RESOURCE_TYPE(AnalyticsEngine) { JSG_METHOD(writeDataPoint); @@ -73,7 +75,9 @@ class AnalyticsEngine: public jsg::Object { int64_t version; uint32_t ownerId; - uint64_t now() { return millisToNanos(dateNow()); } + uint64_t now() { + return millisToNanos(dateNow()); + } }; #define EW_ANALYTICS_ENGINE_ISOLATE_TYPES \ ::workerd::api::AnalyticsEngine, ::workerd::api::AnalyticsEngine::AnalyticsEngineEvent diff --git a/src/workerd/api/api-rtti-test.c++ b/src/workerd/api/api-rtti-test.c++ index 2468ba1db73..cc07fd8b8f5 100644 --- a/src/workerd/api/api-rtti-test.c++ +++ b/src/workerd/api/api-rtti-test.c++ @@ -37,5 +37,5 @@ KJ_TEST("ServiceWorkerGlobalScope") { KJ_EXPECT(builder.structure("workerd::api::DurableObjectId"_kj) != kj::none); } -} // namespace -} // namespace workerd::api +} // namespace +} // namespace workerd::api diff --git a/src/workerd/api/basics-test.c++ b/src/workerd/api/basics-test.c++ index b66085656af..efbeb2458c0 100644 --- a/src/workerd/api/basics-test.c++ +++ b/src/workerd/api/basics-test.c++ @@ -30,24 +30,18 @@ struct BasicsContext: public jsg::Object, public jsg::ContextGlobal { bool onceCalled = false; // Should be invoked multiple times. - auto handler = target->newNativeHandler( - js, - kj::str("foo"), - [&called](jsg::Lock& js, jsg::Ref event) { - called++; - }, false); + auto handler = target->newNativeHandler(js, kj::str("foo"), + [&called](jsg::Lock& js, jsg::Ref event) { called++; }, false); // Should only be invoked once. auto handlerOnce = target->newNativeHandler( - js, - kj::str("foo"), - [&](jsg::Lock& js, jsg::Ref event) { - KJ_ASSERT(!onceCalled); - onceCalled = true; - // Recursively dispatching the event here should not cause this handler to - // be invoked again. - target->dispatchEventImpl(js, jsg::alloc(kj::str("foo"))); - }, true); + js, kj::str("foo"), [&](jsg::Lock& js, jsg::Ref event) { + KJ_ASSERT(!onceCalled); + onceCalled = true; + // Recursively dispatching the event here should not cause this handler to + // be invoked again. + target->dispatchEventImpl(js, jsg::alloc(kj::str("foo"))); + }, true); KJ_ASSERT(target->dispatchEventImpl(js, jsg::alloc(kj::str("foo")))); KJ_ASSERT(target->dispatchEventImpl(js, jsg::alloc(kj::str("foo")))); @@ -59,15 +53,13 @@ struct BasicsContext: public jsg::Object, public jsg::ContextGlobal { JSG_METHOD(test); } }; -JSG_DECLARE_ISOLATE_TYPE( - BasicsIsolate, - BasicsContext, - EW_BASICS_ISOLATE_TYPES, - jsg::TypeWrapperExtension); +JSG_DECLARE_ISOLATE_TYPE(BasicsIsolate, + BasicsContext, + EW_BASICS_ISOLATE_TYPES, + jsg::TypeWrapperExtension); KJ_TEST("EventTarget native listeners work") { - jsg::test::Evaluator e(v8System); + jsg::test::Evaluator e(v8System); e.expectEval("test()", "boolean", "true"); } diff --git a/src/workerd/api/basics.c++ b/src/workerd/api/basics.c++ index 5b57568ac5b..b3d45e4dcba 100644 --- a/src/workerd/api/basics.c++ +++ b/src/workerd/api/basics.c++ @@ -23,22 +23,15 @@ namespace { bool isSpecialEventType(kj::StringPtr type) { // TODO(someday): How should we cover custom events here? Since it's just for a warning I'm // leaving them out for now. - return type == "fetch" || - type == "scheduled" || - type == "tail" || - type == "trace" || - type == "alarm"; + return type == "fetch" || type == "scheduled" || type == "tail" || type == "trace" || + type == "alarm"; } } // namespace EventTarget::NativeHandler::NativeHandler( - jsg::Lock& js, - EventTarget& target, - kj::String type, - jsg::Function func, - bool once) + jsg::Lock& js, EventTarget& target, kj::String type, jsg::Function func, bool once) : type(kj::mv(type)), - state(State { + state(State{ .target = target, .func = kj::mv(func), }), @@ -46,7 +39,9 @@ EventTarget::NativeHandler::NativeHandler( target.addNativeListener(js, *this); } -EventTarget::NativeHandler::~NativeHandler() noexcept(false) { detach(); } +EventTarget::NativeHandler::~NativeHandler() noexcept(false) { + detach(); +} void EventTarget::NativeHandler::operator()(jsg::Lock& js, jsg::Ref event) { KJ_IF_SOME(s, state) { @@ -81,10 +76,7 @@ void EventTarget::NativeHandler::detach() { } kj::Own EventTarget::newNativeHandler( - jsg::Lock& js, - kj::String type, - jsg::Function)> func, - bool once) { + jsg::Lock& js, kj::String type, jsg::Function)> func, bool once) { return kj::heap(js, *this, kj::mv(type), kj::mv(func), once); } @@ -96,8 +88,7 @@ const EventTarget::EventHandler::Handler& EventTarget::EventHandlerHashCallbacks } bool EventTarget::EventHandlerHashCallbacks::matches( - const kj::Own& a, - const jsg::HashableV8Ref& b) const { + const kj::Own& a, const jsg::HashableV8Ref& b) const { KJ_IF_SOME(jsA, a->handler.tryGet()) { return jsA.identity == b; } @@ -105,8 +96,7 @@ bool EventTarget::EventHandlerHashCallbacks::matches( } bool EventTarget::EventHandlerHashCallbacks::matches( - const kj::Own& a, - const NativeHandler& b) const { + const kj::Own& a, const NativeHandler& b) const { KJ_IF_SOME(ref, a->handler.tryGet()) { return &ref.handler == &b; } @@ -114,14 +104,12 @@ bool EventTarget::EventHandlerHashCallbacks::matches( } bool EventTarget::EventHandlerHashCallbacks::matches( - const kj::Own& a, - const EventHandler::NativeHandlerRef& b) const { + const kj::Own& a, const EventHandler::NativeHandlerRef& b) const { return matches(a, b.handler); } bool EventTarget::EventHandlerHashCallbacks::matches( - const kj::Own& a, - const EventHandler::Handler& b) const { + const kj::Own& a, const EventHandler::Handler& b) const { KJ_SWITCH_ONEOF(b) { KJ_CASE_ONEOF(jsB, EventHandler::JavaScriptHandler) { return matches(a, jsB.identity); @@ -169,7 +157,9 @@ jsg::Ref Event::constructor(kj::String type, jsg::Optional init) { return jsg::alloc(kj::mv(type), init.orDefault(defaultInit), false /* not trusted */); } -kj::StringPtr Event::getType() { return type; } +kj::StringPtr Event::getType() { + return type; +} jsg::Optional> Event::getCurrentTarget() { return target.map([&](jsg::Ref& t) { return t.addRef(); }); @@ -195,8 +185,8 @@ jsg::Ref EventTarget::constructor() { } EventTarget::~EventTarget() noexcept(false) { - for (auto& entry : typeMap) { - for (auto& handler : entry.value.handlers) { + for (auto& entry: typeMap) { + for (auto& handler: entry.value.handlers) { KJ_IF_SOME(native, handler->handler.tryGet()) { // Note: Can't call `detach()` here because it would loop back and call // `removeNativeListener()` on us, invalidating the `typeMap` iterator. We'll directly @@ -219,18 +209,18 @@ kj::Array EventTarget::getHandlerNames() const { return KJ_MAP(entry, typeMap) { return entry.key.asPtr(); }; } -void EventTarget::addEventListener(jsg::Lock& js, kj::String type, - jsg::Identified handler, - jsg::Optional maybeOptions) { +void EventTarget::addEventListener(jsg::Lock& js, + kj::String type, + jsg::Identified handler, + jsg::Optional maybeOptions) { if (warnOnSpecialEvents && isSpecialEventType(type)) { - js.logWarning( - kj::str("When using module syntax, the '", type, "' event handler should be " - "declared as an exported function on the root module as opposed to using " - "the global addEventListener().")); + js.logWarning(kj::str("When using module syntax, the '", type, + "' event handler should be " + "declared as an exported function on the root module as opposed to using " + "the global addEventListener().")); } js.withinHandleScope([&] { - // Per the spec, the handler can be either a Function, or an object with a // handleEvent member function. HandlerFunction handlerFn = ([&]() { @@ -254,9 +244,9 @@ void EventTarget::addEventListener(jsg::Lock& js, kj::String type, } KJ_CASE_ONEOF(opts, AddEventListenerOptions) { JSG_REQUIRE(!opts.capture.orDefault(false), TypeError, - "addEventListener(): options.capture must be false."); + "addEventListener(): options.capture must be false."); JSG_REQUIRE(!opts.passive.orDefault(false), TypeError, - "addEventListener(): options.passive must be false."); + "addEventListener(): options.passive must be false."); once = opts.once.orDefault(false); maybeSignal = kj::mv(opts.signal); } @@ -273,30 +263,31 @@ void EventTarget::addEventListener(jsg::Lock& js, kj::String type, auto& set = getOrCreate(type); auto maybeAbortHandler = maybeSignal.map([&](jsg::Ref& signal) { - auto func = JSG_VISITABLE_LAMBDA( - (this, type = kj::mv(type), handler = handler.identity.addRef(js)), - (handler), - (jsg::Lock& js, jsg::Ref) { - removeEventListener(js, kj::mv(type), kj::mv(handler), kj::none); - }); + auto func = + JSG_VISITABLE_LAMBDA((this, type = kj::mv(type), handler = handler.identity.addRef(js)), + (handler), (jsg::Lock& js, jsg::Ref) { + removeEventListener(js, kj::mv(type), kj::mv(handler), kj::none); + }); return signal->newNativeHandler(js, kj::str("abort"), kj::mv(func), true); }); auto eventHandler = kj::heap( - EventHandler::JavaScriptHandler { - .identity = kj::mv(handler.identity), - .callback = kj::mv(handlerFn), - .abortHandler = kj::mv(maybeAbortHandler), - }, once); + EventHandler::JavaScriptHandler{ + .identity = kj::mv(handler.identity), + .callback = kj::mv(handlerFn), + .abortHandler = kj::mv(maybeAbortHandler), + }, + once); set.handlers.upsert(kj::mv(eventHandler), [&](auto&&...) {}); }); } -void EventTarget::removeEventListener(jsg::Lock& js, kj::String type, - jsg::HashableV8Ref handler, - jsg::Optional maybeOptions) { +void EventTarget::removeEventListener(jsg::Lock& js, + kj::String type, + jsg::HashableV8Ref handler, + jsg::Optional maybeOptions) { KJ_IF_SOME(value, maybeOptions) { KJ_SWITCH_ONEOF(value) { KJ_CASE_ONEOF(b, bool) { @@ -304,7 +295,7 @@ void EventTarget::removeEventListener(jsg::Lock& js, kj::String type, } KJ_CASE_ONEOF(opts, EventListenerOptions) { JSG_REQUIRE(!opts.capture.orDefault(false), TypeError, - "removeEventListener(): options.capture must be false."); + "removeEventListener(): options.capture must be false."); } } } @@ -320,9 +311,10 @@ void EventTarget::addNativeListener(jsg::Lock& js, NativeHandler& handler) { auto& set = getOrCreate(handler.type); auto eventHandler = kj::heap( - EventHandler::NativeHandlerRef { - .handler = handler, - }, handler.once); + EventHandler::NativeHandlerRef{ + .handler = handler, + }, + handler.once); set.handlers.upsert(kj::mv(eventHandler), [&](auto&&...) {}); } @@ -361,11 +353,12 @@ bool EventTarget::dispatchEventImpl(jsg::Lock& js, jsg::Ref event) { KJ_IF_SOME(onProp, onEvents.get(js, kj::str("on", event->getType()))) { // If the on-event is not a function, we silently ignore it rather than raise an error. KJ_IF_SOME(cb, onProp.tryGet()) { - callbacks.add(Callback { - .handler = EventHandler::JavaScriptHandler { - .identity = nullptr, // won't be used below if oldStyle is true and once is false - .callback = kj::mv(cb), - }, + callbacks.add(Callback{ + .handler = + EventHandler::JavaScriptHandler{ + .identity = nullptr, // won't be used below if oldStyle is true and once is false + .callback = kj::mv(cb), + }, .oldStyle = true, }); } @@ -376,19 +369,18 @@ bool EventTarget::dispatchEventImpl(jsg::Lock& js, jsg::Ref event) { for (auto& handler: handlerSet.handlers.ordered()) { KJ_SWITCH_ONEOF(handler->handler) { KJ_CASE_ONEOF(jsh, EventHandler::JavaScriptHandler) { - callbacks.add(Callback { - .handler = EventHandler::JavaScriptHandler { - .identity = jsh.identity.addRef(js), - .callback = jsh.callback.addRef(js) - }, + callbacks.add(Callback{ + .handler = EventHandler::JavaScriptHandler{.identity = jsh.identity.addRef(js), + .callback = jsh.callback.addRef(js)}, .once = handler->once, }); } KJ_CASE_ONEOF(native, EventHandler::NativeHandlerRef) { - callbacks.add(Callback { - .handler = EventHandler::NativeHandlerRef { - .handler = native.handler, - }, + callbacks.add(Callback{ + .handler = + EventHandler::NativeHandlerRef{ + .handler = native.handler, + }, .once = handler->once, }); } @@ -468,14 +460,13 @@ bool EventTarget::dispatchEventImpl(jsg::Lock& js, jsg::Ref event) { warnOnHandlerReturn = false; // To help make debugging easier, let's tailor the warning a bit if it was a promise. if (handle->IsPromise()) { - js.logWarning( - kj::str("An event handler returned a promise that will be ignored. Event handlers " - "should not have a return value and should not be async functions.")); + js.logWarning(kj::str( + "An event handler returned a promise that will be ignored. Event handlers " + "should not have a return value and should not be async functions.")); } else { - js.logWarning( - kj::str("An event handler returned a value of type \"", - handle->TypeOf(js.v8Isolate), - "\" that will be ignored. Event handlers should not have a return value.")); + js.logWarning(kj::str("An event handler returned a value of type \"", + handle->TypeOf(js.v8Isolate), + "\" that will be ignored. Event handlers should not have a return value.")); } } } @@ -495,16 +486,16 @@ bool EventTarget::dispatchEvent(jsg::Lock& js, jsg::Ref event) { } AbortSignal::AbortSignal(kj::Maybe exception, - jsg::Optional> maybeReason, - Flag flag) : - canceler(IoContext::current().addObject( - kj::refcounted(kj::cp(exception)))), - flag(flag), - reason(kj::mv(maybeReason)) {} + jsg::Optional> maybeReason, + Flag flag) + : canceler( + IoContext::current().addObject(kj::refcounted(kj::cp(exception)))), + flag(flag), + reason(kj::mv(maybeReason)) {} kj::Maybe AbortSignal::getOnAbort(jsg::Lock& js) { - return onAbortHandler.map([&](jsg::JsRef& ref) - -> jsg::JsValue { return ref.getHandle(js); }); + return onAbortHandler.map( + [&](jsg::JsRef& ref) -> jsg::JsValue { return ref.getHandle(js); }); } void AbortSignal::setOnAbort(jsg::Lock& js, jsg::Optional handler) { @@ -537,8 +528,7 @@ jsg::JsValue AbortSignal::getReason(jsg::Lock& js) { } kj::Exception AbortSignal::abortException( - jsg::Lock& js, - jsg::Optional> maybeReason) { + jsg::Lock& js, jsg::Optional> maybeReason) { KJ_IF_SOME(reason, maybeReason) { KJ_SWITCH_ONEOF(reason) { KJ_CASE_ONEOF(reason, jsg::JsValue) { @@ -553,9 +543,7 @@ kj::Exception AbortSignal::abortException( return JSG_KJ_EXCEPTION(DISCONNECTED, DOMAbortError, "The operation was aborted"); } -jsg::Ref AbortSignal::abort( - jsg::Lock& js, - jsg::Optional maybeReason) { +jsg::Ref AbortSignal::abort(jsg::Lock& js, jsg::Optional maybeReason) { auto exception = abortException(js, maybeReason); KJ_IF_SOME(reason, maybeReason) { return jsg::alloc(kj::mv(exception), reason.addRef(js)); @@ -578,23 +566,23 @@ jsg::Ref AbortSignal::timeout(jsg::Lock& js, double delay) { auto context = js.v8Context(); - auto& global = jsg::extractInternalPointer( - context, context->Global()); + auto& global = + jsg::extractInternalPointer(context, context->Global()); // It's worth noting that the setTimeout holds a strong pointer to the AbortSignal, // keeping it from being garbage collected before the timer fires or until the request // completes, whichever comes first. global.setTimeoutInternal([signal = signal.addRef()](jsg::Lock& js) mutable { - signal->triggerAbort(js, JSG_KJ_EXCEPTION(DISCONNECTED, - DOMTimeoutError, "The operation was aborted due to timeout")); + signal->triggerAbort(js, + JSG_KJ_EXCEPTION( + DISCONNECTED, DOMTimeoutError, "The operation was aborted due to timeout")); }, delay); return kj::mv(signal); } -jsg::Ref AbortSignal::any( - jsg::Lock& js, +jsg::Ref AbortSignal::any(jsg::Lock& js, kj::Array> signals, const jsg::TypeHandler& handler) { // If nothing was passed in, we can just return a signal that never aborts. @@ -604,7 +592,7 @@ jsg::Ref AbortSignal::any( // Let's check to see if any of the signals are already aborted. If it is, we can // optimize here by skipping the event handler registration. - for (auto& sig : signals) { + for (auto& sig: signals) { if (sig->getAborted()) { return AbortSignal::abort(js, sig->getReason(js)); } @@ -613,13 +601,13 @@ jsg::Ref AbortSignal::any( // Otherwise we need to create a new signal and register event handlers on all // of the signals that were passed in. auto signal = jsg::alloc(); - for (auto& sig : signals) { + for (auto& sig: signals) { // This is a bit of a hack. We want to call addEventListener, but that requires a // jsg::Identified, which we can't create directly yet. // So we create a jsg::Function, wrap that in a v8::Function, then convert that into // the jsg::Identified, and voila, we have what we need. - auto fn = js.wrapSimpleFunction(js.v8Context(), - [&signal = *signal, &self = *sig](jsg::Lock& js, auto&) { + auto fn = js.wrapSimpleFunction( + js.v8Context(), [&signal = *signal, &self = *sig](jsg::Lock& js, auto&) { // Note that we are not capturing any strong references here to either signal // or sig. This is because we are capturing a strong reference to the signal // when we add the event below. This ensures that we do not have an unbreakable @@ -628,18 +616,15 @@ jsg::Ref AbortSignal::any( // will have a strong reference to the new signal. signal.triggerAbort(js, self.getReason(js)); }); - jsg::Identified identified = { - .identity = { js.v8Isolate, fn }, + jsg::Identified identified = {.identity = {js.v8Isolate, fn}, .unwrapped = JSG_REQUIRE_NONNULL(handler.tryUnwrap(js, fn.As()), TypeError, - "Unable to create AbortSignal.any handler") - }; + "Unable to create AbortSignal.any handler")}; - sig->addEventListener(js, kj::str("abort"), kj::mv(identified), AddEventListenerOptions { - // Once the abort is triggered, this handler should remove itself. - .once = true, - // When the signal is triggered, we'll use it to cancel the other registered signals. - .signal = signal.addRef() - }); + sig->addEventListener(js, kj::str("abort"), kj::mv(identified), + AddEventListenerOptions{// Once the abort is triggered, this handler should remove itself. + .once = true, + // When the signal is triggered, we'll use it to cancel the other registered signals. + .signal = signal.addRef()}); } return signal; } @@ -653,8 +638,7 @@ RefcountedCanceler& AbortSignal::getCanceler() { } void AbortSignal::triggerAbort( - jsg::Lock& js, - jsg::Optional> maybeReason) { + jsg::Lock& js, jsg::Optional> maybeReason) { KJ_ASSERT(flag != Flag::NEVER_ABORTS); if (canceler->isCanceled()) { return; @@ -685,15 +669,13 @@ void AbortSignal::triggerAbort( dispatchEventImpl(js, jsg::alloc(kj::str("abort"))); } -void AbortController::abort( - jsg::Lock& js, - jsg::Optional maybeReason) { +void AbortController::abort(jsg::Lock& js, jsg::Optional maybeReason) { signal->triggerAbort(js, maybeReason); } void EventTarget::visitForGc(jsg::GcVisitor& visitor) { - for (auto& entry : typeMap) { - for (auto& handler : entry.value.handlers) { + for (auto& entry: typeMap) { + for (auto& handler: entry.value.handlers) { KJ_SWITCH_ONEOF(handler->handler) { KJ_CASE_ONEOF(js, EventHandler::JavaScriptHandler) { visitor.visit(js); @@ -725,9 +707,7 @@ void EventTarget::visitForGc(jsg::GcVisitor& visitor) { } kj::Promise Scheduler::wait( - jsg::Lock& js, - double delay, - jsg::Optional maybeOptions) { + jsg::Lock& js, double delay, jsg::Optional maybeOptions) { KJ_IF_SOME(options, maybeOptions) { KJ_IF_SOME(s, options.signal) { if (s->getAborted()) { @@ -742,13 +722,10 @@ kj::Promise Scheduler::wait( auto context = js.v8Context(); - auto& global = jsg::extractInternalPointer( - context, context->Global()); - global.setTimeoutInternal( - [fulfiller = IoContext::current().addObject(kj::mv(paf.fulfiller))] - (jsg::Lock& lock) mutable { - fulfiller->fulfill(); - }, + auto& global = + jsg::extractInternalPointer(context, context->Global()); + global.setTimeoutInternal([fulfiller = IoContext::current().addObject(kj::mv(paf.fulfiller))]( + jsg::Lock& lock) mutable { fulfiller->fulfill(); }, delay); auto promise = kj::mv(paf.promise); @@ -763,8 +740,8 @@ kj::Promise Scheduler::wait( } void ExtendableEvent::waitUntil(kj::Promise promise) { - JSG_REQUIRE(getIsTrusted(), DOMInvalidStateError, - "waitUntil() can only be called on trusted event."); + JSG_REQUIRE( + getIsTrusted(), DOMInvalidStateError, "waitUntil() can only be called on trusted event."); IoContext::current().addWaitUntil(kj::mv(promise)); } @@ -774,9 +751,7 @@ jsg::Optional> ExtendableEvent::getActorState() { auto& lock = context.getCurrentLock(); auto persistent = actor.makeStorageForSwSyntax(lock); return jsg::alloc( - actor.cloneId(), - actor.getTransient(lock), - kj::mv(persistent)); + actor.cloneId(), actor.getTransient(lock), kj::mv(persistent)); }); } @@ -784,15 +759,13 @@ CustomEvent::CustomEvent(kj::String ownType, CustomEventInit init) : Event(kj::mv(ownType), (Event::Init)init), detail(kj::mv(init.detail)) {} -jsg::Ref CustomEvent::constructor(jsg::Lock& js, kj::String type, - jsg::Optional init) { +jsg::Ref CustomEvent::constructor( + jsg::Lock& js, kj::String type, jsg::Optional init) { return jsg::alloc(kj::mv(type), kj::mv(init).orDefault({})); } jsg::Optional CustomEvent::getDetail(jsg::Lock& js) { - return detail.map([&](jsg::JsRef& val) { - return val.getHandle(js); - }); + return detail.map([&](jsg::JsRef& val) { return val.getHandle(js); }); } CustomEvent::CustomEventInit::operator Event::Init() { @@ -812,8 +785,8 @@ void EventTarget::EventHandler::JavaScriptHandler::jsgGetMemoryInfo( tracker.trackField("identity", identity); tracker.trackField("callback", callback); if (abortHandler != kj::none) { - tracker.trackFieldWithSize("abortHandler", sizeof(kj::Own) + - sizeof(NativeHandler)); + tracker.trackFieldWithSize( + "abortHandler", sizeof(kj::Own) + sizeof(NativeHandler)); } } @@ -837,7 +810,7 @@ size_t EventTarget::EventHandlerSet::jsgGetMemorySelfSize() const { } void EventTarget::EventHandlerSet::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { - for (const auto& handler : handlers) { + for (const auto& handler: handlers) { tracker.trackField("handler", handler); } } diff --git a/src/workerd/api/basics.h b/src/workerd/api/basics.h index 25b3781f942..43a1411d21c 100644 --- a/src/workerd/api/basics.h +++ b/src/workerd/api/basics.h @@ -42,19 +42,31 @@ class Event: public jsg::Object { init(init), trusted(trusted) {} - inline bool isPreventDefault() const { return preventedDefault; } - inline void clearPreventDefault() { preventedDefault = false; } + inline bool isPreventDefault() const { + return preventedDefault; + } + inline void clearPreventDefault() { + preventedDefault = false; + } void beginDispatch(jsg::Ref target); - inline void endDispatch() { isBeingDispatched = false; } + inline void endDispatch() { + isBeingDispatched = false; + } - inline bool isStopped() const { return stopped; } + inline bool isStopped() const { + return stopped; + } static jsg::Ref constructor(kj::String type, jsg::Optional init); kj::StringPtr getType(); - inline void stopImmediatePropagation() { stopped = true; } - inline void preventDefault() { preventedDefault = true; } + inline void stopImmediatePropagation() { + stopped = true; + } + inline void preventDefault() { + preventedDefault = true; + } // The only phases we actually use are NONE and AT_TARGET but we provide // all of them to meet spec compliance. @@ -65,31 +77,53 @@ class Event: public jsg::Object { BUBBLING_PHASE, }; - inline int getEventPhase() const { return isBeingDispatched ? AT_TARGET : NONE; } + inline int getEventPhase() const { + return isBeingDispatched ? AT_TARGET : NONE; + } // Much of the following is not used in our implementation of Event // simply because we do not support the notion of bubbled events // (events propagated up through a hierarchy of objects). They are // provided to fill-out Event spec compliance. - inline bool getCancelBubble() const { return propagationStopped; } - inline void setCancelBubble(bool stopped) { propagationStopped = stopped; } - inline void stopPropagation() { propagationStopped = true; } - inline bool getComposed() const { return init.composed.orDefault(false); } - inline bool getBubbles() const { return init.bubbles.orDefault(false); } - inline bool getCancelable() const { return init.cancelable.orDefault(false); } - inline bool getDefaultPrevented() const { return getCancelable() && preventedDefault; } - inline bool getReturnValue() const { return !getDefaultPrevented(); } + inline bool getCancelBubble() const { + return propagationStopped; + } + inline void setCancelBubble(bool stopped) { + propagationStopped = stopped; + } + inline void stopPropagation() { + propagationStopped = true; + } + inline bool getComposed() const { + return init.composed.orDefault(false); + } + inline bool getBubbles() const { + return init.bubbles.orDefault(false); + } + inline bool getCancelable() const { + return init.cancelable.orDefault(false); + } + inline bool getDefaultPrevented() const { + return getCancelable() && preventedDefault; + } + inline bool getReturnValue() const { + return !getDefaultPrevented(); + } // We provide the timeStamp property for spec compliance but we force // the value to 0.0 always because we really don't want users to rely // on this property for timing details. - inline double getTimestamp() const { return 0.0; } + inline double getTimestamp() const { + return 0.0; + } // What makes an Event trusted? It's pretty simple... any Event created // by EW internally is Trusted, any Event created using new Event() in JS // is not trusted. - inline bool getIsTrusted() const { return trusted; } + inline bool getIsTrusted() const { + return trusted; + } // The currentTarget is the EventTarget on which the Event is being // dispatched. This will be set every time dispatchEvent() is called @@ -210,8 +244,8 @@ class CustomEvent: public Event { explicit CustomEvent(kj::String ownType, CustomEventInit init = CustomEventInit()); - static jsg::Ref constructor(jsg::Lock& js, kj::String type, - jsg::Optional init); + static jsg::Ref constructor( + jsg::Lock& js, kj::String type, jsg::Optional init); jsg::Optional getDetail(jsg::Lock& js); @@ -242,9 +276,13 @@ class EventTarget: public jsg::Object { bool dispatchEventImpl(jsg::Lock& js, jsg::Ref event); - inline void removeAllHandlers() { typeMap.clear(); } + inline void removeAllHandlers() { + typeMap.clear(); + } - inline void enableWarningOnSpecialEvents() { warnOnSpecialEvents = true; } + inline void enableWarningOnSpecialEvents() { + warnOnSpecialEvents = true; + } // --------------------------------------------------------------------------- // JS API @@ -279,10 +317,14 @@ class EventTarget: public jsg::Object { }; typedef kj::OneOf Handler; - void addEventListener(jsg::Lock& js, kj::String type, jsg::Identified handler, - jsg::Optional maybeOptions); - void removeEventListener(jsg::Lock& js, kj::String type, jsg::HashableV8Ref handler, - jsg::Optional options); + void addEventListener(jsg::Lock& js, + kj::String type, + jsg::Identified handler, + jsg::Optional maybeOptions); + void removeEventListener(jsg::Lock& js, + kj::String type, + jsg::HashableV8Ref handler, + jsg::Optional options); bool dispatchEvent(jsg::Lock& js, jsg::Ref event); JSG_RESOURCE_TYPE(EventTarget) { @@ -314,10 +356,8 @@ class EventTarget: public jsg::Object { // // The caller must not do anything with the returned Own except drop it. This is why it // is Own and not Own. - kj::Own newNativeHandler(jsg::Lock& js, - kj::String type, - jsg::Function)> func, - bool once = false); + kj::Own newNativeHandler( + jsg::Lock& js, kj::String type, jsg::Function)> func, bool once = false); void visitForMemoryInfo(jsg::MemoryTracker& tracker) const; @@ -326,16 +366,20 @@ class EventTarget: public jsg::Object { class NativeHandler { public: using Signature = void(jsg::Ref); - NativeHandler(jsg::Lock& js, EventTarget& target, kj::String type, - jsg::Function func, bool once = false); + NativeHandler(jsg::Lock& js, + EventTarget& target, + kj::String type, + jsg::Function func, + bool once = false); ~NativeHandler() noexcept(false); KJ_DISALLOW_COPY_AND_MOVE(NativeHandler); - void operator()(jsg::Lock&js, jsg::Ref event); + void operator()(jsg::Lock& js, jsg::Ref event); uint hashCode() const; void visitForGc(jsg::GcVisitor& visitor); + private: void detach(); @@ -377,7 +421,9 @@ class EventTarget: public jsg::Object { // visit the NativeHandler's content. } - kj::StringPtr jsgGetMemoryName() const { return "JavaScriptHandler"_kjc; } + kj::StringPtr jsgGetMemoryName() const { + return "JavaScriptHandler"_kjc; + } size_t jsgGetMemorySelfSize() const; void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const; }; @@ -396,11 +442,12 @@ class EventTarget: public jsg::Object { // When once is true, the handler will be removed after it is invoked one time. bool once = false; - EventHandler(Handler handler, bool once) - : handler(kj::mv(handler)), once(once) {} + EventHandler(Handler handler, bool once): handler(kj::mv(handler)), once(once) {} KJ_DISALLOW_COPY_AND_MOVE(EventHandler); - kj::StringPtr jsgGetMemoryName() const { return "EventHandler"_kjc; } + kj::StringPtr jsgGetMemoryName() const { + return "EventHandler"_kjc; + } size_t jsgGetMemorySelfSize() const; void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const; }; @@ -420,13 +467,15 @@ class EventTarget: public jsg::Object { struct EventHandlerSet { kj::Table, - kj::HashIndex, - kj::InsertionOrderIndex> handlers; + kj::HashIndex, + kj::InsertionOrderIndex> + handlers; - EventHandlerSet() - : handlers(EventHandlerHashCallbacks(), {}) {} + EventHandlerSet(): handlers(EventHandlerHashCallbacks(), {}) {} - kj::StringPtr jsgGetMemoryName() const { return "EventHandlerSet"_kjc; } + kj::StringPtr jsgGetMemoryName() const { + return "EventHandlerSet"_kjc; + } size_t jsgGetMemorySelfSize() const; void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const; }; @@ -458,38 +507,39 @@ class AbortSignal final: public EventTarget { enum class Flag { NONE, NEVER_ABORTS }; AbortSignal(kj::Maybe exception = kj::none, - jsg::Optional> maybeReason = kj::none, - Flag flag = Flag::NONE); + jsg::Optional> maybeReason = kj::none, + Flag flag = Flag::NONE); // The AbortSignal explicitly does not expose a constructor(). It is // illegal for user code to create an AbortSignal directly. static jsg::Ref constructor() = delete; - bool getAborted() { return canceler->isCanceled(); } + bool getAborted() { + return canceler->isCanceled(); + } jsg::JsValue getReason(jsg::Lock& js); // Will synchronously throw an error if the abort signal has been triggered. void throwIfAborted(jsg::Lock& js); - inline bool getNeverAborts() const { return flag == Flag::NEVER_ABORTS; } + inline bool getNeverAborts() const { + return flag == Flag::NEVER_ABORTS; + } // The static abort() function here returns an AbortSignal that // has been pre-emptively aborted. It's useful when it might still // be desirable to kick off an async process while communicating // that it shouldn't continue. - static jsg::Ref abort( - jsg::Lock& js, - jsg::Optional reason); + static jsg::Ref abort(jsg::Lock& js, jsg::Optional reason); // Returns an AbortSignal that is triggered after delay milliseconds. static jsg::Ref timeout(jsg::Lock& js, double delay); - void triggerAbort(jsg::Lock& js, - jsg::Optional> maybeReason); + void triggerAbort( + jsg::Lock& js, jsg::Optional> maybeReason); - static jsg::Ref any( - jsg::Lock& js, + static jsg::Ref any(jsg::Lock& js, kj::Array> signals, const jsg::TypeHandler& handler); @@ -525,8 +575,7 @@ class AbortSignal final: public EventTarget { template static kj::Promise maybeCancelWrap( - kj::Maybe>& signal, - kj::Promise promise) { + kj::Maybe>& signal, kj::Promise promise) { KJ_IF_SOME(s, signal) { return s->wrap(kj::mv(promise)); } else { @@ -535,15 +584,14 @@ class AbortSignal final: public EventTarget { } static kj::Exception abortException( - jsg::Lock& js, - jsg::Optional> reason = kj::none); + jsg::Lock& js, jsg::Optional> reason = kj::none); RefcountedCanceler& getCanceler(); void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { EventTarget::visitForMemoryInfo(tracker); - tracker.trackInlineFieldWithSize("IoOwn", - sizeof(IoOwn)); + tracker.trackInlineFieldWithSize( + "IoOwn", sizeof(IoOwn)); tracker.trackField("reason", reason); } @@ -561,14 +609,15 @@ class AbortSignal final: public EventTarget { // An implementation of the Web Platform Standard AbortController API class AbortController final: public jsg::Object { public: - explicit AbortController() - : signal(jsg::alloc()) {} + explicit AbortController(): signal(jsg::alloc()) {} static jsg::Ref constructor() { return jsg::alloc(); } - jsg::Ref getSignal() { return signal.addRef(); } + jsg::Ref getSignal() { + return signal.addRef(); + } void abort(jsg::Lock& js, jsg::Optional reason); @@ -608,10 +657,7 @@ class Scheduler final: public jsg::Object { // Returns a promise that resolves after the `delay` milliseconds. // Essentially an awaitable alternative to setTimeout(). The wait // can be canceled using an AbortSignal. - kj::Promise wait( - jsg::Lock& js, - double delay, - jsg::Optional maybeOptions); + kj::Promise wait(jsg::Lock& js, double delay, jsg::Optional maybeOptions); JSG_RESOURCE_TYPE(Scheduler) { JSG_METHOD(wait); @@ -620,20 +666,11 @@ class Scheduler final: public jsg::Object { private: }; -#define EW_BASICS_ISOLATE_TYPES \ - api::Event, \ - api::Event::Init, \ - api::EventTarget, \ - api::EventTarget::EventListenerOptions, \ - api::EventTarget::AddEventListenerOptions, \ - api::EventTarget::HandlerObject, \ - api::AbortController, \ - api::AbortSignal, \ - api::Scheduler, \ - api::Scheduler::WaitOptions, \ - api::ExtendableEvent, \ - api::CustomEvent, \ - api::CustomEvent::CustomEventInit +#define EW_BASICS_ISOLATE_TYPES \ + api::Event, api::Event::Init, api::EventTarget, api::EventTarget::EventListenerOptions, \ + api::EventTarget::AddEventListenerOptions, api::EventTarget::HandlerObject, \ + api::AbortController, api::AbortSignal, api::Scheduler, api::Scheduler::WaitOptions, \ + api::ExtendableEvent, api::CustomEvent, api::CustomEvent::CustomEventInit // The list of basics.h types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE } // namespace workerd::api diff --git a/src/workerd/api/blob.c++ b/src/workerd/api/blob.c++ index f47fc189e56..bb0eaa62aab 100644 --- a/src/workerd/api/blob.c++ +++ b/src/workerd/api/blob.c++ @@ -46,8 +46,8 @@ kj::Array concat(jsg::Lock& js, jsg::Optional maybeBits) { // however, it is practically impossible to reach this limit in any real-world // scenario given the size limit check below. size_t upperLimit = kOverflowLimit - size; - JSG_REQUIRE(partSize <= upperLimit, RangeError, - kj::str("Blob part too large: ", partSize, " bytes")); + JSG_REQUIRE( + partSize <= upperLimit, RangeError, kj::str("Blob part too large: ", partSize, " bytes")); // Checks for oversize if (size + partSize > maxBlobSize) { @@ -57,7 +57,7 @@ kj::Array concat(jsg::Lock& js, jsg::Optional maybeBits) { kj::str("NOSENTRY Attempt to create a Blob with size ", size + partSize)); } JSG_REQUIRE(size + partSize <= maxBlobSize, RangeError, - kj::str("Blob size ", size + partSize ," exceeds limit ", maxBlobSize)); + kj::str("Blob size ", size + partSize, " exceeds limit ", maxBlobSize)); size += partSize; } @@ -118,8 +118,8 @@ kj::String normalizeType(kj::String type) { } jsg::BufferSource wrap(jsg::Lock& js, kj::Array data) { - auto buf = JSG_REQUIRE_NONNULL(jsg::BufferSource::tryAlloc(js, data.size()), - Error, "Unable to allocate space for Blob data"); + auto buf = JSG_REQUIRE_NONNULL(jsg::BufferSource::tryAlloc(js, data.size()), Error, + "Unable to allocate space for Blob data"); buf.asArrayPtr().copyFrom(data); return kj::mv(buf); @@ -146,11 +146,12 @@ Blob::Blob(jsg::Lock& js, kj::Array data, kj::String type) type(kj::mv(type)) {} Blob::Blob(jsg::Ref parent, kj::ArrayPtr data, kj::String type) - : ownData(kj::mv(parent)), data(data), type(kj::mv(type)) {} + : ownData(kj::mv(parent)), + data(data), + type(kj::mv(type)) {} -jsg::Ref Blob::constructor(jsg::Lock& js, - jsg::Optional bits, - jsg::Optional options) { +jsg::Ref Blob::constructor( + jsg::Lock& js, jsg::Optional bits, jsg::Optional options) { kj::String type; // note: default value is intentionally empty string KJ_IF_SOME(o, options) { KJ_IF_SOME(t, o.type) { @@ -166,8 +167,8 @@ kj::ArrayPtr Blob::getData() const { return data; } -jsg::Ref Blob::slice(jsg::Optional maybeStart, jsg::Optional maybeEnd, - jsg::Optional type) { +jsg::Ref Blob::slice( + jsg::Optional maybeStart, jsg::Optional maybeEnd, jsg::Optional type) { int start = maybeStart.orDefault(0); int end = maybeEnd.orDefault(data.size()); @@ -193,8 +194,8 @@ jsg::Ref Blob::slice(jsg::Optional maybeStart, jsg::Optional may end = data.size(); } - return jsg::alloc(JSG_THIS, data.slice(start, end), - normalizeType(kj::mv(type).orDefault(nullptr))); + return jsg::alloc( + JSG_THIS, data.slice(start, end), normalizeType(kj::mv(type).orDefault(nullptr))); } jsg::Promise> Blob::arrayBuffer(jsg::Lock& js) { @@ -214,9 +215,7 @@ jsg::Promise Blob::text(jsg::Lock& js) { class Blob::BlobInputStream final: public ReadableStreamSource { public: - BlobInputStream(jsg::Ref blob) - : unread(blob->data), - blob(kj::mv(blob)) {} + BlobInputStream(jsg::Ref blob): unread(blob->data), blob(kj::mv(blob)) {} // Attempt to read a maximum of maxBytes from the remaining unread content of the blob // into the given buffer. It is the caller's responsibility to ensure that buffer has @@ -269,30 +268,33 @@ private: jsg::Ref Blob::stream() { FeatureObserver::maybeRecordUse(FeatureObserver::Feature::BLOB_AS_STREAM); - return jsg::alloc( - IoContext::current(), - kj::heap(JSG_THIS)); + return jsg::alloc(IoContext::current(), kj::heap(JSG_THIS)); } // ======================================================================================= -File::File(kj::Array data, kj::String name, kj::String type, - double lastModified) +File::File(kj::Array data, kj::String name, kj::String type, double lastModified) : Blob(kj::mv(data), kj::mv(type)), - name(kj::mv(name)), lastModified(lastModified) {} + name(kj::mv(name)), + lastModified(lastModified) {} -File::File(jsg::Lock& js, kj::Array data, kj::String name, kj::String type, - double lastModified) +File::File( + jsg::Lock& js, kj::Array data, kj::String name, kj::String type, double lastModified) : Blob(js, kj::mv(data), kj::mv(type)), - name(kj::mv(name)), lastModified(lastModified) {} - -File::File(jsg::Ref parent, kj::ArrayPtr data, - kj::String name, kj::String type, double lastModified) + name(kj::mv(name)), + lastModified(lastModified) {} + +File::File(jsg::Ref parent, + kj::ArrayPtr data, + kj::String name, + kj::String type, + double lastModified) : Blob(kj::mv(parent), data, kj::mv(type)), - name(kj::mv(name)), lastModified(lastModified) {} + name(kj::mv(name)), + lastModified(lastModified) {} -jsg::Ref File::constructor(jsg::Lock& js, jsg::Optional bits, - kj::String name, jsg::Optional options) { +jsg::Ref File::constructor( + jsg::Lock& js, jsg::Optional bits, kj::String name, jsg::Optional options) { kj::String type; // note: default value is intentionally empty string kj::Maybe maybeLastModified; KJ_IF_SOME(o, options) { diff --git a/src/workerd/api/blob.h b/src/workerd/api/blob.h index 9352996c35f..a3902c5c1ab 100644 --- a/src/workerd/api/blob.h +++ b/src/workerd/api/blob.h @@ -31,14 +31,18 @@ class Blob: public jsg::Object { typedef kj::Array, kj::String, jsg::Ref>> Bits; - static jsg::Ref constructor(jsg::Lock& js, jsg::Optional bits, - jsg::Optional options); + static jsg::Ref constructor( + jsg::Lock& js, jsg::Optional bits, jsg::Optional options); - int getSize() const { return data.size(); } - kj::StringPtr getType() const { return type; } + int getSize() const { + return data.size(); + } + kj::StringPtr getType() const { + return type; + } - jsg::Ref slice(jsg::Optional start, jsg::Optional end, - jsg::Optional type); + jsg::Ref slice( + jsg::Optional start, jsg::Optional end, jsg::Optional type); jsg::Promise> arrayBuffer(jsg::Lock& js); jsg::Promise bytes(jsg::Lock& js); @@ -100,7 +104,8 @@ class Blob: public jsg::Object { KJ_CASE_ONEOF(b, jsg::Ref) { visitor.visit(b); } - KJ_CASE_ONEOF(b, kj::Array) {} + KJ_CASE_ONEOF(b, kj::Array) { + } } } @@ -116,8 +121,11 @@ class File: public Blob { // JavaScript (such as in the internal fiddle service). File(kj::Array data, kj::String name, kj::String type, double lastModified); File(jsg::Lock& js, kj::Array data, kj::String name, kj::String type, double lastModified); - File(jsg::Ref parent, kj::ArrayPtr data, - kj::String name, kj::String type, double lastModified); + File(jsg::Ref parent, + kj::ArrayPtr data, + kj::String name, + kj::String type, + double lastModified); struct Options { jsg::Optional type; @@ -127,11 +135,15 @@ class File: public Blob { JSG_STRUCT(type, lastModified, endings); }; - static jsg::Ref constructor(jsg::Lock& js, jsg::Optional bits, - kj::String name, jsg::Optional options); + static jsg::Ref constructor( + jsg::Lock& js, jsg::Optional bits, kj::String name, jsg::Optional options); - kj::StringPtr getName() { return name; } - double getLastModified() { return lastModified; } + kj::StringPtr getName() { + return name; + } + double getLastModified() { + return lastModified; + } JSG_RESOURCE_TYPE(File, CompatibilityFlags::Reader flags) { JSG_INHERIT(Blob); @@ -153,10 +165,6 @@ class File: public Blob { double lastModified; }; -#define EW_BLOB_ISOLATE_TYPES \ - api::Blob, \ - api::Blob::Options, \ - api::File, \ - api::File::Options +#define EW_BLOB_ISOLATE_TYPES api::Blob, api::Blob::Options, api::File, api::File::Options } // namespace workerd::api diff --git a/src/workerd/api/cache.c++ b/src/workerd/api/cache.c++ index d0860aff1d0..26f6cdfbc61 100644 --- a/src/workerd/api/cache.c++ +++ b/src/workerd/api/cache.c++ @@ -44,13 +44,13 @@ kj::StringPtr validateUrl(kj::StringPtr url) { // But, that might mean e.g. discarding fragments ("hashes", stuff after a '#'), which would // be a change in behavior that could subtly affect production workers... - static constexpr auto urlOptions = kj::Url::Options { + static constexpr auto urlOptions = kj::Url::Options{ .percentDecode = false, .allowEmpty = true, }; JSG_REQUIRE(kj::Url::tryParse(url, kj::Url::HTTP_PROXY_REQUEST, urlOptions) != kj::none, - TypeError, "Invalid URL. Cache API keys must be fully-qualified, valid URLs."); + TypeError, "Invalid URL. Cache API keys must be fully-qualified, valid URLs."); return url; } @@ -86,8 +86,7 @@ jsg::Promise>> Cache::match( return js.resolvedPromise(jsg::Optional>()); } - auto httpClient = getHttpClient(context, jsRequest->serializeCfBlobJson(js), - "cache_match"_kjc); + auto httpClient = getHttpClient(context, jsRequest->serializeCfBlobJson(js), "cache_match"_kjc); auto requestHeaders = kj::HttpHeaders(context.getHeaderTable()); jsRequest->shallowCopyHeadersTo(requestHeaders); requestHeaders.set(context.getHeaderIds().cacheControl, "only-if-cached"); @@ -95,9 +94,8 @@ jsg::Promise>> Cache::match( kj::HttpMethod::GET, validateUrl(jsRequest->getUrl()), requestHeaders, uint64_t(0)); return context.awaitIo(js, kj::mv(nativeRequest.response), - [httpClient = kj::mv(httpClient), &context] - (jsg::Lock& js, kj::HttpClient::Response&& response) - mutable -> jsg::Optional> { + [httpClient = kj::mv(httpClient), &context](jsg::Lock& js, + kj::HttpClient::Response&& response) mutable -> jsg::Optional> { response.body = response.body.attach(kj::mv(httpClient)); kj::StringPtr cacheStatus; @@ -130,10 +128,8 @@ jsg::Promise>> Cache::match( return kj::none; } - return makeHttpResponse( - js, kj::HttpMethod::GET, {}, - response.statusCode, response.statusText, *response.headers, - kj::mv(response.body), kj::none); + return makeHttpResponse(js, kj::HttpMethod::GET, {}, response.statusCode, response.statusText, + *response.headers, kj::mv(response.body), kj::none); }); }); } @@ -149,8 +145,10 @@ jsg::Promise>> Cache::match( // In order to extract the response's data to serialize it, we'll need to call // `jsResponse->send()`, which will properly encode the response's body if a Content-Encoding // header is present. This means we'll need to create an instance of kj::HttpService::Response. -jsg::Promise Cache::put(jsg::Lock& js, Request::Info requestOrUrl, - jsg::Ref jsResponse, CompatibilityFlags::Reader flags) { +jsg::Promise Cache::put(jsg::Lock& js, + Request::Info requestOrUrl, + jsg::Ref jsResponse, + CompatibilityFlags::Reader flags) { // Fake kj::HttpService::Response implementation that allows us to reuse jsResponse->send() to // serialize the response (headers + body) in the format needed to serve as the payload of @@ -175,8 +173,9 @@ jsg::Promise Cache::put(jsg::Lock& js, Request::Info requestOrUrl, } private: - kj::Own send( - uint statusCode, kj::StringPtr statusText, const kj::HttpHeaders& headers, + kj::Own send(uint statusCode, + kj::StringPtr statusText, + const kj::HttpHeaders& headers, kj::Maybe expectedBodySize) override { kj::String contentLength; @@ -190,9 +189,8 @@ jsg::Promise Cache::put(jsg::Lock& js, Request::Info requestOrUrl, auto serializedHeaders = headers.serializeResponse(statusCode, statusText, connectionHeaders); - auto expectedPayloadSize = expectedBodySize.map([&](uint64_t size) { - return size + serializedHeaders.size(); - }); + auto expectedPayloadSize = + expectedBodySize.map([&](uint64_t size) { return size + serializedHeaders.size(); }); // We want to create an AsyncInputStream that represents the payload, including both headers // and body. To do this, we'll create a one-way pipe, using the input end of the pipe as @@ -210,19 +208,17 @@ jsg::Promise Cache::put(jsg::Lock& js, Request::Info requestOrUrl, auto payloadPipe = kj::newOneWayPipe(expectedPayloadSize); static auto constexpr handleHeaders = [](kj::Own out, - kj::String serializedHeaders) + kj::String serializedHeaders) -> kj::Promise, bool>> { co_await out->write(serializedHeaders.asBytes()); co_return kj::tuple(kj::mv(out), false); }; - auto headersPromises = handleHeaders(kj::mv(payloadPipe.out), - kj::mv(serializedHeaders)).split(); + auto headersPromises = + handleHeaders(kj::mv(payloadPipe.out), kj::mv(serializedHeaders)).split(); - payload = Payload { - .stream = kj::mv(payloadPipe.in), - .writeHeadersPromise = kj::get<1>(headersPromises).ignoreResult() - }; + payload = Payload{.stream = kj::mv(payloadPipe.in), + .writeHeadersPromise = kj::get<1>(headersPromises).ignoreResult()}; return kj::newPromisedStream(kj::mv(kj::get<0>(headersPromises))); } @@ -243,16 +239,16 @@ jsg::Promise Cache::put(jsg::Lock& js, Request::Info requestOrUrl, // important if api::Request is changed to parse its URL eagerly (as required by spec), rather // than at fetch()-time. - JSG_REQUIRE(jsRequest->getMethodEnum() == kj::HttpMethod::GET, - TypeError, "Cannot cache response to non-GET request."); + JSG_REQUIRE(jsRequest->getMethodEnum() == kj::HttpMethod::GET, TypeError, + "Cannot cache response to non-GET request."); - JSG_REQUIRE(jsResponse->getStatus() != 206, - TypeError, "Cannot cache response to a range request (206 Partial Content)."); + JSG_REQUIRE(jsResponse->getStatus() != 206, TypeError, + "Cannot cache response to a range request (206 Partial Content)."); auto responseHeadersRef = jsResponse->getHeaders(js); KJ_IF_SOME(vary, responseHeadersRef->get(jsg::ByteString(kj::str("vary")))) { - JSG_REQUIRE(vary.findFirst('*') == kj::none, - TypeError, "Cannot cache response with 'Vary: *' header."); + JSG_REQUIRE(vary.findFirst('*') == kj::none, TypeError, + "Cannot cache response with 'Vary: *' header."); } auto& context = IoContext::current(); @@ -268,7 +264,8 @@ jsg::Promise Cache::put(jsg::Lock& js, Request::Info requestOrUrl, // still spec-conformant. if (context.isInspectorEnabled()) { - context.logWarning("Ignoring attempt to Cache.put() a 304 status response. 304 responses " + context.logWarning( + "Ignoring attempt to Cache.put() a 304 status response. 304 responses " "are not meaningful to cache, and a potential source of bugs. Consider validating that " "the response status is meaningful to cache before calling Cache.put()."); } @@ -306,25 +303,22 @@ jsg::Promise Cache::put(jsg::Lock& js, Request::Info requestOrUrl, startStreamPromise = makeCachePutStream(js); } - return startStreamPromise.then(js, context.addFunctor( - [this, &context, jsRequest = kj::mv(jsRequest), - serializePromise = kj::mv(serializePromise), - writePayloadHeadersPromise = kj::mv(payload.writeHeadersPromise)] - (jsg::Lock& js, IoOwn payloadStream) mutable - -> jsg::Promise { + return startStreamPromise.then(js, + context.addFunctor( + [this, &context, jsRequest = kj::mv(jsRequest), + serializePromise = kj::mv(serializePromise), + writePayloadHeadersPromise = kj::mv(payload.writeHeadersPromise)](jsg::Lock& js, + IoOwn payloadStream) mutable -> jsg::Promise { // Make the PUT request to cache. - auto httpClient = getHttpClient(context, jsRequest->serializeCfBlobJson(js), - "cache_put"_kjc); + auto httpClient = getHttpClient(context, jsRequest->serializeCfBlobJson(js), "cache_put"_kjc); auto requestHeaders = kj::HttpHeaders(context.getHeaderTable()); jsRequest->shallowCopyHeadersTo(requestHeaders); - auto nativeRequest = httpClient->request( - kj::HttpMethod::PUT, validateUrl(jsRequest->getUrl()), - requestHeaders, payloadStream->tryGetLength()); + auto nativeRequest = httpClient->request(kj::HttpMethod::PUT, + validateUrl(jsRequest->getUrl()), requestHeaders, payloadStream->tryGetLength()); - auto pumpRequestBodyPromise = payloadStream->pumpTo(*nativeRequest.body) - .ignoreResult(); - // NOTE: We don't attach nativeRequest.body here because we want to control its - // destruction timing in the event of an error; see below. + auto pumpRequestBodyPromise = payloadStream->pumpTo(*nativeRequest.body).ignoreResult(); + // NOTE: We don't attach nativeRequest.body here because we want to control its + // destruction timing in the event of an error; see below. // The next step is a bit complicated as it occurs in two separate async flows. // First, we await the serialization promise, then enter "deferred proxying" by issuing @@ -386,15 +380,12 @@ jsg::Promise Cache::put(jsg::Lock& js, Request::Info requestOrUrl, // `awaitDeferredProxy()` the whole thing. // Here we handle the promise for the DeferredProxy itself. - static auto constexpr handleSerialize = []( - kj::Promise> serialize, - kj::Own httpClient, - kj::Promise responsePromise, - kj::Own bodyStream, - kj::Promise pumpRequestBodyPromise, - kj::Promise writePayloadHeadersPromise, - kj::Own payloadStream) - -> kj::Promise> { + static auto constexpr handleSerialize = + [](kj::Promise> serialize, kj::Own httpClient, + kj::Promise responsePromise, + kj::Own bodyStream, kj::Promise pumpRequestBodyPromise, + kj::Promise writePayloadHeadersPromise, + kj::Own payloadStream) -> kj::Promise> { // This is extremely odd and a bit annoying but we have to make sure // these are destroyed in a particular order due to cross-dependencies // for each. If the kj::Promise returned by handleSerialize is dropped @@ -442,8 +433,7 @@ jsg::Promise Cache::put(jsg::Lock& js, Request::Info requestOrUrl, // error, which we log. However, there's no need to throw, since the Cache API is an // ephemeral K/V store, and we never guaranteed the script we'd actually cache anything. if (response.statusCode != 204 && response.statusCode != 413) { - LOG_CACHE_ERROR_ONCE( - "Response to Cache API PUT was neither 204 nor 413: ", response); + LOG_CACHE_ERROR_ONCE("Response to Cache API PUT was neither 204 nor 413: ", response); } } catch (...) { auto exception = kj::getCaughtExceptionAsKj(); @@ -462,14 +452,11 @@ jsg::Promise Cache::put(jsg::Lock& js, Request::Info requestOrUrl, } }; - return context.awaitDeferredProxy(js, handleSerialize( - kj::mv(serializePromise), - kj::mv(httpClient), - kj::mv(nativeRequest.response), - kj::mv(nativeRequest.body), - kj::mv(pumpRequestBodyPromise), - kj::mv(writePayloadHeadersPromise), - kj::mv(payloadStream))); + return context.awaitDeferredProxy(js, + handleSerialize(kj::mv(serializePromise), kj::mv(httpClient), + kj::mv(nativeRequest.response), kj::mv(nativeRequest.body), + kj::mv(pumpRequestBodyPromise), kj::mv(writePayloadHeadersPromise), + kj::mv(payloadStream))); })); }); } @@ -495,8 +482,8 @@ jsg::Promise Cache::delete_( // Make the PURGE request to cache. - auto httpClient = getHttpClient(context, jsRequest->serializeCfBlobJson(js), - "cache_delete"_kjc); + auto httpClient = + getHttpClient(context, jsRequest->serializeCfBlobJson(js), "cache_delete"_kjc); auto requestHeaders = kj::HttpHeaders(context.getHeaderTable()); jsRequest->shallowCopyHeadersTo(requestHeaders); // HACK: The cache doesn't permit PURGE requests from the outside world. It does this by @@ -510,16 +497,15 @@ jsg::Promise Cache::delete_( kj::HttpMethod::PURGE, validateUrl(jsRequest->getUrl()), requestHeaders, uint64_t(0)); return context.awaitIo(js, kj::mv(nativeRequest.response), - [httpClient = kj::mv(httpClient)] - (jsg::Lock&, kj::HttpClient::Response&& response) -> bool { + [httpClient = kj::mv(httpClient)](jsg::Lock&, kj::HttpClient::Response&& response) -> bool { if (response.statusCode == 200) { return true; } else if (response.statusCode == 404) { return false; } else if (response.statusCode == 429) { // Throw, but do not log the response to Sentry, as rate-limited subrequests are normal - JSG_FAIL_REQUIRE(Error, - "Unable to delete cached response. Subrequests are being rate-limited."); + JSG_FAIL_REQUIRE( + Error, "Unable to delete cached response. Subrequests are being rate-limited."); } LOG_CACHE_ERROR_ONCE("Response to Cache API PURGE was neither 200 nor 404: ", response); JSG_FAIL_REQUIRE(Error, "Unable to delete cached response."); @@ -527,17 +513,15 @@ jsg::Promise Cache::delete_( }); } -kj::Own Cache::getHttpClient(IoContext& context, - kj::Maybe cfBlobJson, - kj::ConstString operationName) { +kj::Own Cache::getHttpClient( + IoContext& context, kj::Maybe cfBlobJson, kj::ConstString operationName) { auto span = context.makeTraceSpan(kj::mv(operationName)); auto cacheClient = context.getCacheClient(); - auto httpClient = cacheName.map([&](kj::String& n) { + auto httpClient = cacheName + .map([&](kj::String& n) { return cacheClient->getNamespace(n, kj::mv(cfBlobJson), span); - }).orDefault([&]() { - return cacheClient->getDefault(kj::mv(cfBlobJson), span); - }); + }).orDefault([&]() { return cacheClient->getDefault(kj::mv(cfBlobJson), span); }); httpClient = httpClient.attach(kj::mv(span), kj::mv(cacheClient)); return httpClient; } @@ -545,14 +529,13 @@ kj::Own Cache::getHttpClient(IoContext& context, // ======================================================================================= // CacheStorage -CacheStorage::CacheStorage() - : default_(jsg::alloc(nullptr)) {} +CacheStorage::CacheStorage(): default_(jsg::alloc(nullptr)) {} jsg::Promise> CacheStorage::open(jsg::Lock& js, kj::String cacheName) { // Set some reasonable limit to prevent scripts from blowing up our control header size. static constexpr auto MAX_CACHE_NAME_LENGTH = 1024; - JSG_REQUIRE(cacheName.size() < MAX_CACHE_NAME_LENGTH, - TypeError, "Cache name is too long."); // Mah spoon is toooo big. + JSG_REQUIRE(cacheName.size() < MAX_CACHE_NAME_LENGTH, TypeError, + "Cache name is too long."); // Mah spoon is toooo big. // TODO(someday): Implement Cache API in preview. diff --git a/src/workerd/api/cache.h b/src/workerd/api/cache.h index 4592d6b690a..daa4699078c 100644 --- a/src/workerd/api/cache.h +++ b/src/workerd/api/cache.h @@ -43,19 +43,23 @@ class Cache: public jsg::Object { jsg::Promise>> match( jsg::Lock& js, Request::Info request, jsg::Optional options); - jsg::Promise put(jsg::Lock& js, Request::Info request, jsg::Ref response, + jsg::Promise put(jsg::Lock& js, + Request::Info request, + jsg::Ref response, CompatibilityFlags::Reader flags); jsg::Promise delete_( jsg::Lock& js, Request::Info request, jsg::Optional options); // Our cache does not support one-to-many matching, so this is not possible to implement. - jsg::WontImplement matchAll( - jsg::Optional, jsg::Optional) { return {}; } + jsg::WontImplement matchAll(jsg::Optional, jsg::Optional) { + return {}; + } // Our cache does not support cache item enumeration, so this is not possible to implement. - jsg::WontImplement keys( - jsg::Optional, jsg::Optional) { return {}; } + jsg::WontImplement keys(jsg::Optional, jsg::Optional) { + return {}; + } JSG_RESOURCE_TYPE(Cache) { JSG_METHOD(add); @@ -81,8 +85,8 @@ class Cache: public jsg::Object { private: kj::Maybe cacheName; - kj::Own getHttpClient(IoContext& context, - kj::Maybe cfBlobJson, kj::ConstString operationName); + kj::Own getHttpClient( + IoContext& context, kj::Maybe cfBlobJson, kj::ConstString operationName); }; // ======================================================================================= @@ -94,14 +98,24 @@ class CacheStorage: public jsg::Object { jsg::Promise> open(jsg::Lock& js, kj::String cacheName); - jsg::Ref getDefault() { return default_.addRef(); } + jsg::Ref getDefault() { + return default_.addRef(); + } // Our cache does not support namespace enumeration, so none of these are possible to implement. - jsg::WontImplement match(Request::Info, jsg::Optional) { return {}; } - jsg::WontImplement has(kj::String) { return {}; } - jsg::WontImplement delete_(kj::String) { return {}; } - jsg::WontImplement keys() { return {}; } + jsg::WontImplement match(Request::Info, jsg::Optional) { + return {}; + } + jsg::WontImplement has(kj::String) { + return {}; + } + jsg::WontImplement delete_(kj::String) { + return {}; + } + jsg::WontImplement keys() { + return {}; + } JSG_RESOURCE_TYPE(CacheStorage) { JSG_METHOD(open); @@ -121,9 +135,6 @@ class CacheStorage: public jsg::Object { jsg::Ref default_; }; -#define EW_CACHE_ISOLATE_TYPES \ - api::CacheStorage, \ - api::Cache, \ - api::CacheQueryOptions +#define EW_CACHE_ISOLATE_TYPES api::CacheStorage, api::Cache, api::CacheQueryOptions } // namespace workerd::api diff --git a/src/workerd/api/cf-property-test.c++ b/src/workerd/api/cf-property-test.c++ index a1ffde1d157..90ef2422c00 100644 --- a/src/workerd/api/cf-property-test.c++ +++ b/src/workerd/api/cf-property-test.c++ @@ -10,8 +10,7 @@ namespace workerd::api { namespace { KJ_TEST("Test that CfProperty is frozen by default") { - TestFixture fixture({ - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.mainModuleSource = R"SCRIPT( export default { async fetch(request) { request.cf.foo = 100; @@ -24,14 +23,13 @@ KJ_TEST("Test that CfProperty is frozen by default") { auto result = fixture.runRequest(kj::HttpMethod::POST, "http://www.example.com"_kj, "TEST"_kj); KJ_FAIL_REQUIRE("exception expected"); } catch (kj::Exception& e) { - KJ_EXPECT(e.getDescription() == "jsg.TypeError: Cannot add property foo, object is not extensible"_kj); + KJ_EXPECT(e.getDescription() == + "jsg.TypeError: Cannot add property foo, object is not extensible"_kj); } } - KJ_TEST("Test that CfProperty::deepClone returns editable object") { - TestFixture fixture({ - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.mainModuleSource = R"SCRIPT( export default { async fetch(request) { const req = new Request(request); diff --git a/src/workerd/api/cf-property.c++ b/src/workerd/api/cf-property.c++ index 133896e7eb0..6fbed598310 100644 --- a/src/workerd/api/cf-property.c++ +++ b/src/workerd/api/cf-property.c++ @@ -54,9 +54,8 @@ CfProperty::CfProperty(kj::Maybe>&& parsed) { } jsg::Optional CfProperty::get(jsg::Lock& js) { - return getRef(js).map([&js](jsg::JsRef&& ref) mutable { - return ref.getHandle(js); - }); + return getRef(js).map( + [&js](jsg::JsRef&& ref) mutable { return ref.getHandle(js); }); } jsg::Optional> CfProperty::getRef(jsg::Lock& js) { @@ -85,7 +84,6 @@ jsg::Optional> CfProperty::getRef(jsg::Lock& js) { return kj::none; } - kj::Maybe CfProperty::serialize(jsg::Lock& js) { KJ_IF_SOME(cf, value) { KJ_SWITCH_ONEOF(cf) { @@ -143,4 +141,4 @@ void CfProperty::visitForGc(jsg::GcVisitor& visitor) { } } -} // namespace workerd::api +} // namespace workerd::api diff --git a/src/workerd/api/cf-property.h b/src/workerd/api/cf-property.h index 7511c7dc54c..cd7b83c23e7 100644 --- a/src/workerd/api/cf-property.h +++ b/src/workerd/api/cf-property.h @@ -59,5 +59,4 @@ class CfProperty { kj::Maybe>> value; }; - -} // namespace workerd::api +} // namespace workerd::api diff --git a/src/workerd/api/crypto/aes-test.c++ b/src/workerd/api/crypto/aes-test.c++ index dcb2459cba6..39b542d00c5 100644 --- a/src/workerd/api/crypto/aes-test.c++ +++ b/src/workerd/api/crypto/aes-test.c++ @@ -18,8 +18,7 @@ namespace { jsg::V8System v8System; struct CryptoContext: public jsg::Object, public jsg::ContextGlobal { - JSG_RESOURCE_TYPE(CryptoContext) { - } + JSG_RESOURCE_TYPE(CryptoContext) {} }; JSG_DECLARE_ISOLATE_TYPE(CryptoIsolate, CryptoContext); @@ -32,37 +31,32 @@ KJ_TEST("AES-KW key wrap") { auto& js = jsg::Lock::from(isolate); auto rawWrappingKeys = std::array, 3>({ - kj::heapArray({0xe6, 0x95, 0xea, 0xe3, 0xa8, 0xc0, 0x30, - 0xf1, 0x76, 0xe3, 0x0e, 0x8e, 0x36, 0xf8, - 0xf4, 0x31}), - // AES-KW 128 - kj::heapArray( - {0x20, 0xa7, 0x98, 0xd1, 0x82, 0x8c, 0x18, 0x67, - 0xfd, 0xda, 0x16, 0x03, 0x57, 0xc6, 0x32, 0x4f, - 0xcc, 0xe8, 0x08, 0x6d, 0x21, 0xe9, 0x3c, 0x60}), - // AES-KW 192 - kj::heapArray( - {0x52, 0x4b, 0x67, 0x25, 0xe3, 0x56, 0xaa, 0xce, 0x7e, 0x76, 0x9b, - 0x48, 0x92, 0x55, 0x49, 0x06, 0x12, 0x5e, 0xf5, 0xae, 0xce, 0x39, - 0xde, 0xc2, 0x5b, 0x27, 0x33, 0x4e, 0x6e, 0x52, 0x32, 0x4e}), - // AES-KW 256 + kj::heapArray({0xe6, 0x95, 0xea, 0xe3, 0xa8, 0xc0, 0x30, 0xf1, 0x76, 0xe3, 0x0e, + 0x8e, 0x36, 0xf8, 0xf4, 0x31}), + // AES-KW 128 + kj::heapArray({0x20, 0xa7, 0x98, 0xd1, 0x82, 0x8c, 0x18, 0x67, 0xfd, 0xda, 0x16, + 0x03, 0x57, 0xc6, 0x32, 0x4f, 0xcc, 0xe8, 0x08, 0x6d, 0x21, 0xe9, 0x3c, 0x60}), + // AES-KW 192 + kj::heapArray({0x52, 0x4b, 0x67, 0x25, 0xe3, 0x56, 0xaa, 0xce, 0x7e, 0x76, 0x9b, + 0x48, 0x92, 0x55, 0x49, 0x06, 0x12, 0x5e, 0xf5, 0xae, 0xce, 0x39, 0xde, 0xc2, 0x5b, 0x27, + 0x33, 0x4e, 0x6e, 0x52, 0x32, 0x4e}), + // AES-KW 256 }); auto aesKeys = KJ_MAP(rawKey, kj::mv(rawWrappingKeys)) { SubtleCrypto::ImportKeyAlgorithm algorithm = { - .name = kj::str("AES-KW"), + .name = kj::str("AES-KW"), }; bool extractable = false; - return CryptoKey::Impl::importAes( - js, "AES-KW", "raw", kj::mv(rawKey), kj::mv(algorithm), extractable, - {kj::str("wrapKey"), kj::str("unwrapKey")}); + return CryptoKey::Impl::importAes(js, "AES-KW", "raw", kj::mv(rawKey), kj::mv(algorithm), + extractable, {kj::str("wrapKey"), kj::str("unwrapKey")}); }; - auto keyMaterial = kj::heapArray({ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}); + auto keyMaterial = kj::heapArray( + {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}); - for (const auto& aesKey : aesKeys) { + for (const auto& aesKey: aesKeys) { SubtleCrypto::EncryptAlgorithm params; params.name = kj::str("AES-KW"); @@ -87,7 +81,7 @@ KJ_TEST("AES-KW key wrap") { // Disable null pointer checks (a subset of UBSan) here due to the null reference being passed for // jwkHandler. Using attribute push as annotating just the test itself didn't seem to work. #if __clang__ && __has_feature(undefined_behavior_sanitizer) -#pragma clang attribute push (__attribute__((no_sanitize("null"))), apply_to=function) +#pragma clang attribute push(__attribute__((no_sanitize("null"))), apply_to = function) #endif KJ_TEST("AES-CTR key wrap") { // Basic test that let me repro an issue where using an AES key that's not AES-KW would fail to @@ -96,29 +90,22 @@ KJ_TEST("AES-CTR key wrap") { const jsg::TypeHandler* jwkHandler = nullptr; // Not testing JWK here, so valid value isn't needed. - static constexpr kj::byte RAW_KEY_DATA[] = { - 0x52, 0x4b, 0x67, 0x25, 0xe3, 0x56, 0xaa, 0xce, - 0x7e, 0x76, 0x9b, 0x48, 0x92, 0x55, 0x49, 0x06, - 0x12, 0x5e, 0xf5, 0xae, 0xce, 0x39, 0xde, 0xc2, - 0x5b, 0x27, 0x33, 0x4e, 0x6e, 0x52, 0x32, 0x4e - }; + static constexpr kj::byte RAW_KEY_DATA[] = {0x52, 0x4b, 0x67, 0x25, 0xe3, 0x56, 0xaa, 0xce, 0x7e, + 0x76, 0x9b, 0x48, 0x92, 0x55, 0x49, 0x06, 0x12, 0x5e, 0xf5, 0xae, 0xce, 0x39, 0xde, 0xc2, 0x5b, + 0x27, 0x33, 0x4e, 0x6e, 0x52, 0x32, 0x4e}; static constexpr kj::ArrayPtr KEY_DATA(RAW_KEY_DATA, 32); SubtleCrypto subtle; static constexpr auto getWrappingKey = [](jsg::Lock& js, SubtleCrypto& subtle) { - return subtle.importKeySync(js, "raw", - kj::heapArray(KEY_DATA), - SubtleCrypto::ImportKeyAlgorithm { - .name = kj::str("AES-CTR") - }, - false /* extractable */, - { kj::str("wrapKey"), kj::str("unwrapKey") }); + return subtle.importKeySync(js, "raw", kj::heapArray(KEY_DATA), + SubtleCrypto::ImportKeyAlgorithm{.name = kj::str("AES-CTR")}, false /* extractable */, + {kj::str("wrapKey"), kj::str("unwrapKey")}); }; static constexpr auto getEnc = [] { - return SubtleCrypto::EncryptAlgorithm { + return SubtleCrypto::EncryptAlgorithm{ .name = kj::str("AES-CTR"), .counter = kj::arr(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), .length = 5, @@ -126,7 +113,7 @@ KJ_TEST("AES-CTR key wrap") { }; static constexpr auto getImportKeyAlg = [] { - return SubtleCrypto::ImportKeyAlgorithm { + return SubtleCrypto::ImportKeyAlgorithm{ .name = kj::str("AES-CBC"), .length = 256, }; @@ -137,29 +124,23 @@ KJ_TEST("AES-CTR key wrap") { e.getIsolate().runInLockScope([&](CryptoIsolate::Lock& isolateLock) { JSG_WITHIN_CONTEXT_SCOPE(isolateLock, - isolateLock.newContext().getHandle(isolateLock), - [&](jsg::Lock& js) { + isolateLock.newContext().getHandle(isolateLock), [&](jsg::Lock& js) { auto wrappingKey = getWrappingKey(js, subtle); - subtle.importKey( - js, kj::str("raw"), - kj::heapArray(KEY_DATA), - getImportKeyAlg(), - true, kj::arr(kj::str("decrypt"))) - .then(js, [&] (jsg::Lock&, jsg::Ref toWrap) { - return subtle.wrapKey( - js, kj::str("raw"), *toWrap, *wrappingKey, - getEnc(), *jwkHandler); - }).then(js, [&] (jsg::Lock&, kj::Array wrapped) { - return subtle.unwrapKey(js, - kj::str("raw"), - kj::mv(wrapped), - *wrappingKey, - getEnc(), - getImportKeyAlg(), - true, kj::arr(kj::str("encrypt")), *jwkHandler); - }).then(js, [&] (jsg::Lock& js, jsg::Ref unwrapped) { + subtle + .importKey(js, kj::str("raw"), kj::heapArray(KEY_DATA), getImportKeyAlg(), true, + kj::arr(kj::str("decrypt"))) + .then(js, + [&](jsg::Lock&, jsg::Ref toWrap) { + return subtle.wrapKey(js, kj::str("raw"), *toWrap, *wrappingKey, getEnc(), *jwkHandler); + }) + .then(js, + [&](jsg::Lock&, kj::Array wrapped) { + return subtle.unwrapKey(js, kj::str("raw"), kj::mv(wrapped), *wrappingKey, getEnc(), + getImportKeyAlg(), true, kj::arr(kj::str("encrypt")), *jwkHandler); + }) + .then(js, [&](jsg::Lock& js, jsg::Ref unwrapped) { return subtle.exportKey(js, kj::str("raw"), *unwrapped); - }).then(js, [&] (jsg::Lock&, api::SubtleCrypto::ExportKeyData roundTrippedKeyMaterial) { + }).then(js, [&](jsg::Lock&, api::SubtleCrypto::ExportKeyData roundTrippedKeyMaterial) { KJ_ASSERT(roundTrippedKeyMaterial.get>() == KEY_DATA); completed = true; }); @@ -171,7 +152,7 @@ KJ_TEST("AES-CTR key wrap") { KJ_ASSERT(completed, "Microtasks did not run fully."); } #if __clang__ && __has_feature(undefined_behavior_sanitizer) -#pragma clang attribute pop // __attribute__((no_sanitize("null")) +#pragma clang attribute pop // __attribute__((no_sanitize("null")) #endif } // namespace diff --git a/src/workerd/api/crypto/aes.c++ b/src/workerd/api/crypto/aes.c++ index 65646064538..dda1253e808 100644 --- a/src/workerd/api/crypto/aes.c++ +++ b/src/workerd/api/crypto/aes.c++ @@ -15,21 +15,29 @@ namespace workerd::api { namespace { auto lookupAesCbcType(uint bitLength) { switch (bitLength) { - case 128: return EVP_aes_128_cbc(); - case 192: return EVP_aes_192_cbc(); - case 256: return EVP_aes_256_cbc(); - default: KJ_FAIL_ASSERT("CryptoKey has invalid data length", bitLength); - // Assert because the data length must have come from a key we created! + case 128: + return EVP_aes_128_cbc(); + case 192: + return EVP_aes_192_cbc(); + case 256: + return EVP_aes_256_cbc(); + default: + KJ_FAIL_ASSERT("CryptoKey has invalid data length", bitLength); + // Assert because the data length must have come from a key we created! } } auto lookupAesGcmType(uint bitLength) { switch (bitLength) { - case 128: return EVP_aes_128_gcm(); - case 192: return EVP_aes_192_gcm(); - case 256: return EVP_aes_256_gcm(); - default: KJ_FAIL_ASSERT("CryptoKey has invalid data length", bitLength); - // Assert because the data length must have come from a key we created! + case 128: + return EVP_aes_128_gcm(); + case 192: + return EVP_aes_192_gcm(); + case 256: + return EVP_aes_256_gcm(); + default: + KJ_FAIL_ASSERT("CryptoKey has invalid data length", bitLength); + // Assert because the data length must have come from a key we created! } } @@ -42,14 +50,18 @@ void validateAesGcmTagLength(int tagLength) { case 104: case 112: case 120: - case 128: break; + case 128: + break; default: JSG_FAIL_REQUIRE(DOMOperationError, "Invalid AES-GCM tag length ", tagLength, "."); } } -int decryptFinalHelper(kj::StringPtr algorithm, size_t inputLength, - size_t outputLength, EVP_CIPHER_CTX* cipherCtx, kj::byte* out) { +int decryptFinalHelper(kj::StringPtr algorithm, + size_t inputLength, + size_t outputLength, + EVP_CIPHER_CTX* cipherCtx, + kj::byte* out) { // EVP_DecryptFinal_ex() failures can mean a mundane decryption failure, so we have to be careful // with error handling when calling it. We can't use our usual OSSLCALL() macro, because that // throws an unhelpful opaque OperationError. @@ -70,17 +82,18 @@ int decryptFinalHelper(kj::StringPtr algorithm, size_t inputLength, // OperationError for consistency with our OSSLCALL() macro. Notably, AES-GCM tag authentication // failures don't produce any error code, though they should probably be BAD_DECRYPT. JSG_REQUIRE(ec == 0 || ec == ERR_PACK(ERR_LIB_CIPHER, CIPHER_R_BAD_DECRYPT) || - ec == ERR_PACK(ERR_LIB_CIPHER, CIPHER_R_WRONG_FINAL_BLOCK_LENGTH), InternalDOMOperationError, - "Unexpected issue decrypting", internalDescribeOpensslErrors()); + ec == ERR_PACK(ERR_LIB_CIPHER, CIPHER_R_WRONG_FINAL_BLOCK_LENGTH), + InternalDOMOperationError, "Unexpected issue decrypting", internalDescribeOpensslErrors()); // Consume the error since it's one we were expecting. clearErrorOnReturn.consumeError(); // Otherwise, tell the script author they gave us garbage. - JSG_FAIL_REQUIRE(DOMOperationError, "Decryption failed. This could be due " + JSG_FAIL_REQUIRE(DOMOperationError, + "Decryption failed. This could be due " "to a ciphertext authentication failure, bad padding, incorrect CryptoKey, or another " - "algorithm-specific reason. Input length was ", inputLength,", output length expected to be ", - outputLength, " for ", algorithm); + "algorithm-specific reason. Input length was ", + inputLength, ", output length expected to be ", outputLength, " for ", algorithm); } // NOTE: The OpenSSL calls to implement AES-GCM and AES-CBC are quite similar. If you update one @@ -91,10 +104,13 @@ int decryptFinalHelper(kj::StringPtr algorithm, size_t inputLength, // concrete implementations to only define encrypt/decrypt. class AesKeyBase: public CryptoKey::Impl { public: - explicit AesKeyBase(kj::Array keyData, CryptoKey::AesKeyAlgorithm keyAlgorithm, - bool extractable, CryptoKeyUsageSet usages) + explicit AesKeyBase(kj::Array keyData, + CryptoKey::AesKeyAlgorithm keyAlgorithm, + bool extractable, + CryptoKeyUsageSet usages) : CryptoKey::Impl(extractable, usages), - keyData(kj::mv(keyData)), keyAlgorithm(kj::mv(keyAlgorithm)) {} + keyData(kj::mv(keyData)), + keyAlgorithm(kj::mv(keyAlgorithm)) {} protected: kj::StringPtr getAlgorithmName() const override final { @@ -109,23 +125,28 @@ protected: bool equals(const kj::Array& other) const override final { return keyData.size() == other.size() && - CRYPTO_memcmp(keyData.begin(), other.begin(), keyData.size()) == 0; + CRYPTO_memcmp(keyData.begin(), other.begin(), keyData.size()) == 0; } - kj::StringPtr jsgGetMemoryName() const override { return "AesKeyBase"_kjc; } - size_t jsgGetMemorySelfSize() const override { return sizeof(AesKeyBase); } + kj::StringPtr jsgGetMemoryName() const override { + return "AesKeyBase"_kjc; + } + size_t jsgGetMemorySelfSize() const override { + return sizeof(AesKeyBase); + } void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const override { tracker.trackFieldWithSize("keyData", keyData.size()); tracker.trackField("keyAlgorithm", keyAlgorithm); } private: - CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override final { return keyAlgorithm; } + CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override final { + return keyAlgorithm; + } SubtleCrypto::ExportKeyData exportKey(kj::StringPtr format) const override final { - JSG_REQUIRE(format == "raw" || format == "jwk", DOMNotSupportedError, - getAlgorithmName(), " key only supports exporting \"raw\" & \"jwk\", not \"", format, - "\"."); + JSG_REQUIRE(format == "raw" || format == "jwk", DOMNotSupportedError, getAlgorithmName(), + " key only supports exporting \"raw\" & \"jwk\", not \"", format, "\"."); if (format == "jwk") { auto lengthInBytes = keyData.size(); @@ -135,8 +156,8 @@ private: #ifdef KJ_DEBUG static constexpr auto expectedModes = {"GCM", "KW", "CTR", "CBC"}; - KJ_DASSERT(expectedModes.end() != std::find( - expectedModes.begin(), expectedModes.end(), aesMode)); + KJ_DASSERT( + expectedModes.end() != std::find(expectedModes.begin(), expectedModes.end(), aesMode)); #endif SubtleCrypto::JsonWebKey jwk; @@ -168,16 +189,17 @@ protected: class AesGcmKey final: public AesKeyBase { public: - explicit AesGcmKey(kj::Array keyData, CryptoKey::AesKeyAlgorithm keyAlgorithm, - bool extractable, CryptoKeyUsageSet usages) + explicit AesGcmKey(kj::Array keyData, + CryptoKey::AesKeyAlgorithm keyAlgorithm, + bool extractable, + CryptoKeyUsageSet usages) : AesKeyBase(kj::mv(keyData), kj::mv(keyAlgorithm), extractable, usages) {} private: - kj::Array encrypt( - SubtleCrypto::EncryptAlgorithm&& algorithm, + kj::Array encrypt(SubtleCrypto::EncryptAlgorithm&& algorithm, kj::ArrayPtr plainText) const override { - kj::ArrayPtr iv = JSG_REQUIRE_NONNULL(algorithm.iv, TypeError, - "Missing field \"iv\" in \"algorithm\"."); + kj::ArrayPtr iv = + JSG_REQUIRE_NONNULL(algorithm.iv, TypeError, "Missing field \"iv\" in \"algorithm\"."); JSG_REQUIRE(iv.size() != 0, DOMOperationError, "AES-GCM IV must not be empty."); auto additionalData = algorithm.additionalData.orDefault(kj::Array()).asPtr(); @@ -199,18 +221,16 @@ private: // Set up the cipher context with the initialization vector. We pass nullptrs for the key data // and initialization vector because we may need to override the default IV length. OSSLCALL(EVP_EncryptInit_ex(cipherCtx.get(), type, nullptr, nullptr, nullptr)); - OSSLCALL(EVP_CIPHER_CTX_ctrl(cipherCtx.get(), EVP_CTRL_GCM_SET_IVLEN, - iv.size(), nullptr)); - OSSLCALL(EVP_EncryptInit_ex(cipherCtx.get(), nullptr, nullptr, keyData.begin(), - iv.begin())); + OSSLCALL(EVP_CIPHER_CTX_ctrl(cipherCtx.get(), EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr)); + OSSLCALL(EVP_EncryptInit_ex(cipherCtx.get(), nullptr, nullptr, keyData.begin(), iv.begin())); if (additionalData.size() > 0) { // Run the engine with the additional data, which will presumably be transmitted alongside the // cipher text in plain text. I noticed that if I call EncryptUpdate with 0-length AAD here, // the subsequent call to EncryptUpdate will fail, thus the if-check. int dummy; - OSSLCALL(EVP_EncryptUpdate(cipherCtx.get(), nullptr, &dummy, - additionalData.begin(), additionalData.size())); + OSSLCALL(EVP_EncryptUpdate( + cipherCtx.get(), nullptr, &dummy, additionalData.begin(), additionalData.size())); } // We make two cipher calls: EVP_EncryptUpdate() and EVP_EncryptFinal_ex(). AES-GCM behaves like @@ -222,38 +242,39 @@ private: // Perform the actual encryption. int cipherSize = 0; - OSSLCALL(EVP_EncryptUpdate(cipherCtx.get(), cipherText.begin(), &cipherSize, - plainText.begin(), plainText.size())); + OSSLCALL(EVP_EncryptUpdate( + cipherCtx.get(), cipherText.begin(), &cipherSize, plainText.begin(), plainText.size())); KJ_ASSERT(cipherSize == plainText.size(), "EVP_EncryptUpdate should encrypt all at once"); int finalCipherSize = 0; - OSSLCALL(EVP_EncryptFinal_ex(cipherCtx.get(), cipherText.begin() + cipherSize, - &finalCipherSize)); + OSSLCALL( + EVP_EncryptFinal_ex(cipherCtx.get(), cipherText.begin() + cipherSize, &finalCipherSize)); KJ_ASSERT(finalCipherSize == 0, "EVP_EncryptFinal_ex should not output any data"); // Concatenate the tag onto the cipher text. KJ_ASSERT(cipherSize + tagByteSize == cipherText.size(), "imminent buffer overrun"); - OSSLCALL(EVP_CIPHER_CTX_ctrl(cipherCtx.get(), EVP_CTRL_GCM_GET_TAG, - tagByteSize, cipherText.begin() + cipherSize)); + OSSLCALL(EVP_CIPHER_CTX_ctrl( + cipherCtx.get(), EVP_CTRL_GCM_GET_TAG, tagByteSize, cipherText.begin() + cipherSize)); cipherSize += tagByteSize; KJ_ASSERT(cipherSize == cipherText.size(), "buffer overrun"); return cipherText; } - kj::Array decrypt( - SubtleCrypto::EncryptAlgorithm&& algorithm, + kj::Array decrypt(SubtleCrypto::EncryptAlgorithm&& algorithm, kj::ArrayPtr cipherText) const override { - kj::ArrayPtr iv = JSG_REQUIRE_NONNULL(algorithm.iv, TypeError, - "Missing field \"iv\" in \"algorithm\"."); + kj::ArrayPtr iv = + JSG_REQUIRE_NONNULL(algorithm.iv, TypeError, "Missing field \"iv\" in \"algorithm\"."); JSG_REQUIRE(iv.size() != 0, DOMOperationError, "AES-GCM IV must not be empty."); int tagLength = algorithm.tagLength.orDefault(128); validateAesGcmTagLength(tagLength); - JSG_REQUIRE(cipherText.size() >= tagLength / 8, DOMOperationError, - "Ciphertext length of ", cipherText.size() * 8, " bits must be greater than or equal to " - "the size of the AES-GCM tag length of ", tagLength, " bits."); + JSG_REQUIRE(cipherText.size() >= tagLength / 8, DOMOperationError, "Ciphertext length of ", + cipherText.size() * 8, + " bits must be greater than or equal to " + "the size of the AES-GCM tag length of ", + tagLength, " bits."); auto additionalData = algorithm.additionalData.orDefault(kj::Array()).asPtr(); @@ -263,16 +284,14 @@ private: auto type = lookupAesGcmType(keyData.size() * 8); OSSLCALL(EVP_DecryptInit_ex(cipherCtx.get(), type, nullptr, nullptr, nullptr)); - OSSLCALL(EVP_CIPHER_CTX_ctrl(cipherCtx.get(), EVP_CTRL_GCM_SET_IVLEN, - iv.size(), nullptr)); - OSSLCALL(EVP_DecryptInit_ex(cipherCtx.get(), nullptr, nullptr, keyData.begin(), - iv.begin())); + OSSLCALL(EVP_CIPHER_CTX_ctrl(cipherCtx.get(), EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr)); + OSSLCALL(EVP_DecryptInit_ex(cipherCtx.get(), nullptr, nullptr, keyData.begin(), iv.begin())); int plainSize = 0; if (additionalData.size() > 0) { - OSSLCALL(EVP_DecryptUpdate(cipherCtx.get(), nullptr, &plainSize, - additionalData.begin(), additionalData.size())); + OSSLCALL(EVP_DecryptUpdate( + cipherCtx.get(), nullptr, &plainSize, additionalData.begin(), additionalData.size())); plainSize = 0; } @@ -283,7 +302,7 @@ private: // Perform the actual decryption. OSSLCALL(EVP_DecryptUpdate(cipherCtx.get(), plainText.begin(), &plainSize, - actualCipherText.begin(), actualCipherText.size())); + actualCipherText.begin(), actualCipherText.size())); KJ_ASSERT(plainSize == plainText.size()); // NOTE: We const_cast tagText here. EVP_CIPHER_CTX_ctrl() is used to set various @@ -295,7 +314,7 @@ private: // This little hack seems like a lesser evil than accepting the plaintext as mutable in every // decrypt implementation function interface. OSSLCALL(EVP_CIPHER_CTX_ctrl(cipherCtx.get(), EVP_CTRL_GCM_SET_TAG, tagLength / 8, - const_cast(tagText.begin()))); + const_cast(tagText.begin()))); plainSize += decryptFinalHelper(getAlgorithmName(), actualCipherText.size(), plainSize, cipherCtx.get(), plainText.begin() + plainSize); @@ -307,16 +326,17 @@ private: class AesCbcKey final: public AesKeyBase { public: - explicit AesCbcKey(kj::Array keyData, CryptoKey::AesKeyAlgorithm keyAlgorithm, - bool extractable, CryptoKeyUsageSet usages) + explicit AesCbcKey(kj::Array keyData, + CryptoKey::AesKeyAlgorithm keyAlgorithm, + bool extractable, + CryptoKeyUsageSet usages) : AesKeyBase(kj::mv(keyData), kj::mv(keyAlgorithm), extractable, usages) {} private: - kj::Array encrypt( - SubtleCrypto::EncryptAlgorithm&& algorithm, + kj::Array encrypt(SubtleCrypto::EncryptAlgorithm&& algorithm, kj::ArrayPtr plainText) const override { - kj::ArrayPtr iv = JSG_REQUIRE_NONNULL(algorithm.iv, TypeError, - "Missing field \"iv\" in \"algorithm\"."); + kj::ArrayPtr iv = + JSG_REQUIRE_NONNULL(algorithm.iv, TypeError, "Missing field \"iv\" in \"algorithm\"."); JSG_REQUIRE(iv.size() == 16, DOMOperationError, "AES-CBC IV must be 16 bytes long (provided ", iv.size(), " bytes)."); @@ -326,8 +346,7 @@ private: auto type = lookupAesCbcType(keyData.size() * 8); // Set up the cipher context with the initialization vector. - OSSLCALL(EVP_EncryptInit_ex(cipherCtx.get(), type, nullptr, keyData.begin(), - iv.begin())); + OSSLCALL(EVP_EncryptInit_ex(cipherCtx.get(), type, nullptr, keyData.begin(), iv.begin())); auto blockSize = EVP_CIPHER_CTX_block_size(cipherCtx.get()); size_t paddingSize = blockSize - (plainText.size() % blockSize); @@ -339,28 +358,27 @@ private: // takes care of it for us by default in EVP_EncryptFinal_ex(). int cipherSize = 0; - OSSLCALL(EVP_EncryptUpdate(cipherCtx.get(), cipherText.begin(), &cipherSize, - plainText.begin(), plainText.size())); + OSSLCALL(EVP_EncryptUpdate( + cipherCtx.get(), cipherText.begin(), &cipherSize, plainText.begin(), plainText.size())); KJ_ASSERT(cipherSize <= cipherText.size(), "buffer overrun"); KJ_ASSERT(cipherSize + blockSize <= cipherText.size(), "imminent buffer overrun"); int finalCipherSize = 0; - OSSLCALL(EVP_EncryptFinal_ex(cipherCtx.get(), cipherText.begin() + cipherSize, - &finalCipherSize)); + OSSLCALL( + EVP_EncryptFinal_ex(cipherCtx.get(), cipherText.begin() + cipherSize, &finalCipherSize)); cipherSize += finalCipherSize; KJ_ASSERT(cipherSize == cipherText.size(), "buffer overrun"); return cipherText; } - kj::Array decrypt( - SubtleCrypto::EncryptAlgorithm&& algorithm, + kj::Array decrypt(SubtleCrypto::EncryptAlgorithm&& algorithm, kj::ArrayPtr cipherText) const override { - kj::ArrayPtr iv = JSG_REQUIRE_NONNULL(algorithm.iv, TypeError, - "Missing field \"iv\" in \"algorithm\"."); + kj::ArrayPtr iv = + JSG_REQUIRE_NONNULL(algorithm.iv, TypeError, "Missing field \"iv\" in \"algorithm\"."); - JSG_REQUIRE(iv.size() == 16, DOMOperationError, - "AES-CBC IV must be 16 bytes long (provided ", iv.size(), ")."); + JSG_REQUIRE(iv.size() == 16, DOMOperationError, "AES-CBC IV must be 16 bytes long (provided ", + iv.size(), ")."); auto cipherCtx = kj::disposeWith(EVP_CIPHER_CTX_new()); KJ_ASSERT(cipherCtx.get() != nullptr); @@ -368,8 +386,7 @@ private: auto type = lookupAesCbcType(keyData.size() * 8); // Set up the cipher context with the initialization vector. - OSSLCALL(EVP_DecryptInit_ex(cipherCtx.get(), type, nullptr, keyData.begin(), - iv.begin())); + OSSLCALL(EVP_DecryptInit_ex(cipherCtx.get(), type, nullptr, keyData.begin(), iv.begin())); int plainSize = 0; auto blockSize = EVP_CIPHER_CTX_block_size(cipherCtx.get()); @@ -377,8 +394,8 @@ private: auto plainText = kj::heapArray(cipherText.size() + ((blockSize > 1) ? blockSize : 0)); // Perform the actual decryption. - OSSLCALL(EVP_DecryptUpdate(cipherCtx.get(), plainText.begin(), &plainSize, - cipherText.begin(), cipherText.size())); + OSSLCALL(EVP_DecryptUpdate( + cipherCtx.get(), plainText.begin(), &plainSize, cipherText.begin(), cipherText.size())); KJ_ASSERT(plainSize + ((blockSize > 1) ? blockSize : 0) <= plainText.size()); plainSize += decryptFinalHelper(getAlgorithmName(), cipherText.size(), plainSize, @@ -394,18 +411,18 @@ class AesCtrKey final: public AesKeyBase { static constexpr size_t expectedCounterByteSize = 16; public: - explicit AesCtrKey(kj::Array keyData, CryptoKey::AesKeyAlgorithm keyAlgorithm, - bool extractable, CryptoKeyUsageSet usages) + explicit AesCtrKey(kj::Array keyData, + CryptoKey::AesKeyAlgorithm keyAlgorithm, + bool extractable, + CryptoKeyUsageSet usages) : AesKeyBase(kj::mv(keyData), kj::mv(keyAlgorithm), extractable, usages) {} - kj::Array encrypt( - SubtleCrypto::EncryptAlgorithm&& algorithm, + kj::Array encrypt(SubtleCrypto::EncryptAlgorithm&& algorithm, kj::ArrayPtr plainText) const override { return encryptOrDecrypt(kj::mv(algorithm), plainText); } - kj::Array decrypt( - SubtleCrypto::EncryptAlgorithm&& algorithm, + kj::Array decrypt(SubtleCrypto::EncryptAlgorithm&& algorithm, kj::ArrayPtr cipherText) const override { return encryptOrDecrypt(kj::mv(algorithm), cipherText); } @@ -413,25 +430,28 @@ public: protected: static const EVP_CIPHER& lookupAesType(size_t keyLengthBytes) { switch (keyLengthBytes) { - case 16: return *EVP_aes_128_ctr(); + case 16: + return *EVP_aes_128_ctr(); // NOTE: FWIW Chrome intentionally doesn't support 192 (http://crbug.com/533699) & at one // point in removal of the 192 variant was scheduled for removal from BoringSSL. However, we // do support it for completeness (as does Firefox). - case 24: return *EVP_aes_192_ctr(); - case 32: return *EVP_aes_256_ctr(); + case 24: + return *EVP_aes_192_ctr(); + case 32: + return *EVP_aes_256_ctr(); } KJ_FAIL_ASSERT("CryptoKey has invalid data length"); } kj::Array encryptOrDecrypt( SubtleCrypto::EncryptAlgorithm&& algorithm, kj::ArrayPtr data) const { - auto& counter = JSG_REQUIRE_NONNULL(algorithm.counter, TypeError, - "Missing \"counter\" member in \"algorithm\"."); + auto& counter = JSG_REQUIRE_NONNULL( + algorithm.counter, TypeError, "Missing \"counter\" member in \"algorithm\"."); JSG_REQUIRE(counter.size() == expectedCounterByteSize, DOMOperationError, "Counter must have length of 16 bytes (provided ", counter.size(), ")."); - auto& counterBitLength = JSG_REQUIRE_NONNULL(algorithm.length, TypeError, - "Missing \"length\" member in \"algorithm\"."); + auto& counterBitLength = JSG_REQUIRE_NONNULL( + algorithm.length, TypeError, "Missing \"length\" member in \"algorithm\"."); // Web IDL defines an octet as [0, 255] which explains why the spec here only calls out != 0 and // <= 128, which implies the intended range must be [1, 128] which is what we enforce here. @@ -442,8 +462,8 @@ protected: // * https://heycam.github.io/webidl/#EnforceRange, // * https://heycam.github.io/webidl/#es-octet // * https://heycam.github.io/webidl/#abstract-opdef-converttoint - JSG_REQUIRE(counterBitLength > 0 && counterBitLength <= 128, - DOMOperationError, "Invalid counter of ", counterBitLength, " bits length provided."); + JSG_REQUIRE(counterBitLength > 0 && counterBitLength <= 128, DOMOperationError, + "Invalid counter of ", counterBitLength, " bits length provided."); const auto& cipher = lookupAesType(keyData.size()); @@ -460,12 +480,13 @@ protected: // Now figure out how many AES blocks we'll process/how many times to increment the counter. auto numOutputBlocks = newBignum(); - JSG_REQUIRE(BN_set_word(numOutputBlocks.get(), integerCeilDivision(result.size(), - static_cast(AES_BLOCK_SIZE))), InternalDOMOperationError, "Error doing ", - getAlgorithmName(), " encrypt/decrypt", internalDescribeOpensslErrors()); + JSG_REQUIRE(BN_set_word(numOutputBlocks.get(), + integerCeilDivision(result.size(), static_cast(AES_BLOCK_SIZE))), + InternalDOMOperationError, "Error doing ", getAlgorithmName(), " encrypt/decrypt", + internalDescribeOpensslErrors()); - JSG_REQUIRE(BN_cmp(numOutputBlocks.get(), numCounterValues.get()) <= 0, - DOMOperationError, "Counter block values will repeat", tryDescribeOpensslErrors()); + JSG_REQUIRE(BN_cmp(numOutputBlocks.get(), numCounterValues.get()) <= 0, DOMOperationError, + "Counter block values will repeat", tryDescribeOpensslErrors()); auto numBlocksUntilReset = newBignum(); // The number of blocks that can be encrypted without overflowing the counter. Subsequent @@ -501,15 +522,15 @@ protected: } } - process(&cipher, data.slice(inputSizePart1, data.size()), counter, result.slice( - inputSizePart1, result.size())); + process(&cipher, data.slice(inputSizePart1, data.size()), counter, + result.slice(inputSizePart1, result.size())); return result.releaseAsArray(); } private: - kj::Own getCounter(kj::ArrayPtr counterBlock, - const unsigned counterBitLength) const { + kj::Own getCounter( + kj::ArrayPtr counterBlock, const unsigned counterBitLength) const { // See GetCounter from https://chromium.googlesource.com/chromium/src/+/refs/tags/91.0.4458.2/components/webcrypto/algorithms/aes_ctr.cc#86 // The counter is the rightmost "counterBitLength" of the block as a big-endian number. KJ_DASSERT(counterBlock.size() == expectedCounterByteSize); @@ -518,12 +539,11 @@ private: if (remainderBits == 0) { // Multiple of 8 bits, then can pass the remainder to BN_bin2bn (binary to bignum). auto byteLength = counterBitLength / 8; - auto remainingCounter = counterBlock.slice(expectedCounterByteSize - byteLength, - counterBlock.size()); + auto remainingCounter = + counterBlock.slice(expectedCounterByteSize - byteLength, counterBlock.size()); - return JSG_REQUIRE_NONNULL(toBignum(remainingCounter.asBytes()), - InternalDOMOperationError, "Error doing ", getAlgorithmName(), - " encrypt/decrypt", internalDescribeOpensslErrors()); + return JSG_REQUIRE_NONNULL(toBignum(remainingCounter.asBytes()), InternalDOMOperationError, + "Error doing ", getAlgorithmName(), " encrypt/decrypt", internalDescribeOpensslErrors()); } // Convert the counter but zero out the topmost bits so that we can convert to bignum from a @@ -534,8 +554,8 @@ private: KJ_DASSERT(byteLength > 0, counterBitLength, remainderBits); KJ_DASSERT(byteLength <= expectedCounterByteSize, counterBitLength, counterBlock.size()); - auto counterToProcess = counterBlock.slice(expectedCounterByteSize - byteLength, - counterBlock.size()); + auto counterToProcess = + counterBlock.slice(expectedCounterByteSize - byteLength, counterBlock.size()); auto previous = counterToProcess[0]; counterToProcess[0] &= ~(0xFF << remainderBits); KJ_DEFER(counterToProcess[0] = previous); @@ -547,8 +567,10 @@ private: "Error doing ", getAlgorithmName(), " encrypt/decrypt", internalDescribeOpensslErrors()); } - void process(const EVP_CIPHER* cipher, kj::ArrayPtr input, - kj::ArrayPtr counter, kj::ArrayPtr output) const { + void process(const EVP_CIPHER* cipher, + kj::ArrayPtr input, + kj::ArrayPtr counter, + kj::ArrayPtr output) const { // Workers are limited to 128MB so this isn't actually a realistic concern, but sanity check. JSG_REQUIRE(input.size() < INT_MAX, DOMOperationError, "Input is too large to encrypt."); @@ -557,36 +579,40 @@ private: // For CTR, it really does not matter whether we are encrypting or decrypting, so set enc to 0. JSG_REQUIRE(EVP_CipherInit_ex(cipherContext.get(), cipher, nullptr, - keyData.asPtr().asBytes().begin(), counter.asBytes().begin(), 0), + keyData.asPtr().asBytes().begin(), counter.asBytes().begin(), 0), InternalDOMOperationError, "Error doing ", getAlgorithmName(), " encrypt/decrypt", internalDescribeOpensslErrors()); int outputLength = 0; JSG_REQUIRE(EVP_CipherUpdate(cipherContext.get(), output.begin(), &outputLength, - input.asBytes().begin(), input.size()), InternalDOMOperationError, "Error doing ", - getAlgorithmName(), " encrypt/decrypt", internalDescribeOpensslErrors()); + input.asBytes().begin(), input.size()), + InternalDOMOperationError, "Error doing ", getAlgorithmName(), " encrypt/decrypt", + internalDescribeOpensslErrors()); KJ_DASSERT(outputLength >= 0 && outputLength <= output.size(), outputLength, output.size()); int finalOutputChunkLength = 0; auto finalizationBuffer = output.slice(outputLength, output.size()).asBytes().begin(); - JSG_REQUIRE(EVP_CipherFinal_ex(cipherContext.get(), finalizationBuffer, - &finalOutputChunkLength), InternalDOMOperationError, "Error doing ", getAlgorithmName(), - " encrypt/decrypt", internalDescribeOpensslErrors()); + JSG_REQUIRE( + EVP_CipherFinal_ex(cipherContext.get(), finalizationBuffer, &finalOutputChunkLength), + InternalDOMOperationError, "Error doing ", getAlgorithmName(), " encrypt/decrypt", + internalDescribeOpensslErrors()); KJ_DASSERT(finalOutputChunkLength >= 0 && finalOutputChunkLength <= output.size(), finalOutputChunkLength, output.size()); JSG_REQUIRE(static_cast(outputLength) + static_cast(finalOutputChunkLength) == - input.size(), InternalDOMOperationError, "Error doing ", getAlgorithmName(), - " encrypt/decrypt."); + input.size(), + InternalDOMOperationError, "Error doing ", getAlgorithmName(), " encrypt/decrypt."); } }; class AesKwKey final: public AesKeyBase { public: - explicit AesKwKey(kj::Array keyData, CryptoKey::AesKeyAlgorithm keyAlgorithm, - bool extractable, CryptoKeyUsageSet usages) + explicit AesKwKey(kj::Array keyData, + CryptoKey::AesKeyAlgorithm keyAlgorithm, + bool extractable, + CryptoKeyUsageSet usages) : AesKeyBase(kj::mv(keyData), kj::mv(keyAlgorithm), extractable, usages) {} kj::Array wrapKey(SubtleCrypto::EncryptAlgorithm&& algorithm, @@ -600,8 +626,10 @@ public: unwrappedKey.size() * 8, " bits."); JSG_REQUIRE(unwrappedKey.size() >= 16 && unwrappedKey.size() <= SIZE_MAX - 8, DOMOperationError, - "Unwrapped key has length ", unwrappedKey.size(), " bytes but it should be greater than or " - "equal to 16 and less than or equal to ", SIZE_MAX - 8); + "Unwrapped key has length ", unwrappedKey.size(), + " bytes but it should be greater than or " + "equal to 16 and less than or equal to ", + SIZE_MAX - 8); kj::Vector wrapped(unwrappedKey.size() + 8); wrapped.resize(unwrappedKey.size() + 8); @@ -612,9 +640,10 @@ public: InternalDOMOperationError, "Error doing ", getAlgorithmName(), " key wrapping", internalDescribeOpensslErrors()); - JSG_REQUIRE(wrapped.size() == AES_wrap_key(&aesKey, nullptr, wrapped.begin(), - unwrappedKey.begin(), unwrappedKey.size()), DOMOperationError, getAlgorithmName(), - " key wrapping failed", tryDescribeOpensslErrors()); + JSG_REQUIRE(wrapped.size() == + AES_wrap_key( + &aesKey, nullptr, wrapped.begin(), unwrappedKey.begin(), unwrappedKey.size()), + DOMOperationError, getAlgorithmName(), " key wrapping failed", tryDescribeOpensslErrors()); return wrapped.releaseAsArray(); } @@ -644,16 +673,19 @@ public: // null for the IV value here will tell OpenSSL to validate using the default IV from RFC3394. // https://github.com/openssl/openssl/blob/13a574d8bb2523181f8150de49bc041c9841f59d/crypto/modes/wrap128.c - JSG_REQUIRE(unwrapped.size() == AES_unwrap_key(&aesKey, nullptr, unwrapped.begin(), - wrappedKey.begin(), wrappedKey.size()), DOMOperationError, getAlgorithmName(), - " key unwrapping failed", tryDescribeOpensslErrors()); + JSG_REQUIRE(unwrapped.size() == + AES_unwrap_key( + &aesKey, nullptr, unwrapped.begin(), wrappedKey.begin(), wrappedKey.size()), + DOMOperationError, getAlgorithmName(), " key unwrapping failed", + tryDescribeOpensslErrors()); return unwrapped.releaseAsArray(); } }; -CryptoKeyUsageSet validateAesUsages(CryptoKeyUsageSet::Context ctx, kj::StringPtr normalizedName, - kj::ArrayPtr keyUsages) { +CryptoKeyUsageSet validateAesUsages(CryptoKeyUsageSet::Context ctx, + kj::StringPtr normalizedName, + kj::ArrayPtr keyUsages) { // AES-CTR, AES-CBC, AES-GCM, and AES-KW all share the same logic for operations, with the only // difference being the valid usages. CryptoKeyUsageSet validUsages = CryptoKeyUsageSet::wrapKey() | CryptoKeyUsageSet::unwrapKey(); @@ -665,20 +697,22 @@ CryptoKeyUsageSet validateAesUsages(CryptoKeyUsageSet::Context ctx, kj::StringPt } // namespace -kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateAes( - jsg::Lock& js, kj::StringPtr normalizedName, - SubtleCrypto::GenerateKeyAlgorithm&& algorithm, bool extractable, - kj::ArrayPtr keyUsages) { +kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateAes(jsg::Lock& js, + kj::StringPtr normalizedName, + SubtleCrypto::GenerateKeyAlgorithm&& algorithm, + bool extractable, + kj::ArrayPtr keyUsages) { CryptoKeyUsageSet usages = validateAesUsages(CryptoKeyUsageSet::Context::generate, normalizedName, keyUsages); - auto length = JSG_REQUIRE_NONNULL(algorithm.length, TypeError, - "Missing field \"length\" in \"algorithm\"."); + auto length = JSG_REQUIRE_NONNULL( + algorithm.length, TypeError, "Missing field \"length\" in \"algorithm\"."); switch (length) { case 128: case 192: - case 256: break; + case 256: + break; default: JSG_FAIL_REQUIRE(DOMOperationError, "Generated AES key length must be 128, 192, or 256 bits but requested ", length, "."); @@ -706,10 +740,12 @@ kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateAes( return jsg::alloc(kj::mv(keyImpl)); } -kj::Own CryptoKey::Impl::importAes( - jsg::Lock& js, kj::StringPtr normalizedName, kj::StringPtr format, +kj::Own CryptoKey::Impl::importAes(jsg::Lock& js, + kj::StringPtr normalizedName, + kj::StringPtr format, SubtleCrypto::ImportKeyData keyData, - SubtleCrypto::ImportKeyAlgorithm&& algorithm, bool extractable, + SubtleCrypto::ImportKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages) { CryptoKeyUsageSet usages = validateAesUsages(CryptoKeyUsageSet::Context::importSecret, normalizedName, keyUsages); @@ -722,7 +758,8 @@ kj::Own CryptoKey::Impl::importAes( switch (keyDataArray.size() * 8) { case 128: case 192: - case 256: break; + case 256: + break; default: JSG_FAIL_REQUIRE(DOMDataError, "Imported AES key length must be 128, 192, or 256 bits but provided ", @@ -734,7 +771,8 @@ kj::Own CryptoKey::Impl::importAes( auto& keyDataJwk = keyData.get(); JSG_REQUIRE(keyDataJwk.kty == "oct", DOMDataError, "Symmetric \"jwk\" key import requires a JSON Web Key with Key Type parameter " - "\"kty\" equal to \"oct\" (encountered \"", keyDataJwk.kty, "\")."); + "\"kty\" equal to \"oct\" (encountered \"", + keyDataJwk.kty, "\")."); // https://www.rfc-editor.org/rfc/rfc7518.txt Section 6.1 keyDataArray = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.k), DOMDataError, "Symmetric \"jwk\" key import requires a base64Url encoding of the key."); @@ -788,9 +826,10 @@ kj::Own CryptoKey::Impl::importAes( // must be the value for `use'? Or is there something else? KJ_IF_SOME(e, keyDataJwk.ext) { - JSG_REQUIRE(e || !extractable, DOMDataError, - "\"jwk\" key has value \"", e ? "true" : "false", "\", for \"ext\" that is incompatible " - "with import extractability value \"", extractable ? "true" : "false", "\"."); + JSG_REQUIRE(e || !extractable, DOMDataError, "\"jwk\" key has value \"", e ? "true" : "false", + "\", for \"ext\" that is incompatible " + "with import extractability value \"", + extractable ? "true" : "false", "\"."); } } else { JSG_FAIL_REQUIRE(DOMNotSupportedError, "Unrecognized key import format \"", format, "\"."); @@ -811,8 +850,8 @@ kj::Own CryptoKey::Impl::importAes( return kj::heap(kj::mv(keyDataArray), kj::mv(keyAlgorithm), extractable, usages); } - JSG_FAIL_REQUIRE(DOMNotSupportedError, "Unsupported algorithm \"", normalizedName, - "\" to import."); + JSG_FAIL_REQUIRE( + DOMNotSupportedError, "Unsupported algorithm \"", normalizedName, "\" to import."); } } // namespace workerd::api diff --git a/src/workerd/api/crypto/crypto.c++ b/src/workerd/api/crypto/crypto.c++ index bcdab7ba840..b27ccdbb813 100644 --- a/src/workerd/api/crypto/crypto.c++ +++ b/src/workerd/api/crypto/crypto.c++ @@ -20,14 +20,14 @@ namespace workerd::api { kj::StringPtr CryptoKeyUsageSet::name() const { - if (*this == encrypt()) return "encrypt"; - if (*this == decrypt()) return "decrypt"; - if (*this == sign()) return "sign"; - if (*this == verify()) return "verify"; - if (*this == deriveKey()) return "deriveKey"; + if (*this == encrypt()) return "encrypt"; + if (*this == decrypt()) return "decrypt"; + if (*this == sign()) return "sign"; + if (*this == verify()) return "verify"; + if (*this == deriveKey()) return "deriveKey"; if (*this == deriveBits()) return "deriveBits"; - if (*this == wrapKey()) return "wrapKey"; - if (*this == unwrapKey()) return "unwrapKey"; + if (*this == wrapKey()) return "wrapKey"; + if (*this == unwrapKey()) return "unwrapKey"; KJ_FAIL_REQUIRE("CryptoKeyUsageSet does not contain exactly one key usage"); } @@ -40,22 +40,23 @@ CryptoKeyUsageSet CryptoKeyUsageSet::byName(kj::StringPtr name) { kj::ArrayPtr CryptoKeyUsageSet::singletons() { static const workerd::api::CryptoKeyUsageSet singletons[] = { - encrypt(), decrypt(), sign(), verify(), deriveKey(), deriveBits(), wrapKey(), unwrapKey() - }; + encrypt(), decrypt(), sign(), verify(), deriveKey(), deriveBits(), wrapKey(), unwrapKey()}; return singletons; } -CryptoKeyUsageSet CryptoKeyUsageSet::validate(kj::StringPtr normalizedName, Context ctx, - kj::ArrayPtr actual, CryptoKeyUsageSet mask) { - const auto op = (ctx == Context::generate) ? "generate" : - (ctx == Context::importSecret) ? "import secret" : - (ctx == Context::importPublic) ? "import public" : - "import private"; +CryptoKeyUsageSet CryptoKeyUsageSet::validate(kj::StringPtr normalizedName, + Context ctx, + kj::ArrayPtr actual, + CryptoKeyUsageSet mask) { + const auto op = (ctx == Context::generate) ? "generate" + : (ctx == Context::importSecret) ? "import secret" + : (ctx == Context::importPublic) ? "import public" + : "import private"; CryptoKeyUsageSet usages; for (const auto& usage: actual) { CryptoKeyUsageSet match = byName(usage); - JSG_REQUIRE(match.isSingleton() && match <= mask, DOMSyntaxError, - "Attempt to ", op, " ", normalizedName, " key with invalid usage \"", usage, "\"."); + JSG_REQUIRE(match.isSingleton() && match <= mask, DOMSyntaxError, "Attempt to ", op, " ", + normalizedName, " key with invalid usage \"", usage, "\"."); usages |= match; } return usages; @@ -98,25 +99,25 @@ namespace { static kj::Maybe lookupAlgorithm(kj::StringPtr name) { static const std::set ALGORITHMS = { - {"AES-CTR"_kj, &CryptoKey::Impl::importAes, &CryptoKey::Impl::generateAes}, - {"AES-CBC"_kj, &CryptoKey::Impl::importAes, &CryptoKey::Impl::generateAes}, - {"AES-GCM"_kj, &CryptoKey::Impl::importAes, &CryptoKey::Impl::generateAes}, - {"AES-KW"_kj, &CryptoKey::Impl::importAes, &CryptoKey::Impl::generateAes}, - {"HMAC"_kj, &CryptoKey::Impl::importHmac, &CryptoKey::Impl::generateHmac}, - {"PBKDF2"_kj, &CryptoKey::Impl::importPbkdf2}, - {"HKDF"_kj, &CryptoKey::Impl::importHkdf}, + {"AES-CTR"_kj, &CryptoKey::Impl::importAes, &CryptoKey::Impl::generateAes}, + {"AES-CBC"_kj, &CryptoKey::Impl::importAes, &CryptoKey::Impl::generateAes}, + {"AES-GCM"_kj, &CryptoKey::Impl::importAes, &CryptoKey::Impl::generateAes}, + {"AES-KW"_kj, &CryptoKey::Impl::importAes, &CryptoKey::Impl::generateAes}, + {"HMAC"_kj, &CryptoKey::Impl::importHmac, &CryptoKey::Impl::generateHmac}, + {"PBKDF2"_kj, &CryptoKey::Impl::importPbkdf2}, + {"HKDF"_kj, &CryptoKey::Impl::importHkdf}, {"RSASSA-PKCS1-v1_5"_kj, &CryptoKey::Impl::importRsa, &CryptoKey::Impl::generateRsa}, - {"RSA-PSS"_kj, &CryptoKey::Impl::importRsa, &CryptoKey::Impl::generateRsa}, - {"RSA-OAEP"_kj, &CryptoKey::Impl::importRsa, &CryptoKey::Impl::generateRsa}, - {"ECDSA"_kj, &CryptoKey::Impl::importEcdsa, &CryptoKey::Impl::generateEcdsa}, - {"ECDH"_kj, &CryptoKey::Impl::importEcdh, &CryptoKey::Impl::generateEcdh}, - {"NODE-ED25519"_kj, &CryptoKey::Impl::importEddsa, &CryptoKey::Impl::generateEddsa}, - {"Ed25519"_kj, &CryptoKey::Impl::importEddsa, &CryptoKey::Impl::generateEddsa}, - {"X25519"_kj, &CryptoKey::Impl::importEddsa, &CryptoKey::Impl::generateEddsa}, - {"RSA-RAW"_kj, &CryptoKey::Impl::importRsaRaw}, + {"RSA-PSS"_kj, &CryptoKey::Impl::importRsa, &CryptoKey::Impl::generateRsa}, + {"RSA-OAEP"_kj, &CryptoKey::Impl::importRsa, &CryptoKey::Impl::generateRsa}, + {"ECDSA"_kj, &CryptoKey::Impl::importEcdsa, &CryptoKey::Impl::generateEcdsa}, + {"ECDH"_kj, &CryptoKey::Impl::importEcdh, &CryptoKey::Impl::generateEcdh}, + {"NODE-ED25519"_kj, &CryptoKey::Impl::importEddsa, &CryptoKey::Impl::generateEddsa}, + {"Ed25519"_kj, &CryptoKey::Impl::importEddsa, &CryptoKey::Impl::generateEddsa}, + {"X25519"_kj, &CryptoKey::Impl::importEddsa, &CryptoKey::Impl::generateEddsa}, + {"RSA-RAW"_kj, &CryptoKey::Impl::importRsaRaw}, }; - auto iter = ALGORITHMS.find(CryptoAlgorithm {name}); + auto iter = ALGORITHMS.find(CryptoAlgorithm{name}); if (iter == ALGORITHMS.end()) { // No such built-in algorithm, so fall back to checking if the Api has a custom // algorithm registered. @@ -131,10 +132,7 @@ static kj::Maybe lookupAlgorithm(kj::StringPtr name) { // Throws InvalidAccessError if the key is incompatible with the given normalized algorithm name, // or if it doesn't support the given usage. -void validateOperation( - const CryptoKey& key, - kj::StringPtr requestedName, - CryptoKeyUsageSet usage) { +void validateOperation(const CryptoKey& key, kj::StringPtr requestedName, CryptoKeyUsageSet usage) { // TODO(someday): Throw a NotSupportedError? The Web Crypto API spec says InvalidAccessError, but // Web IDL says that's deprecated. // @@ -142,9 +140,8 @@ void validateOperation( // implementations of the CryptoKey::Impl::() functions. JSG_REQUIRE(strcasecmp(requestedName.cStr(), key.getAlgorithmName().cStr()) == 0, - DOMInvalidAccessError, - "Requested algorithm \"", requestedName, "\" does not match this CryptoKey's algorithm \"", - key.getAlgorithmName() ,"\"."); + DOMInvalidAccessError, "Requested algorithm \"", requestedName, + "\" does not match this CryptoKey's algorithm \"", key.getAlgorithmName(), "\"."); JSG_REQUIRE(usage <= key.getUsageSet(), DOMInvalidAccessError, "Requested key usage \"", usage.name(), "\" does not match any usage listed in this CryptoKey."); } @@ -159,7 +156,13 @@ kj::Maybe getKeyLength(const SubtleCrypto::ImportKeyAlgorithm& derived // we ad-hoc match various algorithms below, so the set of supported algorithms must be // hard-coded. static const std::set registeredAlgorithms{ - {"AES-CTR"}, {"AES-CBC"}, {"AES-GCM"}, {"AES-KW"}, {"HMAC"}, {"HKDF"}, {"PBKDF2"}, + {"AES-CTR"}, + {"AES-CBC"}, + {"AES-GCM"}, + {"AES-KW"}, + {"HMAC"}, + {"HKDF"}, + {"PBKDF2"}, }; auto algIter = registeredAlgorithms.find(algName); JSG_REQUIRE(algIter != registeredAlgorithms.end(), DOMNotSupportedError, @@ -170,12 +173,15 @@ kj::Maybe getKeyLength(const SubtleCrypto::ImportKeyAlgorithm& derived // seems worth the bother. The spec only identifies three cases: the AES family, HMAC, and the KDF // algorithms. if (algIter->startsWith("AES-")) { - int length = JSG_REQUIRE_NONNULL(derivedKeyAlgorithm.length, TypeError, - "Missing field \"length\" in \"derivedKeyParams\"."); + int length = JSG_REQUIRE_NONNULL( + derivedKeyAlgorithm.length, TypeError, "Missing field \"length\" in \"derivedKeyParams\"."); switch (length) { - case 128: [[fallthrough]]; - case 192: [[fallthrough]]; - case 256: break; + case 128: + [[fallthrough]]; + case 192: + [[fallthrough]]; + case 256: + break; default: JSG_FAIL_REQUIRE(DOMOperationError, "Derived AES key must be 128, 192, or 256 bits in length but provided ", length, "."); @@ -190,8 +196,8 @@ kj::Maybe getKeyLength(const SubtleCrypto::ImportKeyAlgorithm& derived JSG_FAIL_REQUIRE(TypeError, "HMAC key length must be a non-zero unsigned long integer."); } // Otherwise, assume the user wants the default HMAC key size. - auto digestAlg = getAlgorithmName(JSG_REQUIRE_NONNULL(derivedKeyAlgorithm.hash, TypeError, - "Missing field \"hash\" in \"derivedKeyParams\".")); + auto digestAlg = getAlgorithmName(JSG_REQUIRE_NONNULL( + derivedKeyAlgorithm.hash, TypeError, "Missing field \"hash\" in \"derivedKeyParams\".")); return EVP_MD_block_size(lookupDigestAlgorithm(digestAlg).second) * 8; } else { // HKDF or PBKDF2. I'm not not sure what it means to derive a HKDF/PBKDF2 key from a base key @@ -205,7 +211,7 @@ kj::Maybe getKeyLength(const SubtleCrypto::ImportKeyAlgorithm& derived } auto webCryptoOperationBegin( - const char *operation, kj::StringPtr algorithm, kj::Maybe context = kj::none) { + const char* operation, kj::StringPtr algorithm, kj::Maybe context = kj::none) { // This clears all OpenSSL errors & errno at the start & returns a deferred evaluation to make // sure that, when the WebCrypto entrypoint completes, there are no errors hanging around. // Context is used for adding contextual information (e.g. the algorithm name of the key being @@ -243,18 +249,18 @@ auto webCryptoOperationBegin( } auto webCryptoOperationBegin( - const char *operation, kj::StringPtr algorithm, const kj::String& context) { + const char* operation, kj::StringPtr algorithm, const kj::String& context) { return webCryptoOperationBegin(operation, algorithm, context.slice(0)); } -template ().name)>()>> -[[gnu::always_inline]] auto webCryptoOperationBegin(const char *operation, const T& algorithm, - kj::Maybe context = kj::none) { +template ().name)>()>> +[[gnu::always_inline]] auto webCryptoOperationBegin( + const char* operation, const T& algorithm, kj::Maybe context = kj::none) { return kj::defer([operation, algorithm = kj::str(algorithm.name), context] { // We need a copy of the algorithm name as this defer runs after the EncryptAlgorithm struct // is destroyed. - (void) webCryptoOperationBegin(operation, algorithm, context); + (void)webCryptoOperationBegin(operation, algorithm, context); }); } @@ -265,14 +271,24 @@ template impl): impl(kj::mv(impl)) {} CryptoKey::~CryptoKey() noexcept(false) {} -kj::StringPtr CryptoKey::getAlgorithmName() const { return impl->getAlgorithmName(); } -CryptoKey::AlgorithmVariant CryptoKey::getAlgorithm(jsg::Lock& js) const { return impl->getAlgorithm(js); } -kj::StringPtr CryptoKey::getType() const { return impl->getType(); } -bool CryptoKey::getExtractable() const { return impl->isExtractable(); } +kj::StringPtr CryptoKey::getAlgorithmName() const { + return impl->getAlgorithmName(); +} +CryptoKey::AlgorithmVariant CryptoKey::getAlgorithm(jsg::Lock& js) const { + return impl->getAlgorithm(js); +} +kj::StringPtr CryptoKey::getType() const { + return impl->getType(); +} +bool CryptoKey::getExtractable() const { + return impl->isExtractable(); +} kj::Array CryptoKey::getUsages() const { return getUsageSet().map([](auto singleton) { return singleton.name(); }); } -CryptoKeyUsageSet CryptoKey::getUsageSet() const { return impl->getUsages(); } +CryptoKeyUsageSet CryptoKey::getUsageSet() const { + return impl->getUsages(); +} bool CryptoKey::operator==(const CryptoKey& other) const { // We check this first because we don't want any comparison to happen if @@ -297,8 +313,7 @@ bool CryptoKey::verifyX509Private(const X509* cert) const { return impl->verifyX509Private(cert); } -jsg::Promise> SubtleCrypto::encrypt( - jsg::Lock& js, +jsg::Promise> SubtleCrypto::encrypt(jsg::Lock& js, kj::OneOf algorithmParam, const CryptoKey& key, kj::Array plainText) { @@ -312,8 +327,7 @@ jsg::Promise> SubtleCrypto::encrypt( }); } -jsg::Promise> SubtleCrypto::decrypt( - jsg::Lock& js, +jsg::Promise> SubtleCrypto::decrypt(jsg::Lock& js, kj::OneOf algorithmParam, const CryptoKey& key, kj::Array cipherText) { @@ -327,8 +341,7 @@ jsg::Promise> SubtleCrypto::decrypt( }); } -jsg::Promise> SubtleCrypto::sign( - jsg::Lock& js, +jsg::Promise> SubtleCrypto::sign(jsg::Lock& js, kj::OneOf algorithmParam, const CryptoKey& key, kj::Array data) { @@ -342,8 +355,7 @@ jsg::Promise> SubtleCrypto::sign( }); } -jsg::Promise SubtleCrypto::verify( - jsg::Lock& js, +jsg::Promise SubtleCrypto::verify(jsg::Lock& js, kj::OneOf algorithmParam, const CryptoKey& key, kj::Array signature, @@ -358,8 +370,7 @@ jsg::Promise SubtleCrypto::verify( }); } -jsg::Promise> SubtleCrypto::digest( - jsg::Lock& js, +jsg::Promise> SubtleCrypto::digest(jsg::Lock& js, kj::OneOf algorithmParam, kj::Array data) { auto algorithm = interpretAlgorithmParam(kj::mv(algorithmParam)); @@ -383,10 +394,10 @@ jsg::Promise> SubtleCrypto::digest( }); } -jsg::Promise, CryptoKeyPair>> SubtleCrypto::generateKey( - jsg::Lock& js, +jsg::Promise, CryptoKeyPair>> SubtleCrypto::generateKey(jsg::Lock& js, kj::OneOf algorithmParam, - bool extractable, kj::Array keyUsages) { + bool extractable, + kj::Array keyUsages) { auto algorithm = interpretAlgorithmParam(kj::mv(algorithmParam)); @@ -397,8 +408,8 @@ jsg::Promise, CryptoKeyPair>> SubtleCrypto::genera JSG_REQUIRE(algoImpl.generateFunc != nullptr, DOMNotSupportedError, "Unrecognized key generation algorithm \"", algorithm.name, "\" requested."); - auto cryptoKeyOrPair = algoImpl.generateFunc(js, algoImpl.name, kj::mv(algorithm), extractable, - keyUsages); + auto cryptoKeyOrPair = + algoImpl.generateFunc(js, algoImpl.name, kj::mv(algorithm), extractable, keyUsages); KJ_SWITCH_ONEOF(cryptoKeyOrPair) { KJ_CASE_ONEOF(cryptoKey, jsg::Ref) { if (keyUsages.size() == 0) { @@ -409,15 +420,14 @@ jsg::Promise, CryptoKeyPair>> SubtleCrypto::genera } KJ_CASE_ONEOF(keyPair, CryptoKeyPair) { JSG_REQUIRE(keyPair.privateKey->getUsageSet().size() != 0, DOMSyntaxError, - "Attempt to generate asymmetric keys with no valid private key usages."); + "Attempt to generate asymmetric keys with no valid private key usages."); } } return cryptoKeyOrPair; }); } -jsg::Promise> SubtleCrypto::deriveKey( - jsg::Lock& js, +jsg::Promise> SubtleCrypto::deriveKey(jsg::Lock& js, kj::OneOf algorithmParam, const CryptoKey& baseKey, kj::OneOf derivedKeyAlgorithmParam, @@ -443,8 +453,7 @@ jsg::Promise> SubtleCrypto::deriveKey( }); } -jsg::Promise> SubtleCrypto::deriveBits( - jsg::Lock& js, +jsg::Promise> SubtleCrypto::deriveBits(jsg::Lock& js, kj::OneOf algorithmParam, const CryptoKey& baseKey, jsg::Optional> lengthParam) { @@ -467,11 +476,13 @@ jsg::Promise> SubtleCrypto::deriveBits( } jsg::Promise> SubtleCrypto::wrapKey(jsg::Lock& js, - kj::String format, const CryptoKey& key, - const CryptoKey& wrappingKey, kj::OneOf wrapAlgorithm, + kj::String format, + const CryptoKey& key, + const CryptoKey& wrappingKey, + kj::OneOf wrapAlgorithm, const jsg::TypeHandler& jwkHandler) { - auto checkErrorsOnFinish = webCryptoOperationBegin(__func__, wrappingKey.getAlgorithmName(), - key.getAlgorithmName()); + auto checkErrorsOnFinish = + webCryptoOperationBegin(__func__, wrappingKey.getAlgorithmName(), key.getAlgorithmName()); return js.evalNow([&] { auto algorithm = interpretAlgorithmParam(kj::mv(wrapAlgorithm)); @@ -502,10 +513,13 @@ jsg::Promise> SubtleCrypto::wrapKey(jsg::Lock& js, }); } -jsg::Promise> SubtleCrypto::unwrapKey(jsg::Lock& js, kj::String format, - kj::Array wrappedKey, const CryptoKey& unwrappingKey, +jsg::Promise> SubtleCrypto::unwrapKey(jsg::Lock& js, + kj::String format, + kj::Array wrappedKey, + const CryptoKey& unwrappingKey, kj::OneOf unwrapAlgorithm, - kj::OneOf unwrappedKeyAlgorithm, bool extractable, + kj::OneOf unwrappedKeyAlgorithm, + bool extractable, kj::Array keyUsages, const jsg::TypeHandler& jwkHandler) { auto operation = __func__; @@ -515,8 +529,8 @@ jsg::Promise> SubtleCrypto::unwrapKey(jsg::Lock& js, kj::Str // Need a copy of the algorithm name to live in this scope, because we later kj::mv() it out. auto context = kj::str(normalizedUnwrapAlgorithm.name); - auto checkErrorsOnFinish = webCryptoOperationBegin(operation, unwrappingKey.getAlgorithmName(), - context); + auto checkErrorsOnFinish = + webCryptoOperationBegin(operation, unwrappingKey.getAlgorithmName(), context); validateOperation(unwrappingKey, normalizedAlgorithm.name, CryptoKeyUsageSet::unwrapKey()); @@ -546,8 +560,7 @@ jsg::Promise> SubtleCrypto::unwrapKey(jsg::Lock& js, kj::Str }); } -jsg::Promise> SubtleCrypto::importKey( - jsg::Lock& js, +jsg::Promise> SubtleCrypto::importKey(jsg::Lock& js, kj::String format, ImportKeyData keyData, kj::OneOf algorithmParam, @@ -558,13 +571,11 @@ jsg::Promise> SubtleCrypto::importKey( auto checkErrorsOnFinish = webCryptoOperationBegin(__func__, algorithm, format.asPtr()); return js.evalNow([&] { - return importKeySync(js, format, kj::mv(keyData), kj::mv(algorithm), extractable, - keyUsages); + return importKeySync(js, format, kj::mv(keyData), kj::mv(algorithm), extractable, keyUsages); }); } -jsg::Ref SubtleCrypto::importKeySync( - jsg::Lock& js, +jsg::Ref SubtleCrypto::importKeySync(jsg::Lock& js, kj::StringPtr format, ImportKeyData keyData, ImportKeyAlgorithm algorithm, @@ -581,8 +592,8 @@ jsg::Ref SubtleCrypto::importKeySync( JSG_REQUIRE(keyData.is(), TypeError, "Import data provided for \"jwk\" import format must be a JsonWebKey."); KJ_IF_SOME(ext, keyData.get().ext) { - JSG_REQUIRE(ext || !extractable, - DOMDataError, "JWK ext field for \"", algorithm.name, "\" is set to false but " + JSG_REQUIRE(ext || !extractable, DOMDataError, "JWK ext field for \"", algorithm.name, + "\" is set to false but " "extractable is true"); } } else { @@ -600,9 +611,8 @@ jsg::Ref SubtleCrypto::importKeySync( // implementation functions don't necessarily know the name of the algorithm whose key they're // importing (importKeyAesImpl handles AES-CTR, -CBC, and -GCM, for instance), so they should // rely on this value to set the imported CryptoKey's name. - auto cryptoKey = jsg::alloc( - algoImpl.importFunc(js, algoImpl.name, format, kj::mv(keyData), - kj::mv(algorithm), extractable, keyUsages)); + auto cryptoKey = jsg::alloc(algoImpl.importFunc( + js, algoImpl.name, format, kj::mv(keyData), kj::mv(algorithm), extractable, keyUsages)); if (cryptoKey->getUsageSet().size() == 0) { auto type = cryptoKey->getType(); @@ -620,8 +630,8 @@ jsg::Promise SubtleCrypto::exportKey( return js.evalNow([&] { // TODO(someday): Throw a NotSupportedError? The Web Crypto API spec says InvalidAccessError, // but Web IDL says that's deprecated. - JSG_REQUIRE(key.getExtractable(), DOMInvalidAccessError, - "Attempt to export non-extractable ", key.getAlgorithmName(), " key."); + JSG_REQUIRE(key.getExtractable(), DOMInvalidAccessError, "Attempt to export non-extractable ", + key.getAlgorithmName(), " key."); return key.impl->exportKey(format); }); @@ -643,13 +653,11 @@ bool SubtleCrypto::timingSafeEqual(kj::Array a, kj::Array b) jsg::BufferSource Crypto::getRandomValues(jsg::BufferSource buffer) { // NOTE: TypeMismatchError is deprecated (obviated by TypeError), but the spec and W3C tests still // expect a TypeMismatchError here. - JSG_REQUIRE(buffer.isIntegerType(), - DOMTypeMismatchError, - "ArrayBufferView argument to getRandomValues() must be an integer-typed view."); - JSG_REQUIRE(buffer.size() <= 0x10000, - DOMQuotaExceededError, - "getRandomValues() only accepts buffers of size <= 64K but provided ", - buffer.size(), " bytes."); + JSG_REQUIRE(buffer.isIntegerType(), DOMTypeMismatchError, + "ArrayBufferView argument to getRandomValues() must be an integer-typed view."); + JSG_REQUIRE(buffer.size() <= 0x10000, DOMQuotaExceededError, + "getRandomValues() only accepts buffers of size <= 64K but provided ", buffer.size(), + " bytes."); IoContext::current().getEntropySource().generate(buffer.asArrayPtr()); return kj::mv(buffer); } @@ -670,8 +678,7 @@ DigestStream::DigestContextPtr DigestStream::initContext(SubtleCrypto::HashAlgor return kj::mv(context); } -DigestStream::DigestStream( - kj::Own controller, +DigestStream::DigestStream(kj::Own controller, SubtleCrypto::HashAlgorithm algorithm, jsg::Promise>::Resolver resolver, jsg::Promise> promise) @@ -686,9 +693,7 @@ void DigestStream::dispose(jsg::Lock& js) { ready.resolver.reject(js, reason); state.init(js.v8Ref(reason)); } - }, [&](jsg::Value exception) { - js.throwException(kj::mv(exception)); - }); + }, [&](jsg::Value exception) { js.throwException(kj::mv(exception)); }); } void DigestStream::visitForMemoryInfo(jsg::MemoryTracker& tracker) const { @@ -755,14 +760,13 @@ void DigestStream::abort(jsg::Lock& js, jsg::JsValue reason) { jsg::Ref DigestStream::constructor(jsg::Lock& js, Algorithm algorithm) { auto paf = js.newPromiseAndResolver>(); - auto stream = jsg::alloc( - newWritableStreamJsController(), - interpretAlgorithmParam(kj::mv(algorithm)), - kj::mv(paf.resolver), - kj::mv(paf.promise)); + auto stream = jsg::alloc(newWritableStreamJsController(), + interpretAlgorithmParam(kj::mv(algorithm)), kj::mv(paf.resolver), kj::mv(paf.promise)); - stream->getController().setup(js, UnderlyingSink { - .write = [&stream=*stream](jsg::Lock& js, v8::Local chunk, auto c) mutable { + stream->getController().setup(js, + UnderlyingSink{ + .write = + [&stream = *stream](jsg::Lock& js, v8::Local chunk, auto c) mutable { return js.tryCatch([&] { // Make sure what we got can be interpreted as bytes... std::shared_ptr backing; @@ -772,7 +776,8 @@ jsg::Ref DigestStream::constructor(jsg::Lock& js, Algorithm algori KJ_IF_SOME(error, stream.write(js, source.asArrayPtr())) { return js.rejectedPromise(kj::mv(error)); - } else {} // Here to silence a compiler warning + } else { + } // Here to silence a compiler warning stream.bytesWritten += source.size(); return js.resolvedPromise(); } else if (chunk->IsString()) { @@ -785,33 +790,31 @@ jsg::Ref DigestStream::constructor(jsg::Lock& js, Algorithm algori stream.bytesWritten += str.size(); return js.resolvedPromise(); } - return js.rejectedPromise(js.typeError( - "DigestStream is a byte stream but received an object of " - "non-ArrayBuffer/ArrayBufferView/string type on its writable side.")); - }, [&](jsg::Value exception) { - return js.rejectedPromise(kj::mv(exception)); - }); + return js.rejectedPromise( + js.typeError("DigestStream is a byte stream but received an object of " + "non-ArrayBuffer/ArrayBufferView/string type on its writable side.")); + }, [&](jsg::Value exception) { return js.rejectedPromise(kj::mv(exception)); }); }, - .abort = [&stream=*stream](jsg::Lock& js, auto reason) mutable { + .abort = + [&stream = *stream](jsg::Lock& js, auto reason) mutable { return js.tryCatch([&] { stream.abort(js, jsg::JsValue(reason)); return js.resolvedPromise(); - }, [&](jsg::Value exception) { - return js.rejectedPromise(kj::mv(exception)); - }); + }, [&](jsg::Value exception) { return js.rejectedPromise(kj::mv(exception)); }); }, - .close = [&stream=*stream](jsg::Lock& js) mutable { + .close = + [&stream = *stream](jsg::Lock& js) mutable { return js.tryCatch([&] { // If sink.close returns a non kj::none value, that means the sink was errored // and we return a rejected promise here. Otherwise, we return resolved. KJ_IF_SOME(error, stream.close(js)) { return js.rejectedPromise(kj::mv(error)); - } else {} // Here to silence a compiler warning + } else { + } // Here to silence a compiler warning return js.resolvedPromise(); - }, [&](jsg::Value exception) { - return js.rejectedPromise(kj::mv(exception)); - }); - }}, kj::none); + }, [&](jsg::Value exception) { return js.rejectedPromise(kj::mv(exception)); }); + }}, + kj::none); return kj::mv(stream); } diff --git a/src/workerd/api/crypto/crypto.h b/src/workerd/api/crypto/crypto.h index 6c209b3fb1d..1963fd943f5 100644 --- a/src/workerd/api/crypto/crypto.h +++ b/src/workerd/api/crypto/crypto.h @@ -20,21 +20,37 @@ class CryptoImpl; namespace { class EdDsaKey; class EllipticKey; -} +} // namespace // Subset of recognized key usage values. // // https://w3c.github.io/webcrypto/#dfn-RecognizedKeyUsage class CryptoKeyUsageSet { public: - static constexpr CryptoKeyUsageSet encrypt() { return 1 << 0; } - static constexpr CryptoKeyUsageSet decrypt() { return 1 << 1; } - static constexpr CryptoKeyUsageSet sign() { return 1 << 2; } - static constexpr CryptoKeyUsageSet verify() { return 1 << 3; } - static constexpr CryptoKeyUsageSet deriveKey() { return 1 << 4; } - static constexpr CryptoKeyUsageSet deriveBits() { return 1 << 5; } - static constexpr CryptoKeyUsageSet wrapKey() { return 1 << 6; } - static constexpr CryptoKeyUsageSet unwrapKey() { return 1 << 7; } + static constexpr CryptoKeyUsageSet encrypt() { + return 1 << 0; + } + static constexpr CryptoKeyUsageSet decrypt() { + return 1 << 1; + } + static constexpr CryptoKeyUsageSet sign() { + return 1 << 2; + } + static constexpr CryptoKeyUsageSet verify() { + return 1 << 3; + } + static constexpr CryptoKeyUsageSet deriveKey() { + return 1 << 4; + } + static constexpr CryptoKeyUsageSet deriveBits() { + return 1 << 5; + } + static constexpr CryptoKeyUsageSet wrapKey() { + return 1 << 6; + } + static constexpr CryptoKeyUsageSet unwrapKey() { + return 1 << 7; + } static constexpr CryptoKeyUsageSet publicKeyMask() { return encrypt() | verify() | wrapKey(); @@ -48,10 +64,14 @@ class CryptoKeyUsageSet { return deriveKey() | deriveBits(); } - CryptoKeyUsageSet() : set(0) {} + CryptoKeyUsageSet(): set(0) {} - CryptoKeyUsageSet operator&(CryptoKeyUsageSet other) const { return set & other.set; } - CryptoKeyUsageSet operator|(CryptoKeyUsageSet other) const { return set | other.set; } + CryptoKeyUsageSet operator&(CryptoKeyUsageSet other) const { + return set & other.set; + } + CryptoKeyUsageSet operator|(CryptoKeyUsageSet other) const { + return set | other.set; + } CryptoKeyUsageSet& operator&=(CryptoKeyUsageSet other) { set &= other.set; @@ -64,12 +84,20 @@ class CryptoKeyUsageSet { } // True if and only if this is a subset of the given set. - inline bool operator<=(CryptoKeyUsageSet superset) const { return (superset & *this) == *this; } + inline bool operator<=(CryptoKeyUsageSet superset) const { + return (superset & *this) == *this; + } - inline bool operator==(CryptoKeyUsageSet other) const { return set == other.set; } + inline bool operator==(CryptoKeyUsageSet other) const { + return set == other.set; + } - unsigned int size() const { return std::popcount(set); } - bool isSingleton() const { return size() == 1; } + unsigned int size() const { + return std::popcount(set); + } + bool isSingleton() const { + return size() == 1; + } // The recognized name. This must be a singleton. kj::StringPtr name() const; @@ -83,8 +111,10 @@ class CryptoKeyUsageSet { enum class Context { generate, importSecret, importPublic, importPrivate }; // Parses a list of key usage strings. Throws if any are not recognized or not in mask. - static CryptoKeyUsageSet validate(kj::StringPtr normalizedName, Context ctx, - kj::ArrayPtr actual, CryptoKeyUsageSet mask); + static CryptoKeyUsageSet validate(kj::StringPtr normalizedName, + Context ctx, + kj::ArrayPtr actual, + CryptoKeyUsageSet mask); template auto map(Func f) const -> kj::Array { @@ -96,7 +126,7 @@ class CryptoKeyUsageSet { } private: - constexpr CryptoKeyUsageSet(uint8_t set) : set(set) {} + constexpr CryptoKeyUsageSet(uint8_t set): set(set) {} uint8_t set; }; @@ -166,7 +196,7 @@ class CryptoKey: public jsg::Object { // The length, in bits, of the RSA modulus. The spec would have this be an unsigned long. uint16_t modulusLength; - // The RSA public exponent (in unsigned big-endian form) + // The RSA public exponent (in unsigned big-endian form) kj::OneOf publicExponent; // The hash algorithm that is used with this key. @@ -179,9 +209,9 @@ class CryptoKey: public jsg::Object { if (fixPublicExp) { auto expCopy = kj::heapArray(array.asPtr()); jsg::BackingStore expBack = jsg::BackingStore::from(kj::mv(expCopy)); - return { name, modulusLength, jsg::BufferSource(js, kj::mv(expBack)), hash }; + return {name, modulusLength, jsg::BufferSource(js, kj::mv(expBack)), hash}; } else { - return { name, modulusLength, kj::heapArray(array.asPtr()), hash }; + return {name, modulusLength, kj::heapArray(array.asPtr()), hash}; } } KJ_CASE_ONEOF(source, jsg::BufferSource) { @@ -189,7 +219,7 @@ class CryptoKey: public jsg::Object { KJ_ASSERT(fixPublicExp == true); auto expCopy = kj::heapArray(source.asArrayPtr()); jsg::BackingStore expBack = jsg::BackingStore::from(kj::mv(expCopy)); - return { name, modulusLength, jsg::BufferSource(js, kj::mv(expBack)), hash }; + return {name, modulusLength, jsg::BufferSource(js, kj::mv(expBack)), hash}; } } KJ_UNREACHABLE; @@ -238,12 +268,12 @@ class CryptoKey: public jsg::Object { jsg::Optional divisorLength; jsg::Optional namedCurve; JSG_STRUCT(modulusLength, - publicExponent, - hashAlgorithm, - mgf1HashAlgorithm, - saltLength, - divisorLength, - namedCurve); + publicExponent, + hashAlgorithm, + mgf1HashAlgorithm, + saltLength, + divisorLength, + namedCurve); }; AsymmetricKeyDetails getAsymmetricKeyDetails() const; @@ -254,9 +284,12 @@ class CryptoKey: public jsg::Object { // JS API - using AlgorithmVariant = kj::OneOf< - KeyAlgorithm, AesKeyAlgorithm, HmacKeyAlgorithm, RsaKeyAlgorithm, - EllipticKeyAlgorithm, ArbitraryKeyAlgorithm>; + using AlgorithmVariant = kj::OneOf; AlgorithmVariant getAlgorithm(jsg::Lock& js) const; kj::StringPtr getType() const; @@ -456,7 +489,7 @@ class SubtleCrypto: public jsg::Object { jsg::Optional t; JSG_STRUCT(r, d, t); - JSG_STRUCT_TS_OVERRIDE(RsaOtherPrimesInfo); // Rename from SubtleCryptoJsonWebKeyRsaOtherPrimesInfo + JSG_STRUCT_TS_OVERRIDE(RsaOtherPrimesInfo); // Rename from SubtleCryptoJsonWebKeyRsaOtherPrimesInfo }; // The following fields are defined in Section 3.1 of JSON Web Key (RFC 7517). @@ -489,55 +522,47 @@ class SubtleCrypto: public jsg::Object { jsg::Optional k; JSG_STRUCT(kty, use, key_ops, alg, ext, crv, x, y, d, n, e, p, q, dp, dq, qi, oth, k); - JSG_STRUCT_TS_OVERRIDE(JsonWebKey); // Rename from SubtleCryptoJsonWebKey + JSG_STRUCT_TS_OVERRIDE(JsonWebKey); // Rename from SubtleCryptoJsonWebKey }; using ImportKeyData = kj::OneOf, JsonWebKey>; using ExportKeyData = kj::OneOf, JsonWebKey>; - jsg::Promise> encrypt( - jsg::Lock& js, + jsg::Promise> encrypt(jsg::Lock& js, kj::OneOf algorithm, const CryptoKey& key, kj::Array plainText); - jsg::Promise> decrypt( - jsg::Lock& js, + jsg::Promise> decrypt(jsg::Lock& js, kj::OneOf algorithm, const CryptoKey& key, kj::Array cipherText); - jsg::Promise> sign( - jsg::Lock& js, + jsg::Promise> sign(jsg::Lock& js, kj::OneOf algorithm, const CryptoKey& key, kj::Array data); - jsg::Promise verify( - jsg::Lock& js, + jsg::Promise verify(jsg::Lock& js, kj::OneOf algorithm, const CryptoKey& key, kj::Array signature, kj::Array data); - jsg::Promise> digest( - jsg::Lock& js, + jsg::Promise> digest(jsg::Lock& js, kj::OneOf algorithm, kj::Array data); - jsg::Promise, CryptoKeyPair>> generateKey( - jsg::Lock& js, + jsg::Promise, CryptoKeyPair>> generateKey(jsg::Lock& js, kj::OneOf algorithm, bool extractable, kj::Array keyUsages); - jsg::Promise> deriveKey( - jsg::Lock& js, + jsg::Promise> deriveKey(jsg::Lock& js, kj::OneOf algorithm, const CryptoKey& baseKey, kj::OneOf derivedKeyAlgorithm, bool extractable, kj::Array keyUsages); - jsg::Promise> deriveBits( - jsg::Lock& js, + jsg::Promise> deriveBits(jsg::Lock& js, kj::OneOf algorithm, const CryptoKey& baseKey, // The operation needs to be able to take both undefined and null @@ -547,8 +572,7 @@ class SubtleCrypto: public jsg::Object { // maybe int in order to treat undefined and null as being equivalent. jsg::Optional> length); - jsg::Promise> importKey( - jsg::Lock& js, + jsg::Promise> importKey(jsg::Lock& js, kj::String format, ImportKeyData keyData, kj::OneOf algorithm, @@ -556,28 +580,22 @@ class SubtleCrypto: public jsg::Object { kj::Array keyUsages); // NOT VISIBLE TO JS: like importKey() but return the key, not a promise. - jsg::Ref importKeySync( - jsg::Lock& js, + jsg::Ref importKeySync(jsg::Lock& js, kj::StringPtr format, ImportKeyData keyData, ImportKeyAlgorithm algorithm, bool extractable, kj::ArrayPtr keyUsages); - jsg::Promise exportKey( - jsg::Lock& js, - kj::String format, - const CryptoKey& key); + jsg::Promise exportKey(jsg::Lock& js, kj::String format, const CryptoKey& key); - jsg::Promise> wrapKey( - jsg::Lock& js, + jsg::Promise> wrapKey(jsg::Lock& js, kj::String format, const CryptoKey& key, const CryptoKey& wrappingKey, kj::OneOf wrapAlgorithm, const jsg::TypeHandler& jwkHandler); - jsg::Promise> unwrapKey( - jsg::Lock& js, + jsg::Promise> unwrapKey(jsg::Lock& js, kj::String format, kj::Array wrappedKey, const CryptoKey& unwrappingKey, @@ -616,17 +634,20 @@ class DigestStream: public WritableStream { using DigestContextPtr = kj::Own; using Algorithm = kj::OneOf; - explicit DigestStream( - kj::Own controller, + explicit DigestStream(kj::Own controller, SubtleCrypto::HashAlgorithm algorithm, jsg::Promise>::Resolver resolver, jsg::Promise> promise); static jsg::Ref constructor(jsg::Lock& js, Algorithm algorithm); - jsg::MemoizedIdentity>>& getDigest() { return promise; } + jsg::MemoizedIdentity>>& getDigest() { + return promise; + } void dispose(jsg::Lock& js); - uint64_t getBytesWritten() const { return bytesWritten; } + uint64_t getBytesWritten() const { + return bytesWritten; + } JSG_RESOURCE_TYPE(DigestStream, CompatibilityFlags::Reader flags) { JSG_INHERIT(WritableStream); @@ -650,8 +671,8 @@ class DigestStream: public WritableStream { SubtleCrypto::HashAlgorithm algorithm; jsg::Promise>::Resolver resolver; DigestContextPtr context; - Ready(SubtleCrypto::HashAlgorithm algorithm, - jsg::Promise>::Resolver resolver) + Ready( + SubtleCrypto::HashAlgorithm algorithm, jsg::Promise>::Resolver resolver) : algorithm(kj::mv(algorithm)), resolver(kj::mv(resolver)), context(initContext(this->algorithm)) {} @@ -720,27 +741,16 @@ class Crypto: public jsg::Object { jsg::Ref subtle = jsg::alloc(); }; -#define EW_CRYPTO_ISOLATE_TYPES \ - api::Crypto, \ - api::SubtleCrypto, \ - api::CryptoKey, \ - api::CryptoKeyPair, \ - api::SubtleCrypto::JsonWebKey, \ - api::SubtleCrypto::JsonWebKey::RsaOtherPrimesInfo, \ - api::SubtleCrypto::DeriveKeyAlgorithm, \ - api::SubtleCrypto::EncryptAlgorithm, \ - api::SubtleCrypto::GenerateKeyAlgorithm, \ - api::SubtleCrypto::HashAlgorithm, \ - api::SubtleCrypto::ImportKeyAlgorithm, \ - api::SubtleCrypto::SignAlgorithm, \ - api::CryptoKey::KeyAlgorithm, \ - api::CryptoKey::AesKeyAlgorithm, \ - api::CryptoKey::HmacKeyAlgorithm, \ - api::CryptoKey::RsaKeyAlgorithm, \ - api::CryptoKey::EllipticKeyAlgorithm, \ - api::CryptoKey::ArbitraryKeyAlgorithm, \ - api::CryptoKey::AsymmetricKeyDetails, \ - api::DigestStream +#define EW_CRYPTO_ISOLATE_TYPES \ + api::Crypto, api::SubtleCrypto, api::CryptoKey, api::CryptoKeyPair, \ + api::SubtleCrypto::JsonWebKey, api::SubtleCrypto::JsonWebKey::RsaOtherPrimesInfo, \ + api::SubtleCrypto::DeriveKeyAlgorithm, api::SubtleCrypto::EncryptAlgorithm, \ + api::SubtleCrypto::GenerateKeyAlgorithm, api::SubtleCrypto::HashAlgorithm, \ + api::SubtleCrypto::ImportKeyAlgorithm, api::SubtleCrypto::SignAlgorithm, \ + api::CryptoKey::KeyAlgorithm, api::CryptoKey::AesKeyAlgorithm, \ + api::CryptoKey::HmacKeyAlgorithm, api::CryptoKey::RsaKeyAlgorithm, \ + api::CryptoKey::EllipticKeyAlgorithm, api::CryptoKey::ArbitraryKeyAlgorithm, \ + api::CryptoKey::AsymmetricKeyDetails, api::DigestStream } // namespace workerd::api diff --git a/src/workerd/api/crypto/dh-primes.h b/src/workerd/api/crypto/dh-primes.h index e8e8da3dddd..4e260525063 100644 --- a/src/workerd/api/crypto/dh-primes.h +++ b/src/workerd/api/crypto/dh-primes.h @@ -91,214 +91,398 @@ static BIGNUM *get_params(BIGNUM *ret, const BN_ULONG *words, size_t num_words) BIGNUM *BN_get_rfc3526_prime_2048(BIGNUM *ret) { static const BN_ULONG kWords[] = { - TOBN(0xffffffff, 0xffffffff), TOBN(0x15728e5a, 0x8aacaa68), - TOBN(0x15d22618, 0x98fa0510), TOBN(0x3995497c, 0xea956ae5), - TOBN(0xde2bcbf6, 0x95581718), TOBN(0xb5c55df0, 0x6f4c52c9), - TOBN(0x9b2783a2, 0xec07a28f), TOBN(0xe39e772c, 0x180e8603), - TOBN(0x32905e46, 0x2e36ce3b), TOBN(0xf1746c08, 0xca18217c), - TOBN(0x670c354e, 0x4abc9804), TOBN(0x9ed52907, 0x7096966d), - TOBN(0x1c62f356, 0x208552bb), TOBN(0x83655d23, 0xdca3ad96), - TOBN(0x69163fa8, 0xfd24cf5f), TOBN(0x98da4836, 0x1c55d39a), - TOBN(0xc2007cb8, 0xa163bf05), TOBN(0x49286651, 0xece45b3d), - TOBN(0xae9f2411, 0x7c4b1fe6), TOBN(0xee386bfb, 0x5a899fa5), - TOBN(0x0bff5cb6, 0xf406b7ed), TOBN(0xf44c42e9, 0xa637ed6b), - TOBN(0xe485b576, 0x625e7ec6), TOBN(0x4fe1356d, 0x6d51c245), - TOBN(0x302b0a6d, 0xf25f1437), TOBN(0xef9519b3, 0xcd3a431b), - TOBN(0x514a0879, 0x8e3404dd), TOBN(0x020bbea6, 0x3b139b22), - TOBN(0x29024e08, 0x8a67cc74), TOBN(0xc4c6628b, 0x80dc1cd1), - TOBN(0xc90fdaa2, 0x2168c234), TOBN(0xffffffff, 0xffffffff), + TOBN(0xffffffff, 0xffffffff), + TOBN(0x15728e5a, 0x8aacaa68), + TOBN(0x15d22618, 0x98fa0510), + TOBN(0x3995497c, 0xea956ae5), + TOBN(0xde2bcbf6, 0x95581718), + TOBN(0xb5c55df0, 0x6f4c52c9), + TOBN(0x9b2783a2, 0xec07a28f), + TOBN(0xe39e772c, 0x180e8603), + TOBN(0x32905e46, 0x2e36ce3b), + TOBN(0xf1746c08, 0xca18217c), + TOBN(0x670c354e, 0x4abc9804), + TOBN(0x9ed52907, 0x7096966d), + TOBN(0x1c62f356, 0x208552bb), + TOBN(0x83655d23, 0xdca3ad96), + TOBN(0x69163fa8, 0xfd24cf5f), + TOBN(0x98da4836, 0x1c55d39a), + TOBN(0xc2007cb8, 0xa163bf05), + TOBN(0x49286651, 0xece45b3d), + TOBN(0xae9f2411, 0x7c4b1fe6), + TOBN(0xee386bfb, 0x5a899fa5), + TOBN(0x0bff5cb6, 0xf406b7ed), + TOBN(0xf44c42e9, 0xa637ed6b), + TOBN(0xe485b576, 0x625e7ec6), + TOBN(0x4fe1356d, 0x6d51c245), + TOBN(0x302b0a6d, 0xf25f1437), + TOBN(0xef9519b3, 0xcd3a431b), + TOBN(0x514a0879, 0x8e3404dd), + TOBN(0x020bbea6, 0x3b139b22), + TOBN(0x29024e08, 0x8a67cc74), + TOBN(0xc4c6628b, 0x80dc1cd1), + TOBN(0xc90fdaa2, 0x2168c234), + TOBN(0xffffffff, 0xffffffff), }; return get_params(ret, kWords, OPENSSL_ARRAY_SIZE(kWords)); } BIGNUM *BN_get_rfc3526_prime_3072(BIGNUM *ret) { static const BN_ULONG kWords[] = { - TOBN(0xffffffff, 0xffffffff), TOBN(0x4b82d120, 0xa93ad2ca), - TOBN(0x43db5bfc, 0xe0fd108e), TOBN(0x08e24fa0, 0x74e5ab31), - TOBN(0x770988c0, 0xbad946e2), TOBN(0xbbe11757, 0x7a615d6c), - TOBN(0x521f2b18, 0x177b200c), TOBN(0xd8760273, 0x3ec86a64), - TOBN(0xf12ffa06, 0xd98a0864), TOBN(0xcee3d226, 0x1ad2ee6b), - TOBN(0x1e8c94e0, 0x4a25619d), TOBN(0xabf5ae8c, 0xdb0933d7), - TOBN(0xb3970f85, 0xa6e1e4c7), TOBN(0x8aea7157, 0x5d060c7d), - TOBN(0xecfb8504, 0x58dbef0a), TOBN(0xa85521ab, 0xdf1cba64), - TOBN(0xad33170d, 0x04507a33), TOBN(0x15728e5a, 0x8aaac42d), - TOBN(0x15d22618, 0x98fa0510), TOBN(0x3995497c, 0xea956ae5), - TOBN(0xde2bcbf6, 0x95581718), TOBN(0xb5c55df0, 0x6f4c52c9), - TOBN(0x9b2783a2, 0xec07a28f), TOBN(0xe39e772c, 0x180e8603), - TOBN(0x32905e46, 0x2e36ce3b), TOBN(0xf1746c08, 0xca18217c), - TOBN(0x670c354e, 0x4abc9804), TOBN(0x9ed52907, 0x7096966d), - TOBN(0x1c62f356, 0x208552bb), TOBN(0x83655d23, 0xdca3ad96), - TOBN(0x69163fa8, 0xfd24cf5f), TOBN(0x98da4836, 0x1c55d39a), - TOBN(0xc2007cb8, 0xa163bf05), TOBN(0x49286651, 0xece45b3d), - TOBN(0xae9f2411, 0x7c4b1fe6), TOBN(0xee386bfb, 0x5a899fa5), - TOBN(0x0bff5cb6, 0xf406b7ed), TOBN(0xf44c42e9, 0xa637ed6b), - TOBN(0xe485b576, 0x625e7ec6), TOBN(0x4fe1356d, 0x6d51c245), - TOBN(0x302b0a6d, 0xf25f1437), TOBN(0xef9519b3, 0xcd3a431b), - TOBN(0x514a0879, 0x8e3404dd), TOBN(0x020bbea6, 0x3b139b22), - TOBN(0x29024e08, 0x8a67cc74), TOBN(0xc4c6628b, 0x80dc1cd1), - TOBN(0xc90fdaa2, 0x2168c234), TOBN(0xffffffff, 0xffffffff), + TOBN(0xffffffff, 0xffffffff), + TOBN(0x4b82d120, 0xa93ad2ca), + TOBN(0x43db5bfc, 0xe0fd108e), + TOBN(0x08e24fa0, 0x74e5ab31), + TOBN(0x770988c0, 0xbad946e2), + TOBN(0xbbe11757, 0x7a615d6c), + TOBN(0x521f2b18, 0x177b200c), + TOBN(0xd8760273, 0x3ec86a64), + TOBN(0xf12ffa06, 0xd98a0864), + TOBN(0xcee3d226, 0x1ad2ee6b), + TOBN(0x1e8c94e0, 0x4a25619d), + TOBN(0xabf5ae8c, 0xdb0933d7), + TOBN(0xb3970f85, 0xa6e1e4c7), + TOBN(0x8aea7157, 0x5d060c7d), + TOBN(0xecfb8504, 0x58dbef0a), + TOBN(0xa85521ab, 0xdf1cba64), + TOBN(0xad33170d, 0x04507a33), + TOBN(0x15728e5a, 0x8aaac42d), + TOBN(0x15d22618, 0x98fa0510), + TOBN(0x3995497c, 0xea956ae5), + TOBN(0xde2bcbf6, 0x95581718), + TOBN(0xb5c55df0, 0x6f4c52c9), + TOBN(0x9b2783a2, 0xec07a28f), + TOBN(0xe39e772c, 0x180e8603), + TOBN(0x32905e46, 0x2e36ce3b), + TOBN(0xf1746c08, 0xca18217c), + TOBN(0x670c354e, 0x4abc9804), + TOBN(0x9ed52907, 0x7096966d), + TOBN(0x1c62f356, 0x208552bb), + TOBN(0x83655d23, 0xdca3ad96), + TOBN(0x69163fa8, 0xfd24cf5f), + TOBN(0x98da4836, 0x1c55d39a), + TOBN(0xc2007cb8, 0xa163bf05), + TOBN(0x49286651, 0xece45b3d), + TOBN(0xae9f2411, 0x7c4b1fe6), + TOBN(0xee386bfb, 0x5a899fa5), + TOBN(0x0bff5cb6, 0xf406b7ed), + TOBN(0xf44c42e9, 0xa637ed6b), + TOBN(0xe485b576, 0x625e7ec6), + TOBN(0x4fe1356d, 0x6d51c245), + TOBN(0x302b0a6d, 0xf25f1437), + TOBN(0xef9519b3, 0xcd3a431b), + TOBN(0x514a0879, 0x8e3404dd), + TOBN(0x020bbea6, 0x3b139b22), + TOBN(0x29024e08, 0x8a67cc74), + TOBN(0xc4c6628b, 0x80dc1cd1), + TOBN(0xc90fdaa2, 0x2168c234), + TOBN(0xffffffff, 0xffffffff), }; return get_params(ret, kWords, OPENSSL_ARRAY_SIZE(kWords)); } BIGNUM *BN_get_rfc3526_prime_4096(BIGNUM *ret) { static const BN_ULONG kWords[] = { - TOBN(0xffffffff, 0xffffffff), TOBN(0x4df435c9, 0x34063199), - TOBN(0x86ffb7dc, 0x90a6c08f), TOBN(0x93b4ea98, 0x8d8fddc1), - TOBN(0xd0069127, 0xd5b05aa9), TOBN(0xb81bdd76, 0x2170481c), - TOBN(0x1f612970, 0xcee2d7af), TOBN(0x233ba186, 0x515be7ed), - TOBN(0x99b2964f, 0xa090c3a2), TOBN(0x287c5947, 0x4e6bc05d), - TOBN(0x2e8efc14, 0x1fbecaa6), TOBN(0xdbbbc2db, 0x04de8ef9), - TOBN(0x2583e9ca, 0x2ad44ce8), TOBN(0x1a946834, 0xb6150bda), - TOBN(0x99c32718, 0x6af4e23c), TOBN(0x88719a10, 0xbdba5b26), - TOBN(0x1a723c12, 0xa787e6d7), TOBN(0x4b82d120, 0xa9210801), - TOBN(0x43db5bfc, 0xe0fd108e), TOBN(0x08e24fa0, 0x74e5ab31), - TOBN(0x770988c0, 0xbad946e2), TOBN(0xbbe11757, 0x7a615d6c), - TOBN(0x521f2b18, 0x177b200c), TOBN(0xd8760273, 0x3ec86a64), - TOBN(0xf12ffa06, 0xd98a0864), TOBN(0xcee3d226, 0x1ad2ee6b), - TOBN(0x1e8c94e0, 0x4a25619d), TOBN(0xabf5ae8c, 0xdb0933d7), - TOBN(0xb3970f85, 0xa6e1e4c7), TOBN(0x8aea7157, 0x5d060c7d), - TOBN(0xecfb8504, 0x58dbef0a), TOBN(0xa85521ab, 0xdf1cba64), - TOBN(0xad33170d, 0x04507a33), TOBN(0x15728e5a, 0x8aaac42d), - TOBN(0x15d22618, 0x98fa0510), TOBN(0x3995497c, 0xea956ae5), - TOBN(0xde2bcbf6, 0x95581718), TOBN(0xb5c55df0, 0x6f4c52c9), - TOBN(0x9b2783a2, 0xec07a28f), TOBN(0xe39e772c, 0x180e8603), - TOBN(0x32905e46, 0x2e36ce3b), TOBN(0xf1746c08, 0xca18217c), - TOBN(0x670c354e, 0x4abc9804), TOBN(0x9ed52907, 0x7096966d), - TOBN(0x1c62f356, 0x208552bb), TOBN(0x83655d23, 0xdca3ad96), - TOBN(0x69163fa8, 0xfd24cf5f), TOBN(0x98da4836, 0x1c55d39a), - TOBN(0xc2007cb8, 0xa163bf05), TOBN(0x49286651, 0xece45b3d), - TOBN(0xae9f2411, 0x7c4b1fe6), TOBN(0xee386bfb, 0x5a899fa5), - TOBN(0x0bff5cb6, 0xf406b7ed), TOBN(0xf44c42e9, 0xa637ed6b), - TOBN(0xe485b576, 0x625e7ec6), TOBN(0x4fe1356d, 0x6d51c245), - TOBN(0x302b0a6d, 0xf25f1437), TOBN(0xef9519b3, 0xcd3a431b), - TOBN(0x514a0879, 0x8e3404dd), TOBN(0x020bbea6, 0x3b139b22), - TOBN(0x29024e08, 0x8a67cc74), TOBN(0xc4c6628b, 0x80dc1cd1), - TOBN(0xc90fdaa2, 0x2168c234), TOBN(0xffffffff, 0xffffffff), + TOBN(0xffffffff, 0xffffffff), + TOBN(0x4df435c9, 0x34063199), + TOBN(0x86ffb7dc, 0x90a6c08f), + TOBN(0x93b4ea98, 0x8d8fddc1), + TOBN(0xd0069127, 0xd5b05aa9), + TOBN(0xb81bdd76, 0x2170481c), + TOBN(0x1f612970, 0xcee2d7af), + TOBN(0x233ba186, 0x515be7ed), + TOBN(0x99b2964f, 0xa090c3a2), + TOBN(0x287c5947, 0x4e6bc05d), + TOBN(0x2e8efc14, 0x1fbecaa6), + TOBN(0xdbbbc2db, 0x04de8ef9), + TOBN(0x2583e9ca, 0x2ad44ce8), + TOBN(0x1a946834, 0xb6150bda), + TOBN(0x99c32718, 0x6af4e23c), + TOBN(0x88719a10, 0xbdba5b26), + TOBN(0x1a723c12, 0xa787e6d7), + TOBN(0x4b82d120, 0xa9210801), + TOBN(0x43db5bfc, 0xe0fd108e), + TOBN(0x08e24fa0, 0x74e5ab31), + TOBN(0x770988c0, 0xbad946e2), + TOBN(0xbbe11757, 0x7a615d6c), + TOBN(0x521f2b18, 0x177b200c), + TOBN(0xd8760273, 0x3ec86a64), + TOBN(0xf12ffa06, 0xd98a0864), + TOBN(0xcee3d226, 0x1ad2ee6b), + TOBN(0x1e8c94e0, 0x4a25619d), + TOBN(0xabf5ae8c, 0xdb0933d7), + TOBN(0xb3970f85, 0xa6e1e4c7), + TOBN(0x8aea7157, 0x5d060c7d), + TOBN(0xecfb8504, 0x58dbef0a), + TOBN(0xa85521ab, 0xdf1cba64), + TOBN(0xad33170d, 0x04507a33), + TOBN(0x15728e5a, 0x8aaac42d), + TOBN(0x15d22618, 0x98fa0510), + TOBN(0x3995497c, 0xea956ae5), + TOBN(0xde2bcbf6, 0x95581718), + TOBN(0xb5c55df0, 0x6f4c52c9), + TOBN(0x9b2783a2, 0xec07a28f), + TOBN(0xe39e772c, 0x180e8603), + TOBN(0x32905e46, 0x2e36ce3b), + TOBN(0xf1746c08, 0xca18217c), + TOBN(0x670c354e, 0x4abc9804), + TOBN(0x9ed52907, 0x7096966d), + TOBN(0x1c62f356, 0x208552bb), + TOBN(0x83655d23, 0xdca3ad96), + TOBN(0x69163fa8, 0xfd24cf5f), + TOBN(0x98da4836, 0x1c55d39a), + TOBN(0xc2007cb8, 0xa163bf05), + TOBN(0x49286651, 0xece45b3d), + TOBN(0xae9f2411, 0x7c4b1fe6), + TOBN(0xee386bfb, 0x5a899fa5), + TOBN(0x0bff5cb6, 0xf406b7ed), + TOBN(0xf44c42e9, 0xa637ed6b), + TOBN(0xe485b576, 0x625e7ec6), + TOBN(0x4fe1356d, 0x6d51c245), + TOBN(0x302b0a6d, 0xf25f1437), + TOBN(0xef9519b3, 0xcd3a431b), + TOBN(0x514a0879, 0x8e3404dd), + TOBN(0x020bbea6, 0x3b139b22), + TOBN(0x29024e08, 0x8a67cc74), + TOBN(0xc4c6628b, 0x80dc1cd1), + TOBN(0xc90fdaa2, 0x2168c234), + TOBN(0xffffffff, 0xffffffff), }; return get_params(ret, kWords, OPENSSL_ARRAY_SIZE(kWords)); } BIGNUM *BN_get_rfc3526_prime_6144(BIGNUM *ret) { static const BN_ULONG kWords[] = { - TOBN(0xffffffff, 0xffffffff), TOBN(0xe694f91e, 0x6dcc4024), - TOBN(0x12bf2d5b, 0x0b7474d6), TOBN(0x043e8f66, 0x3f4860ee), - TOBN(0x387fe8d7, 0x6e3c0468), TOBN(0xda56c9ec, 0x2ef29632), - TOBN(0xeb19ccb1, 0xa313d55c), TOBN(0xf550aa3d, 0x8a1fbff0), - TOBN(0x06a1d58b, 0xb7c5da76), TOBN(0xa79715ee, 0xf29be328), - TOBN(0x14cc5ed2, 0x0f8037e0), TOBN(0xcc8f6d7e, 0xbf48e1d8), - TOBN(0x4bd407b2, 0x2b4154aa), TOBN(0x0f1d45b7, 0xff585ac5), - TOBN(0x23a97a7e, 0x36cc88be), TOBN(0x59e7c97f, 0xbec7e8f3), - TOBN(0xb5a84031, 0x900b1c9e), TOBN(0xd55e702f, 0x46980c82), - TOBN(0xf482d7ce, 0x6e74fef6), TOBN(0xf032ea15, 0xd1721d03), - TOBN(0x5983ca01, 0xc64b92ec), TOBN(0x6fb8f401, 0x378cd2bf), - TOBN(0x33205151, 0x2bd7af42), TOBN(0xdb7f1447, 0xe6cc254b), - TOBN(0x44ce6cba, 0xced4bb1b), TOBN(0xda3edbeb, 0xcf9b14ed), - TOBN(0x179727b0, 0x865a8918), TOBN(0xb06a53ed, 0x9027d831), - TOBN(0xe5db382f, 0x413001ae), TOBN(0xf8ff9406, 0xad9e530e), - TOBN(0xc9751e76, 0x3dba37bd), TOBN(0xc1d4dcb2, 0x602646de), - TOBN(0x36c3fab4, 0xd27c7026), TOBN(0x4df435c9, 0x34028492), - TOBN(0x86ffb7dc, 0x90a6c08f), TOBN(0x93b4ea98, 0x8d8fddc1), - TOBN(0xd0069127, 0xd5b05aa9), TOBN(0xb81bdd76, 0x2170481c), - TOBN(0x1f612970, 0xcee2d7af), TOBN(0x233ba186, 0x515be7ed), - TOBN(0x99b2964f, 0xa090c3a2), TOBN(0x287c5947, 0x4e6bc05d), - TOBN(0x2e8efc14, 0x1fbecaa6), TOBN(0xdbbbc2db, 0x04de8ef9), - TOBN(0x2583e9ca, 0x2ad44ce8), TOBN(0x1a946834, 0xb6150bda), - TOBN(0x99c32718, 0x6af4e23c), TOBN(0x88719a10, 0xbdba5b26), - TOBN(0x1a723c12, 0xa787e6d7), TOBN(0x4b82d120, 0xa9210801), - TOBN(0x43db5bfc, 0xe0fd108e), TOBN(0x08e24fa0, 0x74e5ab31), - TOBN(0x770988c0, 0xbad946e2), TOBN(0xbbe11757, 0x7a615d6c), - TOBN(0x521f2b18, 0x177b200c), TOBN(0xd8760273, 0x3ec86a64), - TOBN(0xf12ffa06, 0xd98a0864), TOBN(0xcee3d226, 0x1ad2ee6b), - TOBN(0x1e8c94e0, 0x4a25619d), TOBN(0xabf5ae8c, 0xdb0933d7), - TOBN(0xb3970f85, 0xa6e1e4c7), TOBN(0x8aea7157, 0x5d060c7d), - TOBN(0xecfb8504, 0x58dbef0a), TOBN(0xa85521ab, 0xdf1cba64), - TOBN(0xad33170d, 0x04507a33), TOBN(0x15728e5a, 0x8aaac42d), - TOBN(0x15d22618, 0x98fa0510), TOBN(0x3995497c, 0xea956ae5), - TOBN(0xde2bcbf6, 0x95581718), TOBN(0xb5c55df0, 0x6f4c52c9), - TOBN(0x9b2783a2, 0xec07a28f), TOBN(0xe39e772c, 0x180e8603), - TOBN(0x32905e46, 0x2e36ce3b), TOBN(0xf1746c08, 0xca18217c), - TOBN(0x670c354e, 0x4abc9804), TOBN(0x9ed52907, 0x7096966d), - TOBN(0x1c62f356, 0x208552bb), TOBN(0x83655d23, 0xdca3ad96), - TOBN(0x69163fa8, 0xfd24cf5f), TOBN(0x98da4836, 0x1c55d39a), - TOBN(0xc2007cb8, 0xa163bf05), TOBN(0x49286651, 0xece45b3d), - TOBN(0xae9f2411, 0x7c4b1fe6), TOBN(0xee386bfb, 0x5a899fa5), - TOBN(0x0bff5cb6, 0xf406b7ed), TOBN(0xf44c42e9, 0xa637ed6b), - TOBN(0xe485b576, 0x625e7ec6), TOBN(0x4fe1356d, 0x6d51c245), - TOBN(0x302b0a6d, 0xf25f1437), TOBN(0xef9519b3, 0xcd3a431b), - TOBN(0x514a0879, 0x8e3404dd), TOBN(0x020bbea6, 0x3b139b22), - TOBN(0x29024e08, 0x8a67cc74), TOBN(0xc4c6628b, 0x80dc1cd1), - TOBN(0xc90fdaa2, 0x2168c234), TOBN(0xffffffff, 0xffffffff), + TOBN(0xffffffff, 0xffffffff), + TOBN(0xe694f91e, 0x6dcc4024), + TOBN(0x12bf2d5b, 0x0b7474d6), + TOBN(0x043e8f66, 0x3f4860ee), + TOBN(0x387fe8d7, 0x6e3c0468), + TOBN(0xda56c9ec, 0x2ef29632), + TOBN(0xeb19ccb1, 0xa313d55c), + TOBN(0xf550aa3d, 0x8a1fbff0), + TOBN(0x06a1d58b, 0xb7c5da76), + TOBN(0xa79715ee, 0xf29be328), + TOBN(0x14cc5ed2, 0x0f8037e0), + TOBN(0xcc8f6d7e, 0xbf48e1d8), + TOBN(0x4bd407b2, 0x2b4154aa), + TOBN(0x0f1d45b7, 0xff585ac5), + TOBN(0x23a97a7e, 0x36cc88be), + TOBN(0x59e7c97f, 0xbec7e8f3), + TOBN(0xb5a84031, 0x900b1c9e), + TOBN(0xd55e702f, 0x46980c82), + TOBN(0xf482d7ce, 0x6e74fef6), + TOBN(0xf032ea15, 0xd1721d03), + TOBN(0x5983ca01, 0xc64b92ec), + TOBN(0x6fb8f401, 0x378cd2bf), + TOBN(0x33205151, 0x2bd7af42), + TOBN(0xdb7f1447, 0xe6cc254b), + TOBN(0x44ce6cba, 0xced4bb1b), + TOBN(0xda3edbeb, 0xcf9b14ed), + TOBN(0x179727b0, 0x865a8918), + TOBN(0xb06a53ed, 0x9027d831), + TOBN(0xe5db382f, 0x413001ae), + TOBN(0xf8ff9406, 0xad9e530e), + TOBN(0xc9751e76, 0x3dba37bd), + TOBN(0xc1d4dcb2, 0x602646de), + TOBN(0x36c3fab4, 0xd27c7026), + TOBN(0x4df435c9, 0x34028492), + TOBN(0x86ffb7dc, 0x90a6c08f), + TOBN(0x93b4ea98, 0x8d8fddc1), + TOBN(0xd0069127, 0xd5b05aa9), + TOBN(0xb81bdd76, 0x2170481c), + TOBN(0x1f612970, 0xcee2d7af), + TOBN(0x233ba186, 0x515be7ed), + TOBN(0x99b2964f, 0xa090c3a2), + TOBN(0x287c5947, 0x4e6bc05d), + TOBN(0x2e8efc14, 0x1fbecaa6), + TOBN(0xdbbbc2db, 0x04de8ef9), + TOBN(0x2583e9ca, 0x2ad44ce8), + TOBN(0x1a946834, 0xb6150bda), + TOBN(0x99c32718, 0x6af4e23c), + TOBN(0x88719a10, 0xbdba5b26), + TOBN(0x1a723c12, 0xa787e6d7), + TOBN(0x4b82d120, 0xa9210801), + TOBN(0x43db5bfc, 0xe0fd108e), + TOBN(0x08e24fa0, 0x74e5ab31), + TOBN(0x770988c0, 0xbad946e2), + TOBN(0xbbe11757, 0x7a615d6c), + TOBN(0x521f2b18, 0x177b200c), + TOBN(0xd8760273, 0x3ec86a64), + TOBN(0xf12ffa06, 0xd98a0864), + TOBN(0xcee3d226, 0x1ad2ee6b), + TOBN(0x1e8c94e0, 0x4a25619d), + TOBN(0xabf5ae8c, 0xdb0933d7), + TOBN(0xb3970f85, 0xa6e1e4c7), + TOBN(0x8aea7157, 0x5d060c7d), + TOBN(0xecfb8504, 0x58dbef0a), + TOBN(0xa85521ab, 0xdf1cba64), + TOBN(0xad33170d, 0x04507a33), + TOBN(0x15728e5a, 0x8aaac42d), + TOBN(0x15d22618, 0x98fa0510), + TOBN(0x3995497c, 0xea956ae5), + TOBN(0xde2bcbf6, 0x95581718), + TOBN(0xb5c55df0, 0x6f4c52c9), + TOBN(0x9b2783a2, 0xec07a28f), + TOBN(0xe39e772c, 0x180e8603), + TOBN(0x32905e46, 0x2e36ce3b), + TOBN(0xf1746c08, 0xca18217c), + TOBN(0x670c354e, 0x4abc9804), + TOBN(0x9ed52907, 0x7096966d), + TOBN(0x1c62f356, 0x208552bb), + TOBN(0x83655d23, 0xdca3ad96), + TOBN(0x69163fa8, 0xfd24cf5f), + TOBN(0x98da4836, 0x1c55d39a), + TOBN(0xc2007cb8, 0xa163bf05), + TOBN(0x49286651, 0xece45b3d), + TOBN(0xae9f2411, 0x7c4b1fe6), + TOBN(0xee386bfb, 0x5a899fa5), + TOBN(0x0bff5cb6, 0xf406b7ed), + TOBN(0xf44c42e9, 0xa637ed6b), + TOBN(0xe485b576, 0x625e7ec6), + TOBN(0x4fe1356d, 0x6d51c245), + TOBN(0x302b0a6d, 0xf25f1437), + TOBN(0xef9519b3, 0xcd3a431b), + TOBN(0x514a0879, 0x8e3404dd), + TOBN(0x020bbea6, 0x3b139b22), + TOBN(0x29024e08, 0x8a67cc74), + TOBN(0xc4c6628b, 0x80dc1cd1), + TOBN(0xc90fdaa2, 0x2168c234), + TOBN(0xffffffff, 0xffffffff), }; return get_params(ret, kWords, OPENSSL_ARRAY_SIZE(kWords)); } BIGNUM *BN_get_rfc3526_prime_8192(BIGNUM *ret) { static const BN_ULONG kWords[] = { - TOBN(0xffffffff, 0xffffffff), TOBN(0x60c980dd, 0x98edd3df), - TOBN(0xc81f56e8, 0x80b96e71), TOBN(0x9e3050e2, 0x765694df), - TOBN(0x9558e447, 0x5677e9aa), TOBN(0xc9190da6, 0xfc026e47), - TOBN(0x889a002e, 0xd5ee382b), TOBN(0x4009438b, 0x481c6cd7), - TOBN(0x359046f4, 0xeb879f92), TOBN(0xfaf36bc3, 0x1ecfa268), - TOBN(0xb1d510bd, 0x7ee74d73), TOBN(0xf9ab4819, 0x5ded7ea1), - TOBN(0x64f31cc5, 0x0846851d), TOBN(0x4597e899, 0xa0255dc1), - TOBN(0xdf310ee0, 0x74ab6a36), TOBN(0x6d2a13f8, 0x3f44f82d), - TOBN(0x062b3cf5, 0xb3a278a6), TOBN(0x79683303, 0xed5bdd3a), - TOBN(0xfa9d4b7f, 0xa2c087e8), TOBN(0x4bcbc886, 0x2f8385dd), - TOBN(0x3473fc64, 0x6cea306b), TOBN(0x13eb57a8, 0x1a23f0c7), - TOBN(0x22222e04, 0xa4037c07), TOBN(0xe3fdb8be, 0xfc848ad9), - TOBN(0x238f16cb, 0xe39d652d), TOBN(0x3423b474, 0x2bf1c978), - TOBN(0x3aab639c, 0x5ae4f568), TOBN(0x2576f693, 0x6ba42466), - TOBN(0x741fa7bf, 0x8afc47ed), TOBN(0x3bc832b6, 0x8d9dd300), - TOBN(0xd8bec4d0, 0x73b931ba), TOBN(0x38777cb6, 0xa932df8c), - TOBN(0x74a3926f, 0x12fee5e4), TOBN(0xe694f91e, 0x6dbe1159), - TOBN(0x12bf2d5b, 0x0b7474d6), TOBN(0x043e8f66, 0x3f4860ee), - TOBN(0x387fe8d7, 0x6e3c0468), TOBN(0xda56c9ec, 0x2ef29632), - TOBN(0xeb19ccb1, 0xa313d55c), TOBN(0xf550aa3d, 0x8a1fbff0), - TOBN(0x06a1d58b, 0xb7c5da76), TOBN(0xa79715ee, 0xf29be328), - TOBN(0x14cc5ed2, 0x0f8037e0), TOBN(0xcc8f6d7e, 0xbf48e1d8), - TOBN(0x4bd407b2, 0x2b4154aa), TOBN(0x0f1d45b7, 0xff585ac5), - TOBN(0x23a97a7e, 0x36cc88be), TOBN(0x59e7c97f, 0xbec7e8f3), - TOBN(0xb5a84031, 0x900b1c9e), TOBN(0xd55e702f, 0x46980c82), - TOBN(0xf482d7ce, 0x6e74fef6), TOBN(0xf032ea15, 0xd1721d03), - TOBN(0x5983ca01, 0xc64b92ec), TOBN(0x6fb8f401, 0x378cd2bf), - TOBN(0x33205151, 0x2bd7af42), TOBN(0xdb7f1447, 0xe6cc254b), - TOBN(0x44ce6cba, 0xced4bb1b), TOBN(0xda3edbeb, 0xcf9b14ed), - TOBN(0x179727b0, 0x865a8918), TOBN(0xb06a53ed, 0x9027d831), - TOBN(0xe5db382f, 0x413001ae), TOBN(0xf8ff9406, 0xad9e530e), - TOBN(0xc9751e76, 0x3dba37bd), TOBN(0xc1d4dcb2, 0x602646de), - TOBN(0x36c3fab4, 0xd27c7026), TOBN(0x4df435c9, 0x34028492), - TOBN(0x86ffb7dc, 0x90a6c08f), TOBN(0x93b4ea98, 0x8d8fddc1), - TOBN(0xd0069127, 0xd5b05aa9), TOBN(0xb81bdd76, 0x2170481c), - TOBN(0x1f612970, 0xcee2d7af), TOBN(0x233ba186, 0x515be7ed), - TOBN(0x99b2964f, 0xa090c3a2), TOBN(0x287c5947, 0x4e6bc05d), - TOBN(0x2e8efc14, 0x1fbecaa6), TOBN(0xdbbbc2db, 0x04de8ef9), - TOBN(0x2583e9ca, 0x2ad44ce8), TOBN(0x1a946834, 0xb6150bda), - TOBN(0x99c32718, 0x6af4e23c), TOBN(0x88719a10, 0xbdba5b26), - TOBN(0x1a723c12, 0xa787e6d7), TOBN(0x4b82d120, 0xa9210801), - TOBN(0x43db5bfc, 0xe0fd108e), TOBN(0x08e24fa0, 0x74e5ab31), - TOBN(0x770988c0, 0xbad946e2), TOBN(0xbbe11757, 0x7a615d6c), - TOBN(0x521f2b18, 0x177b200c), TOBN(0xd8760273, 0x3ec86a64), - TOBN(0xf12ffa06, 0xd98a0864), TOBN(0xcee3d226, 0x1ad2ee6b), - TOBN(0x1e8c94e0, 0x4a25619d), TOBN(0xabf5ae8c, 0xdb0933d7), - TOBN(0xb3970f85, 0xa6e1e4c7), TOBN(0x8aea7157, 0x5d060c7d), - TOBN(0xecfb8504, 0x58dbef0a), TOBN(0xa85521ab, 0xdf1cba64), - TOBN(0xad33170d, 0x04507a33), TOBN(0x15728e5a, 0x8aaac42d), - TOBN(0x15d22618, 0x98fa0510), TOBN(0x3995497c, 0xea956ae5), - TOBN(0xde2bcbf6, 0x95581718), TOBN(0xb5c55df0, 0x6f4c52c9), - TOBN(0x9b2783a2, 0xec07a28f), TOBN(0xe39e772c, 0x180e8603), - TOBN(0x32905e46, 0x2e36ce3b), TOBN(0xf1746c08, 0xca18217c), - TOBN(0x670c354e, 0x4abc9804), TOBN(0x9ed52907, 0x7096966d), - TOBN(0x1c62f356, 0x208552bb), TOBN(0x83655d23, 0xdca3ad96), - TOBN(0x69163fa8, 0xfd24cf5f), TOBN(0x98da4836, 0x1c55d39a), - TOBN(0xc2007cb8, 0xa163bf05), TOBN(0x49286651, 0xece45b3d), - TOBN(0xae9f2411, 0x7c4b1fe6), TOBN(0xee386bfb, 0x5a899fa5), - TOBN(0x0bff5cb6, 0xf406b7ed), TOBN(0xf44c42e9, 0xa637ed6b), - TOBN(0xe485b576, 0x625e7ec6), TOBN(0x4fe1356d, 0x6d51c245), - TOBN(0x302b0a6d, 0xf25f1437), TOBN(0xef9519b3, 0xcd3a431b), - TOBN(0x514a0879, 0x8e3404dd), TOBN(0x020bbea6, 0x3b139b22), - TOBN(0x29024e08, 0x8a67cc74), TOBN(0xc4c6628b, 0x80dc1cd1), - TOBN(0xc90fdaa2, 0x2168c234), TOBN(0xffffffff, 0xffffffff), + TOBN(0xffffffff, 0xffffffff), + TOBN(0x60c980dd, 0x98edd3df), + TOBN(0xc81f56e8, 0x80b96e71), + TOBN(0x9e3050e2, 0x765694df), + TOBN(0x9558e447, 0x5677e9aa), + TOBN(0xc9190da6, 0xfc026e47), + TOBN(0x889a002e, 0xd5ee382b), + TOBN(0x4009438b, 0x481c6cd7), + TOBN(0x359046f4, 0xeb879f92), + TOBN(0xfaf36bc3, 0x1ecfa268), + TOBN(0xb1d510bd, 0x7ee74d73), + TOBN(0xf9ab4819, 0x5ded7ea1), + TOBN(0x64f31cc5, 0x0846851d), + TOBN(0x4597e899, 0xa0255dc1), + TOBN(0xdf310ee0, 0x74ab6a36), + TOBN(0x6d2a13f8, 0x3f44f82d), + TOBN(0x062b3cf5, 0xb3a278a6), + TOBN(0x79683303, 0xed5bdd3a), + TOBN(0xfa9d4b7f, 0xa2c087e8), + TOBN(0x4bcbc886, 0x2f8385dd), + TOBN(0x3473fc64, 0x6cea306b), + TOBN(0x13eb57a8, 0x1a23f0c7), + TOBN(0x22222e04, 0xa4037c07), + TOBN(0xe3fdb8be, 0xfc848ad9), + TOBN(0x238f16cb, 0xe39d652d), + TOBN(0x3423b474, 0x2bf1c978), + TOBN(0x3aab639c, 0x5ae4f568), + TOBN(0x2576f693, 0x6ba42466), + TOBN(0x741fa7bf, 0x8afc47ed), + TOBN(0x3bc832b6, 0x8d9dd300), + TOBN(0xd8bec4d0, 0x73b931ba), + TOBN(0x38777cb6, 0xa932df8c), + TOBN(0x74a3926f, 0x12fee5e4), + TOBN(0xe694f91e, 0x6dbe1159), + TOBN(0x12bf2d5b, 0x0b7474d6), + TOBN(0x043e8f66, 0x3f4860ee), + TOBN(0x387fe8d7, 0x6e3c0468), + TOBN(0xda56c9ec, 0x2ef29632), + TOBN(0xeb19ccb1, 0xa313d55c), + TOBN(0xf550aa3d, 0x8a1fbff0), + TOBN(0x06a1d58b, 0xb7c5da76), + TOBN(0xa79715ee, 0xf29be328), + TOBN(0x14cc5ed2, 0x0f8037e0), + TOBN(0xcc8f6d7e, 0xbf48e1d8), + TOBN(0x4bd407b2, 0x2b4154aa), + TOBN(0x0f1d45b7, 0xff585ac5), + TOBN(0x23a97a7e, 0x36cc88be), + TOBN(0x59e7c97f, 0xbec7e8f3), + TOBN(0xb5a84031, 0x900b1c9e), + TOBN(0xd55e702f, 0x46980c82), + TOBN(0xf482d7ce, 0x6e74fef6), + TOBN(0xf032ea15, 0xd1721d03), + TOBN(0x5983ca01, 0xc64b92ec), + TOBN(0x6fb8f401, 0x378cd2bf), + TOBN(0x33205151, 0x2bd7af42), + TOBN(0xdb7f1447, 0xe6cc254b), + TOBN(0x44ce6cba, 0xced4bb1b), + TOBN(0xda3edbeb, 0xcf9b14ed), + TOBN(0x179727b0, 0x865a8918), + TOBN(0xb06a53ed, 0x9027d831), + TOBN(0xe5db382f, 0x413001ae), + TOBN(0xf8ff9406, 0xad9e530e), + TOBN(0xc9751e76, 0x3dba37bd), + TOBN(0xc1d4dcb2, 0x602646de), + TOBN(0x36c3fab4, 0xd27c7026), + TOBN(0x4df435c9, 0x34028492), + TOBN(0x86ffb7dc, 0x90a6c08f), + TOBN(0x93b4ea98, 0x8d8fddc1), + TOBN(0xd0069127, 0xd5b05aa9), + TOBN(0xb81bdd76, 0x2170481c), + TOBN(0x1f612970, 0xcee2d7af), + TOBN(0x233ba186, 0x515be7ed), + TOBN(0x99b2964f, 0xa090c3a2), + TOBN(0x287c5947, 0x4e6bc05d), + TOBN(0x2e8efc14, 0x1fbecaa6), + TOBN(0xdbbbc2db, 0x04de8ef9), + TOBN(0x2583e9ca, 0x2ad44ce8), + TOBN(0x1a946834, 0xb6150bda), + TOBN(0x99c32718, 0x6af4e23c), + TOBN(0x88719a10, 0xbdba5b26), + TOBN(0x1a723c12, 0xa787e6d7), + TOBN(0x4b82d120, 0xa9210801), + TOBN(0x43db5bfc, 0xe0fd108e), + TOBN(0x08e24fa0, 0x74e5ab31), + TOBN(0x770988c0, 0xbad946e2), + TOBN(0xbbe11757, 0x7a615d6c), + TOBN(0x521f2b18, 0x177b200c), + TOBN(0xd8760273, 0x3ec86a64), + TOBN(0xf12ffa06, 0xd98a0864), + TOBN(0xcee3d226, 0x1ad2ee6b), + TOBN(0x1e8c94e0, 0x4a25619d), + TOBN(0xabf5ae8c, 0xdb0933d7), + TOBN(0xb3970f85, 0xa6e1e4c7), + TOBN(0x8aea7157, 0x5d060c7d), + TOBN(0xecfb8504, 0x58dbef0a), + TOBN(0xa85521ab, 0xdf1cba64), + TOBN(0xad33170d, 0x04507a33), + TOBN(0x15728e5a, 0x8aaac42d), + TOBN(0x15d22618, 0x98fa0510), + TOBN(0x3995497c, 0xea956ae5), + TOBN(0xde2bcbf6, 0x95581718), + TOBN(0xb5c55df0, 0x6f4c52c9), + TOBN(0x9b2783a2, 0xec07a28f), + TOBN(0xe39e772c, 0x180e8603), + TOBN(0x32905e46, 0x2e36ce3b), + TOBN(0xf1746c08, 0xca18217c), + TOBN(0x670c354e, 0x4abc9804), + TOBN(0x9ed52907, 0x7096966d), + TOBN(0x1c62f356, 0x208552bb), + TOBN(0x83655d23, 0xdca3ad96), + TOBN(0x69163fa8, 0xfd24cf5f), + TOBN(0x98da4836, 0x1c55d39a), + TOBN(0xc2007cb8, 0xa163bf05), + TOBN(0x49286651, 0xece45b3d), + TOBN(0xae9f2411, 0x7c4b1fe6), + TOBN(0xee386bfb, 0x5a899fa5), + TOBN(0x0bff5cb6, 0xf406b7ed), + TOBN(0xf44c42e9, 0xa637ed6b), + TOBN(0xe485b576, 0x625e7ec6), + TOBN(0x4fe1356d, 0x6d51c245), + TOBN(0x302b0a6d, 0xf25f1437), + TOBN(0xef9519b3, 0xcd3a431b), + TOBN(0x514a0879, 0x8e3404dd), + TOBN(0x020bbea6, 0x3b139b22), + TOBN(0x29024e08, 0x8a67cc74), + TOBN(0xc4c6628b, 0x80dc1cd1), + TOBN(0xc90fdaa2, 0x2168c234), + TOBN(0xffffffff, 0xffffffff), }; return get_params(ret, kWords, OPENSSL_ARRAY_SIZE(kWords)); } diff --git a/src/workerd/api/crypto/dh.c++ b/src/workerd/api/crypto/dh.c++ index d5857549691..e48816e56bc 100644 --- a/src/workerd/api/crypto/dh.c++ +++ b/src/workerd/api/crypto/dh.c++ @@ -7,7 +7,7 @@ #if WORKERD_BSSL_NEED_DH_PRIMES #include -#endif // WORKERD_BSSL_NEED_DH_PRIMES +#endif // WORKERD_BSSL_NEED_DH_PRIMES #if !_WIN32 #include @@ -21,9 +21,15 @@ namespace { // Diffie-Hellman group. BIGNUM* (*findDiffieHellmanGroup(const char* name))(BIGNUM*) { #if _WIN32 -#define V(n, p) if (_strnicmp(name, n, 7) == 0) {return p;} +#define V(n, p) \ + if (_strnicmp(name, n, 7) == 0) { \ + return p; \ + } #else -#define V(n, p) if (strncasecmp(name, n, 7) == 0) {return p;} +#define V(n, p) \ + if (strncasecmp(name, n, 7) == 0) { \ + return p; \ + } #endif // Only the following primes are supported based on security concerns about the smaller prime // groups (https://www.rfc-editor.org/rfc/rfc8247#section-2.4). @@ -39,8 +45,9 @@ BIGNUM* (*findDiffieHellmanGroup(const char* name))(BIGNUM*) { kj::Own initDhGroup(kj::StringPtr name) { auto group = findDiffieHellmanGroup(name.begin()); - JSG_REQUIRE(group != nullptr, Error, "Failed to init DiffieHellmanGroup: invalid group. Only " - "groups {modp14, modp15, modp16, modp17, modp18} are supported."); + JSG_REQUIRE(group != nullptr, Error, + "Failed to init DiffieHellmanGroup: invalid group. Only " + "groups {modp14, modp15, modp16, modp17, modp18} are supported."); auto groupKey = group(nullptr); KJ_ASSERT(groupKey != nullptr); @@ -59,7 +66,7 @@ kj::Own initDhGroup(kj::StringPtr name) { } kj::Own initDh(kj::OneOf, int>& sizeOrKey, - kj::OneOf, int>& generator) { + kj::OneOf, int>& generator) { KJ_SWITCH_ONEOF(sizeOrKey) { KJ_CASE_ONEOF(size, int) { KJ_SWITCH_ONEOF(generator) { @@ -68,14 +75,12 @@ kj::Own initDh(kj::OneOf, int>& sizeOrKey, // We will only allow it if there is an active IoContext so that // we can enforce a timeout associate with the limit enforcer. JSG_REQUIRE(IoContext::hasCurrent(), Error, - "DiffieHellman key generation requires an active request"); + "DiffieHellman key generation requires an active request"); struct Status { IoContext& context; kj::Maybe status; - } status { - .context = IoContext::current() - }; + } status{.context = IoContext::current()}; auto dh = OSSL_NEW(DH); BN_GENCB cb; @@ -95,11 +100,11 @@ kj::Own initDh(kj::OneOf, int>& sizeOrKey, if (!DH_generate_parameters_ex(dh.get(), size, gen, &cb)) { KJ_IF_SOME(outcome, status.status) { if (outcome == EventOutcome::EXCEEDED_CPU) { - JSG_FAIL_REQUIRE(Error, - "DiffieHellman init failed: key generation exceeded CPU limit"); + JSG_FAIL_REQUIRE( + Error, "DiffieHellman init failed: key generation exceeded CPU limit"); } else if (outcome == EventOutcome::EXCEEDED_MEMORY) { - JSG_FAIL_REQUIRE(Error, - "DiffieHellman init failed: key generation exceeded memory limit"); + JSG_FAIL_REQUIRE( + Error, "DiffieHellman init failed: key generation exceeded memory limit"); } } JSG_FAIL_REQUIRE(Error, "DiffieHellman init failed: could not generate parameters"); @@ -114,15 +119,15 @@ kj::Own initDh(kj::OneOf, int>& sizeOrKey, } } KJ_CASE_ONEOF(key, kj::Array) { - JSG_REQUIRE(key.size() <= INT32_MAX, RangeError, - "DiffieHellman init failed: key is too large"); + JSG_REQUIRE( + key.size() <= INT32_MAX, RangeError, "DiffieHellman init failed: key is too large"); JSG_REQUIRE(key.size() > 0, Error, "DiffieHellman init failed: invalid key"); auto dh = OSSL_NEW(DH); // We use a std::unique_ptr here instead of a kj::Own because DH_set0_pqg takes ownership // and we need to be able to release ownership if the operation succeeds but want the // BIGNUMs to be appropriately freed if the operations fail. - using UniqueBignum = std::unique_ptr; + using UniqueBignum = std::unique_ptr; UniqueBignum bn_g(nullptr, &BN_clear_free); KJ_SWITCH_ONEOF(generator) { @@ -135,7 +140,7 @@ kj::Own initDh(kj::OneOf, int>& sizeOrKey, } KJ_CASE_ONEOF(gen, kj::Array) { JSG_REQUIRE(gen.size() <= INT32_MAX, RangeError, - "DiffieHellman init failed: generator is too large"); + "DiffieHellman init failed: generator is too large"); JSG_REQUIRE(gen.size() > 0, Error, "DiffieHellman init failed: invalid generator"); bn_g.reset(toBignumUnowned(gen)); @@ -147,8 +152,8 @@ kj::Own initDh(kj::OneOf, int>& sizeOrKey, UniqueBignum bn_p(toBignumUnowned(key), &BN_clear_free); JSG_REQUIRE(bn_p != nullptr, Error, "DiffieHellman init failed: could not convert key representation"); - JSG_REQUIRE(DH_set0_pqg(dh, bn_p.get(), nullptr, bn_g.get()), - Error, "DiffieHellman init failed: could not set keys"); + JSG_REQUIRE(DH_set0_pqg(dh, bn_p.get(), nullptr, bn_g.get()), Error, + "DiffieHellman init failed: could not set keys"); bn_g.release(); bn_p.release(); return kj::mv(dh); @@ -157,9 +162,7 @@ kj::Own initDh(kj::OneOf, int>& sizeOrKey, KJ_UNREACHABLE; } -void zeroPadDiffieHellmanSecret(size_t remainder_size, - unsigned char* data, - size_t prime_size) { +void zeroPadDiffieHellmanSecret(size_t remainder_size, unsigned char* data, size_t prime_size) { // DH_size returns number of bytes in a prime number. // DH_compute_key returns number of bytes in a remainder of exponent, which // may have less bytes than a prime number. Therefore add 0-padding to the @@ -175,9 +178,9 @@ void zeroPadDiffieHellmanSecret(size_t remainder_size, DiffieHellman::DiffieHellman(kj::StringPtr group): dh(initDhGroup(group)) {} -DiffieHellman::DiffieHellman(kj::OneOf, int>& sizeOrKey, - kj::OneOf, int>& generator) - : dh(initDh(sizeOrKey, generator)) {} +DiffieHellman::DiffieHellman( + kj::OneOf, int>& sizeOrKey, kj::OneOf, int>& generator) + : dh(initDh(sizeOrKey, generator)) {} kj::Maybe DiffieHellman::check() { ClearErrorOnReturn clearErrorOnReturn; @@ -199,39 +202,39 @@ void DiffieHellman::setPublicKey(kj::ArrayPtr key) { kj::Array DiffieHellman::getPublicKey() { const BIGNUM* pub_key; DH_get0_key(dh, &pub_key, nullptr); - return JSG_REQUIRE_NONNULL(bignumToArrayPadded(*pub_key), Error, - "Error while retrieving DiffieHellman public key"); + return JSG_REQUIRE_NONNULL( + bignumToArrayPadded(*pub_key), Error, "Error while retrieving DiffieHellman public key"); } kj::Array DiffieHellman::getPrivateKey() { const BIGNUM* priv_key; DH_get0_key(dh, nullptr, &priv_key); - return JSG_REQUIRE_NONNULL(bignumToArrayPadded(*priv_key), Error, - "Error while retrieving DiffieHellman private key"); + return JSG_REQUIRE_NONNULL( + bignumToArrayPadded(*priv_key), Error, "Error while retrieving DiffieHellman private key"); } kj::Array DiffieHellman::getGenerator() { const BIGNUM* g; DH_get0_pqg(dh, nullptr, nullptr, &g); - return JSG_REQUIRE_NONNULL(bignumToArrayPadded(*g), Error, - "Error while retrieving DiffieHellman generator"); + return JSG_REQUIRE_NONNULL( + bignumToArrayPadded(*g), Error, "Error while retrieving DiffieHellman generator"); } kj::Array DiffieHellman::getPrime() { const BIGNUM* p; DH_get0_pqg(dh, &p, nullptr, nullptr); - return JSG_REQUIRE_NONNULL(bignumToArrayPadded(*p), Error, - "Error while retrieving DiffieHellman prime"); + return JSG_REQUIRE_NONNULL( + bignumToArrayPadded(*p), Error, "Error while retrieving DiffieHellman prime"); } kj::Array DiffieHellman::computeSecret(kj::ArrayPtr key) { JSG_REQUIRE(key.size() <= INT32_MAX, RangeError, - "DiffieHellman computeSecret() failed: key is too large"); + "DiffieHellman computeSecret() failed: key is too large"); JSG_REQUIRE(key.size() > 0, Error, "DiffieHellman computeSecret() failed: invalid key"); ClearErrorOnReturn clear_error_on_return; - auto k = JSG_REQUIRE_NONNULL(toBignum(key), Error, - "Error getting key while computing DiffieHellman secret"); + auto k = JSG_REQUIRE_NONNULL( + toBignum(key), Error, "Error getting key while computing DiffieHellman secret"); size_t prime_size = DH_size(dh); auto prime_enc = kj::heapArray(prime_size); @@ -244,9 +247,9 @@ kj::Array DiffieHellman::computeSecret(kj::ArrayPtr key) { if (checked && checkResult) { JSG_REQUIRE(!(checkResult & DH_CHECK_PUBKEY_TOO_SMALL), RangeError, - "DiffieHellman computeSecret() failed: Supplied key is too small"); + "DiffieHellman computeSecret() failed: Supplied key is too small"); JSG_REQUIRE(!(checkResult & DH_CHECK_PUBKEY_TOO_LARGE), RangeError, - "DiffieHellman computeSecret() failed: Supplied key is too large"); + "DiffieHellman computeSecret() failed: Supplied key is too large"); } JSG_FAIL_REQUIRE(Error, "Invalid Key"); } @@ -261,8 +264,8 @@ kj::Array DiffieHellman::generateKeys() { OSSLCALL(DH_generate_key(dh)); const BIGNUM* pub_key; DH_get0_key(dh, &pub_key, nullptr); - return JSG_REQUIRE_NONNULL(bignumToArrayPadded(*pub_key), Error, - "Error while generating DiffieHellman keys"); + return JSG_REQUIRE_NONNULL( + bignumToArrayPadded(*pub_key), Error, "Error while generating DiffieHellman keys"); } } // namespace workerd::api diff --git a/src/workerd/api/crypto/dh.h b/src/workerd/api/crypto/dh.h index 3191ba1630d..544629e1978 100644 --- a/src/workerd/api/crypto/dh.h +++ b/src/workerd/api/crypto/dh.h @@ -10,7 +10,7 @@ class DiffieHellman final { public: DiffieHellman(kj::StringPtr group); DiffieHellman(kj::OneOf, int>& sizeOrKey, - kj::OneOf, int>& generator); + kj::OneOf, int>& generator); DiffieHellman(DiffieHellman&&) = default; DiffieHellman& operator=(DiffieHellman&&) = default; KJ_DISALLOW_COPY(DiffieHellman); @@ -22,8 +22,7 @@ class DiffieHellman final { kj::Array getPrivateKey() KJ_WARN_UNUSED_RESULT; kj::Array getGenerator() KJ_WARN_UNUSED_RESULT; kj::Array getPrime() KJ_WARN_UNUSED_RESULT; - kj::Array computeSecret(kj::ArrayPtr key) - KJ_WARN_UNUSED_RESULT; + kj::Array computeSecret(kj::ArrayPtr key) KJ_WARN_UNUSED_RESULT; kj::Array generateKeys() KJ_WARN_UNUSED_RESULT; kj::Maybe check() KJ_WARN_UNUSED_RESULT; diff --git a/src/workerd/api/crypto/digest.c++ b/src/workerd/api/crypto/digest.c++ index b5b7182e88b..99088166a2f 100644 --- a/src/workerd/api/crypto/digest.c++ +++ b/src/workerd/api/crypto/digest.c++ @@ -14,13 +14,20 @@ namespace { class HmacKey final: public CryptoKey::Impl { public: - explicit HmacKey(kj::Array keyData, CryptoKey::HmacKeyAlgorithm keyAlgorithm, - bool extractable, CryptoKeyUsageSet usages) + explicit HmacKey(kj::Array keyData, + CryptoKey::HmacKeyAlgorithm keyAlgorithm, + bool extractable, + CryptoKeyUsageSet usages) : CryptoKey::Impl(extractable, usages), - keyData(kj::mv(keyData)), keyAlgorithm(kj::mv(keyAlgorithm)) {} + keyData(kj::mv(keyData)), + keyAlgorithm(kj::mv(keyAlgorithm)) {} - kj::StringPtr jsgGetMemoryName() const override { return "HmacKey"; } - size_t jsgGetMemorySelfSize() const override { return sizeof(HmacKey); } + kj::StringPtr jsgGetMemoryName() const override { + return "HmacKey"; + } + size_t jsgGetMemorySelfSize() const override { + return sizeof(HmacKey); + } void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const override { tracker.trackFieldWithSize("keyData", keyData.size()); tracker.trackField("keyAlgorithm", keyAlgorithm); @@ -28,30 +35,27 @@ public: private: kj::Array sign( - SubtleCrypto::SignAlgorithm&& algorithm, - kj::ArrayPtr data) const override { + SubtleCrypto::SignAlgorithm&& algorithm, kj::ArrayPtr data) const override { return computeHmac(kj::mv(algorithm), data); } - bool verify( - SubtleCrypto::SignAlgorithm&& algorithm, - kj::ArrayPtr signature, kj::ArrayPtr data) const override { + bool verify(SubtleCrypto::SignAlgorithm&& algorithm, + kj::ArrayPtr signature, + kj::ArrayPtr data) const override { auto messageDigest = computeHmac(kj::mv(algorithm), data); return messageDigest.size() == signature.size() && CRYPTO_memcmp(messageDigest.begin(), signature.begin(), signature.size()) == 0; } kj::Array computeHmac( - SubtleCrypto::SignAlgorithm&& algorithm, - kj::ArrayPtr data) const { + SubtleCrypto::SignAlgorithm&& algorithm, kj::ArrayPtr data) const { // For HMAC, the hash is specified when creating the key, not at call time. auto type = lookupDigestAlgorithm(keyAlgorithm.hash.name).second; auto messageDigest = kj::heapArray(EVP_MD_size(type)); uint messageDigestSize = 0; - auto ptr = HMAC(type, keyData.begin(), keyData.size(), - data.begin(), data.size(), - messageDigest.begin(), &messageDigestSize); + auto ptr = HMAC(type, keyData.begin(), keyData.size(), data.begin(), data.size(), + messageDigest.begin(), &messageDigestSize); JSG_REQUIRE(ptr != nullptr, DOMOperationError, "HMAC computation failed."); KJ_ASSERT(messageDigestSize == messageDigest.size()); @@ -65,7 +69,8 @@ private: if (format == "jwk") { // This assert enforces that the slice logic to fill in `.alg` below is safe. JSG_REQUIRE(keyAlgorithm.hash.name.slice(0, 4) == "SHA-"_kj, DOMNotSupportedError, - "Unimplemented JWK key export format for key algorithm \"", keyAlgorithm.hash.name, "\"."); + "Unimplemented JWK key export format for key algorithm \"", keyAlgorithm.hash.name, + "\"."); SubtleCrypto::JsonWebKey jwk; jwk.kty = kj::str("oct"); @@ -89,8 +94,12 @@ private: return kj::heapArray(keyData.asPtr()); } - kj::StringPtr getAlgorithmName() const override { return "HMAC"; } - CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override { return keyAlgorithm; } + kj::StringPtr getAlgorithmName() const override { + return "HMAC"; + } + CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override { + return keyAlgorithm; + } bool equals(const CryptoKey::Impl& other) const override final { return this == &other || (other.getType() == "secret"_kj && other.equals(keyData)); @@ -98,7 +107,7 @@ private: bool equals(const kj::Array& other) const override final { return keyData.size() == other.size() && - CRYPTO_memcmp(keyData.begin(), other.begin(), keyData.size()) == 0; + CRYPTO_memcmp(keyData.begin(), other.begin(), keyData.size()) == 0; } ZeroOnFree keyData; @@ -126,7 +135,8 @@ kj::Own initHmacContext(kj::StringPtr algorithm, HmacContext::KeyData& static constexpr auto mt = ""_kjc; auto hmac_ctx = OSSL_NEW(HMAC_CTX); JSG_REQUIRE(HMAC_Init_ex(hmac_ctx.get(), key.size() ? key.asChars().begin() : mt.begin(), - key.size(), md, nullptr), Error, "Failed to initalize HMAC"); + key.size(), md, nullptr), + Error, "Failed to initalize HMAC"); return kj::mv(hmac_ctx); }; @@ -174,8 +184,7 @@ kj::ArrayPtr HmacContext::digest() { auto theCtx = kj::mv(ctx); unsigned len; auto digest = kj::heapArray(HMAC_size(theCtx.get())); - JSG_REQUIRE(HMAC_Final(theCtx.get(), digest.begin(), &len), Error, - "Failed to finalize HMAC"); + JSG_REQUIRE(HMAC_Final(theCtx.get(), digest.begin(), &len), Error, "Failed to finalize HMAC"); KJ_ASSERT(len == digest.size()); ret = digest.asPtr(); state = kj::mv(digest); @@ -199,18 +208,18 @@ size_t HmacContext::size() const { KJ_UNREACHABLE; } -kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateHmac( - jsg::Lock& js, kj::StringPtr normalizedName, - SubtleCrypto::GenerateKeyAlgorithm&& algorithm, bool extractable, - kj::ArrayPtr keyUsages) { +kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateHmac(jsg::Lock& js, + kj::StringPtr normalizedName, + SubtleCrypto::GenerateKeyAlgorithm&& algorithm, + bool extractable, + kj::ArrayPtr keyUsages) { KJ_REQUIRE(normalizedName == "HMAC"); - kj::StringPtr hash = api::getAlgorithmName(JSG_REQUIRE_NONNULL(algorithm.hash, TypeError, - "Missing field \"hash\" in \"algorithm\".")); + kj::StringPtr hash = api::getAlgorithmName( + JSG_REQUIRE_NONNULL(algorithm.hash, TypeError, "Missing field \"hash\" in \"algorithm\".")); auto [normalizedHashName, hashEvpMd] = lookupDigestAlgorithm(hash); - auto usages = - CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::generate, keyUsages, - CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); + auto usages = CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::generate, + keyUsages, CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); // If the user requested a specific HMAC key length, honor it. auto length = algorithm.length.orDefault(EVP_MD_block_size(hashEvpMd) * 8); @@ -222,25 +231,27 @@ kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateHmac( IoContext::current().getEntropySource().generate(keyDataArray); zeroOutTrailingKeyBits(keyDataArray, length); - auto keyAlgorithm = CryptoKey::HmacKeyAlgorithm{normalizedName, {normalizedHashName}, - static_cast(length)}; + auto keyAlgorithm = CryptoKey::HmacKeyAlgorithm{ + normalizedName, {normalizedHashName}, static_cast(length)}; - return jsg::alloc(kj::heap(kj::mv(keyDataArray), - kj::mv(keyAlgorithm), extractable, usages)); + return jsg::alloc( + kj::heap(kj::mv(keyDataArray), kj::mv(keyAlgorithm), extractable, usages)); } -kj::Own CryptoKey::Impl::importHmac( - jsg::Lock& js, kj::StringPtr normalizedName, kj::StringPtr format, +kj::Own CryptoKey::Impl::importHmac(jsg::Lock& js, + kj::StringPtr normalizedName, + kj::StringPtr format, SubtleCrypto::ImportKeyData keyData, - SubtleCrypto::ImportKeyAlgorithm&& algorithm, bool extractable, + SubtleCrypto::ImportKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages) { auto usages = CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::importSecret, keyUsages, CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); kj::Array keyDataArray; - kj::StringPtr hash = api::getAlgorithmName(JSG_REQUIRE_NONNULL(algorithm.hash, TypeError, - "Missing field \"hash\" in \"algorithm\".")); + kj::StringPtr hash = api::getAlgorithmName( + JSG_REQUIRE_NONNULL(algorithm.hash, TypeError, "Missing field \"hash\" in \"algorithm\".")); if (format == "raw") { // NOTE: Checked in SubtleCrypto::importKey(). @@ -249,7 +260,8 @@ kj::Own CryptoKey::Impl::importHmac( auto& keyDataJwk = keyData.get(); JSG_REQUIRE(keyDataJwk.kty == "oct", DOMDataError, "HMAC \"jwk\" key import requires a JSON Web Key with Key Type parameter " - "(\"kty\") equal to \"oct\" (encountered \"", keyDataJwk.kty, "\")."); + "(\"kty\") equal to \"oct\" (encountered \"", + keyDataJwk.kty, "\")."); // https://www.rfc-editor.org/rfc/rfc7518.txt Section 6.1 keyDataArray = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.k), DOMDataError, "HMAC \"jwk\" key import requires a base64Url encoding of the key"); @@ -259,15 +271,16 @@ kj::Own CryptoKey::Impl::importHmac( auto expectedAlg = kj::str("HS", hash.slice(4)); JSG_REQUIRE(alg == expectedAlg, DOMDataError, "HMAC \"jwk\" key import specifies \"alg\" that is incompatible with the hash name " - "(encountered \"", alg, "\", expected \"", expectedAlg, "\")."); + "(encountered \"", + alg, "\", expected \"", expectedAlg, "\")."); } else { // TODO(conform): Spec says this for non-SHA hashes: // > Perform any key import steps defined by other applicable specifications, passing // > format, jwk and hash and obtaining hash. // What other hashes should be supported (if any)? For example, technically we support MD5 // below in `lookupDigestAlgorithm` for "raw" keys... - JSG_FAIL_REQUIRE(DOMNotSupportedError, - "Unrecognized or unimplemented hash algorithm requested", alg); + JSG_FAIL_REQUIRE( + DOMNotSupportedError, "Unrecognized or unimplemented hash algorithm requested", alg); } } } else { @@ -281,17 +294,18 @@ kj::Own CryptoKey::Impl::importHmac( auto keySize = keyDataArray.size() * 8; auto length = algorithm.length.orDefault(keySize); if (length == 0 || length > keySize || length <= keySize - 8) { - JSG_FAIL_REQUIRE(DOMDataError, - "Imported HMAC key length (", length, ") must be a non-zero value up to 7 bits less than, " - "and no greater than, the bit length of the raw key data (", keySize, ")."); + JSG_FAIL_REQUIRE(DOMDataError, "Imported HMAC key length (", length, + ") must be a non-zero value up to 7 bits less than, " + "and no greater than, the bit length of the raw key data (", + keySize, ")."); } // Not required by the spec, but zeroing out the unused bits makes me feel better. zeroOutTrailingKeyBits(keyDataArray, length); auto normalizedHashName = lookupDigestAlgorithm(hash).first; - auto keyAlgorithm = CryptoKey::HmacKeyAlgorithm{normalizedName, {normalizedHashName}, - static_cast(length)}; + auto keyAlgorithm = CryptoKey::HmacKeyAlgorithm{ + normalizedName, {normalizedHashName}, static_cast(length)}; return kj::heap(kj::mv(keyDataArray), kj::mv(keyAlgorithm), extractable, usages); } @@ -316,9 +330,10 @@ void checkXofLen(EVP_MD_CTX* ctx, kj::Maybe& maybeXof) { } } // namespace -HashContext::HashContext(kj::OneOf, kj::Array> state, - kj::Maybe maybeXof) - : state(kj::mv(state)), maybeXof(kj::mv(maybeXof)) { +HashContext::HashContext( + kj::OneOf, kj::Array> state, kj::Maybe maybeXof) + : state(kj::mv(state)), + maybeXof(kj::mv(maybeXof)) { checkXofLen(this->state.get>().get(), this->maybeXof); } diff --git a/src/workerd/api/crypto/digest.h b/src/workerd/api/crypto/digest.h index 2969ef63d04..840b0f87aac 100644 --- a/src/workerd/api/crypto/digest.h +++ b/src/workerd/api/crypto/digest.h @@ -40,8 +40,7 @@ class HashContext final { size_t size() const; private: - HashContext(kj::OneOf, kj::Array>, - kj::Maybe maybeXof); + HashContext(kj::OneOf, kj::Array>, kj::Maybe maybeXof); // Will be kj::Own while the hash data is being updated, // and kj::Array after the digest() has been called. @@ -49,4 +48,3 @@ class HashContext final { kj::Maybe maybeXof; }; } // namespace workerd::api - diff --git a/src/workerd/api/crypto/ec.c++ b/src/workerd/api/crypto/ec.c++ index da970ae6709..ce3887d3be2 100644 --- a/src/workerd/api/crypto/ec.c++ +++ b/src/workerd/api/crypto/ec.c++ @@ -18,10 +18,11 @@ namespace workerd::api { -Ec::Ec(EC_KEY* key) : key(key), x(OSSL_NEW(BIGNUM)), y(OSSL_NEW(BIGNUM)) { +Ec::Ec(EC_KEY* key): key(key), x(OSSL_NEW(BIGNUM)), y(OSSL_NEW(BIGNUM)) { KJ_ASSERT(key != nullptr); group = EC_KEY_get0_group(key); - JSG_REQUIRE(1 == EC_POINT_get_affine_coordinates(group, getPublicKey(), x.get(), y.get(), nullptr), + JSG_REQUIRE( + 1 == EC_POINT_get_affine_coordinates(group, getPublicKey(), x.get(), y.get(), nullptr), InternalDOMOperationError, "Error getting affine coordinates for export", internalDescribeOpensslErrors()); } @@ -43,11 +44,10 @@ const BIGNUM* Ec::getPrivateKey() const { } SubtleCrypto::JsonWebKey Ec::toJwk(KeyType keyType, kj::StringPtr curveName) const { - JSG_REQUIRE(group != nullptr, DOMOperationError, - "No elliptic curve group in this key", tryDescribeOpensslErrors()); - JSG_REQUIRE(getPublicKey() != nullptr, DOMOperationError, - "No public elliptic curve key data in this key", + JSG_REQUIRE(group != nullptr, DOMOperationError, "No elliptic curve group in this key", tryDescribeOpensslErrors()); + JSG_REQUIRE(getPublicKey() != nullptr, DOMOperationError, + "No public elliptic curve key data in this key", tryDescribeOpensslErrors()); auto groupDegreeInBytes = integerCeilDivision(getDegree(), 8u); // EC_GROUP_get_degree returns number of bits. We need this because x, y, & d need to match the @@ -58,9 +58,8 @@ SubtleCrypto::JsonWebKey Ec::toJwk(KeyType keyType, kj::StringPtr curveName) con jwk.crv = kj::str(curveName); static constexpr auto handleBn = [](const BIGNUM& bn, size_t size) { - return JSG_REQUIRE_NONNULL(bignumToArrayPadded(bn, size), - InternalDOMOperationError, "Error converting EC affine co-ordinates to padded array", - internalDescribeOpensslErrors()); + return JSG_REQUIRE_NONNULL(bignumToArrayPadded(bn, size), InternalDOMOperationError, + "Error converting EC affine co-ordinates to padded array", internalDescribeOpensslErrors()); }; auto xa = handleBn(*x, groupDegreeInBytes); @@ -72,8 +71,8 @@ SubtleCrypto::JsonWebKey Ec::toJwk(KeyType keyType, kj::StringPtr curveName) con if (keyType == KeyType::PRIVATE) { const auto privateKey = getPrivateKey(); JSG_REQUIRE(privateKey != nullptr, InternalDOMOperationError, - "Error getting private key material for JSON Web Key export", - internalDescribeOpensslErrors()); + "Error getting private key material for JSON Web Key export", + internalDescribeOpensslErrors()); auto pk = handleBn(*privateKey, groupDegreeInBytes); jwk.d = kj::encodeBase64Url(pk); } @@ -81,13 +80,11 @@ SubtleCrypto::JsonWebKey Ec::toJwk(KeyType keyType, kj::StringPtr curveName) con } kj::Array Ec::getRawPublicKey() const { - JSG_REQUIRE_NONNULL(group, InternalDOMOperationError, - "No elliptic curve group in this key", - tryDescribeOpensslErrors()); + JSG_REQUIRE_NONNULL(group, InternalDOMOperationError, "No elliptic curve group in this key", + tryDescribeOpensslErrors()); auto publicKey = getPublicKey(); JSG_REQUIRE(publicKey != nullptr, InternalDOMOperationError, - "No public elliptic curve key data in this key", - tryDescribeOpensslErrors()); + "No public elliptic curve key data in this key", tryDescribeOpensslErrors()); // Serialize the public key as an uncompressed point in X9.62 form. uint8_t* raw; @@ -98,8 +95,9 @@ kj::Array Ec::getRawPublicKey() const { internalDescribeOpensslErrors()); KJ_DEFER(CBB_cleanup(&cbb)); - JSG_REQUIRE(1 == EC_POINT_point2cbb(&cbb, group, publicKey, POINT_CONVERSION_UNCOMPRESSED, - nullptr), InternalDOMOperationError, "Failed to convert to serialize EC key", + JSG_REQUIRE( + 1 == EC_POINT_point2cbb(&cbb, group, publicKey, POINT_CONVERSION_UNCOMPRESSED, nullptr), + InternalDOMOperationError, "Failed to convert to serialize EC key", internalDescribeOpensslErrors()); JSG_REQUIRE(1 == CBB_finish(&cbb, &raw, &raw_len), InternalDOMOperationError, @@ -110,9 +108,8 @@ kj::Array Ec::getRawPublicKey() const { CryptoKey::AsymmetricKeyDetails Ec::getAsymmetricKeyDetail() const { // Adapted from Node.js' GetEcKeyDetail - return CryptoKey::AsymmetricKeyDetails { - .namedCurve = kj::str(OBJ_nid2sn(EC_GROUP_get_curve_name(group))) - }; + return CryptoKey::AsymmetricKeyDetails{ + .namedCurve = kj::str(OBJ_nid2sn(EC_GROUP_get_curve_name(group)))}; } kj::Maybe Ec::tryGetEc(const EVP_PKEY* key) { @@ -131,14 +128,19 @@ namespace { class EllipticKey final: public AsymmetricKeyCryptoKeyImpl { public: explicit EllipticKey(AsymmetricKeyData keyData, - CryptoKey::EllipticKeyAlgorithm keyAlgorithm, - uint rsSize, - bool extractable) + CryptoKey::EllipticKeyAlgorithm keyAlgorithm, + uint rsSize, + bool extractable) : AsymmetricKeyCryptoKeyImpl(kj::mv(keyData), extractable), - keyAlgorithm(kj::mv(keyAlgorithm)), rsSize(rsSize) {} + keyAlgorithm(kj::mv(keyAlgorithm)), + rsSize(rsSize) {} - CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override { return keyAlgorithm; } - kj::StringPtr getAlgorithmName() const override { return keyAlgorithm.name; } + CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override { + return keyAlgorithm; + } + kj::StringPtr getAlgorithmName() const override { + return keyAlgorithm.name; + } void requireSigningAbility() const { // This assert is internal to our WebCrypto implementation because we share the AsymmetricKey @@ -161,31 +163,39 @@ public: "algorithms for historical reasons.)")); } - kj::Array deriveBits( - jsg::Lock& js, SubtleCrypto::DeriveKeyAlgorithm&& algorithm, + kj::Array deriveBits(jsg::Lock& js, + SubtleCrypto::DeriveKeyAlgorithm&& algorithm, kj::Maybe resultBitLength) const override final { - JSG_REQUIRE(keyAlgorithm.name == "ECDH", DOMNotSupportedError, "" - "The deriveBits operation is not implemented for \"", keyAlgorithm.name, "\"."); + JSG_REQUIRE(keyAlgorithm.name == "ECDH", DOMNotSupportedError, + "" + "The deriveBits operation is not implemented for \"", + keyAlgorithm.name, "\"."); - JSG_REQUIRE(getTypeEnum() == KeyType::PRIVATE, DOMInvalidAccessError, "" - "The deriveBits operation is only valid for a private key, not \"", getType(), "\"."); + JSG_REQUIRE(getTypeEnum() == KeyType::PRIVATE, DOMInvalidAccessError, + "" + "The deriveBits operation is only valid for a private key, not \"", + getType(), "\"."); - auto& publicKey = JSG_REQUIRE_NONNULL(algorithm.$public, TypeError, - "Missing field \"public\" in \"derivedKeyParams\"."); + auto& publicKey = JSG_REQUIRE_NONNULL( + algorithm.$public, TypeError, "Missing field \"public\" in \"derivedKeyParams\"."); - JSG_REQUIRE(publicKey->getType() == "public"_kj, DOMInvalidAccessError, "" - "The provided key has type \"", publicKey->getType(), "\", not \"public\""); + JSG_REQUIRE(publicKey->getType() == "public"_kj, DOMInvalidAccessError, + "" + "The provided key has type \"", + publicKey->getType(), "\", not \"public\""); JSG_REQUIRE(getAlgorithm(js).which() == publicKey->getAlgorithm(js).which(), - DOMInvalidAccessError, "Base ", getAlgorithmName(), " private key cannot be used to derive" - " a key from a peer ", publicKey->getAlgorithmName(), " public key"); + DOMInvalidAccessError, "Base ", getAlgorithmName(), + " private key cannot be used to derive" + " a key from a peer ", + publicKey->getAlgorithmName(), " public key"); JSG_REQUIRE(getAlgorithmName() == publicKey->getAlgorithmName(), DOMInvalidAccessError, "Private key for derivation is using \"", getAlgorithmName(), "\" while public key is using \"", publicKey->getAlgorithmName(), "\"."); - auto publicCurve = publicKey->getAlgorithm(js).get() - .namedCurve; + auto publicCurve = + publicKey->getAlgorithm(js).get().namedCurve; JSG_REQUIRE(keyAlgorithm.namedCurve == publicCurve, DOMInvalidAccessError, "Private key for derivation is using curve \"", keyAlgorithm.namedCurve, "\" while public key is using \"", publicCurve, "\"."); @@ -196,15 +206,13 @@ public: auto& publicKeyImpl = kj::downcast(*publicKey->impl); // Adapted from https://wiki.openssl.org/index.php/Elliptic_Curve_Diffie_Hellman: - auto privateEcKey = JSG_REQUIRE_NONNULL(Ec::tryGetEc(getEvpPkey()), - InternalDOMOperationError, "No elliptic curve data backing key", - tryDescribeOpensslErrors()); - auto publicEcKey = JSG_REQUIRE_NONNULL(Ec::tryGetEc(publicKeyImpl.getEvpPkey()), - InternalDOMOperationError, "No elliptic curve data backing key", - tryDescribeOpensslErrors()); + auto privateEcKey = JSG_REQUIRE_NONNULL(Ec::tryGetEc(getEvpPkey()), InternalDOMOperationError, + "No elliptic curve data backing key", tryDescribeOpensslErrors()); + auto publicEcKey = + JSG_REQUIRE_NONNULL(Ec::tryGetEc(publicKeyImpl.getEvpPkey()), InternalDOMOperationError, + "No elliptic curve data backing key", tryDescribeOpensslErrors()); JSG_REQUIRE(publicEcKey.getPublicKey() != nullptr, DOMOperationError, - "No public elliptic curve key data in this key", - tryDescribeOpensslErrors()); + "No public elliptic curve key data in this key", tryDescribeOpensslErrors()); auto fieldSize = privateEcKey.getDegree(); // Assuming that `fieldSize` will always be a sane value since it's related to the keys we @@ -213,11 +221,8 @@ public: kj::Vector sharedSecret; sharedSecret.resize( integerCeilDivision::type>(fieldSize, 8u)); - auto written = ECDH_compute_key(sharedSecret.begin(), - sharedSecret.capacity(), - publicEcKey.getPublicKey(), - privateEcKey.getKey(), - nullptr); + auto written = ECDH_compute_key(sharedSecret.begin(), sharedSecret.capacity(), + publicEcKey.getPublicKey(), privateEcKey.getKey(), nullptr); JSG_REQUIRE(written > 0, DOMOperationError, "Failed to generate shared ECDH secret", tryDescribeOpensslErrors()); @@ -371,11 +376,17 @@ public: static kj::OneOf, CryptoKeyPair> generateElliptic( kj::StringPtr normalizedName, - SubtleCrypto::GenerateKeyAlgorithm&& algorithm, bool extractable, - CryptoKeyUsageSet privateKeyUsages, CryptoKeyUsageSet publicKeyUsages); + SubtleCrypto::GenerateKeyAlgorithm&& algorithm, + bool extractable, + CryptoKeyUsageSet privateKeyUsages, + CryptoKeyUsageSet publicKeyUsages); - kj::StringPtr jsgGetMemoryName() const override { return "EllipticKey"; } - size_t jsgGetMemorySelfSize() const override { return sizeof(EllipticKey); } + kj::StringPtr jsgGetMemoryName() const override { + return "EllipticKey"; + } + size_t jsgGetMemorySelfSize() const override { + return sizeof(EllipticKey); + } void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const override { AsymmetricKeyCryptoKeyImpl::jsgGetMemoryInfo(tracker); tracker.trackField("keyAlgorithm", keyAlgorithm); @@ -392,8 +403,8 @@ private: JSG_REQUIRE(getTypeEnum() == KeyType::PUBLIC, DOMInvalidAccessError, "Raw export of elliptic curve keys is only allowed for public keys."); return JSG_REQUIRE_NONNULL(Ec::tryGetEc(getEvpPkey()), InternalDOMOperationError, - "No elliptic curve data backing key", - tryDescribeOpensslErrors()).getRawPublicKey(); + "No elliptic curve data backing key", tryDescribeOpensslErrors()) + .getRawPublicKey(); } CryptoKey::AsymmetricKeyDetails getAsymmetricKeyDetail() const override { @@ -412,7 +423,7 @@ struct EllipticCurveInfo { }; EllipticCurveInfo lookupEllipticCurve(kj::StringPtr curveName) { - static const std::map registeredCurves { + static const std::map registeredCurves{ {"P-256", {"P-256", NID_X9_62_prime256v1, 32}}, {"P-384", {"P-384", NID_secp384r1, 48}}, {"P-521", {"P-521", NID_secp521r1, 66}}, @@ -426,14 +437,16 @@ EllipticCurveInfo lookupEllipticCurve(kj::StringPtr curveName) { kj::OneOf, CryptoKeyPair> EllipticKey::generateElliptic( kj::StringPtr normalizedName, - SubtleCrypto::GenerateKeyAlgorithm&& algorithm, bool extractable, - CryptoKeyUsageSet privateKeyUsages, CryptoKeyUsageSet publicKeyUsages) { - kj::StringPtr namedCurve = JSG_REQUIRE_NONNULL(algorithm.namedCurve,TypeError, - "Missing field \"namedCurve\" in \"algorithm\"."); + SubtleCrypto::GenerateKeyAlgorithm&& algorithm, + bool extractable, + CryptoKeyUsageSet privateKeyUsages, + CryptoKeyUsageSet publicKeyUsages) { + kj::StringPtr namedCurve = JSG_REQUIRE_NONNULL( + algorithm.namedCurve, TypeError, "Missing field \"namedCurve\" in \"algorithm\"."); auto [normalizedNamedCurve, curveId, rsSize] = lookupEllipticCurve(namedCurve); - auto keyAlgorithm = CryptoKey::EllipticKeyAlgorithm { + auto keyAlgorithm = CryptoKey::EllipticKeyAlgorithm{ normalizedName, normalizedNamedCurve, }; @@ -443,45 +456,44 @@ kj::OneOf, CryptoKeyPair> EllipticKey::generateElliptic( // https://stackoverflow.com/questions/18155559/how-does-one-access-the-raw-ecdh-public-key-private-key-and-params-inside-opens // for the reference on how to deserialize the public/private key. - auto ecPrivateKey = OSSLCALL_OWN(EC_KEY, EC_KEY_new_by_curve_name(curveId), - InternalDOMOperationError, "Error generating EC \"", namedCurve, "\" key", - internalDescribeOpensslErrors()); + auto ecPrivateKey = + OSSLCALL_OWN(EC_KEY, EC_KEY_new_by_curve_name(curveId), InternalDOMOperationError, + "Error generating EC \"", namedCurve, "\" key", internalDescribeOpensslErrors()); OSSLCALL(EC_KEY_generate_key(ecPrivateKey)); auto privateEvpPKey = OSSL_NEW(EVP_PKEY); OSSLCALL(EVP_PKEY_set1_EC_KEY(privateEvpPKey.get(), ecPrivateKey.get())); - auto ecPublicKey = OSSLCALL_OWN(EC_KEY, EC_KEY_new_by_curve_name(curveId), - InternalDOMOperationError, "Error generating EC \"", namedCurve, "\" key", - internalDescribeOpensslErrors()); + auto ecPublicKey = + OSSLCALL_OWN(EC_KEY, EC_KEY_new_by_curve_name(curveId), InternalDOMOperationError, + "Error generating EC \"", namedCurve, "\" key", internalDescribeOpensslErrors()); OSSLCALL(EC_KEY_set_public_key(ecPublicKey, EC_KEY_get0_public_key(ecPrivateKey))); auto publicEvpPKey = OSSL_NEW(EVP_PKEY); OSSLCALL(EVP_PKEY_set1_EC_KEY(publicEvpPKey.get(), ecPublicKey.get())); - AsymmetricKeyData privateKeyData { + AsymmetricKeyData privateKeyData{ .evpPkey = kj::mv(privateEvpPKey), .keyType = KeyType::PRIVATE, .usages = privateKeyUsages, }; - AsymmetricKeyData publicKeyData { + AsymmetricKeyData publicKeyData{ .evpPkey = kj::mv(publicEvpPKey), .keyType = KeyType::PUBLIC, .usages = publicKeyUsages, }; - auto privateKey = jsg::alloc(kj::heap(kj::mv(privateKeyData), - keyAlgorithm, rsSize, extractable)); - auto publicKey = jsg::alloc(kj::heap(kj::mv(publicKeyData), - keyAlgorithm, rsSize, true)); + auto privateKey = jsg::alloc( + kj::heap(kj::mv(privateKeyData), keyAlgorithm, rsSize, extractable)); + auto publicKey = jsg::alloc( + kj::heap(kj::mv(publicKeyData), keyAlgorithm, rsSize, true)); - return CryptoKeyPair { - .publicKey = kj::mv(publicKey), - .privateKey = kj::mv(privateKey) - }; + return CryptoKeyPair{.publicKey = kj::mv(publicKey), .privateKey = kj::mv(privateKey)}; } -AsymmetricKeyData importEllipticRaw(SubtleCrypto::ImportKeyData keyData, int curveId, - kj::StringPtr normalizedName, kj::ArrayPtr keyUsages, +AsymmetricKeyData importEllipticRaw(SubtleCrypto::ImportKeyData keyData, + int curveId, + kj::StringPtr normalizedName, + kj::ArrayPtr keyUsages, CryptoKeyUsageSet allowedUsages) { // Import an elliptic key represented by raw data, only public keys are supported. JSG_REQUIRE(keyData.is>(), DOMDataError, @@ -489,19 +501,23 @@ AsymmetricKeyData importEllipticRaw(SubtleCrypto::ImportKeyData keyData, int cur const auto& raw = keyData.get>(); - auto usages = CryptoKeyUsageSet::validate(normalizedName, - CryptoKeyUsageSet::Context::importPublic, keyUsages, allowedUsages); + auto usages = CryptoKeyUsageSet::validate( + normalizedName, CryptoKeyUsageSet::Context::importPublic, keyUsages, allowedUsages); if (curveId == NID_ED25519 || curveId == NID_X25519) { auto evpId = curveId == NID_X25519 ? EVP_PKEY_X25519 : EVP_PKEY_ED25519; auto curveName = curveId == NID_X25519 ? "X25519" : "Ed25519"; - JSG_REQUIRE(raw.size() == 32, DOMDataError, curveName, " raw keys must be exactly 32-bytes " - "(provided ", raw.size(), ")."); + JSG_REQUIRE(raw.size() == 32, DOMDataError, curveName, + " raw keys must be exactly 32-bytes " + "(provided ", + raw.size(), ")."); - return { OSSLCALL_OWN(EVP_PKEY, EVP_PKEY_new_raw_public_key(evpId, nullptr, - raw.begin(), raw.size()), InternalDOMOperationError, "Failed to import raw public EDDSA", - raw.size(), internalDescribeOpensslErrors()), KeyType::PUBLIC, usages }; + return { + OSSLCALL_OWN(EVP_PKEY, EVP_PKEY_new_raw_public_key(evpId, nullptr, raw.begin(), raw.size()), + InternalDOMOperationError, "Failed to import raw public EDDSA", raw.size(), + internalDescribeOpensslErrors()), + KeyType::PUBLIC, usages}; } auto ecKey = OSSLCALL_OWN(EC_KEY, EC_KEY_new_by_curve_name(curveId), DOMOperationError, @@ -509,9 +525,8 @@ AsymmetricKeyData importEllipticRaw(SubtleCrypto::ImportKeyData keyData, int cur auto ecGroup = EC_KEY_get0_group(ecKey.get()); auto point = OSSL_NEW(EC_POINT, ecGroup); - JSG_REQUIRE(1 == EC_POINT_oct2point(ecGroup, point.get(), raw.begin(), - raw.size(), nullptr), DOMDataError, "Failed to import raw EC key data", - tryDescribeOpensslErrors()); + JSG_REQUIRE(1 == EC_POINT_oct2point(ecGroup, point.get(), raw.begin(), raw.size(), nullptr), + DOMDataError, "Failed to import raw EC key data", tryDescribeOpensslErrors()); JSG_REQUIRE(1 == EC_KEY_set_public_key(ecKey.get(), point.get()), InternalDOMOperationError, "Failed to set EC raw public key", internalDescribeOpensslErrors()); JSG_REQUIRE(1 == EC_KEY_check_key(ecKey.get()), DOMDataError, "Invalid raw EC key provided", @@ -520,41 +535,44 @@ AsymmetricKeyData importEllipticRaw(SubtleCrypto::ImportKeyData keyData, int cur auto evpPkey = OSSL_NEW(EVP_PKEY); OSSLCALL(EVP_PKEY_set1_EC_KEY(evpPkey.get(), ecKey.get())); - return AsymmetricKeyData{ kj::mv(evpPkey), KeyType::PUBLIC, usages }; + return AsymmetricKeyData{kj::mv(evpPkey), KeyType::PUBLIC, usages}; } -kj::Own ellipticJwkReader(int curveId, SubtleCrypto::JsonWebKey&& keyDataJwk, - kj::StringPtr normalizedName) { +kj::Own ellipticJwkReader( + int curveId, SubtleCrypto::JsonWebKey&& keyDataJwk, kj::StringPtr normalizedName) { if (curveId == NID_ED25519 || curveId == NID_X25519) { auto evpId = curveId == NID_X25519 ? EVP_PKEY_X25519 : EVP_PKEY_ED25519; auto curveName = curveId == NID_X25519 ? "X25519" : "Ed25519"; - JSG_REQUIRE(keyDataJwk.kty == "OKP", DOMDataError, - curveName, " \"jwk\" key imports requires a JSON Web Key with Key Type parameter " - "\"kty\" (\"", keyDataJwk.kty, "\") equal to \"OKP\"."); - auto& crv = JSG_REQUIRE_NONNULL(keyDataJwk.crv, DOMDataError, - "Missing field \"crv\" for ", curveName, " key."); - JSG_REQUIRE(crv == curveName, DOMNotSupportedError, - "Only ", curveName, " is supported but \"", crv, "\" was requested."); + JSG_REQUIRE(keyDataJwk.kty == "OKP", DOMDataError, curveName, + " \"jwk\" key imports requires a JSON Web Key with Key Type parameter " + "\"kty\" (\"", + keyDataJwk.kty, "\") equal to \"OKP\"."); + auto& crv = JSG_REQUIRE_NONNULL( + keyDataJwk.crv, DOMDataError, "Missing field \"crv\" for ", curveName, " key."); + JSG_REQUIRE(crv == curveName, DOMNotSupportedError, "Only ", curveName, " is supported but \"", + crv, "\" was requested."); KJ_IF_SOME(alg, keyDataJwk.alg) { // If this JWK specifies an algorithm, make sure it jives with the hash we were passed via // importKey(). if (curveId == NID_ED25519) { - JSG_REQUIRE(alg == "EdDSA", DOMDataError, - "JSON Web Key Algorithm parameter \"alg\" (\"", alg, "\") does not match requested " + JSG_REQUIRE(alg == "EdDSA", DOMDataError, "JSON Web Key Algorithm parameter \"alg\" (\"", + alg, + "\") does not match requested " "Ed25519 curve."); } } - auto x = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.x), DOMDataError, - "Invalid ", crv, " key in JSON WebKey; missing or invalid public key component (\"x\")."); + auto x = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.x), DOMDataError, "Invalid ", crv, + " key in JSON WebKey; missing or invalid public key component (\"x\")."); JSG_REQUIRE(x.size() == 32, DOMDataError, "Invalid length ", x.size(), " for public key"); if (keyDataJwk.d == kj::none) { // This is a public key. - return OSSLCALL_OWN(EVP_PKEY, EVP_PKEY_new_raw_public_key(evpId, nullptr, - x.begin(), x.size()), InternalDOMOperationError, - "Failed to construct ", crv, " public key", internalDescribeOpensslErrors()); + return OSSLCALL_OWN(EVP_PKEY, + EVP_PKEY_new_raw_public_key(evpId, nullptr, x.begin(), x.size()), + InternalDOMOperationError, "Failed to construct ", crv, " public key", + internalDescribeOpensslErrors()); } // This is a private key. The Section 2 of the RFC says... @@ -564,24 +582,25 @@ kj::Own ellipticJwkReader(int curveId, SubtleCrypto::JsonWebKey&& keyD // ... but there's nothing really to do beside enforce that it's set? The NodeJS implementation // seems to throw it away when a private key is provided. - auto d = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.d), DOMDataError, - "Invalid ", curveName, " key in JSON Web Key; missing or invalid private key component (\"d\")."); + auto d = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.d), DOMDataError, "Invalid ", curveName, + " key in JSON Web Key; missing or invalid private key component (\"d\")."); JSG_REQUIRE(d.size() == 32, DOMDataError, "Invalid length ", d.size(), " for private key"); - return OSSLCALL_OWN(EVP_PKEY, EVP_PKEY_new_raw_private_key(evpId, nullptr, - d.begin(), d.size()), InternalDOMOperationError, - "Failed to construct ", crv, " private key", internalDescribeOpensslErrors()); + return OSSLCALL_OWN(EVP_PKEY, EVP_PKEY_new_raw_private_key(evpId, nullptr, d.begin(), d.size()), + InternalDOMOperationError, "Failed to construct ", crv, " private key", + internalDescribeOpensslErrors()); } JSG_REQUIRE(keyDataJwk.kty == "EC", DOMDataError, "Elliptic curve \"jwk\" key import requires a JSON Web Key with Key Type parameter " - "\"kty\" (\"", keyDataJwk.kty, "\") equal to \"EC\"."); + "\"kty\" (\"", + keyDataJwk.kty, "\") equal to \"EC\"."); if (normalizedName == "ECDSA") { KJ_IF_SOME(alg, keyDataJwk.alg) { // If this JWK specifies an algorithm, make sure it jives with the hash we were passed via // importKey(). - static const std::map ecdsaAlgorithms { + static const std::map ecdsaAlgorithms{ {"ES256", NID_X9_62_prime256v1}, {"ES384", NID_secp384r1}, {"ES512", NID_secp521r1}, @@ -601,17 +620,17 @@ kj::Own ellipticJwkReader(int curveId, SubtleCrypto::JsonWebKey&& keyD auto ecKey = OSSLCALL_OWN(EC_KEY, EC_KEY_new_by_curve_name(curveId), DOMOperationError, "Error importing EC key", tryDescribeOpensslErrors()); - auto x = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.x), DOMDataError, - "Invalid EC key in JSON Web Key; missing \"x\"."); - auto y = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.y), DOMDataError, - "Invalid EC key in JSON Web Key; missing \"y\"."); + auto x = UNWRAP_JWK_BIGNUM( + kj::mv(keyDataJwk.x), DOMDataError, "Invalid EC key in JSON Web Key; missing \"x\"."); + auto y = UNWRAP_JWK_BIGNUM( + kj::mv(keyDataJwk.y), DOMDataError, "Invalid EC key in JSON Web Key; missing \"y\"."); auto group = EC_KEY_get0_group(ecKey); - auto bigX = JSG_REQUIRE_NONNULL(toBignum(x), InternalDOMOperationError, - "Error importing EC key", internalDescribeOpensslErrors()); - auto bigY = JSG_REQUIRE_NONNULL(toBignum(y), InternalDOMOperationError, - "Error importing EC key", internalDescribeOpensslErrors()); + auto bigX = JSG_REQUIRE_NONNULL(toBignum(x), InternalDOMOperationError, "Error importing EC key", + internalDescribeOpensslErrors()); + auto bigY = JSG_REQUIRE_NONNULL(toBignum(y), InternalDOMOperationError, "Error importing EC key", + internalDescribeOpensslErrors()); auto point = OSSL_NEW(EC_POINT, group); OSSLCALL(EC_POINT_set_affine_coordinates_GFp(group, point, bigX, bigY, nullptr)); @@ -635,56 +654,60 @@ kj::Own ellipticJwkReader(int curveId, SubtleCrypto::JsonWebKey&& keyD } } // namespace -kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateEcdsa( - jsg::Lock& js, kj::StringPtr normalizedName, - SubtleCrypto::GenerateKeyAlgorithm&& algorithm, bool extractable, +kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateEcdsa(jsg::Lock& js, + kj::StringPtr normalizedName, + SubtleCrypto::GenerateKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages) { - auto usages = - CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::generate, keyUsages, - CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); + auto usages = CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::generate, + keyUsages, CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); auto privateKeyUsages = usages & CryptoKeyUsageSet::privateKeyMask(); auto publicKeyUsages = usages & CryptoKeyUsageSet::publicKeyMask(); - return EllipticKey::generateElliptic(normalizedName, kj::mv(algorithm), extractable, - privateKeyUsages, publicKeyUsages); + return EllipticKey::generateElliptic( + normalizedName, kj::mv(algorithm), extractable, privateKeyUsages, publicKeyUsages); } -kj::Own CryptoKey::Impl::importEcdsa( - jsg::Lock& js, kj::StringPtr normalizedName, kj::StringPtr format, +kj::Own CryptoKey::Impl::importEcdsa(jsg::Lock& js, + kj::StringPtr normalizedName, + kj::StringPtr format, SubtleCrypto::ImportKeyData keyData, - SubtleCrypto::ImportKeyAlgorithm&& algorithm, bool extractable, + SubtleCrypto::ImportKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages) { - kj::StringPtr namedCurve = JSG_REQUIRE_NONNULL(algorithm.namedCurve, TypeError, - "Missing field \"namedCurve\" in \"algorithm\"."); + kj::StringPtr namedCurve = JSG_REQUIRE_NONNULL( + algorithm.namedCurve, TypeError, "Missing field \"namedCurve\" in \"algorithm\"."); auto [normalizedNamedCurve, curveId, rsSize] = lookupEllipticCurve(namedCurve); auto importedKey = [&, curveId = curveId] { if (format != "raw") { - return importAsymmetricForWebCrypto( - js, format, kj::mv(keyData), normalizedName, extractable, keyUsages, + return importAsymmetricForWebCrypto(js, format, kj::mv(keyData), normalizedName, extractable, + keyUsages, // Verbose lambda capture needed because: https://bugs.llvm.org/show_bug.cgi?id=35984 - [curveId = curveId, normalizedName = kj::str(normalizedName)] - (SubtleCrypto::JsonWebKey keyDataJwk) -> kj::Own { + [curveId = curveId, normalizedName = kj::str(normalizedName)]( + SubtleCrypto::JsonWebKey keyDataJwk) -> kj::Own { return ellipticJwkReader(curveId, kj::mv(keyDataJwk), normalizedName); - }, CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); + }, + CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); } else { - return importEllipticRaw(kj::mv(keyData), curveId, normalizedName, keyUsages, - CryptoKeyUsageSet::verify()); + return importEllipticRaw( + kj::mv(keyData), curveId, normalizedName, keyUsages, CryptoKeyUsageSet::verify()); } }(); // get0 avoids adding a refcount... auto ecKey = JSG_REQUIRE_NONNULL(Ec::tryGetEc(importedKey.evpPkey.get()), DOMDataError, - "Input was not an EC key", - tryDescribeOpensslErrors()); + "Input was not an EC key", tryDescribeOpensslErrors()); // Verify namedCurve matches what was specified in the key data. JSG_REQUIRE(ecKey.getGroup() != nullptr && ecKey.getCurveName() == curveId, DOMDataError, - "\"algorithm.namedCurve\" \"", namedCurve, "\" does not match the curve specified by the " - "input key data", tryDescribeOpensslErrors()); + "\"algorithm.namedCurve\" \"", namedCurve, + "\" does not match the curve specified by the " + "input key data", + tryDescribeOpensslErrors()); - auto keyAlgorithm = CryptoKey::EllipticKeyAlgorithm { + auto keyAlgorithm = CryptoKey::EllipticKeyAlgorithm{ normalizedName, normalizedNamedCurve, }; @@ -692,23 +715,25 @@ kj::Own CryptoKey::Impl::importEcdsa( return kj::heap(kj::mv(importedKey), kj::mv(keyAlgorithm), rsSize, extractable); } -kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateEcdh( - jsg::Lock& js, kj::StringPtr normalizedName, - SubtleCrypto::GenerateKeyAlgorithm&& algorithm, bool extractable, +kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateEcdh(jsg::Lock& js, + kj::StringPtr normalizedName, + SubtleCrypto::GenerateKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages) { - auto usages = - CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::generate, keyUsages, - CryptoKeyUsageSet::derivationKeyMask()); + auto usages = CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::generate, + keyUsages, CryptoKeyUsageSet::derivationKeyMask()); return EllipticKey::generateElliptic(normalizedName, kj::mv(algorithm), extractable, usages, {}); } -kj::Own CryptoKey::Impl::importEcdh( - jsg::Lock& js, kj::StringPtr normalizedName, kj::StringPtr format, +kj::Own CryptoKey::Impl::importEcdh(jsg::Lock& js, + kj::StringPtr normalizedName, + kj::StringPtr format, SubtleCrypto::ImportKeyData keyData, - SubtleCrypto::ImportKeyAlgorithm&& algorithm, bool extractable, + SubtleCrypto::ImportKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages) { - kj::StringPtr namedCurve = JSG_REQUIRE_NONNULL(algorithm.namedCurve, TypeError, - "Missing field \"namedCurve\" in \"algorithm\"."); + kj::StringPtr namedCurve = JSG_REQUIRE_NONNULL( + algorithm.namedCurve, TypeError, "Missing field \"namedCurve\" in \"algorithm\"."); auto [normalizedNamedCurve, curveId, rsSize] = lookupEllipticCurve(namedCurve); @@ -717,13 +742,14 @@ kj::Own CryptoKey::Impl::importEcdh( auto usageSet = strictCrypto ? CryptoKeyUsageSet() : CryptoKeyUsageSet::derivationKeyMask(); if (format != "raw") { - return importAsymmetricForWebCrypto( - js, format, kj::mv(keyData), normalizedName, extractable, keyUsages, + return importAsymmetricForWebCrypto(js, format, kj::mv(keyData), normalizedName, extractable, + keyUsages, // Verbose lambda capture needed because: https://bugs.llvm.org/show_bug.cgi?id=35984 - [curveId = curveId, normalizedName = kj::str(normalizedName)] - (SubtleCrypto::JsonWebKey keyDataJwk) -> kj::Own { + [curveId = curveId, normalizedName = kj::str(normalizedName)]( + SubtleCrypto::JsonWebKey keyDataJwk) -> kj::Own { return ellipticJwkReader(curveId, kj::mv(keyDataJwk), normalizedName); - }, CryptoKeyUsageSet::derivationKeyMask()); + }, + CryptoKeyUsageSet::derivationKeyMask()); } else { // The usage set is required to be empty for public ECDH keys, including raw keys. return importEllipticRaw(kj::mv(keyData), curveId, normalizedName, keyUsages, usageSet); @@ -731,8 +757,7 @@ kj::Own CryptoKey::Impl::importEcdh( }(); auto ecKey = JSG_REQUIRE_NONNULL(Ec::tryGetEc(importedKey.evpPkey.get()), DOMDataError, - "Input was not an EC public key nor a DH key", - tryDescribeOpensslErrors()); + "Input was not an EC public key nor a DH key", tryDescribeOpensslErrors()); // We ignore id-ecDH because BoringSSL doesn't implement this. // https://bugs.chromium.org/p/chromium/issues/detail?id=532728 @@ -740,11 +765,12 @@ kj::Own CryptoKey::Impl::importEcdh( // Verify namedCurve matches what was specified in the key data. JSG_REQUIRE(ecKey.getGroup() != nullptr && ecKey.getCurveName() == curveId, DOMDataError, - "\"algorithm.namedCurve\" \"", namedCurve, "\", does not match the curve " - "specified by the input key data", - tryDescribeOpensslErrors()); + "\"algorithm.namedCurve\" \"", namedCurve, + "\", does not match the curve " + "specified by the input key data", + tryDescribeOpensslErrors()); - auto keyAlgorithm = CryptoKey::EllipticKeyAlgorithm { + auto keyAlgorithm = CryptoKey::EllipticKeyAlgorithm{ normalizedName, normalizedNamedCurve, }; @@ -762,27 +788,25 @@ namespace { // keeping track of the algorithm identifier and returning an algorithm struct based on that. class EdDsaKey final: public AsymmetricKeyCryptoKeyImpl { public: - explicit EdDsaKey(AsymmetricKeyData keyData, - kj::StringPtr keyAlgorithm, - bool extractable) + explicit EdDsaKey(AsymmetricKeyData keyData, kj::StringPtr keyAlgorithm, bool extractable) : AsymmetricKeyCryptoKeyImpl(kj::mv(keyData), extractable), keyAlgorithm(kj::mv(keyAlgorithm)) {} - static kj::OneOf, CryptoKeyPair> generateKey( - kj::StringPtr normalizedName, int nid, CryptoKeyUsageSet privateKeyUsages, - CryptoKeyUsageSet publicKeyUsages, bool extractablePrivateKey); + static kj::OneOf, CryptoKeyPair> generateKey(kj::StringPtr normalizedName, + int nid, + CryptoKeyUsageSet privateKeyUsages, + CryptoKeyUsageSet publicKeyUsages, + bool extractablePrivateKey); CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override { // For legacy node-based keys with NODE-ED25519, algorithm contains a namedCurve field. - if (keyAlgorithm == "NODE-ED25519"){ - return CryptoKey::EllipticKeyAlgorithm { + if (keyAlgorithm == "NODE-ED25519") { + return CryptoKey::EllipticKeyAlgorithm{ keyAlgorithm, keyAlgorithm, }; } else { - return CryptoKey::KeyAlgorithm { - keyAlgorithm - }; + return CryptoKey::KeyAlgorithm{keyAlgorithm}; } } @@ -791,14 +815,13 @@ public: } kj::StringPtr chooseHash( - const kj::Maybe>& callTimeHash) const override { + const kj::Maybe>& callTimeHash) + const override { KJ_UNIMPLEMENTED(); } kj::Array sign( - SubtleCrypto::SignAlgorithm&& algorithm, - kj::ArrayPtr data) const override { + SubtleCrypto::SignAlgorithm&& algorithm, kj::ArrayPtr data) const override { JSG_REQUIRE(getTypeEnum() == KeyType::PRIVATE, DOMInvalidAccessError, "Asymmetric signing requires a private key."); @@ -819,8 +842,10 @@ public: JSG_REQUIRE(1 == EVP_DigestSignInit(digestCtx.get(), nullptr, nullptr, nullptr, getEvpPkey()), InternalDOMOperationError, "Failed to initialize Ed25519 signing digest", internalDescribeOpensslErrors()); - JSG_REQUIRE(1 == EVP_DigestSign(digestCtx.get(), signature.begin(), &signatureLength, - data.begin(), data.size()), InternalDOMOperationError, "Failed to sign with Ed25119 key", + JSG_REQUIRE(1 == + EVP_DigestSign( + digestCtx.get(), signature.begin(), &signatureLength, data.begin(), data.size()), + InternalDOMOperationError, "Failed to sign with Ed25119 key", internalDescribeOpensslErrors()); JSG_REQUIRE(signatureLength == signature.size(), InternalDOMOperationError, @@ -829,9 +854,9 @@ public: return signature; } - bool verify( - SubtleCrypto::SignAlgorithm&& algorithm, - kj::ArrayPtr signature, kj::ArrayPtr data) const override { + bool verify(SubtleCrypto::SignAlgorithm&& algorithm, + kj::ArrayPtr signature, + kj::ArrayPtr data) const override { ClearErrorOnReturn clearErrorOnReturn; JSG_REQUIRE(getTypeEnum() == KeyType::PUBLIC, DOMInvalidAccessError, @@ -840,16 +865,16 @@ public: JSG_REQUIRE(getAlgorithmName() == "Ed25519" || getAlgorithmName() == "NODE-ED25519", DOMOperationError, "Not implemented for this algorithm", getAlgorithmName()); - JSG_REQUIRE(signature.size() == ED25519_SIGNATURE_LEN, DOMOperationError, - "Invalid ", getAlgorithmName(), " signature length ", signature.size()); + JSG_REQUIRE(signature.size() == ED25519_SIGNATURE_LEN, DOMOperationError, "Invalid ", + getAlgorithmName(), " signature length ", signature.size()); auto digestCtx = OSSL_NEW(EVP_MD_CTX); JSG_REQUIRE(1 == EVP_DigestSignInit(digestCtx.get(), nullptr, nullptr, nullptr, getEvpPkey()), InternalDOMOperationError, "Failed to initialize Ed25519 verification digest", internalDescribeOpensslErrors()); - auto result = EVP_DigestVerify(digestCtx.get(), signature.begin(), signature.size(), - data.begin(), data.size()); + auto result = EVP_DigestVerify( + digestCtx.get(), signature.begin(), signature.size(), data.begin(), data.size()); JSG_REQUIRE(result == 0 || result == 1, InternalDOMOperationError, "Unexpected return code", result, internalDescribeOpensslErrors()); @@ -857,24 +882,32 @@ public: return !!result; } - kj::Array deriveBits( - jsg::Lock& js, SubtleCrypto::DeriveKeyAlgorithm&& algorithm, + kj::Array deriveBits(jsg::Lock& js, + SubtleCrypto::DeriveKeyAlgorithm&& algorithm, kj::Maybe resultBitLength) const override final { - JSG_REQUIRE(getAlgorithmName() == "X25519", DOMNotSupportedError, "" - "The deriveBits operation is not implemented for \"", getAlgorithmName(), "\"."); + JSG_REQUIRE(getAlgorithmName() == "X25519", DOMNotSupportedError, + "" + "The deriveBits operation is not implemented for \"", + getAlgorithmName(), "\"."); - JSG_REQUIRE(getTypeEnum() == KeyType::PRIVATE, DOMInvalidAccessError, "" - "The deriveBits operation is only valid for a private key, not \"", getType(), "\"."); + JSG_REQUIRE(getTypeEnum() == KeyType::PRIVATE, DOMInvalidAccessError, + "" + "The deriveBits operation is only valid for a private key, not \"", + getType(), "\"."); - auto& publicKey = JSG_REQUIRE_NONNULL(algorithm.$public, TypeError, - "Missing field \"public\" in \"derivedKeyParams\"."); + auto& publicKey = JSG_REQUIRE_NONNULL( + algorithm.$public, TypeError, "Missing field \"public\" in \"derivedKeyParams\"."); - JSG_REQUIRE(publicKey->getType() == "public"_kj, DOMInvalidAccessError, "" - "The provided key has type \"", publicKey->getType(), "\", not \"public\""); + JSG_REQUIRE(publicKey->getType() == "public"_kj, DOMInvalidAccessError, + "" + "The provided key has type \"", + publicKey->getType(), "\", not \"public\""); JSG_REQUIRE(getAlgorithm(js).which() == publicKey->getAlgorithm(js).which(), - DOMInvalidAccessError, "Base ", getAlgorithmName(), " private key cannot be used to derive" - " a key from a peer ", publicKey->getAlgorithmName(), " public key"); + DOMInvalidAccessError, "Base ", getAlgorithmName(), + " private key cannot be used to derive" + " a key from a peer ", + publicKey->getAlgorithmName(), " public key"); JSG_REQUIRE(getAlgorithmName() == publicKey->getAlgorithmName(), DOMInvalidAccessError, "Private key for derivation is using \"", getAlgorithmName(), @@ -906,7 +939,7 @@ public: // Check for all-zero value as mandated by spec kj::byte isNonZeroSecret = 0; - for (kj::byte b : sharedSecret) { + for (kj::byte b: sharedSecret) { isNonZeroSecret |= b; } JSG_REQUIRE(isNonZeroSecret, DOMOperationError, @@ -924,11 +957,15 @@ public: CryptoKey::AsymmetricKeyDetails getAsymmetricKeyDetail() const override { // Node.js implementation for EdDsa keys currently does not provide any detail - return CryptoKey::AsymmetricKeyDetails {}; + return CryptoKey::AsymmetricKeyDetails{}; } - kj::StringPtr jsgGetMemoryName() const override { return "EdDsaKey"; } - size_t jsgGetMemorySelfSize() const override { return sizeof(EdDsaKey); } + kj::StringPtr jsgGetMemoryName() const override { + return "EdDsaKey"; + } + size_t jsgGetMemorySelfSize() const override { + return sizeof(EdDsaKey); + } void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const override { AsymmetricKeyCryptoKeyImpl::jsgGetMemoryInfo(tracker); } @@ -976,8 +1013,8 @@ private: } kj::Array exportRaw() const override final { - JSG_REQUIRE(getTypeEnum() == KeyType::PUBLIC, DOMInvalidAccessError, - "Raw export of ", getAlgorithmName(), " keys is only allowed for public keys."); + JSG_REQUIRE(getTypeEnum() == KeyType::PUBLIC, DOMInvalidAccessError, "Raw export of ", + getAlgorithmName(), " keys is only allowed for public keys."); kj::Vector raw(ED25519_PUBLIC_KEY_LEN); raw.resize(ED25519_PUBLIC_KEY_LEN); @@ -992,13 +1029,15 @@ private: return raw.releaseAsArray(); } - }; -template -CryptoKeyPair generateKeyImpl(kj::StringPtr normalizedName, int nid, - CryptoKeyUsageSet privateKeyUsages, CryptoKeyUsageSet publicKeyUsages, - bool extractablePrivateKey, kj::StringPtr curveName) { +template +CryptoKeyPair generateKeyImpl(kj::StringPtr normalizedName, + int nid, + CryptoKeyUsageSet privateKeyUsages, + CryptoKeyUsageSet publicKeyUsages, + bool extractablePrivateKey, + kj::StringPtr curveName) { uint8_t rawPublicKey[keySize] = {0}; uint8_t rawPrivateKey[keySize * 2] = {0}; KeypairInit(rawPublicKey, rawPrivateKey); @@ -1006,25 +1045,23 @@ CryptoKeyPair generateKeyImpl(kj::StringPtr normalizedName, int nid, // The private key technically also contains the public key. Why does the keypair function bother // writing out the public key to a separate buffer? - auto privateEvpPKey = - OSSLCALL_OWN(EVP_PKEY, EVP_PKEY_new_raw_private_key(nid, nullptr, rawPrivateKey, keySize), - InternalDOMOperationError, "Error constructing ", curveName, " private key", - internalDescribeOpensslErrors()); + auto privateEvpPKey = OSSLCALL_OWN(EVP_PKEY, + EVP_PKEY_new_raw_private_key(nid, nullptr, rawPrivateKey, keySize), InternalDOMOperationError, + "Error constructing ", curveName, " private key", internalDescribeOpensslErrors()); - auto publicEvpPKey = - OSSLCALL_OWN(EVP_PKEY, EVP_PKEY_new_raw_public_key(nid, nullptr, rawPublicKey, keySize), - InternalDOMOperationError, "Internal error construct ", curveName, "public key", - internalDescribeOpensslErrors()); + auto publicEvpPKey = OSSLCALL_OWN(EVP_PKEY, + EVP_PKEY_new_raw_public_key(nid, nullptr, rawPublicKey, keySize), InternalDOMOperationError, + "Internal error construct ", curveName, "public key", internalDescribeOpensslErrors()); AsymmetricKeyData privateKeyData{ - .evpPkey = kj::mv(privateEvpPKey), - .keyType = KeyType::PRIVATE, - .usages = privateKeyUsages, + .evpPkey = kj::mv(privateEvpPKey), + .keyType = KeyType::PRIVATE, + .usages = privateKeyUsages, }; AsymmetricKeyData publicKeyData{ - .evpPkey = kj::mv(publicEvpPKey), - .keyType = KeyType::PUBLIC, - .usages = publicKeyUsages, + .evpPkey = kj::mv(publicEvpPKey), + .keyType = KeyType::PUBLIC, + .usages = publicKeyUsages, }; auto privateKey = jsg::alloc( @@ -1035,78 +1072,81 @@ CryptoKeyPair generateKeyImpl(kj::StringPtr normalizedName, int nid, return CryptoKeyPair{.publicKey = kj::mv(publicKey), .privateKey = kj::mv(privateKey)}; } -kj::OneOf, CryptoKeyPair> EdDsaKey::generateKey( - kj::StringPtr normalizedName, int nid, CryptoKeyUsageSet privateKeyUsages, - CryptoKeyUsageSet publicKeyUsages, bool extractablePrivateKey) { - switch (nid) { - // BoringSSL doesn't support ED448/X448. - case NID_ED25519: - return generateKeyImpl( - normalizedName, nid, privateKeyUsages, publicKeyUsages, extractablePrivateKey, - "Ed25519"_kj); - case NID_X25519: - return generateKeyImpl( - normalizedName, nid, privateKeyUsages, publicKeyUsages, extractablePrivateKey, - "X25519"_kj); - } +kj::OneOf, CryptoKeyPair> EdDsaKey::generateKey(kj::StringPtr normalizedName, + int nid, + CryptoKeyUsageSet privateKeyUsages, + CryptoKeyUsageSet publicKeyUsages, + bool extractablePrivateKey) { + switch (nid) { + // BoringSSL doesn't support ED448/X448. + case NID_ED25519: + return generateKeyImpl(normalizedName, nid, + privateKeyUsages, publicKeyUsages, extractablePrivateKey, "Ed25519"_kj); + case NID_X25519: + return generateKeyImpl(normalizedName, nid, + privateKeyUsages, publicKeyUsages, extractablePrivateKey, "X25519"_kj); + } - KJ_FAIL_REQUIRE("ED ", normalizedName, " unimplemented", nid); + KJ_FAIL_REQUIRE("ED ", normalizedName, " unimplemented", nid); } } // namespace -kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateEddsa( - jsg::Lock& js, kj::StringPtr normalizedName, - SubtleCrypto::GenerateKeyAlgorithm&& algorithm, bool extractable, +kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateEddsa(jsg::Lock& js, + kj::StringPtr normalizedName, + SubtleCrypto::GenerateKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages) { auto usages = CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::generate, keyUsages, - normalizedName == "X25519" ? - CryptoKeyUsageSet::derivationKeyMask() : - CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); + normalizedName == "X25519" ? CryptoKeyUsageSet::derivationKeyMask() + : CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); auto privateKeyUsages = usages & CryptoKeyUsageSet::privateKeyMask(); auto publicKeyUsages = usages & CryptoKeyUsageSet::publicKeyMask(); if (normalizedName == "NODE-ED25519") { - kj::StringPtr namedCurve = JSG_REQUIRE_NONNULL(algorithm.namedCurve, TypeError, - "Missing field \"namedCurve\" in \"algorithm\"."); - JSG_REQUIRE(namedCurve == "NODE-ED25519", DOMNotSupportedError, - "EDDSA curve \"", namedCurve, "\" isn't supported."); + kj::StringPtr namedCurve = JSG_REQUIRE_NONNULL( + algorithm.namedCurve, TypeError, "Missing field \"namedCurve\" in \"algorithm\"."); + JSG_REQUIRE(namedCurve == "NODE-ED25519", DOMNotSupportedError, "EDDSA curve \"", namedCurve, + "\" isn't supported."); } - return EdDsaKey::generateKey(normalizedName, normalizedName == "X25519" ? NID_X25519 : - NID_ED25519, privateKeyUsages, publicKeyUsages, extractable); + return EdDsaKey::generateKey(normalizedName, + normalizedName == "X25519" ? NID_X25519 : NID_ED25519, privateKeyUsages, publicKeyUsages, + extractable); } -kj::Own CryptoKey::Impl::importEddsa( - jsg::Lock& js, kj::StringPtr normalizedName, kj::StringPtr format, +kj::Own CryptoKey::Impl::importEddsa(jsg::Lock& js, + kj::StringPtr normalizedName, + kj::StringPtr format, SubtleCrypto::ImportKeyData keyData, - SubtleCrypto::ImportKeyAlgorithm&& algorithm, bool extractable, + SubtleCrypto::ImportKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages) { // BoringSSL doesn't support ED448. if (normalizedName == "NODE-ED25519") { // TODO: I prefer this style (declaring variables within the scope where they are needed) – // does KJ style want this to be done differently? - kj::StringPtr namedCurve = JSG_REQUIRE_NONNULL(algorithm.namedCurve, TypeError, - "Missing field \"namedCurve\" in \"algorithm\"."); - JSG_REQUIRE(namedCurve == "NODE-ED25519", DOMNotSupportedError, - "EDDSA curve \"", namedCurve, "\" isn't supported."); + kj::StringPtr namedCurve = JSG_REQUIRE_NONNULL( + algorithm.namedCurve, TypeError, "Missing field \"namedCurve\" in \"algorithm\"."); + JSG_REQUIRE(namedCurve == "NODE-ED25519", DOMNotSupportedError, "EDDSA curve \"", namedCurve, + "\" isn't supported."); } auto importedKey = [&] { auto nid = normalizedName == "X25519" ? NID_X25519 : NID_ED25519; if (format != "raw") { - return importAsymmetricForWebCrypto( - js, format, kj::mv(keyData), normalizedName, extractable, keyUsages, - [nid, normalizedName = kj::str(normalizedName)] - (SubtleCrypto::JsonWebKey keyDataJwk) -> kj::Own { + return importAsymmetricForWebCrypto(js, format, kj::mv(keyData), normalizedName, extractable, + keyUsages, + [nid, normalizedName = kj::str(normalizedName)]( + SubtleCrypto::JsonWebKey keyDataJwk) -> kj::Own { return ellipticJwkReader(nid, kj::mv(keyDataJwk), normalizedName); - }, normalizedName == "X25519" ? CryptoKeyUsageSet::derivationKeyMask() : - CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); + }, + normalizedName == "X25519" ? CryptoKeyUsageSet::derivationKeyMask() + : CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); } else { - return importEllipticRaw( - kj::mv(keyData), nid, normalizedName, keyUsages, + return importEllipticRaw(kj::mv(keyData), nid, normalizedName, keyUsages, normalizedName == "X25519" ? CryptoKeyUsageSet() : CryptoKeyUsageSet::verify()); } }(); @@ -1128,21 +1168,23 @@ kj::Own fromEcKey(kj::Own key) { auto [normalizedNamedCurve, curveId, rsSize] = lookupEllipticCurve(curveName); - return kj::heap(AsymmetricKeyData { - .evpPkey = kj::mv(key), - .keyType = KeyType::PUBLIC, - .usages = CryptoKeyUsageSet::verify(), - }, CryptoKey::EllipticKeyAlgorithm { - .name = "ECDSA"_kj, - .namedCurve = normalizedNamedCurve - }, rsSize, true); + return kj::heap( + AsymmetricKeyData{ + .evpPkey = kj::mv(key), + .keyType = KeyType::PUBLIC, + .usages = CryptoKeyUsageSet::verify(), + }, + CryptoKey::EllipticKeyAlgorithm{.name = "ECDSA"_kj, .namedCurve = normalizedNamedCurve}, + rsSize, true); } kj::Own fromEd25519Key(kj::Own key) { - return kj::heap(AsymmetricKeyData { - .evpPkey = kj::mv(key), - .keyType = KeyType::PUBLIC, - .usages = CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify(), - }, "Ed25519"_kj, true); + return kj::heap( + AsymmetricKeyData{ + .evpPkey = kj::mv(key), + .keyType = KeyType::PUBLIC, + .usages = CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify(), + }, + "Ed25519"_kj, true); } } // namespace workerd::api diff --git a/src/workerd/api/crypto/ec.h b/src/workerd/api/crypto/ec.h index af248d88bfd..246cc689118 100644 --- a/src/workerd/api/crypto/ec.h +++ b/src/workerd/api/crypto/ec.h @@ -13,19 +13,27 @@ class Ec final { static kj::Maybe tryGetEc(const EVP_PKEY* key); Ec(EC_KEY* key); - inline const EC_KEY* getKey() { return key; } - inline const EC_GROUP* getGroup() const { return group; } + inline const EC_KEY* getKey() { + return key; + } + inline const EC_GROUP* getGroup() const { + return group; + } int getCurveName() const; const EC_POINT* getPublicKey() const; const BIGNUM* getPrivateKey() const; uint32_t getDegree() const; - inline const BIGNUM& getX() const { return *x; } - inline const BIGNUM& getY() const { return *y; } + inline const BIGNUM& getX() const { + return *x; + } + inline const BIGNUM& getY() const { + return *y; + } - SubtleCrypto::JsonWebKey toJwk(KeyType keyType, kj::StringPtr curveName) const - KJ_WARN_UNUSED_RESULT; + SubtleCrypto::JsonWebKey toJwk( + KeyType keyType, kj::StringPtr curveName) const KJ_WARN_UNUSED_RESULT; kj::Array getRawPublicKey() const KJ_WARN_UNUSED_RESULT; diff --git a/src/workerd/api/crypto/hkdf.c++ b/src/workerd/api/crypto/hkdf.c++ index 6853a19e095..73a4dc440dd 100644 --- a/src/workerd/api/crypto/hkdf.c++ +++ b/src/workerd/api/crypto/hkdf.c++ @@ -12,33 +12,40 @@ namespace { class HkdfKey final: public CryptoKey::Impl { public: - explicit HkdfKey(kj::Array keyData, CryptoKey::KeyAlgorithm keyAlgorithm, - bool extractable, CryptoKeyUsageSet usages) + explicit HkdfKey(kj::Array keyData, + CryptoKey::KeyAlgorithm keyAlgorithm, + bool extractable, + CryptoKeyUsageSet usages) : CryptoKey::Impl(extractable, usages), - keyData(kj::mv(keyData)), keyAlgorithm(kj::mv(keyAlgorithm)) {} + keyData(kj::mv(keyData)), + keyAlgorithm(kj::mv(keyAlgorithm)) {} - kj::StringPtr jsgGetMemoryName() const override { return "HkdfKey"; } - size_t jsgGetMemorySelfSize() const override { return sizeof(HkdfKey); } + kj::StringPtr jsgGetMemoryName() const override { + return "HkdfKey"; + } + size_t jsgGetMemorySelfSize() const override { + return sizeof(HkdfKey); + } void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const override { tracker.trackFieldWithSize("keyData", keyData.size()); tracker.trackField("keyAlgorithm", keyAlgorithm); } private: - kj::Array deriveBits( - jsg::Lock& js, SubtleCrypto::DeriveKeyAlgorithm&& algorithm, + kj::Array deriveBits(jsg::Lock& js, + SubtleCrypto::DeriveKeyAlgorithm&& algorithm, kj::Maybe maybeLength) const override { - kj::StringPtr hashName = api::getAlgorithmName(JSG_REQUIRE_NONNULL(algorithm.hash, TypeError, - "Missing field \"hash\" in \"algorithm\".")); + kj::StringPtr hashName = api::getAlgorithmName( + JSG_REQUIRE_NONNULL(algorithm.hash, TypeError, "Missing field \"hash\" in \"algorithm\".")); const EVP_MD* hashType = lookupDigestAlgorithm(hashName).second; - const auto& salt = JSG_REQUIRE_NONNULL(algorithm.salt, TypeError, - "Missing field \"salt\" in \"algorithm\"."); - const auto& info = JSG_REQUIRE_NONNULL(algorithm.info, TypeError, - "Missing field \"info\" in \"algorithm\"."); + const auto& salt = + JSG_REQUIRE_NONNULL(algorithm.salt, TypeError, "Missing field \"salt\" in \"algorithm\"."); + const auto& info = + JSG_REQUIRE_NONNULL(algorithm.info, TypeError, "Missing field \"info\" in \"algorithm\"."); - uint32_t length = JSG_REQUIRE_NONNULL(maybeLength, DOMOperationError, - "HKDF cannot derive a key with null length."); + uint32_t length = JSG_REQUIRE_NONNULL( + maybeLength, DOMOperationError, "HKDF cannot derive a key with null length."); JSG_REQUIRE(length != 0 && (length % 8) == 0, DOMOperationError, "HKDF requires a derived key length that is a non-zero multiple of eight (requested ", @@ -50,8 +57,12 @@ private: DOMOperationError, "HKDF deriveBits failed."); } - kj::StringPtr getAlgorithmName() const override { return "HKDF"; } - CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override { return keyAlgorithm; } + kj::StringPtr getAlgorithmName() const override { + return "HKDF"; + } + CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override { + return keyAlgorithm; + } bool equals(const CryptoKey::Impl& other) const override final { return this == &other || (other.getType() == "secret"_kj && other.equals(keyData)); @@ -59,7 +70,7 @@ private: bool equals(const kj::Array& other) const override final { return keyData.size() == other.size() && - CRYPTO_memcmp(keyData.begin(), other.begin(), keyData.size()) == 0; + CRYPTO_memcmp(keyData.begin(), other.begin(), keyData.size()) == 0; } ZeroOnFree keyData; @@ -68,30 +79,34 @@ private: } // namespace -kj::Maybe> hkdf(size_t length, const EVP_MD* digest, - kj::ArrayPtr key, - kj::ArrayPtr salt, - kj::ArrayPtr info) { +kj::Maybe> hkdf(size_t length, + const EVP_MD* digest, + kj::ArrayPtr key, + kj::ArrayPtr salt, + kj::ArrayPtr info) { auto buf = kj::heapArray(length); - if (HKDF(buf.begin(), length, digest, key.begin(), key.size(), salt.begin(), - salt.size(), info.begin(), info.size()) != 1) { + if (HKDF(buf.begin(), length, digest, key.begin(), key.size(), salt.begin(), salt.size(), + info.begin(), info.size()) != 1) { return kj::none; } return kj::mv(buf); } -kj::Own CryptoKey::Impl::importHkdf( - jsg::Lock& js, kj::StringPtr normalizedName, kj::StringPtr format, +kj::Own CryptoKey::Impl::importHkdf(jsg::Lock& js, + kj::StringPtr normalizedName, + kj::StringPtr format, SubtleCrypto::ImportKeyData keyData, - SubtleCrypto::ImportKeyAlgorithm&& algorithm, bool extractable, + SubtleCrypto::ImportKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages) { - auto usages = - CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::importSecret, - keyUsages, CryptoKeyUsageSet::derivationKeyMask()); + auto usages = CryptoKeyUsageSet::validate(normalizedName, + CryptoKeyUsageSet::Context::importSecret, keyUsages, CryptoKeyUsageSet::derivationKeyMask()); JSG_REQUIRE(!extractable, DOMSyntaxError, "HKDF key cannot be extractable."); - JSG_REQUIRE(format == "raw", DOMNotSupportedError, "HKDF key must be imported " - "in \"raw\" format (requested \"", format, "\")"); + JSG_REQUIRE(format == "raw", DOMNotSupportedError, + "HKDF key must be imported " + "in \"raw\" format (requested \"", + format, "\")"); // NOTE: Checked in SubtleCrypto::importKey(). auto keyDataArray = kj::mv(keyData.get>()); diff --git a/src/workerd/api/crypto/impl.c++ b/src/workerd/api/crypto/impl.c++ index 1fbb2c19439..978b3a37a53 100644 --- a/src/workerd/api/crypto/impl.c++ +++ b/src/workerd/api/crypto/impl.c++ @@ -38,7 +38,9 @@ kj::String errorsToString( return kj::str(": ", description, "."); } - return kj::str(": ", kj::strArray(KJ_MAP(e, accumulatedErrors) { + return kj::str(": ", + kj::strArray( + KJ_MAP(e, accumulatedErrors) { KJ_SWITCH_ONEOF(accumulatedErrors[0]) { KJ_CASE_ONEOF(e, kj::StringPtr) { return e; @@ -48,14 +50,18 @@ kj::String errorsToString( } } KJ_UNREACHABLE; - }, " "), "."); -} + }, " "), + "."); } +} // namespace const SslArrayDisposer SslArrayDisposer::INSTANCE; -void SslArrayDisposer::disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, - size_t capacity, void (*destroyElement)(void*)) const { +void SslArrayDisposer::disposeImpl(void* firstElement, + size_t elementSize, + size_t elementCount, + size_t capacity, + void (*destroyElement)(void*)) const { OPENSSL_free(firstElement); } @@ -67,17 +73,18 @@ void throwOpensslError(const char* file, int line, kj::StringPtr code) { // in the queue might have been accidentally left there by previous, unrelated operations. // Unfortunately BoringSSL's ERR_error_string() and friends produce unfriendly strings that // mostly just tell you the error constant name, which isn't what we want to throw at users. - switch(ERR_GET_LIB(ERR_peek_last_error())) { + switch (ERR_GET_LIB(ERR_peek_last_error())) { // The error code defines overlap between the different boringssl libraries (for example, we // have EC_R_INVALID_ENCODING == RSA_R_CANNOT_RECOVER_MULTI_PRIME_KEY), so we must check the // library code. case ERR_LIB_EC: switch (ERR_GET_REASON(ERR_peek_last_error())) { -#define MAP_ERROR(CODE, TEXT) \ - case CODE: { \ - ClearErrorOnReturn clearErrorOnReturn; \ - kj::throwFatalException(kj::Exception(kj::Exception::Type::FAILED, file, line, \ - kj::str(JSG_EXCEPTION(DOMOperationError) ": ", TEXT))); } +#define MAP_ERROR(CODE, TEXT) \ + case CODE: { \ + ClearErrorOnReturn clearErrorOnReturn; \ + kj::throwFatalException(kj::Exception(kj::Exception::Type::FAILED, file, line, \ + kj::str(JSG_EXCEPTION(DOMOperationError) ": ", TEXT))); \ + } MAP_ERROR(EC_R_INVALID_ENCODING, "Invalid point encoding.") MAP_ERROR(EC_R_INVALID_COMPRESSED_POINT, "Invalid compressed point.") @@ -109,9 +116,9 @@ void throwOpensslError(const char* file, int line, kj::StringPtr code) { ERR_error_string_n(error, message, sizeof(message)); lines.add(kj::heapString(message)); } - kj::throwFatalException(kj::Exception(kj::Exception::Type::FAILED, file, line, kj::str( - "OpenSSL call failed: ", code, "; ", - lines.size() == 0 ? "but ERR_get_error() returned 0"_kj : kj::strArray(lines, "; ")))); + kj::throwFatalException(kj::Exception(kj::Exception::Type::FAILED, file, line, + kj::str("OpenSSL call failed: ", code, "; ", + lines.size() == 0 ? "but ERR_get_error() returned 0"_kj : kj::strArray(lines, "; ")))); } kj::Vector> consumeAllOpensslErrors() { @@ -140,7 +147,7 @@ kj::Vector> consumeAllOpenssl break; } - return OpensslUntranslatedError { + return OpensslUntranslatedError{ .library = ERR_lib_error_string(error), .reasonName = ERR_reason_error_string(error), }; @@ -162,9 +169,7 @@ kj::String tryDescribeOpensslErrors(kj::StringPtr defaultIfNoError) { // debugging issues. #if 1 auto removeBegin = std::remove_if(accumulatedErrors.begin(), accumulatedErrors.end(), - [](const auto& error) { - return error.template is(); - }); + [](const auto& error) { return error.template is(); }); accumulatedErrors.resize(removeBegin - accumulatedErrors.begin()); #endif @@ -192,7 +197,7 @@ std::pair lookupDigestAlgorithm(kj::StringPtr algo auto algIter = registeredAlgorithms.find(algorithm); JSG_REQUIRE(algIter != registeredAlgorithms.end(), DOMNotSupportedError, - "Unrecognized or unimplemented digest algorithm requested."); + "Unrecognized or unimplemented digest algorithm requested."); return *algIter; } @@ -231,8 +236,8 @@ void checkPbkdfLimits(jsg::Lock& js, size_t iterations) { auto& limits = Worker::Isolate::from(js).getLimitEnforcer(); KJ_IF_SOME(max, limits.checkPbkdfIterations(js, iterations)) { JSG_FAIL_REQUIRE(DOMNotSupportedError, - kj::str("Pbkdf2 failed: iteration counts above ", max ," are not supported (requested ", - iterations, ").")); + kj::str("Pbkdf2 failed: iteration counts above ", max, " are not supported (requested ", + iterations, ").")); } } @@ -264,7 +269,6 @@ kj::Maybe> bignumToArrayPadded(const BIGNUM& n, size_t padde return kj::none; } return kj::mv(result); - } kj::Own newBignum() { @@ -278,8 +282,7 @@ void CryptoKey::visitForMemoryInfo(jsg::MemoryTracker& tracker) const { bool CSPRNG(kj::ArrayPtr buffer) { do { if (1 == RAND_status()) - if (1 == RAND_bytes(buffer.begin(), buffer.size())) - return true; + if (1 == RAND_bytes(buffer.begin(), buffer.size())) return true; #if OPENSSL_VERSION_MAJOR >= 3 const auto code = ERR_peek_last_error(); // A misconfigured OpenSSL 3 installation may report 1 from RAND_poll() @@ -287,8 +290,7 @@ bool CSPRNG(kj::ArrayPtr buffer) { // a matching algorithm for the CSPRNG. if (ERR_GET_LIB(code) == ERR_LIB_RAND) { const auto reason = ERR_GET_REASON(code); - if (reason == RAND_R_ERROR_INSTANTIATING_DRBG || - reason == RAND_R_UNABLE_TO_FETCH_DRBG || + if (reason == RAND_R_ERROR_INSTANTIATING_DRBG || reason == RAND_R_UNABLE_TO_FETCH_DRBG || reason == RAND_R_UNABLE_TO_CREATE_DRBG) { return false; } @@ -299,19 +301,15 @@ bool CSPRNG(kj::ArrayPtr buffer) { return false; } - kj::Maybe> tryGetAsn1Sequence(kj::ArrayPtr data) { - if (data.size() < 2 || data[0] != 0x30) - return kj::none; + if (data.size() < 2 || data[0] != 0x30) return kj::none; if (data[1] & 0x80) { // Long form. size_t n_bytes = data[1] & ~0x80; - if (n_bytes + 2 > data.size() || n_bytes > sizeof(size_t)) - return kj::none; + if (n_bytes + 2 > data.size() || n_bytes > sizeof(size_t)) return kj::none; size_t length = 0; - for (size_t i = 0; i < n_bytes; i++) - length = (length << 8) | data[i + 2]; + for (size_t i = 0; i < n_bytes; i++) length = (length << 8) | data[i + 2]; auto start = 2 + n_bytes; auto end = start + kj::min(data.size() - 2 - n_bytes, length); return data.slice(start, end); diff --git a/src/workerd/api/crypto/impl.h b/src/workerd/api/crypto/impl.h index 7f06c4af0da..16c0bf20ce8 100644 --- a/src/workerd/api/crypto/impl.h +++ b/src/workerd/api/crypto/impl.h @@ -17,12 +17,11 @@ typedef struct bignum_st BIGNUM; // Wrap calls to OpenSSL's EVP_* interface (and similar APIs) in this macro to // deal with errors. -#define OSSLCALL(...) if ((__VA_ARGS__) != 1) \ - ::workerd::api::throwOpensslError(__FILE__, __LINE__, #__VA_ARGS__) +#define OSSLCALL(...) \ + if ((__VA_ARGS__) != 1) ::workerd::api::throwOpensslError(__FILE__, __LINE__, #__VA_ARGS__) -#define UNWRAP_JWK_BIGNUM(value, ...) \ - JSG_REQUIRE_NONNULL( \ - decodeBase64Url(JSG_REQUIRE_NONNULL((value), __VA_ARGS__)), __VA_ARGS__) +#define UNWRAP_JWK_BIGNUM(value, ...) \ + JSG_REQUIRE_NONNULL(decodeBase64Url(JSG_REQUIRE_NONNULL((value), __VA_ARGS__)), __VA_ARGS__) namespace workerd::api { @@ -100,10 +99,12 @@ class CryptoKey::Impl { public: // C++ API - using ImportFunc = kj::Own( - jsg::Lock& js, kj::StringPtr normalizedName, kj::StringPtr format, + using ImportFunc = kj::Own(jsg::Lock& js, + kj::StringPtr normalizedName, + kj::StringPtr format, SubtleCrypto::ImportKeyData keyData, - SubtleCrypto::ImportKeyAlgorithm&& algorithm, bool extractable, + SubtleCrypto::ImportKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages); static ImportFunc importAes; @@ -116,9 +117,10 @@ class CryptoKey::Impl { static ImportFunc importEddsa; static ImportFunc importRsaRaw; - using GenerateFunc = kj::OneOf, CryptoKeyPair>( - jsg::Lock& js, kj::StringPtr normalizedName, - SubtleCrypto::GenerateKeyAlgorithm&& algorithm, bool extractable, + using GenerateFunc = kj::OneOf, CryptoKeyPair>(jsg::Lock& js, + kj::StringPtr normalizedName, + SubtleCrypto::GenerateKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages); static GenerateFunc generateAes; @@ -128,64 +130,65 @@ class CryptoKey::Impl { static GenerateFunc generateEcdh; static GenerateFunc generateEddsa; - Impl(bool extractable, CryptoKeyUsageSet usages) : extractable(extractable), usages(usages) {} + Impl(bool extractable, CryptoKeyUsageSet usages): extractable(extractable), usages(usages) {} static kj::Own from(kj::Own key); - bool isExtractable() const { return extractable; } - CryptoKeyUsageSet getUsages() const { return usages; } + bool isExtractable() const { + return extractable; + } + CryptoKeyUsageSet getUsages() const { + return usages; + } virtual kj::Array encrypt( - SubtleCrypto::EncryptAlgorithm&& algorithm, - kj::ArrayPtr plainText) const { + SubtleCrypto::EncryptAlgorithm&& algorithm, kj::ArrayPtr plainText) const { JSG_FAIL_REQUIRE(DOMNotSupportedError, "The encrypt operation is not implemented for \"", getAlgorithmName(), "\"."); } virtual kj::Array decrypt( - SubtleCrypto::EncryptAlgorithm&& algorithm, - kj::ArrayPtr cipherText) const { + SubtleCrypto::EncryptAlgorithm&& algorithm, kj::ArrayPtr cipherText) const { JSG_FAIL_REQUIRE(DOMNotSupportedError, "The decrypt operation is not implemented for \"", getAlgorithmName(), "\"."); } virtual kj::Array sign( - SubtleCrypto::SignAlgorithm&& algorithm, - kj::ArrayPtr data) const { + SubtleCrypto::SignAlgorithm&& algorithm, kj::ArrayPtr data) const { JSG_FAIL_REQUIRE(DOMNotSupportedError, "The sign operation is not implemented for \"", getAlgorithmName(), "\"."); } - virtual bool verify( - SubtleCrypto::SignAlgorithm&& algorithm, kj::ArrayPtr signature, + virtual bool verify(SubtleCrypto::SignAlgorithm&& algorithm, + kj::ArrayPtr signature, kj::ArrayPtr data) const { JSG_FAIL_REQUIRE(DOMNotSupportedError, "The verify operation is not implemented for \"", getAlgorithmName(), "\"."); } - virtual kj::Array deriveBits( - jsg::Lock& js, - SubtleCrypto::DeriveKeyAlgorithm&& algorithm, kj::Maybe length) const { + virtual kj::Array deriveBits(jsg::Lock& js, + SubtleCrypto::DeriveKeyAlgorithm&& algorithm, + kj::Maybe length) const { JSG_FAIL_REQUIRE(DOMNotSupportedError, - "The deriveKey and deriveBits operations are not implemented for \"", - getAlgorithmName(), "\"."); + "The deriveKey and deriveBits operations are not implemented for \"", getAlgorithmName(), + "\"."); } - virtual kj::Array wrapKey(SubtleCrypto::EncryptAlgorithm&& algorithm, - kj::ArrayPtr unwrappedKey) const { + virtual kj::Array wrapKey( + SubtleCrypto::EncryptAlgorithm&& algorithm, kj::ArrayPtr unwrappedKey) const { // For many algorithms, wrapKey() is the same as encrypt(), so as a convenience the default // implementation just forwards to it. return encrypt(kj::mv(algorithm), unwrappedKey); } - virtual kj::Array unwrapKey(SubtleCrypto::EncryptAlgorithm&& algorithm, - kj::ArrayPtr wrappedKey) const { + virtual kj::Array unwrapKey( + SubtleCrypto::EncryptAlgorithm&& algorithm, kj::ArrayPtr wrappedKey) const { // For many algorithms, unwrapKey() is the same as decrypt(), so as a convenience the default // implementation just forwards to it. return decrypt(kj::mv(algorithm), wrappedKey); } virtual SubtleCrypto::ExportKeyData exportKey(kj::StringPtr format) const { - JSG_FAIL_REQUIRE(DOMNotSupportedError, - "Unrecognized or unsupported export of \"", getAlgorithmName(), "\" requested."); + JSG_FAIL_REQUIRE(DOMNotSupportedError, "Unrecognized or unsupported export of \"", + getAlgorithmName(), "\" requested."); } // The exportKeyExt variant is used by the Node.js crypto module. It allows the caller to @@ -196,13 +199,12 @@ class CryptoKey::Impl { // cipher and passphrase. // Rather than modify the existing exportKey API, we add this new variant to support the // Node.js implementation without risking breaking the Web Crypto impl. - virtual kj::Array exportKeyExt( - kj::StringPtr format, + virtual kj::Array exportKeyExt(kj::StringPtr format, kj::StringPtr type, jsg::Optional cipher = kj::none, jsg::Optional> passphrase = kj::none) const { - JSG_FAIL_REQUIRE(DOMNotSupportedError, - "Unrecognized or unsupported export of \"", getAlgorithmName(), "\" requested."); + JSG_FAIL_REQUIRE(DOMNotSupportedError, "Unrecognized or unsupported export of \"", + getAlgorithmName(), "\" requested."); } virtual kj::StringPtr getAlgorithmName() const = 0; @@ -216,17 +218,28 @@ class CryptoKey::Impl { // JS API implementation virtual AlgorithmVariant getAlgorithm(jsg::Lock& js) const = 0; - virtual kj::StringPtr getType() const { return "secret"_kj; } + virtual kj::StringPtr getType() const { + return "secret"_kj; + } virtual bool equals(const Impl& other) const = 0; virtual bool equals(const kj::Array& other) const; - virtual kj::StringPtr jsgGetMemoryName() const { return "CryptoKey::Impl"; } - virtual size_t jsgGetMemorySelfSize() const { return sizeof(Impl); } + virtual kj::StringPtr jsgGetMemoryName() const { + return "CryptoKey::Impl"; + } + virtual size_t jsgGetMemorySelfSize() const { + return sizeof(Impl); + } virtual void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const {} - virtual bool verifyX509Public(const X509* cert) const { return false; } - virtual bool verifyX509Private(const X509* cert) const { return false; } + virtual bool verifyX509Public(const X509* cert) const { + return false; + } + virtual bool verifyX509Private(const X509* cert) const { + return false; + } + private: const bool extractable; const CryptoKeyUsageSet usages; @@ -254,19 +267,22 @@ struct CryptoAlgorithm { return strcasecmp(name.cStr(), other.name.cStr()) == 0; } // Allow comparison by name, case-insensitive. This is a convenience for placing in an std::set. - inline bool operator< (const CryptoAlgorithm& other) const { + inline bool operator<(const CryptoAlgorithm& other) const { return strcasecmp(name.cStr(), other.name.cStr()) < 0; } // TODO(cleanup): I'd rather use kj::Table with HashIndex but we need a case-insensitive hash // function, which seemed slightly too annoying to implement now. }; -class SslArrayDisposer : public kj::ArrayDisposer { +class SslArrayDisposer: public kj::ArrayDisposer { public: static const SslArrayDisposer INSTANCE; - void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, - size_t capacity, void (*destroyElement)(void*)) const; + void disposeImpl(void* firstElement, + size_t elementSize, + size_t elementCount, + size_t capacity, + void (*destroyElement)(void*)) const; }; template @@ -283,14 +299,14 @@ class SslDisposer: public kj::Disposer { template const SslDisposer SslDisposer::INSTANCE; -#define OSSLCALL_OWN(T, code, ...) \ - ({ \ - T* result = code; \ - JSG_REQUIRE(result != nullptr, ##__VA_ARGS__); \ - kj::Own(result, workerd::api::SslDisposer::INSTANCE); \ +#define OSSLCALL_OWN(T, code, ...) \ + ({ \ + T* result = code; \ + JSG_REQUIRE(result != nullptr, ##__VA_ARGS__); \ + kj::Own(result, workerd::api::SslDisposer::INSTANCE); \ }) -#define OSSL_NEW(T, ...) \ +#define OSSL_NEW(T, ...) \ OSSLCALL_OWN(T, T##_new(__VA_ARGS__), InternalDOMOperationError, "Error allocating crypto") #define BIGNUM_new BN_new @@ -299,7 +315,7 @@ const SslDisposer SslDisposer::INSTANCE; // Using BN_clear_free here ensures that any potentially sensitive information in the // BIGNUM is also cleansed when it is freed. -using UniqueBignum = std::unique_ptr; +using UniqueBignum = std::unique_ptr; kj::Maybe> toBignum(kj::ArrayPtr data); BIGNUM* toBignumUnowned(kj::ArrayPtr data); kj::Maybe> bignumToArray(const BIGNUM& bignum); @@ -307,29 +323,41 @@ kj::Maybe> bignumToArrayPadded(const BIGNUM& bignum); kj::Maybe> bignumToArrayPadded(const BIGNUM& bignum, size_t paddedLength); kj::Own newBignum(); -#define OSSL_BIO_MEM() \ - ({ \ - BIO* result = BIO_new(BIO_s_mem()); \ - JSG_REQUIRE(result != nullptr, InternalDOMOperationError, "Error allocating crypto"); \ - kj::Own(result, workerd::api::SslDisposer::INSTANCE); \ +#define OSSL_BIO_MEM() \ + ({ \ + BIO* result = BIO_new(BIO_s_mem()); \ + JSG_REQUIRE(result != nullptr, InternalDOMOperationError, "Error allocating crypto"); \ + kj::Own(result, workerd::api::SslDisposer::INSTANCE); \ }) // Adopted from Node.js' crypto implementation. the MarkPopErrorOnReturn // and ClearErrorOnReturn mechanisms make working with the openssl error // stack a bit easier... struct MarkPopErrorOnReturn { - MarkPopErrorOnReturn() { ERR_set_mark(); } - ~MarkPopErrorOnReturn() { ERR_pop_to_mark(); } + MarkPopErrorOnReturn() { + ERR_set_mark(); + } + ~MarkPopErrorOnReturn() { + ERR_pop_to_mark(); + } KJ_DISALLOW_COPY_AND_MOVE(MarkPopErrorOnReturn); }; struct ClearErrorOnReturn { - ClearErrorOnReturn() { ERR_clear_error(); } - ~ClearErrorOnReturn() { ERR_clear_error(); } + ClearErrorOnReturn() { + ERR_clear_error(); + } + ~ClearErrorOnReturn() { + ERR_clear_error(); + } KJ_DISALLOW_COPY_AND_MOVE(ClearErrorOnReturn); - uint32_t peekError() { return ERR_peek_error(); } - uint32_t consumeError() { return ERR_get_error(); } + uint32_t peekError() { + return ERR_peek_error(); + } + uint32_t consumeError() { + return ERR_get_error(); + } }; // Returns ceil(a / b) for integers (std::ceil always returns a floating point result). @@ -343,15 +371,27 @@ static inline T integerCeilDivision(T a, T b) { // with zeroes when destroyed. class ZeroOnFree { public: - inline ZeroOnFree(kj::Array&& inner) : inner(kj::mv(inner)) {} + inline ZeroOnFree(kj::Array&& inner): inner(kj::mv(inner)) {} ~ZeroOnFree() noexcept(false); - inline size_t size() const { return inner.size(); } - inline const kj::byte* begin() const { return inner.begin(); } - inline operator kj::ArrayPtr() const { return inner.asPtr(); } - inline operator const kj::Array&() const { return inner; } - inline kj::ArrayPtr asPtr() { return inner.asPtr(); } - inline kj::ArrayPtr asPtr() const { return inner.asPtr(); } + inline size_t size() const { + return inner.size(); + } + inline const kj::byte* begin() const { + return inner.begin(); + } + inline operator kj::ArrayPtr() const { + return inner.asPtr(); + } + inline operator const kj::Array&() const { + return inner; + } + inline kj::ArrayPtr asPtr() { + return inner.asPtr(); + } + inline kj::ArrayPtr asPtr() const { + return inner.asPtr(); + } private: kj::Array inner; @@ -373,7 +413,7 @@ kj::Own fromRsaKey(kj::Own key); kj::Own fromEcKey(kj::Own key); kj::Own fromEd25519Key(kj::Own key); - // If the input bytes are a valid ASN.1 sequence, return them minus the prefix. +// If the input bytes are a valid ASN.1 sequence, return them minus the prefix. kj::Maybe> tryGetAsn1Sequence(kj::ArrayPtr data); } // namespace workerd::api diff --git a/src/workerd/api/crypto/kdf.h b/src/workerd/api/crypto/kdf.h index b0aed5a0c33..b18380befb3 100644 --- a/src/workerd/api/crypto/kdf.h +++ b/src/workerd/api/crypto/kdf.h @@ -12,25 +12,25 @@ namespace workerd::api { // Perform HKDF key derivation. kj::Maybe> hkdf(size_t length, - const EVP_MD* digest, - kj::ArrayPtr key, - kj::ArrayPtr salt, - kj::ArrayPtr info); + const EVP_MD* digest, + kj::ArrayPtr key, + kj::ArrayPtr salt, + kj::ArrayPtr info); // Perform PBKDF2 key derivation. kj::Maybe> pbkdf2(size_t length, - size_t iterations, - const EVP_MD* digest, - kj::ArrayPtr password, - kj::ArrayPtr salt); + size_t iterations, + const EVP_MD* digest, + kj::ArrayPtr password, + kj::ArrayPtr salt); // Perform Scrypt key derivation. kj::Maybe> scrypt(size_t length, - uint32_t N, - uint32_t r, - uint32_t p, - uint32_t maxmem, - kj::ArrayPtr pass, - kj::ArrayPtr salt); + uint32_t N, + uint32_t r, + uint32_t p, + uint32_t maxmem, + kj::ArrayPtr pass, + kj::ArrayPtr salt); } // namespace workerd::api diff --git a/src/workerd/api/crypto/keys.c++ b/src/workerd/api/crypto/keys.c++ index f01ad490825..f9fd87e6cb5 100644 --- a/src/workerd/api/crypto/keys.c++ +++ b/src/workerd/api/crypto/keys.c++ @@ -12,28 +12,31 @@ static const char EMPTY_PASSPHRASE[] = ""; kj::StringPtr toStringPtr(KeyType type) { switch (type) { - case KeyType::SECRET: return "secret"_kj; - case KeyType::PUBLIC: return "public"_kj; - case KeyType::PRIVATE: return "private"_kj; + case KeyType::SECRET: + return "secret"_kj; + case KeyType::PUBLIC: + return "public"_kj; + case KeyType::PRIVATE: + return "private"_kj; } KJ_UNREACHABLE; } -AsymmetricKeyCryptoKeyImpl::AsymmetricKeyCryptoKeyImpl(AsymmetricKeyData&& key, - bool extractable) +AsymmetricKeyCryptoKeyImpl::AsymmetricKeyCryptoKeyImpl(AsymmetricKeyData&& key, bool extractable) : CryptoKey::Impl(extractable, key.usages), keyData(kj::mv(key.evpPkey)), keyType(key.keyType) { KJ_DASSERT(keyType != KeyType::SECRET); } -kj::Array AsymmetricKeyCryptoKeyImpl::signatureSslToWebCrypto(kj::Array signature) const { +kj::Array AsymmetricKeyCryptoKeyImpl::signatureSslToWebCrypto( + kj::Array signature) const { return kj::mv(signature); } kj::Array AsymmetricKeyCryptoKeyImpl::signatureWebCryptoToSsl( kj::ArrayPtr signature) const { - return { signature.begin(), signature.size(), kj::NullArrayDisposer::instance }; + return {signature.begin(), signature.size(), kj::NullArrayDisposer::instance}; } SubtleCrypto::ExportKeyData AsymmetricKeyCryptoKeyImpl::exportKey(kj::StringPtr format) const { @@ -41,23 +44,21 @@ SubtleCrypto::ExportKeyData AsymmetricKeyCryptoKeyImpl::exportKey(kj::StringPtr // extensions which export asymmetric keys in DER format. // DER is the binary format which *should* work to export any EVP_PKEY. - uint8_t *der = nullptr; + uint8_t* der = nullptr; KJ_DEFER(if (der != nullptr) { OPENSSL_free(der); }); size_t derLen; bssl::ScopedCBB cbb; if (format == "pkcs8"_kj) { JSG_REQUIRE(keyType == KeyType::PRIVATE, DOMInvalidAccessError, "Asymmetric pkcs8 export requires private key (not \"", toStringPtr(keyType), "\")."); - if (!CBB_init(cbb.get(), 0) || - !EVP_marshal_private_key(cbb.get(), keyData.get()) || + if (!CBB_init(cbb.get(), 0) || !EVP_marshal_private_key(cbb.get(), keyData.get()) || !CBB_finish(cbb.get(), &der, &derLen)) { JSG_FAIL_REQUIRE(DOMOperationError, "Private key export failed."); } } else if (format == "spki"_kj) { - JSG_REQUIRE(keyType == KeyType::PUBLIC, DOMInvalidAccessError, + JSG_REQUIRE(keyType == KeyType::PUBLIC, DOMInvalidAccessError, "Asymmetric spki export requires public key (not \"", toStringPtr(keyType), "\")."); - if (!CBB_init(cbb.get(), 0) || - !EVP_marshal_public_key(cbb.get(), keyData.get()) || + if (!CBB_init(cbb.get(), 0) || !EVP_marshal_public_key(cbb.get(), keyData.get()) || !CBB_finish(cbb.get(), &der, &derLen)) { JSG_FAIL_REQUIRE(DOMOperationError, "Public key export failed."); } @@ -78,8 +79,7 @@ SubtleCrypto::ExportKeyData AsymmetricKeyCryptoKeyImpl::exportKey(kj::StringPtr return kj::heapArray(der, derLen); } -kj::Array AsymmetricKeyCryptoKeyImpl::exportKeyExt( - kj::StringPtr format, +kj::Array AsymmetricKeyCryptoKeyImpl::exportKeyExt(kj::StringPtr format, kj::StringPtr type, jsg::Optional cipher, jsg::Optional> passphrase) const { @@ -153,19 +153,14 @@ kj::Array AsymmetricKeyCryptoKeyImpl::exportKeyExt( if (type == "pkcs1"_kj) { // PKCS#1 is only for RSA keys. - JSG_REQUIRE(EVP_PKEY_id(pkey) == EVP_PKEY_RSA, TypeError, - "The pkcs1 type is only valid for RSA keys."); + JSG_REQUIRE( + EVP_PKEY_id(pkey) == EVP_PKEY_RSA, TypeError, "The pkcs1 type is only valid for RSA keys."); auto rsa = EVP_PKEY_get1_RSA(pkey); KJ_DEFER(RSA_free(rsa)); if (format == "pem"_kj) { auto enc = getEncDetail(); - if (PEM_write_bio_RSAPrivateKey( - bio.get(), - rsa, - enc.cipher, - reinterpret_cast(enc.pass), - enc.pass_len, - nullptr, nullptr) == 1) { + if (PEM_write_bio_RSAPrivateKey(bio.get(), rsa, enc.cipher, + reinterpret_cast(enc.pass), enc.pass_len, nullptr, nullptr) == 1) { return fromBio(format); } } else if (format == "der"_kj) { @@ -178,37 +173,25 @@ kj::Array AsymmetricKeyCryptoKeyImpl::exportKeyExt( auto enc = getEncDetail(); if (format == "pem"_kj) { if (PEM_write_bio_PKCS8PrivateKey( - bio.get(), pkey, - enc.cipher, - enc.pass, - enc.pass_len, - nullptr, nullptr) == 1) { + bio.get(), pkey, enc.cipher, enc.pass, enc.pass_len, nullptr, nullptr) == 1) { return fromBio(format); } } else if (format == "der"_kj) { if (i2d_PKCS8PrivateKey_bio( - bio.get(), pkey, - enc.cipher, - enc.pass, - enc.pass_len, - nullptr, nullptr) == 1) { + bio.get(), pkey, enc.cipher, enc.pass, enc.pass_len, nullptr, nullptr) == 1) { return fromBio(format); } } } else if (type == "sec1"_kj) { // SEC1 is only used for EC keys. - JSG_REQUIRE(EVP_PKEY_id(pkey) == EVP_PKEY_EC, TypeError, - "The sec1 type is only valid for EC keys."); + JSG_REQUIRE( + EVP_PKEY_id(pkey) == EVP_PKEY_EC, TypeError, "The sec1 type is only valid for EC keys."); auto ec = EVP_PKEY_get1_EC_KEY(pkey); KJ_DEFER(EC_KEY_free(ec)); if (format == "pem"_kj) { auto enc = getEncDetail(); - if (PEM_write_bio_ECPrivateKey( - bio.get(), ec, - enc.cipher, - reinterpret_cast(enc.pass), - enc.pass_len, - nullptr, nullptr) == 1) { + if (PEM_write_bio_ECPrivateKey(bio.get(), ec, enc.cipher, + reinterpret_cast(enc.pass), enc.pass_len, nullptr, nullptr) == 1) { return fromBio(format); } } else if (format == "der"_kj) { @@ -223,8 +206,7 @@ kj::Array AsymmetricKeyCryptoKeyImpl::exportKeyExt( } kj::Array AsymmetricKeyCryptoKeyImpl::sign( - SubtleCrypto::SignAlgorithm&& algorithm, - kj::ArrayPtr data) const { + SubtleCrypto::SignAlgorithm&& algorithm, kj::ArrayPtr data) const { JSG_REQUIRE(keyType == KeyType::PRIVATE, DOMInvalidAccessError, "Asymmetric signing requires a private key."); @@ -236,17 +218,17 @@ kj::Array AsymmetricKeyCryptoKeyImpl::sign( // least 32 bytes larger than the hash digest. // Similar checks could also be adopted for more detailed error handling in verify(), but the // current approach should be sufficient to avoid internal errors. - RSA& rsa = JSG_REQUIRE_NONNULL(EVP_PKEY_get0_RSA(getEvpPkey()), DOMDataError, - "Missing RSA key", tryDescribeOpensslErrors()); + RSA& rsa = JSG_REQUIRE_NONNULL(EVP_PKEY_get0_RSA(getEvpPkey()), DOMDataError, "Missing RSA key", + tryDescribeOpensslErrors()); JSG_REQUIRE(EVP_MD_size(type) + 32 <= RSA_size(&rsa), DOMOperationError, - "key too small for signing with given digest, need at least ", - 8 * (EVP_MD_size(type) + 32), "bits."); + "key too small for signing with given digest, need at least ", 8 * (EVP_MD_size(type) + 32), + "bits."); } else if (getAlgorithmName() == "RSA-PSS") { // Similarly, RSA-PSS requires keys to be at least the size of the digest and salt plus 2 // bytes, see https://developer.mozilla.org/en-US/docs/Web/API/RsaPssParams for details. - RSA& rsa = JSG_REQUIRE_NONNULL(EVP_PKEY_get0_RSA(getEvpPkey()), DOMDataError, - "Missing RSA key", tryDescribeOpensslErrors()); + RSA& rsa = JSG_REQUIRE_NONNULL(EVP_PKEY_get0_RSA(getEvpPkey()), DOMDataError, "Missing RSA key", + tryDescribeOpensslErrors()); auto salt = JSG_REQUIRE_NONNULL(algorithm.saltLength, DOMDataError, "Failed to provide salt for RSA-PSS key operation which requires a salt"); JSG_REQUIRE(salt >= 0, DOMDataError, "SaltLength for RSA-PSS must be non-negative ", @@ -277,9 +259,9 @@ kj::Array AsymmetricKeyCryptoKeyImpl::sign( return signatureSslToWebCrypto(kj::mv(signature)); } -bool AsymmetricKeyCryptoKeyImpl::verify( - SubtleCrypto::SignAlgorithm&& algorithm, - kj::ArrayPtr signature, kj::ArrayPtr data) const { +bool AsymmetricKeyCryptoKeyImpl::verify(SubtleCrypto::SignAlgorithm&& algorithm, + kj::ArrayPtr signature, + kj::ArrayPtr data) const { ClearErrorOnReturn clearErrorOnReturn; JSG_REQUIRE(keyType == KeyType::PUBLIC, DOMInvalidAccessError, @@ -323,15 +305,14 @@ bool AsymmetricKeyCryptoKeyImpl::verifyX509Public(const X509* cert) const { return X509_verify(const_cast(cert), getEvpPkey()) > 0; } -bool AsymmetricKeyCryptoKeyImpl::verifyX509Private(const X509* cert) const{ +bool AsymmetricKeyCryptoKeyImpl::verifyX509Private(const X509* cert) const { ClearErrorOnReturn clearErrorOnReturn; return X509_check_private_key(const_cast(cert), getEvpPkey()) == 1; } // ====================================================================================== -AsymmetricKeyData importAsymmetricForWebCrypto( - jsg::Lock& js, +AsymmetricKeyData importAsymmetricForWebCrypto(jsg::Lock& js, kj::StringPtr format, SubtleCrypto::ImportKeyData keyData, kj::StringPtr normalizedName, @@ -344,8 +325,8 @@ AsymmetricKeyData importAsymmetricForWebCrypto( // I found jww's SO answer immeasurably helpful while writing this: // https://stackoverflow.com/questions/24093272/how-to-load-a-private-key-from-a-jwk-into-openssl - auto& keyDataJwk = JSG_REQUIRE_NONNULL(keyData.tryGet(), - DOMDataError, "JSON Web Key import requires a JSON Web Key object."); + auto& keyDataJwk = JSG_REQUIRE_NONNULL(keyData.tryGet(), DOMDataError, + "JSON Web Key import requires a JSON Web Key object."); KeyType keyType = KeyType::PRIVATE; if (keyDataJwk.d != kj::none) { @@ -366,16 +347,18 @@ AsymmetricKeyData importAsymmetricForWebCrypto( // restrict key usages to public key usages. In the case of ECDH, usages must be empty, but // if the strict crypto compat flag is not enabled allow the same usages as with private ECDH // keys, i.e. derivationKeyMask(). - usages = - CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::importPublic, - keyUsages, allowedUsages & (normalizedName == "ECDH" ? - strictCrypto ? CryptoKeyUsageSet(): - CryptoKeyUsageSet::derivationKeyMask() : - CryptoKeyUsageSet::publicKeyMask())); + usages = CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::importPublic, + keyUsages, + allowedUsages & + (normalizedName == "ECDH" + ? strictCrypto ? CryptoKeyUsageSet() : CryptoKeyUsageSet::derivationKeyMask() + : CryptoKeyUsageSet::publicKeyMask())); } auto [expectedUse, op0, op1] = [&, normalizedName] { - if (normalizedName == "RSA-OAEP") {return std::make_tuple("enc", "encrypt", "wrapKey");} + if (normalizedName == "RSA-OAEP") { + return std::make_tuple("enc", "encrypt", "wrapKey"); + } if (normalizedName == "ECDH" || normalizedName == "X25519") { return std::make_tuple("enc", "unused", "unused"); } @@ -386,7 +369,8 @@ AsymmetricKeyData importAsymmetricForWebCrypto( KJ_IF_SOME(use, keyDataJwk.use) { JSG_REQUIRE(use == expectedUse, DOMDataError, "Asymmetric \"jwk\" key import with usages requires a JSON Web Key with " - "Public Key Use parameter \"use\" (\"", use, "\") equal to \"sig\"."); + "Public Key Use parameter \"use\" (\"", + use, "\") equal to \"sig\"."); } } @@ -405,14 +389,18 @@ AsymmetricKeyData importAsymmetricForWebCrypto( // "The "use" and "key_ops" JWK members SHOULD NOT be used together; however, if both are // used, the information they convey MUST be consistent." -- RFC 7517, section 4.3. - JSG_REQUIRE(use == expectedUse, DOMDataError, "Asymmetric \"jwk\" import requires a JSON " - "Web Key with Public Key Use \"use\" (\"", use, "\") equal to \"", expectedUse, "\"."); + JSG_REQUIRE(use == expectedUse, DOMDataError, + "Asymmetric \"jwk\" import requires a JSON " + "Web Key with Public Key Use \"use\" (\"", + use, "\") equal to \"", expectedUse, "\"."); for (const auto& op: ops) { JSG_REQUIRE(normalizedName != "ECDH" && normalizedName != "X25519", DOMDataError, "A JSON Web Key should have either a Public Key Use parameter (\"use\") or a Key " "Operations parameter (\"key_ops\"); otherwise, the parameters must be consistent " - "with each other. For public ", normalizedName, " keys, there are no valid usages," + "with each other. For public ", + normalizedName, + " keys, there are no valid usages," "so keys with a non-empty \"key_ops\" parameter are not allowed."); // TODO(conform): Can a JWK private key actually be used to verify? Not @@ -420,9 +408,11 @@ AsymmetricKeyData importAsymmetricForWebCrypto( JSG_REQUIRE(op == op0 || op == op1, DOMDataError, "A JSON Web Key should have either a Public Key Use parameter (\"use\") or a Key " "Operations parameter (\"key_ops\"); otherwise, the parameters must be consistent " - "with each other. A Public Key Use for ", normalizedName, " would allow a Key " - "Operations array with only \"", op0, "\" and/or \"", op1, "\" values (not \"", op, - "\")."); + "with each other. A Public Key Use for ", + normalizedName, + " would allow a Key " + "Operations array with only \"", + op0, "\" and/or \"", op1, "\" values (not \"", op, "\")."); } } @@ -432,14 +422,15 @@ AsymmetricKeyData importAsymmetricForWebCrypto( // and the next usages. Test the first usage and the first usage distinct from the first, if // present (i.e. the second allowed usage, even if there are duplicates). if (keyUsages.size() > 0) { - JSG_REQUIRE(std::find(ops.begin(), ops.end(), keyUsages.front()) != ops.end(), - DOMDataError, "All specified key usages must be present in the JSON " + JSG_REQUIRE(std::find(ops.begin(), ops.end(), keyUsages.front()) != ops.end(), DOMDataError, + "All specified key usages must be present in the JSON " "Web Key's Key Operations parameter (\"key_ops\")."); auto secondUsage = std::find_end(keyUsages.begin(), keyUsages.end(), keyUsages.begin(), - keyUsages.begin() + 1) + 1; + keyUsages.begin() + 1) + + 1; if (secondUsage != keyUsages.end()) { - JSG_REQUIRE(std::find(ops.begin(), ops.end(), *secondUsage) != ops.end(), - DOMDataError, "All specified key usages must be present in the JSON " + JSG_REQUIRE(std::find(ops.begin(), ops.end(), *secondUsage) != ops.end(), DOMDataError, + "All specified key usages must be present in the JSON " "Web Key's Key Operations parameter (\"key_ops\")."); } } @@ -451,41 +442,40 @@ AsymmetricKeyData importAsymmetricForWebCrypto( "Cannot create an extractable CryptoKey from an unextractable JSON Web Key."); } - return { readJwk(kj::mv(keyDataJwk)), keyType, usages }; + return {readJwk(kj::mv(keyDataJwk)), keyType, usages}; } else if (format == "spki") { - kj::ArrayPtr keyBytes = JSG_REQUIRE_NONNULL( - keyData.tryGet>(), DOMDataError, - "SPKI import requires an ArrayBuffer."); + kj::ArrayPtr keyBytes = + JSG_REQUIRE_NONNULL(keyData.tryGet>(), DOMDataError, + "SPKI import requires an ArrayBuffer."); const kj::byte* ptr = keyBytes.begin(); - auto evpPkey = OSSLCALL_OWN(EVP_PKEY, d2i_PUBKEY(nullptr, &ptr, keyBytes.size()), DOMDataError, - "Invalid SPKI input."); + auto evpPkey = OSSLCALL_OWN( + EVP_PKEY, d2i_PUBKEY(nullptr, &ptr, keyBytes.size()), DOMDataError, "Invalid SPKI input."); if (ptr != keyBytes.end()) { - JSG_FAIL_REQUIRE(DOMDataError, "Invalid ", keyBytes.end() - ptr, - " trailing bytes after SPKI input."); + JSG_FAIL_REQUIRE( + DOMDataError, "Invalid ", keyBytes.end() - ptr, " trailing bytes after SPKI input."); } // usages must be empty for ECDH public keys, so use CryptoKeyUsageSet() when validating the // usage set. - usages = - CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::importPublic, - keyUsages, allowedUsages & (normalizedName == "ECDH" ? - CryptoKeyUsageSet() : CryptoKeyUsageSet::publicKeyMask())); - return { kj::mv(evpPkey), KeyType::PUBLIC, usages }; + usages = CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::importPublic, + keyUsages, + allowedUsages & + (normalizedName == "ECDH" ? CryptoKeyUsageSet() : CryptoKeyUsageSet::publicKeyMask())); + return {kj::mv(evpPkey), KeyType::PUBLIC, usages}; } else if (format == "pkcs8") { - kj::ArrayPtr keyBytes = JSG_REQUIRE_NONNULL( - keyData.tryGet>(), DOMDataError, - "PKCS8 import requires an ArrayBuffer."); + kj::ArrayPtr keyBytes = + JSG_REQUIRE_NONNULL(keyData.tryGet>(), DOMDataError, + "PKCS8 import requires an ArrayBuffer."); const kj::byte* ptr = keyBytes.begin(); auto evpPkey = OSSLCALL_OWN(EVP_PKEY, d2i_AutoPrivateKey(nullptr, &ptr, keyBytes.size()), DOMDataError, "Invalid PKCS8 input."); if (ptr != keyBytes.end()) { - JSG_FAIL_REQUIRE(DOMDataError, "Invalid ", keyBytes.end() - ptr, - " trailing bytes after PKCS8 input."); + JSG_FAIL_REQUIRE( + DOMDataError, "Invalid ", keyBytes.end() - ptr, " trailing bytes after PKCS8 input."); } - usages = - CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::importPrivate, - keyUsages, allowedUsages & CryptoKeyUsageSet::privateKeyMask()); - return { kj::mv(evpPkey), KeyType::PRIVATE, usages }; + usages = CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::importPrivate, + keyUsages, allowedUsages & CryptoKeyUsageSet::privateKeyMask()); + return {kj::mv(evpPkey), KeyType::PRIVATE, usages}; } else { JSG_FAIL_REQUIRE(DOMNotSupportedError, "Unrecognized key import format \"", format, "\"."); } diff --git a/src/workerd/api/crypto/keys.h b/src/workerd/api/crypto/keys.h index 40f4ff121be..56617376056 100644 --- a/src/workerd/api/crypto/keys.h +++ b/src/workerd/api/crypto/keys.h @@ -13,10 +13,14 @@ enum class KeyEncoding { inline kj::StringPtr KJ_STRINGIFY(KeyEncoding encoding) { switch (encoding) { - case KeyEncoding::PKCS1: return "pkcs1"; - case KeyEncoding::PKCS8: return "pkcs8"; - case KeyEncoding::SPKI: return "spki"; - case KeyEncoding::SEC1: return "sec1"; + case KeyEncoding::PKCS1: + return "pkcs1"; + case KeyEncoding::PKCS8: + return "pkcs8"; + case KeyEncoding::SPKI: + return "spki"; + case KeyEncoding::SEC1: + return "sec1"; } KJ_UNREACHABLE; } @@ -67,37 +71,43 @@ class AsymmetricKeyCryptoKeyImpl: public CryptoKey::Impl { // Add salt to digest context in order to generate or verify salted signature. // Currently only used for RSA-PSS sign and verify operations. - virtual void addSalt(EVP_PKEY_CTX* digestCtx, - const SubtleCrypto::SignAlgorithm& algorithm) const {} + virtual void addSalt( + EVP_PKEY_CTX* digestCtx, const SubtleCrypto::SignAlgorithm& algorithm) const {} // --------------------------------------------------------------------------- // Implementation of CryptoKey SubtleCrypto::ExportKeyData exportKey(kj::StringPtr format) const override final; - virtual kj::Array exportKeyExt( - kj::StringPtr format, + virtual kj::Array exportKeyExt(kj::StringPtr format, kj::StringPtr type, jsg::Optional cipher = kj::none, jsg::Optional> passphrase = kj::none) const override final; kj::Array sign( - SubtleCrypto::SignAlgorithm&& algorithm, - kj::ArrayPtr data) const override; + SubtleCrypto::SignAlgorithm&& algorithm, kj::ArrayPtr data) const override; - bool verify( - SubtleCrypto::SignAlgorithm&& algorithm, - kj::ArrayPtr signature, kj::ArrayPtr data) const override; + bool verify(SubtleCrypto::SignAlgorithm&& algorithm, + kj::ArrayPtr signature, + kj::ArrayPtr data) const override; kj::StringPtr getType() const override; - KeyType getTypeEnum() const { return keyType; } + KeyType getTypeEnum() const { + return keyType; + } - inline EVP_PKEY* getEvpPkey() const { return keyData.get(); } + inline EVP_PKEY* getEvpPkey() const { + return keyData.get(); + } bool equals(const CryptoKey::Impl& other) const override final; - kj::StringPtr jsgGetMemoryName() const override { return "AsymmetricKey"; } - size_t jsgGetMemorySelfSize() const override { return sizeof(AsymmetricKeyCryptoKeyImpl); } + kj::StringPtr jsgGetMemoryName() const override { + return "AsymmetricKey"; + } + size_t jsgGetMemorySelfSize() const override { + return sizeof(AsymmetricKeyCryptoKeyImpl); + } void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const override {} bool verifyX509Public(const X509* cert) const override; @@ -113,8 +123,7 @@ class AsymmetricKeyCryptoKeyImpl: public CryptoKey::Impl { }; // Performs asymmetric key import per the Web Crypto spec. -AsymmetricKeyData importAsymmetricForWebCrypto( - jsg::Lock& js, +AsymmetricKeyData importAsymmetricForWebCrypto(jsg::Lock& js, kj::StringPtr format, SubtleCrypto::ImportKeyData keyData, kj::StringPtr normalizedName, diff --git a/src/workerd/api/crypto/pbkdf2.c++ b/src/workerd/api/crypto/pbkdf2.c++ index 82e6892a802..3d9f1ddf696 100644 --- a/src/workerd/api/crypto/pbkdf2.c++ +++ b/src/workerd/api/crypto/pbkdf2.c++ @@ -11,32 +11,39 @@ namespace { class Pbkdf2Key final: public CryptoKey::Impl { public: - explicit Pbkdf2Key(kj::Array keyData, CryptoKey::KeyAlgorithm keyAlgorithm, - bool extractable, CryptoKeyUsageSet usages) + explicit Pbkdf2Key(kj::Array keyData, + CryptoKey::KeyAlgorithm keyAlgorithm, + bool extractable, + CryptoKeyUsageSet usages) : CryptoKey::Impl(extractable, usages), - keyData(kj::mv(keyData)), keyAlgorithm(kj::mv(keyAlgorithm)) {} + keyData(kj::mv(keyData)), + keyAlgorithm(kj::mv(keyAlgorithm)) {} - kj::StringPtr jsgGetMemoryName() const override { return "Pbkdf2Key"; } - size_t jsgGetMemorySelfSize() const override { return sizeof(Pbkdf2Key); } + kj::StringPtr jsgGetMemoryName() const override { + return "Pbkdf2Key"; + } + size_t jsgGetMemorySelfSize() const override { + return sizeof(Pbkdf2Key); + } void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const override { tracker.trackFieldWithSize("keyData", keyData.size()); tracker.trackField("keyAlgorithm", keyAlgorithm); } private: - kj::Array deriveBits( - jsg::Lock& js, SubtleCrypto::DeriveKeyAlgorithm&& algorithm, + kj::Array deriveBits(jsg::Lock& js, + SubtleCrypto::DeriveKeyAlgorithm&& algorithm, kj::Maybe maybeLength) const override { - kj::StringPtr hashName = api::getAlgorithmName(JSG_REQUIRE_NONNULL(algorithm.hash, TypeError, - "Missing field \"hash\" in \"algorithm\".")); + kj::StringPtr hashName = api::getAlgorithmName( + JSG_REQUIRE_NONNULL(algorithm.hash, TypeError, "Missing field \"hash\" in \"algorithm\".")); auto hashType = lookupDigestAlgorithm(hashName).second; - kj::ArrayPtr salt = JSG_REQUIRE_NONNULL(algorithm.salt, TypeError, - "Missing field \"salt\" in \"algorithm\"."); - int iterations = JSG_REQUIRE_NONNULL(algorithm.iterations, TypeError, - "Missing field \"iterations\" in \"algorithm\"."); + kj::ArrayPtr salt = + JSG_REQUIRE_NONNULL(algorithm.salt, TypeError, "Missing field \"salt\" in \"algorithm\"."); + int iterations = JSG_REQUIRE_NONNULL( + algorithm.iterations, TypeError, "Missing field \"iterations\" in \"algorithm\"."); - uint32_t length = JSG_REQUIRE_NONNULL(maybeLength, DOMOperationError, - "PBKDF2 cannot derive a key with null length."); + uint32_t length = JSG_REQUIRE_NONNULL( + maybeLength, DOMOperationError, "PBKDF2 cannot derive a key with null length."); JSG_REQUIRE(length != 0 && (length & 0b111) == 0, DOMOperationError, "PBKDF2 requires a derived key length that is a non-zero multiple of eight (requested ", @@ -53,8 +60,8 @@ private: // wisest. checkPbkdfLimits(js, iterations); - return JSG_REQUIRE_NONNULL(pbkdf2(length / 8, iterations, hashType, keyData, salt), - Error, "PBKDF2 deriveBits failed."); + return JSG_REQUIRE_NONNULL(pbkdf2(length / 8, iterations, hashType, keyData, salt), Error, + "PBKDF2 deriveBits failed."); } // TODO(bug): Possibly by mistake, PBKDF2 was historically not on the allow list of @@ -63,14 +70,18 @@ private: // preexisting behavior, then, this implementation had to be commented out. If disallowing this // was a mistake, we can un-comment this method, but we would need to make sure to add tests // when we do. -// SubtleCrypto::ExportKeyData exportKey(kj::StringPtr format) const override { -// JSG_REQUIRE(format == "raw", DOMNotSupportedError, -// "Unimplemented key export format \"", format, "\"."); -// return kj::heapArray(keyData.asPtr()); -// } - - kj::StringPtr getAlgorithmName() const override { return "PBKDF2"; } - CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override { return keyAlgorithm; } + // SubtleCrypto::ExportKeyData exportKey(kj::StringPtr format) const override { + // JSG_REQUIRE(format == "raw", DOMNotSupportedError, + // "Unimplemented key export format \"", format, "\"."); + // return kj::heapArray(keyData.asPtr()); + // } + + kj::StringPtr getAlgorithmName() const override { + return "PBKDF2"; + } + CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override { + return keyAlgorithm; + } bool equals(const CryptoKey::Impl& other) const override final { return this == &other || (other.getType() == "secret"_kj && other.equals(keyData)); @@ -78,7 +89,7 @@ private: bool equals(const kj::Array& other) const override final { return keyData.size() == other.size() && - CRYPTO_memcmp(keyData.begin(), other.begin(), keyData.size()) == 0; + CRYPTO_memcmp(keyData.begin(), other.begin(), keyData.size()) == 0; } ZeroOnFree keyData; @@ -88,32 +99,27 @@ private: } // namespace kj::Maybe> pbkdf2(size_t length, - size_t iterations, - const EVP_MD* digest, - kj::ArrayPtr password, - kj::ArrayPtr salt) { + size_t iterations, + const EVP_MD* digest, + kj::ArrayPtr password, + kj::ArrayPtr salt) { auto buf = kj::heapArray(length); - if (PKCS5_PBKDF2_HMAC(password.asChars().begin(), - password.size(), - salt.begin(), - salt.size(), - iterations, - digest, - length, - buf.begin()) != 1) { + if (PKCS5_PBKDF2_HMAC(password.asChars().begin(), password.size(), salt.begin(), salt.size(), + iterations, digest, length, buf.begin()) != 1) { return kj::none; } return kj::mv(buf); } -kj::Own CryptoKey::Impl::importPbkdf2( - jsg::Lock& js, kj::StringPtr normalizedName, kj::StringPtr format, +kj::Own CryptoKey::Impl::importPbkdf2(jsg::Lock& js, + kj::StringPtr normalizedName, + kj::StringPtr format, SubtleCrypto::ImportKeyData keyData, - SubtleCrypto::ImportKeyAlgorithm&& algorithm, bool extractable, + SubtleCrypto::ImportKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages) { - auto usages = - CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::importSecret, - keyUsages, CryptoKeyUsageSet::derivationKeyMask()); + auto usages = CryptoKeyUsageSet::validate(normalizedName, + CryptoKeyUsageSet::Context::importSecret, keyUsages, CryptoKeyUsageSet::derivationKeyMask()); JSG_REQUIRE(!extractable, DOMSyntaxError, "PBKDF2 key cannot be extractable."); JSG_REQUIRE(format == "raw", DOMNotSupportedError, diff --git a/src/workerd/api/crypto/prime.c++ b/src/workerd/api/crypto/prime.c++ index d0a2db4b07d..243f271f56d 100644 --- a/src/workerd/api/crypto/prime.c++ +++ b/src/workerd/api/crypto/prime.c++ @@ -5,29 +5,30 @@ namespace workerd::api { -kj::Array randomPrime(uint32_t size, bool safe, - kj::Maybe> add_buf, - kj::Maybe> rem_buf) { +kj::Array randomPrime(uint32_t size, + bool safe, + kj::Maybe> add_buf, + kj::Maybe> rem_buf) { ClearErrorOnReturn clearErrorOnReturn; // Use mapping to have kj::Own work with optional buffer const auto maybeOwnBignum = [](kj::Maybe>& maybeBignum) { return maybeBignum.map([](kj::ArrayPtr& a) { - return JSG_REQUIRE_NONNULL(toBignum(a), RangeError, - "Error importing add parameter", internalDescribeOpensslErrors()); + return JSG_REQUIRE_NONNULL(toBignum(a), RangeError, "Error importing add parameter", + internalDescribeOpensslErrors()); }); }; BIGNUM* add = nullptr; auto _add = maybeOwnBignum(add_buf); KJ_IF_SOME(a, _add) { - add = a.get(); + add = a.get(); } BIGNUM* rem = nullptr; auto _rem = maybeOwnBignum(rem_buf); KJ_IF_SOME(r, _rem) { - rem = r.get(); + rem = r.get(); } if (add != nullptr) { @@ -49,47 +50,41 @@ kj::Array randomPrime(uint32_t size, bool safe, return BN_cmp(add, addCheck.get()) == 0 && BN_cmp(rem, remCheck.get()) == 0; }; - JSG_REQUIRE(rem != nullptr && (checkAddRem(12, 11) || checkAddRem(24, 23) || - checkAddRem(60, 59)), RangeError, "Invalid values for add and rem"); + JSG_REQUIRE( + rem != nullptr && (checkAddRem(12, 11) || checkAddRem(24, 23) || checkAddRem(60, 59)), + RangeError, "Invalid values for add and rem"); } // The JS interface already ensures that the (positive) size fits into an int. int bits = static_cast(size); if (add) { - // If we allowed this, the best case would be returning a static prime - // that wasn't generated randomly. The worst case would be an infinite - // loop within OpenSSL, blocking the main thread or one of the threads - // in the thread pool. + // If we allowed this, the best case would be returning a static prime + // that wasn't generated randomly. The worst case would be an infinite + // loop within OpenSSL, blocking the main thread or one of the threads + // in the thread pool. JSG_REQUIRE(BN_num_bits(add) <= bits, RangeError, "options.add must not be bigger than size of the requested prime"); if (rem) { // This would definitely lead to an infinite loop if allowed since // OpenSSL does not check this condition. - JSG_REQUIRE(BN_cmp(add, rem) == 1, RangeError, - "options.rem must be smaller than options.add"); + JSG_REQUIRE( + BN_cmp(add, rem) == 1, RangeError, "options.rem must be smaller than options.add"); } } // BN_generate_prime_ex() calls RAND_bytes_ex() internally. // Make sure the CSPRNG is properly seeded. - JSG_REQUIRE(workerd::api::CSPRNG(nullptr), Error, - "Error while generating prime (bad random state)"); + JSG_REQUIRE( + workerd::api::CSPRNG(nullptr), Error, "Error while generating prime (bad random state)"); auto prime = OSSL_NEW(BIGNUM); - int ret = BN_generate_prime_ex( - prime.get(), - bits, - safe ? 1 : 0, - add, - rem, - nullptr); + int ret = BN_generate_prime_ex(prime.get(), bits, safe ? 1 : 0, add, rem, nullptr); JSG_REQUIRE(ret == 1, Error, "Error while generating prime"); - return JSG_REQUIRE_NONNULL(bignumToArrayPadded(*prime), Error, - "Error while generating prime"); + return JSG_REQUIRE_NONNULL(bignumToArrayPadded(*prime), Error, "Error while generating prime"); } bool checkPrime(kj::ArrayPtr bufferView, uint32_t num_checks) { diff --git a/src/workerd/api/crypto/prime.h b/src/workerd/api/crypto/prime.h index b1cd7fe26a8..1e363846ca0 100644 --- a/src/workerd/api/crypto/prime.h +++ b/src/workerd/api/crypto/prime.h @@ -6,9 +6,10 @@ namespace workerd::api { // Generate a random prime number -kj::Array randomPrime(uint32_t size, bool safe, - kj::Maybe> add_buf, - kj::Maybe> rem_buf); +kj::Array randomPrime(uint32_t size, + bool safe, + kj::Maybe> add_buf, + kj::Maybe> rem_buf); // Checks if the given buffer represents a prime. bool checkPrime(kj::ArrayPtr buffer, uint32_t num_checks); diff --git a/src/workerd/api/crypto/rsa.c++ b/src/workerd/api/crypto/rsa.c++ index 590cde926c9..8b36f381349 100644 --- a/src/workerd/api/crypto/rsa.c++ +++ b/src/workerd/api/crypto/rsa.c++ @@ -43,17 +43,14 @@ kj::Array bioToArray(BIO* bio) { kj::Maybe> simdutfBase64UrlDecode(kj::StringPtr input) { auto size = simdutf::maximal_binary_length_from_base64(input.begin(), input.size()); auto buf = kj::heapArray(size); - auto result = simdutf::base64_to_binary(input.begin(), - input.size(), - buf.asChars().begin(), - simdutf::base64_url); + auto result = simdutf::base64_to_binary( + input.begin(), input.size(), buf.asChars().begin(), simdutf::base64_url); if (result.error != simdutf::SUCCESS) return kj::none; KJ_ASSERT(result.count <= size); return buf.first(result.count).attach(kj::mv(buf)); } -kj::Array simdutfBase64UrlDecodeChecked(kj::StringPtr input, - kj::StringPtr error) { +kj::Array simdutfBase64UrlDecodeChecked(kj::StringPtr input, kj::StringPtr error) { return JSG_REQUIRE_NONNULL(simdutfBase64UrlDecode(input), Error, error); } } // namespace @@ -66,7 +63,7 @@ kj::Maybe Rsa::tryGetRsa(const EVP_PKEY* key) { return Rsa(rsa); } -Rsa::Rsa(RSA* rsa) : rsa(rsa) { +Rsa::Rsa(RSA* rsa): rsa(rsa) { RSA_get0_key(rsa, &n, &e, &d); } @@ -86,8 +83,8 @@ CryptoKey::AsymmetricKeyDetails Rsa::getAsymmetricKeyDetail() const { CryptoKey::AsymmetricKeyDetails details; details.modulusLength = BN_num_bits(n); - details.publicExponent = JSG_REQUIRE_NONNULL(bignumToArrayPadded(*e), Error, - "Failed to extract public exponent"); + details.publicExponent = + JSG_REQUIRE_NONNULL(bignumToArrayPadded(*e), Error, "Failed to extract public exponent"); // TODO(soon): Does BoringSSL not support retrieving RSA_PSS params? // if (type == EVP_PKEY_RSA_PSS) { @@ -144,9 +141,11 @@ kj::Array Rsa::sign(const kj::ArrayPtr data) const { // size – having both the same size makes it highly likely that some values are higher than the // key value – but there are scripts and test cases that depend on signing data with keys of // the same size. - JSG_REQUIRE(data.size() <= size, DOMDataError, - "Blind Signing requires presigned data (", data.size(), " bytes) to be smaller than " - "the key (", size, " bytes)."); + JSG_REQUIRE(data.size() <= size, DOMDataError, "Blind Signing requires presigned data (", + data.size(), + " bytes) to be smaller than " + "the key (", + size, " bytes)."); if (data.size() == size) { auto dataVal = JSG_REQUIRE_NONNULL(toBignum(data), InternalDOMOperationError, "Error converting presigned data", internalDescribeOpensslErrors()); @@ -157,10 +156,8 @@ kj::Array Rsa::sign(const kj::ArrayPtr data) const { auto signature = kj::heapArray(size); size_t signatureSize = 0; - OSSLCALL(RSA_decrypt(rsa, &signatureSize, - signature.begin(), signature.size(), - data.begin(), data.size(), - RSA_NO_PADDING)); + OSSLCALL(RSA_decrypt(rsa, &signatureSize, signature.begin(), signature.size(), data.begin(), + data.size(), RSA_NO_PADDING)); KJ_ASSERT(signatureSize <= signature.size()); if (signatureSize < signature.size()) { // We did not fill the entire buffer, let's make sure we zero @@ -173,10 +170,10 @@ kj::Array Rsa::sign(const kj::ArrayPtr data) const { } kj::Array Rsa::cipher(EVP_PKEY_CTX* ctx, - SubtleCrypto::EncryptAlgorithm&& algorithm, - kj::ArrayPtr data, - EncryptDecryptFunction encryptDecrypt, - const EVP_MD* digest) const { + SubtleCrypto::EncryptAlgorithm&& algorithm, + kj::ArrayPtr data, + EncryptDecryptFunction encryptDecrypt, + const EVP_MD* digest) const { JSG_REQUIRE(1 == EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING), InternalDOMOperationError, "Error doing RSA OAEP encrypt/decrypt (", "padding", ")", @@ -196,15 +193,13 @@ kj::Array Rsa::cipher(EVP_PKEY_CTX* ctx, // this API call can fail. JSG_REQUIRE(labelCopy != nullptr, DOMOperationError, - "Failed to allocate space for RSA-OAEP label copy", - tryDescribeOpensslErrors()); + "Failed to allocate space for RSA-OAEP label copy", tryDescribeOpensslErrors()); std::copy(l.begin(), l.end(), labelCopy); // EVP_PKEY_CTX_set0_rsa_oaep_label below takes ownership of the buffer passed in (must have // been OPENSSL_malloc-allocated). - JSG_REQUIRE(1 == EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, labelCopy, l.size()), - DOMOperationError, "Failed to set RSA-OAEP label", - tryDescribeOpensslErrors()); + JSG_REQUIRE(1 == EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, labelCopy, l.size()), DOMOperationError, + "Failed to set RSA-OAEP label", tryDescribeOpensslErrors()); // Ownership has now been transferred. The chromium WebCrypto code technically has a potential // memory leak here in that they check the error for EVP_PKEY_CTX_set0_rsa_oaep_label after @@ -216,22 +211,20 @@ kj::Array Rsa::cipher(EVP_PKEY_CTX* ctx, size_t maxResultLength = 0; // First compute an upper bound on the amount of space we need to store the encrypted/decrypted // result. Then we actually apply the encryption & finally resize to the actual correct length. - JSG_REQUIRE(1 == encryptDecrypt(ctx, nullptr, &maxResultLength, data.begin(), - data.size()), DOMOperationError, "Failed to compute length of RSA-OAEP result", - tryDescribeOpensslErrors()); + JSG_REQUIRE(1 == encryptDecrypt(ctx, nullptr, &maxResultLength, data.begin(), data.size()), + DOMOperationError, "Failed to compute length of RSA-OAEP result", tryDescribeOpensslErrors()); kj::Vector result(maxResultLength); - auto err = encryptDecrypt(ctx, result.begin(), &maxResultLength, data.begin(), - data.size()); - JSG_REQUIRE(1 == err, DOMOperationError, "RSA-OAEP failed encrypt/decrypt", - tryDescribeOpensslErrors()); + auto err = encryptDecrypt(ctx, result.begin(), &maxResultLength, data.begin(), data.size()); + JSG_REQUIRE( + 1 == err, DOMOperationError, "RSA-OAEP failed encrypt/decrypt", tryDescribeOpensslErrors()); result.resize(maxResultLength); return result.releaseAsArray(); } -SubtleCrypto::JsonWebKey Rsa::toJwk(KeyType keyType, - kj::Maybe maybeHashAlgorithm) const { +SubtleCrypto::JsonWebKey Rsa::toJwk( + KeyType keyType, kj::Maybe maybeHashAlgorithm) const { SubtleCrypto::JsonWebKey jwk; jwk.kty = kj::str("RSA"); KJ_IF_SOME(name, maybeHashAlgorithm) { @@ -253,17 +246,16 @@ SubtleCrypto::JsonWebKey Rsa::toJwk(KeyType keyType, return jwk; } -kj::Maybe Rsa::fromJwk(KeyType keyType, - const SubtleCrypto::JsonWebKey& jwk) { +kj::Maybe Rsa::fromJwk(KeyType keyType, const SubtleCrypto::JsonWebKey& jwk) { ClearErrorOnReturn clearErrorOnReturn; if (jwk.kty != "RSA"_kj) return kj::none; auto n = JSG_REQUIRE_NONNULL(jwk.n.map([](auto& str) { return str.asPtr(); }), Error, - "Invalid RSA key in JSON Web Key; missing or invalid " - "Modulus parameter (\"n\")."); + "Invalid RSA key in JSON Web Key; missing or invalid " + "Modulus parameter (\"n\")."); auto e = JSG_REQUIRE_NONNULL(jwk.e.map([](auto& str) { return str.asPtr(); }), Error, - "Invalid RSA key in JSON Web Key; missing or invalid " - "Exponent parameter (\"e\")."); + "Invalid RSA key in JSON Web Key; missing or invalid " + "Exponent parameter (\"e\")."); auto rsa = OSSL_NEW(RSA); @@ -272,29 +264,29 @@ kj::Maybe Rsa::fromJwk(KeyType keyType, auto nDecoded = toBignumUnowned(simdutfBase64UrlDecodeChecked(n, kInvalidBase64Error)); auto eDecoded = toBignumUnowned(simdutfBase64UrlDecodeChecked(e, kInvalidBase64Error)); JSG_REQUIRE(RSA_set0_key(rsa.get(), nDecoded, eDecoded, nullptr) == 1, Error, - "Invalid RSA key in JSON Web Key; failed to set key parameters"); + "Invalid RSA key in JSON Web Key; failed to set key parameters"); if (keyType == KeyType::PRIVATE) { auto d = JSG_REQUIRE_NONNULL(jwk.d.map([](auto& str) { return str.asPtr(); }), Error, - "Invalid RSA key in JSON Web Key; missing or invalid " - "Private Exponent parameter (\"d\")."); + "Invalid RSA key in JSON Web Key; missing or invalid " + "Private Exponent parameter (\"d\")."); auto p = JSG_REQUIRE_NONNULL(jwk.p.map([](auto& str) { return str.asPtr(); }), Error, - "Invalid RSA key in JSON Web Key; missing or invalid " - "First Prime Factor parameter (\"p\")."); + "Invalid RSA key in JSON Web Key; missing or invalid " + "First Prime Factor parameter (\"p\")."); auto q = JSG_REQUIRE_NONNULL(jwk.q.map([](auto& str) { return str.asPtr(); }), Error, - "Invalid RSA key in JSON Web Key; missing or invalid " - "Second Prime Factor parameter (\"q\")."); + "Invalid RSA key in JSON Web Key; missing or invalid " + "Second Prime Factor parameter (\"q\")."); auto dp = JSG_REQUIRE_NONNULL(jwk.dp.map([](auto& str) { return str.asPtr(); }), Error, - "Invalid RSA key in JSON Web Key; missing or invalid " - "First Factor CRT Exponent parameter (\"dp\")."); + "Invalid RSA key in JSON Web Key; missing or invalid " + "First Factor CRT Exponent parameter (\"dp\")."); auto dq = JSG_REQUIRE_NONNULL(jwk.dq.map([](auto& str) { return str.asPtr(); }), Error, - "Invalid RSA key in JSON Web Key; missing or invalid " - "Second Factor CRT Exponent parameter (\"dq\")."); + "Invalid RSA key in JSON Web Key; missing or invalid " + "Second Factor CRT Exponent parameter (\"dq\")."); auto qi = JSG_REQUIRE_NONNULL(jwk.qi.map([](auto& str) { return str.asPtr(); }), Error, - "Invalid RSA key in JSON Web Key; missing or invalid " - "First CRT Coefficient parameter (\"qi\")."); - auto dDecoded = toBignumUnowned(simdutfBase64UrlDecodeChecked(d, - "Invalid RSA key in JSON Web Key"_kj)); + "Invalid RSA key in JSON Web Key; missing or invalid " + "First CRT Coefficient parameter (\"qi\")."); + auto dDecoded = + toBignumUnowned(simdutfBase64UrlDecodeChecked(d, "Invalid RSA key in JSON Web Key"_kj)); auto pDecoded = toBignumUnowned(simdutfBase64UrlDecodeChecked(p, kInvalidBase64Error)); auto qDecoded = toBignumUnowned(simdutfBase64UrlDecodeChecked(q, kInvalidBase64Error)); auto dpDecoded = toBignumUnowned(simdutfBase64UrlDecodeChecked(dp, kInvalidBase64Error)); @@ -302,11 +294,11 @@ kj::Maybe Rsa::fromJwk(KeyType keyType, auto qiDecoded = toBignumUnowned(simdutfBase64UrlDecodeChecked(qi, kInvalidBase64Error)); JSG_REQUIRE(RSA_set0_key(rsa.get(), nullptr, nullptr, dDecoded) == 1, Error, - "Invalid RSA key in JSON Web Key; failed to set private exponent"); + "Invalid RSA key in JSON Web Key; failed to set private exponent"); JSG_REQUIRE(RSA_set0_factors(rsa.get(), pDecoded, qDecoded) == 1, Error, - "Invalid RSA key in JSON Web Key; failed to set prime factors"); + "Invalid RSA key in JSON Web Key; failed to set prime factors"); JSG_REQUIRE(RSA_set0_crt_params(rsa.get(), dpDecoded, dqDecoded, qiDecoded) == 1, Error, - "Invalid RSA key in JSON Web Key; failed to set CRT parameters"); + "Invalid RSA key in JSON Web Key; failed to set CRT parameters"); } auto evpPkey = OSSL_NEW(EVP_PKEY); @@ -314,16 +306,11 @@ kj::Maybe Rsa::fromJwk(KeyType keyType, auto usages = keyType == KeyType::PRIVATE ? CryptoKeyUsageSet::privateKeyMask() : CryptoKeyUsageSet::publicKeyMask(); - return AsymmetricKeyData { - kj::mv(evpPkey), - keyType, - usages - }; + return AsymmetricKeyData{kj::mv(evpPkey), keyType, usages}; } -kj::String Rsa::toPem(KeyEncoding encoding, - KeyType keyType, - kj::Maybe options) const { +kj::String Rsa::toPem( + KeyEncoding encoding, KeyType keyType, kj::Maybe options) const { ClearErrorOnReturn clearErrorOnReturn; auto bio = OSSL_BIO_MEM(); switch (keyType) { @@ -357,17 +344,16 @@ kj::String Rsa::toPem(KeyEncoding encoding, switch (encoding) { case KeyEncoding::PKCS1: { JSG_REQUIRE(PEM_write_bio_RSAPrivateKey( - bio.get(), rsa, cipher, passphrase, passLen, nullptr, nullptr) == 1, Error, - "Failed to write RSA private key to PEM", tryDescribeOpensslErrors()); + bio.get(), rsa, cipher, passphrase, passLen, nullptr, nullptr) == 1, + Error, "Failed to write RSA private key to PEM", tryDescribeOpensslErrors()); break; } case KeyEncoding::PKCS8: { auto evpPkey = OSSL_NEW(EVP_PKEY); EVP_PKEY_set1_RSA(evpPkey.get(), rsa); - JSG_REQUIRE(PEM_write_bio_PKCS8PrivateKey( - bio.get(), evpPkey.get(), cipher, reinterpret_cast(passphrase), - passLen, nullptr, nullptr) == 1, Error, - "Failed to write RSA private key to PKCS8 PEM", tryDescribeOpensslErrors()); + JSG_REQUIRE(PEM_write_bio_PKCS8PrivateKey(bio.get(), evpPkey.get(), cipher, + reinterpret_cast(passphrase), passLen, nullptr, nullptr) == 1, + Error, "Failed to write RSA private key to PKCS8 PEM", tryDescribeOpensslErrors()); break; } default: { @@ -376,14 +362,14 @@ kj::String Rsa::toPem(KeyEncoding encoding, } break; } - default: KJ_UNREACHABLE; + default: + KJ_UNREACHABLE; } return kj::String(bioToArray(bio.get()).releaseAsChars()); } -kj::Array Rsa::toDer(KeyEncoding encoding, - KeyType keyType, - kj::Maybe options) const { +kj::Array Rsa::toDer( + KeyEncoding encoding, KeyType keyType, kj::Maybe options) const { ClearErrorOnReturn clearErrorOnReturn; auto bio = OSSL_BIO_MEM(); switch (keyType) { @@ -426,9 +412,9 @@ kj::Array Rsa::toDer(KeyEncoding encoding, case KeyEncoding::PKCS8: { auto evpPkey = OSSL_NEW(EVP_PKEY); EVP_PKEY_set1_RSA(evpPkey.get(), rsa); - JSG_REQUIRE(i2d_PKCS8PrivateKey_bio(bio.get(), evpPkey.get(), - cipher, reinterpret_cast(passphrase), passLen, nullptr, nullptr) == 1, Error, - "Failed to write RSA private key to PKCS8 PEM", tryDescribeOpensslErrors()); + JSG_REQUIRE(i2d_PKCS8PrivateKey_bio(bio.get(), evpPkey.get(), cipher, + reinterpret_cast(passphrase), passLen, nullptr, nullptr) == 1, + Error, "Failed to write RSA private key to PKCS8 PEM", tryDescribeOpensslErrors()); break; } default: { @@ -437,23 +423,25 @@ kj::Array Rsa::toDer(KeyEncoding encoding, } break; } - default: KJ_UNREACHABLE; + default: + KJ_UNREACHABLE; } return bioToArray(bio.get()); } -void Rsa::validateRsaParams(jsg::Lock& js, - size_t modulusLength, - kj::ArrayPtr publicExponent, - bool isImport) { +void Rsa::validateRsaParams( + jsg::Lock& js, size_t modulusLength, kj::ArrayPtr publicExponent, bool isImport) { KJ_ASSERT(modulusLength <= ~uint16_t(0)); // Use Chromium's limits for RSA keygen to avoid infinite loops: // * Key sizes a multiple of 8 bits. // * Key sizes must be in [256, 16k] bits. auto strictCrypto = FeatureFlags::get(js).getStrictCrypto(); - JSG_REQUIRE(!(strictCrypto || !isImport) || (modulusLength % 8 == 0 && modulusLength >= 256 && - modulusLength <= 16384), DOMOperationError, "The modulus length must be a multiple of 8 and " - "between 256 and 16k, but ", modulusLength, " was requested."); + JSG_REQUIRE(!(strictCrypto || !isImport) || + (modulusLength % 8 == 0 && modulusLength >= 256 && modulusLength <= 16384), + DOMOperationError, + "The modulus length must be a multiple of 8 and " + "between 256 and 16k, but ", + modulusLength, " was requested."); // Now check the public exponent for allow-listed values. // First see if we can convert the public exponent to an unsigned number. Unfortunately OpenSSL @@ -472,14 +460,15 @@ void Rsa::validateRsaParams(jsg::Lock& js, "Imported RSA key has invalid publicExponent ", v, "."); } } else { - JSG_FAIL_REQUIRE(DOMOperationError, "The \"publicExponent\" must be either 3 or 65537, but " + JSG_FAIL_REQUIRE(DOMOperationError, + "The \"publicExponent\" must be either 3 or 65537, but " "got a number larger than 2^32."); } } bool Rsa::isRSAPrivateKey(kj::ArrayPtr keyData) { KJ_IF_SOME(rem, tryGetAsn1Sequence(keyData)) { - return rem.size() >= 3 && rem[0] == 2 && rem[1] == 1 && !(rem[2] & 0xfe); + return rem.size() >= 3 && rem[0] == 2 && rem[1] == 1 && !(rem[2] & 0xfe); } return false; } @@ -490,14 +479,17 @@ bool Rsa::isRSAPrivateKey(kj::ArrayPtr keyData) { namespace { class RsaBase: public AsymmetricKeyCryptoKeyImpl { public: - explicit RsaBase(AsymmetricKeyData keyData, - CryptoKey::RsaKeyAlgorithm keyAlgorithm, - bool extractable) - : AsymmetricKeyCryptoKeyImpl(kj::mv(keyData), extractable), - keyAlgorithm(kj::mv(keyAlgorithm)) {} - - kj::StringPtr jsgGetMemoryName() const override { return "AsymmetricKey"; } - size_t jsgGetMemorySelfSize() const override { return sizeof(AsymmetricKeyCryptoKeyImpl); } + explicit RsaBase( + AsymmetricKeyData keyData, CryptoKey::RsaKeyAlgorithm keyAlgorithm, bool extractable) + : AsymmetricKeyCryptoKeyImpl(kj::mv(keyData), extractable), + keyAlgorithm(kj::mv(keyAlgorithm)) {} + + kj::StringPtr jsgGetMemoryName() const override { + return "AsymmetricKey"; + } + size_t jsgGetMemorySelfSize() const override { + return sizeof(AsymmetricKeyCryptoKeyImpl); + } void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const override { AsymmetricKeyCryptoKeyImpl::jsgGetMemoryInfo(tracker); tracker.trackField("keyAlgorithm", keyAlgorithm); @@ -514,8 +506,8 @@ private: } kj::Array exportRaw() const override final { - JSG_FAIL_REQUIRE(DOMInvalidAccessError, "Cannot export \"", getAlgorithmName(), - "\" in \"raw\" format."); + JSG_FAIL_REQUIRE( + DOMInvalidAccessError, "Cannot export \"", getAlgorithmName(), "\" in \"raw\" format."); } CryptoKey::AsymmetricKeyDetails getAsymmetricKeyDetail() const override { @@ -527,15 +519,16 @@ private: class RsassaPkcs1V15Key final: public RsaBase { public: - explicit RsassaPkcs1V15Key(AsymmetricKeyData keyData, - CryptoKey::RsaKeyAlgorithm keyAlgorithm, - bool extractable) + explicit RsassaPkcs1V15Key( + AsymmetricKeyData keyData, CryptoKey::RsaKeyAlgorithm keyAlgorithm, bool extractable) : RsaBase(kj::mv(keyData), kj::mv(keyAlgorithm), extractable) {} CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override { return keyAlgorithm.clone(js); } - kj::StringPtr getAlgorithmName() const override { return "RSASSA-PKCS1-v1_5"; } + kj::StringPtr getAlgorithmName() const override { + return "RSASSA-PKCS1-v1_5"; + } kj::StringPtr chooseHash( const kj::Maybe>& callTimeHash) @@ -555,15 +548,16 @@ private: class RsaPssKey final: public RsaBase { public: - explicit RsaPssKey(AsymmetricKeyData keyData, - CryptoKey::RsaKeyAlgorithm keyAlgorithm, - bool extractable) + explicit RsaPssKey( + AsymmetricKeyData keyData, CryptoKey::RsaKeyAlgorithm keyAlgorithm, bool extractable) : RsaBase(kj::mv(keyData), kj::mv(keyAlgorithm), extractable) {} CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override { return keyAlgorithm.clone(js); } - kj::StringPtr getAlgorithmName() const override { return keyAlgorithm.name; } + kj::StringPtr getAlgorithmName() const override { + return keyAlgorithm.name; + } kj::StringPtr chooseHash( const kj::Maybe>& callTimeHash) @@ -590,20 +584,21 @@ private: } }; -class RsaOaepKey final : public RsaBase { +class RsaOaepKey final: public RsaBase { using InitFunction = decltype(EVP_PKEY_encrypt_init); using EncryptDecryptFunction = decltype(EVP_PKEY_encrypt); public: - explicit RsaOaepKey(AsymmetricKeyData keyData, - CryptoKey::RsaKeyAlgorithm keyAlgorithm, - bool extractable) + explicit RsaOaepKey( + AsymmetricKeyData keyData, CryptoKey::RsaKeyAlgorithm keyAlgorithm, bool extractable) : RsaBase(kj::mv(keyData), kj::mv(keyAlgorithm), extractable) {} CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override { return keyAlgorithm.clone(js); } - kj::StringPtr getAlgorithmName() const override { return keyAlgorithm.name; } + kj::StringPtr getAlgorithmName() const override { + return keyAlgorithm.name; + } kj::StringPtr chooseHash( const kj::Maybe>& callTimeHash) @@ -614,27 +609,26 @@ public: "The sign and verify operations are not implemented for \"", keyAlgorithm.name, "\"."); } - kj::Array encrypt( - SubtleCrypto::EncryptAlgorithm&& algorithm, + kj::Array encrypt(SubtleCrypto::EncryptAlgorithm&& algorithm, kj::ArrayPtr plainText) const override { JSG_REQUIRE(getTypeEnum() == KeyType::PUBLIC, DOMInvalidAccessError, "Encryption/key wrapping only works with public keys, not \"", getType(), "\"."); - return commonEncryptDecrypt(kj::mv(algorithm), plainText, EVP_PKEY_encrypt_init, - EVP_PKEY_encrypt); + return commonEncryptDecrypt( + kj::mv(algorithm), plainText, EVP_PKEY_encrypt_init, EVP_PKEY_encrypt); } - kj::Array decrypt( - SubtleCrypto::EncryptAlgorithm&& algorithm, + kj::Array decrypt(SubtleCrypto::EncryptAlgorithm&& algorithm, kj::ArrayPtr cipherText) const override { JSG_REQUIRE(getTypeEnum() == KeyType::PRIVATE, DOMInvalidAccessError, "Decryption/key unwrapping only works with private keys, not \"", getType(), "\"."); - return commonEncryptDecrypt(kj::mv(algorithm), cipherText, EVP_PKEY_decrypt_init, - EVP_PKEY_decrypt); + return commonEncryptDecrypt( + kj::mv(algorithm), cipherText, EVP_PKEY_decrypt_init, EVP_PKEY_decrypt); } private: kj::Array commonEncryptDecrypt(SubtleCrypto::EncryptAlgorithm&& algorithm, - kj::ArrayPtr data, InitFunction init, + kj::ArrayPtr data, + InitFunction init, EncryptDecryptFunction encryptDecrypt) const { auto pkey = getEvpPkey(); auto digest = lookupDigestAlgorithm(KJ_REQUIRE_NONNULL(keyAlgorithm.hash).name).second; @@ -642,7 +636,7 @@ private: JSG_REQUIRE(1 == init(ctx.get()), DOMOperationError, "RSA-OAEP failed to initialize", tryDescribeOpensslErrors()); return KJ_ASSERT_NONNULL(Rsa::tryGetRsa(pkey)) - .cipher(ctx, kj::mv(algorithm), data, encryptDecrypt, digest); + .cipher(ctx, kj::mv(algorithm), data, encryptDecrypt, digest); } kj::String jwkHashAlgorithmName() const override { @@ -658,21 +652,19 @@ private: class RsaRawKey final: public RsaBase { public: - explicit RsaRawKey(AsymmetricKeyData keyData, - CryptoKey::RsaKeyAlgorithm keyAlgorithm, - bool extractable) + explicit RsaRawKey( + AsymmetricKeyData keyData, CryptoKey::RsaKeyAlgorithm keyAlgorithm, bool extractable) : RsaBase(kj::mv(keyData), kj::mv(keyAlgorithm), extractable) {} kj::Array sign( - SubtleCrypto::SignAlgorithm&& algorithm, - kj::ArrayPtr data) const override { + SubtleCrypto::SignAlgorithm&& algorithm, kj::ArrayPtr data) const override { auto rsa = JSG_REQUIRE_NONNULL(Rsa::tryGetRsa(getEvpPkey()), DOMDataError, "Missing RSA key"); return rsa.sign(data); } - bool verify( - SubtleCrypto::SignAlgorithm&& algorithm, - kj::ArrayPtr signature, kj::ArrayPtr data) const override { + bool verify(SubtleCrypto::SignAlgorithm&& algorithm, + kj::ArrayPtr signature, + kj::ArrayPtr data) const override { KJ_UNIMPLEMENTED("RawRsa Verification currently unsupported"); } @@ -680,7 +672,9 @@ public: return keyAlgorithm.clone(js); } - kj::StringPtr getAlgorithmName() const override { return keyAlgorithm.name; } + kj::StringPtr getAlgorithmName() const override { + return keyAlgorithm.name; + } kj::StringPtr chooseHash( const kj::Maybe>& callTimeHash) @@ -698,51 +692,44 @@ private: }; CryptoKeyPair generateRsaPair(jsg::Lock& js, - kj::StringPtr normalizedName, - kj::Own privateEvpPKey, - kj::Own publicEvpPKey, - CryptoKey::RsaKeyAlgorithm&& keyAlgorithm, - bool privateKeyExtractable, - CryptoKeyUsageSet usages) { + kj::StringPtr normalizedName, + kj::Own privateEvpPKey, + kj::Own publicEvpPKey, + CryptoKey::RsaKeyAlgorithm&& keyAlgorithm, + bool privateKeyExtractable, + CryptoKeyUsageSet usages) { auto privateKeyAlgorithm = keyAlgorithm.clone(js); - AsymmetricKeyData publicKeyData { + AsymmetricKeyData publicKeyData{ .evpPkey = kj::mv(publicEvpPKey), .keyType = KeyType::PUBLIC, .usages = usages & CryptoKeyUsageSet::publicKeyMask(), }; - AsymmetricKeyData privateKeyData { + AsymmetricKeyData privateKeyData{ .evpPkey = kj::mv(privateEvpPKey), .keyType = KeyType::PRIVATE, .usages = usages & CryptoKeyUsageSet::privateKeyMask(), }; static constexpr auto createPair = [](kj::Own publicKey, - kj::Own privateKey) { - return CryptoKeyPair { - .publicKey = jsg::alloc(kj::mv(publicKey)), - .privateKey = jsg::alloc(kj::mv(privateKey)) - }; + kj::Own privateKey) { + return CryptoKeyPair{.publicKey = jsg::alloc(kj::mv(publicKey)), + .privateKey = jsg::alloc(kj::mv(privateKey))}; }; if (normalizedName == "RSASSA-PKCS1-v1_5") { - return createPair(kj::heap(kj::mv(publicKeyData), - kj::mv(keyAlgorithm), true), - kj::heap(kj::mv(privateKeyData), - kj::mv(privateKeyAlgorithm), - privateKeyExtractable)); + return createPair( + kj::heap(kj::mv(publicKeyData), kj::mv(keyAlgorithm), true), + kj::heap( + kj::mv(privateKeyData), kj::mv(privateKeyAlgorithm), privateKeyExtractable)); } else if (normalizedName == "RSA-PSS") { - return createPair(kj::heap(kj::mv(publicKeyData), - kj::mv(keyAlgorithm), true), - kj::heap(kj::mv(privateKeyData), - kj::mv(privateKeyAlgorithm), - privateKeyExtractable)); + return createPair(kj::heap(kj::mv(publicKeyData), kj::mv(keyAlgorithm), true), + kj::heap( + kj::mv(privateKeyData), kj::mv(privateKeyAlgorithm), privateKeyExtractable)); } else if (normalizedName == "RSA-OAEP") { - return createPair(kj::heap(kj::mv(publicKeyData), - kj::mv(keyAlgorithm), true), - kj::heap(kj::mv(privateKeyData), - kj::mv(privateKeyAlgorithm), - privateKeyExtractable)); + return createPair(kj::heap(kj::mv(publicKeyData), kj::mv(keyAlgorithm), true), + kj::heap( + kj::mv(privateKeyData), kj::mv(privateKeyAlgorithm), privateKeyExtractable)); } JSG_FAIL_REQUIRE(DOMNotSupportedError, "Unimplemented RSA generation \"", normalizedName, "\"."); } @@ -750,57 +737,51 @@ CryptoKeyPair generateRsaPair(jsg::Lock& js, kj::Own rsaJwkReader(SubtleCrypto::JsonWebKey&& keyDataJwk) { auto rsaKey = OSSL_NEW(RSA); - auto modulus = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.n), - DOMDataError, "Invalid RSA key in JSON Web Key; missing or invalid Modulus " + auto modulus = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.n), DOMDataError, + "Invalid RSA key in JSON Web Key; missing or invalid Modulus " "parameter (\"n\")."); - auto publicExponent = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.e), - DOMDataError, "Invalid RSA key in JSON Web Key; missing or invalid " + auto publicExponent = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.e), DOMDataError, + "Invalid RSA key in JSON Web Key; missing or invalid " "Exponent parameter (\"e\")."); // RSA_set0_*() transfers BIGNUM ownership to the RSA key, so we don't need to worry about // calling BN_free(). - OSSLCALL(RSA_set0_key(rsaKey.get(), - toBignumUnowned(modulus), - toBignumUnowned(publicExponent), - nullptr)); + OSSLCALL(RSA_set0_key( + rsaKey.get(), toBignumUnowned(modulus), toBignumUnowned(publicExponent), nullptr)); if (keyDataJwk.d != kj::none) { // This is a private key. - auto privateExponent = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.d), - DOMDataError, "Invalid RSA key in JSON Web Key; missing or invalid " + auto privateExponent = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.d), DOMDataError, + "Invalid RSA key in JSON Web Key; missing or invalid " "Private Exponent parameter (\"d\")."); OSSLCALL(RSA_set0_key(rsaKey.get(), nullptr, nullptr, toBignumUnowned(privateExponent))); auto presence = (keyDataJwk.p != kj::none) + (keyDataJwk.q != kj::none) + - (keyDataJwk.dp != kj::none) + (keyDataJwk.dq != kj::none) + - (keyDataJwk.qi != kj::none); + (keyDataJwk.dp != kj::none) + (keyDataJwk.dq != kj::none) + (keyDataJwk.qi != kj::none); if (presence == 5) { - auto firstPrimeFactor = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.p), - DOMDataError, "Invalid RSA key in JSON Web Key; invalid First Prime " + auto firstPrimeFactor = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.p), DOMDataError, + "Invalid RSA key in JSON Web Key; invalid First Prime " "Factor parameter (\"p\")."); - auto secondPrimeFactor = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.q), - DOMDataError, "Invalid RSA key in JSON Web Key; invalid Second Prime " + auto secondPrimeFactor = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.q), DOMDataError, + "Invalid RSA key in JSON Web Key; invalid Second Prime " "Factor parameter (\"q\")."); - auto firstFactorCrtExponent = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.dp), - DOMDataError, "Invalid RSA key in JSON Web Key; invalid First Factor " + auto firstFactorCrtExponent = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.dp), DOMDataError, + "Invalid RSA key in JSON Web Key; invalid First Factor " "CRT Exponent parameter (\"dp\")."); - auto secondFactorCrtExponent = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.dq), - DOMDataError, "Invalid RSA key in JSON Web Key; invalid Second Factor " + auto secondFactorCrtExponent = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.dq), DOMDataError, + "Invalid RSA key in JSON Web Key; invalid Second Factor " "CRT Exponent parameter (\"dq\")."); - auto firstCrtCoefficient = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.qi), - DOMDataError, "Invalid RSA key in JSON Web Key; invalid First CRT " + auto firstCrtCoefficient = UNWRAP_JWK_BIGNUM(kj::mv(keyDataJwk.qi), DOMDataError, + "Invalid RSA key in JSON Web Key; invalid First CRT " "Coefficient parameter (\"qi\")."); - OSSLCALL(RSA_set0_factors(rsaKey.get(), - toBignumUnowned(firstPrimeFactor), - toBignumUnowned(secondPrimeFactor))); - OSSLCALL(RSA_set0_crt_params(rsaKey.get(), - toBignumUnowned(firstFactorCrtExponent), - toBignumUnowned(secondFactorCrtExponent), - toBignumUnowned(firstCrtCoefficient))); + OSSLCALL(RSA_set0_factors( + rsaKey.get(), toBignumUnowned(firstPrimeFactor), toBignumUnowned(secondPrimeFactor))); + OSSLCALL(RSA_set0_crt_params(rsaKey.get(), toBignumUnowned(firstFactorCrtExponent), + toBignumUnowned(secondFactorCrtExponent), toBignumUnowned(firstCrtCoefficient))); } else { JSG_REQUIRE(presence == 0, DOMDataError, "Invalid RSA private key in JSON Web Key; if one Prime " @@ -815,32 +796,34 @@ kj::Own rsaJwkReader(SubtleCrypto::JsonWebKey&& keyDataJwk) { } } // namespace -kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateRsa( - jsg::Lock& js, kj::StringPtr normalizedName, - SubtleCrypto::GenerateKeyAlgorithm&& algorithm, bool extractable, +kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateRsa(jsg::Lock& js, + kj::StringPtr normalizedName, + SubtleCrypto::GenerateKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages) { - KJ_ASSERT(normalizedName == "RSASSA-PKCS1-v1_5" || - normalizedName == "RSA-PSS" || - normalizedName == "RSA-OAEP", - "generateRsa called on non-RSA cryptoKey", normalizedName); + KJ_ASSERT(normalizedName == "RSASSA-PKCS1-v1_5" || normalizedName == "RSA-PSS" || + normalizedName == "RSA-OAEP", + "generateRsa called on non-RSA cryptoKey", normalizedName); auto publicExponent = JSG_REQUIRE_NONNULL(kj::mv(algorithm.publicExponent), TypeError, - "Missing field \"publicExponent\" in \"algorithm\"."); - kj::StringPtr hash = api::getAlgorithmName(JSG_REQUIRE_NONNULL(algorithm.hash, TypeError, - "Missing field \"hash\" in \"algorithm\".")); - int modulusLength = JSG_REQUIRE_NONNULL(algorithm.modulusLength, TypeError, - "Missing field \"modulusLength\" in \"algorithm\"."); - JSG_REQUIRE(modulusLength > 0, DOMOperationError, "modulusLength must be greater than zero " - "(requested ", modulusLength, ")."); + "Missing field \"publicExponent\" in \"algorithm\"."); + kj::StringPtr hash = api::getAlgorithmName( + JSG_REQUIRE_NONNULL(algorithm.hash, TypeError, "Missing field \"hash\" in \"algorithm\".")); + int modulusLength = JSG_REQUIRE_NONNULL( + algorithm.modulusLength, TypeError, "Missing field \"modulusLength\" in \"algorithm\"."); + JSG_REQUIRE(modulusLength > 0, DOMOperationError, + "modulusLength must be greater than zero " + "(requested ", + modulusLength, ")."); auto [normalizedHashName, hashEvpMd] = lookupDigestAlgorithm(hash); - CryptoKeyUsageSet validUsages = (normalizedName == "RSA-OAEP") ? - (CryptoKeyUsageSet::encrypt() | CryptoKeyUsageSet::decrypt() | - CryptoKeyUsageSet::wrapKey() | CryptoKeyUsageSet::unwrapKey()) : - (CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); - auto usages = CryptoKeyUsageSet::validate(normalizedName, CryptoKeyUsageSet::Context::generate, - keyUsages, validUsages); + CryptoKeyUsageSet validUsages = (normalizedName == "RSA-OAEP") + ? (CryptoKeyUsageSet::encrypt() | CryptoKeyUsageSet::decrypt() | + CryptoKeyUsageSet::wrapKey() | CryptoKeyUsageSet::unwrapKey()) + : (CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); + auto usages = CryptoKeyUsageSet::validate( + normalizedName, CryptoKeyUsageSet::Context::generate, keyUsages, validUsages); Rsa::validateRsaParams(js, modulusLength, publicExponent.asPtr()); // boringssl silently uses (modulusLength & ~127) for the key size, i.e. it rounds down to the @@ -850,11 +833,10 @@ kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateRsa( // is disabled and the key size is rounded down, but since it is not currently used this is // acceptable. JSG_REQUIRE(!(FeatureFlags::get(js).getStrictCrypto() && (modulusLength & 127)), - DOMOperationError, - "Can't generate key: RSA key size is required to be a multiple of 128"); + DOMOperationError, "Can't generate key: RSA key size is required to be a multiple of 128"); - auto bnExponent = JSG_REQUIRE_NONNULL(toBignum(publicExponent), InternalDOMOperationError, - "Error setting up RSA keygen."); + auto bnExponent = JSG_REQUIRE_NONNULL( + toBignum(publicExponent), InternalDOMOperationError, "Error setting up RSA keygen."); auto rsaPrivateKey = OSSL_NEW(RSA); OSSLCALL(RSA_generate_key_ex(rsaPrivateKey, modulusLength, bnExponent.get(), 0)); @@ -865,39 +847,41 @@ kj::OneOf, CryptoKeyPair> CryptoKey::Impl::generateRsa( auto publicEvpPKey = OSSL_NEW(EVP_PKEY); OSSLCALL(EVP_PKEY_set1_RSA(publicEvpPKey.get(), rsaPublicKey)); - auto keyAlgorithm = CryptoKey::RsaKeyAlgorithm { - .name = normalizedName, + auto keyAlgorithm = CryptoKey::RsaKeyAlgorithm{.name = normalizedName, .modulusLength = static_cast(modulusLength), .publicExponent = kj::mv(publicExponent), - .hash = KeyAlgorithm { normalizedHashName } - }; + .hash = KeyAlgorithm{normalizedHashName}}; return generateRsaPair(js, normalizedName, kj::mv(privateEvpPKey), kj::mv(publicEvpPKey), kj::mv(keyAlgorithm), extractable, usages); } -kj::Own CryptoKey::Impl::importRsa( - jsg::Lock& js, kj::StringPtr normalizedName, kj::StringPtr format, +kj::Own CryptoKey::Impl::importRsa(jsg::Lock& js, + kj::StringPtr normalizedName, + kj::StringPtr format, SubtleCrypto::ImportKeyData keyData, - SubtleCrypto::ImportKeyAlgorithm&& algorithm, bool extractable, + SubtleCrypto::ImportKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages) { - kj::StringPtr hash = api::getAlgorithmName(JSG_REQUIRE_NONNULL(algorithm.hash, TypeError, - "Missing field \"hash\" in \"algorithm\".")); + kj::StringPtr hash = api::getAlgorithmName( + JSG_REQUIRE_NONNULL(algorithm.hash, TypeError, "Missing field \"hash\" in \"algorithm\".")); - CryptoKeyUsageSet allowedUsages = (normalizedName == "RSA-OAEP") ? - (CryptoKeyUsageSet::encrypt() | CryptoKeyUsageSet::decrypt() | - CryptoKeyUsageSet::wrapKey() | CryptoKeyUsageSet::unwrapKey()) : - (CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); + CryptoKeyUsageSet allowedUsages = (normalizedName == "RSA-OAEP") + ? (CryptoKeyUsageSet::encrypt() | CryptoKeyUsageSet::decrypt() | + CryptoKeyUsageSet::wrapKey() | CryptoKeyUsageSet::unwrapKey()) + : (CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()); auto [normalizedHashName, hashEvpMd] = lookupDigestAlgorithm(hash); - auto importedKey = importAsymmetricForWebCrypto( - js, kj::mv(format), kj::mv(keyData), normalizedName, extractable, keyUsages, + auto importedKey = importAsymmetricForWebCrypto(js, kj::mv(format), kj::mv(keyData), + normalizedName, extractable, keyUsages, // Verbose lambda capture needed because: https://bugs.llvm.org/show_bug.cgi?id=35984 - [hashEvpMd = hashEvpMd, &algorithm](SubtleCrypto::JsonWebKey keyDataJwk) -> kj::Own { + [hashEvpMd = hashEvpMd, &algorithm]( + SubtleCrypto::JsonWebKey keyDataJwk) -> kj::Own { JSG_REQUIRE(keyDataJwk.kty == "RSA", DOMDataError, "RSASSA-PKCS1-v1_5 \"jwk\" key import requires a JSON Web Key with Key Type parameter " - "\"kty\" (\"", keyDataJwk.kty, "\") equal to \"RSA\"."); + "\"kty\" (\"", + keyDataJwk.kty, "\") equal to \"RSA\"."); KJ_IF_SOME(alg, keyDataJwk.alg) { // If this JWK specifies an algorithm, make sure it jives with the hash we were passed via @@ -928,22 +912,26 @@ kj::Own CryptoKey::Impl::importRsa( } else if (algorithm.name == "RSA-OAEP") { return rsaOaepAlgorithms; } else { - JSG_FAIL_REQUIRE(DOMNotSupportedError, "Unrecognized RSA variant \"", algorithm.name, - "\"."); + JSG_FAIL_REQUIRE( + DOMNotSupportedError, "Unrecognized RSA variant \"", algorithm.name, "\"."); } }(); auto jwkHash = validAlgorithms.find(alg); JSG_REQUIRE(jwkHash != rsaPssAlgorithms.end(), DOMNotSupportedError, - "Unrecognized or unimplemented algorithm \"", alg, "\" listed in JSON Web Key Algorithm " + "Unrecognized or unimplemented algorithm \"", alg, + "\" listed in JSON Web Key Algorithm " "parameter."); JSG_REQUIRE(jwkHash->second == hashEvpMd, DOMDataError, - "JSON Web Key Algorithm parameter \"alg\" (\"", alg, "\") does not match requested hash " - "algorithm \"", jwkHash->first, "\"."); + "JSON Web Key Algorithm parameter \"alg\" (\"", alg, + "\") does not match requested hash " + "algorithm \"", + jwkHash->first, "\"."); } return rsaJwkReader(kj::mv(keyDataJwk)); - }, allowedUsages); + }, + allowedUsages); // get0 avoids adding a refcount... auto rsa = JSG_REQUIRE_NONNULL(Rsa::tryGetRsa(importedKey.evpPkey.get()), DOMDataError, @@ -959,15 +947,12 @@ kj::Own CryptoKey::Impl::importRsa( // Validate modulus and exponent, reject imported RSA keys that may be unsafe. Rsa::validateRsaParams(js, modulusLength, publicExponent, true); - auto keyAlgorithm = CryptoKey::RsaKeyAlgorithm { - .name = normalizedName, + auto keyAlgorithm = CryptoKey::RsaKeyAlgorithm{.name = normalizedName, .modulusLength = static_cast(modulusLength), .publicExponent = kj::mv(publicExponent), - .hash = KeyAlgorithm { normalizedHashName } - }; + .hash = KeyAlgorithm{normalizedHashName}}; if (normalizedName == "RSASSA-PKCS1-v1_5") { - return kj::heap( - kj::mv(importedKey), kj::mv(keyAlgorithm), extractable); + return kj::heap(kj::mv(importedKey), kj::mv(keyAlgorithm), extractable); } else if (normalizedName == "RSA-PSS") { return kj::heap(kj::mv(importedKey), kj::mv(keyAlgorithm), extractable); } else if (normalizedName == "RSA-OAEP") { @@ -977,21 +962,24 @@ kj::Own CryptoKey::Impl::importRsa( } } -kj::Own CryptoKey::Impl::importRsaRaw( - jsg::Lock& js, kj::StringPtr normalizedName, kj::StringPtr format, +kj::Own CryptoKey::Impl::importRsaRaw(jsg::Lock& js, + kj::StringPtr normalizedName, + kj::StringPtr format, SubtleCrypto::ImportKeyData keyData, - SubtleCrypto::ImportKeyAlgorithm&& algorithm, bool extractable, + SubtleCrypto::ImportKeyAlgorithm&& algorithm, + bool extractable, kj::ArrayPtr keyUsages) { // Note that in this context raw refers to the RSA-RAW algorithm, not to keys represented by raw // data. Importing raw keys is currently not supported for this algorithm. CryptoKeyUsageSet allowedUsages = CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify(); - auto importedKey = importAsymmetricForWebCrypto( - js, kj::mv(format), kj::mv(keyData), normalizedName, extractable, keyUsages, + auto importedKey = importAsymmetricForWebCrypto(js, kj::mv(format), kj::mv(keyData), + normalizedName, extractable, keyUsages, // Verbose lambda capture needed because: https://bugs.llvm.org/show_bug.cgi?id=35984 [](SubtleCrypto::JsonWebKey keyDataJwk) -> kj::Own { JSG_REQUIRE(keyDataJwk.kty == "RSA", DOMDataError, "RSA-RAW \"jwk\" key import requires a JSON Web Key with Key Type parameter " - "\"kty\" (\"", keyDataJwk.kty, "\") equal to \"RSA\"."); + "\"kty\" (\"", + keyDataJwk.kty, "\") equal to \"RSA\"."); KJ_IF_SOME(alg, keyDataJwk.alg) { // If this JWK specifies an algorithm, make sure it jives with the hash we were passed via @@ -1011,8 +999,8 @@ kj::Own CryptoKey::Impl::importRsaRaw( }, allowedUsages); JSG_REQUIRE(importedKey.keyType == KeyType::PRIVATE, DOMDataError, - "RSA-RAW only supports private keys but requested \"", - toStringPtr(importedKey.keyType), "\"."); + "RSA-RAW only supports private keys but requested \"", toStringPtr(importedKey.keyType), + "\"."); // get0 avoids adding a refcount... auto rsa = JSG_REQUIRE_NONNULL(Rsa::tryGetRsa(importedKey.evpPkey.get()), DOMDataError, @@ -1024,21 +1012,19 @@ kj::Own CryptoKey::Impl::importRsaRaw( // Validate modulus and exponent, reject imported RSA keys that may be unsafe. Rsa::validateRsaParams(js, modulusLength, publicExponent, true); - auto keyAlgorithm = CryptoKey::RsaKeyAlgorithm { - .name = "RSA-RAW"_kj, + auto keyAlgorithm = CryptoKey::RsaKeyAlgorithm{.name = "RSA-RAW"_kj, .modulusLength = static_cast(modulusLength), - .publicExponent = kj::mv(publicExponent) - }; + .publicExponent = kj::mv(publicExponent)}; return kj::heap(kj::mv(importedKey), kj::mv(keyAlgorithm), extractable); } kj::Own fromRsaKey(kj::Own key) { - return kj::heap(AsymmetricKeyData { - .evpPkey = kj::mv(key), - .keyType = KeyType::PUBLIC, - .usages = CryptoKeyUsageSet::decrypt() | CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify() - }, CryptoKey::RsaKeyAlgorithm {.name = "RSA"_kj }, true); + return kj::heap(AsymmetricKeyData{.evpPkey = kj::mv(key), + .keyType = KeyType::PUBLIC, + .usages = CryptoKeyUsageSet::decrypt() | + CryptoKeyUsageSet::sign() | CryptoKeyUsageSet::verify()}, + CryptoKey::RsaKeyAlgorithm{.name = "RSA"_kj}, true); } } // namespace workerd::api diff --git a/src/workerd/api/crypto/rsa.h b/src/workerd/api/crypto/rsa.h index 2cfe583aa05..b8c8470ff02 100644 --- a/src/workerd/api/crypto/rsa.h +++ b/src/workerd/api/crypto/rsa.h @@ -16,9 +16,15 @@ class Rsa final { size_t getModulusBits() const; size_t getModulusSize() const; - inline const BIGNUM* getN() const { return n; } - inline const BIGNUM* getE() const { return e; } - inline const BIGNUM* getD() const { return d; } + inline const BIGNUM* getN() const { + return n; + } + inline const BIGNUM* getE() const { + return e; + } + inline const BIGNUM* getD() const { + return d; + } kj::Array getPublicExponent() KJ_WARN_UNUSED_RESULT; @@ -27,12 +33,10 @@ class Rsa final { kj::Array sign(const kj::ArrayPtr data) const KJ_WARN_UNUSED_RESULT; static kj::Maybe fromJwk( - KeyType keyType, - const SubtleCrypto::JsonWebKey& jwk) KJ_WARN_UNUSED_RESULT; + KeyType keyType, const SubtleCrypto::JsonWebKey& jwk) KJ_WARN_UNUSED_RESULT; - SubtleCrypto::JsonWebKey toJwk(KeyType keytype, - kj::Maybe maybeHashAlgorithm) const - KJ_WARN_UNUSED_RESULT; + SubtleCrypto::JsonWebKey toJwk( + KeyType keytype, kj::Maybe maybeHashAlgorithm) const KJ_WARN_UNUSED_RESULT; struct CipherOptions { const EVP_CIPHER* cipher; @@ -40,29 +44,28 @@ class Rsa final { }; kj::String toPem(KeyEncoding encoding, - KeyType keyType, - kj::Maybe options = kj::none) const KJ_WARN_UNUSED_RESULT; + KeyType keyType, + kj::Maybe options = kj::none) const KJ_WARN_UNUSED_RESULT; kj::Array toDer(KeyEncoding encoding, - KeyType keyType, - kj::Maybe options = kj::none) const - KJ_WARN_UNUSED_RESULT; + KeyType keyType, + kj::Maybe options = kj::none) const KJ_WARN_UNUSED_RESULT; using EncryptDecryptFunction = decltype(EVP_PKEY_encrypt); kj::Array cipher(EVP_PKEY_CTX* ctx, - SubtleCrypto::EncryptAlgorithm&& algorithm, - kj::ArrayPtr data, - EncryptDecryptFunction encryptDecrypt, - const EVP_MD* cipher) const KJ_WARN_UNUSED_RESULT; + SubtleCrypto::EncryptAlgorithm&& algorithm, + kj::ArrayPtr data, + EncryptDecryptFunction encryptDecrypt, + const EVP_MD* cipher) const KJ_WARN_UNUSED_RESULT; // The W3C standard itself doesn't describe any parameter validation but the conformance tests // do test "bad" exponents, likely because everyone uses OpenSSL that suffers from poor behavior // with these bad exponents (e.g. if an exponent < 3 or 65535 generates an infinite loop, a // library might be expected to handle such cases on its own, no?). static void validateRsaParams(jsg::Lock& js, - size_t modulusLength, - kj::ArrayPtr publicExponent, - bool isImport = false); + size_t modulusLength, + kj::ArrayPtr publicExponent, + bool isImport = false); static bool isRSAPrivateKey(kj::ArrayPtr keyData) KJ_WARN_UNUSED_RESULT; diff --git a/src/workerd/api/crypto/scrypt.c++ b/src/workerd/api/crypto/scrypt.c++ index 41dc7f02dbe..6339797fb4c 100644 --- a/src/workerd/api/crypto/scrypt.c++ +++ b/src/workerd/api/crypto/scrypt.c++ @@ -9,21 +9,16 @@ namespace workerd::api { kj::Maybe> scrypt(size_t length, - uint32_t N, - uint32_t r, - uint32_t p, - uint32_t maxmem, - kj::ArrayPtr pass, - kj::ArrayPtr salt) { + uint32_t N, + uint32_t r, + uint32_t p, + uint32_t maxmem, + kj::ArrayPtr pass, + kj::ArrayPtr salt) { ClearErrorOnReturn clearErrorOnReturn; auto buf = kj::heapArray(length); - if (!EVP_PBE_scrypt(pass.asChars().begin(), - pass.size(), - salt.begin(), - salt.size(), - N, r, p, maxmem, - buf.begin(), - length)) { + if (!EVP_PBE_scrypt(pass.asChars().begin(), pass.size(), salt.begin(), salt.size(), N, r, p, + maxmem, buf.begin(), length)) { // This does not currently handle the errors in exactly the same way as // the Node.js implementation but that's probably ok? We can update the // error thrown to match Node.js more closely later if necessary. There diff --git a/src/workerd/api/crypto/spkac.c++ b/src/workerd/api/crypto/spkac.c++ index 7ca8c47c936..346a0e3214d 100644 --- a/src/workerd/api/crypto/spkac.c++ +++ b/src/workerd/api/crypto/spkac.c++ @@ -97,10 +97,8 @@ kj::Maybe> exportChallenge(kj::ArrayPtr inpu int buf_size = ASN1_STRING_to_UTF8(&buf, spki->spkac->challenge); if (buf_size < 0 || buf == nullptr) return kj::none; // Pay attention to how the buffer is freed below... - return kj::arrayPtr(buf, buf_size).attach(kj::defer([buf]() { - OPENSSL_free(buf); - })); + return kj::arrayPtr(buf, buf_size).attach(kj::defer([buf]() { OPENSSL_free(buf); })); } return kj::none; } -} +} // namespace workerd::api diff --git a/src/workerd/api/crypto/spkac.h b/src/workerd/api/crypto/spkac.h index 925870c56ab..b415595d6e9 100644 --- a/src/workerd/api/crypto/spkac.h +++ b/src/workerd/api/crypto/spkac.h @@ -10,4 +10,4 @@ kj::Maybe> exportPublicKey(kj::ArrayPtr inpu kj::Maybe> exportChallenge(kj::ArrayPtr input); -} +} // namespace workerd::api diff --git a/src/workerd/api/crypto/x509.c++ b/src/workerd/api/crypto/x509.c++ index bb1bb1c8083..97c33ea6b2d 100644 --- a/src/workerd/api/crypto/x509.c++ +++ b/src/workerd/api/crypto/x509.c++ @@ -10,17 +10,11 @@ namespace workerd::api { namespace { -static constexpr int kX509NameFlagsMultiline = - ASN1_STRFLGS_ESC_2253 | - ASN1_STRFLGS_ESC_CTRL | - ASN1_STRFLGS_UTF8_CONVERT | - XN_FLAG_SEP_MULTILINE | - XN_FLAG_FN_SN; +static constexpr int kX509NameFlagsMultiline = ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_CTRL | + ASN1_STRFLGS_UTF8_CONVERT | XN_FLAG_SEP_MULTILINE | XN_FLAG_FN_SN; static constexpr int kX509NameFlagsRFC2253WithinUtf8JSON = - XN_FLAG_RFC2253 & - ~ASN1_STRFLGS_ESC_MSB & - ~ASN1_STRFLGS_ESC_CTRL; + XN_FLAG_RFC2253 & ~ASN1_STRFLGS_ESC_MSB & ~ASN1_STRFLGS_ESC_CTRL; kj::Maybe> newBio() { auto ptr = BIO_new(BIO_s_mem()); @@ -55,43 +49,41 @@ bool isSafeAltName(const char* name, size_t length, bool utf8) { for (size_t i = 0; i < length; i++) { char c = name[i]; switch (c) { - case '"': - case '\\': - // These mess with encoding rules. - // Fall through. - case ',': - // Commas make it impossible to split the list of subject alternative - // names unambiguously, which is why we have to escape. - // Fall through. - case '\'': - // Single quotes are unlikely to appear in any legitimate values, but they - // could be used to make a value look like it was escaped (i.e., enclosed - // in single/double quotes). - return false; - default: - if (utf8) { - // In UTF8 strings, we require escaping for any ASCII control character, - // but NOT for non-ASCII characters. Note that all bytes of any code - // point that consists of more than a single byte have their MSB set. - if (static_cast(c) < ' ' || c == '\x7f') { - return false; - } - } else { - // Check if the char is a control character or non-ASCII character. Note - // that char may or may not be a signed type. Regardless, non-ASCII - // values will always be outside of this range. - if (c < ' ' || c > '~') { - return false; + case '"': + case '\\': + // These mess with encoding rules. + // Fall through. + case ',': + // Commas make it impossible to split the list of subject alternative + // names unambiguously, which is why we have to escape. + // Fall through. + case '\'': + // Single quotes are unlikely to appear in any legitimate values, but they + // could be used to make a value look like it was escaped (i.e., enclosed + // in single/double quotes). + return false; + default: + if (utf8) { + // In UTF8 strings, we require escaping for any ASCII control character, + // but NOT for non-ASCII characters. Note that all bytes of any code + // point that consists of more than a single byte have their MSB set. + if (static_cast(c) < ' ' || c == '\x7f') { + return false; + } + } else { + // Check if the char is a control character or non-ASCII character. Note + // that char may or may not be a signed type. Regardless, non-ASCII + // values will always be outside of this range. + if (c < ' ' || c > '~') { + return false; + } } - } } } return true; } -void printAltName(BIO* out, const char* name, - size_t length, bool utf8, - const char* safe_prefix) { +void printAltName(BIO* out, const char* name, size_t length, bool utf8, const char* safe_prefix) { if (isSafeAltName(name, length, utf8)) { // For backward-compatibility, append "safe" names without any // modifications. @@ -125,7 +117,7 @@ void printAltName(BIO* out, const char* name, // Control character or non-ASCII character. We treat everything as // Latin-1, which corresponds to the first 255 Unicode code points. const char hex[] = "0123456789abcdef"; - char u[] = { '\\', 'u', '0', '0', hex[(c & 0xf0) >> 4], hex[c & 0x0f] }; + char u[] = {'\\', 'u', '0', '0', hex[(c & 0xf0) >> 4], hex[c & 0x0f]}; BIO_write(out, u, sizeof(u)); } } @@ -133,18 +125,12 @@ void printAltName(BIO* out, const char* name, } } -void printLatin1AltName(BIO* out, - const ASN1_IA5STRING* name, - const char* safe_prefix = nullptr) { - printAltName(out, reinterpret_cast(name->data), name->length, - false, safe_prefix); +void printLatin1AltName(BIO* out, const ASN1_IA5STRING* name, const char* safe_prefix = nullptr) { + printAltName(out, reinterpret_cast(name->data), name->length, false, safe_prefix); } -void printUtf8AltName(BIO* out, - const ASN1_UTF8STRING* name, - const char* safe_prefix = nullptr) { - printAltName(out, reinterpret_cast(name->data), name->length, - true, safe_prefix); +void printUtf8AltName(BIO* out, const ASN1_UTF8STRING* name, const char* safe_prefix = nullptr) { + printAltName(out, reinterpret_cast(name->data), name->length, true, safe_prefix); } bool printGeneralName(BIO* out, const GENERAL_NAME* gen) { @@ -182,16 +168,15 @@ bool printGeneralName(BIO* out, const GENERAL_NAME* gen) { // PrintAltName handles all of that safely. BIO_printf(out, "DirName:"); auto tmp = KJ_ASSERT_NONNULL(newBio()); - if (X509_NAME_print_ex(tmp.get(), - gen->d.dirn, - 0, - kX509NameFlagsRFC2253WithinUtf8JSON) < 0) { + if (X509_NAME_print_ex(tmp.get(), gen->d.dirn, 0, kX509NameFlagsRFC2253WithinUtf8JSON) < 0) { return false; } char* oline = nullptr; long n_bytes = BIO_get_mem_data(tmp.get(), &oline); // NOLINT(runtime/int) KJ_REQUIRE(n_bytes >= 0); - if (n_bytes > 0) { KJ_REQUIRE(oline != nullptr); } + if (n_bytes > 0) { + KJ_REQUIRE(oline != nullptr); + } printAltName(out, oline, static_cast(n_bytes), true, nullptr); } else if (gen->type == GEN_IPADD) { @@ -245,18 +230,15 @@ bool printGeneralName(BIO* out, const GENERAL_NAME* gen) { } #endif // OPENSSL_VERSION_MAJOR >= 3 int val_type = gen->d.otherName->value->type; - if (prefix == nullptr || - (unicode && val_type != V_ASN1_UTF8STRING) || + if (prefix == nullptr || (unicode && val_type != V_ASN1_UTF8STRING) || (!unicode && val_type != V_ASN1_IA5STRING)) { BIO_printf(out, "othername:"); } else { BIO_printf(out, "othername:"); if (unicode) { - printUtf8AltName(out, gen->d.otherName->value->value.utf8string, - prefix); + printUtf8AltName(out, gen->d.otherName->value->value.utf8string, prefix); } else { - printLatin1AltName(out, gen->d.otherName->value->value.ia5string, - prefix); + printLatin1AltName(out, gen->d.otherName->value->value.ia5string, prefix); } } } else if (gen->type == GEN_X400) { @@ -278,16 +260,14 @@ bool safeX509SubjectAltNamePrint(BIO* out, X509_EXTENSION* ext) { KJ_REQUIRE(OBJ_obj2nid(X509_EXTENSION_get_object(ext)) == NID_subject_alt_name); GENERAL_NAMES* names = static_cast(X509V3_EXT_d2i(ext)); - if (names == nullptr) - return false; + if (names == nullptr) return false; bool ok = true; for (int i = 0; i < sk_GENERAL_NAME_num(names); i++) { GENERAL_NAME* gen = sk_GENERAL_NAME_value(names, i); - if (i != 0) - BIO_write(out, ", ", 2); + if (i != 0) BIO_write(out, ", ", 2); if (!(ok = printGeneralName(out, gen))) { break; @@ -301,18 +281,15 @@ bool safeX509SubjectAltNamePrint(BIO* out, X509_EXTENSION* ext) { bool safeX509InfoAccessPrint(BIO* out, X509_EXTENSION* ext) { KJ_REQUIRE(OBJ_obj2nid(X509_EXTENSION_get_object(ext)) == NID_info_access); - AUTHORITY_INFO_ACCESS* descs = - static_cast(X509V3_EXT_d2i(ext)); - if (descs == nullptr) - return false; + AUTHORITY_INFO_ACCESS* descs = static_cast(X509V3_EXT_d2i(ext)); + if (descs == nullptr) return false; bool ok = true; for (int i = 0; i < sk_ACCESS_DESCRIPTION_num(descs); i++) { ACCESS_DESCRIPTION* desc = sk_ACCESS_DESCRIPTION_value(descs, i); - if (i != 0) - BIO_write(out, "\n", 1); + if (i != 0) BIO_write(out, "\n", 1); char objtmp[80] = {0}; i2t_ASN1_OBJECT(objtmp, sizeof(objtmp), desc->method); @@ -331,16 +308,14 @@ bool safeX509InfoAccessPrint(BIO* out, X509_EXTENSION* ext) { } void addFingerprintDigest( - const unsigned char* md, - unsigned int md_size, - char fingerprint[3 * EVP_MAX_MD_SIZE]) { + const unsigned char* md, unsigned int md_size, char fingerprint[3 * EVP_MAX_MD_SIZE]) { unsigned int i; const char hex[] = "0123456789ABCDEF"; for (i = 0; i < md_size; i++) { - fingerprint[3*i] = hex[(md[i] & 0xf0) >> 4]; - fingerprint[(3*i)+1] = hex[(md[i] & 0x0f)]; - fingerprint[(3*i)+2] = ':'; + fingerprint[3 * i] = hex[(md[i] & 0xf0) >> 4]; + fingerprint[(3 * i) + 1] = hex[(md[i] & 0x0f)]; + fingerprint[(3 * i) + 2] = ':'; } fingerprint[(3 * (md_size - 1)) + 2] = '\0'; } @@ -417,20 +392,16 @@ kj::Array getRsaPubKey(RSA* rsa) { } kj::Maybe getECGroupBits(const EC_GROUP* group) { - if (group == nullptr) - return kj::none; + if (group == nullptr) return kj::none; int32_t bits = EC_GROUP_order_bits(group); - if (bits <= 0) - return kj::none; + if (bits <= 0) return kj::none; return bits; } - -kj::Maybe> eCPointToBuffer(const EC_GROUP* group, - const EC_POINT* point, - point_conversion_form_t form) { +kj::Maybe> eCPointToBuffer( + const EC_GROUP* group, const EC_POINT* point, point_conversion_form_t form) { size_t len = EC_POINT_point2oct(group, point, form, nullptr, 0, nullptr); if (len == 0) { return kj::none; @@ -438,12 +409,7 @@ kj::Maybe> eCPointToBuffer(const EC_GROUP* group, auto buffer = kj::heapArray(len); - len = EC_POINT_point2oct(group, - point, - form, - buffer.begin(), - buffer.size(), - nullptr); + len = EC_POINT_point2oct(group, point, form, buffer.begin(), buffer.size(), nullptr); if (len == 0) { return kj::none; } @@ -462,8 +428,7 @@ kj::Maybe getCurveName(const int nid) { kj::Maybe> getECPubKey(const EC_GROUP* group, EC_KEY* ec) { const EC_POINT* pubkey = EC_KEY_get0_public_key(ec); - if (pubkey == nullptr) - return kj::none; + if (pubkey == nullptr) return kj::none; return eCPointToBuffer(group, pubkey, EC_KEY_get_conv_form(ec)); } @@ -563,8 +528,8 @@ kj::Maybe> X509Certificate::parse(kj::Array X509Certificate::getSubject() { ClearErrorOnReturn clearErrorOnReturn; KJ_IF_SOME(bio, newBio()) { - if (X509_NAME_print_ex(bio.get(), X509_get_subject_name(cert_.get()), 0, - kX509NameFlagsMultiline) > 0) { + if (X509_NAME_print_ex( + bio.get(), X509_get_subject_name(cert_.get()), 0, kX509NameFlagsMultiline) > 0) { return toString(bio.get()); } } @@ -610,8 +575,8 @@ kj::Maybe X509Certificate::getInfoAccess() { kj::Maybe X509Certificate::getIssuer() { ClearErrorOnReturn clearErrorOnReturn; KJ_IF_SOME(bio, newBio()) { - if (X509_NAME_print_ex(bio.get(), X509_get_issuer_name(cert_.get()), 0, - kX509NameFlagsMultiline) > 0) { + if (X509_NAME_print_ex( + bio.get(), X509_get_issuer_name(cert_.get()), 0, kX509NameFlagsMultiline) > 0) { return toString(bio.get()); } } @@ -620,8 +585,7 @@ kj::Maybe X509Certificate::getIssuer() { kj::Maybe> X509Certificate::getIssuerCert() { ClearErrorOnReturn clearErrorOnReturn; - return issuerCert_.map([](jsg::Ref& cert) mutable - -> jsg::Ref { + return issuerCert_.map([](jsg::Ref& cert) mutable -> jsg::Ref { return cert.addRef(); }); } @@ -656,9 +620,7 @@ kj::Maybe> X509Certificate::getKeyUsage() { int j = 0; for (int i = 0; i < count; i++) { - if (OBJ_obj2txt(buf, - sizeof(buf), - sk_ASN1_OBJECT_value(eku.get(), i), 1) >= 0) { + if (OBJ_obj2txt(buf, sizeof(buf), sk_ASN1_OBJECT_value(eku.get(), i), 1) >= 0) { ext_key_usage[j++] = kj::str(buf); } } @@ -674,9 +636,7 @@ kj::Maybe> X509Certificate::getSerialNumber() { KJ_DEFER(BN_clear_free(bn)); char* data = BN_bn2hex(bn); return kj::arrayPtr(data, strlen(data)) - .attach(kj::defer([data,len=strlen(data)]{ - OPENSSL_clear_free(data, len); - })); + .attach(kj::defer([data, len = strlen(data)] { OPENSSL_clear_free(data, len); })); } } @@ -730,26 +690,22 @@ bool X509Certificate::getIsCA() { return X509_check_ca(cert_.get()) == 1; } -kj::Maybe X509Certificate::checkHost(kj::String name, - jsg::Optional options) { +kj::Maybe X509Certificate::checkHost( + kj::String name, jsg::Optional options) { ClearErrorOnReturn clearErrorOnReturn; char* peername = nullptr; - switch (X509_check_host( - cert_.get(), - name.begin(), - name.size(), - optionsToFlags(options), - &peername)) { - case 1: { // Match! + switch ( + X509_check_host(cert_.get(), name.begin(), name.size(), optionsToFlags(options), &peername)) { + case 1: { // Match! if (peername != nullptr) { KJ_DEFER(OPENSSL_free(peername)); return kj::str(peername); } return kj::mv(name); } - case 0: // No Match! + case 0: // No Match! return kj::none; // No return value is set - case -2: // Error! + case -2: // Error! JSG_FAIL_REQUIRE(Error, "Invalid name"); default: // Error! JSG_FAIL_REQUIRE(Error, "Operation failed"); @@ -758,19 +714,15 @@ kj::Maybe X509Certificate::checkHost(kj::String name, KJ_UNREACHABLE; } -kj::Maybe X509Certificate::checkEmail(kj::String email, - jsg::Optional options) { +kj::Maybe X509Certificate::checkEmail( + kj::String email, jsg::Optional options) { ClearErrorOnReturn clearErrorOnReturn; - switch (X509_check_email( - cert_.get(), - email.begin(), - email.size(), - optionsToFlags(options))) { + switch (X509_check_email(cert_.get(), email.begin(), email.size(), optionsToFlags(options))) { case 1: // Match! return kj::mv(email); - case 0: // No Match! + case 0: // No Match! return kj::none; // No return value is set - case -2: // Error! + case -2: // Error! JSG_FAIL_REQUIRE(Error, "Invalid name"); default: // Error! JSG_FAIL_REQUIRE(Error, "Operation failed"); @@ -784,9 +736,9 @@ kj::Maybe X509Certificate::checkIp(kj::String ip, jsg::Optional(nid)) { - obj.set(js,"asn1Curve", js.str(name)); - } - KJ_IF_SOME(name, getCurveName(nid)) { - obj.set(js,"nistCurve", js.str(name)); - } - } else { - // Unnamed curves can be described by their mathematical properties, - // but aren't used much (at all?) with X.509/TLS. Support later if needed. - } + const int nid = EC_GROUP_get_curve_name(group); + if (nid != 0) { + // Curve is well-known, get its OID and NIST nick-name (if it has one). + + KJ_IF_SOME(name, getCurveName(nid)) { + obj.set(js, "asn1Curve", js.str(name)); + } + KJ_IF_SOME(name, getCurveName(nid)) { + obj.set(js, "nistCurve", js.str(name)); + } + } else { + // Unnamed curves can be described by their mathematical properties, + // but aren't used much (at all?) with X.509/TLS. Support later if needed. + } break; } } @@ -883,9 +835,7 @@ jsg::JsObject X509Certificate::toLegacyObject(jsg::Lock& js) { obj.set(js, "fingerprint512", js.str(fingerprint512)); } KJ_IF_SOME(keyUsage, getKeyUsage()) { - auto values = KJ_MAP(str, keyUsage) { - return jsg::JsValue(js.str(str)); - }; + auto values = KJ_MAP(str, keyUsage) { return jsg::JsValue(js.str(str)); }; obj.set(js, "ext_key_usage", js.arr(values)); } KJ_IF_SOME(serialNumber, getSerialNumber()) { diff --git a/src/workerd/api/crypto/x509.h b/src/workerd/api/crypto/x509.h index 47d8690ec3d..60f057ab82f 100644 --- a/src/workerd/api/crypto/x509.h +++ b/src/workerd/api/crypto/x509.h @@ -88,6 +88,4 @@ class X509Certificate: public jsg::Object { KJ_DECLARE_NON_POLYMORPHIC(X509); -#define EW_CRYPTO_X509_ISOLATE_TYPES \ - api::X509Certificate, \ - api::X509Certificate::CheckOptions +#define EW_CRYPTO_X509_ISOLATE_TYPES api::X509Certificate, api::X509Certificate::CheckOptions diff --git a/src/workerd/api/data-url-test.c++ b/src/workerd/api/data-url-test.c++ index f04c216862b..4fa894f7f29 100644 --- a/src/workerd/api/data-url-test.c++ +++ b/src/workerd/api/data-url-test.c++ @@ -6,8 +6,8 @@ namespace workerd::api { namespace { KJ_TEST("DataUrl Basics") { - auto dataUrl = KJ_ASSERT_NONNULL( - DataUrl::tryParse("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=="_kj)); + auto dataUrl = + KJ_ASSERT_NONNULL(DataUrl::tryParse("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=="_kj)); KJ_ASSERT(dataUrl.getMimeType() == MimeType::PLAINTEXT); KJ_ASSERT(dataUrl.getData().asChars() == "Hello, World!"_kj); } @@ -38,22 +38,19 @@ KJ_TEST("DataUrl no-base64") { } KJ_TEST("DataUrl default mime type") { - auto dataUrl = KJ_ASSERT_NONNULL( - DataUrl::tryParse("data:,Hello, World!"_kj)); + auto dataUrl = KJ_ASSERT_NONNULL(DataUrl::tryParse("data:,Hello, World!"_kj)); KJ_ASSERT(dataUrl.getMimeType() == MimeType::PLAINTEXT); KJ_ASSERT(dataUrl.getData().asChars() == "Hello, World!"_kj); } KJ_TEST("DataUrl default mime type") { - auto dataUrl = KJ_ASSERT_NONNULL( - DataUrl::tryParse("data:;,Hello, World!"_kj)); + auto dataUrl = KJ_ASSERT_NONNULL(DataUrl::tryParse("data:;,Hello, World!"_kj)); KJ_ASSERT(dataUrl.getMimeType() == MimeType::PLAINTEXT); KJ_ASSERT(dataUrl.getData().asChars() == "Hello, World!"_kj); } KJ_TEST("DataUrl default mime type") { - auto dataUrl = KJ_ASSERT_NONNULL( - DataUrl::tryParse("data:;charset=UTF-8,Hello, World!"_kj)); + auto dataUrl = KJ_ASSERT_NONNULL(DataUrl::tryParse("data:;charset=UTF-8,Hello, World!"_kj)); KJ_ASSERT(dataUrl.getMimeType() == MimeType::PLAINTEXT); KJ_ASSERT(dataUrl.getData().asChars() == "Hello, World!"_kj); @@ -69,12 +66,11 @@ struct Test { KJ_TEST("DataUrl Web Platform Tests") { - Test tests[] = { - { - "data://test/,X"_kj, - "text/plain;charset=US-ASCII"_kj, - kj::heapArray({88}), - }, + Test tests[] = {{ + "data://test/,X"_kj, + "text/plain;charset=US-ASCII"_kj, + kj::heapArray({88}), + }, { "data://test:test/,X"_kj, nullptr, @@ -86,9 +82,9 @@ KJ_TEST("DataUrl Web Platform Tests") { kj::heapArray({88}), }, { - "data:"_kj, - nullptr, - kj::heapArray(0), + "data:"_kj, + nullptr, + kj::heapArray(0), }, { "data:text/html"_kj, @@ -429,12 +425,11 @@ KJ_TEST("DataUrl Web Platform Tests") { "data:;CHARSET=\"X\",X"_kj, "text/plain;charset=X"_kj, kj::heapArray({88}), - } - }; + }}; auto testPtr = kj::arrayPtr(tests, 72); - for (auto& test : testPtr) { + for (auto& test: testPtr) { if (test.mimeType == nullptr) { KJ_ASSERT(DataUrl::tryParse(test.input) == kj::none); } else { @@ -455,100 +450,71 @@ KJ_TEST("DataUrl base64") { // web platform's forgiving base64 decoder. That's just fine for us. // These cases were extracted from the Web Platform Tests for data urls // See: https://github.com/web-platform-tests/wpt/blob/master/fetch/data-urls/resources/ - Base64Test tests[] = { - { ""_kj, nullptr }, - { "abcd"_kj, kj::heapArray({105, 183, 29}) }, - { " abcd"_kj, kj::heapArray({105, 183, 29}) }, - { "abcd "_kj, kj::heapArray({105, 183, 29}) }, - { " abcd==="_kj, kj::heapArray({105, 183, 29}) }, - { "abcd=== "_kj, kj::heapArray({105, 183, 29}) }, - { "abcd ==="_kj, kj::heapArray({105, 183, 29}) }, - { "a"_kj, nullptr }, - { "ab"_kj, kj::heapArray({105}) }, - { "abc"_kj, kj::heapArray({105, 183}) }, - { "abcde"_kj, kj::heapArray({105, 183, 29}) }, - { "𐀀"_kj, nullptr }, - { "="_kj, nullptr }, - { "=="_kj, nullptr }, - { "==="_kj, nullptr }, - { "===="_kj, nullptr }, - { "====="_kj, nullptr }, - { "a="_kj, nullptr }, - { "a=="_kj, nullptr }, - { "a==="_kj, nullptr }, - { "a===="_kj, nullptr }, - { "a====="_kj, nullptr }, - { "ab="_kj, kj::heapArray({105}) }, - { "ab=="_kj, kj::heapArray({105}) }, - { "ab==="_kj, kj::heapArray({105}) }, - { "ab===="_kj, kj::heapArray({105}) }, - { "ab====="_kj, kj::heapArray({105}) }, - { "abc="_kj, kj::heapArray({105, 183}) }, - { "abc=="_kj, kj::heapArray({105, 183}) }, - { "abc==="_kj, kj::heapArray({105, 183}) }, - { "abc===="_kj, kj::heapArray({105, 183}) }, - { "abc====="_kj, kj::heapArray({105, 183}) }, - { "abcd="_kj, kj::heapArray({105, 183, 29}) }, - { "abcd=="_kj, kj::heapArray({105, 183, 29}) }, - { "abcd==="_kj, kj::heapArray({105, 183, 29}) }, - { "abcd===="_kj, kj::heapArray({105, 183, 29}) }, - { "abcd====="_kj, kj::heapArray({105, 183, 29}) }, - { "abcde="_kj, kj::heapArray({105, 183, 29}) }, - { "abcde=="_kj, kj::heapArray({105, 183, 29}) }, - { "abcde==="_kj, kj::heapArray({105, 183, 29}) }, - { "abcde===="_kj, kj::heapArray({105, 183, 29}) }, - { "abcde====="_kj, kj::heapArray({105, 183, 29}) }, - { "=a"_kj, nullptr }, - { "=a="_kj, nullptr }, - { "a=b"_kj, kj::heapArray({105}) }, - { "a=b="_kj, kj::heapArray({105}) }, - { "ab=c"_kj, kj::heapArray({105, 183}) }, - { "ab=c="_kj, kj::heapArray({105, 183}) }, - { "abc=d"_kj, kj::heapArray({105, 183, 29}) }, - { "abc=d="_kj, kj::heapArray({105, 183, 29}) }, - { "ab\u000Bcd"_kj, kj::heapArray({105, 183, 29}) }, - { "ab\u3000cd"_kj, kj::heapArray({105, 183, 29}) }, - { "ab\u3001cd"_kj, kj::heapArray({105, 183, 29}) }, - { "ab\tcd"_kj, kj::heapArray({105, 183, 29}) }, - { "ab\ncd"_kj, kj::heapArray({105, 183, 29}) }, - { "ab\fcd"_kj, kj::heapArray({105, 183, 29}) }, - { "ab\rcd"_kj, kj::heapArray({105, 183, 29}) }, - { "ab cd"_kj, kj::heapArray({105, 183, 29}) }, - { "ab\u00a0cd"_kj, kj::heapArray({105, 183, 29}) }, - { "ab\t\n\f\r cd"_kj, kj::heapArray({105, 183, 29}) }, - { " \t\n\f\r ab\t\n\f\r cd\t\n\f\r "_kj, kj::heapArray({105, 183, 29}) }, - { "ab\t\n\f\r =\t\n\f\r =\t\n\f\r "_kj, kj::heapArray({105})}, - { "A"_kj, nullptr }, - { "/A"_kj, kj::heapArray({252}) }, - { "//A"_kj, kj::heapArray({255, 240}) }, - { "///A"_kj, kj::heapArray({255, 255, 192}) }, - { "////A"_kj, kj::heapArray({255, 255, 255}) }, - { "/"_kj, nullptr }, - { "A/"_kj, kj::heapArray({3}) }, - { "AA/"_kj, kj::heapArray({0, 15}) }, - { "AAAA/"_kj, kj::heapArray({0, 0, 0}) }, - { "AAA/"_kj, kj::heapArray({0, 0, 63}) }, - { "\u0000nonsense"_kj, kj::heapArray({158, 137, 236, 122, 123, 30}) }, - { "abcd\u0000nonsense"_kj, - kj::heapArray({105, 183, 29, 158, 137, 236, 122, 123, 30}) }, - { "YQ"_kj, kj::heapArray({97}) }, - { "YR"_kj, kj::heapArray({97}) }, - { "~~"_kj, nullptr }, - { ".."_kj, nullptr }, - { "--"_kj, nullptr }, - { "__"_kj, nullptr } - }; + Base64Test tests[] = {{""_kj, nullptr}, {"abcd"_kj, kj::heapArray({105, 183, 29})}, + {" abcd"_kj, kj::heapArray({105, 183, 29})}, + {"abcd "_kj, kj::heapArray({105, 183, 29})}, + {" abcd==="_kj, kj::heapArray({105, 183, 29})}, + {"abcd=== "_kj, kj::heapArray({105, 183, 29})}, + {"abcd ==="_kj, kj::heapArray({105, 183, 29})}, {"a"_kj, nullptr}, + {"ab"_kj, kj::heapArray({105})}, {"abc"_kj, kj::heapArray({105, 183})}, + {"abcde"_kj, kj::heapArray({105, 183, 29})}, {"𐀀"_kj, nullptr}, {"="_kj, nullptr}, + {"=="_kj, nullptr}, {"==="_kj, nullptr}, {"===="_kj, nullptr}, {"====="_kj, nullptr}, + {"a="_kj, nullptr}, {"a=="_kj, nullptr}, {"a==="_kj, nullptr}, {"a===="_kj, nullptr}, + {"a====="_kj, nullptr}, {"ab="_kj, kj::heapArray({105})}, + {"ab=="_kj, kj::heapArray({105})}, {"ab==="_kj, kj::heapArray({105})}, + {"ab===="_kj, kj::heapArray({105})}, {"ab====="_kj, kj::heapArray({105})}, + {"abc="_kj, kj::heapArray({105, 183})}, + {"abc=="_kj, kj::heapArray({105, 183})}, + {"abc==="_kj, kj::heapArray({105, 183})}, + {"abc===="_kj, kj::heapArray({105, 183})}, + {"abc====="_kj, kj::heapArray({105, 183})}, + {"abcd="_kj, kj::heapArray({105, 183, 29})}, + {"abcd=="_kj, kj::heapArray({105, 183, 29})}, + {"abcd==="_kj, kj::heapArray({105, 183, 29})}, + {"abcd===="_kj, kj::heapArray({105, 183, 29})}, + {"abcd====="_kj, kj::heapArray({105, 183, 29})}, + {"abcde="_kj, kj::heapArray({105, 183, 29})}, + {"abcde=="_kj, kj::heapArray({105, 183, 29})}, + {"abcde==="_kj, kj::heapArray({105, 183, 29})}, + {"abcde===="_kj, kj::heapArray({105, 183, 29})}, + {"abcde====="_kj, kj::heapArray({105, 183, 29})}, {"=a"_kj, nullptr}, + {"=a="_kj, nullptr}, {"a=b"_kj, kj::heapArray({105})}, + {"a=b="_kj, kj::heapArray({105})}, {"ab=c"_kj, kj::heapArray({105, 183})}, + {"ab=c="_kj, kj::heapArray({105, 183})}, + {"abc=d"_kj, kj::heapArray({105, 183, 29})}, + {"abc=d="_kj, kj::heapArray({105, 183, 29})}, + {"ab\u000Bcd"_kj, kj::heapArray({105, 183, 29})}, + {"ab\u3000cd"_kj, kj::heapArray({105, 183, 29})}, + {"ab\u3001cd"_kj, kj::heapArray({105, 183, 29})}, + {"ab\tcd"_kj, kj::heapArray({105, 183, 29})}, + {"ab\ncd"_kj, kj::heapArray({105, 183, 29})}, + {"ab\fcd"_kj, kj::heapArray({105, 183, 29})}, + {"ab\rcd"_kj, kj::heapArray({105, 183, 29})}, + {"ab cd"_kj, kj::heapArray({105, 183, 29})}, + {"ab\u00a0cd"_kj, kj::heapArray({105, 183, 29})}, + {"ab\t\n\f\r cd"_kj, kj::heapArray({105, 183, 29})}, + {" \t\n\f\r ab\t\n\f\r cd\t\n\f\r "_kj, kj::heapArray({105, 183, 29})}, + {"ab\t\n\f\r =\t\n\f\r =\t\n\f\r "_kj, kj::heapArray({105})}, {"A"_kj, nullptr}, + {"/A"_kj, kj::heapArray({252})}, {"//A"_kj, kj::heapArray({255, 240})}, + {"///A"_kj, kj::heapArray({255, 255, 192})}, + {"////A"_kj, kj::heapArray({255, 255, 255})}, {"/"_kj, nullptr}, + {"A/"_kj, kj::heapArray({3})}, {"AA/"_kj, kj::heapArray({0, 15})}, + {"AAAA/"_kj, kj::heapArray({0, 0, 0})}, + {"AAA/"_kj, kj::heapArray({0, 0, 63})}, + {"\u0000nonsense"_kj, kj::heapArray({158, 137, 236, 122, 123, 30})}, + {"abcd\u0000nonsense"_kj, kj::heapArray({105, 183, 29, 158, 137, 236, 122, 123, 30})}, + {"YQ"_kj, kj::heapArray({97})}, {"YR"_kj, kj::heapArray({97})}, + {"~~"_kj, nullptr}, {".."_kj, nullptr}, {"--"_kj, nullptr}, {"__"_kj, nullptr}}; auto testPtr = kj::arrayPtr(tests, 80); - for (auto& test : testPtr) { + for (auto& test: testPtr) { auto input = kj::str("data:;base64,", test.input); auto url = KJ_ASSERT_NONNULL(DataUrl::tryParse(input)); KJ_ASSERT(url.getData() == test.expected, test.input); } - } KJ_TEST("Large Data URL") { diff --git a/src/workerd/api/data-url.c++ b/src/workerd/api/data-url.c++ index 358f094a8d1..5fa6a623d22 100644 --- a/src/workerd/api/data-url.c++ +++ b/src/workerd/api/data-url.c++ @@ -22,25 +22,26 @@ kj::Maybe DataUrl::from(const jsg::Url& url) { // string value in the MIME type... which is fun. static const auto isAsciiWhitespace = [](auto c) { - return c == 0x09 /* tab */ || - c == 0x0a /* lf */ || - c == 0x0c /* ff */ || - c == 0x0d /* cr */ || - c == 0x20 /* sp */; + return c == 0x09 /* tab */ || c == 0x0a /* lf */ || c == 0x0c /* ff */ || + c == 0x0d /* cr */ || c == 0x20 /* sp */; }; static const auto trim = [](auto label) { size_t start = 0; auto end = label.size(); - while (start < end && isAsciiWhitespace(label[start])) { start++; } - while (end > start && isAsciiWhitespace(label[end - 1])) { end--; } + while (start < end && isAsciiWhitespace(label[start])) { + start++; + } + while (end > start && isAsciiWhitespace(label[end - 1])) { + end--; + } return label.slice(start, end).asChars(); }; static const auto strip = [](auto label) { auto result = kj::heapArray(label.size()); size_t len = 0; - for (auto c : label) { + for (auto c: label) { if (!isAsciiWhitespace(c)) { result[len++] = c; } @@ -51,13 +52,8 @@ kj::Maybe DataUrl::from(const jsg::Url& url) { static const auto isBase64 = [](kj::ArrayPtr label) -> bool { KJ_IF_SOME(pos, label.findLast(';')) { auto res = trim(label.slice(pos + 1)); - return res.size() == 6 && - (res[0] | 0x20) == 'b' && - (res[1] | 0x20) == 'a' && - (res[2] | 0x20) == 's' && - (res[3] | 0x20) == 'e' && - (res[4] == '6') && - (res[5] == '4'); + return res.size() == 6 && (res[0] | 0x20) == 'b' && (res[1] | 0x20) == 'a' && + (res[2] | 0x20) == 's' && (res[3] | 0x20) == 'e' && (res[4] == '6') && (res[5] == '4'); } return false; }; @@ -86,7 +82,6 @@ kj::Maybe DataUrl::from(const jsg::Url& url) { decoded = jsg::Url::percentDecode(data.asBytes()); } - if (unparsed.startsWith(";"_kj)) { // If the mime type starts with ;, then the spec tells us to // prepend "text/plain" to the mime type. diff --git a/src/workerd/api/data-url.h b/src/workerd/api/data-url.h index 2b429535a3e..8c88b7d9d74 100644 --- a/src/workerd/api/data-url.h +++ b/src/workerd/api/data-url.h @@ -15,14 +15,21 @@ class DataUrl final { DataUrl& operator=(DataUrl&&) = default; KJ_DISALLOW_COPY(DataUrl); - const MimeType& getMimeType() const { return mimeType; } - kj::ArrayPtr getData() const { return data.asPtr(); } + const MimeType& getMimeType() const { + return mimeType; + } + kj::ArrayPtr getData() const { + return data.asPtr(); + } - kj::Array releaseData() { return data.releaseAsBytes(); } + kj::Array releaseData() { + return data.releaseAsBytes(); + } private: DataUrl(MimeType mimeType, kj::Array data) - : mimeType(kj::mv(mimeType)), data(kj::mv(data)) {} + : mimeType(kj::mv(mimeType)), + data(kj::mv(data)) {} MimeType mimeType; kj::Array data; diff --git a/src/workerd/api/deferred-proxy-test.c++ b/src/workerd/api/deferred-proxy-test.c++ index e2d54e85431..4599b1fa679 100644 --- a/src/workerd/api/deferred-proxy-test.c++ +++ b/src/workerd/api/deferred-proxy-test.c++ @@ -21,9 +21,7 @@ KJ_TEST("kj::Promise>: early co_return implicitly fulfills oute } { // Explicit void co_return. - auto coro = []() -> kj::Promise> { - co_return; - }; + auto coro = []() -> kj::Promise> { co_return; }; auto promise = coro(); KJ_EXPECT(promise.poll(waitScope)); auto proxyTask = promise.wait(waitScope).proxyTask; @@ -32,9 +30,7 @@ KJ_TEST("kj::Promise>: early co_return implicitly fulfills oute } { // Valueful co_return. - auto coro = []() -> kj::Promise> { - co_return 123; - }; + auto coro = []() -> kj::Promise> { co_return 123; }; auto promise = coro(); KJ_EXPECT(promise.poll(waitScope)); auto proxyTask = promise.wait(waitScope).proxyTask; @@ -44,7 +40,7 @@ KJ_TEST("kj::Promise>: early co_return implicitly fulfills oute } KJ_TEST("kj::Promise>: `KJ_CO_MAGIC BEGIN_DEFERRED_PROXYING` fulfills outer " - "promise") { + "promise") { kj::EventLoop loop; kj::WaitScope waitScope(loop); @@ -77,7 +73,7 @@ KJ_TEST("kj::Promise>: `KJ_CO_MAGIC BEGIN_DEFERRED_PROXYING` fu } KJ_TEST("kj::Promise>: unhandled exception before " - "`KJ_CO_MAGIC BEGIN_DEFERRED_PROXYING`") { + "`KJ_CO_MAGIC BEGIN_DEFERRED_PROXYING`") { kj::EventLoop loop; kj::WaitScope waitScope(loop); @@ -100,7 +96,7 @@ KJ_TEST("kj::Promise>: unhandled exception before " } KJ_TEST("kj::Promise>: unhandled exception after " - "`KJ_CO_MAGIC BEGIN_DEFERRED_PROXYING`") { + "`KJ_CO_MAGIC BEGIN_DEFERRED_PROXYING`") { kj::EventLoop loop; kj::WaitScope waitScope(loop); @@ -173,13 +169,16 @@ KJ_TEST("kj::Promise>: can be `co_await`ed from another corouti struct Counter { size_t& wind; size_t& unwind; - Counter(size_t& wind, size_t& unwind): wind(wind), unwind(unwind) { ++wind; } - ~Counter() { ++unwind; } + Counter(size_t& wind, size_t& unwind): wind(wind), unwind(unwind) { + ++wind; + } + ~Counter() { + ++unwind; + } KJ_DISALLOW_COPY_AND_MOVE(Counter); }; -kj::Promise> cancellationTester( - kj::Promise preDeferredProxying, +kj::Promise> cancellationTester(kj::Promise preDeferredProxying, kj::Promise postDeferredProxying, size_t& wind, size_t& unwind) { @@ -230,7 +229,7 @@ KJ_TEST("kj::Promise>: can be canceled while suspended after de } KJ_TEST("kj::Promise>: destroying inner PromiseNode before outer does not " - "segfault") { + "segfault") { // Destroy the inner promise before the outer promise to test our safeguard against incorrect // destruction order causing segfaults. diff --git a/src/workerd/api/deferred-proxy.h b/src/workerd/api/deferred-proxy.h index 66408b8619a..f537897a384 100644 --- a/src/workerd/api/deferred-proxy.h +++ b/src/workerd/api/deferred-proxy.h @@ -39,12 +39,12 @@ struct DeferredProxy { }; inline DeferredProxy newNoopDeferredProxy() { - return DeferredProxy { kj::READY_NOW }; + return DeferredProxy{kj::READY_NOW}; } template inline DeferredProxy newNoopDeferredProxy(T&& value) { - return DeferredProxy { kj::mv(value) }; + return DeferredProxy{kj::mv(value)}; } // Helper method to use when you need to return `Promise>` but no part of the @@ -101,13 +101,13 @@ namespace workerd::api { class BeginDeferredProxyingConstant final {}; // A magic constant which a DeferredProxyPromise coroutine can `KJ_CO_MAGIC` to indicate that the // deferred proxying phase of its operation has begun. -constexpr BeginDeferredProxyingConstant BEGIN_DEFERRED_PROXYING {}; +constexpr BeginDeferredProxyingConstant BEGIN_DEFERRED_PROXYING{}; // A concept which is true if C is a coroutine adapter which supports the `co_yield` operator for // type T. We could also check that the expression results in an awaitable, but that is already a // compile error in other ways. template -concept CoroutineYieldValue = requires (T&& v, C coroutineAdapter) { +concept CoroutineYieldValue = requires(T&& v, C coroutineAdapter) { { coroutineAdapter.yield_value(kj::fwd(v)) }; }; @@ -136,12 +136,16 @@ class DeferredProxyCoroutine: public kj::_::PromiseNode, // called. This gives us the opportunity (that is, in `destroy()`) to destroy our // `inner.get_return_object()` Promise, breaking the ownership cycle and destroying `this`. - result.value = DeferredProxy { inner.get_return_object() }; + result.value = DeferredProxy{inner.get_return_object()}; return kj::_::PromiseNode::to>>(kj::_::OwnPromiseNode(this)); } - auto initial_suspend() { return inner.initial_suspend(); } - auto final_suspend() noexcept { return inner.final_suspend(); } + auto initial_suspend() { + return inner.initial_suspend(); + } + auto final_suspend() noexcept { + return inner.final_suspend(); + } // Just trivially forward these. void unhandled_exception() { @@ -182,7 +186,9 @@ class DeferredProxyCoroutine: public kj::_::PromiseNode, return inner.await_transform(kj::fwd(awaitable)); } - operator kj::_::CoroutineBase&() { return inner; } + operator kj::_::CoroutineBase&() { + return inner; + } // Required by Awaiter::await_suspend() to support awaiting Promises. private: diff --git a/src/workerd/api/encoding.c++ b/src/workerd/api/encoding.c++ index a43af7460b5..dd8dff12720 100644 --- a/src/workerd/api/encoding.c++ +++ b/src/workerd/api/encoding.c++ @@ -16,241 +16,244 @@ namespace workerd::api { // TextDecoder implementation namespace { -#define EW_ENCODING_LABELS(V) \ - V("unicode-1-1-utf-8", Utf8) \ - V("unicode11utf8", Utf8) \ - V("unicode20utf8", Utf8) \ - V("utf-8", Utf8) \ - V("utf8", Utf8) \ - V("x-unicode20utf8", Utf8) \ - V("866", Ibm866) \ - V("cp866", Ibm866) \ - V("csibm866", Ibm866) \ - V("ibm866", Ibm866) \ - V("csisolatin2", Iso8859_2) \ - V("iso-8859-2", Iso8859_2) \ - V("iso-ir-101", Iso8859_2) \ - V("iso8859-2", Iso8859_2) \ - V("iso88592", Iso8859_2) \ - V("iso_8859-2", Iso8859_2) \ - V("iso_8859-2:1987", Iso8859_2) \ - V("l2", Iso8859_2) \ - V("latin2", Iso8859_2) \ - V("csisolatin3", Iso8859_3) \ - V("iso-8859-3", Iso8859_3) \ - V("iso-ir-109", Iso8859_3) \ - V("iso8859-3", Iso8859_3) \ - V("iso88593", Iso8859_3) \ - V("iso_8859-3", Iso8859_3) \ - V("iso_8859-3:1988", Iso8859_3) \ - V("l3", Iso8859_3) \ - V("latin3", Iso8859_3) \ - V("csisolatin4", Iso8859_4) \ - V("iso-8859-4", Iso8859_4) \ - V("iso-ir-110", Iso8859_4) \ - V("iso8859-4", Iso8859_4) \ - V("iso88594", Iso8859_4) \ - V("iso_8859-4", Iso8859_4) \ - V("iso_8859-4:1988", Iso8859_4) \ - V("l4", Iso8859_4) \ - V("latin4", Iso8859_4) \ - V("csisolatincyrillic", Iso8859_5) \ - V("cyrillic", Iso8859_5) \ - V("iso-8859-5", Iso8859_5) \ - V("iso-ir-144", Iso8859_5) \ - V("iso8859-5", Iso8859_5) \ - V("iso88595", Iso8859_5) \ - V("iso_8859-5", Iso8859_5) \ - V("iso_8859-5:1988", Iso8859_5) \ - V("arabic", Iso8859_6) \ - V("asmo-708", Iso8859_6) \ - V("csiso88596e", Iso8859_6) \ - V("csiso88596i", Iso8859_6) \ - V("csisolatinarabic", Iso8859_6) \ - V("ecma-114", Iso8859_6) \ - V("iso-8859-6", Iso8859_6) \ - V("iso-8859-6-e", Iso8859_6) \ - V("iso-8859-6-i", Iso8859_6) \ - V("iso-ir-127", Iso8859_6) \ - V("iso8859-6", Iso8859_6) \ - V("iso88596", Iso8859_6) \ - V("iso_8859-6", Iso8859_6) \ - V("iso_8859-6:1987", Iso8859_6) \ - V("csisolatingreek", Iso8859_7) \ - V("ecma-118", Iso8859_7) \ - V("elot_928", Iso8859_7) \ - V("greek", Iso8859_7) \ - V("greek8", Iso8859_7) \ - V("iso-8859-7", Iso8859_7) \ - V("iso-ir-126", Iso8859_7) \ - V("iso8859-7", Iso8859_7) \ - V("iso88597", Iso8859_7) \ - V("iso_8859-7", Iso8859_7) \ - V("iso_8859-7:1987", Iso8859_7) \ - V("sun_eu_greek", Iso8859_7) \ - V("csiso88598e", Iso8859_8) \ - V("csisolatinhebrew", Iso8859_8) \ - V("hebrew", Iso8859_8) \ - V("iso-8859-8", Iso8859_8) \ - V("iso-8859-8-e", Iso8859_8) \ - V("iso-ir-138", Iso8859_8) \ - V("iso8859-8", Iso8859_8) \ - V("iso88598", Iso8859_8) \ - V("iso_8859-8", Iso8859_8) \ - V("iso_8859-8:1988", Iso8859_8) \ - V("visual", Iso8859_8) \ - V("csiso88598i", Iso8859_8i) \ - V("iso-8859-8-i", Iso8859_8i) \ - V("logical", Iso8859_8i) \ - V("csisolatin6", Iso8859_10) \ - V("iso-8859-10", Iso8859_10) \ - V("iso-ir-157", Iso8859_10) \ - V("iso8859-10", Iso8859_10) \ - V("iso885910", Iso8859_10) \ - V("l6", Iso8859_10) \ - V("latin6", Iso8859_10) \ - V("iso-8859-13", Iso8859_13) \ - V("iso8859-13", Iso8859_13) \ - V("iso885913", Iso8859_13) \ - V("iso-8859-14", Iso8859_14) \ - V("iso8859-14", Iso8859_14) \ - V("iso885914", Iso8859_14) \ - V("csisolatin9", Iso8859_15) \ - V("iso-8859-15", Iso8859_15) \ - V("iso8859-15", Iso8859_15) \ - V("iso885915", Iso8859_15) \ - V("iso_8859-15", Iso8859_15) \ - V("l9", Iso8859_15) \ - V("iso-8859-16", Iso8859_16) \ - V("cskoi8r", Ko18_r) \ - V("koi", Ko18_r) \ - V("koi8", Ko18_r) \ - V("koi8-r", Ko18_r) \ - V("koi8_r", Ko18_r) \ - V("koi8-ru", Koi8_u) \ - V("koi8-u", Koi8_u) \ - V("csmacintosh", Macintosh) \ - V("mac", Macintosh) \ - V("macintosh", Macintosh) \ - V("x-mac-roman", Macintosh) \ - V("dos-874", Windows_874) \ - V("iso-8859-11", Windows_874) \ - V("iso8859-11", Windows_874) \ - V("iso885911", Windows_874) \ - V("tis-620", Windows_874) \ - V("windows-874", Windows_874) \ - V("cp1250", Windows_1250) \ - V("windows-1250", Windows_1250) \ - V("x-cp1250", Windows_1250) \ - V("cp1251", Windows_1251) \ - V("windows-1251", Windows_1251) \ - V("x-cp1251", Windows_1251) \ - V("ansi_x3.4-1968", Windows_1252) \ - V("ascii", Windows_1252) \ - V("cp1252", Windows_1252) \ - V("cp819", Windows_1252) \ - V("csisolatin1", Windows_1252) \ - V("ibm819", Windows_1252) \ - V("iso-8859-1", Windows_1252) \ - V("iso-ir-100", Windows_1252) \ - V("iso8859-1", Windows_1252) \ - V("iso88591", Windows_1252) \ - V("iso_8859-1", Windows_1252) \ - V("iso_8859-1:1987", Windows_1252) \ - V("l1", Windows_1252) \ - V("latin1", Windows_1252) \ - V("us-ascii", Windows_1252) \ - V("windows-1252", Windows_1252) \ - V("x-cp1252", Windows_1252) \ - V("cp1253", Windows_1253) \ - V("windows-1253", Windows_1253) \ - V("x-cp1253", Windows_1253) \ - V("cp1254", Windows_1254) \ - V("csisolatin5", Windows_1254) \ - V("iso-8859-9", Windows_1254) \ - V("iso-ir-148", Windows_1254) \ - V("iso8859-9", Windows_1254) \ - V("iso88599", Windows_1254) \ - V("iso_8859-9", Windows_1254) \ - V("iso_8859-9:1989", Windows_1254) \ - V("l5", Windows_1254) \ - V("latin5", Windows_1254) \ - V("windows-1254", Windows_1254) \ - V("x-cp1254", Windows_1254) \ - V("cp1255", Windows_1255) \ - V("windows-1255", Windows_1255) \ - V("x-cp1255", Windows_1255) \ - V("cp1256", Windows_1256) \ - V("windows-1256", Windows_1256) \ - V("x-cp1256", Windows_1256) \ - V("cp1257", Windows_1257) \ - V("windows-1257", Windows_1257) \ - V("x-cp1257", Windows_1257) \ - V("cp1258", Windows_1258) \ - V("windows-1258", Windows_1258) \ - V("x-cp1258", Windows_1258) \ - V("x-mac-cyrillic", X_Mac_Cyrillic) \ - V("x-mac-ukrainian", X_Mac_Cyrillic) \ - V("chinese", Gbk) \ - V("csgb2312", Gbk) \ - V("csiso58gb231280", Gbk) \ - V("gb2312", Gbk) \ - V("gb_2312", Gbk) \ - V("gb_2312-80", Gbk) \ - V("gbk", Gbk) \ - V("iso-ir-58", Gbk) \ - V("x-gbk", Gbk) \ - V("gb18030", Gb18030) \ - V("big5", Big5) \ - V("big5-hkscs", Big5) \ - V("cn-big5", Big5) \ - V("csbig5", Big5) \ - V("x-x-big5", Big5) \ - V("cseucpkdfmtjapanese", Euc_Jp) \ - V("euc-jp", Euc_Jp) \ - V("x-euc-jp", Euc_Jp) \ - V("csiso2022jp", Iso2022_Jp) \ - V("iso-2022-jp", Iso2022_Jp) \ - V("csshiftjis", Shift_Jis) \ - V("ms932", Shift_Jis) \ - V("ms_kanji", Shift_Jis) \ - V("shift-jis", Shift_Jis) \ - V("shift_jis", Shift_Jis) \ - V("sjis", Shift_Jis) \ - V("windows-31j", Shift_Jis) \ - V("x-sjis", Shift_Jis) \ - V("cseuckr", Euc_Kr) \ - V("csksc56011987", Euc_Kr) \ - V("euc-kr", Euc_Kr) \ - V("iso-ir-149", Euc_Kr) \ - V("korean", Euc_Kr) \ - V("ks_c_5601-1987", Euc_Kr) \ - V("ks_c_5601-1989", Euc_Kr) \ - V("ksc5601", Euc_Kr) \ - V("ksc_5601", Euc_Kr) \ - V("windows-949", Euc_Kr) \ - V("csiso2022kr", Replacement) \ - V("hz-gb-2312", Replacement) \ - V("iso-2022-cn", Replacement) \ - V("iso-2022-cn-ext", Replacement) \ - V("iso-2022-kr", Replacement) \ - V("replacement", Replacement) \ - V("unicodefffe", Utf16be) \ - V("utf-16be", Utf16be) \ - V("csunicode", Utf16le) \ - V("iso-10646-ucs-2", Utf16le) \ - V("ucs-2", Utf16le) \ - V("unicode", Utf16le) \ - V("unicodefeff", Utf16le) \ - V("utf-16", Utf16le) \ - V("utf-16le", Utf16le) \ +#define EW_ENCODING_LABELS(V) \ + V("unicode-1-1-utf-8", Utf8) \ + V("unicode11utf8", Utf8) \ + V("unicode20utf8", Utf8) \ + V("utf-8", Utf8) \ + V("utf8", Utf8) \ + V("x-unicode20utf8", Utf8) \ + V("866", Ibm866) \ + V("cp866", Ibm866) \ + V("csibm866", Ibm866) \ + V("ibm866", Ibm866) \ + V("csisolatin2", Iso8859_2) \ + V("iso-8859-2", Iso8859_2) \ + V("iso-ir-101", Iso8859_2) \ + V("iso8859-2", Iso8859_2) \ + V("iso88592", Iso8859_2) \ + V("iso_8859-2", Iso8859_2) \ + V("iso_8859-2:1987", Iso8859_2) \ + V("l2", Iso8859_2) \ + V("latin2", Iso8859_2) \ + V("csisolatin3", Iso8859_3) \ + V("iso-8859-3", Iso8859_3) \ + V("iso-ir-109", Iso8859_3) \ + V("iso8859-3", Iso8859_3) \ + V("iso88593", Iso8859_3) \ + V("iso_8859-3", Iso8859_3) \ + V("iso_8859-3:1988", Iso8859_3) \ + V("l3", Iso8859_3) \ + V("latin3", Iso8859_3) \ + V("csisolatin4", Iso8859_4) \ + V("iso-8859-4", Iso8859_4) \ + V("iso-ir-110", Iso8859_4) \ + V("iso8859-4", Iso8859_4) \ + V("iso88594", Iso8859_4) \ + V("iso_8859-4", Iso8859_4) \ + V("iso_8859-4:1988", Iso8859_4) \ + V("l4", Iso8859_4) \ + V("latin4", Iso8859_4) \ + V("csisolatincyrillic", Iso8859_5) \ + V("cyrillic", Iso8859_5) \ + V("iso-8859-5", Iso8859_5) \ + V("iso-ir-144", Iso8859_5) \ + V("iso8859-5", Iso8859_5) \ + V("iso88595", Iso8859_5) \ + V("iso_8859-5", Iso8859_5) \ + V("iso_8859-5:1988", Iso8859_5) \ + V("arabic", Iso8859_6) \ + V("asmo-708", Iso8859_6) \ + V("csiso88596e", Iso8859_6) \ + V("csiso88596i", Iso8859_6) \ + V("csisolatinarabic", Iso8859_6) \ + V("ecma-114", Iso8859_6) \ + V("iso-8859-6", Iso8859_6) \ + V("iso-8859-6-e", Iso8859_6) \ + V("iso-8859-6-i", Iso8859_6) \ + V("iso-ir-127", Iso8859_6) \ + V("iso8859-6", Iso8859_6) \ + V("iso88596", Iso8859_6) \ + V("iso_8859-6", Iso8859_6) \ + V("iso_8859-6:1987", Iso8859_6) \ + V("csisolatingreek", Iso8859_7) \ + V("ecma-118", Iso8859_7) \ + V("elot_928", Iso8859_7) \ + V("greek", Iso8859_7) \ + V("greek8", Iso8859_7) \ + V("iso-8859-7", Iso8859_7) \ + V("iso-ir-126", Iso8859_7) \ + V("iso8859-7", Iso8859_7) \ + V("iso88597", Iso8859_7) \ + V("iso_8859-7", Iso8859_7) \ + V("iso_8859-7:1987", Iso8859_7) \ + V("sun_eu_greek", Iso8859_7) \ + V("csiso88598e", Iso8859_8) \ + V("csisolatinhebrew", Iso8859_8) \ + V("hebrew", Iso8859_8) \ + V("iso-8859-8", Iso8859_8) \ + V("iso-8859-8-e", Iso8859_8) \ + V("iso-ir-138", Iso8859_8) \ + V("iso8859-8", Iso8859_8) \ + V("iso88598", Iso8859_8) \ + V("iso_8859-8", Iso8859_8) \ + V("iso_8859-8:1988", Iso8859_8) \ + V("visual", Iso8859_8) \ + V("csiso88598i", Iso8859_8i) \ + V("iso-8859-8-i", Iso8859_8i) \ + V("logical", Iso8859_8i) \ + V("csisolatin6", Iso8859_10) \ + V("iso-8859-10", Iso8859_10) \ + V("iso-ir-157", Iso8859_10) \ + V("iso8859-10", Iso8859_10) \ + V("iso885910", Iso8859_10) \ + V("l6", Iso8859_10) \ + V("latin6", Iso8859_10) \ + V("iso-8859-13", Iso8859_13) \ + V("iso8859-13", Iso8859_13) \ + V("iso885913", Iso8859_13) \ + V("iso-8859-14", Iso8859_14) \ + V("iso8859-14", Iso8859_14) \ + V("iso885914", Iso8859_14) \ + V("csisolatin9", Iso8859_15) \ + V("iso-8859-15", Iso8859_15) \ + V("iso8859-15", Iso8859_15) \ + V("iso885915", Iso8859_15) \ + V("iso_8859-15", Iso8859_15) \ + V("l9", Iso8859_15) \ + V("iso-8859-16", Iso8859_16) \ + V("cskoi8r", Ko18_r) \ + V("koi", Ko18_r) \ + V("koi8", Ko18_r) \ + V("koi8-r", Ko18_r) \ + V("koi8_r", Ko18_r) \ + V("koi8-ru", Koi8_u) \ + V("koi8-u", Koi8_u) \ + V("csmacintosh", Macintosh) \ + V("mac", Macintosh) \ + V("macintosh", Macintosh) \ + V("x-mac-roman", Macintosh) \ + V("dos-874", Windows_874) \ + V("iso-8859-11", Windows_874) \ + V("iso8859-11", Windows_874) \ + V("iso885911", Windows_874) \ + V("tis-620", Windows_874) \ + V("windows-874", Windows_874) \ + V("cp1250", Windows_1250) \ + V("windows-1250", Windows_1250) \ + V("x-cp1250", Windows_1250) \ + V("cp1251", Windows_1251) \ + V("windows-1251", Windows_1251) \ + V("x-cp1251", Windows_1251) \ + V("ansi_x3.4-1968", Windows_1252) \ + V("ascii", Windows_1252) \ + V("cp1252", Windows_1252) \ + V("cp819", Windows_1252) \ + V("csisolatin1", Windows_1252) \ + V("ibm819", Windows_1252) \ + V("iso-8859-1", Windows_1252) \ + V("iso-ir-100", Windows_1252) \ + V("iso8859-1", Windows_1252) \ + V("iso88591", Windows_1252) \ + V("iso_8859-1", Windows_1252) \ + V("iso_8859-1:1987", Windows_1252) \ + V("l1", Windows_1252) \ + V("latin1", Windows_1252) \ + V("us-ascii", Windows_1252) \ + V("windows-1252", Windows_1252) \ + V("x-cp1252", Windows_1252) \ + V("cp1253", Windows_1253) \ + V("windows-1253", Windows_1253) \ + V("x-cp1253", Windows_1253) \ + V("cp1254", Windows_1254) \ + V("csisolatin5", Windows_1254) \ + V("iso-8859-9", Windows_1254) \ + V("iso-ir-148", Windows_1254) \ + V("iso8859-9", Windows_1254) \ + V("iso88599", Windows_1254) \ + V("iso_8859-9", Windows_1254) \ + V("iso_8859-9:1989", Windows_1254) \ + V("l5", Windows_1254) \ + V("latin5", Windows_1254) \ + V("windows-1254", Windows_1254) \ + V("x-cp1254", Windows_1254) \ + V("cp1255", Windows_1255) \ + V("windows-1255", Windows_1255) \ + V("x-cp1255", Windows_1255) \ + V("cp1256", Windows_1256) \ + V("windows-1256", Windows_1256) \ + V("x-cp1256", Windows_1256) \ + V("cp1257", Windows_1257) \ + V("windows-1257", Windows_1257) \ + V("x-cp1257", Windows_1257) \ + V("cp1258", Windows_1258) \ + V("windows-1258", Windows_1258) \ + V("x-cp1258", Windows_1258) \ + V("x-mac-cyrillic", X_Mac_Cyrillic) \ + V("x-mac-ukrainian", X_Mac_Cyrillic) \ + V("chinese", Gbk) \ + V("csgb2312", Gbk) \ + V("csiso58gb231280", Gbk) \ + V("gb2312", Gbk) \ + V("gb_2312", Gbk) \ + V("gb_2312-80", Gbk) \ + V("gbk", Gbk) \ + V("iso-ir-58", Gbk) \ + V("x-gbk", Gbk) \ + V("gb18030", Gb18030) \ + V("big5", Big5) \ + V("big5-hkscs", Big5) \ + V("cn-big5", Big5) \ + V("csbig5", Big5) \ + V("x-x-big5", Big5) \ + V("cseucpkdfmtjapanese", Euc_Jp) \ + V("euc-jp", Euc_Jp) \ + V("x-euc-jp", Euc_Jp) \ + V("csiso2022jp", Iso2022_Jp) \ + V("iso-2022-jp", Iso2022_Jp) \ + V("csshiftjis", Shift_Jis) \ + V("ms932", Shift_Jis) \ + V("ms_kanji", Shift_Jis) \ + V("shift-jis", Shift_Jis) \ + V("shift_jis", Shift_Jis) \ + V("sjis", Shift_Jis) \ + V("windows-31j", Shift_Jis) \ + V("x-sjis", Shift_Jis) \ + V("cseuckr", Euc_Kr) \ + V("csksc56011987", Euc_Kr) \ + V("euc-kr", Euc_Kr) \ + V("iso-ir-149", Euc_Kr) \ + V("korean", Euc_Kr) \ + V("ks_c_5601-1987", Euc_Kr) \ + V("ks_c_5601-1989", Euc_Kr) \ + V("ksc5601", Euc_Kr) \ + V("ksc_5601", Euc_Kr) \ + V("windows-949", Euc_Kr) \ + V("csiso2022kr", Replacement) \ + V("hz-gb-2312", Replacement) \ + V("iso-2022-cn", Replacement) \ + V("iso-2022-cn-ext", Replacement) \ + V("iso-2022-kr", Replacement) \ + V("replacement", Replacement) \ + V("unicodefffe", Utf16be) \ + V("utf-16be", Utf16be) \ + V("csunicode", Utf16le) \ + V("iso-10646-ucs-2", Utf16le) \ + V("ucs-2", Utf16le) \ + V("unicode", Utf16le) \ + V("unicodefeff", Utf16le) \ + V("utf-16", Utf16le) \ + V("utf-16le", Utf16le) \ V("x-user-defined", X_User_Defined) kj::StringPtr getEncodingId(Encoding encoding) { switch (encoding) { - case Encoding::INVALID: return "invalid"_kj; -#define V(name, id) case Encoding::name: return id##_kj; - EW_ENCODINGS(V) + case Encoding::INVALID: + return "invalid"_kj; +#define V(name, id) \ + case Encoding::name: \ + return id##_kj; + EW_ENCODINGS(V) #undef V } KJ_UNREACHABLE; @@ -260,21 +263,23 @@ Encoding getEncodingForLabel(kj::StringPtr label) { kj::String labelInsensitive = toLower(label); const auto trim = [](kj::StringPtr label) { const auto isAsciiWhitespace = [](auto c) { - return c == 0x09 /* tab */ || - c == 0x0a /* lf */ || - c == 0x0c /* ff */ || - c == 0x0d /* cr */ || - c == 0x20 /* sp */; + return c == 0x09 /* tab */ || c == 0x0a /* lf */ || c == 0x0c /* ff */ || + c == 0x0d /* cr */ || c == 0x20 /* sp */; }; size_t start = 0; auto end = label.size(); - while (start < end && isAsciiWhitespace(label[start])) { start++; } - while (end > start && isAsciiWhitespace(label[end - 1])) { end--; } + while (start < end && isAsciiWhitespace(label[start])) { + start++; + } + while (end > start && isAsciiWhitespace(label[end - 1])) { + end--; + } return label.slice(start, end).asChars(); }; auto trimmed = trim(labelInsensitive); -#define V(label, key) if (trimmed == label##_kj) return Encoding::key; +#define V(label, key) \ + if (trimmed == label##_kj) return Encoding::key; EW_ENCODING_LABELS(V) #undef V return Encoding::INVALID; @@ -300,9 +305,7 @@ kj::Maybe IcuDecoder::create(Encoding encoding, bool fatal, bool ign } kj::Maybe IcuDecoder::decode( - jsg::Lock& js, - kj::ArrayPtr buffer, - bool flush) { + jsg::Lock& js, kj::ArrayPtr buffer, bool flush) { UErrorCode status = U_ZERO_ERROR; const auto maxCharSize = [this]() { return ucnv_getMaxCharSize(inner.get()); }; @@ -321,7 +324,9 @@ kj::Maybe IcuDecoder::decode( const auto isUsAscii = [](const auto& b) { return b <= 0x7f; }; - KJ_DEFER({ if (flush) reset(); }); + KJ_DEFER({ + if (flush) reset(); + }); // Evaluate fast-path options. These provide shortcuts for common cases with the caveat // that error handling for invalid sequences might be a bit different (because the @@ -364,11 +369,9 @@ kj::Maybe IcuDecoder::decode( status = U_ZERO_ERROR; auto limit = 2 * maxCharSize() * - (!flush ? - buffer.size() : - std::max( - buffer.size(), - static_cast(ucnv_toUCountPending(inner.get(), &status)))); + (!flush ? buffer.size() + : std::max(buffer.size(), + static_cast(ucnv_toUCountPending(inner.get(), &status)))); KJ_STACK_ARRAY(UChar, result, limit, 512, 4096); @@ -376,12 +379,7 @@ kj::Maybe IcuDecoder::decode( auto source = reinterpret_cast(buffer.begin()); ucnv_toUnicode( - inner.get(), - &dest, dest + limit, - &source, source + buffer.size(), - nullptr, - flush, - &status); + inner.get(), &dest, dest + limit, &source, source + buffer.size(), nullptr, flush, &status); if (U_FAILURE(status)) return kj::none; @@ -395,9 +393,8 @@ kj::Maybe IcuDecoder::decode( return js.str(result.slice(omitInitialBom ? 1 : 0, length)); } -kj::Maybe AsciiDecoder::decode(jsg::Lock& js, - kj::ArrayPtr buffer, - bool flush) { +kj::Maybe AsciiDecoder::decode( + jsg::Lock& js, kj::ArrayPtr buffer, bool flush) { return js.str(buffer); } @@ -408,15 +405,18 @@ void IcuDecoder::reset() { Decoder& TextDecoder::getImpl() { KJ_SWITCH_ONEOF(decoder) { - KJ_CASE_ONEOF(dec, AsciiDecoder) { return dec; } - KJ_CASE_ONEOF(dec, IcuDecoder) { return dec; } + KJ_CASE_ONEOF(dec, AsciiDecoder) { + return dec; + } + KJ_CASE_ONEOF(dec, IcuDecoder) { + return dec; + } } KJ_UNREACHABLE; } -jsg::Ref -TextDecoder::constructor(jsg::Optional maybeLabel, - jsg::Optional maybeOptions) { +jsg::Ref TextDecoder::constructor( + jsg::Optional maybeLabel, jsg::Optional maybeOptions) { static constexpr ConstructorOptions DEFAULT_OPTIONS; auto options = maybeOptions.orDefault(DEFAULT_OPTIONS); auto encoding = Encoding::Utf8; @@ -427,11 +427,9 @@ TextDecoder::constructor(jsg::Optional maybeLabel, KJ_IF_SOME(label, maybeLabel) { encoding = getEncodingForLabel(label); - JSG_REQUIRE(encoding != Encoding::Replacement && - encoding != Encoding::X_User_Defined && - encoding != Encoding::INVALID, - RangeError, - errorMessage(label)); + JSG_REQUIRE(encoding != Encoding::Replacement && encoding != Encoding::X_User_Defined && + encoding != Encoding::INVALID, + RangeError, errorMessage(label)); } if (encoding == Encoding::Windows_1252) { @@ -440,8 +438,7 @@ TextDecoder::constructor(jsg::Optional maybeLabel, return jsg::alloc( JSG_REQUIRE_NONNULL(IcuDecoder::create(encoding, options.fatal, options.ignoreBOM), - RangeError, - errorMessage(getEncodingId(encoding))), + RangeError, errorMessage(getEncodingId(encoding))), options); } @@ -449,21 +446,17 @@ kj::StringPtr TextDecoder::getEncoding() { return getEncodingId(getImpl().getEncoding()); } -jsg::JsString TextDecoder::decode( - jsg::Lock& js, +jsg::JsString TextDecoder::decode(jsg::Lock& js, jsg::Optional> maybeInput, jsg::Optional maybeOptions) { auto options = maybeOptions.orDefault(DEFAULT_OPTIONS); auto& input = maybeInput.orDefault(EMPTY); return JSG_REQUIRE_NONNULL( - getImpl().decode(js, input, !options.stream), - TypeError, - "Failed to decode input."); + getImpl().decode(js, input, !options.stream), TypeError, "Failed to decode input."); } -kj::Maybe TextDecoder::decodePtr(jsg::Lock& js, - kj::ArrayPtr buffer, - bool flush) { +kj::Maybe TextDecoder::decodePtr( + jsg::Lock& js, kj::ArrayPtr buffer, bool flush) { KJ_SWITCH_ONEOF(decoder) { KJ_CASE_ONEOF(dec, AsciiDecoder) { return dec.decode(js, buffer, flush); @@ -483,14 +476,12 @@ jsg::Ref TextEncoder::constructor() { } namespace { -TextEncoder::EncodeIntoResult encodeIntoImpl(jsg::Lock& js, - jsg::JsString input, - jsg::BufferSource& buffer) { +TextEncoder::EncodeIntoResult encodeIntoImpl( + jsg::Lock& js, jsg::JsString input, jsg::BufferSource& buffer) { auto result = input.writeInto(js, buffer.asArrayPtr().asChars(), - static_cast( - jsg::JsString::NO_NULL_TERMINATION | - jsg::JsString::REPLACE_INVALID_UTF8)); - return TextEncoder::EncodeIntoResult { + static_cast( + jsg::JsString::NO_NULL_TERMINATION | jsg::JsString::REPLACE_INVALID_UTF8)); + return TextEncoder::EncodeIntoResult{ .read = result.read, .written = result.written, }; @@ -499,16 +490,15 @@ TextEncoder::EncodeIntoResult encodeIntoImpl(jsg::Lock& js, jsg::BufferSource TextEncoder::encode(jsg::Lock& js, jsg::Optional input) { auto str = input.orDefault(js.str()); - auto view = JSG_REQUIRE_NONNULL(jsg::BufferSource::tryAlloc(js, str.utf8Length(js)), - RangeError, "Cannot allocate space for TextEncoder.encode"); + auto view = JSG_REQUIRE_NONNULL(jsg::BufferSource::tryAlloc(js, str.utf8Length(js)), RangeError, + "Cannot allocate space for TextEncoder.encode"); [[maybe_unused]] auto result = encodeIntoImpl(js, str, view); KJ_DASSERT(result.written == view.size()); return kj::mv(view); } -TextEncoder::EncodeIntoResult TextEncoder::encodeInto(jsg::Lock& js, - jsg::JsString input, - jsg::BufferSource buffer) { +TextEncoder::EncodeIntoResult TextEncoder::encodeInto( + jsg::Lock& js, jsg::JsString input, jsg::BufferSource buffer) { auto handle = buffer.getHandle(js); JSG_REQUIRE(handle->IsUint8Array(), TypeError, "buffer must be a Uint8Array"); return encodeIntoImpl(js, input, buffer); diff --git a/src/workerd/api/encoding.h b/src/workerd/api/encoding.h index 797b63fdbd6..1922e09ce50 100644 --- a/src/workerd/api/encoding.h +++ b/src/workerd/api/encoding.h @@ -13,46 +13,46 @@ namespace workerd::api { // The encodings listed here are defined as required by the Encoding spec. // The first label is enum we use to identify the encoding in code, while // the second label is the public identifier. -#define EW_ENCODINGS(V) \ - V(Utf8, "utf-8") \ - V(Ibm866, "ibm-866") \ - V(Iso8859_2, "iso-8859-2") \ - V(Iso8859_3, "iso-8859-3") \ - V(Iso8859_4, "iso-8859-4") \ - V(Iso8859_5, "iso-8859-5") \ - V(Iso8859_6, "iso-8859-6") \ - V(Iso8859_7, "iso-8859-7") \ - V(Iso8859_8, "iso-8859-8") \ - V(Iso8859_8i, "iso-8859-8-i") \ - V(Iso8859_10, "iso-8859-10") \ - V(Iso8859_13, "iso-8859-13") \ - V(Iso8859_14, "iso-8859-14") \ - V(Iso8859_15, "iso-8859-15") \ - V(Iso8859_16, "iso-8859-16") \ - V(Ko18_r, "koi8-r") \ - V(Koi8_u, "koi8-u") \ - V(Macintosh, "macintosh") \ - V(Windows_874, "windows-874") \ - V(Windows_1250, "windows-1250") \ - V(Windows_1251, "windows-1251") \ - V(Windows_1252, "windows-1252") \ - V(Windows_1253, "windows-1253") \ - V(Windows_1254, "windows-1254") \ - V(Windows_1255, "windows-1255") \ - V(Windows_1256, "windows-1256") \ - V(Windows_1257, "windows-1257") \ - V(Windows_1258, "windows-1258") \ - V(X_Mac_Cyrillic, "x-mac-cyrillic") \ - V(Gbk, "gbk") \ - V(Gb18030, "gb18030") \ - V(Big5, "big5") \ - V(Euc_Jp, "euc-jp") \ - V(Iso2022_Jp, "iso-2022-jp") \ - V(Shift_Jis, "shift-jis") \ - V(Euc_Kr, "euc-kr") \ - V(Replacement, "replacement") \ - V(Utf16be, "utf-16be") \ - V(Utf16le, "utf-16le") \ +#define EW_ENCODINGS(V) \ + V(Utf8, "utf-8") \ + V(Ibm866, "ibm-866") \ + V(Iso8859_2, "iso-8859-2") \ + V(Iso8859_3, "iso-8859-3") \ + V(Iso8859_4, "iso-8859-4") \ + V(Iso8859_5, "iso-8859-5") \ + V(Iso8859_6, "iso-8859-6") \ + V(Iso8859_7, "iso-8859-7") \ + V(Iso8859_8, "iso-8859-8") \ + V(Iso8859_8i, "iso-8859-8-i") \ + V(Iso8859_10, "iso-8859-10") \ + V(Iso8859_13, "iso-8859-13") \ + V(Iso8859_14, "iso-8859-14") \ + V(Iso8859_15, "iso-8859-15") \ + V(Iso8859_16, "iso-8859-16") \ + V(Ko18_r, "koi8-r") \ + V(Koi8_u, "koi8-u") \ + V(Macintosh, "macintosh") \ + V(Windows_874, "windows-874") \ + V(Windows_1250, "windows-1250") \ + V(Windows_1251, "windows-1251") \ + V(Windows_1252, "windows-1252") \ + V(Windows_1253, "windows-1253") \ + V(Windows_1254, "windows-1254") \ + V(Windows_1255, "windows-1255") \ + V(Windows_1256, "windows-1256") \ + V(Windows_1257, "windows-1257") \ + V(Windows_1258, "windows-1258") \ + V(X_Mac_Cyrillic, "x-mac-cyrillic") \ + V(Gbk, "gbk") \ + V(Gb18030, "gb18030") \ + V(Big5, "big5") \ + V(Euc_Jp, "euc-jp") \ + V(Iso2022_Jp, "iso-2022-jp") \ + V(Shift_Jis, "shift-jis") \ + V(Euc_Kr, "euc-kr") \ + V(Replacement, "replacement") \ + V(Utf16be, "utf-16be") \ + V(Utf16le, "utf-16le") \ V(X_User_Defined, "x-user-defined") enum class Encoding { @@ -68,9 +68,7 @@ class Decoder { virtual ~Decoder() noexcept(true) {} virtual Encoding getEncoding() = 0; virtual kj::Maybe decode( - jsg::Lock& js, - kj::ArrayPtr buffer, - bool flush = false) = 0; + jsg::Lock& js, kj::ArrayPtr buffer, bool flush = false) = 0; virtual void reset() {} }; @@ -83,12 +81,12 @@ class AsciiDecoder final: public Decoder { AsciiDecoder& operator=(AsciiDecoder&&) = default; KJ_DISALLOW_COPY(AsciiDecoder); - Encoding getEncoding() override { return Encoding::Windows_1252; } + Encoding getEncoding() override { + return Encoding::Windows_1252; + } kj::Maybe decode( - jsg::Lock& js, - kj::ArrayPtr buffer, - bool flush = false) override; + jsg::Lock& js, kj::ArrayPtr buffer, bool flush = false) override; }; // Decoder implementation that uses ICU's built-in conversion APIs. @@ -97,24 +95,29 @@ class AsciiDecoder final: public Decoder { class IcuDecoder final: public Decoder { public: IcuDecoder(Encoding encoding, UConverter* converter, bool ignoreBom) - : encoding(encoding), inner(converter), ignoreBom(ignoreBom), bomSeen(false) {} + : encoding(encoding), + inner(converter), + ignoreBom(ignoreBom), + bomSeen(false) {} IcuDecoder(IcuDecoder&&) = default; IcuDecoder& operator=(IcuDecoder&&) = default; static kj::Maybe create(Encoding encoding, bool fatal, bool ignoreBom); - Encoding getEncoding() override { return encoding; } + Encoding getEncoding() override { + return encoding; + } kj::Maybe decode( - jsg::Lock& js, - kj::ArrayPtr buffer, - bool flush = false) override; + jsg::Lock& js, kj::ArrayPtr buffer, bool flush = false) override; void reset() override; private: struct ConverterDeleter { - void operator()(UConverter* pointer) const { ucnv_close(pointer); } + void operator()(UConverter* pointer) const { + ucnv_close(pointer); + } }; Encoding encoding; @@ -144,17 +147,20 @@ class TextDecoder final: public jsg::Object { }; static jsg::Ref constructor( - jsg::Optional label, - jsg::Optional options); + jsg::Optional label, jsg::Optional options); jsg::JsString decode(jsg::Lock& js, - jsg::Optional> input, - jsg::Optional options); + jsg::Optional> input, + jsg::Optional options); kj::StringPtr getEncoding(); - bool getFatal() { return ctorOptions.fatal; } - bool getIgnoreBom() { return ctorOptions.ignoreBOM; } + bool getFatal() { + return ctorOptions.fatal; + } + bool getIgnoreBom() { + return ctorOptions.ignoreBOM; + } JSG_RESOURCE_TYPE(TextDecoder, CompatibilityFlags::Reader flags) { JSG_METHOD(decode); @@ -172,11 +178,11 @@ class TextDecoder final: public jsg::Object { explicit TextDecoder(DecoderImpl decoder): decoder(kj::mv(decoder)) {} explicit TextDecoder(DecoderImpl decoder, const ConstructorOptions& options) - : decoder(kj::mv(decoder)), ctorOptions(options) {} + : decoder(kj::mv(decoder)), + ctorOptions(options) {} - kj::Maybe decodePtr(jsg::Lock& js, - kj::ArrayPtr buffer, - bool flush); + kj::Maybe decodePtr( + jsg::Lock& js, kj::ArrayPtr buffer, bool flush); private: Decoder& getImpl(); @@ -205,12 +211,12 @@ class TextEncoder final: public jsg::Object { jsg::BufferSource encode(jsg::Lock& js, jsg::Optional input); - EncodeIntoResult encodeInto(jsg::Lock& js, - jsg::JsString input, - jsg::BufferSource buffer); + EncodeIntoResult encodeInto(jsg::Lock& js, jsg::JsString input, jsg::BufferSource buffer); // UTF-8 is the only encoding type supported by the WHATWG spec. - kj::StringPtr getEncoding() { return "utf-8"; } + kj::StringPtr getEncoding() { + return "utf-8"; + } JSG_RESOURCE_TYPE(TextEncoder, CompatibilityFlags::Reader flags) { JSG_METHOD(encode); @@ -230,10 +236,7 @@ class TextEncoder final: public jsg::Object { } }; -#define EW_ENCODING_ISOLATE_TYPES \ - api::TextDecoder, \ - api::TextEncoder, \ - api::TextDecoder::ConstructorOptions, \ - api::TextDecoder::DecodeOptions, \ - api::TextEncoder::EncodeIntoResult +#define EW_ENCODING_ISOLATE_TYPES \ + api::TextDecoder, api::TextEncoder, api::TextDecoder::ConstructorOptions, \ + api::TextDecoder::DecodeOptions, api::TextEncoder::EncodeIntoResult } // namespace workerd::api diff --git a/src/workerd/api/events.c++ b/src/workerd/api/events.c++ index 8a6e025d4f6..617bc70cc18 100644 --- a/src/workerd/api/events.c++ +++ b/src/workerd/api/events.c++ @@ -3,12 +3,11 @@ namespace workerd::api { ErrorEvent::ErrorEvent(kj::String type, ErrorEventInit init) - : Event(kj::mv(type)), init(kj::mv(init)) {} + : Event(kj::mv(type)), + init(kj::mv(init)) {} jsg::Ref ErrorEvent::constructor( - jsg::Lock& js, - kj::String type, - jsg::Optional init) { + jsg::Lock& js, kj::String type, jsg::Optional init) { return jsg::alloc(kj::mv(type), kj::mv(init).orDefault({})); } diff --git a/src/workerd/api/events.h b/src/workerd/api/events.h index 27eee3ad54c..83d00c999d2 100644 --- a/src/workerd/api/events.h +++ b/src/workerd/api/events.h @@ -19,9 +19,7 @@ class ErrorEvent: public Event { ErrorEvent(kj::String type, ErrorEventInit init); static jsg::Ref constructor( - jsg::Lock& js, - kj::String type, - jsg::Optional init); + jsg::Lock& js, kj::String type, jsg::Optional init); kj::StringPtr getFilename(); kj::StringPtr getMessage(); @@ -49,8 +47,6 @@ class ErrorEvent: public Event { void visitForGc(jsg::GcVisitor& visitor); }; -#define EW_EVENTS_ISOLATE_TYPES \ - api::ErrorEvent, \ - api::ErrorEvent::ErrorEventInit +#define EW_EVENTS_ISOLATE_TYPES api::ErrorEvent, api::ErrorEvent::ErrorEventInit } // namespace workerd::api diff --git a/src/workerd/api/eventsource.c++ b/src/workerd/api/eventsource.c++ index d3b2a139ad9..a73bad51e61 100644 --- a/src/workerd/api/eventsource.c++ +++ b/src/workerd/api/eventsource.c++ @@ -14,7 +14,7 @@ namespace workerd::api { namespace { class EventSourceSink final: public WritableStreamSink { public: - EventSourceSink(EventSource& eventSource) : eventSource(eventSource) {} + EventSourceSink(EventSource& eventSource): eventSource(eventSource) {} kj::Promise write(kj::ArrayPtr buffer) override { // The event stream is a new-line delimited format where each line represents an event. @@ -37,21 +37,18 @@ public: // codepoint U+FEFF. We only want to check for this once. if (!bomChecked) { bomChecked = true; - if (input.size() >= 3 && - input[0] == '\xEF' && - input[1] == '\xBB' && - input[2] == '\xBF') { + if (input.size() >= 3 && input[0] == '\xEF' && input[1] == '\xBB' && input[2] == '\xBF') { input = input.slice(3); } } while (input != nullptr) { KJ_IF_SOME(found, findEndOfLine(input)) { - auto prefix = kept.releaseAsArray(); - // Feed the line into the processor. - feed(kj::str(prefix, input.slice(0, found.pos))); - input = found.remaining; - // If we've reached the end of the input, input will == nullptr here. + auto prefix = kept.releaseAsArray(); + // Feed the line into the processor. + feed(kj::str(prefix, input.slice(0, found.pos))); + input = found.remaining; + // If we've reached the end of the input, input will == nullptr here. } else { // No end-of-line found, buffer the input. kept.addAll(input.begin(), input.end()); @@ -66,7 +63,7 @@ public: } kj::Promise write(kj::ArrayPtr> pieces) override { - for (auto& piece : pieces) { + for (auto& piece: pieces) { co_await write(piece); } co_return; @@ -144,8 +141,8 @@ private: } else if (line[0] == ':') { // Ignore the line. } else { - static constexpr auto handle = - [](auto& self, kj::ArrayPtr field, kj::ArrayPtr value) { + static constexpr auto handle = [](auto& self, kj::ArrayPtr field, + kj::ArrayPtr value) { auto& pending = self.getPendingMessage(); auto& ev = KJ_ASSERT_NONNULL(self.eventSource); // Per the spec, only one space after the colon is optional and trimmed. @@ -232,9 +229,7 @@ kj::Promise processBody(IoContext& context, kj::Promise EventSource::constructor( - jsg::Lock& js, - kj::String url, - jsg::Optional init) { + jsg::Lock& js, kj::String url, jsg::Optional init) { JSG_REQUIRE(IoContext::hasCurrent(), DOMNotSupportedError, "An EventSource can only be created within the context of a worker request."); @@ -246,9 +241,8 @@ jsg::Ref EventSource::constructor( } auto eventsource = jsg::alloc(js, - JSG_REQUIRE_NONNULL(jsg::Url::tryParse(url.asPtr()), - DOMSyntaxError, - kj::str("Cannot open an EventSource to '", url ,"'. The URL is invalid.")), + JSG_REQUIRE_NONNULL(jsg::Url::tryParse(url.asPtr()), DOMSyntaxError, + kj::str("Cannot open an EventSource to '", url, "'. The URL is invalid.")), kj::mv(init)); eventsource->start(js); return kj::mv(eventsource); @@ -257,10 +251,9 @@ jsg::Ref EventSource::constructor( jsg::Ref EventSource::from(jsg::Lock& js, jsg::Ref readable) { JSG_REQUIRE(IoContext::hasCurrent(), DOMNotSupportedError, "An EventSource can only be created within the context of a worker request."); - JSG_REQUIRE(!readable->isLocked(), TypeError, - "This ReadableStream is locked."); - JSG_REQUIRE(!readable->isDisturbed(), TypeError, - "This ReadableStream has already been read from."); + JSG_REQUIRE(!readable->isLocked(), TypeError, "This ReadableStream is locked."); + JSG_REQUIRE( + !readable->isDisturbed(), TypeError, "This ReadableStream has already been read from."); auto eventsource = jsg::alloc(js); eventsource->run(js, kj::mv(readable), false /* No reconnection attempts */); return kj::mv(eventsource); @@ -287,8 +280,10 @@ void EventSource::notifyError(jsg::Lock& js, const jsg::JsValue& error, bool rec // controller has already been aborted. abortController->abort(js, error); - if (!reconnecting) readyState = State::CLOSED; - else readyState = State::CONNECTING; + if (!reconnecting) + readyState = State::CLOSED; + else + readyState = State::CONNECTING; // Dispatch the error event. dispatchEventImpl(js, jsg::alloc(js, error)); @@ -306,14 +301,12 @@ void EventSource::notifyOpen(jsg::Lock& js) { void EventSource::notifyMessages(jsg::Lock& js, kj::Array messages) { if (readyState == State::CLOSED) return; js.tryCatch([&] { - for (auto& message : messages) { - auto data = kj::str(kj::delimited(kj::mv(message.data), "\n"_kjc)); - if (data.size() == 0) continue; - dispatchEventImpl(js, jsg::alloc( - kj::mv(message.event), - kj::mv(data), - kj::mv(message.id), - impl.map([](FetchImpl& i) -> jsg::Url& { return i.url; }))); + for (auto& message: messages) { + auto data = kj::str(kj::delimited(kj::mv(message.data), "\n"_kjc)); + if (data.size() == 0) continue; + dispatchEventImpl(js, + jsg::alloc(kj::mv(message.event), kj::mv(data), kj::mv(message.id), + impl.map([](FetchImpl& i) -> jsg::Url& { return i.url; }))); } }, [&](jsg::Value exception) { // If we end up with an exception being thrown in one of the event handlers, we will @@ -328,13 +321,14 @@ void EventSource::reconnect(jsg::Lock& js) { abortController = jsg::alloc(); auto signal = abortController->getSignal(); context.awaitIo(js, signal->wrap(context.afterLimitTimeout(reconnectionTime))) - .then(js, JSG_VISITABLE_LAMBDA((self=JSG_THIS), (self), (jsg::Lock& js) mutable { - self->start(js); - }), JSG_VISITABLE_LAMBDA((self=JSG_THIS),(self),(jsg::Lock& js, jsg::Value exception) { - // In this case, it is most likely the EventSource was closed by the user or - // there was some other failure. We should not continue trying to reconnect. - self->notifyError(js, jsg::JsValue(exception.getHandle(js))); - })); + .then(js, + JSG_VISITABLE_LAMBDA( + (self = JSG_THIS), (self), (jsg::Lock & js) mutable { self->start(js); }), + JSG_VISITABLE_LAMBDA((self = JSG_THIS), (self), (jsg::Lock& js, jsg::Value exception) { + // In this case, it is most likely the EventSource was closed by the user or + // there was some other failure. We should not continue trying to reconnect. + self->notifyError(js, jsg::JsValue(exception.getHandle(js))); + })); } void EventSource::start(jsg::Lock& js) { @@ -351,92 +345,91 @@ void EventSource::start(jsg::Lock& js) { }; auto onSuccess = JSG_VISITABLE_LAMBDA( - (self=JSG_THIS, - fetcher = fetcher.map([](jsg::Ref& f) -> jsg::Ref { return f.addRef(); })), - (self, fetcher), - (jsg::Lock& js, jsg::Ref response) { - if (self->readyState == State::CLOSED) return js.resolvedPromise(); - auto& impl = KJ_ASSERT_NONNULL(self->impl); - if (!response->getOk()) { - // Response status code is not 2xx, so we fail. - // No reconnection attempt should be made. - return handleError(js, self, - kj::str("The response status code was ", response->getStatus(), ".")); - } + (self = JSG_THIS, fetcher = fetcher.map([](jsg::Ref& f) -> jsg::Ref { + return f.addRef(); + })), + (self, fetcher), (jsg::Lock& js, jsg::Ref response) { + if (self->readyState == State::CLOSED) return js.resolvedPromise(); + auto& impl = KJ_ASSERT_NONNULL(self->impl); + if (!response->getOk()) { + // Response status code is not 2xx, so we fail. + // No reconnection attempt should be made. + return handleError( + js, self, kj::str("The response status code was ", response->getStatus(), ".")); + } - // TODO(cleanup): Using jsg::ByteString here is really annoying. It would be nice to have - // an internal alternative that doesn't require an allocation. - KJ_IF_SOME(contentType, response->getHeaders(js)->get( - jsg::ByteString(kj::str("content-type")))) { - bool invalid = false; - KJ_IF_SOME(parsed, MimeType::tryParse(contentType)) { + // TODO(cleanup): Using jsg::ByteString here is really annoying. It would be nice to have + // an internal alternative that doesn't require an allocation. + KJ_IF_SOME(contentType, + response->getHeaders(js)->get(jsg::ByteString(kj::str("content-type")))) { + bool invalid = false; + KJ_IF_SOME(parsed, MimeType::tryParse(contentType)) { invalid = parsed != MimeType::EVENT_STREAM; - } else { + } else { invalid = true; - } - if (invalid) { + } + if (invalid) { // No reconnection attempt should be made. return handleError(js, self, kj::str("The content type '", contentType, "' is invalid.")); - } - } else { - // No reconnection attempt should be made. - return handleError(js, self, kj::str("No content type header was present in the response.")); - } + } + } else { + // No reconnection attempt should be made. + return handleError( + js, self, kj::str("No content type header was present in the response.")); + } - // If the request was redirected, update the URL to the new location. - if (response->getRedirected()) { - KJ_IF_SOME(newUrl, jsg::Url::tryParse(response->getUrl())) { + // If the request was redirected, update the URL to the new location. + if (response->getRedirected()) { + KJ_IF_SOME(newUrl, jsg::Url::tryParse(response->getUrl())) { impl.url = kj::mv(newUrl); - } else {} // Extra else block to squash compiler warning - } + } else { + } // Extra else block to squash compiler warning + } - KJ_IF_SOME(body, response->getBody()) { - // Well, ok! We're ready to start trying to process the stream! We do so by - // pumping the body into an EventSourceSink until the body is closed, canceled, - // or errored. - self->run(js, kj::mv(body), true, response.addRef(), kj::mv(fetcher)); - return js.resolvedPromise(); - } else { - auto& i = KJ_ASSERT_NONNULL(self->impl); - // If there is no body, there's nothing to do. We'll treat this as if - // the server disconnected. If it only happens once, we'll try to reconnect. - // If it happens again, we'll fail the connection as it is likely indicative - // of a bug in the server or along the path to the server. - if (i.previousNoBody) { - self->notifyError(js, js.error("The server provided no content.")); - } else { + KJ_IF_SOME(body, response->getBody()) { + // Well, ok! We're ready to start trying to process the stream! We do so by + // pumping the body into an EventSourceSink until the body is closed, canceled, + // or errored. + self->run(js, kj::mv(body), true, response.addRef(), kj::mv(fetcher)); + return js.resolvedPromise(); + } else { + auto& i = KJ_ASSERT_NONNULL(self->impl); + // If there is no body, there's nothing to do. We'll treat this as if + // the server disconnected. If it only happens once, we'll try to reconnect. + // If it happens again, we'll fail the connection as it is likely indicative + // of a bug in the server or along the path to the server. + if (i.previousNoBody) { + self->notifyError(js, js.error("The server provided no content.")); + } else { i.previousNoBody = true; - self->notifyError(js, - js.error("The server provided no content. Will try reconnecting."), + self->notifyError(js, js.error("The server provided no content. Will try reconnecting."), true /* reconnecting */); self->reconnect(js); - } - return js.resolvedPromise(); - } - }); + } + return js.resolvedPromise(); + } + }); - auto onFailed = JSG_VISITABLE_LAMBDA( - (self=JSG_THIS), - (self), - (jsg::Lock& js, jsg::Value exception) { - self->notifyError(js, jsg::JsValue(exception.getHandle(js))); - return js.resolvedPromise(); - }); + auto onFailed = + JSG_VISITABLE_LAMBDA((self = JSG_THIS), (self), (jsg::Lock& js, jsg::Value exception) { + self->notifyError(js, jsg::JsValue(exception.getHandle(js))); + return js.resolvedPromise(); + }); auto headers = jsg::alloc(); - headers->set(jsg::ByteString(kj::str("accept")), - jsg::ByteString(MimeType::EVENT_STREAM.essence())); - headers->set(jsg::ByteString(kj::str("cache-control")), - jsg::ByteString(kj::str("no-cache"))); + headers->set( + jsg::ByteString(kj::str("accept")), jsg::ByteString(MimeType::EVENT_STREAM.essence())); + headers->set(jsg::ByteString(kj::str("cache-control")), jsg::ByteString(kj::str("no-cache"))); if (lastEventId != ""_kjc) { - headers->set(jsg::ByteString(kj::str("last-event-id")), - jsg::ByteString(kj::str(lastEventId))); + headers->set(jsg::ByteString(kj::str("last-event-id")), jsg::ByteString(kj::str(lastEventId))); } - fetchImpl(js, kj::mv(fetcher), kj::str(i.url), RequestInitializerDict { - .headers = kj::mv(headers), - .signal = abortController->getSignal(), - }).then(js, kj::mv(onSuccess), kj::mv(onFailed)); + fetchImpl(js, kj::mv(fetcher), kj::str(i.url), + RequestInitializerDict{ + .headers = kj::mv(headers), + .signal = abortController->getSignal(), + }) + .then(js, kj::mv(onSuccess), kj::mv(onFailed)); } namespace { @@ -447,39 +440,37 @@ kj::Maybe> addRef(kj::Maybe>& ref) { } // namespace void EventSource::run(jsg::Lock& js, - jsg::Ref readable, - bool withReconnection, - kj::Maybe> response, - kj::Maybe> fetcher) { + jsg::Ref readable, + bool withReconnection, + kj::Maybe> response, + kj::Maybe> fetcher) { notifyOpen(js); - auto onSuccess = JSG_VISITABLE_LAMBDA( - (self=JSG_THIS, readable=readable.addRef(), withReconnection, - response=addRef(response), - fetcher=addRef(fetcher)), - (self, readable, response, fetcher), - (jsg::Lock& js) { - // The pump finished. Did the server disconnect? If so, try reconnecting if we can. - self->notifyError(js, js.error("The server disconnected."), withReconnection); - if (withReconnection) self->reconnect(js); - }); + auto onSuccess = + JSG_VISITABLE_LAMBDA((self = JSG_THIS, readable = readable.addRef(), withReconnection, + response = addRef(response), fetcher = addRef(fetcher)), + (self, readable, response, fetcher), (jsg::Lock& js) { + // The pump finished. Did the server disconnect? If so, try reconnecting if we can. + self->notifyError(js, js.error("The server disconnected."), withReconnection); + if (withReconnection) self->reconnect(js); + }); auto onFailed = JSG_VISITABLE_LAMBDA( - (self=JSG_THIS, response=addRef(response), fetcher=addRef(fetcher)), - (self, response, fetcher), - (jsg::Lock& js, jsg::Value exception) { - // If the pump fails, catch the error and convert it into an error event. - // If we got here, it likely isn't just a DISCONNECT event. Let's not - // try to reconnect at this point. - self->notifyError(js, jsg::JsValue(exception.getHandle(js))); - }); + (self = JSG_THIS, response = addRef(response), fetcher = addRef(fetcher)), + (self, response, fetcher), (jsg::Lock& js, jsg::Value exception) { + // If the pump fails, catch the error and convert it into an error event. + // If we got here, it likely isn't just a DISCONNECT event. Let's not + // try to reconnect at this point. + self->notifyError(js, jsg::JsValue(exception.getHandle(js))); + }); // Well, ok! We're ready to start trying to process the stream! We do so by // pumping the body into an EventSourceSink until the body is closed, canceled, // or errored. - context.awaitIo(js, - processBody(context, readable->pumpTo(js, kj::heap(*this), true))) - .then(js, kj::mv(onSuccess), kj::mv(onFailed)); + context + .awaitIo( + js, processBody(context, readable->pumpTo(js, kj::heap(*this), true))) + .then(js, kj::mv(onSuccess), kj::mv(onFailed)); } void EventSource::close(jsg::Lock& js) { @@ -490,9 +481,8 @@ void EventSource::close(jsg::Lock& js) { } void EventSource::enqueueMessages(kj::Array messages) { - context.addTask(context.run([this, messages=kj::mv(messages)](auto& lock) mutable { - notifyMessages(lock, kj::mv(messages)); - })); + context.addTask(context.run([this, messages = kj::mv(messages)]( + auto& lock) mutable { notifyMessages(lock, kj::mv(messages)); })); } void EventSource::setReconnectionTime(uint32_t time) { @@ -502,7 +492,9 @@ void EventSource::setReconnectionTime(uint32_t time) { kj::max(kj::min(time, MAX_RECONNECTION_TIME), MIN_RECONNECTION_TIME) * kj::MILLISECONDS; } -kj::StringPtr EventSource::getLastEventId() { return lastEventId; } +kj::StringPtr EventSource::getLastEventId() { + return lastEventId; +} void EventSource::setLastEventId(kj::String id) { lastEventId = kj::mv(id); diff --git a/src/workerd/api/eventsource.h b/src/workerd/api/eventsource.h index 2217b901242..e08726fb49d 100644 --- a/src/workerd/api/eventsource.h +++ b/src/workerd/api/eventsource.h @@ -33,12 +33,14 @@ class EventSource: public EventTarget { private: jsg::JsRef error; - jsg::JsValue getError(jsg::Lock& js) { return error.getHandle(js); } + jsg::JsValue getError(jsg::Lock& js) { + return error.getHandle(js); + } }; class OpenEvent final: public Event { public: - OpenEvent() : Event(kj::str("open")) {} + OpenEvent(): Event(kj::str("open")) {} static jsg::Ref constructor() = delete; JSG_RESOURCE_TYPE(OpenEvent) { JSG_INHERIT(Event); @@ -48,10 +50,10 @@ class EventSource: public EventTarget { class MessageEvent final: public Event { public: explicit MessageEvent(kj::Maybe type, - kj::String data, - kj::String lastEventId, - kj::Maybe url) - : Event(kj::mv(type).orDefault([] { return kj::str("message");})), + kj::String data, + kj::String lastEventId, + kj::Maybe url) + : Event(kj::mv(type).orDefault([] { return kj::str("message"); })), data(kj::mv(data)), lastEventId(kj::mv(lastEventId)), origin(url.map([](auto& url) { return url.getOrigin(); })) {} @@ -69,8 +71,12 @@ class EventSource: public EventTarget { kj::String lastEventId; kj::Maybe> origin; - kj::StringPtr getData() { return data; } - kj::StringPtr getLastEventId() { return lastEventId; } + kj::StringPtr getData() { + return data; + } + kj::StringPtr getLastEventId() { + return lastEventId; + } kj::Maybe> getOrigin() { return origin.map([](auto& a) -> kj::ArrayPtr { return a.asPtr(); }); } @@ -97,9 +103,8 @@ class EventSource: public EventTarget { EventSource(jsg::Lock& js); - static jsg::Ref constructor(jsg::Lock& js, - kj::String url, - jsg::Optional init); + static jsg::Ref constructor( + jsg::Lock& js, kj::String url, jsg::Optional init); kj::ArrayPtr getUrl() const { KJ_IF_SOME(i, impl) { @@ -107,8 +112,12 @@ class EventSource: public EventTarget { } return nullptr; } - bool getWithCredentials() const { return false; } - uint getReadyState() const { return static_cast(readyState); } + bool getWithCredentials() const { + return false; + } + uint getReadyState() const { + return static_cast(readyState); + } void close(jsg::Lock& js); @@ -120,9 +129,8 @@ class EventSource: public EventTarget { static jsg::Ref from(jsg::Lock& js, jsg::Ref stream); kj::Maybe getOnOpen(jsg::Lock& js) { - return onopenValue.map([&](jsg::JsRef& ref) -> jsg::JsValue { - return ref.getHandle(js); - }); + return onopenValue.map( + [&](jsg::JsRef& ref) -> jsg::JsValue { return ref.getHandle(js); }); } void setOnOpen(jsg::Lock& js, jsg::JsValue value) { if (!value.isObject() && !value.isFunction()) { @@ -132,9 +140,8 @@ class EventSource: public EventTarget { } } kj::Maybe getOnMessage(jsg::Lock& js) { - return onmessageValue.map([&](jsg::JsRef& ref) -> jsg::JsValue { - return ref.getHandle(js); - }); + return onmessageValue.map( + [&](jsg::JsRef& ref) -> jsg::JsValue { return ref.getHandle(js); }); } void setOnMessage(jsg::Lock& js, jsg::JsValue value) { if (!value.isObject() && !value.isFunction()) { @@ -144,9 +151,8 @@ class EventSource: public EventTarget { } } kj::Maybe getOnError(jsg::Lock& js) { - return onerrorValue.map([&](jsg::JsRef& ref) -> jsg::JsValue { - return ref.getHandle(js); - }); + return onerrorValue.map( + [&](jsg::JsRef& ref) -> jsg::JsValue { return ref.getHandle(js); }); } void setOnError(jsg::Lock& js, jsg::JsValue value) { if (!value.isObject() && !value.isFunction()) { @@ -244,10 +250,10 @@ class EventSource: public EventTarget { // The run() method handles the actual processing of the stream. void run(jsg::Lock& js, - jsg::Ref stream, - bool withReconnection = true, - kj::Maybe> response = kj::none, - kj::Maybe> fetcher = kj::none); + jsg::Ref stream, + bool withReconnection = true, + kj::Maybe> response = kj::none, + kj::Maybe> fetcher = kj::none); // The start() method initializes the fetch and the processing of the // stream by calling run. void start(jsg::Lock& js); @@ -256,9 +262,6 @@ class EventSource: public EventTarget { } // namespace workerd::api -#define EW_EVENTSOURCE_ISOLATE_TYPES \ - api::EventSource, \ - api::EventSource::ErrorEvent, \ - api::EventSource::OpenEvent, \ - api::EventSource::MessageEvent, \ - api::EventSource::EventSourceInit +#define EW_EVENTSOURCE_ISOLATE_TYPES \ + api::EventSource, api::EventSource::ErrorEvent, api::EventSource::OpenEvent, \ + api::EventSource::MessageEvent, api::EventSource::EventSourceInit diff --git a/src/workerd/api/form-data.c++ b/src/workerd/api/form-data.c++ index 47e2f2352ad..75cc8fad68c 100644 --- a/src/workerd/api/form-data.c++ +++ b/src/workerd/api/form-data.c++ @@ -20,13 +20,12 @@ namespace workerd::api { namespace { // Like split() in kj/compat/url.c++, but splits at a substring rather than a character. -kj::ArrayPtr splitAtSubString( - kj::ArrayPtr& text, kj::StringPtr subString) { +kj::ArrayPtr splitAtSubString(kj::ArrayPtr& text, kj::StringPtr subString) { // TODO(perf): Use a Boyer-Moore search? auto iter = std::search(text.begin(), text.end(), subString.begin(), subString.end()); auto result = kj::arrayPtr(text.begin(), iter - text.begin()); - text = text.slice(kj::min(text.size(), result.end() - text.begin() + subString.size()), - text.size()); + text = + text.slice(kj::min(text.size(), result.end() - text.begin() + subString.size()), text.size()); return result; } @@ -50,25 +49,28 @@ const FormDataHeaderTable& getFormDataHeaderTable() { namespace p = kj::parse; constexpr auto httpIdentifier = p::oneOrMore(p::nameChar.orChar('-')); -constexpr auto quotedChar = p::oneOf( - p::anyOfChars("\"\n\\").invert(), +constexpr auto quotedChar = p::oneOf(p::anyOfChars("\"\n\\").invert(), // Chrome interprets "\" as reducing to for any character , including double quote. // (So "\n" = "n", etc.) p::sequence(p::exactChar<'\\'>(), p::anyOfChars("\n").invert())); -constexpr auto contentDispositionParam = - p::sequence(p::exactChar<';'>(), p::discardWhitespace, - httpIdentifier, p::discardWhitespace, - p::exactChar<'='>(), p::discardWhitespace, - p::exactChar<'"'>(), - p::oneOrMore(quotedChar), - p::exactChar<'"'>(), p::discardWhitespace); -constexpr auto contentDisposition = - p::sequence(p::discardWhitespace, httpIdentifier, - p::discardWhitespace, p::many(contentDispositionParam)); - -void parseFormData(kj::Maybe js, kj::Vector& data, - kj::StringPtr boundary, kj::ArrayPtr body, - bool convertFilesToStrings) { +constexpr auto contentDispositionParam = p::sequence(p::exactChar<';'>(), + p::discardWhitespace, + httpIdentifier, + p::discardWhitespace, + p::exactChar<'='>(), + p::discardWhitespace, + p::exactChar<'"'>(), + p::oneOrMore(quotedChar), + p::exactChar<'"'>(), + p::discardWhitespace); +constexpr auto contentDisposition = p::sequence( + p::discardWhitespace, httpIdentifier, p::discardWhitespace, p::many(contentDispositionParam)); + +void parseFormData(kj::Maybe js, + kj::Vector& data, + kj::StringPtr boundary, + kj::ArrayPtr body, + bool convertFilesToStrings) { // multipart/form-data messages are delimited by --. We want to be able to handle // omitted carriage returns, though, so our delimiter only matches against a preceding line feed. const auto delimiter = kj::str("\n--", boundary); @@ -78,8 +80,8 @@ void parseFormData(kj::Maybe js, kj::Vector& data, // newline is required. auto message = splitAtSubString(body, delimiter.slice(1)); - JSG_REQUIRE(body.size() > 0, TypeError, - "No initial boundary string (or you have a truncated message)."); + JSG_REQUIRE( + body.size() > 0, TypeError, "No initial boundary string (or you have a truncated message)."); const auto done = [](kj::ArrayPtr& body) { // Consume any (CR)LF characters that trailed the boundary and indicate continuation, or consume @@ -97,8 +99,8 @@ void parseFormData(kj::Maybe js, kj::Vector& data, return false; }; - constexpr auto staticRegexFlags = std::regex_constants::ECMAScript - | std::regex_constants::optimize; + constexpr auto staticRegexFlags = + std::regex_constants::ECMAScript | std::regex_constants::optimize; static const auto headerTerminationRegex = std::regex("\r?\n\r?\n", staticRegexFlags); @@ -108,7 +110,7 @@ void parseFormData(kj::Maybe js, kj::Vector& data, while (!done(body)) { JSG_REQUIRE(std::regex_search(body.begin(), body.end(), match, headerTerminationRegex), - TypeError, "No multipart message header termination found."); + TypeError, "No multipart message header termination found."); // TODO(cleanup): Use kj-http to parse multipart headers. Right now that API isn't public, so // I'm just using a regex. For reference, multipart/form-data supports the following three @@ -126,19 +128,20 @@ void parseFormData(kj::Maybe js, kj::Vector& data, kj::HttpHeaders headers(*formDataHeaderTable.table); JSG_REQUIRE(headers.tryParse(headersText), TypeError, "FormData part had invalid headers."); - kj::StringPtr disposition = JSG_REQUIRE_NONNULL( - headers.get(formDataHeaderTable.contentDispositionId), - TypeError, "No valid Content-Disposition header found in FormData part."); + kj::StringPtr disposition = + JSG_REQUIRE_NONNULL(headers.get(formDataHeaderTable.contentDispositionId), TypeError, + "No valid Content-Disposition header found in FormData part."); kj::Maybe maybeName; kj::Maybe filename; { p::IteratorInput input(disposition.begin(), disposition.end()); - auto result = JSG_REQUIRE_NONNULL(contentDisposition(input), - TypeError, "Invalid Content-Disposition header found in FormData part."); + auto result = JSG_REQUIRE_NONNULL(contentDisposition(input), TypeError, + "Invalid Content-Disposition header found in FormData part."); JSG_REQUIRE(kj::get<0>(result) == "form-data"_kj.asArray(), TypeError, "Content-Disposition header for FormData part must have the value \"form-data\", " - "possibly followed by parameters. Got: \"", kj::get<0>(result), "\""); + "possibly followed by parameters. Got: \"", + kj::get<0>(result), "\""); for (auto& param: kj::get<1>(result)) { if (kj::get<0>(param) == "name"_kj.asArray()) { @@ -149,14 +152,14 @@ void parseFormData(kj::Maybe js, kj::Vector& data, } } - kj::String name = JSG_REQUIRE_NONNULL(kj::mv(maybeName), - TypeError, "Content-Disposition header in FormData part is missing a name."); + kj::String name = JSG_REQUIRE_NONNULL(kj::mv(maybeName), TypeError, + "Content-Disposition header in FormData part is missing a name."); kj::Maybe type = headers.get(kj::HttpHeaderId::CONTENT_TYPE); message = splitAtSubString(body, delimiter); - JSG_REQUIRE(body.size() > 0, TypeError, - "No subsequent boundary string after multipart message."); + JSG_REQUIRE( + body.size() > 0, TypeError, "No subsequent boundary string after multipart message."); if (message.size() > 0) { // If we skipped a CR, we must avoid including it in the message data. @@ -164,35 +167,29 @@ void parseFormData(kj::Maybe js, kj::Vector& data, } if (filename == kj::none || convertFilesToStrings) { - data.add(FormData::Entry { kj::mv(name), kj::str(message) }); + data.add(FormData::Entry{kj::mv(name), kj::str(message)}); } else { auto bytes = kj::heapArray(message.asBytes()); KJ_IF_SOME(lock, js) { - data.add(FormData::Entry { - kj::mv(name), - jsg::alloc(lock, kj::mv(bytes), - KJ_ASSERT_NONNULL(kj::mv(filename)), - kj::str(type.orDefault(nullptr)), dateNow()) - }); + data.add(FormData::Entry{kj::mv(name), + jsg::alloc(lock, kj::mv(bytes), KJ_ASSERT_NONNULL(kj::mv(filename)), + kj::str(type.orDefault(nullptr)), dateNow())}); } else { // This variation is used when we do not have an isolate lock. In this // case, the external memory held by the File is not tracked towards // the isolate's external memory. - data.add(FormData::Entry { - kj::mv(name), - jsg::alloc(kj::mv(bytes), - KJ_ASSERT_NONNULL(kj::mv(filename)), - kj::str(type.orDefault(nullptr)), dateNow()) - }); + data.add(FormData::Entry{kj::mv(name), + jsg::alloc(kj::mv(bytes), KJ_ASSERT_NONNULL(kj::mv(filename)), + kj::str(type.orDefault(nullptr)), dateNow())}); } } } } -kj::OneOf, kj::String> -blobToFile(jsg::Lock& js, kj::StringPtr name, - kj::OneOf, jsg::Ref, kj::String> value, - jsg::Optional filename) { +kj::OneOf, kj::String> blobToFile(jsg::Lock& js, + kj::StringPtr name, + kj::OneOf, jsg::Ref, kj::String> value, + jsg::Optional filename) { auto fromBlob = [&](jsg::Ref blob) { kj::String fn; KJ_IF_SOME(f, filename) { @@ -202,8 +199,8 @@ blobToFile(jsg::Lock& js, kj::StringPtr name, } // The file is created with the same data as the blob (essentially as just // a view of the same blob) to avoid copying the data. - return jsg::alloc(blob.addRef(), blob->getData(), kj::mv(fn), - kj::str(blob->getType()), dateNow()); + return jsg::alloc( + blob.addRef(), blob->getData(), kj::mv(fn), kj::str(blob->getType()), dateNow()); }; KJ_SWITCH_ONEOF(value) { @@ -315,8 +312,10 @@ FormData::EntryType FormData::clone(FormData::EntryType& value) { KJ_UNREACHABLE; } -void FormData::parse(kj::Maybe js, kj::ArrayPtr rawText, - kj::StringPtr contentType, bool convertFilesToStrings) { +void FormData::parse(kj::Maybe js, + kj::ArrayPtr rawText, + kj::StringPtr contentType, + bool convertFilesToStrings) { KJ_IF_SOME(parsed, MimeType::tryParse(contentType)) { auto& params = parsed.params(); if (MimeType::FORM_DATA == parsed) { @@ -333,40 +332,40 @@ void FormData::parse(kj::Maybe js, kj::ArrayPtr rawText, KJ_IF_SOME(charsetParam, params.find("charset"_kj)) { auto charset = kj::str(charsetParam); JSG_REQUIRE(strcasecmp(charset.cStr(), "utf-8") == 0 || - strcasecmp(charset.cStr(), "utf8") == 0 || - strcasecmp(charset.cStr(), "unicode-1-1-utf-8") == 0, + strcasecmp(charset.cStr(), "utf8") == 0 || + strcasecmp(charset.cStr(), "unicode-1-1-utf-8") == 0, TypeError, "Non-utf-8 application/x-www-form-urlencoded body."); } kj::Vector query; parseQueryString(query, kj::mv(rawText)); data.reserve(query.size()); for (auto& param: query) { - data.add(Entry { kj::mv(param.name), kj::mv(param.value) }); + data.add(Entry{kj::mv(param.name), kj::mv(param.value)}); } return; } } - JSG_FAIL_REQUIRE(TypeError, kj::str( - "Unrecognized Content-Type header value. FormData can only " - "parse the following MIME types: ", - MimeType::FORM_DATA.toString(), ", ", - MimeType::FORM_URLENCODED.toString())); + JSG_FAIL_REQUIRE(TypeError, + kj::str("Unrecognized Content-Type header value. FormData can only " + "parse the following MIME types: ", + MimeType::FORM_DATA.toString(), ", ", MimeType::FORM_URLENCODED.toString())); } jsg::Ref FormData::constructor() { return jsg::alloc(); } -void FormData::append(jsg::Lock& js, kj::String name, +void FormData::append(jsg::Lock& js, + kj::String name, kj::OneOf, jsg::Ref, kj::String> value, jsg::Optional filename) { auto filifiedValue = blobToFile(js, name, kj::mv(value), kj::mv(filename)); - data.add(Entry { kj::mv(name), kj::mv(filifiedValue) }); + data.add(Entry{kj::mv(name), kj::mv(filifiedValue)}); } void FormData::delete_(kj::String name) { - auto pivot = std::remove_if(data.begin(), data.end(), - [&name](const auto& kv) { return kv.name == name; }); + auto pivot = + std::remove_if(data.begin(), data.end(), [&name](const auto& kv) { return kv.name == name; }); data.truncate(pivot - data.begin()); } @@ -399,7 +398,8 @@ bool FormData::has(kj::String name) { } // Set the first element named `name` to `value`, then remove all the rest matching that name. -void FormData::set(jsg::Lock& js, kj::String name, +void FormData::set(jsg::Lock& js, + kj::String name, kj::OneOf, jsg::Ref, kj::String> value, jsg::Optional filename) { const auto predicate = [name = name.slice(0)](const auto& kv) { return kv.name == name; }; @@ -414,19 +414,18 @@ void FormData::set(jsg::Lock& js, kj::String name, } jsg::Ref FormData::entries(jsg::Lock&) { - return jsg::alloc(IteratorState { JSG_THIS }); + return jsg::alloc(IteratorState{JSG_THIS}); } jsg::Ref FormData::keys(jsg::Lock&) { - return jsg::alloc(IteratorState { JSG_THIS }); + return jsg::alloc(IteratorState{JSG_THIS}); } jsg::Ref FormData::values(jsg::Lock&) { - return jsg::alloc(IteratorState { JSG_THIS }); + return jsg::alloc(IteratorState{JSG_THIS}); } -void FormData::forEach( - jsg::Lock& js, +void FormData::forEach(jsg::Lock& js, jsg::Function)> callback, jsg::Optional thisArg) { // Here, if the thisArg is not passed, or is passed explicitly as a null or diff --git a/src/workerd/api/global-scope.c++ b/src/workerd/api/global-scope.c++ index 66eff3ccf7d..005d48e058f 100644 --- a/src/workerd/api/global-scope.c++ +++ b/src/workerd/api/global-scope.c++ @@ -29,23 +29,19 @@ namespace workerd::api { namespace { -enum class NeuterReason { - SENT_RESPONSE, - THREW_EXCEPTION, - CLIENT_DISCONNECTED -}; +enum class NeuterReason { SENT_RESPONSE, THREW_EXCEPTION, CLIENT_DISCONNECTED }; kj::Exception makeNeuterException(NeuterReason reason) { switch (reason) { case NeuterReason::SENT_RESPONSE: - return JSG_KJ_EXCEPTION(FAILED, TypeError, - "Can't read from request stream after response has been sent."); + return JSG_KJ_EXCEPTION( + FAILED, TypeError, "Can't read from request stream after response has been sent."); case NeuterReason::THREW_EXCEPTION: - return JSG_KJ_EXCEPTION(FAILED, TypeError, - "Can't read from request stream after responding with an exception."); + return JSG_KJ_EXCEPTION( + FAILED, TypeError, "Can't read from request stream after responding with an exception."); case NeuterReason::CLIENT_DISCONNECTED: - return JSG_KJ_EXCEPTION(DISCONNECTED, TypeError, - "Can't read from request stream because client disconnected."); + return JSG_KJ_EXCEPTION( + DISCONNECTED, TypeError, "Can't read from request stream because client disconnected."); } KJ_UNREACHABLE; } @@ -65,9 +61,7 @@ kj::String getEventName(v8::PromiseRejectEvent type) { } // namespace PromiseRejectionEvent::PromiseRejectionEvent( - v8::PromiseRejectEvent type, - jsg::V8Ref promise, - jsg::Value reason) + v8::PromiseRejectEvent type, jsg::V8Ref promise, jsg::Value reason) : Event(getEventName(type)), promise(kj::mv(promise)), reason(kj::mv(reason)) {} @@ -91,35 +85,37 @@ void ExecutionContext::abort(jsg::Lock& js, jsg::Optional reason) { IoContext::current().abort(js.exceptionToKj(r.addRef(js))); js.throwException(kj::mv(r)); } else { - auto e = JSG_KJ_EXCEPTION(FAILED, Error, - "Worker execution was aborted due to call to ctx.abort()."); + auto e = + JSG_KJ_EXCEPTION(FAILED, Error, "Worker execution was aborted due to call to ctx.abort()."); IoContext::current().abort(kj::cp(e)); kj::throwFatalException(kj::mv(e)); } } ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(v8::Isolate* isolate) - : unhandledRejections( - [this](jsg::Lock& js, - v8::PromiseRejectEvent event, - jsg::V8Ref promise, - jsg::Value value) { - // If async context tracking is enabled, then we need to ensure that we enter the frame - // associated with the promise before we invoke the unhandled rejection callback handling. - auto ev = jsg::alloc(event, kj::mv(promise), kj::mv(value)); - dispatchEventImpl(js, kj::mv(ev)); - }) {} + : unhandledRejections([this](jsg::Lock& js, + v8::PromiseRejectEvent event, + jsg::V8Ref promise, + jsg::Value value) { + // If async context tracking is enabled, then we need to ensure that we enter the frame + // associated with the promise before we invoke the unhandled rejection callback handling. + auto ev = jsg::alloc(event, kj::mv(promise), kj::mv(value)); + dispatchEventImpl(js, kj::mv(ev)); + }) {} void ServiceWorkerGlobalScope::clear() { removeAllHandlers(); unhandledRejections.clear(); } -kj::Promise> ServiceWorkerGlobalScope::request( - kj::HttpMethod method, kj::StringPtr url, const kj::HttpHeaders& headers, - kj::AsyncInputStream& requestBody, kj::HttpService::Response& response, +kj::Promise> ServiceWorkerGlobalScope::request(kj::HttpMethod method, + kj::StringPtr url, + const kj::HttpHeaders& headers, + kj::AsyncInputStream& requestBody, + kj::HttpService::Response& response, kj::Maybe cfBlobJson, - Worker::Lock& lock, kj::Maybe exportedHandler) { + Worker::Lock& lock, + kj::Maybe exportedHandler) { TRACE_EVENT("workerd", "ServiceWorkerGlobalScope::request()"); // To construct a ReadableStream object, we're supposed to pass in an Own, so // that it can drop the reference whenever it gets GC'd. But in this case the stream's lifetime @@ -175,24 +171,21 @@ kj::Promise> ServiceWorkerGlobalScope::request( // If the request doesn't specify "Content-Length" or "Transfer-Encoding", set "Content-Length" // to the body length if it's known. This ensures handlers for worker-to-worker requests can // access known body lengths if they're set, without buffering bodies. - if (body != kj::none && - headers.get(kj::HttpHeaderId::CONTENT_LENGTH) == kj::none && + if (body != kj::none && headers.get(kj::HttpHeaderId::CONTENT_LENGTH) == kj::none && headers.get(kj::HttpHeaderId::TRANSFER_ENCODING) == kj::none) { // We can't use headers.set() here as headers is marked const. Instead, we call set() on the // JavaScript headers object, ignoring the REQUEST guard that usually makes them immutable. KJ_IF_SOME(l, requestBody.tryGetLength()) { - jsHeaders->setUnguarded(jsg::ByteString(kj::str("Content-Length")), - jsg::ByteString(kj::str(l))); + jsHeaders->setUnguarded( + jsg::ByteString(kj::str("Content-Length")), jsg::ByteString(kj::str(l))); } else { - jsHeaders->setUnguarded(jsg::ByteString(kj::str("Transfer-Encoding")), - jsg::ByteString(kj::str("chunked"))); + jsHeaders->setUnguarded( + jsg::ByteString(kj::str("Transfer-Encoding")), jsg::ByteString(kj::str("chunked"))); } } - auto jsRequest = jsg::alloc( - method, url, Request::Redirect::MANUAL, kj::mv(jsHeaders), - jsg::alloc(IoContext::NEXT_CLIENT_CHANNEL, - Fetcher::RequiresHostAndProtocol::YES), + auto jsRequest = jsg::alloc(method, url, Request::Redirect::MANUAL, kj::mv(jsHeaders), + jsg::alloc(IoContext::NEXT_CLIENT_CHANNEL, Fetcher::RequiresHostAndProtocol::YES), kj::none /** AbortSignal **/, kj::mv(cf), kj::mv(body)); // I set the redirect mode to manual here, so that by default scripts that just pass requests // through to a fetch() call will behave the same as scripts which don't call .respondWith(): if @@ -213,7 +206,7 @@ kj::Promise> ServiceWorkerGlobalScope::request( } else { // In modules mode we don't have a concept of "default handling". lock.logWarningOnce("Received a FetchEvent but we lack a handler for FetchEvents. " - "Did you remember to export a fetch() function?"); + "Did you remember to export a fetch() function?"); JSG_FAIL_REQUIRE(Error, "Handler does not export a fetch() function."); } } else { @@ -239,17 +232,15 @@ kj::Promise> ServiceWorkerGlobalScope::request( lock.logUncaughtException( "Script consumed request body but didn't call respondWith(). Can't forward request."); return addNoopDeferredProxy( - response.sendError(500, "Internal Server Error", ioContext.getHeaderTable())); + response.sendError(500, "Internal Server Error", ioContext.getHeaderTable())); } else { - auto client = ioContext.getHttpClient( - IoContext::NEXT_CLIENT_CHANNEL, false, - cfBlobJson.map([](kj::StringPtr s) { return kj::str(s); }), - "fetch_default"_kjc); + auto client = ioContext.getHttpClient(IoContext::NEXT_CLIENT_CHANNEL, false, + cfBlobJson.map([](kj::StringPtr s) { return kj::str(s); }), "fetch_default"_kjc); auto adapter = kj::newHttpService(*client); auto promise = adapter->request(method, url, headers, requestBody, response); // Default handling doesn't rely on the IoContext at all so we can return it as a // deferred proxy task. - return DeferredProxy { promise.attach(kj::mv(adapter), kj::mv(client)) }; + return DeferredProxy{promise.attach(kj::mv(adapter), kj::mv(client))}; } } else KJ_IF_SOME(promise, event->getResponsePromise(lock)) { auto body2 = kj::addRef(*ownRequestBody); @@ -264,12 +255,14 @@ kj::Promise> ServiceWorkerGlobalScope::request( }; auto canceled = kj::refcounted(false); - return ioContext.awaitJs(lock ,promise.then(kj::implicitCast(lock), - ioContext.addFunctor( - [&response, allowWebSocket = headers.isWebSocket(), - canceled = kj::addRef(*canceled), &headers, span = kj::mv(span)] - (jsg::Lock& js, jsg::Ref innerResponse) mutable - -> IoOwn>> { + return ioContext + .awaitJs(lock, + promise.then(kj::implicitCast(lock), + ioContext.addFunctor( + [&response, allowWebSocket = headers.isWebSocket(), + canceled = kj::addRef(*canceled), &headers, span = kj::mv(span)]( + jsg::Lock& js, jsg::Ref innerResponse) mutable + -> IoOwn>> { auto& context = IoContext::current(); // Drop our fetch_handler span now that the promise has resolved. span = kj::none; @@ -278,17 +271,19 @@ kj::Promise> ServiceWorkerGlobalScope::request( // a dangling reference, let's not use it. return context.addObject(kj::heap(addNoopDeferredProxy(kj::READY_NOW))); } else { - return context.addObject(kj::heap(innerResponse->send( - js, response, { .allowWebSocket = allowWebSocket }, headers))); + return context.addObject(kj::heap( + innerResponse->send(js, response, {.allowWebSocket = allowWebSocket}, headers))); } - }))).attach(kj::defer([canceled = kj::mv(canceled)]() mutable { canceled->value = true; })) - .then([ownRequestBody = kj::mv(ownRequestBody), deferredNeuter = kj::mv(deferredNeuter)] - (DeferredProxy deferredProxy) mutable { + }))) + .attach(kj::defer([canceled = kj::mv(canceled)]() mutable { canceled->value = true; })) + .then( + [ownRequestBody = kj::mv(ownRequestBody), deferredNeuter = kj::mv(deferredNeuter)]( + DeferredProxy deferredProxy) mutable { // In the case of bidirectional streaming, the request body stream needs to remain valid // while proxying the response. So, arrange for neutering to happen only after the proxy // task finishes. deferredProxy.proxyTask = deferredProxy.proxyTask - .then([body = kj::addRef(*ownRequestBody)]() mutable { + .then([body = kj::addRef(*ownRequestBody)]() mutable { body->neuter(makeNeuterException(NeuterReason::SENT_RESPONSE)); }, [body = kj::addRef(*ownRequestBody)](kj::Exception&& e) mutable { body->neuter(makeNeuterException(NeuterReason::THREW_EXCEPTION)); @@ -296,7 +291,8 @@ kj::Promise> ServiceWorkerGlobalScope::request( }).attach(kj::mv(deferredNeuter)); return deferredProxy; - }, [body = kj::mv(body2)](kj::Exception&& e) mutable -> DeferredProxy { + }, + [body = kj::mv(body2)](kj::Exception&& e) mutable -> DeferredProxy { // HACK: We depend on the fact that the success-case lambda above hasn't been destroyed yet // so `deferredNeuter` hasn't been destroyed yet. body->neuter(makeNeuterException(NeuterReason::THREW_EXCEPTION)); @@ -310,7 +306,8 @@ kj::Promise> ServiceWorkerGlobalScope::request( } void ServiceWorkerGlobalScope::sendTraces(kj::ArrayPtr> traces, - Worker::Lock& lock, kj::Maybe exportedHandler) { + Worker::Lock& lock, + kj::Maybe exportedHandler) { auto isolate = lock.getIsolate(); KJ_IF_SOME(h, exportedHandler) { @@ -323,9 +320,8 @@ void ServiceWorkerGlobalScope::sendTraces(kj::ArrayPtr> traces, auto promise = f(lock, traceEvent->getEvents(), h.env.addRef(isolate), h.getCtx()); traceEvent->waitUntil(kj::mv(promise)); } else { - lock.logWarningOnce( - "Attempted to send events but we lack a handler, " - "did you remember to export a tail() function?"); + lock.logWarningOnce("Attempted to send events but we lack a handler, " + "did you remember to export a tail() function?"); JSG_FAIL_REQUIRE(Error, "Handler does not export a tail() function."); } } else { @@ -340,10 +336,10 @@ void ServiceWorkerGlobalScope::sendTraces(kj::ArrayPtr> traces, } } -void ServiceWorkerGlobalScope::startScheduled( - kj::Date scheduledTime, +void ServiceWorkerGlobalScope::startScheduled(kj::Date scheduledTime, kj::StringPtr cron, - Worker::Lock& lock, kj::Maybe exportedHandler) { + Worker::Lock& lock, + kj::Maybe exportedHandler) { auto& context = IoContext::current(); double eventTime = (scheduledTime - kj::UNIX_EPOCH) / kj::MILLISECONDS; @@ -354,8 +350,8 @@ void ServiceWorkerGlobalScope::startScheduled( KJ_IF_SOME(h, exportedHandler) { KJ_IF_SOME(f, h.scheduled) { - auto promise = f(lock, jsg::alloc(event.addRef()), - h.env.addRef(isolate), h.getCtx()); + auto promise = f( + lock, jsg::alloc(event.addRef()), h.env.addRef(isolate), h.getCtx()); event->waitUntil(kj::mv(promise)); } else { lock.logWarningOnce( @@ -377,11 +373,11 @@ void ServiceWorkerGlobalScope::startScheduled( } } -kj::Promise ServiceWorkerGlobalScope::runAlarm( - kj::Date scheduledTime, +kj::Promise ServiceWorkerGlobalScope::runAlarm(kj::Date scheduledTime, kj::Duration timeout, uint32_t retryCount, - Worker::Lock& lock, kj::Maybe exportedHandler) { + Worker::Lock& lock, + kj::Maybe exportedHandler) { auto& context = IoContext::current(); auto& actor = KJ_ASSERT_NONNULL(context.getActor()); @@ -392,26 +388,24 @@ kj::Promise ServiceWorkerGlobalScope::runAlarm( auto& handler = KJ_REQUIRE_NONNULL(exportedHandler); if (handler.alarm == kj::none) { - lock.logWarningOnce( - "Attempted to run a scheduled alarm without a handler, " - "did you remember to export an alarm() function?"); - return WorkerInterface::AlarmResult { - .retry = false, - .outcome = EventOutcome::SCRIPT_NOT_FOUND - }; + lock.logWarningOnce("Attempted to run a scheduled alarm without a handler, " + "did you remember to export an alarm() function?"); + return WorkerInterface::AlarmResult{ + .retry = false, .outcome = EventOutcome::SCRIPT_NOT_FOUND}; } auto& alarm = KJ_ASSERT_NONNULL(handler.alarm); return context .run([exportedHandler, &context, timeout, retryCount, &alarm, - maybeAsyncContext = jsg::AsyncContextFrame::currentRef(lock)] - (Worker::Lock& lock) mutable -> kj::Promise { + maybeAsyncContext = jsg::AsyncContextFrame::currentRef(lock)]( + Worker::Lock& lock) mutable -> kj::Promise { jsg::AsyncContextFrame::Scope asyncScope(lock, maybeAsyncContext); // We want to limit alarm handler walltime to 15 minutes at most. If the timeout promise // completes we want to cancel the alarm handler. If the alarm handler promise completes first // timeout will be canceled. - auto timeoutPromise = context.afterLimitTimeout(timeout).then([&context]() -> kj::Promise { + auto timeoutPromise = context.afterLimitTimeout(timeout).then( + [&context]() -> kj::Promise { // We don't want to delete the alarm since we have not successfully completed the alarm // execution. auto& actor = KJ_ASSERT_NONNULL(context.getActor()); @@ -420,7 +414,8 @@ kj::Promise ServiceWorkerGlobalScope::runAlarm( LOG_NOSENTRY(WARNING, "Alarm exceeded its allowed execution time"); // Report alarm handler failure and log it. - auto e = KJ_EXCEPTION(OVERLOADED, "broken.dropped; worker_do_not_log; jsg.Error: Alarm exceeded its allowed execution time"); + auto e = KJ_EXCEPTION(OVERLOADED, + "broken.dropped; worker_do_not_log; jsg.Error: Alarm exceeded its allowed execution time"); context.getMetrics().reportFailure(e); // We don't want the handler to keep running after timeout. @@ -429,20 +424,16 @@ kj::Promise ServiceWorkerGlobalScope::runAlarm( // retriable, and we'll count the retries against the alarm retries limit. This will ensure // that the handler will attempt to run for a number of times before giving up and deleting // the alarm. - return WorkerInterface::AlarmResult { - .retry = true, - .retryCountsAgainstLimit = true, - .outcome = EventOutcome::EXCEEDED_CPU - }; + return WorkerInterface::AlarmResult{ + .retry = true, .retryCountsAgainstLimit = true, .outcome = EventOutcome::EXCEEDED_CPU}; }); - return alarm(lock, jsg::alloc(retryCount)).then([]() -> kj::Promise { - return WorkerInterface::AlarmResult { - .retry = false, - .outcome = EventOutcome::OK - }; + return alarm(lock, jsg::alloc(retryCount)) + .then([]() -> kj::Promise { + return WorkerInterface::AlarmResult{.retry = false, .outcome = EventOutcome::OK}; }).exclusiveJoin(kj::mv(timeoutPromise)); - }).catch_([&context, deferredDelete = kj::mv(deferredDelete)](kj::Exception&& e) mutable { + }) + .catch_([&context, deferredDelete = kj::mv(deferredDelete)](kj::Exception&& e) mutable { auto& actor = KJ_ASSERT_NONNULL(context.getActor()); auto& persistent = KJ_ASSERT_NONNULL(actor.getPersistent()); persistent.cancelDeferredAlarmDeletion(); @@ -472,30 +463,30 @@ kj::Promise ServiceWorkerGlobalScope::runAlarm( auto shouldRetryCountsAgainstLimits = !context.isOutputGateBroken(); // We want to alert if we aren't going to count this alarm retry against limits - if (auto desc = e.getDescription(); - !jsg::isTunneledException(desc) && !jsg::isDoNotLogException(desc) - && context.isOutputGateBroken()) { + if (auto desc = e.getDescription(); !jsg::isTunneledException(desc) && + !jsg::isDoNotLogException(desc) && context.isOutputGateBroken()) { LOG_NOSENTRY(ERROR, "output lock broke during alarm execution", actorId, e); } else if (context.isOutputGateBroken()) { // We don't usually log these messages, but it's useful to know the real reason we failed // to correctly investigate stuck alarms. - LOG_NOSENTRY(ERROR, "output lock broke during alarm execution without an interesting error description", actorId, e); + LOG_NOSENTRY(ERROR, + "output lock broke during alarm execution without an interesting error description", + actorId, e); if (e.getDetail(jsg::EXCEPTION_IS_USER_ERROR) != kj::none) { // The handler failed because the user overloaded the object. It's their fault, we'll not // retry forever. shouldRetryCountsAgainstLimits = true; } } - return WorkerInterface::AlarmResult { - .retry = true, + return WorkerInterface::AlarmResult{.retry = true, .retryCountsAgainstLimit = shouldRetryCountsAgainstLimits, - .outcome = outcome - }; + .outcome = outcome}; }) - .then([&context](WorkerInterface::AlarmResult result) -> kj::Promise { - return context.waitForOutputLocks().then([result]() { - return kj::mv(result); - }, [&context](kj::Exception&& e) { + .then( + [&context]( + WorkerInterface::AlarmResult result) -> kj::Promise { + return context.waitForOutputLocks().then( + [result]() { return kj::mv(result); }, [&context](kj::Exception&& e) { auto& actor = KJ_ASSERT_NONNULL(context.getActor()); kj::String actorId; KJ_SWITCH_ONEOF(actor.getId()) { @@ -519,25 +510,22 @@ kj::Promise ServiceWorkerGlobalScope::runAlarm( } else { // We don't usually log these messages, but it's useful to know the real reason we failed // to correctly investigate stuck alarms. - LOG_NOSENTRY(ERROR, "output lock broke after executing alarm without an interesting error description", actorId, e); + LOG_NOSENTRY(ERROR, + "output lock broke after executing alarm without an interesting error description", + actorId, e); if (e.getDetail(jsg::EXCEPTION_IS_USER_ERROR) != kj::none) { // The handler failed because the user overloaded the object. It's their fault, we'll not // retry forever. shouldRetryCountsAgainstLimits = true; } } - return WorkerInterface::AlarmResult { - .retry = true, + return WorkerInterface::AlarmResult{.retry = true, .retryCountsAgainstLimit = shouldRetryCountsAgainstLimits, - .outcome = EventOutcome::EXCEPTION - }; + .outcome = EventOutcome::EXCEPTION}; }); }); } else { - return WorkerInterface::AlarmResult { - .retry = false, - .outcome = EventOutcome::CANCELED - }; + return WorkerInterface::AlarmResult{.retry = false, .outcome = EventOutcome::CANCELED}; } } @@ -545,11 +533,11 @@ jsg::Promise ServiceWorkerGlobalScope::test( Worker::Lock& lock, kj::Maybe exportedHandler) { // TODO(someday): For Service Workers syntax, do we want addEventListener("test")? Not supporting // it for now. - ExportedHandler& eh = JSG_REQUIRE_NONNULL(exportedHandler, Error, - "Tests are not currently supported with Service Workers syntax."); + ExportedHandler& eh = JSG_REQUIRE_NONNULL( + exportedHandler, Error, "Tests are not currently supported with Service Workers syntax."); - auto& testHandler = JSG_REQUIRE_NONNULL(eh.test, Error, - "Entrypoint does not export a test() function."); + auto& testHandler = + JSG_REQUIRE_NONNULL(eh.test, Error, "Entrypoint does not export a test() function."); return testHandler(lock, jsg::alloc(), eh.env.addRef(lock), eh.getCtx()); } @@ -561,12 +549,13 @@ kj::Promise ServiceWorkerGlobalScope::eventTimeoutPromise(uint32_t timeout co_await IoContext::current().afterLimitTimeout(timeoutMs * kj::MILLISECONDS); // This is the ActorFlushReason for eviction in Cloudflare's internal implementation. auto evictionCode = 2; - actor.shutdown(evictionCode, KJ_EXCEPTION(DISCONNECTED, - "broken.dropped; jsg.Error: Actor exceeded event execution time and was disconnected.")); + actor.shutdown(evictionCode, + KJ_EXCEPTION(DISCONNECTED, + "broken.dropped; jsg.Error: Actor exceeded event execution time and was disconnected.")); } -kj::Promise ServiceWorkerGlobalScope::setHibernatableEventTimeout(kj::Promise event, - kj::Maybe eventTimeoutMs) { +kj::Promise ServiceWorkerGlobalScope::setHibernatableEventTimeout( + kj::Promise event, kj::Maybe eventTimeoutMs) { // If we have a maximum event duration timeout set, we should prevent the actor from running // for more than the user selected duration. auto timeoutMs = eventTimeoutMs.orDefault((uint32_t)0); @@ -580,7 +569,8 @@ void ServiceWorkerGlobalScope::sendHibernatableWebSocketMessage( kj::OneOf> message, kj::Maybe eventTimeoutMs, kj::String websocketId, - Worker::Lock& lock, kj::Maybe exportedHandler) { + Worker::Lock& lock, + kj::Maybe exportedHandler) { auto event = jsg::alloc(); // Even if no handler is exported, we need to claim the websocket so it's removed from the map. auto websocket = event->claimWebSocket(lock, websocketId); @@ -594,11 +584,11 @@ void ServiceWorkerGlobalScope::sendHibernatableWebSocketMessage( } } -void ServiceWorkerGlobalScope::sendHibernatableWebSocketClose( - HibernatableSocketParams::Close close, +void ServiceWorkerGlobalScope::sendHibernatableWebSocketClose(HibernatableSocketParams::Close close, kj::Maybe eventTimeoutMs, kj::String websocketId, - Worker::Lock& lock, kj::Maybe exportedHandler) { + Worker::Lock& lock, + kj::Maybe exportedHandler) { auto event = jsg::alloc(); // Even if no handler is exported, we need to claim the websocket so it's removed from the map. @@ -608,20 +598,18 @@ void ServiceWorkerGlobalScope::sendHibernatableWebSocketClose( auto releasePackage = event->prepareForRelease(lock, websocketId); auto websocket = kj::mv(releasePackage.webSocketRef); websocket->initiateHibernatableRelease(lock, kj::mv(releasePackage.ownedWebSocket), - kj::mv(releasePackage.tags), - api::WebSocket::HibernatableReleaseState::CLOSE); + kj::mv(releasePackage.tags), api::WebSocket::HibernatableReleaseState::CLOSE); KJ_IF_SOME(h, exportedHandler) { KJ_IF_SOME(handler, h.webSocketClose) { event->waitUntil(setHibernatableEventTimeout( - handler(lock, kj::mv(websocket), close.code, kj::mv(close.reason), - close.wasClean), eventTimeoutMs)); + handler(lock, kj::mv(websocket), close.code, kj::mv(close.reason), close.wasClean), + eventTimeoutMs)); } // We want to deliver close, but if no webSocketClose handler is exported, we shouldn't fail } } -void ServiceWorkerGlobalScope::sendHibernatableWebSocketError( - kj::Exception e, +void ServiceWorkerGlobalScope::sendHibernatableWebSocketError(kj::Exception e, kj::Maybe eventTimeoutMs, kj::String websocketId, Worker::Lock& lock, @@ -635,29 +623,25 @@ void ServiceWorkerGlobalScope::sendHibernatableWebSocketError( auto releasePackage = event->prepareForRelease(lock, websocketId); auto& websocket = releasePackage.webSocketRef; websocket->initiateHibernatableRelease(lock, kj::mv(releasePackage.ownedWebSocket), - kj::mv(releasePackage.tags), - WebSocket::HibernatableReleaseState::ERROR); + kj::mv(releasePackage.tags), WebSocket::HibernatableReleaseState::ERROR); jsg::Lock& js(lock); KJ_IF_SOME(h, exportedHandler) { KJ_IF_SOME(handler, h.webSocketError) { event->waitUntil(setHibernatableEventTimeout( - handler(js, kj::mv(websocket), js.exceptionToJs(kj::mv(e))), - eventTimeoutMs)); + handler(js, kj::mv(websocket), js.exceptionToJs(kj::mv(e))), eventTimeoutMs)); } // We want to deliver an error, but if no webSocketError handler is exported, we shouldn't fail } } -void ServiceWorkerGlobalScope::emitPromiseRejection( - jsg::Lock& js, +void ServiceWorkerGlobalScope::emitPromiseRejection(jsg::Lock& js, v8::PromiseRejectEvent event, jsg::V8Ref promise, jsg::Value value) { const auto hasHandlers = [this] { - return getHandlerCount("unhandledrejection"_kj) + - getHandlerCount("rejectionhandled"_kj); + return getHandlerCount("unhandledrejection"_kj) + getHandlerCount("rejectionhandled"_kj); }; const auto hasInspector = [] { @@ -700,9 +684,7 @@ jsg::JsString ServiceWorkerGlobalScope::atob(jsg::Lock& js, kj::String data) { return js.str(decoded.asBytes()); } -void ServiceWorkerGlobalScope::queueMicrotask( - jsg::Lock& js, - v8::Local task) { +void ServiceWorkerGlobalScope::queueMicrotask(jsg::Lock& js, v8::Local task) { // TODO(later): It currently does not appear as if v8 attaches the continuation embedder data // to microtasks scheduled using EnqueueMicrotask, so we have to wrap in order to propagate // the context to those. Once V8 is fixed to correctly associate continuation data with @@ -714,14 +696,10 @@ void ServiceWorkerGlobalScope::queueMicrotask( } jsg::JsValue ServiceWorkerGlobalScope::structuredClone( - jsg::Lock& js, - jsg::JsValue value, - jsg::Optional maybeOptions) { + jsg::Lock& js, jsg::JsValue value, jsg::Optional maybeOptions) { KJ_IF_SOME(options, maybeOptions) { KJ_IF_SOME(transfer, options.transfer) { - auto transfers = KJ_MAP(i, transfer) { - return i.getHandle(js); - }; + auto transfers = KJ_MAP(i, transfer) { return i.getHandle(js); }; return value.structuredClone(js, kj::mv(transfers)); } } @@ -729,34 +707,25 @@ jsg::JsValue ServiceWorkerGlobalScope::structuredClone( } TimeoutId::NumberType ServiceWorkerGlobalScope::setTimeoutInternal( - jsg::Function function, - double msDelay) { - auto timeoutId = IoContext::current().setTimeoutImpl( - timeoutIdGenerator, - /** repeats = */ false, - kj::mv(function), - msDelay); + jsg::Function function, double msDelay) { + auto timeoutId = IoContext::current().setTimeoutImpl(timeoutIdGenerator, + /** repeats = */ false, kj::mv(function), msDelay); return timeoutId.toNumber(); } -TimeoutId::NumberType ServiceWorkerGlobalScope::setTimeout( - jsg::Lock& js, +TimeoutId::NumberType ServiceWorkerGlobalScope::setTimeout(jsg::Lock& js, jsg::Function)> function, jsg::Optional msDelay, jsg::Arguments args) { function.setReceiver(js.v8Ref(js.v8Context()->Global())); - auto fn = [function=kj::mv(function), - args=kj::mv(args), - context=jsg::AsyncContextFrame::currentRef(js)](jsg::Lock& js) mutable { + auto fn = [function = kj::mv(function), args = kj::mv(args), + context = jsg::AsyncContextFrame::currentRef(js)](jsg::Lock& js) mutable { jsg::AsyncContextFrame::Scope scope(js, context); function(js, kj::mv(args)); }; - auto timeoutId = IoContext::current().setTimeoutImpl( - timeoutIdGenerator, - /* repeats = */ false, - [function = kj::mv(fn)](jsg::Lock& js) mutable { - function(js); - }, msDelay.orDefault(0)); + auto timeoutId = IoContext::current().setTimeoutImpl(timeoutIdGenerator, + /* repeats = */ false, [function = kj::mv(fn)](jsg::Lock& js) mutable { function(js); }, + msDelay.orDefault(0)); return timeoutId.toNumber(); } @@ -766,27 +735,21 @@ void ServiceWorkerGlobalScope::clearTimeout(kj::Maybe tim } } -TimeoutId::NumberType ServiceWorkerGlobalScope::setInterval( - jsg::Lock& js, +TimeoutId::NumberType ServiceWorkerGlobalScope::setInterval(jsg::Lock& js, jsg::Function)> function, jsg::Optional msDelay, jsg::Arguments args) { function.setReceiver(js.v8Ref(js.v8Context()->Global())); - auto fn = [function=kj::mv(function), - args=kj::mv(args), - context=jsg::AsyncContextFrame::currentRef(js)] - (jsg::Lock& js) mutable { + auto fn = [function = kj::mv(function), args = kj::mv(args), + context = jsg::AsyncContextFrame::currentRef(js)](jsg::Lock& js) mutable { jsg::AsyncContextFrame::Scope scope(js, context); // Because the fn is called multiple times, we will clone the args on each call. auto argv = KJ_MAP(i, args) { return i.addRef(js); }; function(js, jsg::Arguments(kj::mv(argv))); }; - auto timeoutId = IoContext::current().setTimeoutImpl( - timeoutIdGenerator, - /* repeats = */ true, - [function = kj::mv(fn)](jsg::Lock& js) mutable { - function(js); - }, msDelay.orDefault(0)); + auto timeoutId = IoContext::current().setTimeoutImpl(timeoutIdGenerator, + /* repeats = */ true, [function = kj::mv(fn)](jsg::Lock& js) mutable { function(js); }, + msDelay.orDefault(0)); return timeoutId.toNumber(); } @@ -798,8 +761,8 @@ jsg::Ref ServiceWorkerGlobalScope::getCaches() { return jsg::alloc(); } -jsg::Promise> ServiceWorkerGlobalScope::fetch( - jsg::Lock& js, kj::OneOf, kj::String> requestOrUrl, +jsg::Promise> ServiceWorkerGlobalScope::fetch(jsg::Lock& js, + kj::OneOf, kj::String> requestOrUrl, jsg::Optional requestInit) { return fetchImpl(js, kj::none, kj::mv(requestOrUrl), kj::mv(requestInit)); } @@ -810,13 +773,11 @@ void ServiceWorkerGlobalScope::reportError(jsg::Lock& js, jsg::JsValue error) { // that we do not throw the error at all. auto message = v8::Exception::CreateMessage(js.v8Isolate, error); auto event = jsg::alloc(kj::str("error"), - ErrorEvent::ErrorEventInit { - .message = kj::str(message->Get()), + ErrorEvent::ErrorEventInit{.message = kj::str(message->Get()), .filename = kj::str(message->GetScriptResourceName()), .lineno = jsg::check(message->GetLineNumber(js.v8Context())), .colno = jsg::check(message->GetStartColumn(js.v8Context())), - .error = jsg::JsRef(js, error) - }); + .error = jsg::JsRef(js, error)}); if (dispatchEventImpl(js, kj::mv(event))) { js.reportError(error); } @@ -835,8 +796,8 @@ jsg::JsValue resolveFromRegistry(jsg::Lock& js, kj::StringPtr specifier) { } auto spec = kj::Path::parse(specifier); - auto& info = JSG_REQUIRE_NONNULL(moduleRegistry->resolve(js, spec), Error, - kj::str("No such module: ", specifier)); + auto& info = JSG_REQUIRE_NONNULL( + moduleRegistry->resolve(js, spec), Error, kj::str("No such module: ", specifier)); auto module = info.module.getHandle(js); jsg::instantiateModule(js, module); @@ -854,8 +815,8 @@ jsg::JsValue resolveFromRegistry(jsg::Lock& js, kj::StringPtr specifier) { jsg::JsValue ServiceWorkerGlobalScope::getBuffer(jsg::Lock& js) { KJ_ASSERT(FeatureFlags::get(js).getNodeJsCompatV2()); auto value = resolveFromRegistry(js, "node:buffer"_kj); - auto obj = JSG_REQUIRE_NONNULL(value.tryCast(), TypeError, - "Invalid node:buffer implementation"); + auto obj = JSG_REQUIRE_NONNULL( + value.tryCast(), TypeError, "Invalid node:buffer implementation"); // Unlike the getProcess() case below, this getter is returning an object that // is exported by the node:buffer module and not the module itself, so we need // this additional get to the grab the reference to the thing we're actually @@ -881,9 +842,9 @@ double Performance::now() { #ifdef WORKERD_EXPERIMENTAL_ENABLE_WEBGPU jsg::Ref Navigator::getGPU(CompatibilityFlags::Reader flags) { // is this a durable object? - KJ_IF_SOME (actor, IoContext::current().getActor()) { + KJ_IF_SOME(actor, IoContext::current().getActor()) { JSG_REQUIRE(actor.getPersistent() != kj::none, TypeError, - "webgpu api is only available in Durable Objects (no storage)"); + "webgpu api is only available in Durable Objects (no storage)"); } else { JSG_FAIL_REQUIRE(TypeError, "webgpu api is only available in Durable Objects"); }; @@ -894,16 +855,16 @@ jsg::Ref Navigator::getGPU(CompatibilityFlags::Reader flags) { } #endif -bool Navigator::sendBeacon(jsg::Lock& js, kj::String url, - jsg::Optional body) { +bool Navigator::sendBeacon(jsg::Lock& js, kj::String url, jsg::Optional body) { if (IoContext::hasCurrent()) { auto v8Context = js.v8Context(); - auto& global = jsg::extractInternalPointer( - v8Context, v8Context->Global()); - auto promise = global.fetch(js, kj::mv(url), Request::InitializerDict { - .method = kj::str("POST"), - .body = kj::mv(body), - }); + auto& global = + jsg::extractInternalPointer(v8Context, v8Context->Global()); + auto promise = global.fetch(js, kj::mv(url), + Request::InitializerDict{ + .method = kj::str("POST"), + .body = kj::mv(body), + }); auto& context = IoContext::current(); @@ -922,13 +883,10 @@ Immediate::Immediate(IoContext& context, TimeoutId timeoutId) timeoutId(timeoutId) {} void Immediate::dispose() { - contextRef->runIfAlive([&](IoContext& context) { - context.clearTimeoutImpl(timeoutId); - }); + contextRef->runIfAlive([&](IoContext& context) { context.clearTimeoutImpl(timeoutId); }); } -jsg::Ref ServiceWorkerGlobalScope::setImmediate( - jsg::Lock& js, +jsg::Ref ServiceWorkerGlobalScope::setImmediate(jsg::Lock& js, jsg::Function)> function, jsg::Arguments args) { @@ -944,26 +902,20 @@ jsg::Ref ServiceWorkerGlobalScope::setImmediate( // would require a compat flag... but that's ok for now? auto& context = IoContext::current(); - auto fn = [function=kj::mv(function), - args=kj::mv(args), - context=jsg::AsyncContextFrame::currentRef(js)](jsg::Lock& js) mutable { + auto fn = [function = kj::mv(function), args = kj::mv(args), + context = jsg::AsyncContextFrame::currentRef(js)](jsg::Lock& js) mutable { jsg::AsyncContextFrame::Scope scope(js, context); function(js, kj::mv(args)); }; - auto timeoutId = context.setTimeoutImpl( - timeoutIdGenerator, - /* repeats = */ false, - [function = kj::mv(fn)](jsg::Lock& js) mutable { - function(js); - }, 0); + auto timeoutId = context.setTimeoutImpl(timeoutIdGenerator, + /* repeats = */ false, [function = kj::mv(fn)](jsg::Lock& js) mutable { function(js); }, 0); return jsg::alloc(context, timeoutId); } -void ServiceWorkerGlobalScope::clearImmediate( - kj::Maybe> maybeImmediate) { +void ServiceWorkerGlobalScope::clearImmediate(kj::Maybe> maybeImmediate) { KJ_IF_SOME(immediate, maybeImmediate) { immediate->dispose(); } } -} // namespace workerd::api +} // namespace workerd::api diff --git a/src/workerd/api/global-scope.h b/src/workerd/api/global-scope.h index 3839289a88b..46b5a1aff1a 100644 --- a/src/workerd/api/global-scope.h +++ b/src/workerd/api/global-scope.h @@ -17,7 +17,7 @@ namespace workerd::jsg { class DOMException; -} // namespace jsg +} // namespace workerd::jsg namespace workerd::api { @@ -58,7 +58,7 @@ class URLSearchParams; namespace url { class URL; class URLSearchParams; -} // namespace +} // namespace url // We need access to DOMException within this namespace so JSG_NESTED_TYPE can name it correctly. using DOMException = jsg::DOMException; @@ -66,7 +66,9 @@ using DOMException = jsg::DOMException; // A subset of the standard Navigator API. class Navigator: public jsg::Object { public: - kj::StringPtr getUserAgent() { return "Cloudflare-Workers"_kj; } + kj::StringPtr getUserAgent() { + return "Cloudflare-Workers"_kj; + } #ifdef WORKERD_EXPERIMENTAL_ENABLE_WEBGPU jsg::Ref getGPU(CompatibilityFlags::Reader flags); #endif @@ -96,7 +98,9 @@ class Performance: public jsg::Object { // smaller in magnitude, which allows them to be more precise due to the nature of floating // point numbers. In our case, though, we don't return precise measurements from this interface // anyway, for Spectre reasons -- it returns the same as Date.now(). - double getTimeOrigin() { return 0.0; } + double getTimeOrigin() { + return 0.0; + } double now(); @@ -109,14 +113,16 @@ class Performance: public jsg::Object { class PromiseRejectionEvent: public Event { public: PromiseRejectionEvent( - v8::PromiseRejectEvent type, - jsg::V8Ref promise, - jsg::Value reason); + v8::PromiseRejectEvent type, jsg::V8Ref promise, jsg::Value reason); static jsg::Ref constructor(kj::String type) = delete; - jsg::V8Ref getPromise(jsg::Lock& js) { return promise.addRef(js); } - jsg::Value getReason(jsg::Lock& js) { return reason.addRef(js); } + jsg::V8Ref getPromise(jsg::Lock& js) { + return promise.addRef(js); + } + jsg::Value getReason(jsg::Lock& js) { + return reason.addRef(js); + } JSG_RESOURCE_TYPE(PromiseRejectionEvent) { JSG_INHERIT(Event); @@ -138,7 +144,9 @@ class PromiseRejectionEvent: public Event { class WorkerGlobalScope: public EventTarget, public jsg::ContextGlobal { public: - jsg::Unimplemented importScripts(kj::String s) { return {}; }; + jsg::Unimplemented importScripts(kj::String s) { + return {}; + }; JSG_RESOURCE_TYPE(WorkerGlobalScope, CompatibilityFlags::Reader flags) { JSG_INHERIT(EventTarget); @@ -208,8 +216,12 @@ class AlarmInvocationInfo: public jsg::Object { public: AlarmInvocationInfo(uint32_t retry): retryCount(retry) {} - bool getIsRetry() { return retryCount > 0; } - uint32_t getRetryCount() { return retryCount; } + bool getIsRetry() { + return retryCount > 0; + } + uint32_t getRetryCount() { + return retryCount; + } JSG_RESOURCE_TYPE(AlarmInvocationInfo) { JSG_READONLY_INSTANCE_PROPERTY(isRetry, getIsRetry); @@ -226,32 +238,37 @@ class AlarmInvocationInfo: public jsg::Object { // treat incorrect types as if the field is undefined. Without this, Durable Object class // constructors that set a field with one of these names would cause confusing type errors. struct ExportedHandler { - typedef jsg::Promise> FetchHandler( - jsg::Ref request, jsg::Value env, jsg::Optional> ctx); + typedef jsg::Promise> FetchHandler(jsg::Ref request, + jsg::Value env, + jsg::Optional> ctx); jsg::LenientOptional> fetch; - typedef kj::Promise TailHandler( - kj::Array> events, jsg::Value env, jsg::Optional> ctx); + typedef kj::Promise TailHandler(kj::Array> events, + jsg::Value env, + jsg::Optional> ctx); jsg::LenientOptional> tail; jsg::LenientOptional> trace; - typedef kj::Promise ScheduledHandler( - jsg::Ref controller, jsg::Value env, jsg::Optional> ctx); + typedef kj::Promise ScheduledHandler(jsg::Ref controller, + jsg::Value env, + jsg::Optional> ctx); jsg::LenientOptional> scheduled; typedef kj::Promise AlarmHandler(jsg::Ref alarmInfo); // Alarms are only exported on DOs, which receive env bindings from the constructor jsg::LenientOptional> alarm; - typedef jsg::Promise TestHandler( - jsg::Ref controller, jsg::Value env, + typedef jsg::Promise TestHandler(jsg::Ref controller, + jsg::Value env, jsg::Optional> ctx); jsg::LenientOptional> test; - typedef kj::Promise HibernatableWebSocketMessageHandler(jsg::Ref, kj::OneOf> message); + typedef kj::Promise HibernatableWebSocketMessageHandler( + jsg::Ref, kj::OneOf> message); jsg::LenientOptional> webSocketMessage; - typedef kj::Promise HibernatableWebSocketCloseHandler(jsg::Ref, int code, kj::String reason, bool wasClean); + typedef kj::Promise HibernatableWebSocketCloseHandler( + jsg::Ref, int code, kj::String reason, bool wasClean); jsg::LenientOptional> webSocketClose; typedef kj::Promise HibernatableWebSocketErrorHandler(jsg::Ref, jsg::Value); @@ -260,7 +277,16 @@ struct ExportedHandler { // Self-ref potentially allows extracting other custom handlers from the object. jsg::SelfRef self; - JSG_STRUCT(fetch, tail, trace, scheduled, alarm, test, webSocketMessage, webSocketClose, webSocketError, self); + JSG_STRUCT(fetch, + tail, + trace, + scheduled, + alarm, + test, + webSocketMessage, + webSocketClose, + webSocketError, + self); JSG_STRUCT_TS_ROOT(); // ExportedHandler isn't included in the global scope, but we still want to @@ -323,7 +349,9 @@ class Immediate final: public jsg::Object { // We do not implement a similar mechanism in workerd. These are here only to // satisfy the API contract for the `Immediate` object but are never expected // to actually do anything. - bool hasRef() { return false; } + bool hasRef() { + return false; + } void ref() { /* non-op */ } void unref() { /* non-op */ } @@ -361,64 +389,64 @@ class ServiceWorkerGlobalScope: public WorkerGlobalScope { // // If `exportedHandler` is provided, the request will be delivered to it rather than to event // listeners. - kj::Promise> request( - kj::HttpMethod method, kj::StringPtr url, const kj::HttpHeaders& headers, - kj::AsyncInputStream& requestBody, kj::HttpService::Response& response, + kj::Promise> request(kj::HttpMethod method, + kj::StringPtr url, + const kj::HttpHeaders& headers, + kj::AsyncInputStream& requestBody, + kj::HttpService::Response& response, kj::Maybe cfBlobJson, - Worker::Lock& lock, kj::Maybe exportedHandler); + Worker::Lock& lock, + kj::Maybe exportedHandler); // TODO(cleanup): Factor out the shared code used between old-style event listeners vs. module // exports and move that code somewhere more appropriate. // Received sendTraces (called from C++, not JS). void sendTraces(kj::ArrayPtr> traces, - Worker::Lock& lock, kj::Maybe exportedHandler); + Worker::Lock& lock, + kj::Maybe exportedHandler); // Start a scheduled event (called from C++, not JS). It is the caller's responsibility to wait // for waitUntil()s in order to construct the final ScheduledResult. - void startScheduled( - kj::Date scheduledTime, + void startScheduled(kj::Date scheduledTime, kj::StringPtr cron, - Worker::Lock& lock, kj::Maybe exportedHandler); + Worker::Lock& lock, + kj::Maybe exportedHandler); // Received runAlarm (called from C++, not JS). - kj::Promise runAlarm( - kj::Date scheduledTime, + kj::Promise runAlarm(kj::Date scheduledTime, kj::Duration timeout, uint32_t retryCount, - Worker::Lock& lock, kj::Maybe exportedHandler); + Worker::Lock& lock, + kj::Maybe exportedHandler); // Received test() (called from C++, not JS). See WorkerInterface::test(). This version returns // a jsg::Promise; it fails if an exception is thrown. WorkerEntrypoint will catch these // and report them. - jsg::Promise test( - Worker::Lock& lock, kj::Maybe exportedHandler); + jsg::Promise test(Worker::Lock& lock, kj::Maybe exportedHandler); kj::Promise eventTimeoutPromise(uint32_t timeoutMs); - kj::Promise setHibernatableEventTimeout(kj::Promise event, kj::Maybe eventTimeoutMs); + kj::Promise setHibernatableEventTimeout( + kj::Promise event, kj::Maybe eventTimeoutMs); - void sendHibernatableWebSocketMessage( - kj::OneOf> message, + void sendHibernatableWebSocketMessage(kj::OneOf> message, kj::Maybe eventTimeoutMs, kj::String websocketId, Worker::Lock& lock, kj::Maybe exportedHandler); - void sendHibernatableWebSocketClose( - HibernatableSocketParams::Close close, + void sendHibernatableWebSocketClose(HibernatableSocketParams::Close close, kj::Maybe eventTimeoutMs, kj::String websocketId, Worker::Lock& lock, kj::Maybe exportedHandler); - void sendHibernatableWebSocketError( - kj::Exception e, + void sendHibernatableWebSocketError(kj::Exception e, kj::Maybe eventTimeoutMs, kj::String websocketId, Worker::Lock& lock, kj::Maybe exportedHandler); - void emitPromiseRejection( - jsg::Lock& js, + void emitPromiseRejection(jsg::Lock& js, v8::PromiseRejectEvent event, jsg::V8Ref promise, jsg::Value value); @@ -438,28 +466,26 @@ class ServiceWorkerGlobalScope: public WorkerGlobalScope { }; jsg::JsValue structuredClone( - jsg::Lock& js, - jsg::JsValue value, - jsg::Optional options); + jsg::Lock& js, jsg::JsValue value, jsg::Optional options); TimeoutId::NumberType setTimeout(jsg::Lock& js, - jsg::Function)> function, - jsg::Optional msDelay, - jsg::Arguments args); + jsg::Function)> function, + jsg::Optional msDelay, + jsg::Arguments args); void clearTimeout(kj::Maybe timeoutId); - TimeoutId::NumberType setTimeoutInternal( - jsg::Function function, - double msDelay); + TimeoutId::NumberType setTimeoutInternal(jsg::Function function, double msDelay); TimeoutId::NumberType setInterval(jsg::Lock& js, - jsg::Function)> function, - jsg::Optional msDelay, - jsg::Arguments args); - void clearInterval(kj::Maybe timeoutId) { clearTimeout(timeoutId); } + jsg::Function)> function, + jsg::Optional msDelay, + jsg::Arguments args); + void clearInterval(kj::Maybe timeoutId) { + clearTimeout(timeoutId); + } - jsg::Promise> fetch( - jsg::Lock& js, kj::OneOf, kj::String> request, + jsg::Promise> fetch(jsg::Lock& js, + kj::OneOf, kj::String> request, jsg::Optional requestInitr); jsg::Ref getSelf() { @@ -483,7 +509,9 @@ class ServiceWorkerGlobalScope: public WorkerGlobalScope { // The origin is unknown, return "null" as described in // https://html.spec.whatwg.org/multipage/browsers.html#concept-origin-opaque. - kj::StringPtr getOrigin() { return "null"; } + kj::StringPtr getOrigin() { + return "null"; + } jsg::Ref getCaches(); @@ -495,8 +523,8 @@ class ServiceWorkerGlobalScope: public WorkerGlobalScope { jsg::JsValue getBuffer(jsg::Lock& js); jsg::JsValue getProcess(jsg::Lock& js); jsg::Ref setImmediate(jsg::Lock& js, - jsg::Function)> function, - jsg::Arguments args); + jsg::Function)> function, + jsg::Arguments args); void clearImmediate(kj::Maybe> immediate); JSG_RESOURCE_TYPE(ServiceWorkerGlobalScope, CompatibilityFlags::Reader flags) { @@ -792,17 +820,10 @@ class ServiceWorkerGlobalScope: public WorkerGlobalScope { // be monkeypatchable / mutable at the global scope. }; -#define EW_GLOBAL_SCOPE_ISOLATE_TYPES \ - api::WorkerGlobalScope, \ - api::ServiceWorkerGlobalScope, \ - api::TestController, \ - api::ExecutionContext, \ - api::ExportedHandler, \ - api::ServiceWorkerGlobalScope::StructuredCloneOptions, \ - api::PromiseRejectionEvent, \ - api::Navigator, \ - api::Performance, \ - api::AlarmInvocationInfo, \ - api::Immediate +#define EW_GLOBAL_SCOPE_ISOLATE_TYPES \ + api::WorkerGlobalScope, api::ServiceWorkerGlobalScope, api::TestController, \ + api::ExecutionContext, api::ExportedHandler, \ + api::ServiceWorkerGlobalScope::StructuredCloneOptions, api::PromiseRejectionEvent, \ + api::Navigator, api::Performance, api::AlarmInvocationInfo, api::Immediate // The list of global-scope.h types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE } // namespace workerd::api diff --git a/src/workerd/api/gpu/gpu-adapter-info.c++ b/src/workerd/api/gpu/gpu-adapter-info.c++ index 9e47e51a76b..40ef821ec3f 100644 --- a/src/workerd/api/gpu/gpu-adapter-info.c++ +++ b/src/workerd/api/gpu/gpu-adapter-info.c++ @@ -7,7 +7,9 @@ namespace workerd::api::gpu { GPUAdapterInfo::GPUAdapterInfo(wgpu::AdapterInfo info) - : vendor_(kj::str(info.vendor)), architecture_(kj::str(info.architecture)), - device_(kj::str(info.device)), description_(kj::str(info.description)) {} + : vendor_(kj::str(info.vendor)), + architecture_(kj::str(info.architecture)), + device_(kj::str(info.device)), + description_(kj::str(info.description)) {} -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-adapter-info.h b/src/workerd/api/gpu/gpu-adapter-info.h index 46ab7fd34fb..553f446fc7f 100644 --- a/src/workerd/api/gpu/gpu-adapter-info.h +++ b/src/workerd/api/gpu/gpu-adapter-info.h @@ -9,7 +9,7 @@ namespace workerd::api::gpu { -class GPUAdapterInfo : public jsg::Object { +class GPUAdapterInfo: public jsg::Object { public: explicit GPUAdapterInfo(wgpu::AdapterInfo); JSG_RESOURCE_TYPE(GPUAdapterInfo) { @@ -45,4 +45,4 @@ class GPUAdapterInfo : public jsg::Object { }; }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-adapter.c++ b/src/workerd/api/gpu/gpu-adapter.c++ index a8d648a9e70..99001ee217e 100644 --- a/src/workerd/api/gpu/gpu-adapter.c++ +++ b/src/workerd/api/gpu/gpu-adapter.c++ @@ -56,8 +56,8 @@ void setLimit(wgpu::RequiredLimits& limits, kj::StringPtr name, unsigned long lo JSG_FAIL_REQUIRE(TypeError, "unknown limit", name); } -jsg::Promise> -GPUAdapter::requestAdapterInfo(jsg::Lock& js, jsg::Optional> unmaskHints) { +jsg::Promise> GPUAdapter::requestAdapterInfo( + jsg::Lock& js, jsg::Optional> unmaskHints) { wgpu::AdapterInfo info = {}; adapter_.GetInfo(&info); @@ -67,19 +67,19 @@ GPUAdapter::requestAdapterInfo(jsg::Lock& js, jsg::Optional> -GPUAdapter::requestDevice(jsg::Lock& js, jsg::Optional descriptor) { +jsg::Promise> GPUAdapter::requestDevice( + jsg::Lock& js, jsg::Optional descriptor) { wgpu::DeviceDescriptor desc{}; kj::Vector requiredFeatures; wgpu::RequiredLimits limits; @@ -89,7 +89,7 @@ GPUAdapter::requestDevice(jsg::Lock& js, jsg::Optional desc } KJ_IF_SOME(features, d.requiredFeatures) { - for (auto& required : features) { + for (auto& required: features) { requiredFeatures.add(parseFeatureName(required)); } @@ -98,7 +98,7 @@ GPUAdapter::requestDevice(jsg::Lock& js, jsg::Optional desc } KJ_IF_SOME(requiredLimits, d.requiredLimits) { - for (auto& f : requiredLimits.fields) { + for (auto& f: requiredLimits.fields) { setLimit(limits, f.name, f.value); } desc.requiredLimits = &limits; @@ -107,52 +107,50 @@ GPUAdapter::requestDevice(jsg::Lock& js, jsg::Optional desc using DeviceLostContext = AsyncContext>; auto deviceLostCtx = kj::refcounted(js, kj::addRef(*async_)); - desc.SetDeviceLostCallback( - wgpu::CallbackMode::AllowSpontaneous, - [ctx = kj::addRef(*deviceLostCtx)](const wgpu::Device&, wgpu::DeviceLostReason reason, - const char* message) mutable { - auto r = parseDeviceLostReason(reason); - if (ctx->fulfiller_->isWaiting()) { - auto lostInfo = jsg::alloc(kj::mv(r), kj::str(message)); - ctx->fulfiller_->fulfill(kj::mv(lostInfo)); - } - }); + desc.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous, + [ctx = kj::addRef(*deviceLostCtx)]( + const wgpu::Device&, wgpu::DeviceLostReason reason, const char* message) mutable { + auto r = parseDeviceLostReason(reason); + if (ctx->fulfiller_->isWaiting()) { + auto lostInfo = jsg::alloc(kj::mv(r), kj::str(message)); + ctx->fulfiller_->fulfill(kj::mv(lostInfo)); + } + }); auto uErrorCtx = kj::heap(); desc.SetUncapturedErrorCallback( [](const wgpu::Device&, wgpu::ErrorType type, const char* message, void* userdata) { - auto maybeTarget = static_cast*>(userdata); - - KJ_IF_SOME(target, *maybeTarget) { - if (target->getHandlerCount("uncapturederror") > 0) { - jsg::Ref error = nullptr; - switch (type) { - case wgpu::ErrorType::Validation: - error = jsg::alloc(kj::str(message)); - break; - case wgpu::ErrorType::NoError: - KJ_UNREACHABLE; - case wgpu::ErrorType::OutOfMemory: - error = jsg::alloc(kj::str(message)); - break; - case wgpu::ErrorType::Internal: - case wgpu::ErrorType::DeviceLost: - case wgpu::ErrorType::Unknown: - error = jsg::alloc(kj::str(message)); - break; - } - - auto init = GPUUncapturedErrorEventInit{kj::mv(error)}; - auto ev = jsg::alloc("uncapturederror"_kj, kj::mv(init)); - target->dispatchEventImpl(IoContext::current().getCurrentLock(), kj::mv(ev)); - return; - } + auto maybeTarget = static_cast*>(userdata); + + KJ_IF_SOME(target, *maybeTarget) { + if (target->getHandlerCount("uncapturederror") > 0) { + jsg::Ref error = nullptr; + switch (type) { + case wgpu::ErrorType::Validation: + error = jsg::alloc(kj::str(message)); + break; + case wgpu::ErrorType::NoError: + KJ_UNREACHABLE; + case wgpu::ErrorType::OutOfMemory: + error = jsg::alloc(kj::str(message)); + break; + case wgpu::ErrorType::Internal: + case wgpu::ErrorType::DeviceLost: + case wgpu::ErrorType::Unknown: + error = jsg::alloc(kj::str(message)); + break; } - // no "uncapturederror" handler - KJ_LOG(INFO, "WebGPU uncaptured error", kj::str((uint32_t)type), message); - }, - (void*)&uErrorCtx->target); + auto init = GPUUncapturedErrorEventInit{kj::mv(error)}; + auto ev = jsg::alloc("uncapturederror"_kj, kj::mv(init)); + target->dispatchEventImpl(IoContext::current().getCurrentLock(), kj::mv(ev)); + return; + } + } + + // no "uncapturederror" handler + KJ_LOG(INFO, "WebGPU uncaptured error", kj::str((uint32_t)type), message); + }, (void*)&uErrorCtx->target); struct UserData { wgpu::Device device = nullptr; @@ -160,16 +158,14 @@ GPUAdapter::requestDevice(jsg::Lock& js, jsg::Optional desc }; UserData userData; - adapter_.RequestDevice( - &desc, + adapter_.RequestDevice(&desc, [](WGPURequestDeviceStatus status, WGPUDevice cDevice, const char* message, void* pUserData) { - JSG_REQUIRE(status == WGPURequestDeviceStatus_Success, Error, message); + JSG_REQUIRE(status == WGPURequestDeviceStatus_Success, Error, message); - UserData& userData = *reinterpret_cast(pUserData); - userData.device = wgpu::Device::Acquire(cDevice); - userData.requestEnded = true; - }, - (void*)&userData); + UserData& userData = *reinterpret_cast(pUserData); + userData.device = wgpu::Device::Acquire(cDevice); + userData.requestEnded = true; + }, (void*)&userData); KJ_ASSERT(userData.requestEnded); @@ -202,4 +198,4 @@ jsg::Ref GPUAdapter::getLimits() { return jsg::alloc(kj::mv(wgpuLimits)); } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-adapter.h b/src/workerd/api/gpu/gpu-adapter.h index c9bbedffc55..56b6fd334c3 100644 --- a/src/workerd/api/gpu/gpu-adapter.h +++ b/src/workerd/api/gpu/gpu-adapter.h @@ -15,10 +15,11 @@ namespace workerd::api::gpu { -class GPUAdapter : public jsg::Object { +class GPUAdapter: public jsg::Object { public: explicit GPUAdapter(dawn::native::Adapter a, kj::Own async) - : adapter_(a), async_(kj::mv(async)){}; + : adapter_(a), + async_(kj::mv(async)) {}; JSG_RESOURCE_TYPE(GPUAdapter) { JSG_METHOD(requestDevice); JSG_METHOD(requestAdapterInfo); @@ -30,10 +31,10 @@ class GPUAdapter : public jsg::Object { jsg::Promise> requestDevice(jsg::Lock&, jsg::Optional); dawn::native::Adapter adapter_; kj::Own async_; - jsg::Promise> - requestAdapterInfo(jsg::Lock& js, jsg::Optional> unmaskHints); + jsg::Promise> requestAdapterInfo( + jsg::Lock& js, jsg::Optional> unmaskHints); jsg::Ref getFeatures(); jsg::Ref getLimits(); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-async-runner.c++ b/src/workerd/api/gpu/gpu-async-runner.c++ index 492da03a7a7..94438583aa3 100644 --- a/src/workerd/api/gpu/gpu-async-runner.c++ +++ b/src/workerd/api/gpu/gpu-async-runner.c++ @@ -29,16 +29,13 @@ void AsyncRunner::QueueTick() { } tick_queued_ = true; - IoContext::current().setTimeoutImpl( - timeoutIdGenerator, false, - [this](jsg::Lock& js) mutable { - this->tick_queued_ = false; - if (this->count_ > 0) { - this->instance_.ProcessEvents(); - QueueTick(); - } - }, - BUSY_LOOP_DELAY_MS); + IoContext::current().setTimeoutImpl(timeoutIdGenerator, false, [this](jsg::Lock& js) mutable { + this->tick_queued_ = false; + if (this->count_ > 0) { + this->instance_.ProcessEvents(); + QueueTick(); + } + }, BUSY_LOOP_DELAY_MS); } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-async-runner.h b/src/workerd/api/gpu/gpu-async-runner.h index 696ac8da59c..df9a955a916 100644 --- a/src/workerd/api/gpu/gpu-async-runner.h +++ b/src/workerd/api/gpu/gpu-async-runner.h @@ -14,9 +14,9 @@ namespace workerd::api::gpu { // AsyncRunner is used to poll a wgpu::Instance with calls to ProcessEvents() while there // are asynchronous tasks in flight. -class AsyncRunner : public kj::Refcounted { +class AsyncRunner: public kj::Refcounted { public: - AsyncRunner(wgpu::Instance instance) : instance_(instance){}; + AsyncRunner(wgpu::Instance instance): instance_(instance) {}; // Begin() should be called when a new asynchronous task is started. // If the number of executing asynchronous tasks transitions from 0 to 1, then @@ -40,14 +40,16 @@ class AsyncRunner : public kj::Refcounted { // AsyncTask is a RAII helper for calling AsyncRunner::Begin() on construction, // and AsyncRunner::End() on destruction, that also encapsulates the promise generally // associated with any async task. -template class AsyncContext : public kj::Refcounted { +template +class AsyncContext: public kj::Refcounted { public: inline AsyncContext(AsyncContext&&) = default; // Constructor. // Calls AsyncRunner::Begin() explicit inline AsyncContext(jsg::Lock& js, kj::Own runner) - : promise_(nullptr), runner_(kj::mv(runner)) { + : promise_(nullptr), + runner_(kj::mv(runner)) { auto& context = IoContext::current(); auto paf = kj::newPromiseAndFulfiller(); fulfiller_ = kj::mv(paf.fulfiller); @@ -70,4 +72,4 @@ template class AsyncContext : public kj::Refcounted { kj::Own runner_; }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-bindgroup-layout.c++ b/src/workerd/api/gpu/gpu-bindgroup-layout.c++ index 3e258352648..f19a7741d6b 100644 --- a/src/workerd/api/gpu/gpu-bindgroup-layout.c++ +++ b/src/workerd/api/gpu/gpu-bindgroup-layout.c++ @@ -95,8 +95,8 @@ wgpu::TextureBindingLayout parseTextureBindingLayout(GPUTextureBindingLayout& te return kj::mv(layout); } -wgpu::StorageTextureBindingLayout -parseStorageTextureBindingLayout(GPUStorageTextureBindingLayout& storage) { +wgpu::StorageTextureBindingLayout parseStorageTextureBindingLayout( + GPUStorageTextureBindingLayout& storage) { wgpu::StorageTextureBindingLayout layout; layout.access = parseStorageAccess(storage.access.orDefault([] { return "write-only"_kj; })); @@ -131,4 +131,4 @@ wgpu::BindGroupLayoutEntry parseBindGroupLayoutEntry(GPUBindGroupLayoutEntry& en return kj::mv(layoutEntry); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-bindgroup-layout.h b/src/workerd/api/gpu/gpu-bindgroup-layout.h index 71ee29334c6..c903e0c1696 100644 --- a/src/workerd/api/gpu/gpu-bindgroup-layout.h +++ b/src/workerd/api/gpu/gpu-bindgroup-layout.h @@ -10,9 +10,9 @@ namespace workerd::api::gpu { -class GPUBindGroupLayout : public jsg::Object { +class GPUBindGroupLayout: public jsg::Object { public: - explicit GPUBindGroupLayout(wgpu::BindGroupLayout l) : layout_(kj::mv(l)){}; + explicit GPUBindGroupLayout(wgpu::BindGroupLayout l): layout_(kj::mv(l)) {}; // Implicit cast operator to Dawn GPU object inline operator const wgpu::BindGroupLayout&() const { @@ -77,4 +77,4 @@ struct GPUBindGroupLayoutDescriptor { wgpu::BindGroupLayoutEntry parseBindGroupLayoutEntry(GPUBindGroupLayoutEntry&); -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-bindgroup.c++ b/src/workerd/api/gpu/gpu-bindgroup.c++ index 7e6c052a75c..d5da6a590c1 100644 --- a/src/workerd/api/gpu/gpu-bindgroup.c++ +++ b/src/workerd/api/gpu/gpu-bindgroup.c++ @@ -13,10 +13,10 @@ wgpu::BindGroupEntry parseBindGroupEntry(GPUBindGroupEntry& entry) { KJ_SWITCH_ONEOF(entry.resource) { KJ_CASE_ONEOF(buffer, GPUBufferBinding) { e.buffer = *buffer.buffer; - KJ_IF_SOME (offset, buffer.offset) { + KJ_IF_SOME(offset, buffer.offset) { e.offset = offset; } - KJ_IF_SOME (size, buffer.size) { + KJ_IF_SOME(size, buffer.size) { e.size = size; } } @@ -28,4 +28,4 @@ wgpu::BindGroupEntry parseBindGroupEntry(GPUBindGroupEntry& entry) { return kj::mv(e); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-bindgroup.h b/src/workerd/api/gpu/gpu-bindgroup.h index 8989363b502..1b664769a32 100644 --- a/src/workerd/api/gpu/gpu-bindgroup.h +++ b/src/workerd/api/gpu/gpu-bindgroup.h @@ -13,13 +13,13 @@ namespace workerd::api::gpu { -class GPUBindGroup : public jsg::Object { +class GPUBindGroup: public jsg::Object { public: // Implicit cast operator to Dawn GPU object inline operator const wgpu::BindGroup&() const { return group_; } - explicit GPUBindGroup(wgpu::BindGroup g) : group_(kj::mv(g)){}; + explicit GPUBindGroup(wgpu::BindGroup g): group_(kj::mv(g)) {}; JSG_RESOURCE_TYPE(GPUBindGroup) {} private: @@ -54,4 +54,4 @@ struct GPUBindGroupDescriptor { wgpu::BindGroupEntry parseBindGroupEntry(GPUBindGroupEntry&); -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-buffer.c++ b/src/workerd/api/gpu/gpu-buffer.c++ index 265e527880c..8e6978c35a1 100644 --- a/src/workerd/api/gpu/gpu-buffer.c++ +++ b/src/workerd/api/gpu/gpu-buffer.c++ @@ -8,9 +8,15 @@ namespace workerd::api::gpu { -GPUBuffer::GPUBuffer(jsg::Lock& js, wgpu::Buffer b, wgpu::BufferDescriptor desc, - wgpu::Device device, kj::Own async) - : buffer_(kj::mv(b)), device_(kj::mv(device)), desc_(kj::mv(desc)), async_(kj::mv(async)), +GPUBuffer::GPUBuffer(jsg::Lock& js, + wgpu::Buffer b, + wgpu::BufferDescriptor desc, + wgpu::Device device, + kj::Own async) + : buffer_(kj::mv(b)), + device_(kj::mv(device)), + desc_(kj::mv(desc)), + async_(kj::mv(async)), detachKey_(js.v8Ref(v8::Object::New(js.v8Isolate))) { if (desc.mappedAtCreation) { @@ -18,26 +24,26 @@ GPUBuffer::GPUBuffer(jsg::Lock& js, wgpu::Buffer b, wgpu::BufferDescriptor desc, } }; -v8::Local GPUBuffer::getMappedRange(jsg::Lock& js, jsg::Optional offset, - jsg::Optional size) { +v8::Local GPUBuffer::getMappedRange( + jsg::Lock& js, jsg::Optional offset, jsg::Optional size) { JSG_REQUIRE(state_ == State::Mapped || state_ == State::MappedAtCreation, TypeError, - "trying to get mapped range of unmapped buffer"); + "trying to get mapped range of unmapped buffer"); uint64_t o = offset.orDefault(0); uint64_t s = size.orDefault(desc_.size - o); uint64_t start = o; uint64_t end = o + s; - for (auto& mapping : mapped_) { + for (auto& mapping: mapped_) { if (mapping.Intersects(start, end)) { JSG_FAIL_REQUIRE(TypeError, "mapping intersects with existing one"); } } auto* ptr = (desc_.usage & wgpu::BufferUsage::MapWrite) - ? buffer_.GetMappedRange(o, s) - : const_cast(buffer_.GetConstMappedRange(o, s)); + ? buffer_.GetMappedRange(o, s) + : const_cast(buffer_.GetConstMappedRange(o, s)); JSG_REQUIRE(ptr, TypeError, "could not obtain mapped range"); @@ -50,15 +56,13 @@ v8::Local GPUBuffer::getMappedRange(jsg::Lock& js, jsg::Optiona // object to ensure that it still lives while the arraybuffer is in scope. // This object will be deallocated when the callback finishes. auto ctx = new Context{ref.addRef()}; - std::shared_ptr backing = v8::ArrayBuffer::NewBackingStore( - ptr, s, - [](void* data, size_t length, void* deleter_data) { - // we have a persistent reference to GPUBuffer so that it lives at least - // as long as this arraybuffer - // Note: this is invoked outside the JS isolate lock - auto c = std::unique_ptr(static_cast(deleter_data)); - }, - ctx); + std::shared_ptr backing = + v8::ArrayBuffer::NewBackingStore(ptr, s, [](void* data, size_t length, void* deleter_data) { + // we have a persistent reference to GPUBuffer so that it lives at least + // as long as this arraybuffer + // Note: this is invoked outside the JS isolate lock + auto c = std::unique_ptr(static_cast(deleter_data)); + }, ctx); v8::Local arrayBuffer = v8::ArrayBuffer::New(js.v8Isolate, backing); arrayBuffer->SetDetachKey(detachKey_.getHandle(js)); @@ -68,7 +72,7 @@ v8::Local GPUBuffer::getMappedRange(jsg::Lock& js, jsg::Optiona } void GPUBuffer::DetachMappings(jsg::Lock& js) { - for (auto& mapping : mapped_) { + for (auto& mapping: mapped_) { auto ab = mapping.buffer.getHandle(js); auto res = ab->Detach(detachKey_.getHandle(js)); @@ -99,15 +103,16 @@ void GPUBuffer::unmap(jsg::Lock& js) { } } -jsg::Promise GPUBuffer::mapAsync(jsg::Lock& js, GPUFlagsConstant mode, - jsg::Optional offset, - jsg::Optional size) { +jsg::Promise GPUBuffer::mapAsync(jsg::Lock& js, + GPUFlagsConstant mode, + jsg::Optional offset, + jsg::Optional size) { wgpu::MapMode md = static_cast(mode); // we can only map unmapped buffers if (state_ != State::Unmapped) { - device_.InjectError(wgpu::ErrorType::Validation, - "mapAsync called on buffer that is not in the unmapped state"); + device_.InjectError( + wgpu::ErrorType::Validation, "mapAsync called on buffer that is not in the unmapped state"); JSG_FAIL_REQUIRE(Error, "mapAsync called on buffer that is not in the unmapped state"); } @@ -125,31 +130,30 @@ jsg::Promise GPUBuffer::mapAsync(jsg::Lock& js, GPUFlagsConstant mode, state_ = State::MappingPending; buffer_.MapAsync(md, o, s, wgpu::CallbackMode::AllowProcessEvents, - [ctx = kj::mv(ctx), this](wgpu::MapAsyncStatus status, char const*) mutable { - // Note: this is invoked outside the JS isolate lock - state_ = State::Unmapped; - - JSG_REQUIRE(ctx->fulfiller_->isWaiting(), TypeError, - "async operation has been canceled"); - - switch (status) { - case wgpu::MapAsyncStatus::Success: - ctx->fulfiller_->fulfill(); - state_ = State::Mapped; - break; - case wgpu::MapAsyncStatus::Aborted: - ctx->fulfiller_->reject(JSG_KJ_EXCEPTION(FAILED, TypeError, "aborted")); - break; - case wgpu::MapAsyncStatus::Unknown: - case wgpu::MapAsyncStatus::Error: - case wgpu::MapAsyncStatus::InstanceDropped: - ctx->fulfiller_->reject( - JSG_KJ_EXCEPTION(FAILED, TypeError, "unknown error or device lost")); - break; - } - }); + [ctx = kj::mv(ctx), this](wgpu::MapAsyncStatus status, char const*) mutable { + // Note: this is invoked outside the JS isolate lock + state_ = State::Unmapped; + + JSG_REQUIRE(ctx->fulfiller_->isWaiting(), TypeError, "async operation has been canceled"); + + switch (status) { + case wgpu::MapAsyncStatus::Success: + ctx->fulfiller_->fulfill(); + state_ = State::Mapped; + break; + case wgpu::MapAsyncStatus::Aborted: + ctx->fulfiller_->reject(JSG_KJ_EXCEPTION(FAILED, TypeError, "aborted")); + break; + case wgpu::MapAsyncStatus::Unknown: + case wgpu::MapAsyncStatus::Error: + case wgpu::MapAsyncStatus::InstanceDropped: + ctx->fulfiller_->reject( + JSG_KJ_EXCEPTION(FAILED, TypeError, "unknown error or device lost")); + break; + } + }); return promise; } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-buffer.h b/src/workerd/api/gpu/gpu-buffer.h index 92711fcc412..67767de7008 100644 --- a/src/workerd/api/gpu/gpu-buffer.h +++ b/src/workerd/api/gpu/gpu-buffer.h @@ -10,14 +10,14 @@ namespace workerd::api::gpu { -class GPUBuffer : public jsg::Object { +class GPUBuffer: public jsg::Object { public: // Implicit cast operator to Dawn GPU object inline operator const wgpu::Buffer&() const { return buffer_; } - explicit GPUBuffer(jsg::Lock& js, wgpu::Buffer, wgpu::BufferDescriptor, wgpu::Device, - kj::Own); + explicit GPUBuffer( + jsg::Lock& js, wgpu::Buffer, wgpu::BufferDescriptor, wgpu::Device, kj::Own); JSG_RESOURCE_TYPE(GPUBuffer) { JSG_METHOD(getMappedRange); @@ -30,7 +30,7 @@ class GPUBuffer : public jsg::Object { } void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { - for (const auto& mapping : mapped_) { + for (const auto& mapping: mapped_) { tracker.trackField(nullptr, mapping); } tracker.trackField("detachKey", detachKey_); @@ -66,8 +66,8 @@ class GPUBuffer : public jsg::Object { kj::Vector mapped_; jsg::V8Ref detachKey_; - v8::Local getMappedRange(jsg::Lock&, jsg::Optional offset, - jsg::Optional size); + v8::Local getMappedRange( + jsg::Lock&, jsg::Optional offset, jsg::Optional size); GPUSize64 getSize() { return buffer_.GetSize(); @@ -79,12 +79,12 @@ class GPUBuffer : public jsg::Object { GPUBufferMapState getMapState() { switch (buffer_.GetMapState()) { - case wgpu::BufferMapState::Unmapped: - return kj::str("unmapped"); - case wgpu::BufferMapState::Pending: - return kj::str("pending"); - case wgpu::BufferMapState::Mapped: - return kj::str("mapped"); + case wgpu::BufferMapState::Unmapped: + return kj::str("unmapped"); + case wgpu::BufferMapState::Pending: + return kj::str("pending"); + case wgpu::BufferMapState::Mapped: + return kj::str("mapped"); }; KJ_UNREACHABLE; @@ -92,8 +92,10 @@ class GPUBuffer : public jsg::Object { void unmap(jsg::Lock& js); void destroy(jsg::Lock& js); - jsg::Promise mapAsync(jsg::Lock&, GPUFlagsConstant mode, jsg::Optional offset, - jsg::Optional size); + jsg::Promise mapAsync(jsg::Lock&, + GPUFlagsConstant mode, + jsg::Optional offset, + jsg::Optional size); void DetachMappings(jsg::Lock& js); }; @@ -105,4 +107,4 @@ struct GPUBufferDescriptor { JSG_STRUCT(label, size, usage, mappedAtCreation); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-command-buffer.h b/src/workerd/api/gpu/gpu-command-buffer.h index 89d5d32078d..3577d6718e8 100644 --- a/src/workerd/api/gpu/gpu-command-buffer.h +++ b/src/workerd/api/gpu/gpu-command-buffer.h @@ -9,13 +9,13 @@ namespace workerd::api::gpu { -class GPUCommandBuffer : public jsg::Object { +class GPUCommandBuffer: public jsg::Object { public: // Implicit cast operator to Dawn GPU object inline operator const wgpu::CommandBuffer&() const { return cmd_buf_; } - explicit GPUCommandBuffer(wgpu::CommandBuffer b) : cmd_buf_(kj::mv(b)){}; + explicit GPUCommandBuffer(wgpu::CommandBuffer b): cmd_buf_(kj::mv(b)) {}; JSG_RESOURCE_TYPE(GPUCommandBuffer) {} private: @@ -28,4 +28,4 @@ struct GPUCommandBufferDescriptor { JSG_STRUCT(label); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-command-encoder.c++ b/src/workerd/api/gpu/gpu-command-encoder.c++ index 180e0027dee..24b6862501f 100644 --- a/src/workerd/api/gpu/gpu-command-encoder.c++ +++ b/src/workerd/api/gpu/gpu-command-encoder.c++ @@ -8,8 +8,8 @@ namespace workerd::api::gpu { -jsg::Ref -GPUCommandEncoder::finish(jsg::Optional descriptor) { +jsg::Ref GPUCommandEncoder::finish( + jsg::Optional descriptor) { wgpu::CommandBufferDescriptor desc{}; KJ_IF_SOME(d, descriptor) { @@ -81,18 +81,18 @@ wgpu::Extent3D parseGPUExtent3D(GPUExtent3D copySize) { // if we have a sequence of coordinates we assume that the order is: width, heigth, depth, if // available, and ignore all the rest. switch (coords.size()) { - default: - case 3: - size.depthOrArrayLayers = coords[2]; - KJ_FALLTHROUGH; - case 2: - size.height = coords[1]; - KJ_FALLTHROUGH; - case 1: - size.width = coords[0]; - break; - case 0: - JSG_FAIL_REQUIRE(TypeError, "invalid value for GPUExtent3D"); + default: + case 3: + size.depthOrArrayLayers = coords[2]; + KJ_FALLTHROUGH; + case 2: + size.height = coords[1]; + KJ_FALLTHROUGH; + case 1: + size.width = coords[0]; + break; + case 0: + JSG_FAIL_REQUIRE(TypeError, "invalid value for GPUExtent3D"); } } KJ_CASE_ONEOF(someSize, GPUExtent3DDict) { @@ -109,9 +109,8 @@ wgpu::Extent3D parseGPUExtent3D(GPUExtent3D copySize) { return kj::mv(size); } -void GPUCommandEncoder::copyTextureToTexture(GPUImageCopyTexture source, - GPUImageCopyTexture destination, - GPUExtent3D copySize) { +void GPUCommandEncoder::copyTextureToTexture( + GPUImageCopyTexture source, GPUImageCopyTexture destination, GPUExtent3D copySize) { wgpu::ImageCopyTexture src = parseGPUImageCopyTexture(kj::mv(source)); wgpu::ImageCopyTexture dst = parseGPUImageCopyTexture(kj::mv(destination)); wgpu::Extent3D size = parseGPUExtent3D(kj::mv(copySize)); @@ -119,8 +118,8 @@ void GPUCommandEncoder::copyTextureToTexture(GPUImageCopyTexture source, encoder_.CopyTextureToTexture(&src, &dst, &size); } -void GPUCommandEncoder::copyBufferToTexture(GPUImageCopyBuffer source, - GPUImageCopyTexture destination, GPUExtent3D copySize) { +void GPUCommandEncoder::copyBufferToTexture( + GPUImageCopyBuffer source, GPUImageCopyTexture destination, GPUExtent3D copySize) { wgpu::ImageCopyBuffer src = parseGPUImageCopyBuffer(kj::mv(source)); wgpu::ImageCopyTexture dst = parseGPUImageCopyTexture(kj::mv(destination)); @@ -129,8 +128,8 @@ void GPUCommandEncoder::copyBufferToTexture(GPUImageCopyBuffer source, encoder_.CopyBufferToTexture(&src, &dst, &size); } -void GPUCommandEncoder::copyTextureToBuffer(GPUImageCopyTexture source, - GPUImageCopyBuffer destination, GPUExtent3D copySize) { +void GPUCommandEncoder::copyTextureToBuffer( + GPUImageCopyTexture source, GPUImageCopyBuffer destination, GPUExtent3D copySize) { wgpu::ImageCopyTexture src = parseGPUImageCopyTexture(kj::mv(source)); wgpu::ImageCopyBuffer dst = parseGPUImageCopyBuffer(kj::mv(destination)); wgpu::Extent3D size = parseGPUExtent3D(kj::mv(copySize)); @@ -138,23 +137,25 @@ void GPUCommandEncoder::copyTextureToBuffer(GPUImageCopyTexture source, encoder_.CopyTextureToBuffer(&src, &dst, &size); } -void GPUCommandEncoder::copyBufferToBuffer(jsg::Ref source, GPUSize64 sourceOffset, - jsg::Ref destination, - GPUSize64 destinationOffset, GPUSize64 size) { +void GPUCommandEncoder::copyBufferToBuffer(jsg::Ref source, + GPUSize64 sourceOffset, + jsg::Ref destination, + GPUSize64 destinationOffset, + GPUSize64 size) { encoder_.CopyBufferToBuffer(*source, sourceOffset, *destination, destinationOffset, size); }; -void GPUCommandEncoder::clearBuffer(jsg::Ref buffer, jsg::Optional offset, - jsg::Optional size) { +void GPUCommandEncoder::clearBuffer( + jsg::Ref buffer, jsg::Optional offset, jsg::Optional size) { uint64_t o = offset.orDefault(0); uint64_t s = size.orDefault(wgpu::kWholeSize); encoder_.ClearBuffer(*buffer, o, s); } -jsg::Ref -GPUCommandEncoder::beginRenderPass(GPURenderPassDescriptor descriptor) { +jsg::Ref GPUCommandEncoder::beginRenderPass( + GPURenderPassDescriptor descriptor) { wgpu::RenderPassDescriptor desc{}; @@ -163,7 +164,7 @@ GPUCommandEncoder::beginRenderPass(GPURenderPassDescriptor descriptor) { } kj::Vector colorAttachments; - for (auto& attach : descriptor.colorAttachments) { + for (auto& attach: descriptor.colorAttachments) { wgpu::RenderPassColorAttachment cAttach{}; cAttach.view = *attach.view; // TODO: depthSlice is not yet supported by dawn @@ -249,8 +250,8 @@ GPUCommandEncoder::beginRenderPass(GPURenderPassDescriptor descriptor) { return jsg::alloc(kj::mv(renderPassEncoder)); } -jsg::Ref -GPUCommandEncoder::beginComputePass(jsg::Optional descriptor) { +jsg::Ref GPUCommandEncoder::beginComputePass( + jsg::Optional descriptor) { wgpu::ComputePassDescriptor desc{}; @@ -277,4 +278,4 @@ GPUCommandEncoder::beginComputePass(jsg::Optional desc return jsg::alloc(kj::mv(computePassEncoder)); } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-command-encoder.h b/src/workerd/api/gpu/gpu-command-encoder.h index cacdbf9d62f..702123bb8a2 100644 --- a/src/workerd/api/gpu/gpu-command-encoder.h +++ b/src/workerd/api/gpu/gpu-command-encoder.h @@ -37,10 +37,11 @@ struct GPUImageCopyBuffer { JSG_STRUCT(buffer, offset, bytesPerRow, rowsPerImage); }; -class GPUCommandEncoder : public jsg::Object { +class GPUCommandEncoder: public jsg::Object { public: explicit GPUCommandEncoder(wgpu::CommandEncoder e, kj::String label) - : encoder_(kj::mv(e)), label_(kj::mv(label)){}; + : encoder_(kj::mv(e)), + label_(kj::mv(label)) {}; JSG_RESOURCE_TYPE(GPUCommandEncoder) { JSG_READONLY_PROTOTYPE_PROPERTY(label, getLabel); JSG_METHOD(beginComputePass); @@ -64,21 +65,23 @@ class GPUCommandEncoder : public jsg::Object { return label_; } - jsg::Ref - beginComputePass(jsg::Optional descriptor); + jsg::Ref beginComputePass( + jsg::Optional descriptor); jsg::Ref beginRenderPass(GPURenderPassDescriptor descriptor); jsg::Ref finish(jsg::Optional); - void copyBufferToBuffer(jsg::Ref source, GPUSize64 sourceOffset, - jsg::Ref destination, GPUSize64 destinationOffset, - GPUSize64 size); - void copyTextureToBuffer(GPUImageCopyTexture source, GPUImageCopyBuffer destination, - GPUExtent3D copySize); - void copyBufferToTexture(GPUImageCopyBuffer source, GPUImageCopyTexture destination, - GPUExtent3D copySize); - void copyTextureToTexture(GPUImageCopyTexture source, GPUImageCopyTexture destination, - GPUExtent3D copySize); - void clearBuffer(jsg::Ref buffer, jsg::Optional offset, - jsg::Optional size); + void copyBufferToBuffer(jsg::Ref source, + GPUSize64 sourceOffset, + jsg::Ref destination, + GPUSize64 destinationOffset, + GPUSize64 size); + void copyTextureToBuffer( + GPUImageCopyTexture source, GPUImageCopyBuffer destination, GPUExtent3D copySize); + void copyBufferToTexture( + GPUImageCopyBuffer source, GPUImageCopyTexture destination, GPUExtent3D copySize); + void copyTextureToTexture( + GPUImageCopyTexture source, GPUImageCopyTexture destination, GPUExtent3D copySize); + void clearBuffer( + jsg::Ref buffer, jsg::Optional offset, jsg::Optional size); }; struct GPUCommandEncoderDescriptor { @@ -87,4 +90,4 @@ struct GPUCommandEncoderDescriptor { JSG_STRUCT(label); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-compute-pass-encoder.c++ b/src/workerd/api/gpu/gpu-compute-pass-encoder.c++ index 1be36dda8ae..34512280641 100644 --- a/src/workerd/api/gpu/gpu-compute-pass-encoder.c++ +++ b/src/workerd/api/gpu/gpu-compute-pass-encoder.c++ @@ -11,8 +11,8 @@ void GPUComputePassEncoder::setPipeline(jsg::Ref pipeline) { } void GPUComputePassEncoder::dispatchWorkgroups(GPUSize32 workgroupCountX, - jsg::Optional workgroupCountY, - jsg::Optional workgroupCountZ) { + jsg::Optional workgroupCountY, + jsg::Optional workgroupCountZ) { GPUSize32 countY = workgroupCountY.orDefault(1); GPUSize32 countZ = workgroupCountZ.orDefault(1); @@ -24,8 +24,8 @@ void GPUComputePassEncoder::end() { encoder_.End(); } -void GPUComputePassEncoder::setBindGroup( - GPUIndex32 index, kj::Maybe> bindGroup, +void GPUComputePassEncoder::setBindGroup(GPUIndex32 index, + kj::Maybe> bindGroup, jsg::Optional> dynamicOffsets) { wgpu::BindGroup bg = nullptr; @@ -44,4 +44,4 @@ void GPUComputePassEncoder::setBindGroup( encoder_.SetBindGroup(index, bg, num_offsets, offsets); } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-compute-pass-encoder.h b/src/workerd/api/gpu/gpu-compute-pass-encoder.h index 0fb978ac9f0..b8ccf74e608 100644 --- a/src/workerd/api/gpu/gpu-compute-pass-encoder.h +++ b/src/workerd/api/gpu/gpu-compute-pass-encoder.h @@ -13,9 +13,9 @@ namespace workerd::api::gpu { -class GPUComputePassEncoder : public jsg::Object { +class GPUComputePassEncoder: public jsg::Object { public: - explicit GPUComputePassEncoder(wgpu::ComputePassEncoder e) : encoder_(kj::mv(e)){}; + explicit GPUComputePassEncoder(wgpu::ComputePassEncoder e): encoder_(kj::mv(e)) {}; JSG_RESOURCE_TYPE(GPUComputePassEncoder) { JSG_METHOD(setPipeline); JSG_METHOD(setBindGroup); @@ -26,11 +26,13 @@ class GPUComputePassEncoder : public jsg::Object { private: wgpu::ComputePassEncoder encoder_; void setPipeline(jsg::Ref pipeline); - void dispatchWorkgroups(GPUSize32 workgroupCountX, jsg::Optional workgroupCountY, - jsg::Optional workgroupCountZ); + void dispatchWorkgroups(GPUSize32 workgroupCountX, + jsg::Optional workgroupCountY, + jsg::Optional workgroupCountZ); void end(); - void setBindGroup(GPUIndex32 index, kj::Maybe> bindGroup, - jsg::Optional> dynamicOffsets); + void setBindGroup(GPUIndex32 index, + kj::Maybe> bindGroup, + jsg::Optional> dynamicOffsets); // TODO(soon): overloads don't seem to be supported // void setBindGroup(GPUIndex32 index, // kj::Maybe> bindGroup, @@ -55,4 +57,4 @@ struct GPUComputePassDescriptor { JSG_STRUCT(label, timestampWrites); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-compute-pipeline.c++ b/src/workerd/api/gpu/gpu-compute-pipeline.c++ index 0ddabdcb806..05874abdf72 100644 --- a/src/workerd/api/gpu/gpu-compute-pipeline.c++ +++ b/src/workerd/api/gpu/gpu-compute-pipeline.c++ @@ -9,4 +9,4 @@ jsg::Ref GPUComputePipeline::getBindGroupLayout(uint32_t ind auto layout = pipeline_.GetBindGroupLayout(index); return jsg::alloc(kj::mv(layout)); } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-compute-pipeline.h b/src/workerd/api/gpu/gpu-compute-pipeline.h index 95a782f9db9..521bf7e404a 100644 --- a/src/workerd/api/gpu/gpu-compute-pipeline.h +++ b/src/workerd/api/gpu/gpu-compute-pipeline.h @@ -11,13 +11,13 @@ namespace workerd::api::gpu { -class GPUComputePipeline : public jsg::Object { +class GPUComputePipeline: public jsg::Object { public: // Implicit cast operator to Dawn GPU object inline operator const wgpu::ComputePipeline&() const { return pipeline_; } - explicit GPUComputePipeline(wgpu::ComputePipeline p) : pipeline_(kj::mv(p)){}; + explicit GPUComputePipeline(wgpu::ComputePipeline p): pipeline_(kj::mv(p)) {}; JSG_RESOURCE_TYPE(GPUComputePipeline) { JSG_METHOD(getBindGroupLayout); } @@ -35,4 +35,4 @@ struct GPUComputePipelineDescriptor { JSG_STRUCT(label, compute, layout); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-device.c++ b/src/workerd/api/gpu/gpu-device.c++ index 4c23b148529..1b38f7cd726 100644 --- a/src/workerd/api/gpu/gpu-device.c++ +++ b/src/workerd/api/gpu/gpu-device.c++ @@ -38,18 +38,18 @@ jsg::Ref GPUDevice::createTexture(jsg::Lock& js, GPUTextureDescripto // if we have a sequence of coordinates we assume that the order is: width, heigth, depth, if // available, and ignore all the rest. switch (coords.size()) { - default: - case 3: - desc.size.depthOrArrayLayers = coords[2]; - KJ_FALLTHROUGH; - case 2: - desc.size.height = coords[1]; - KJ_FALLTHROUGH; - case 1: - desc.size.width = coords[0]; - break; - case 0: - JSG_FAIL_REQUIRE(TypeError, "invalid value for GPUExtent3D"); + default: + case 3: + desc.size.depthOrArrayLayers = coords[2]; + KJ_FALLTHROUGH; + case 2: + desc.size.height = coords[1]; + KJ_FALLTHROUGH; + case 1: + desc.size.width = coords[0]; + break; + case 0: + JSG_FAIL_REQUIRE(TypeError, "invalid value for GPUExtent3D"); } } KJ_CASE_ONEOF(size, GPUExtent3DDict) { @@ -75,9 +75,8 @@ jsg::Ref GPUDevice::createTexture(jsg::Lock& js, GPUTextureDescripto desc.format = parseTextureFormat(descriptor.format); desc.usage = static_cast(descriptor.usage); KJ_IF_SOME(viewFormatsSeq, descriptor.viewFormats) { - auto viewFormats = KJ_MAP(format, viewFormatsSeq)->wgpu::TextureFormat { - return parseTextureFormat(format); - }; + auto viewFormats = + KJ_MAP(format, viewFormatsSeq)-> wgpu::TextureFormat { return parseTextureFormat(format); }; desc.viewFormats = viewFormats.begin(); desc.viewFormatCount = viewFormats.size(); } @@ -205,8 +204,8 @@ jsg::Ref GPUDevice::createSampler(GPUSamplerDescriptor descriptor) { return jsg::alloc(kj::mv(sampler)); } -jsg::Ref -GPUDevice::createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor) { +jsg::Ref GPUDevice::createBindGroupLayout( + GPUBindGroupLayoutDescriptor descriptor) { wgpu::BindGroupLayoutDescriptor desc{}; KJ_IF_SOME(label, descriptor.label) { @@ -214,7 +213,7 @@ GPUDevice::createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor) { } kj::Vector layoutEntries; - for (auto& e : descriptor.entries) { + for (auto& e: descriptor.entries) { layoutEntries.add(parseBindGroupLayoutEntry(e)); } desc.entries = layoutEntries.begin(); @@ -234,7 +233,7 @@ jsg::Ref GPUDevice::createBindGroup(GPUBindGroupDescriptor descrip desc.layout = *descriptor.layout; kj::Vector bindGroupEntries; - for (auto& e : descriptor.entries) { + for (auto& e: descriptor.entries) { bindGroupEntries.add(parseBindGroupEntry(e)); } @@ -292,8 +291,8 @@ struct ParsedRenderPipelineDescriptor { kj::Vector blends; }; -ParsedRenderPipelineDescriptor -parseRenderPipelineDescriptor(GPURenderPipelineDescriptor& descriptor) { +ParsedRenderPipelineDescriptor parseRenderPipelineDescriptor( + GPURenderPipelineDescriptor& descriptor) { ParsedRenderPipelineDescriptor parsedDesc{}; KJ_IF_SOME(label, descriptor.label) { @@ -306,7 +305,7 @@ parseRenderPipelineDescriptor(GPURenderPipelineDescriptor& descriptor) { KJ_IF_SOME(cDict, descriptor.vertex.constants) { kj::Vector constants; - for (auto& f : cDict.fields) { + for (auto& f: cDict.fields) { wgpu::ConstantEntry e; e.key = f.name.cStr(); e.value = f.value; @@ -321,7 +320,7 @@ parseRenderPipelineDescriptor(GPURenderPipelineDescriptor& descriptor) { KJ_IF_SOME(bList, descriptor.vertex.buffers) { kj::Vector buffers; - for (auto& b : bList) { + for (auto& b: bList) { wgpu::VertexBufferLayout bLayout; bLayout.arrayStride = b.arrayStride; @@ -330,7 +329,7 @@ parseRenderPipelineDescriptor(GPURenderPipelineDescriptor& descriptor) { } kj::Vector attributes; - for (auto& a : b.attributes) { + for (auto& a: b.attributes) { wgpu::VertexAttribute attr; attr.format = parseVertexFormat(a.format); attr.offset = a.offset; @@ -352,7 +351,7 @@ parseRenderPipelineDescriptor(GPURenderPipelineDescriptor& descriptor) { KJ_SWITCH_ONEOF(descriptor.layout) { KJ_CASE_ONEOF(autoLayoutMode, jsg::NonCoercible) { JSG_REQUIRE(autoLayoutMode.value == "auto", TypeError, "unknown auto layout mode", - autoLayoutMode.value); + autoLayoutMode.value); parsedDesc.desc.layout = nullptr; } KJ_CASE_ONEOF(layout, jsg::Ref) { @@ -430,7 +429,7 @@ parseRenderPipelineDescriptor(GPURenderPipelineDescriptor& descriptor) { KJ_IF_SOME(cDict, fragment.constants) { kj::Vector constants; - for (auto& f : cDict.fields) { + for (auto& f: cDict.fields) { wgpu::ConstantEntry e; e.key = f.name.cStr(); e.value = f.value; @@ -443,7 +442,7 @@ parseRenderPipelineDescriptor(GPURenderPipelineDescriptor& descriptor) { } kj::Vector targets; - for (auto& t : fragment.targets) { + for (auto& t: fragment.targets) { wgpu::ColorTargetState target; wgpu::BlendState blend; @@ -487,15 +486,15 @@ parseRenderPipelineDescriptor(GPURenderPipelineDescriptor& descriptor) { return kj::mv(parsedDesc); } -jsg::Ref -GPUDevice::createRenderPipeline(GPURenderPipelineDescriptor descriptor) { +jsg::Ref GPUDevice::createRenderPipeline( + GPURenderPipelineDescriptor descriptor) { auto parsedDesc = parseRenderPipelineDescriptor(descriptor); auto pipeline = device_.CreateRenderPipeline(&parsedDesc.desc); return jsg::alloc(kj::mv(pipeline)); } -jsg::Ref -GPUDevice::createPipelineLayout(GPUPipelineLayoutDescriptor descriptor) { +jsg::Ref GPUDevice::createPipelineLayout( + GPUPipelineLayoutDescriptor descriptor) { wgpu::PipelineLayoutDescriptor desc{}; KJ_IF_SOME(label, descriptor.label) { @@ -503,7 +502,7 @@ GPUDevice::createPipelineLayout(GPUPipelineLayoutDescriptor descriptor) { } kj::Vector bindGroupLayouts; - for (auto& l : descriptor.bindGroupLayouts) { + for (auto& l: descriptor.bindGroupLayouts) { bindGroupLayouts.add(*l); } @@ -514,8 +513,8 @@ GPUDevice::createPipelineLayout(GPUPipelineLayoutDescriptor descriptor) { return jsg::alloc(kj::mv(layout)); } -jsg::Ref -GPUDevice::createCommandEncoder(jsg::Optional descriptor) { +jsg::Ref GPUDevice::createCommandEncoder( + jsg::Optional descriptor) { wgpu::CommandEncoderDescriptor desc{}; kj::String label = kj::str(""); @@ -534,8 +533,8 @@ GPUDevice::createCommandEncoder(jsg::Optional descr // Will problably need to implement some allocator that will keep track of what needs // to be deallocated as it's being done in parseRenderPipelineDescriptor(). The constants // vector jumps to mind since we're just returning a pointer to a local variable. -wgpu::ComputePipelineDescriptor -parseComputePipelineDescriptor(GPUComputePipelineDescriptor& descriptor) { +wgpu::ComputePipelineDescriptor parseComputePipelineDescriptor( + GPUComputePipelineDescriptor& descriptor) { wgpu::ComputePipelineDescriptor desc{}; KJ_IF_SOME(label, descriptor.label) { @@ -547,7 +546,7 @@ parseComputePipelineDescriptor(GPUComputePipelineDescriptor& descriptor) { kj::Vector constants; KJ_IF_SOME(cDict, descriptor.compute.constants) { - for (auto& f : cDict.fields) { + for (auto& f: cDict.fields) { wgpu::ConstantEntry e; e.key = f.name.cStr(); e.value = f.value; @@ -561,7 +560,7 @@ parseComputePipelineDescriptor(GPUComputePipelineDescriptor& descriptor) { KJ_SWITCH_ONEOF(descriptor.layout) { KJ_CASE_ONEOF(autoLayoutMode, jsg::NonCoercible) { JSG_REQUIRE(autoLayoutMode.value == "auto", TypeError, "unknown auto layout mode", - autoLayoutMode.value); + autoLayoutMode.value); desc.layout = nullptr; } KJ_CASE_ONEOF(layout, jsg::Ref) { @@ -572,8 +571,8 @@ parseComputePipelineDescriptor(GPUComputePipelineDescriptor& descriptor) { return kj::mv(desc); } -jsg::Ref -GPUDevice::createComputePipeline(GPUComputePipelineDescriptor descriptor) { +jsg::Ref GPUDevice::createComputePipeline( + GPUComputePipelineDescriptor descriptor) { wgpu::ComputePipelineDescriptor desc = parseComputePipelineDescriptor(descriptor); auto pipeline = device_.CreateComputePipeline(&desc); return jsg::alloc(kj::mv(pipeline)); @@ -588,39 +587,38 @@ jsg::Promise>> GPUDevice::popErrorScope(jsg::Lock& using MapAsyncContext = AsyncContext>>; auto ctx = kj::heap(js, kj::addRef(*async_)); auto promise = kj::mv(ctx->promise_); - device_.PopErrorScope( - wgpu::CallbackMode::AllowProcessEvents, - [ctx = kj::mv(ctx)](wgpu::PopErrorScopeStatus, wgpu::ErrorType type, - char const* message) mutable { - switch (type) { - case wgpu::ErrorType::NoError: - ctx->fulfiller_->fulfill(kj::none); - break; - case wgpu::ErrorType::OutOfMemory: { - jsg::Ref err = jsg::alloc(kj::str(message)); - ctx->fulfiller_->fulfill(kj::mv(err)); - break; - } - case wgpu::ErrorType::Validation: { - jsg::Ref err = jsg::alloc(kj::str(message)); - ctx->fulfiller_->fulfill(kj::mv(err)); - break; - } - case wgpu::ErrorType::Unknown: - case wgpu::ErrorType::DeviceLost: - ctx->fulfiller_->reject(JSG_KJ_EXCEPTION(FAILED, TypeError, message)); - break; - default: - ctx->fulfiller_->reject(JSG_KJ_EXCEPTION(FAILED, TypeError, "unhandled error type")); - break; - } - }); + device_.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, + [ctx = kj::mv(ctx)]( + wgpu::PopErrorScopeStatus, wgpu::ErrorType type, char const* message) mutable { + switch (type) { + case wgpu::ErrorType::NoError: + ctx->fulfiller_->fulfill(kj::none); + break; + case wgpu::ErrorType::OutOfMemory: { + jsg::Ref err = jsg::alloc(kj::str(message)); + ctx->fulfiller_->fulfill(kj::mv(err)); + break; + } + case wgpu::ErrorType::Validation: { + jsg::Ref err = jsg::alloc(kj::str(message)); + ctx->fulfiller_->fulfill(kj::mv(err)); + break; + } + case wgpu::ErrorType::Unknown: + case wgpu::ErrorType::DeviceLost: + ctx->fulfiller_->reject(JSG_KJ_EXCEPTION(FAILED, TypeError, message)); + break; + default: + ctx->fulfiller_->reject(JSG_KJ_EXCEPTION(FAILED, TypeError, "unhandled error type")); + break; + } + }); return promise; } -jsg::Promise> -GPUDevice::createComputePipelineAsync(jsg::Lock& js, GPUComputePipelineDescriptor descriptor) { +jsg::Promise> GPUDevice::createComputePipelineAsync( + jsg::Lock& js, GPUComputePipelineDescriptor descriptor) { wgpu::ComputePipelineDescriptor desc = parseComputePipelineDescriptor(descriptor); // This context object will hold information for the callback, including the @@ -630,21 +628,20 @@ GPUDevice::createComputePipelineAsync(jsg::Lock& js, GPUComputePipelineDescripto using MapAsyncContext = AsyncContext>; auto ctx = kj::heap(js, kj::addRef(*async_)); auto promise = kj::mv(ctx->promise_); - device_.CreateComputePipelineAsync( - &desc, wgpu::CallbackMode::AllowProcessEvents, + device_.CreateComputePipelineAsync(&desc, wgpu::CallbackMode::AllowProcessEvents, [ctx = kj::mv(ctx)](wgpu::CreatePipelineAsyncStatus status, wgpu::ComputePipeline pipeline, - char const*) mutable { - // Note: this is invoked outside the JS isolate lock + char const*) mutable { + // Note: this is invoked outside the JS isolate lock - switch (status) { - case wgpu::CreatePipelineAsyncStatus::Success: - ctx->fulfiller_->fulfill(jsg::alloc(kj::mv(pipeline))); - break; - default: - ctx->fulfiller_->reject(JSG_KJ_EXCEPTION(FAILED, TypeError, "unknown error")); - break; - } - }); + switch (status) { + case wgpu::CreatePipelineAsyncStatus::Success: + ctx->fulfiller_->fulfill(jsg::alloc(kj::mv(pipeline))); + break; + default: + ctx->fulfiller_->reject(JSG_KJ_EXCEPTION(FAILED, TypeError, "unknown error")); + break; + } + }); return promise; } @@ -676,17 +673,20 @@ jsg::MemoizedIdentity>>& GPUDevice::get return lost_promise_; } -GPUDevice::GPUDevice(jsg::Lock& js, wgpu::Device d, kj::Own async, - kj::Own>> deviceLostCtx, - kj::Own uErrorCtx) - : device_(d), dlc_(kj::mv(deviceLostCtx)), lost_promise_(kj::mv(dlc_->promise_)), - uec_(kj::mv(uErrorCtx)), async_(kj::mv(async)) { +GPUDevice::GPUDevice(jsg::Lock& js, + wgpu::Device d, + kj::Own async, + kj::Own>> deviceLostCtx, + kj::Own uErrorCtx) + : device_(d), + dlc_(kj::mv(deviceLostCtx)), + lost_promise_(kj::mv(dlc_->promise_)), + uec_(kj::mv(uErrorCtx)), + async_(kj::mv(async)) { uec_->target = this; - device_.SetLoggingCallback( - [](WGPULoggingType type, char const* message, void* userdata) { - KJ_LOG(INFO, "WebGPU logging", kj::str(type), message); - }, - this); + device_.SetLoggingCallback([](WGPULoggingType type, char const* message, void* userdata) { + KJ_LOG(INFO, "WebGPU logging", kj::str(type), message); + }, this); }; jsg::Ref GPUDevice::createQuerySet(GPUQuerySetDescriptor descriptor) { @@ -741,4 +741,4 @@ jsg::Ref GPUDevice::getLimits() { return jsg::alloc(kj::mv(limits)); } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-device.h b/src/workerd/api/gpu/gpu-device.h index 6d6af2e2fc2..f3325226d1f 100644 --- a/src/workerd/api/gpu/gpu-device.h +++ b/src/workerd/api/gpu/gpu-device.h @@ -32,11 +32,13 @@ struct UncapturedErrorContext { kj::Maybe target; }; -class GPUDevice : public EventTarget { +class GPUDevice: public EventTarget { public: - explicit GPUDevice(jsg::Lock& js, wgpu::Device d, kj::Own async, - kj::Own>> deviceLostCtx, - kj::Own uErrorCtx); + explicit GPUDevice(jsg::Lock& js, + wgpu::Device d, + kj::Own async, + kj::Own>> deviceLostCtx, + kj::Own uErrorCtx); ~GPUDevice(); JSG_RESOURCE_TYPE(GPUDevice) { JSG_INHERIT(EventTarget); @@ -80,10 +82,10 @@ class GPUDevice : public EventTarget { jsg::Ref createPipelineLayout(GPUPipelineLayoutDescriptor descriptor); jsg::Ref createComputePipeline(GPUComputePipelineDescriptor descriptor); jsg::Ref createRenderPipeline(GPURenderPipelineDescriptor descriptor); - jsg::Promise> - createComputePipelineAsync(jsg::Lock& js, GPUComputePipelineDescriptor descriptor); - jsg::Ref - createCommandEncoder(jsg::Optional descriptor); + jsg::Promise> createComputePipelineAsync( + jsg::Lock& js, GPUComputePipelineDescriptor descriptor); + jsg::Ref createCommandEncoder( + jsg::Optional descriptor); jsg::Ref getQueue(); void destroy(); jsg::Ref createQuerySet(GPUQuerySetDescriptor descriptor); @@ -114,11 +116,12 @@ struct GPUUncapturedErrorEventInit { JSG_STRUCT(error); }; -class GPUUncapturedErrorEvent : public Event { +class GPUUncapturedErrorEvent: public Event { public: - GPUUncapturedErrorEvent(kj::StringPtr type, - GPUUncapturedErrorEventInit gpuUncapturedErrorEventInitDict) - : Event(kj::mv(type)), error_(kj::mv(gpuUncapturedErrorEventInitDict.error)){}; + GPUUncapturedErrorEvent( + kj::StringPtr type, GPUUncapturedErrorEventInit gpuUncapturedErrorEventInitDict) + : Event(kj::mv(type)), + error_(kj::mv(gpuUncapturedErrorEventInitDict.error)) {}; static jsg::Ref constructor() = delete; @@ -142,4 +145,4 @@ class GPUUncapturedErrorEvent : public Event { } }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-errors.h b/src/workerd/api/gpu/gpu-errors.h index 4e4841190fd..c62c508ff25 100644 --- a/src/workerd/api/gpu/gpu-errors.h +++ b/src/workerd/api/gpu/gpu-errors.h @@ -10,9 +10,9 @@ namespace workerd::api::gpu { -class GPUError : public jsg::Object { +class GPUError: public jsg::Object { public: - explicit GPUError(kj::String m) : message_(kj::mv(m)){}; + explicit GPUError(kj::String m): message_(kj::mv(m)) {}; JSG_RESOURCE_TYPE(GPUError) { JSG_READONLY_PROTOTYPE_PROPERTY(message, getMessage); } @@ -29,7 +29,7 @@ class GPUError : public jsg::Object { kj::String message_; }; -class GPUOutOfMemoryError : public GPUError { +class GPUOutOfMemoryError: public GPUError { public: using GPUError::GPUError; JSG_RESOURCE_TYPE(GPUOutOfMemoryError) { @@ -37,7 +37,7 @@ class GPUOutOfMemoryError : public GPUError { } }; -class GPUValidationError : public GPUError { +class GPUValidationError: public GPUError { public: using GPUError::GPUError; JSG_RESOURCE_TYPE(GPUValidationError) { @@ -45,7 +45,7 @@ class GPUValidationError : public GPUError { } }; -class GPUInternalError : public GPUError { +class GPUInternalError: public GPUError { public: using GPUError::GPUError; JSG_RESOURCE_TYPE(GPUInternalError) { @@ -53,10 +53,11 @@ class GPUInternalError : public GPUError { } }; -class GPUDeviceLostInfo : public jsg::Object { +class GPUDeviceLostInfo: public jsg::Object { public: explicit GPUDeviceLostInfo(GPUDeviceLostReason r, kj::String m) - : reason_(kj::mv(r)), message_(kj::mv(m)){}; + : reason_(kj::mv(r)), + message_(kj::mv(m)) {}; JSG_RESOURCE_TYPE(GPUDeviceLostInfo) { JSG_READONLY_PROTOTYPE_PROPERTY(message, getMessage); JSG_READONLY_PROTOTYPE_PROPERTY(reason, getReason); @@ -78,4 +79,4 @@ class GPUDeviceLostInfo : public jsg::Object { } }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-pipeline-layout.h b/src/workerd/api/gpu/gpu-pipeline-layout.h index ffefb99d300..92f1b7f3566 100644 --- a/src/workerd/api/gpu/gpu-pipeline-layout.h +++ b/src/workerd/api/gpu/gpu-pipeline-layout.h @@ -10,13 +10,13 @@ namespace workerd::api::gpu { -class GPUPipelineLayout : public jsg::Object { +class GPUPipelineLayout: public jsg::Object { public: // Implicit cast operator to Dawn GPU object inline operator const wgpu::PipelineLayout&() const { return layout_; } - explicit GPUPipelineLayout(wgpu::PipelineLayout l) : layout_(kj::mv(l)){}; + explicit GPUPipelineLayout(wgpu::PipelineLayout l): layout_(kj::mv(l)) {}; JSG_RESOURCE_TYPE(GPUPipelineLayout) {} private: @@ -32,4 +32,4 @@ struct GPUPipelineLayoutDescriptor { using GPUPipelineLayoutBase = kj::OneOf, jsg::Ref>; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-query-set.c++ b/src/workerd/api/gpu/gpu-query-set.c++ index 4423559576b..55a3b4a3da5 100644 --- a/src/workerd/api/gpu/gpu-query-set.c++ +++ b/src/workerd/api/gpu/gpu-query-set.c++ @@ -19,4 +19,4 @@ wgpu::QueryType parseQueryType(kj::StringPtr type) { JSG_FAIL_REQUIRE(TypeError, "unknown Query type", type); } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-query-set.h b/src/workerd/api/gpu/gpu-query-set.h index 376ca9a446e..e8c7c7d9e4b 100644 --- a/src/workerd/api/gpu/gpu-query-set.h +++ b/src/workerd/api/gpu/gpu-query-set.h @@ -10,13 +10,13 @@ namespace workerd::api::gpu { -class GPUQuerySet : public jsg::Object { +class GPUQuerySet: public jsg::Object { public: // Implicit cast operator to Dawn GPU object inline operator const wgpu::QuerySet&() const { return querySet_; } - explicit GPUQuerySet(wgpu::QuerySet q) : querySet_(kj::mv(q)){}; + explicit GPUQuerySet(wgpu::QuerySet q): querySet_(kj::mv(q)) {}; JSG_RESOURCE_TYPE(GPUQuerySet) {} private: @@ -34,4 +34,4 @@ struct GPUQuerySetDescriptor { wgpu::QueryType parseQueryType(kj::StringPtr type); -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-queue.c++ b/src/workerd/api/gpu/gpu-queue.c++ index 2bbee007256..39a47596f38 100644 --- a/src/workerd/api/gpu/gpu-queue.c++ +++ b/src/workerd/api/gpu/gpu-queue.c++ @@ -5,25 +5,26 @@ #include "gpu-queue.h" #include - namespace workerd::api::gpu { void GPUQueue::submit(kj::Array> commandBuffers) { kj::Vector bufs(commandBuffers.size()); - for (auto& cb : commandBuffers) { + for (auto& cb: commandBuffers) { bufs.add(*cb); } queue_.Submit(bufs.size(), bufs.begin()); } -void GPUQueue::writeBuffer(jsg::Ref buffer, GPUSize64 bufferOffset, - jsg::BufferSource data, jsg::Optional dataOffsetElements, - jsg::Optional sizeElements) { +void GPUQueue::writeBuffer(jsg::Ref buffer, + GPUSize64 bufferOffset, + jsg::BufferSource data, + jsg::Optional dataOffsetElements, + jsg::Optional sizeElements) { wgpu::Buffer buf = *buffer; uint64_t dataOffset = 0; - KJ_IF_SOME (offset, dataOffsetElements) { + KJ_IF_SOME(offset, dataOffsetElements) { // In the JS semantics of WebGPU, writeBuffer works in number of // elements of the typed arrays. dataOffset = offset * data.getElementSize(); @@ -32,12 +33,12 @@ void GPUQueue::writeBuffer(jsg::Ref buffer, GPUSize64 bufferOffset, auto dataPtr = reinterpret_cast(data.asArrayPtr().begin()) + dataOffset; size_t dataSize = data.size() - dataOffset; - KJ_IF_SOME (size, sizeElements) { + KJ_IF_SOME(size, sizeElements) { JSG_REQUIRE(size <= std::numeric_limits::max() / data.getElementSize(), TypeError, - "size overflows."); + "size overflows."); dataSize = size * data.getElementSize(); JSG_REQUIRE(dataOffset + dataSize <= data.size(), TypeError, - "size + dataOffset is larger than data's size."); + "size + dataOffset is larger than data's size."); JSG_REQUIRE(dataSize % 4 == 0, TypeError, "size is not a multiple of 4 bytes."); } @@ -46,4 +47,4 @@ void GPUQueue::writeBuffer(jsg::Ref buffer, GPUSize64 bufferOffset, queue_.WriteBuffer(buf, bufferOffset, dataPtr, static_cast(dataSize)); } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-queue.h b/src/workerd/api/gpu/gpu-queue.h index 2ae48972416..e5d8dd23c5b 100644 --- a/src/workerd/api/gpu/gpu-queue.h +++ b/src/workerd/api/gpu/gpu-queue.h @@ -12,13 +12,13 @@ namespace workerd::api::gpu { -class GPUQueue : public jsg::Object { +class GPUQueue: public jsg::Object { public: // Implicit cast operator to Dawn GPU object inline operator const wgpu::Queue&() const { return queue_; } - explicit GPUQueue(wgpu::Queue q) : queue_(kj::mv(q)){}; + explicit GPUQueue(wgpu::Queue q): queue_(kj::mv(q)) {}; JSG_RESOURCE_TYPE(GPUQueue) { JSG_METHOD(submit); JSG_METHOD(writeBuffer); @@ -27,8 +27,11 @@ class GPUQueue : public jsg::Object { private: wgpu::Queue queue_; void submit(kj::Array> commandBuffers); - void writeBuffer(jsg::Ref buffer, GPUSize64 bufferOffset, jsg::BufferSource data, - jsg::Optional dataOffset, jsg::Optional size); + void writeBuffer(jsg::Ref buffer, + GPUSize64 bufferOffset, + jsg::BufferSource data, + jsg::Optional dataOffset, + jsg::Optional size); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-render-pass-encoder.c++ b/src/workerd/api/gpu/gpu-render-pass-encoder.c++ index a91d8d41ccf..e5f51ded274 100644 --- a/src/workerd/api/gpu/gpu-render-pass-encoder.c++ +++ b/src/workerd/api/gpu/gpu-render-pass-encoder.c++ @@ -10,9 +10,10 @@ void GPURenderPassEncoder::setPipeline(jsg::Ref pipeline) { encoder_.SetPipeline(*pipeline); } -void GPURenderPassEncoder::draw(GPUSize32 vertexCount, jsg::Optional instanceCount, - jsg::Optional firstVertex, - jsg::Optional firstInstance) { +void GPURenderPassEncoder::draw(GPUSize32 vertexCount, + jsg::Optional instanceCount, + jsg::Optional firstVertex, + jsg::Optional firstInstance) { KJ_IF_SOME(iCount, instanceCount) { KJ_IF_SOME(fVertex, firstVertex) { KJ_IF_SOME(fInstance, firstInstance) { @@ -25,4 +26,4 @@ void GPURenderPassEncoder::draw(GPUSize32 vertexCount, jsg::Optional return encoder_.Draw(vertexCount); } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-render-pass-encoder.h b/src/workerd/api/gpu/gpu-render-pass-encoder.h index b8324063824..10306d2508b 100644 --- a/src/workerd/api/gpu/gpu-render-pass-encoder.h +++ b/src/workerd/api/gpu/gpu-render-pass-encoder.h @@ -13,9 +13,9 @@ namespace workerd::api::gpu { -class GPURenderPassEncoder : public jsg::Object { +class GPURenderPassEncoder: public jsg::Object { public: - explicit GPURenderPassEncoder(wgpu::RenderPassEncoder e) : encoder_(kj::mv(e)){}; + explicit GPURenderPassEncoder(wgpu::RenderPassEncoder e): encoder_(kj::mv(e)) {}; JSG_RESOURCE_TYPE(GPURenderPassEncoder) { JSG_METHOD(setPipeline); JSG_METHOD(draw); @@ -25,8 +25,10 @@ class GPURenderPassEncoder : public jsg::Object { private: wgpu::RenderPassEncoder encoder_; void setPipeline(jsg::Ref pipeline); - void draw(GPUSize32 vertexCount, jsg::Optional instanceCount, - jsg::Optional firstVertex, jsg::Optional firstInstance); + void draw(GPUSize32 vertexCount, + jsg::Optional instanceCount, + jsg::Optional firstVertex, + jsg::Optional firstInstance); void end() { encoder_.End(); }; @@ -42,8 +44,15 @@ struct GPURenderPassDepthStencilAttachment { jsg::Optional stencilLoadOp; jsg::Optional stencilStoreOp; jsg::Optional stencilReadOnly; - JSG_STRUCT(view, depthClearValue, depthLoadOp, depthStoreOp, depthReadOnly, stencilClearValue, - stencilLoadOp, stencilStoreOp, stencilReadOnly); + JSG_STRUCT(view, + depthClearValue, + depthLoadOp, + depthStoreOp, + depthReadOnly, + stencilClearValue, + stencilLoadOp, + stencilStoreOp, + stencilReadOnly); }; struct GPUColorDict { @@ -78,8 +87,12 @@ struct GPURenderPassDescriptor { jsg::Optional> occlusionQuerySet; jsg::Optional timestampWrites; jsg::Optional maxDrawCount; - JSG_STRUCT(label, colorAttachments, depthStencilAttachment, occlusionQuerySet, timestampWrites, - maxDrawCount); + JSG_STRUCT(label, + colorAttachments, + depthStencilAttachment, + occlusionQuerySet, + timestampWrites, + maxDrawCount); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-render-pipeline.h b/src/workerd/api/gpu/gpu-render-pipeline.h index 8eda1ca89ec..976287d7505 100644 --- a/src/workerd/api/gpu/gpu-render-pipeline.h +++ b/src/workerd/api/gpu/gpu-render-pipeline.h @@ -11,13 +11,13 @@ namespace workerd::api::gpu { -class GPURenderPipeline : public jsg::Object { +class GPURenderPipeline: public jsg::Object { public: // Implicit cast operator to Dawn GPU object inline operator const wgpu::RenderPipeline&() const { return pipeline_; } - explicit GPURenderPipeline(wgpu::RenderPipeline p) : pipeline_(kj::mv(p)){}; + explicit GPURenderPipeline(wgpu::RenderPipeline p): pipeline_(kj::mv(p)) {}; JSG_RESOURCE_TYPE(GPURenderPipeline) {} private: @@ -112,8 +112,16 @@ struct GPUDepthStencilState { jsg::Optional depthBiasSlopeScale; jsg::Optional depthBiasClamp; - JSG_STRUCT(format, depthWriteEnabled, depthCompare, stencilFront, stencilBack, stencilReadMask, - stencilWriteMask, depthBias, depthBiasSlopeScale, depthBiasClamp); + JSG_STRUCT(format, + depthWriteEnabled, + depthCompare, + stencilFront, + stencilBack, + stencilReadMask, + stencilWriteMask, + depthBias, + depthBiasSlopeScale, + depthBiasClamp); }; struct GPUMultisampleState { @@ -136,4 +144,4 @@ struct GPURenderPipelineDescriptor { JSG_STRUCT(label, layout, vertex, primitive, depthStencil, multisample, fragment); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-sampler.h b/src/workerd/api/gpu/gpu-sampler.h index bf3aa8ce850..05787ccc414 100644 --- a/src/workerd/api/gpu/gpu-sampler.h +++ b/src/workerd/api/gpu/gpu-sampler.h @@ -10,14 +10,14 @@ namespace workerd::api::gpu { -class GPUSampler : public jsg::Object { +class GPUSampler: public jsg::Object { public: // Implicit cast operator to Dawn GPU object inline operator const wgpu::Sampler&() const { return sampler_; } - explicit GPUSampler(wgpu::Sampler s) : sampler_(kj::mv(s)){}; + explicit GPUSampler(wgpu::Sampler s): sampler_(kj::mv(s)) {}; JSG_RESOURCE_TYPE(GPUSampler) {} private: @@ -37,8 +37,17 @@ struct GPUSamplerDescriptor { GPUCompareFunction compare; jsg::Optional maxAnisotropy; - JSG_STRUCT(label, addressModeU, addressModeV, addressModeW, magFilter, minFilter, mipmapFilter, - lodMinClamp, lodMaxClamp, compare, maxAnisotropy); + JSG_STRUCT(label, + addressModeU, + addressModeV, + addressModeW, + magFilter, + minFilter, + mipmapFilter, + lodMinClamp, + lodMaxClamp, + compare, + maxAnisotropy); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-shader-module.c++ b/src/workerd/api/gpu/gpu-shader-module.c++ index d9c3b99f866..46895717cc6 100644 --- a/src/workerd/api/gpu/gpu-shader-module.c++ +++ b/src/workerd/api/gpu/gpu-shader-module.c++ @@ -16,20 +16,19 @@ jsg::Promise> GPUShaderModule::getCompilationInfo(j using MapAsyncContext = AsyncContext>; auto ctx = kj::heap(js, kj::addRef(*async_)); auto promise = kj::mv(ctx->promise_); - shader_.GetCompilationInfo( - wgpu::CallbackMode::AllowProcessEvents, + shader_.GetCompilationInfo(wgpu::CallbackMode::AllowProcessEvents, [ctx = kj::mv(ctx)](wgpu::CompilationInfoRequestStatus status, - wgpu::CompilationInfo const* compilationInfo) mutable { - kj::Vector> messages(compilationInfo->messageCount); - for (uint32_t i = 0; i < compilationInfo->messageCount; i++) { - auto& msg = compilationInfo->messages[i]; - messages.add(jsg::alloc(msg)); - } + wgpu::CompilationInfo const* compilationInfo) mutable { + kj::Vector> messages(compilationInfo->messageCount); + for (uint32_t i = 0; i < compilationInfo->messageCount; i++) { + auto& msg = compilationInfo->messages[i]; + messages.add(jsg::alloc(msg)); + } - ctx->fulfiller_->fulfill(jsg::alloc(kj::mv(messages))); - }); + ctx->fulfiller_->fulfill(jsg::alloc(kj::mv(messages))); + }); return promise; } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-shader-module.h b/src/workerd/api/gpu/gpu-shader-module.h index 9adf6efe785..db0a88a15e4 100644 --- a/src/workerd/api/gpu/gpu-shader-module.h +++ b/src/workerd/api/gpu/gpu-shader-module.h @@ -11,9 +11,9 @@ namespace workerd::api::gpu { -class GPUCompilationMessage : public jsg::Object { +class GPUCompilationMessage: public jsg::Object { public: - explicit GPUCompilationMessage(const WGPUCompilationMessage& m) : message(m) {} + explicit GPUCompilationMessage(const WGPUCompilationMessage& m): message(m) {} JSG_RESOURCE_TYPE(GPUCompilationMessage) { JSG_READONLY_PROTOTYPE_PROPERTY(message, getMessage); @@ -32,14 +32,14 @@ class GPUCompilationMessage : public jsg::Object { } GPUCompilationMessageType getType() { switch (message.type) { - case WGPUCompilationMessageType_Error: - return kj::str("error"); - case WGPUCompilationMessageType_Warning: - return kj::str("warning"); - case WGPUCompilationMessageType_Info: - return kj::str("info"); - default: - KJ_UNREACHABLE + case WGPUCompilationMessageType_Error: + return kj::str("error"); + case WGPUCompilationMessageType_Warning: + return kj::str("warning"); + case WGPUCompilationMessageType_Info: + return kj::str("info"); + default: + KJ_UNREACHABLE } } double getLineNum() { @@ -56,16 +56,16 @@ class GPUCompilationMessage : public jsg::Object { } }; -class GPUCompilationInfo : public jsg::Object { +class GPUCompilationInfo: public jsg::Object { public: explicit GPUCompilationInfo(kj::Vector> messages) - : messages_(kj::mv(messages)){}; + : messages_(kj::mv(messages)) {}; JSG_RESOURCE_TYPE(GPUCompilationInfo) { JSG_READONLY_PROTOTYPE_PROPERTY(messages, getMessages); } void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { - for (const auto& message : messages_) { + for (const auto& message: messages_) { tracker.trackField(nullptr, message); } } @@ -80,14 +80,15 @@ class GPUCompilationInfo : public jsg::Object { } }; -class GPUShaderModule : public jsg::Object { +class GPUShaderModule: public jsg::Object { public: // Implicit cast operator to Dawn GPU object inline operator const wgpu::ShaderModule&() const { return shader_; } explicit GPUShaderModule(wgpu::ShaderModule s, kj::Own async) - : shader_(kj::mv(s)), async_(kj::mv(async)){}; + : shader_(kj::mv(s)), + async_(kj::mv(async)) {}; JSG_RESOURCE_TYPE(GPUShaderModule) { JSG_METHOD(getCompilationInfo); } @@ -113,4 +114,4 @@ struct GPUProgrammableStage { JSG_STRUCT(module, entryPoint, constants); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-supported-features.c++ b/src/workerd/api/gpu/gpu-supported-features.c++ index b99723b1f57..7f192a45c83 100644 --- a/src/workerd/api/gpu/gpu-supported-features.c++ +++ b/src/workerd/api/gpu/gpu-supported-features.c++ @@ -7,9 +7,9 @@ namespace workerd::api::gpu { GPUSupportedFeatures::GPUSupportedFeatures(kj::Array features) { - for (wgpu::FeatureName feature : features) { + for (wgpu::FeatureName feature: features) { // add only known features to the feature list - KJ_IF_SOME (knownF, getFeatureName(feature)) { + KJ_IF_SOME(knownF, getFeatureName(feature)) { enabled_.insert(kj::mv(knownF)); } } @@ -25,4 +25,4 @@ kj::Array GPUSupportedFeatures::keys() { return res.releaseAsArray(); } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-supported-features.h b/src/workerd/api/gpu/gpu-supported-features.h index b4d3286d845..a92e9b6a4e4 100644 --- a/src/workerd/api/gpu/gpu-supported-features.h +++ b/src/workerd/api/gpu/gpu-supported-features.h @@ -10,7 +10,7 @@ namespace workerd::api::gpu { -class GPUSupportedFeatures : public jsg::Object { +class GPUSupportedFeatures: public jsg::Object { public: explicit GPUSupportedFeatures(kj::Array features); JSG_RESOURCE_TYPE(GPUSupportedFeatures) { @@ -19,7 +19,7 @@ class GPUSupportedFeatures : public jsg::Object { } void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { - for (const auto& feature : enabled_) { + for (const auto& feature: enabled_) { tracker.trackField(nullptr, feature); } } @@ -30,4 +30,4 @@ class GPUSupportedFeatures : public jsg::Object { kj::Array keys(); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-supported-limits.h b/src/workerd/api/gpu/gpu-supported-limits.h index 4cbf8374ea5..16d41ad0158 100644 --- a/src/workerd/api/gpu/gpu-supported-limits.h +++ b/src/workerd/api/gpu/gpu-supported-limits.h @@ -10,9 +10,9 @@ namespace workerd::api::gpu { -class GPUSupportedLimits : public jsg::Object { +class GPUSupportedLimits: public jsg::Object { public: - explicit GPUSupportedLimits(wgpu::SupportedLimits limits) : limits_(kj::mv(limits)){}; + explicit GPUSupportedLimits(wgpu::SupportedLimits limits): limits_(kj::mv(limits)) {}; JSG_RESOURCE_TYPE(GPUSupportedLimits) { JSG_READONLY_PROTOTYPE_PROPERTY(maxTextureDimension1D, getMaxTextureDimension1D); JSG_READONLY_PROTOTYPE_PROPERTY(maxTextureDimension2D, getMaxTextureDimension2D); @@ -20,44 +20,44 @@ class GPUSupportedLimits : public jsg::Object { JSG_READONLY_PROTOTYPE_PROPERTY(maxTextureArrayLayers, getMaxTextureArrayLayers); JSG_READONLY_PROTOTYPE_PROPERTY(maxBindGroups, getMaxBindGroups); JSG_READONLY_PROTOTYPE_PROPERTY(maxBindingsPerBindGroup, getMaxBindingsPerBindGroup); - JSG_READONLY_PROTOTYPE_PROPERTY(maxDynamicUniformBuffersPerPipelineLayout, - getMaxDynamicUniformBuffersPerPipelineLayout); - JSG_READONLY_PROTOTYPE_PROPERTY(maxDynamicStorageBuffersPerPipelineLayout, - getMaxDynamicStorageBuffersPerPipelineLayout); - JSG_READONLY_PROTOTYPE_PROPERTY(maxSampledTexturesPerShaderStage, - getMaxSampledTexturesPerShaderStage); + JSG_READONLY_PROTOTYPE_PROPERTY( + maxDynamicUniformBuffersPerPipelineLayout, getMaxDynamicUniformBuffersPerPipelineLayout); + JSG_READONLY_PROTOTYPE_PROPERTY( + maxDynamicStorageBuffersPerPipelineLayout, getMaxDynamicStorageBuffersPerPipelineLayout); + JSG_READONLY_PROTOTYPE_PROPERTY( + maxSampledTexturesPerShaderStage, getMaxSampledTexturesPerShaderStage); JSG_READONLY_PROTOTYPE_PROPERTY(maxSamplersPerShaderStage, getMaxSamplersPerShaderStage); - JSG_READONLY_PROTOTYPE_PROPERTY(maxStorageBuffersPerShaderStage, - getMaxStorageBuffersPerShaderStage); - JSG_READONLY_PROTOTYPE_PROPERTY(maxStorageTexturesPerShaderStage, - getMaxStorageTexturesPerShaderStage); - JSG_READONLY_PROTOTYPE_PROPERTY(maxUniformBuffersPerShaderStage, - getMaxUniformBuffersPerShaderStage); + JSG_READONLY_PROTOTYPE_PROPERTY( + maxStorageBuffersPerShaderStage, getMaxStorageBuffersPerShaderStage); + JSG_READONLY_PROTOTYPE_PROPERTY( + maxStorageTexturesPerShaderStage, getMaxStorageTexturesPerShaderStage); + JSG_READONLY_PROTOTYPE_PROPERTY( + maxUniformBuffersPerShaderStage, getMaxUniformBuffersPerShaderStage); JSG_READONLY_PROTOTYPE_PROPERTY(maxUniformBufferBindingSize, getMaxUniformBufferBindingSize); JSG_READONLY_PROTOTYPE_PROPERTY(maxStorageBufferBindingSize, getMaxStorageBufferBindingSize); - JSG_READONLY_PROTOTYPE_PROPERTY(minUniformBufferOffsetAlignment, - getMinUniformBufferOffsetAlignment); - JSG_READONLY_PROTOTYPE_PROPERTY(minStorageBufferOffsetAlignment, - getMinStorageBufferOffsetAlignment); + JSG_READONLY_PROTOTYPE_PROPERTY( + minUniformBufferOffsetAlignment, getMinUniformBufferOffsetAlignment); + JSG_READONLY_PROTOTYPE_PROPERTY( + minStorageBufferOffsetAlignment, getMinStorageBufferOffsetAlignment); JSG_READONLY_PROTOTYPE_PROPERTY(maxVertexBuffers, getMaxVertexBuffers); JSG_READONLY_PROTOTYPE_PROPERTY(maxBufferSize, getMaxBufferSize); JSG_READONLY_PROTOTYPE_PROPERTY(maxVertexAttributes, getMaxVertexAttributes); JSG_READONLY_PROTOTYPE_PROPERTY(maxVertexBufferArrayStride, getMaxVertexBufferArrayStride); - JSG_READONLY_PROTOTYPE_PROPERTY(maxInterStageShaderComponents, - getMaxInterStageShaderComponents); + JSG_READONLY_PROTOTYPE_PROPERTY( + maxInterStageShaderComponents, getMaxInterStageShaderComponents); JSG_READONLY_PROTOTYPE_PROPERTY(maxInterStageShaderVariables, getMaxInterStageShaderVariables); JSG_READONLY_PROTOTYPE_PROPERTY(maxColorAttachments, getMaxColorAttachments); - JSG_READONLY_PROTOTYPE_PROPERTY(maxColorAttachmentBytesPerSample, - getMaxColorAttachmentBytesPerSample); - JSG_READONLY_PROTOTYPE_PROPERTY(maxComputeWorkgroupStorageSize, - getMaxComputeWorkgroupStorageSize); - JSG_READONLY_PROTOTYPE_PROPERTY(maxComputeInvocationsPerWorkgroup, - getMaxComputeInvocationsPerWorkgroup); + JSG_READONLY_PROTOTYPE_PROPERTY( + maxColorAttachmentBytesPerSample, getMaxColorAttachmentBytesPerSample); + JSG_READONLY_PROTOTYPE_PROPERTY( + maxComputeWorkgroupStorageSize, getMaxComputeWorkgroupStorageSize); + JSG_READONLY_PROTOTYPE_PROPERTY( + maxComputeInvocationsPerWorkgroup, getMaxComputeInvocationsPerWorkgroup); JSG_READONLY_PROTOTYPE_PROPERTY(maxComputeWorkgroupSizeX, getMaxComputeWorkgroupSizeX); JSG_READONLY_PROTOTYPE_PROPERTY(maxComputeWorkgroupSizeY, getMaxComputeWorkgroupSizeY); JSG_READONLY_PROTOTYPE_PROPERTY(maxComputeWorkgroupSizeZ, getMaxComputeWorkgroupSizeZ); - JSG_READONLY_PROTOTYPE_PROPERTY(maxComputeWorkgroupsPerDimension, - getMaxComputeWorkgroupsPerDimension); + JSG_READONLY_PROTOTYPE_PROPERTY( + maxComputeWorkgroupsPerDimension, getMaxComputeWorkgroupsPerDimension); } private: @@ -187,4 +187,4 @@ class GPUSupportedLimits : public jsg::Object { } }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-texture-view.h b/src/workerd/api/gpu/gpu-texture-view.h index 65120885777..4ac0090897d 100644 --- a/src/workerd/api/gpu/gpu-texture-view.h +++ b/src/workerd/api/gpu/gpu-texture-view.h @@ -12,13 +12,13 @@ namespace workerd::api::gpu { -class GPUTextureView : public jsg::Object { +class GPUTextureView: public jsg::Object { public: // Implicit cast operator to Dawn GPU object inline operator const wgpu::TextureView&() const { return textureView_; } - explicit GPUTextureView(wgpu::TextureView t) : textureView_(kj::mv(t)){}; + explicit GPUTextureView(wgpu::TextureView t): textureView_(kj::mv(t)) {}; JSG_RESOURCE_TYPE(GPUTextureView) {} private: @@ -34,8 +34,14 @@ struct GPUTextureViewDescriptor { GPUIntegerCoordinate mipLevelCount; jsg::Optional baseArrayLayer; GPUIntegerCoordinate arrayLayerCount; - JSG_STRUCT(label, format, dimension, aspect, baseMipLevel, mipLevelCount, baseArrayLayer, - arrayLayerCount); + JSG_STRUCT(label, + format, + dimension, + aspect, + baseMipLevel, + mipLevelCount, + baseArrayLayer, + arrayLayerCount); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-texture.c++ b/src/workerd/api/gpu/gpu-texture.c++ index b69c46517d6..c5609f3c0b0 100644 --- a/src/workerd/api/gpu/gpu-texture.c++ +++ b/src/workerd/api/gpu/gpu-texture.c++ @@ -10,8 +10,8 @@ namespace workerd::api::gpu { -jsg::Ref -GPUTexture::createView(jsg::Optional descriptor) { +jsg::Ref GPUTexture::createView( + jsg::Optional descriptor) { wgpu::TextureViewDescriptor desc{}; KJ_IF_SOME(d, descriptor) { desc.label = d.label.cStr(); @@ -28,4 +28,4 @@ GPUTexture::createView(jsg::Optional descriptor) { return jsg::alloc(kj::mv(textureView)); } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-texture.h b/src/workerd/api/gpu/gpu-texture.h index 827359adf23..eb3ec994354 100644 --- a/src/workerd/api/gpu/gpu-texture.h +++ b/src/workerd/api/gpu/gpu-texture.h @@ -13,13 +13,13 @@ namespace workerd::api::gpu { -class GPUTexture : public jsg::Object { +class GPUTexture: public jsg::Object { public: // Implicit cast operator to Dawn GPU object inline operator const wgpu::Texture&() const { return texture_; } - explicit GPUTexture(wgpu::Texture t) : texture_(kj::mv(t)){}; + explicit GPUTexture(wgpu::Texture t): texture_(kj::mv(t)) {}; JSG_RESOURCE_TYPE(GPUTexture) { JSG_METHOD(createView); JSG_METHOD(destroy); @@ -97,4 +97,4 @@ struct GPUTextureDescriptor { JSG_STRUCT(label, size, mipLevelCount, sampleCount, dimension, format, usage, viewFormats); }; -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-utils.c++ b/src/workerd/api/gpu/gpu-utils.c++ index a37e76bbca6..42c808d242e 100644 --- a/src/workerd/api/gpu/gpu-utils.c++ +++ b/src/workerd/api/gpu/gpu-utils.c++ @@ -10,8 +10,8 @@ namespace workerd::api::gpu { wgpu::StoreOp parseGPUStoreOp(kj::StringPtr storeOp) { static std::map mapping{ - {"store", wgpu::StoreOp::Store}, - {"discard", wgpu::StoreOp::Discard}, + {"store", wgpu::StoreOp::Store}, + {"discard", wgpu::StoreOp::Discard}, }; auto found = mapping.find(storeOp); JSG_REQUIRE(found != mapping.end(), TypeError, "unload GPU store operation: ", storeOp); @@ -20,8 +20,8 @@ wgpu::StoreOp parseGPUStoreOp(kj::StringPtr storeOp) { wgpu::LoadOp parseGPULoadOp(kj::StringPtr loadOp) { static std::map mapping{ - {"load", wgpu::LoadOp::Load}, - {"clear", wgpu::LoadOp::Clear}, + {"load", wgpu::LoadOp::Load}, + {"clear", wgpu::LoadOp::Clear}, }; auto found = mapping.find(loadOp); JSG_REQUIRE(found != mapping.end(), TypeError, "unload GPU load operation: ", loadOp); @@ -71,331 +71,331 @@ wgpu::FeatureName parseFeatureName(GPUFeatureName& str) { GPUTextureDimension getTextureDimension(wgpu::TextureDimension& dimension) { switch (dimension) { - case wgpu::TextureDimension::e1D: - return kj::str("1d"); - case wgpu::TextureDimension::e2D: - return kj::str("2d"); - case wgpu::TextureDimension::e3D: - return kj::str("3d"); - default: - KJ_UNREACHABLE + case wgpu::TextureDimension::e1D: + return kj::str("1d"); + case wgpu::TextureDimension::e2D: + return kj::str("2d"); + case wgpu::TextureDimension::e3D: + return kj::str("3d"); + default: + KJ_UNREACHABLE } } GPUTextureFormat getTextureFormat(wgpu::TextureFormat& format) { switch (format) { - case wgpu::TextureFormat::R8Unorm: - return kj::str("r8unorm"); + case wgpu::TextureFormat::R8Unorm: + return kj::str("r8unorm"); - case wgpu::TextureFormat::R8Snorm: - return kj::str("r8snorm"); + case wgpu::TextureFormat::R8Snorm: + return kj::str("r8snorm"); - case wgpu::TextureFormat::R8Uint: - return kj::str("r8uint"); + case wgpu::TextureFormat::R8Uint: + return kj::str("r8uint"); - case wgpu::TextureFormat::R8Sint: - return kj::str("r8sint"); + case wgpu::TextureFormat::R8Sint: + return kj::str("r8sint"); - case wgpu::TextureFormat::R16Uint: - return kj::str("r16uint"); + case wgpu::TextureFormat::R16Uint: + return kj::str("r16uint"); - case wgpu::TextureFormat::R16Sint: - return kj::str("r16sint"); + case wgpu::TextureFormat::R16Sint: + return kj::str("r16sint"); - case wgpu::TextureFormat::R16Float: - return kj::str("r16float"); + case wgpu::TextureFormat::R16Float: + return kj::str("r16float"); - case wgpu::TextureFormat::RG8Unorm: - return kj::str("rg8unorm"); + case wgpu::TextureFormat::RG8Unorm: + return kj::str("rg8unorm"); - case wgpu::TextureFormat::RG8Snorm: - return kj::str("rg8snorm"); + case wgpu::TextureFormat::RG8Snorm: + return kj::str("rg8snorm"); - case wgpu::TextureFormat::RG8Uint: - return kj::str("rg8uint"); + case wgpu::TextureFormat::RG8Uint: + return kj::str("rg8uint"); - case wgpu::TextureFormat::RG8Sint: - return kj::str("rg8sint"); + case wgpu::TextureFormat::RG8Sint: + return kj::str("rg8sint"); - case wgpu::TextureFormat::R32Uint: - return kj::str("r32uint"); + case wgpu::TextureFormat::R32Uint: + return kj::str("r32uint"); - case wgpu::TextureFormat::R32Sint: - return kj::str("r32sint"); + case wgpu::TextureFormat::R32Sint: + return kj::str("r32sint"); - case wgpu::TextureFormat::R32Float: - return kj::str("r32float"); + case wgpu::TextureFormat::R32Float: + return kj::str("r32float"); - case wgpu::TextureFormat::RG16Uint: - return kj::str("rg16uint"); + case wgpu::TextureFormat::RG16Uint: + return kj::str("rg16uint"); - case wgpu::TextureFormat::RG16Sint: - return kj::str("rg16sint"); + case wgpu::TextureFormat::RG16Sint: + return kj::str("rg16sint"); - case wgpu::TextureFormat::RG16Float: - return kj::str("rg16float"); + case wgpu::TextureFormat::RG16Float: + return kj::str("rg16float"); - case wgpu::TextureFormat::RGBA8Unorm: - return kj::str("rgba8unorm"); + case wgpu::TextureFormat::RGBA8Unorm: + return kj::str("rgba8unorm"); - case wgpu::TextureFormat::RGBA8UnormSrgb: - return kj::str("rgba8unorm-srgb"); + case wgpu::TextureFormat::RGBA8UnormSrgb: + return kj::str("rgba8unorm-srgb"); - case wgpu::TextureFormat::RGBA8Snorm: - return kj::str("rgba8snorm"); + case wgpu::TextureFormat::RGBA8Snorm: + return kj::str("rgba8snorm"); - case wgpu::TextureFormat::RGBA8Uint: - return kj::str("rgba8uint"); + case wgpu::TextureFormat::RGBA8Uint: + return kj::str("rgba8uint"); - case wgpu::TextureFormat::RGBA8Sint: - return kj::str("rgba8sint"); + case wgpu::TextureFormat::RGBA8Sint: + return kj::str("rgba8sint"); - case wgpu::TextureFormat::BGRA8Unorm: - return kj::str("bgra8unorm"); + case wgpu::TextureFormat::BGRA8Unorm: + return kj::str("bgra8unorm"); - case wgpu::TextureFormat::BGRA8UnormSrgb: - return kj::str("bgra8unorm-srgb"); + case wgpu::TextureFormat::BGRA8UnormSrgb: + return kj::str("bgra8unorm-srgb"); - case wgpu::TextureFormat::RGB9E5Ufloat: - return kj::str("rgb9e5ufloat"); + case wgpu::TextureFormat::RGB9E5Ufloat: + return kj::str("rgb9e5ufloat"); - case wgpu::TextureFormat::RGB10A2Unorm: - return kj::str("rgb10a2unorm"); + case wgpu::TextureFormat::RGB10A2Unorm: + return kj::str("rgb10a2unorm"); - case wgpu::TextureFormat::RG11B10Ufloat: - return kj::str("rg11b10ufloat"); + case wgpu::TextureFormat::RG11B10Ufloat: + return kj::str("rg11b10ufloat"); - case wgpu::TextureFormat::RG32Uint: - return kj::str("rg32uint"); + case wgpu::TextureFormat::RG32Uint: + return kj::str("rg32uint"); - case wgpu::TextureFormat::RG32Sint: - return kj::str("rg32sint"); + case wgpu::TextureFormat::RG32Sint: + return kj::str("rg32sint"); - case wgpu::TextureFormat::RG32Float: - return kj::str("rg32float"); + case wgpu::TextureFormat::RG32Float: + return kj::str("rg32float"); - case wgpu::TextureFormat::RGBA16Uint: - return kj::str("rgba16uint"); + case wgpu::TextureFormat::RGBA16Uint: + return kj::str("rgba16uint"); - case wgpu::TextureFormat::RGBA16Sint: - return kj::str("rgba16sint"); + case wgpu::TextureFormat::RGBA16Sint: + return kj::str("rgba16sint"); - case wgpu::TextureFormat::RGBA16Float: - return kj::str("rgba16float"); + case wgpu::TextureFormat::RGBA16Float: + return kj::str("rgba16float"); - case wgpu::TextureFormat::RGBA32Uint: - return kj::str("rgba32uint"); + case wgpu::TextureFormat::RGBA32Uint: + return kj::str("rgba32uint"); - case wgpu::TextureFormat::RGBA32Sint: - return kj::str("rgba32sint"); + case wgpu::TextureFormat::RGBA32Sint: + return kj::str("rgba32sint"); - case wgpu::TextureFormat::RGBA32Float: - return kj::str("rgba32float"); + case wgpu::TextureFormat::RGBA32Float: + return kj::str("rgba32float"); - case wgpu::TextureFormat::Stencil8: - return kj::str("stencil8"); + case wgpu::TextureFormat::Stencil8: + return kj::str("stencil8"); - case wgpu::TextureFormat::Depth16Unorm: - return kj::str("depth16unorm"); + case wgpu::TextureFormat::Depth16Unorm: + return kj::str("depth16unorm"); - case wgpu::TextureFormat::Depth24Plus: - return kj::str("depth24plus"); + case wgpu::TextureFormat::Depth24Plus: + return kj::str("depth24plus"); - case wgpu::TextureFormat::Depth24PlusStencil8: - return kj::str("depth24plus-stencil8"); + case wgpu::TextureFormat::Depth24PlusStencil8: + return kj::str("depth24plus-stencil8"); - case wgpu::TextureFormat::Depth32Float: - return kj::str("depth32float"); + case wgpu::TextureFormat::Depth32Float: + return kj::str("depth32float"); - case wgpu::TextureFormat::Depth32FloatStencil8: - return kj::str("depth32float-stencil8"); + case wgpu::TextureFormat::Depth32FloatStencil8: + return kj::str("depth32float-stencil8"); - case wgpu::TextureFormat::BC1RGBAUnorm: - return kj::str("bc1-rgba-unorm"); + case wgpu::TextureFormat::BC1RGBAUnorm: + return kj::str("bc1-rgba-unorm"); - case wgpu::TextureFormat::BC1RGBAUnormSrgb: - return kj::str("bc1-rgba-unorm-srgb"); + case wgpu::TextureFormat::BC1RGBAUnormSrgb: + return kj::str("bc1-rgba-unorm-srgb"); - case wgpu::TextureFormat::BC2RGBAUnorm: - return kj::str("bc2-rgba-unorm"); + case wgpu::TextureFormat::BC2RGBAUnorm: + return kj::str("bc2-rgba-unorm"); - case wgpu::TextureFormat::BC2RGBAUnormSrgb: - return kj::str("bc2-rgba-unorm-srgb"); + case wgpu::TextureFormat::BC2RGBAUnormSrgb: + return kj::str("bc2-rgba-unorm-srgb"); - case wgpu::TextureFormat::BC3RGBAUnorm: - return kj::str("bc3-rgba-unorm"); + case wgpu::TextureFormat::BC3RGBAUnorm: + return kj::str("bc3-rgba-unorm"); - case wgpu::TextureFormat::BC3RGBAUnormSrgb: - return kj::str("bc3-rgba-unorm-srgb"); + case wgpu::TextureFormat::BC3RGBAUnormSrgb: + return kj::str("bc3-rgba-unorm-srgb"); - case wgpu::TextureFormat::BC4RUnorm: - return kj::str("bc4-r-unorm"); + case wgpu::TextureFormat::BC4RUnorm: + return kj::str("bc4-r-unorm"); - case wgpu::TextureFormat::BC4RSnorm: - return kj::str("bc4-r-snorm"); + case wgpu::TextureFormat::BC4RSnorm: + return kj::str("bc4-r-snorm"); - case wgpu::TextureFormat::BC5RGUnorm: - return kj::str("bc5-rg-unorm"); + case wgpu::TextureFormat::BC5RGUnorm: + return kj::str("bc5-rg-unorm"); - case wgpu::TextureFormat::BC5RGSnorm: - return kj::str("bc5-rg-snorm"); + case wgpu::TextureFormat::BC5RGSnorm: + return kj::str("bc5-rg-snorm"); - case wgpu::TextureFormat::BC6HRGBUfloat: - return kj::str("bc6h-rgb-ufloat"); + case wgpu::TextureFormat::BC6HRGBUfloat: + return kj::str("bc6h-rgb-ufloat"); - case wgpu::TextureFormat::BC6HRGBFloat: - return kj::str("bc6h-rgb-float"); + case wgpu::TextureFormat::BC6HRGBFloat: + return kj::str("bc6h-rgb-float"); - case wgpu::TextureFormat::BC7RGBAUnorm: - return kj::str("bc7-rgba-unorm"); + case wgpu::TextureFormat::BC7RGBAUnorm: + return kj::str("bc7-rgba-unorm"); - case wgpu::TextureFormat::BC7RGBAUnormSrgb: - return kj::str("bc7-rgba-unorm-srgb"); + case wgpu::TextureFormat::BC7RGBAUnormSrgb: + return kj::str("bc7-rgba-unorm-srgb"); - case wgpu::TextureFormat::ETC2RGB8Unorm: - return kj::str("etc2-rgb8unorm"); + case wgpu::TextureFormat::ETC2RGB8Unorm: + return kj::str("etc2-rgb8unorm"); - case wgpu::TextureFormat::ETC2RGB8UnormSrgb: - return kj::str("etc2-rgb8unorm-srgb"); + case wgpu::TextureFormat::ETC2RGB8UnormSrgb: + return kj::str("etc2-rgb8unorm-srgb"); - case wgpu::TextureFormat::ETC2RGB8A1Unorm: - return kj::str("etc2-rgb8a1unorm"); + case wgpu::TextureFormat::ETC2RGB8A1Unorm: + return kj::str("etc2-rgb8a1unorm"); - case wgpu::TextureFormat::ETC2RGB8A1UnormSrgb: - return kj::str("etc2-rgb8a1unorm-srgb"); + case wgpu::TextureFormat::ETC2RGB8A1UnormSrgb: + return kj::str("etc2-rgb8a1unorm-srgb"); - case wgpu::TextureFormat::ETC2RGBA8Unorm: - return kj::str("etc2-rgba8unorm"); + case wgpu::TextureFormat::ETC2RGBA8Unorm: + return kj::str("etc2-rgba8unorm"); - case wgpu::TextureFormat::ETC2RGBA8UnormSrgb: - return kj::str("etc2-rgba8unorm-srgb"); + case wgpu::TextureFormat::ETC2RGBA8UnormSrgb: + return kj::str("etc2-rgba8unorm-srgb"); - case wgpu::TextureFormat::EACR11Unorm: - return kj::str("eac-r11unorm"); + case wgpu::TextureFormat::EACR11Unorm: + return kj::str("eac-r11unorm"); - case wgpu::TextureFormat::EACR11Snorm: - return kj::str("eac-r11snorm"); + case wgpu::TextureFormat::EACR11Snorm: + return kj::str("eac-r11snorm"); - case wgpu::TextureFormat::EACRG11Unorm: - return kj::str("eac-rg11unorm"); + case wgpu::TextureFormat::EACRG11Unorm: + return kj::str("eac-rg11unorm"); - case wgpu::TextureFormat::EACRG11Snorm: - return kj::str("eac-rg11snorm"); + case wgpu::TextureFormat::EACRG11Snorm: + return kj::str("eac-rg11snorm"); - case wgpu::TextureFormat::ASTC4x4Unorm: - return kj::str("astc-4x4-unorm"); + case wgpu::TextureFormat::ASTC4x4Unorm: + return kj::str("astc-4x4-unorm"); - case wgpu::TextureFormat::ASTC4x4UnormSrgb: - return kj::str("astc-4x4-unorm-srgb"); + case wgpu::TextureFormat::ASTC4x4UnormSrgb: + return kj::str("astc-4x4-unorm-srgb"); - case wgpu::TextureFormat::ASTC5x4Unorm: - return kj::str("astc-5x4-unorm"); + case wgpu::TextureFormat::ASTC5x4Unorm: + return kj::str("astc-5x4-unorm"); - case wgpu::TextureFormat::ASTC5x4UnormSrgb: - return kj::str("astc-5x4-unorm-srgb"); + case wgpu::TextureFormat::ASTC5x4UnormSrgb: + return kj::str("astc-5x4-unorm-srgb"); - case wgpu::TextureFormat::ASTC5x5Unorm: - return kj::str("astc-5x5-unorm"); + case wgpu::TextureFormat::ASTC5x5Unorm: + return kj::str("astc-5x5-unorm"); - case wgpu::TextureFormat::ASTC5x5UnormSrgb: - return kj::str("astc-5x5-unorm-srgb"); + case wgpu::TextureFormat::ASTC5x5UnormSrgb: + return kj::str("astc-5x5-unorm-srgb"); - case wgpu::TextureFormat::ASTC6x5Unorm: - return kj::str("astc-6x5-unorm"); + case wgpu::TextureFormat::ASTC6x5Unorm: + return kj::str("astc-6x5-unorm"); - case wgpu::TextureFormat::ASTC6x5UnormSrgb: - return kj::str("astc-6x5-unorm-srgb"); + case wgpu::TextureFormat::ASTC6x5UnormSrgb: + return kj::str("astc-6x5-unorm-srgb"); - case wgpu::TextureFormat::ASTC6x6Unorm: - return kj::str("astc-6x6-unorm"); + case wgpu::TextureFormat::ASTC6x6Unorm: + return kj::str("astc-6x6-unorm"); - case wgpu::TextureFormat::ASTC6x6UnormSrgb: - return kj::str("astc-6x6-unorm-srgb"); + case wgpu::TextureFormat::ASTC6x6UnormSrgb: + return kj::str("astc-6x6-unorm-srgb"); - case wgpu::TextureFormat::ASTC8x5Unorm: - return kj::str("astc-8x5-unorm"); + case wgpu::TextureFormat::ASTC8x5Unorm: + return kj::str("astc-8x5-unorm"); - case wgpu::TextureFormat::ASTC8x5UnormSrgb: - return kj::str("astc-8x5-unorm-srgb"); + case wgpu::TextureFormat::ASTC8x5UnormSrgb: + return kj::str("astc-8x5-unorm-srgb"); - case wgpu::TextureFormat::ASTC8x6Unorm: - return kj::str("astc-8x6-unorm"); + case wgpu::TextureFormat::ASTC8x6Unorm: + return kj::str("astc-8x6-unorm"); - case wgpu::TextureFormat::ASTC8x6UnormSrgb: - return kj::str("astc-8x6-unorm-srgb"); + case wgpu::TextureFormat::ASTC8x6UnormSrgb: + return kj::str("astc-8x6-unorm-srgb"); - case wgpu::TextureFormat::ASTC8x8Unorm: - return kj::str("astc-8x8-unorm"); + case wgpu::TextureFormat::ASTC8x8Unorm: + return kj::str("astc-8x8-unorm"); - case wgpu::TextureFormat::ASTC8x8UnormSrgb: - return kj::str("astc-8x8-unorm-srgb"); + case wgpu::TextureFormat::ASTC8x8UnormSrgb: + return kj::str("astc-8x8-unorm-srgb"); - case wgpu::TextureFormat::ASTC10x5Unorm: - return kj::str("astc-10x5-unorm"); + case wgpu::TextureFormat::ASTC10x5Unorm: + return kj::str("astc-10x5-unorm"); - case wgpu::TextureFormat::ASTC10x5UnormSrgb: - return kj::str("astc-10x5-unorm-srgb"); + case wgpu::TextureFormat::ASTC10x5UnormSrgb: + return kj::str("astc-10x5-unorm-srgb"); - case wgpu::TextureFormat::ASTC10x6Unorm: - return kj::str("astc-10x6-unorm"); + case wgpu::TextureFormat::ASTC10x6Unorm: + return kj::str("astc-10x6-unorm"); - case wgpu::TextureFormat::ASTC10x6UnormSrgb: - return kj::str("astc-10x6-unorm-srgb"); + case wgpu::TextureFormat::ASTC10x6UnormSrgb: + return kj::str("astc-10x6-unorm-srgb"); - case wgpu::TextureFormat::ASTC10x8Unorm: - return kj::str("astc-10x8-unorm"); + case wgpu::TextureFormat::ASTC10x8Unorm: + return kj::str("astc-10x8-unorm"); - case wgpu::TextureFormat::ASTC10x8UnormSrgb: - return kj::str("astc-10x8-unorm-srgb"); + case wgpu::TextureFormat::ASTC10x8UnormSrgb: + return kj::str("astc-10x8-unorm-srgb"); - case wgpu::TextureFormat::ASTC10x10Unorm: - return kj::str("astc-10x10-unorm"); + case wgpu::TextureFormat::ASTC10x10Unorm: + return kj::str("astc-10x10-unorm"); - case wgpu::TextureFormat::ASTC10x10UnormSrgb: - return kj::str("astc-10x10-unorm-srgb"); + case wgpu::TextureFormat::ASTC10x10UnormSrgb: + return kj::str("astc-10x10-unorm-srgb"); - case wgpu::TextureFormat::ASTC12x10Unorm: - return kj::str("astc-12x10-unorm"); + case wgpu::TextureFormat::ASTC12x10Unorm: + return kj::str("astc-12x10-unorm"); - case wgpu::TextureFormat::ASTC12x10UnormSrgb: - return kj::str("astc-12x10-unorm-srgb"); + case wgpu::TextureFormat::ASTC12x10UnormSrgb: + return kj::str("astc-12x10-unorm-srgb"); - case wgpu::TextureFormat::ASTC12x12Unorm: - return kj::str("astc-12x12-unorm"); + case wgpu::TextureFormat::ASTC12x12Unorm: + return kj::str("astc-12x12-unorm"); - case wgpu::TextureFormat::ASTC12x12UnormSrgb: - return kj::str("astc-12x12-unorm-srgb"); - default: - KJ_UNREACHABLE + case wgpu::TextureFormat::ASTC12x12UnormSrgb: + return kj::str("astc-12x12-unorm-srgb"); + default: + KJ_UNREACHABLE } } kj::Maybe getFeatureName(wgpu::FeatureName& feature) { switch (feature) { - case wgpu::FeatureName::DepthClipControl: - return kj::str("depth-clip-control"); - case wgpu::FeatureName::Depth32FloatStencil8: - return kj::str("depth32float-stencil8"); - case wgpu::FeatureName::TextureCompressionBC: - return kj::str("texture-compression-bc"); - case wgpu::FeatureName::TextureCompressionETC2: - return kj::str("texture-compression-etc2"); - case wgpu::FeatureName::TextureCompressionASTC: - return kj::str("texture-compression-astc"); - case wgpu::FeatureName::TimestampQuery: - return kj::str("timestamp-query"); - case wgpu::FeatureName::IndirectFirstInstance: - return kj::str("indirect-first-instance"); - case wgpu::FeatureName::ShaderF16: - return kj::str("shader-f16"); - case wgpu::FeatureName::RG11B10UfloatRenderable: - return kj::str("rg11b10ufloat-renderable"); - case wgpu::FeatureName::BGRA8UnormStorage: - return kj::str("bgra8unorm-storage"); - case wgpu::FeatureName::Float32Filterable: - return kj::str("float32-filterable"); - default: - break; + case wgpu::FeatureName::DepthClipControl: + return kj::str("depth-clip-control"); + case wgpu::FeatureName::Depth32FloatStencil8: + return kj::str("depth32float-stencil8"); + case wgpu::FeatureName::TextureCompressionBC: + return kj::str("texture-compression-bc"); + case wgpu::FeatureName::TextureCompressionETC2: + return kj::str("texture-compression-etc2"); + case wgpu::FeatureName::TextureCompressionASTC: + return kj::str("texture-compression-astc"); + case wgpu::FeatureName::TimestampQuery: + return kj::str("timestamp-query"); + case wgpu::FeatureName::IndirectFirstInstance: + return kj::str("indirect-first-instance"); + case wgpu::FeatureName::ShaderF16: + return kj::str("shader-f16"); + case wgpu::FeatureName::RG11B10UfloatRenderable: + return kj::str("rg11b10ufloat-renderable"); + case wgpu::FeatureName::BGRA8UnormStorage: + return kj::str("bgra8unorm-storage"); + case wgpu::FeatureName::Float32Filterable: + return kj::str("float32-filterable"); + default: + break; } return kj::none; @@ -1136,4 +1136,4 @@ wgpu::BlendOperation parseBlendOperation(kj::StringPtr operation) { JSG_FAIL_REQUIRE(TypeError, "unknown blend operation: ", operation); } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu-utils.h b/src/workerd/api/gpu/gpu-utils.h index ae855684e00..1cf6ece3e0a 100644 --- a/src/workerd/api/gpu/gpu-utils.h +++ b/src/workerd/api/gpu/gpu-utils.h @@ -54,7 +54,7 @@ using GPUBlendFactor = kj::String; using GPULoadOp = kj::String; using GPUStoreOp = kj::String; -struct GPUMapMode : public jsg::Object { +struct GPUMapMode: public jsg::Object { static constexpr GPUFlagsConstant READ = 0x0001; static constexpr GPUFlagsConstant WRITE = 0x0002; @@ -64,7 +64,7 @@ struct GPUMapMode : public jsg::Object { } }; -struct GPUShaderStage : public jsg::Object { +struct GPUShaderStage: public jsg::Object { static constexpr GPUFlagsConstant VERTEX = 0x1; static constexpr GPUFlagsConstant FRAGMENT = 0x2; static constexpr GPUFlagsConstant COMPUTE = 0x4; @@ -76,7 +76,7 @@ struct GPUShaderStage : public jsg::Object { }; }; -struct GPUBufferUsage : public jsg::Object { +struct GPUBufferUsage: public jsg::Object { static constexpr GPUFlagsConstant MAP_READ = 0x0001; static constexpr GPUFlagsConstant MAP_WRITE = 0x0002; static constexpr GPUFlagsConstant COPY_SRC = 0x0004; @@ -102,7 +102,7 @@ struct GPUBufferUsage : public jsg::Object { }; }; -struct GPUColorWrite : public jsg::Object { +struct GPUColorWrite: public jsg::Object { static constexpr GPUFlagsConstant RED = 0x1; static constexpr GPUFlagsConstant GREEN = 0x2; static constexpr GPUFlagsConstant BLUE = 0x4; @@ -118,7 +118,7 @@ struct GPUColorWrite : public jsg::Object { }; }; -struct GPUTextureUsage : public jsg::Object { +struct GPUTextureUsage: public jsg::Object { static constexpr GPUFlagsConstant COPY_SRC = 0x01; static constexpr GPUFlagsConstant COPY_DST = 0x02; static constexpr GPUFlagsConstant TEXTURE_BINDING = 0x04; @@ -155,4 +155,4 @@ wgpu::BlendOperation parseBlendOperation(kj::StringPtr operation); wgpu::LoadOp parseGPULoadOp(kj::StringPtr loadOp); wgpu::StoreOp parseGPUStoreOp(kj::StringPtr storeOp); -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu.c++ b/src/workerd/api/gpu/gpu.c++ index 94bc6561be4..24f4cf7b5a3 100644 --- a/src/workerd/api/gpu/gpu.c++ +++ b/src/workerd/api/gpu/gpu.c++ @@ -22,23 +22,23 @@ void initialize() { dawnProcSetProcs(&dawn::native::GetProcs()); } -GPU::GPU() : async_(kj::refcounted(instance_.Get())) {} +GPU::GPU(): async_(kj::refcounted(instance_.Get())) {} kj::String parseAdapterType(wgpu::AdapterType type) { switch (type) { - case wgpu::AdapterType::DiscreteGPU: - return kj::str("Discrete GPU"); - case wgpu::AdapterType::IntegratedGPU: - return kj::str("Integrated GPU"); - case wgpu::AdapterType::CPU: - return kj::str("CPU"); - case wgpu::AdapterType::Unknown: - return kj::str("Unknown"); + case wgpu::AdapterType::DiscreteGPU: + return kj::str("Discrete GPU"); + case wgpu::AdapterType::IntegratedGPU: + return kj::str("Integrated GPU"); + case wgpu::AdapterType::CPU: + return kj::str("CPU"); + case wgpu::AdapterType::Unknown: + return kj::str("Unknown"); } } -jsg::Promise>> -GPU::requestAdapter(jsg::Lock& js, jsg::Optional options) { +jsg::Promise>> GPU::requestAdapter( + jsg::Lock& js, jsg::Optional options) { #if defined(_WIN32) constexpr auto defaultBackendType = wgpu::BackendType::D3D12; @@ -57,15 +57,16 @@ GPU::requestAdapter(jsg::Lock& js, jsg::Optional optio } kj::Maybe adapter; - for (auto& a : adapters) { + for (auto& a: adapters) { wgpu::AdapterInfo info; a.GetInfo(&info); if (info.backendType != defaultBackendType) { continue; } - KJ_LOG(INFO, kj::str("found webgpu device '", info.device, "' of type ", - parseAdapterType(info.adapterType))); + KJ_LOG(INFO, + kj::str("found webgpu device '", info.device, "' of type ", + parseAdapterType(info.adapterType))); adapter = a; break; } @@ -79,4 +80,4 @@ GPU::requestAdapter(jsg::Lock& js, jsg::Optional optio return js.resolvedPromise(kj::Maybe>(kj::none)); } -} // namespace workerd::api::gpu +} // namespace workerd::api::gpu diff --git a/src/workerd/api/gpu/gpu.h b/src/workerd/api/gpu/gpu.h index 63a5ec6d8be..79f797adda6 100644 --- a/src/workerd/api/gpu/gpu.h +++ b/src/workerd/api/gpu/gpu.h @@ -41,7 +41,7 @@ struct GPURequestAdapterOptions { JSG_STRUCT(powerPreference, forceFallbackAdapter); }; -class GPU : public jsg::Object { +class GPU: public jsg::Object { public: explicit GPU(); JSG_RESOURCE_TYPE(GPU) { @@ -49,8 +49,8 @@ class GPU : public jsg::Object { } private: - jsg::Promise>> - requestAdapter(jsg::Lock&, jsg::Optional); + jsg::Promise>> requestAdapter( + jsg::Lock&, jsg::Optional); dawn::native::Instance instance_; kj::Own async_; }; @@ -88,4 +88,4 @@ class GPU : public jsg::Object { api::gpu::GPURenderPassTimestampWrites, api::gpu::GPUImageCopyTexture, \ api::gpu::GPUImageCopyBuffer, api::gpu::GPUOrigin3DDict -}; // namespace workerd::api::gpu +}; // namespace workerd::api::gpu diff --git a/src/workerd/api/hibernatable-web-socket.c++ b/src/workerd/api/hibernatable-web-socket.c++ index 244c9bdf937..bc398fe7717 100644 --- a/src/workerd/api/hibernatable-web-socket.c++ +++ b/src/workerd/api/hibernatable-web-socket.c++ @@ -9,8 +9,7 @@ namespace workerd::api { -HibernatableWebSocketEvent::HibernatableWebSocketEvent() - : ExtendableEvent("webSocketMessage") {}; +HibernatableWebSocketEvent::HibernatableWebSocketEvent(): ExtendableEvent("webSocketMessage") {}; Worker::Actor::HibernationManager& HibernatableWebSocketEvent::getHibernationManager( jsg::Lock& lock) { @@ -19,10 +18,10 @@ Worker::Actor::HibernationManager& HibernatableWebSocketEvent::getHibernationMan } HibernatableWebSocketEvent::ItemsForRelease HibernatableWebSocketEvent::prepareForRelease( - jsg::Lock &lock, kj::StringPtr websocketId) { + jsg::Lock& lock, kj::StringPtr websocketId) { auto& manager = kj::downcast(getHibernationManager(lock)); - auto& hibernatableWebSocket = KJ_REQUIRE_NONNULL( - manager.webSocketsForEventHandler.findEntry(websocketId)); + auto& hibernatableWebSocket = + KJ_REQUIRE_NONNULL(manager.webSocketsForEventHandler.findEntry(websocketId)); // Note that we don't call `claimWebSocket()` to get this, since we would lose our reference to // the HibernatableWebSocket (it removes it from `webSocketsForEventHandler`). @@ -36,15 +35,15 @@ HibernatableWebSocketEvent::ItemsForRelease HibernatableWebSocketEvent::prepareF return ItemsForRelease(kj::mv(websocketRef), kj::mv(ownedWebSocket), kj::mv(tags)); } -jsg::Ref HibernatableWebSocketEvent::claimWebSocket(jsg::Lock& lock, - kj::StringPtr websocketId) { +jsg::Ref HibernatableWebSocketEvent::claimWebSocket( + jsg::Lock& lock, kj::StringPtr websocketId) { // Should only be called once per event since it removes the HibernatableWebSocket from the // webSocketsForEventHandler collection. auto& manager = kj::downcast(getHibernationManager(lock)); // Grab it from our collection. - auto& hibernatableWebSocket = KJ_REQUIRE_NONNULL( - manager.webSocketsForEventHandler.findEntry(websocketId)); + auto& hibernatableWebSocket = + KJ_REQUIRE_NONNULL(manager.webSocketsForEventHandler.findEntry(websocketId)); // Get the reference. auto websocket = hibernatableWebSocket.value->getActiveOrUnhibernate(lock); @@ -75,8 +74,8 @@ kj::Promise HibernatableWebSocketCustomEve auto eventParameters = consumeParams(); KJ_IF_SOME(t, incomingRequest->getWorkerTracer()) { - Trace::HibernatableWebSocketEventInfo::Type type = [&]() - -> Trace::HibernatableWebSocketEventInfo::Type { + Trace::HibernatableWebSocketEventInfo::Type type = + [&]() -> Trace::HibernatableWebSocketEventInfo::Type { KJ_SWITCH_ONEOF(eventParameters.eventType) { KJ_CASE_ONEOF(_, HibernatableSocketParams::Text) { return Trace::HibernatableWebSocketEventInfo::Message{}; @@ -86,9 +85,7 @@ kj::Promise HibernatableWebSocketCustomEve } KJ_CASE_ONEOF(close, HibernatableSocketParams::Close) { return Trace::HibernatableWebSocketEventInfo::Close{ - .code = close.code, - .wasClean = close.wasClean - }; + .code = close.code, .wasClean = close.wasClean}; } KJ_CASE_ONEOF(_, HibernatableSocketParams::Error) { return Trace::HibernatableWebSocketEventInfo::Error{}; @@ -97,52 +94,38 @@ kj::Promise HibernatableWebSocketCustomEve KJ_UNREACHABLE; }(); - t.setEventInfo(context.now(), - Trace::HibernatableWebSocketEventInfo(kj::mv(type)) - ); + t.setEventInfo(context.now(), Trace::HibernatableWebSocketEventInfo(kj::mv(type))); } try { co_await context.run( - [entrypointName=entrypointName, &context, eventParameters = kj::mv(eventParameters)] - (Worker::Lock& lock) mutable { + [entrypointName = entrypointName, &context, eventParameters = kj::mv(eventParameters)]( + Worker::Lock& lock) mutable { KJ_SWITCH_ONEOF(eventParameters.eventType) { KJ_CASE_ONEOF(text, HibernatableSocketParams::Text) { - return lock.getGlobalScope().sendHibernatableWebSocketMessage( - kj::mv(text.message), - eventParameters.eventTimeoutMs, - kj::mv(eventParameters.websocketId), - lock, + return lock.getGlobalScope().sendHibernatableWebSocketMessage(kj::mv(text.message), + eventParameters.eventTimeoutMs, kj::mv(eventParameters.websocketId), lock, lock.getExportedHandler(entrypointName, context.getActor())); } KJ_CASE_ONEOF(data, HibernatableSocketParams::Data) { - return lock.getGlobalScope().sendHibernatableWebSocketMessage( - kj::mv(data.message), - eventParameters.eventTimeoutMs, - kj::mv(eventParameters.websocketId), - lock, + return lock.getGlobalScope().sendHibernatableWebSocketMessage(kj::mv(data.message), + eventParameters.eventTimeoutMs, kj::mv(eventParameters.websocketId), lock, lock.getExportedHandler(entrypointName, context.getActor())); } KJ_CASE_ONEOF(close, HibernatableSocketParams::Close) { - return lock.getGlobalScope().sendHibernatableWebSocketClose( - kj::mv(close), - eventParameters.eventTimeoutMs, - kj::mv(eventParameters.websocketId), - lock, + return lock.getGlobalScope().sendHibernatableWebSocketClose(kj::mv(close), + eventParameters.eventTimeoutMs, kj::mv(eventParameters.websocketId), lock, lock.getExportedHandler(entrypointName, context.getActor())); } KJ_CASE_ONEOF(e, HibernatableSocketParams::Error) { - return lock.getGlobalScope().sendHibernatableWebSocketError( - kj::mv(e.error), - eventParameters.eventTimeoutMs, - kj::mv(eventParameters.websocketId), - lock, + return lock.getGlobalScope().sendHibernatableWebSocketError(kj::mv(e.error), + eventParameters.eventTimeoutMs, kj::mv(eventParameters.websocketId), lock, lock.getExportedHandler(entrypointName, context.getActor())); } KJ_UNREACHABLE; } }); - } catch(kj::Exception e) { + } catch (kj::Exception e) { if (auto desc = e.getDescription(); !jsg::isTunneledException(desc) && !jsg::isDoNotLogException(desc)) { LOG_EXCEPTION("HibernatableWebSocketCustomEventImpl"_kj, e); @@ -152,19 +135,18 @@ kj::Promise HibernatableWebSocketCustomEve waitUntilTasks.add(incomingRequest->drain().attach(kj::mv(incomingRequest))); - co_return Result { + co_return Result{ .outcome = outcome, }; } -kj::Promise - HibernatableWebSocketCustomEventImpl::sendRpc( +kj::Promise HibernatableWebSocketCustomEventImpl::sendRpc( capnp::HttpOverCapnpFactory& httpOverCapnpFactory, capnp::ByteStreamFactory& byteStreamFactory, kj::TaskSet& waitUntilTasks, rpc::EventDispatcher::Client dispatcher) { - auto req = dispatcher.castAs< - rpc::HibernatableWebSocketEventDispatcher>().hibernatableWebSocketEventRequest(); + auto req = dispatcher.castAs() + .hibernatableWebSocketEventRequest(); KJ_IF_SOME(rpcParameters, params.tryGet>()) { req.setMessage(rpcParameters->getMessage()); @@ -198,7 +180,7 @@ kj::Promise return req.send().then([](auto resp) { auto respResult = resp.getResult(); - return WorkerInterface::CustomEvent::Result { + return WorkerInterface::CustomEvent::Result{ .outcome = respResult.getOutcome(), }; }); @@ -206,27 +188,30 @@ kj::Promise HibernatableWebSocketEvent::ItemsForRelease::ItemsForRelease( jsg::Ref ref, kj::Own owned, kj::Array tags) - : webSocketRef(kj::mv(ref)), ownedWebSocket(kj::mv(owned)), tags(kj::mv(tags)) {} + : webSocketRef(kj::mv(ref)), + ownedWebSocket(kj::mv(owned)), + tags(kj::mv(tags)) {} -HibernatableWebSocketCustomEventImpl::HibernatableWebSocketCustomEventImpl( - uint16_t typeId, +HibernatableWebSocketCustomEventImpl::HibernatableWebSocketCustomEventImpl(uint16_t typeId, kj::TaskSet& waitUntilTasks, kj::Own params, kj::Maybe manager) - : typeId(typeId), params(kj::mv(params)) {} -HibernatableWebSocketCustomEventImpl::HibernatableWebSocketCustomEventImpl( - uint16_t typeId, + : typeId(typeId), + params(kj::mv(params)) {} +HibernatableWebSocketCustomEventImpl::HibernatableWebSocketCustomEventImpl(uint16_t typeId, kj::TaskSet& waitUntilTasks, HibernatableSocketParams params, Worker::Actor::HibernationManager& manager) - : typeId(typeId), params(kj::mv(params)), manager(manager) {} + : typeId(typeId), + params(kj::mv(params)), + manager(manager) {} HibernatableSocketParams HibernatableWebSocketCustomEventImpl::consumeParams() { KJ_IF_SOME(p, params.tryGet>()) { kj::Maybe eventParameters; auto websocketId = kj::str(p->getMessage().getWebsocketId()); auto payload = p->getMessage().getPayload(); - switch(payload.which()) { + switch (payload.which()) { case rpc::HibernatableWebSocketEventMessage::Payload::TEXT: { eventParameters.emplace(kj::str(payload.getText()), kj::mv(websocketId)); break; @@ -239,16 +224,12 @@ HibernatableSocketParams HibernatableWebSocketCustomEventImpl::consumeParams() { case rpc::HibernatableWebSocketEventMessage::Payload::CLOSE: { auto close = payload.getClose(); eventParameters.emplace( - close.getCode(), - kj::str(close.getReason()), - close.getWasClean(), - kj::mv(websocketId)); + close.getCode(), kj::str(close.getReason()), close.getWasClean(), kj::mv(websocketId)); break; } case rpc::HibernatableWebSocketEventMessage::Payload::ERROR: { eventParameters.emplace( - KJ_EXCEPTION(FAILED, kj::str(payload.getError())), - kj::mv(websocketId)); + KJ_EXCEPTION(FAILED, kj::str(payload.getError())), kj::mv(websocketId)); break; } } diff --git a/src/workerd/api/hibernatable-web-socket.h b/src/workerd/api/hibernatable-web-socket.h index 2f73f50b43e..f0451b0908a 100644 --- a/src/workerd/api/hibernatable-web-socket.h +++ b/src/workerd/api/hibernatable-web-socket.h @@ -34,9 +34,7 @@ class HibernatableWebSocketEvent final: public ExtendableEvent { kj::Array tags; explicit ItemsForRelease( - jsg::Ref ref, - kj::Own owned, - kj::Array tags); + jsg::Ref ref, kj::Own owned, kj::Array tags); }; // Call this when transferring ownership of the kj::WebSocket and tags to the api::WebSocket. @@ -51,31 +49,28 @@ class HibernatableWebSocketEvent final: public ExtendableEvent { JSG_RESOURCE_TYPE(HibernatableWebSocketEvent) { JSG_INHERIT(ExtendableEvent); } + private: Worker::Actor::HibernationManager& getHibernationManager(jsg::Lock& lock); }; class HibernatableWebSocketCustomEventImpl final: public WorkerInterface::CustomEvent, - public kj::Refcounted { + public kj::Refcounted { public: - HibernatableWebSocketCustomEventImpl( - uint16_t typeId, + HibernatableWebSocketCustomEventImpl(uint16_t typeId, kj::TaskSet& waitUntilTasks, kj::Own params, - kj::Maybe manager=kj::none); - HibernatableWebSocketCustomEventImpl( - uint16_t typeId, + kj::Maybe manager = kj::none); + HibernatableWebSocketCustomEventImpl(uint16_t typeId, kj::TaskSet& waitUntilTasks, HibernatableSocketParams params, Worker::Actor::HibernationManager& manager); - kj::Promise run( - kj::Own incomingRequest, + kj::Promise run(kj::Own incomingRequest, kj::Maybe entrypointName, kj::TaskSet& waitUntilTasks) override; - kj::Promise sendRpc( - capnp::HttpOverCapnpFactory& httpOverCapnpFactory, + kj::Promise sendRpc(capnp::HttpOverCapnpFactory& httpOverCapnpFactory, capnp::ByteStreamFactory& byteStreamFactory, kj::TaskSet& waitUntilTasks, rpc::EventDispatcher::Client dispatcher) override; @@ -95,7 +90,6 @@ class HibernatableWebSocketCustomEventImpl final: public WorkerInterface::Custom kj::Maybe manager; }; -#define EW_WEB_SOCKET_MESSAGE_ISOLATE_TYPES \ - api::HibernatableWebSocketEvent, \ - api::HibernatableWebSocketExportedHandler +#define EW_WEB_SOCKET_MESSAGE_ISOLATE_TYPES \ + api::HibernatableWebSocketEvent, api::HibernatableWebSocketExportedHandler } // namespace workerd::api diff --git a/src/workerd/api/hibernation-event-params.h b/src/workerd/api/hibernation-event-params.h index 371e61ae143..89586dba5fd 100644 --- a/src/workerd/api/hibernation-event-params.h +++ b/src/workerd/api/hibernation-event-params.h @@ -11,47 +11,51 @@ #include namespace workerd::api { - // Event types and their corresponding parameters. - struct HibernatableSocketParams { - struct Text { - kj::String message; - }; - - struct Data { - kj::Array message; - }; - - struct Close { - uint16_t code; - kj::String reason; - bool wasClean; - }; - - struct Error { - kj::Exception error; - }; - - kj::OneOf eventType; - kj::String websocketId; - kj::Maybe eventTimeoutMs; - - explicit HibernatableSocketParams(kj::String message, kj::String id) - : eventType(Text { kj::mv(message) }), websocketId(kj::mv(id)) {} - explicit HibernatableSocketParams(kj::Array message, kj::String id) - : eventType(Data { kj::mv(message) }), websocketId(kj::mv(id)) {} - explicit HibernatableSocketParams(uint16_t code, kj::String reason, bool wasClean, kj::String id) - : eventType(Close { code, kj::mv(reason), wasClean }), websocketId(kj::mv(id)) {} - explicit HibernatableSocketParams(kj::Exception e, kj::String id) - : eventType(Error { kj::mv(e) }), websocketId(kj::mv(id)) {} - - HibernatableSocketParams(HibernatableSocketParams&& other) = default; - - bool isCloseEvent() { - return eventType.is(); - } - - void setTimeout(kj::Maybe timeoutMs) { - eventTimeoutMs = kj::mv(timeoutMs); - } +// Event types and their corresponding parameters. +struct HibernatableSocketParams { + struct Text { + kj::String message; }; -}; // namespace workerd::api + + struct Data { + kj::Array message; + }; + + struct Close { + uint16_t code; + kj::String reason; + bool wasClean; + }; + + struct Error { + kj::Exception error; + }; + + kj::OneOf eventType; + kj::String websocketId; + kj::Maybe eventTimeoutMs; + + explicit HibernatableSocketParams(kj::String message, kj::String id) + : eventType(Text{kj::mv(message)}), + websocketId(kj::mv(id)) {} + explicit HibernatableSocketParams(kj::Array message, kj::String id) + : eventType(Data{kj::mv(message)}), + websocketId(kj::mv(id)) {} + explicit HibernatableSocketParams(uint16_t code, kj::String reason, bool wasClean, kj::String id) + : eventType(Close{code, kj::mv(reason), wasClean}), + websocketId(kj::mv(id)) {} + explicit HibernatableSocketParams(kj::Exception e, kj::String id) + : eventType(Error{kj::mv(e)}), + websocketId(kj::mv(id)) {} + + HibernatableSocketParams(HibernatableSocketParams&& other) = default; + + bool isCloseEvent() { + return eventType.is(); + } + + void setTimeout(kj::Maybe timeoutMs) { + eventTimeoutMs = kj::mv(timeoutMs); + } +}; +}; // namespace workerd::api diff --git a/src/workerd/api/html-rewriter.c++ b/src/workerd/api/html-rewriter.c++ index 6c2265aefd2..9eb1d71195d 100644 --- a/src/workerd/api/html-rewriter.c++ +++ b/src/workerd/api/html-rewriter.c++ @@ -39,11 +39,11 @@ protected: template const LolHtmlDisposer LolHtmlDisposer::INSTANCE; -#define LOL_HTML_OWN(name, ...) \ - ({ \ - using T = lol_html_##name##_t; \ - constexpr auto* lolhtmlFree = lol_html_##name##_free; \ - kj::Own(&check(__VA_ARGS__), LolHtmlDisposer::INSTANCE); \ +#define LOL_HTML_OWN(name, ...) \ + ({ \ + using T = lol_html_##name##_t; \ + constexpr auto* lolhtmlFree = lol_html_##name##_free; \ + kj::Own(&check(__VA_ARGS__), LolHtmlDisposer::INSTANCE); \ }) // RAII helper for lol_html_str_t. @@ -56,7 +56,7 @@ class LolString { public: explicit LolString(lol_html_str_t s): chars(s.data, s.len) {} ~LolString() noexcept(false) { - lol_html_str_free({ chars.begin(), chars.size() }); + lol_html_str_free({chars.begin(), chars.size()}); } KJ_DISALLOW_COPY(LolString); LolString(LolString&& other): chars(other.chars) { @@ -69,7 +69,9 @@ public: return *this; } - kj::ArrayPtr asChars() const { return chars; } + kj::ArrayPtr asChars() const { + return chars; + } kj::Maybe asKjString() { if (chars.begin() != nullptr) { @@ -130,8 +132,8 @@ template // content handler, you're gonna get this exception. template decltype(auto) checkToken(kj::Maybe& impl) { - return JSG_REQUIRE_NONNULL(impl, - TypeError, "This content token is no longer valid. Content tokens are only valid " + return JSG_REQUIRE_NONNULL(impl, TypeError, + "This content token is no longer valid. Content tokens are only valid " "during the execution of the relevant content handler."); } @@ -143,14 +145,13 @@ decltype(auto) checkToken(kj::Maybe& impl) { class HTMLRewriter::TokenScope { public: template - explicit TokenScope(jsg::Ref& value) - : contentToken(value.addRef()) {} + explicit TokenScope(jsg::Ref& value): contentToken(value.addRef()) {} ~TokenScope() noexcept(false) { KJ_IF_SOME(token, contentToken) { token->htmlContentScopeEnd(); } } - TokenScope(TokenScope&& o) : contentToken(kj::mv(o.contentToken)) { + TokenScope(TokenScope&& o): contentToken(kj::mv(o.contentToken)) { o.contentToken = kj::none; } KJ_DISALLOW_COPY(TokenScope); @@ -216,8 +217,7 @@ using UnregisteredElementOrDocumentHandlers = // Wrapper around an actual rewriter (streaming parser). class Rewriter final: public WritableStreamSink { public: - explicit Rewriter( - jsg::Lock& js, + explicit Rewriter(jsg::Lock& js, kj::ArrayPtr unregisteredHandlers, kj::ArrayPtr encoding, kj::Own inner); @@ -230,7 +230,7 @@ public: void abort(kj::Exception reason) override; // Implementation for `Element::onEndTag` to avoid exposing private details of Rewriter. - void onEndTag(lol_html_element_t *element, ElementCallbackFunction&& callback); + void onEndTag(lol_html_element_t* element, ElementCallbackFunction&& callback); private: // Wait for the write promise (if any) produced by our `output()` callback, then, if there is a @@ -240,7 +240,8 @@ private: static kj::Own buildRewriter(jsg::Lock& js, kj::ArrayPtr unregisteredHandlers, - kj::ArrayPtr encoding, Rewriter& rewriterWrapper); + kj::ArrayPtr encoding, + Rewriter& rewriterWrapper); static void output(const char* buffer, size_t size, void* userdata); void outputImpl(kj::ArrayPtr buffer); @@ -256,7 +257,7 @@ private: KJ_ASSERT(rc == -1); discardLastError(); - throw kj::CanceledException { }; + throw kj::CanceledException{}; } } @@ -283,9 +284,9 @@ private: template static lol_html_rewriter_directive_t thunk(CType* content, void* userdata); template - lol_html_rewriter_directive_t thunkImpl( CType* content, RegisteredHandler& registration); + lol_html_rewriter_directive_t thunkImpl(CType* content, RegisteredHandler& registration); template - kj::Promise thunkPromise( CType* content, RegisteredHandler& registration); + kj::Promise thunkPromise(CType* content, RegisteredHandler& registration); // Eagerly free this handler. Should only be called if we're confident the handler will never be // used again. @@ -325,14 +326,15 @@ private: } }; -kj::Own Rewriter::buildRewriter( - jsg::Lock& js, kj::ArrayPtr unregisteredHandlers, - kj::ArrayPtr encoding, Rewriter& rewriter) { +kj::Own Rewriter::buildRewriter(jsg::Lock& js, + kj::ArrayPtr unregisteredHandlers, + kj::ArrayPtr encoding, + Rewriter& rewriter) { auto builder = LOL_HTML_OWN(rewriter_builder, lol_html_rewriter_builder_new()); auto registerCallback = [&](ElementCallbackFunction& callback) { - auto registeredHandler = RegisteredHandler{rewriter, callback.addRef(js) }; - return rewriter.registeredHandlers.add(kj::heap(kj::mv(registeredHandler))).get(); + auto registeredHandler = RegisteredHandler{rewriter, callback.addRef(js)}; + return rewriter.registeredHandlers.add(kj::heap(kj::mv(registeredHandler))).get(); }; for (auto& handlers: unregisteredHandlers) { @@ -342,14 +344,10 @@ kj::Own Rewriter::buildRewriter( auto comments = elementHandlers.comments.map(registerCallback); auto text = elementHandlers.text.map(registerCallback); - check(lol_html_rewriter_builder_add_element_content_handlers( - builder, - elementHandlers.selector, - element == kj::none ? nullptr : &Rewriter::thunk, - element.orDefault(nullptr), - comments == kj::none ? nullptr : &Rewriter::thunk, - comments.orDefault(nullptr), - text == kj::none ? nullptr : &Rewriter::thunk, + check(lol_html_rewriter_builder_add_element_content_handlers(builder, + elementHandlers.selector, element == kj::none ? nullptr : &Rewriter::thunk, + element.orDefault(nullptr), comments == kj::none ? nullptr : &Rewriter::thunk, + comments.orDefault(nullptr), text == kj::none ? nullptr : &Rewriter::thunk, text.orDefault(nullptr))); } KJ_CASE_ONEOF(documentHandlers, UnregisteredDocumentHandlers) { @@ -359,16 +357,11 @@ kj::Own Rewriter::buildRewriter( auto end = documentHandlers.end.map(registerCallback); // Adding document content handlers cannot fail, so no need for check(). - lol_html_rewriter_builder_add_document_content_handlers( - builder, - doctype == kj::none ? nullptr : &Rewriter::thunk, - doctype.orDefault(nullptr), - comments == kj::none ? nullptr : &Rewriter::thunk, - comments.orDefault(nullptr), - text == kj::none ? nullptr : &Rewriter::thunk, - text.orDefault(nullptr), - end == kj::none ? nullptr : &Rewriter::thunk, - end.orDefault(nullptr)); + lol_html_rewriter_builder_add_document_content_handlers(builder, + doctype == kj::none ? nullptr : &Rewriter::thunk, doctype.orDefault(nullptr), + comments == kj::none ? nullptr : &Rewriter::thunk, comments.orDefault(nullptr), + text == kj::none ? nullptr : &Rewriter::thunk, text.orDefault(nullptr), + end == kj::none ? nullptr : &Rewriter::thunk, end.orDefault(nullptr)); } } } @@ -381,22 +374,21 @@ kj::Own Rewriter::buildRewriter( // Configure a maximum memory limit that `lol-html` is allowed to use and // preallocate some memory for its internal buffer. lol_html_memory_settings_t memorySettings = { - .preallocated_parsing_buffer_size = 1024, - .max_allowed_memory_usage = 3 * 1024 * 1024 - }; + .preallocated_parsing_buffer_size = 1024, .max_allowed_memory_usage = 3 * 1024 * 1024}; if (FeatureFlags::get(js).getEsiIncludeIsVoidTag()) { - return LOL_HTML_OWN(rewriter, unstable_lol_html_rewriter_build_with_esi_tags( - builder, encoding.begin(), encoding.size(), memorySettings, &Rewriter::output, &rewriter, isStrict)); + return LOL_HTML_OWN(rewriter, + unstable_lol_html_rewriter_build_with_esi_tags(builder, encoding.begin(), encoding.size(), + memorySettings, &Rewriter::output, &rewriter, isStrict)); } else { - return LOL_HTML_OWN(rewriter, lol_html_rewriter_build( - builder, encoding.begin(), encoding.size(), memorySettings, &Rewriter::output, &rewriter, isStrict)); + return LOL_HTML_OWN(rewriter, + lol_html_rewriter_build(builder, encoding.begin(), encoding.size(), memorySettings, + &Rewriter::output, &rewriter, isStrict)); } } -Rewriter::Rewriter( - jsg::Lock& js, +Rewriter::Rewriter(jsg::Lock& js, kj::ArrayPtr unregisteredHandlers, kj::ArrayPtr encoding, kj::Own inner) @@ -416,7 +408,7 @@ const kj::FiberPool& getFiberPool() { return FIBER_POOL; } -} // namespace +} // namespace kj::Promise Rewriter::write(kj::ArrayPtr buffer) { KJ_ASSERT(maybeWaitScope == kj::none); @@ -434,8 +426,7 @@ kj::Promise Rewriter::write(kj::ArrayPtr buffer) { }); } -kj::Promise Rewriter::write( - kj::ArrayPtr> pieces) { +kj::Promise Rewriter::write(kj::ArrayPtr> pieces) { KJ_ASSERT(maybeWaitScope == kj::none); return getFiberPool().startFiber([this, pieces](kj::WaitScope& scope) { maybeWaitScope = scope; @@ -494,9 +485,7 @@ kj::Promise Rewriter::finishWrite() { KJ_IF_SOME(wp, writePromise) { KJ_DEFER(writePromise = kj::none); - return wp.then([checkException]() { - return checkException(); - }); + return wp.then([checkException]() { return checkException(); }); } return checkException(); @@ -524,7 +513,7 @@ lol_html_rewriter_directive_t Rewriter::thunkImpl( // here, we're in an entirely different stack that V8 doesn't know about, so it gets confused // and may think we've overflowed our stack. evalLater will run thunkPromise on the main stack // to keep V8 from getting confused. - auto promise = kj::evalLater([&] () { return thunkPromise(content, registeredHandler); }); + auto promise = kj::evalLater([&]() { return thunkPromise(content, registeredHandler); }); promise.wait(KJ_ASSERT_NONNULL(maybeWaitScope)); })) { // Exception in handler. We need to abort the streaming parser, but can't do so just yet: we @@ -562,9 +551,9 @@ void Rewriter::removeEndTagHandler(RegisteredHandler& handler) { } template -kj::Promise Rewriter::thunkPromise( CType* content, RegisteredHandler& registeredHandler) { +kj::Promise Rewriter::thunkPromise(CType* content, RegisteredHandler& registeredHandler) { return ioContext.run( - [this,content,®isteredHandler](Worker::Lock& lock) -> kj::Promise { + [this, content, ®isteredHandler](Worker::Lock& lock) -> kj::Promise { // We enter the AsyncContextFrame that was current when the Rewriter was created // (when transform() was called). If someone wants, instead, to use the context // that was current when on(...) is called, the ElementHandler can use AsyncResource @@ -587,8 +576,8 @@ kj::Promise Rewriter::thunkPromise( CType* content, RegisteredHandler& reg }); } -void Rewriter::onEndTag(lol_html_element_t *element, ElementCallbackFunction&& callback) { - auto registeredHandler = Rewriter::RegisteredHandler { *this, kj::mv(callback) }; +void Rewriter::onEndTag(lol_html_element_t* element, ElementCallbackFunction&& callback) { + auto registeredHandler = Rewriter::RegisteredHandler{*this, kj::mv(callback)}; // NOTE: this gets freed in `thunkPromise` above. // TODO(someday): this uses more memory than necessary for implied end tags, which lol-html // doesn't actually call `thunk` on. LOL HTML drops the handler after it finishes transforming @@ -600,7 +589,8 @@ void Rewriter::onEndTag(lol_html_element_t *element, ElementCallbackFunction&& c // this will cause a memory leak! auto& registeredHandlerPtr = registeredEndTagHandlers.add(kj::heap(kj::mv(registeredHandler))); lol_html_element_clear_end_tag_handlers(element); - check(lol_html_element_add_end_tag_handler(element, Rewriter::thunk, registeredHandlerPtr.get())); + check(lol_html_element_add_end_tag_handler( + element, Rewriter::thunk, registeredHandlerPtr.get())); } void Rewriter::output(const char* buffer, size_t size, void* userdata) { @@ -652,8 +642,7 @@ kj::StringPtr Element::getNamespaceURI() { jsg::Ref Element::getAttributes() { auto& implRef = checkToken(impl); - auto iter = LOL_HTML_OWN( - attributes_iterator, lol_html_attributes_iterator_get(&implRef.element)); + auto iter = LOL_HTML_OWN(attributes_iterator, lol_html_attributes_iterator_get(&implRef.element)); auto jsIter = jsg::alloc(kj::mv(iter)); implRef.attributesIterators.add(jsIter.addRef()); @@ -663,9 +652,9 @@ jsg::Ref Element::getAttributes() { kj::Maybe Element::getAttribute(kj::String name) { // NOTE: lol_html_element_get_attribute() returns NULL for both nonexistent attributes and for // errors, so we can't use check() here. - LolString attr(lol_html_element_get_attribute( - &checkToken(impl).element, name.cStr(), name.size())); - // TODO(perf): We could construct a v8::String directly here, saving a copy. + LolString attr( + lol_html_element_get_attribute(&checkToken(impl).element, name.cStr(), name.size())); + // TODO(perf): We could construct a v8::String directly here, saving a copy. kj::Maybe kjAttr = attr.asKjString(); if (kjAttr != kj::none) { return kj::mv(kjAttr); @@ -680,15 +669,13 @@ kj::Maybe Element::getAttribute(kj::String name) { } bool Element::hasAttribute(kj::String name) { - return !!check(lol_html_element_has_attribute( - &checkToken(impl).element, name.cStr(), name.size())); + return !!check( + lol_html_element_has_attribute(&checkToken(impl).element, name.cStr(), name.size())); } jsg::Ref Element::setAttribute(kj::String name, kj::String value) { check(lol_html_element_set_attribute( - &checkToken(impl).element, - name.cStr(), name.size(), - value.cStr(), value.size())); + &checkToken(impl).element, name.cStr(), name.size(), value.cStr(), value.size())); return JSG_THIS; } @@ -702,22 +689,20 @@ jsg::Ref Element::removeAttribute(kj::String name) { namespace { kj::String unwrapContent(Content content) { -return kj::mv(JSG_REQUIRE_NONNULL(content.tryGet(), - TypeError, "Replacing HTML content using a ReadableStream or Response object is not " - "implemented. You must provide a string.")); + return kj::mv(JSG_REQUIRE_NONNULL(content.tryGet(), TypeError, + "Replacing HTML content using a ReadableStream or Response object is not " + "implemented. You must provide a string.")); } } // namespace -#define DEFINE_CONTENT_REWRITER_FUNCTION(camel, snake) \ - jsg::Ref Element::camel(Content content, jsg::Optional options) { \ - auto stringContent = unwrapContent(kj::mv(content)); \ - check(lol_html_element_##snake( \ - &checkToken(impl).element, \ - stringContent.cStr(), stringContent.size(), \ - options.orDefault({}).html.orDefault(false))); \ - return JSG_THIS; \ - } +#define DEFINE_CONTENT_REWRITER_FUNCTION(camel, snake) \ + jsg::Ref Element::camel(Content content, jsg::Optional options) { \ + auto stringContent = unwrapContent(kj::mv(content)); \ + check(lol_html_element_##snake(&checkToken(impl).element, stringContent.cStr(), \ + stringContent.size(), options.orDefault({}).html.orDefault(false))); \ + return JSG_THIS; \ + } DEFINE_CONTENT_REWRITER_FUNCTION(before, before) DEFINE_CONTENT_REWRITER_FUNCTION(after, after) @@ -760,9 +745,7 @@ void EndTag::setName(kj::String text) { jsg::Ref EndTag::before(Content content, jsg::Optional options) { auto stringContent = unwrapContent(kj::mv(content)); - check(lol_html_end_tag_before( - &checkToken(impl), - stringContent.cStr(), stringContent.size(), + check(lol_html_end_tag_before(&checkToken(impl), stringContent.cStr(), stringContent.size(), options.orDefault({}).html.orDefault(false))); return JSG_THIS; @@ -770,9 +753,7 @@ jsg::Ref EndTag::before(Content content, jsg::Optional o jsg::Ref EndTag::after(Content content, jsg::Optional options) { auto stringContent = unwrapContent(kj::mv(content)); - check(lol_html_end_tag_after( - &checkToken(impl), - stringContent.cStr(), stringContent.size(), + check(lol_html_end_tag_after(&checkToken(impl), stringContent.cStr(), stringContent.size(), options.orDefault({}).html.orDefault(false))); return JSG_THIS; @@ -798,8 +779,7 @@ Element::Impl::~Impl() noexcept(false) { // ======================================================================================= // Element::AttributesIterator -Element::AttributesIterator::AttributesIterator(kj::Own iter) - : impl(kj::mv(iter)) {} +Element::AttributesIterator::AttributesIterator(kj::Own iter): impl(kj::mv(iter)) {} jsg::Ref Element::AttributesIterator::self() { return JSG_THIS; @@ -812,13 +792,13 @@ Element::AttributesIterator::Next Element::AttributesIterator::next() { // End of iteration. // TODO(someday): Eagerly deallocate. Can't seem to nullify the Own without also nullifying the // enclosing Maybe, however. - return { true, kj::none }; + return {true, kj::none}; } auto name = LolString(lol_html_attribute_name_get(attribute)); auto value = LolString(lol_html_attribute_value_get(attribute)); - return { false, kj::arr(kj::str(name.asChars()), kj::str(value.asChars())) }; + return {false, kj::arr(kj::str(name.asChars()), kj::str(value.asChars()))}; } void Element::AttributesIterator::htmlContentScopeEnd() { @@ -846,9 +826,7 @@ bool Comment::getRemoved() { jsg::Ref Comment::before(Content content, jsg::Optional options) { auto stringContent = unwrapContent(kj::mv(content)); - check(lol_html_comment_before( - &checkToken(impl), - stringContent.cStr(), stringContent.size(), + check(lol_html_comment_before(&checkToken(impl), stringContent.cStr(), stringContent.size(), options.orDefault({}).html.orDefault(false))); return JSG_THIS; @@ -856,9 +834,7 @@ jsg::Ref Comment::before(Content content, jsg::Optional jsg::Ref Comment::after(Content content, jsg::Optional options) { auto stringContent = unwrapContent(kj::mv(content)); - check(lol_html_comment_after( - &checkToken(impl), - stringContent.cStr(), stringContent.size(), + check(lol_html_comment_after(&checkToken(impl), stringContent.cStr(), stringContent.size(), options.orDefault({}).html.orDefault(false))); return JSG_THIS; @@ -866,9 +842,7 @@ jsg::Ref Comment::after(Content content, jsg::Optional jsg::Ref Comment::replace(Content content, jsg::Optional options) { auto stringContent = unwrapContent(kj::mv(content)); - check(lol_html_comment_replace( - &checkToken(impl), - stringContent.cStr(), stringContent.size(), + check(lol_html_comment_replace(&checkToken(impl), stringContent.cStr(), stringContent.size(), options.orDefault({}).html.orDefault(false))); return JSG_THIS; @@ -906,9 +880,7 @@ bool Text::getRemoved() { jsg::Ref Text::before(Content content, jsg::Optional options) { auto stringContent = unwrapContent(kj::mv(content)); - check(lol_html_text_chunk_before( - &checkToken(impl), - stringContent.cStr(), stringContent.size(), + check(lol_html_text_chunk_before(&checkToken(impl), stringContent.cStr(), stringContent.size(), options.orDefault({}).html.orDefault(false))); return JSG_THIS; @@ -916,9 +888,7 @@ jsg::Ref Text::before(Content content, jsg::Optional optio jsg::Ref Text::after(Content content, jsg::Optional options) { auto stringContent = unwrapContent(kj::mv(content)); - check(lol_html_text_chunk_after( - &checkToken(impl), - stringContent.cStr(), stringContent.size(), + check(lol_html_text_chunk_after(&checkToken(impl), stringContent.cStr(), stringContent.size(), options.orDefault({}).html.orDefault(false))); return JSG_THIS; @@ -926,9 +896,7 @@ jsg::Ref Text::after(Content content, jsg::Optional option jsg::Ref Text::replace(Content content, jsg::Optional options) { auto stringContent = unwrapContent(kj::mv(content)); - check(lol_html_text_chunk_replace( - &checkToken(impl), - stringContent.cStr(), stringContent.size(), + check(lol_html_text_chunk_replace(&checkToken(impl), stringContent.cStr(), stringContent.size(), options.orDefault({}).html.orDefault(false))); return JSG_THIS; @@ -975,9 +943,7 @@ DocumentEnd::DocumentEnd(CType& documentEnd, Rewriter&): impl(documentEnd) {} jsg::Ref DocumentEnd::append(Content content, jsg::Optional options) { auto stringContent = unwrapContent(kj::mv(content)); - check(lol_html_doc_end_append( - &checkToken(impl), - stringContent.cStr(), stringContent.size(), + check(lol_html_doc_end_append(&checkToken(impl), stringContent.cStr(), stringContent.size(), options.orDefault({}).html.orDefault(false))); return JSG_THIS; @@ -1003,7 +969,7 @@ struct HTMLRewriter::Impl { // order, on the builder object that we create inside of .transform(). JSG_MEMORY_INFO(HTMLRewriter::Impl) { - for (const auto& handlers : unregisteredHandlers) { + for (const auto& handlers: unregisteredHandlers) { KJ_SWITCH_ONEOF(handlers) { KJ_CASE_ONEOF(h, UnregisteredElementHandlers) { tracker.trackField(nullptr, h); @@ -1027,28 +993,20 @@ jsg::Ref HTMLRewriter::constructor() { return jsg::alloc(); } -jsg::Ref HTMLRewriter::on(kj::String stringSelector, ElementContentHandlers&& handlers) { +jsg::Ref HTMLRewriter::on( + kj::String stringSelector, ElementContentHandlers&& handlers) { kj::Own selector = - LOL_HTML_OWN(selector, lol_html_selector_parse(stringSelector.cStr(), - stringSelector.size())); - - impl->unregisteredHandlers.add(UnregisteredElementHandlers { - kj::mv(selector), - kj::mv(handlers.element), - kj::mv(handlers.comments), - kj::mv(handlers.text) - }); + LOL_HTML_OWN(selector, lol_html_selector_parse(stringSelector.cStr(), stringSelector.size())); + + impl->unregisteredHandlers.add(UnregisteredElementHandlers{ + kj::mv(selector), kj::mv(handlers.element), kj::mv(handlers.comments), kj::mv(handlers.text)}); return JSG_THIS; } jsg::Ref HTMLRewriter::onDocument(DocumentContentHandlers&& handlers) { - impl->unregisteredHandlers.add(UnregisteredDocumentHandlers { - kj::mv(handlers.doctype), - kj::mv(handlers.comments), - kj::mv(handlers.text), - kj::mv(handlers.end) - }); + impl->unregisteredHandlers.add(UnregisteredDocumentHandlers{kj::mv(handlers.doctype), + kj::mv(handlers.comments), kj::mv(handlers.text), kj::mv(handlers.end)}); return JSG_THIS; } @@ -1064,9 +1022,8 @@ jsg::Ref HTMLRewriter::transform(jsg::Lock& js, jsg::Ref res auto& ioContext = IoContext::current(); auto pipe = newIdentityPipe(); - response = Response::constructor(js, - kj::Maybe(jsg::alloc(ioContext, kj::mv(pipe.in))), - kj::mv(response)); + response = Response::constructor( + js, kj::Maybe(jsg::alloc(ioContext, kj::mv(pipe.in))), kj::mv(response)); kj::String ownContentType; kj::String encoding = kj::str("utf-8"); diff --git a/src/workerd/api/html-rewriter.h b/src/workerd/api/html-rewriter.h index 485051a0256..44bc731bf22 100644 --- a/src/workerd/api/html-rewriter.h +++ b/src/workerd/api/html-rewriter.h @@ -437,18 +437,10 @@ class DocumentEnd final: public HTMLRewriter::Token { void htmlContentScopeEnd() override; }; -#define EW_HTML_REWRITER_ISOLATE_TYPES \ - api::ContentOptions, \ - api::HTMLRewriter, \ - api::HTMLRewriter::ElementContentHandlers, \ - api::HTMLRewriter::DocumentContentHandlers, \ - api::Doctype, \ - api::Element, \ - api::EndTag, \ - api::Comment, \ - api::Text, \ - api::DocumentEnd, \ - api::Element::AttributesIterator, \ - api::Element::AttributesIterator::Next +#define EW_HTML_REWRITER_ISOLATE_TYPES \ + api::ContentOptions, api::HTMLRewriter, api::HTMLRewriter::ElementContentHandlers, \ + api::HTMLRewriter::DocumentContentHandlers, api::Doctype, api::Element, api::EndTag, \ + api::Comment, api::Text, api::DocumentEnd, api::Element::AttributesIterator, \ + api::Element::AttributesIterator::Next } // namespace workerd::api diff --git a/src/workerd/api/http.c++ b/src/workerd/api/http.c++ index ec82b28933d..c1f7c6bea4a 100644 --- a/src/workerd/api/http.c++ +++ b/src/workerd/api/http.c++ @@ -41,19 +41,22 @@ void warnIfBadHeaderString(const jsg::ByteString& byteString) { KJ_ASSERT(b < 256); // Guaranteed by StringWrapper having set CONTAINS_EXTENDED_ASCII. return kj::str("\\x", kj::hex(kj::byte(b))); }, ""); - auto utf8Hex = kj::strArray(KJ_MAP(b, byteString) { - return kj::str("\\x", kj::hex(kj::byte(b))); - }, ""); + auto utf8Hex = + kj::strArray( + KJ_MAP(b, byteString) { return kj::str("\\x", kj::hex(kj::byte(b))); }, ""); - context.logWarning(kj::str( - "Problematic header name or value: \"", byteString, "\" (raw bytes: \"", rawHex, "\"). " + context.logWarning(kj::str("Problematic header name or value: \"", byteString, + "\" (raw bytes: \"", rawHex, + "\"). " "This string contains 8-bit characters in the range 0x80 - 0xFF. As a quirk to support " "Unicode, we encode header strings in UTF-8, meaning the actual header name/value on " - "the wire will be \"", utf8Hex, "\". Consider encoding this string in ASCII for " + "the wire will be \"", + utf8Hex, + "\". Consider encoding this string in ASCII for " "compatibility with browser implementations of the Fetch specifications.")); } else if (byteString.warning == jsg::ByteString::Warning::CONTAINS_UNICODE) { - context.logWarning(kj::str( - "Invalid header name or value: \"", byteString, "\". Per the Fetch specification, the " + context.logWarning(kj::str("Invalid header name or value: \"", byteString, + "\". Per the Fetch specification, the " "Headers class may only accept header names and values which contain 8-bit characters. " "That is, they must not contain any Unicode code points greater than 0xFF. As a quirk, " "we are encoding this string in UTF-8 in the header, but in a browser this would " @@ -69,9 +72,7 @@ jsg::ByteString normalizeHeaderValue(jsg::ByteString value) { warnIfBadHeaderString(value); kj::ArrayPtr slice = value; - auto isHttpWhitespace = [](char c) { - return c == '\t' || c == '\r' || c == '\n' || c == ' '; - }; + auto isHttpWhitespace = [](char c) { return c == '\t' || c == '\r' || c == '\n' || c == ' '; }; while (slice.size() > 0 && isHttpWhitespace(slice.front())) { slice = slice.slice(1, slice.size()); } @@ -92,11 +93,10 @@ void requireValidHeaderName(const jsg::ByteString& name) { constexpr auto HTTP_SEPARATOR_CHARS = kj::parse::anyOfChars("()<>@,;:\\\"/[]?={} \t"); // RFC2616 section 2.2: https://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 - constexpr auto HTTP_TOKEN_CHARS = - kj::parse::controlChar.orChar('\x7f') - .orGroup(kj::parse::whitespaceChar) - .orGroup(HTTP_SEPARATOR_CHARS) - .invert(); + constexpr auto HTTP_TOKEN_CHARS = kj::parse::controlChar.orChar('\x7f') + .orGroup(kj::parse::whitespaceChar) + .orGroup(HTTP_SEPARATOR_CHARS) + .invert(); // RFC2616 section 2.2: https://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 // RFC2616 section 4.2: https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 @@ -115,17 +115,15 @@ void requireValidHeaderValue(kj::StringPtr value) { } // namespace -Headers::Headers(jsg::Dict dict) - : guard(Guard::NONE) { +Headers::Headers(jsg::Dict dict): guard(Guard::NONE) { for (auto& field: dict.fields) { append(kj::mv(field.name), kj::mv(field.value)); } } -Headers::Headers(const Headers& other) - : guard(Guard::NONE) { +Headers::Headers(const Headers& other): guard(Guard::NONE) { for (auto& header: other.headers) { - Header copy { + Header copy{ jsg::ByteString(kj::str(header.second.key)), jsg::ByteString(kj::str(header.second.name)), KJ_MAP(value, header.second.values) { return jsg::ByteString(kj::str(value)); }, @@ -135,8 +133,7 @@ Headers::Headers(const Headers& other) } } -Headers::Headers(const kj::HttpHeaders& other, Guard guard) - : guard(Guard::NONE) { +Headers::Headers(const kj::HttpHeaders& other, Guard guard): guard(Guard::NONE) { other.forEach([this](auto name, auto value) { append(jsg::ByteString(kj::str(name)), jsg::ByteString(kj::str(value))); }); @@ -172,21 +169,19 @@ bool Headers::hasLowerCase(kj::StringPtr name) { kj::Array Headers::getDisplayedHeaders(jsg::Lock& js) { if (FeatureFlags::get(js).getHttpHeadersGetSetCookie()) { kj::Vector copy; - for (auto& entry : headers) { + for (auto& entry: headers) { if (entry.first == "set-cookie") { // For set-cookie entries, we iterate each individually without // combining them. - for (auto& value : entry.second.values) { - copy.add(Headers::DisplayedHeader { + for (auto& value: entry.second.values) { + copy.add(Headers::DisplayedHeader{ .key = jsg::ByteString(kj::str(entry.first)), .value = jsg::ByteString(kj::str(value)), }); } } else { - copy.add(Headers::DisplayedHeader { - .key = jsg::ByteString(kj::str(entry.first)), - .value = jsg::ByteString(kj::strArray(entry.second.values, ", ")) - }); + copy.add(Headers::DisplayedHeader{.key = jsg::ByteString(kj::str(entry.first)), + .value = jsg::ByteString(kj::strArray(entry.second.values, ", "))}); } } return copy.releaseAsArray(); @@ -194,10 +189,8 @@ kj::Array Headers::getDisplayedHeaders(jsg::Lock& js) // The old behavior before the standard getSetCookie() API was introduced... auto headersCopy = KJ_MAP(mapEntry, headers) { const auto& header = mapEntry.second; - return DisplayedHeader { - jsg::ByteString(kj::str(header.key)), - jsg::ByteString(kj::strArray(header.values, ", ")) - }; + return DisplayedHeader{ + jsg::ByteString(kj::str(header.key)), jsg::ByteString(kj::strArray(header.values, ", "))}; }; return headersCopy; } @@ -236,8 +229,8 @@ jsg::Ref Headers::constructor(jsg::Lock& js, jsg::Optional KJ_CASE_ONEOF(pairs, ByteStringPairs) { auto dict = KJ_MAP(entry, pairs) { JSG_REQUIRE(entry.size() == 2, TypeError, - "To initialize a Headers object from a sequence, each inner sequence " - "must have exactly two elements."); + "To initialize a Headers object from a sequence, each inner sequence " + "must have exactly two elements."); return StringDict::Field{kj::mv(entry[0]), kj::mv(entry[1])}; }; return jsg::alloc(StringDict{kj::mv(dict)}); @@ -347,14 +340,12 @@ void Headers::delete_(jsg::ByteString name) { // invalidation, but the elements would be cheaper to copy. jsg::Ref Headers::entries(jsg::Lock& js) { - return jsg::alloc(IteratorState { - getDisplayedHeaders(js) - }); + return jsg::alloc(IteratorState{getDisplayedHeaders(js)}); } jsg::Ref Headers::keys(jsg::Lock& js) { if (FeatureFlags::get(js).getHttpHeadersGetSetCookie()) { kj::Vector keysCopy; - for (auto& entry : headers) { + for (auto& entry: headers) { // Set-Cookie headers must be handled specially. They should never be combined into a // single value, so the values iterator must separate them. It seems a bit silly, but // the keys iterator can end up having multiple set-cookie instances. @@ -366,39 +357,37 @@ jsg::Ref Headers::keys(jsg::Lock& js) { keysCopy.add(jsg::ByteString(kj::str(entry.first))); } } - return jsg::alloc(IteratorState { keysCopy.releaseAsArray() }); + return jsg::alloc(IteratorState{keysCopy.releaseAsArray()}); } else { - auto keysCopy = KJ_MAP(mapEntry, headers) { - return jsg::ByteString(kj::str(mapEntry.second.key)); - }; - return jsg::alloc(IteratorState { kj::mv(keysCopy) }); + auto keysCopy = + KJ_MAP(mapEntry, headers) { return jsg::ByteString(kj::str(mapEntry.second.key)); }; + return jsg::alloc(IteratorState{kj::mv(keysCopy)}); } } jsg::Ref Headers::values(jsg::Lock& js) { if (FeatureFlags::get(js).getHttpHeadersGetSetCookie()) { kj::Vector values; - for (auto& entry : headers) { + for (auto& entry: headers) { // Set-Cookie headers must be handled specially. They should never be combined into a // single value, so the values iterator must separate them. if (entry.first == "set-cookie") { - for (auto& value : entry.second.values) { + for (auto& value: entry.second.values) { values.add(jsg::ByteString(kj::str(value))); } } else { values.add(jsg::ByteString(kj::strArray(entry.second.values, ", "))); } } - return jsg::alloc(IteratorState { values.releaseAsArray() }); + return jsg::alloc(IteratorState{values.releaseAsArray()}); } else { auto valuesCopy = KJ_MAP(mapEntry, headers) { return jsg::ByteString(kj::strArray(mapEntry.second.values, ", ")); }; - return jsg::alloc(IteratorState { kj::mv(valuesCopy) }); + return jsg::alloc(IteratorState{kj::mv(valuesCopy)}); } } -void Headers::forEach( - jsg::Lock& js, +void Headers::forEach(jsg::Lock& js, jsg::Function)> callback, jsg::Optional thisArg) { auto receiver = js.v8Undefined(); @@ -636,15 +625,14 @@ Body::Buffer Body::Buffer::clone(jsg::Lock& js) { return result; } -Body::ExtractedBody::ExtractedBody(jsg::Ref stream, - kj::Maybe buffer, - kj::Maybe contentType) - : impl { kj::mv(stream), kj::mv(buffer) }, +Body::ExtractedBody::ExtractedBody( + jsg::Ref stream, kj::Maybe buffer, kj::Maybe contentType) + : impl{kj::mv(stream), kj::mv(buffer)}, contentType(kj::mv(contentType)) { // This check is in the constructor rather than `extractBody()`, because we often construct // ExtractedBodys from ReadableStreams directly. - JSG_REQUIRE(!impl.stream->isDisturbed(), - TypeError, "This ReadableStream is disturbed (has already been read from), and cannot " + JSG_REQUIRE(!impl.stream->isDisturbed(), TypeError, + "This ReadableStream is disturbed (has already been read from), and cannot " "be used as a body."); } @@ -694,11 +682,8 @@ Body::ExtractedBody Body::extractBody(jsg::Lock& js, Initializer init) { auto bodyStream = kj::heap(buffer.clone(js)); - return { - jsg::alloc(IoContext::current(), kj::mv(bodyStream)), - kj::mv(buffer), - kj::mv(contentType) - }; + return {jsg::alloc(IoContext::current(), kj::mv(bodyStream)), kj::mv(buffer), + kj::mv(contentType)}; } Body::Body(kj::Maybe init, Headers& headers) @@ -715,14 +700,12 @@ Body::Body(kj::Maybe init, Headers& headers) "A FormData body was provided with a custom Content-Type header when constructing " "a Request or Response object. This will prevent the recipient of the Request or " "Response from being able to parse the body. Consider omitting the custom " - "Content-Type header." - ); + "Content-Type header."); } } return kj::mv(i.impl); })), - headersRef(headers) { -} + headersRef(headers) {} kj::Maybe Body::getBodyBuffer(jsg::Lock& js) { KJ_IF_SOME(i, impl) { @@ -771,10 +754,11 @@ bool Body::getBodyUsed() { jsg::Promise> Body::arrayBuffer(jsg::Lock& js) { KJ_IF_SOME(i, impl) { return js.evalNow([&] { - JSG_REQUIRE(!i.stream->isDisturbed(), TypeError, "Body has already been used. " + JSG_REQUIRE(!i.stream->isDisturbed(), TypeError, + "Body has already been used. " "It can only be used once. Use tee() first if you need to read it twice."); - return i.stream->getController().readAllBytes(js, - IoContext::current().getLimitEnforcer().getBufferingLimit()); + return i.stream->getController().readAllBytes( + js, IoContext::current().getLimitEnforcer().getBufferingLimit()); }); } @@ -784,15 +768,15 @@ jsg::Promise> Body::arrayBuffer(jsg::Lock& js) { } jsg::Promise Body::bytes(jsg::Lock& js) { - return arrayBuffer(js).then(js, [](jsg::Lock& js, kj::Array data) { - return js.bytes(kj::mv(data)); - }); + return arrayBuffer(js).then( + js, [](jsg::Lock& js, kj::Array data) { return js.bytes(kj::mv(data)); }); } jsg::Promise Body::text(jsg::Lock& js) { KJ_IF_SOME(i, impl) { return js.evalNow([&] { - JSG_REQUIRE(!i.stream->isDisturbed(), TypeError, "Body has already been used. " + JSG_REQUIRE(!i.stream->isDisturbed(), TypeError, + "Body has already been used. " "It can only be used once. Use tee() first if you need to read it twice."); // A common mistake is to call .text() on non-text content, e.g. because you're implementing a @@ -805,8 +789,8 @@ jsg::Promise Body::text(jsg::Lock& js) { } } - return i.stream->getController().readAllText(js, - context.getLimitEnforcer().getBufferingLimit()); + return i.stream->getController().readAllText( + js, context.getLimitEnforcer().getBufferingLimit()); }); } @@ -819,20 +803,21 @@ jsg::Promise> Body::formData(jsg::Lock& js) { auto formData = jsg::alloc(); return js.evalNow([&] { - JSG_REQUIRE(!getBodyUsed(), TypeError, "Body has already been used. " + JSG_REQUIRE(!getBodyUsed(), TypeError, + "Body has already been used. " "It can only be used once. Use tee() first if you need to read it twice."); - auto contentType = JSG_REQUIRE_NONNULL( - headersRef.get(jsg::ByteString(kj::str("Content-Type"))), + auto contentType = JSG_REQUIRE_NONNULL(headersRef.get(jsg::ByteString(kj::str("Content-Type"))), TypeError, "Parsing a Body as FormData requires a Content-Type header."); KJ_IF_SOME(i, impl) { KJ_ASSERT(!i.stream->isDisturbed()); auto& context = IoContext::current(); - return i.stream->getController().readAllText(js, - context.getLimitEnforcer().getBufferingLimit()).then(js, - [contentType = kj::mv(contentType), formData = kj::mv(formData)] - (auto& js, kj::String rawText) mutable { + return i.stream->getController() + .readAllText(js, context.getLimitEnforcer().getBufferingLimit()) + .then(js, + [contentType = kj::mv(contentType), formData = kj::mv(formData)]( + auto& js, kj::String rawText) mutable { formData->parse(js, kj::mv(rawText), contentType, !FeatureFlags::get(js).getFormDataParserSupportsFiles()); return kj::mv(formData); @@ -842,30 +827,28 @@ jsg::Promise> Body::formData(jsg::Lock& js) { // Theoretically, we already know if this will throw: the empty string is a valid // application/x-www-form-urlencoded body, but not multipart/form-data. However, best to let // FormData::parse() make the decision, to keep the logic in one place. - formData->parse(js, kj::String(), contentType, - !FeatureFlags::get(js).getFormDataParserSupportsFiles()); + formData->parse( + js, kj::String(), contentType, !FeatureFlags::get(js).getFormDataParserSupportsFiles()); return js.resolvedPromise(kj::mv(formData)); }); } jsg::Promise Body::json(jsg::Lock& js) { - return text(js).then(js, [](jsg::Lock& js, kj::String text) { - return js.parseJson(text); - }); + return text(js).then(js, [](jsg::Lock& js, kj::String text) { return js.parseJson(text); }); } jsg::Promise> Body::blob(jsg::Lock& js) { return arrayBuffer(js).then(js, [this](jsg::Lock& js, kj::Array buffer) { - kj::String contentType = - headersRef.get(jsg::ByteString(kj::str("Content-Type"))) - .map([](jsg::ByteString&& b) -> kj::String { return kj::mv(b); }) - .orDefault(nullptr); + kj::String contentType = headersRef.get(jsg::ByteString(kj::str("Content-Type"))) + .map([](jsg::ByteString&& b) -> kj::String { + return kj::mv(b); + }).orDefault(nullptr); if (FeatureFlags::get(js).getBlobStandardMimeType()) { - contentType = - MimeType::extract(contentType).map([](MimeType&& mt) -> kj::String { - return mt.toString(); - }).orDefault(nullptr); + contentType = MimeType::extract(contentType) + .map([](MimeType&& mt) -> kj::String { + return mt.toString(); + }).orDefault(nullptr); } return jsg::alloc(js, kj::mv(buffer), kj::mv(contentType)); @@ -878,10 +861,7 @@ kj::Maybe Body::clone(jsg::Lock& js) { i.stream = kj::mv(branches[0]); - return ExtractedBody { - kj::mv(branches[1]), - i.buffer.map([&](Buffer& b) { return b.clone(js); }) - }; + return ExtractedBody{kj::mv(branches[1]), i.buffer.map([&](Buffer& b) { return b.clone(js); })}; } return kj::none; @@ -890,18 +870,14 @@ kj::Maybe Body::clone(jsg::Lock& js) { // ======================================================================================= jsg::Ref Request::coerce( - jsg::Lock& js, - Request::Info input, - jsg::Optional init) { + jsg::Lock& js, Request::Info input, jsg::Optional init) { return input.is>() && init == kj::none - ? kj::mv(input.get>()) - : Request::constructor(js, kj::mv(input), kj::mv(init)); + ? kj::mv(input.get>()) + : Request::constructor(js, kj::mv(input), kj::mv(init)); } jsg::Ref Request::constructor( - jsg::Lock& js, - Request::Info input, - jsg::Optional init) { + jsg::Lock& js, Request::Info input, jsg::Optional init) { kj::String url; kj::HttpMethod method = kj::HttpMethod::GET; kj::Maybe> headers; @@ -926,8 +902,8 @@ jsg::Ref Request::constructor( // the rest of the implementation. Fortunately the standard parser is fast // but it would eventually be nice to eliminate the double parsing. if (FeatureFlags::get(js).getFetchStandardUrl()) { - auto parsed = JSG_REQUIRE_NONNULL(jsg::Url::tryParse(url.asPtr()), TypeError, - kj::str("Invalid URL: ", url)); + auto parsed = JSG_REQUIRE_NONNULL( + jsg::Url::tryParse(url.asPtr()), TypeError, kj::str("Invalid URL: ", url)); url = kj::str(parsed.getHref()); } } @@ -963,8 +939,8 @@ jsg::Ref Request::constructor( headers = jsg::alloc(*oldRequest->headers); cf = oldRequest->cf.deepClone(js); if (!ignoreInputBody) { - JSG_REQUIRE(!oldRequest->getBodyUsed(), - TypeError, "Cannot reconstruct a Request with a used body."); + JSG_REQUIRE(!oldRequest->getBodyUsed(), TypeError, + "Cannot reconstruct a Request with a used body."); KJ_IF_SOME(oldJsBody, oldRequest->getBody()) { // The stream spec says to "create a proxy" for the passed in readable, which it // defines generically as creating a TransformStream and using pipeThrough to pass @@ -997,7 +973,7 @@ jsg::Ref Request::constructor( } else { KJ_IF_SOME(code, kj::tryParseHttpMethod(toUpper(kj::mv(m)))) { method = code; - switch(method) { + switch (method) { case kj::HttpMethod::GET: case kj::HttpMethod::POST: case kj::HttpMethod::PUT: @@ -1006,10 +982,11 @@ jsg::Ref Request::constructor( case kj::HttpMethod::OPTIONS: break; default: - JSG_FAIL_REQUIRE(TypeError, kj::str("Invalid HTTP method string: ", originalMethod)); + JSG_FAIL_REQUIRE( + TypeError, kj::str("Invalid HTTP method string: ", originalMethod)); } } else { - JSG_FAIL_REQUIRE(TypeError, kj::str("Invalid HTTP method string: ", originalMethod)); + JSG_FAIL_REQUIRE(TypeError, kj::str("Invalid HTTP method string: ", originalMethod)); } } } @@ -1040,8 +1017,8 @@ jsg::Ref Request::constructor( KJ_IF_SOME(b, kj::mv(initDict.body).orDefault(kj::none)) { body = Body::extractBody(js, kj::mv(b)); - JSG_REQUIRE(method != kj::HttpMethod::GET && method != kj::HttpMethod::HEAD, - TypeError, "Request with a GET or HEAD method cannot have a body."); + JSG_REQUIRE(method != kj::HttpMethod::GET && method != kj::HttpMethod::HEAD, TypeError, + "Request with a GET or HEAD method cannot have a body."); } KJ_IF_SOME(r, initDict.redirect) { @@ -1057,8 +1034,8 @@ jsg::Ref Request::constructor( // of these fields was modified, but the original Request object that we're rewriting // already represented a GET/HEAD method with a body, we allow that to pass through. // We support proxying such requests and rewriting their URL/headers/etc.) - JSG_REQUIRE((method != kj::HttpMethod::GET && method != kj::HttpMethod::HEAD) - || body == kj::none, + JSG_REQUIRE( + (method != kj::HttpMethod::GET && method != kj::HttpMethod::HEAD) || body == kj::none, TypeError, "Request with a GET or HEAD method cannot have a body."); } } @@ -1084,9 +1061,8 @@ jsg::Ref Request::constructor( } // TODO(conform): If `init` has a keepalive flag, pass it to the Body constructor. - return jsg::alloc(method, url, redirect, - KJ_ASSERT_NONNULL(kj::mv(headers)), kj::mv(fetcher), kj::mv(signal), - kj::mv(cf), kj::mv(body)); + return jsg::alloc(method, url, redirect, KJ_ASSERT_NONNULL(kj::mv(headers)), + kj::mv(fetcher), kj::mv(signal), kj::mv(cf), kj::mv(body)); } jsg::Ref Request::clone(jsg::Lock& js) { @@ -1095,8 +1071,7 @@ jsg::Ref Request::clone(jsg::Lock& js) { auto cfClone = cf.deepClone(js); auto bodyClone = Body::clone(js); - return jsg::alloc( - method, url, redirect, kj::mv(headersClone), getFetcher(), getSignal(), + return jsg::alloc(method, url, redirect, kj::mv(headersClone), getFetcher(), getSignal(), kj::mv(cfClone), kj::mv(bodyClone)); } @@ -1114,17 +1089,19 @@ kj::StringPtr Request::getRedirect() { // factored out. switch (redirect) { - case Redirect::FOLLOW: return "follow"; - case Redirect::MANUAL: return "manual"; + case Redirect::FOLLOW: + return "follow"; + case Redirect::MANUAL: + return "manual"; } KJ_UNREACHABLE; } kj::Maybe> Request::getFetcher() { - return fetcher.map([](jsg::Ref& f) {return f.addRef();}); + return fetcher.map([](jsg::Ref& f) { return f.addRef(); }); } kj::Maybe> Request::getSignal() { - return signal.map([](jsg::Ref& s) {return s.addRef();}); + return signal.map([](jsg::Ref& s) { return s.addRef(); }); } jsg::Optional Request::getCf(jsg::Lock& js) { @@ -1169,58 +1146,60 @@ kj::Maybe Request::serializeCfBlobJson(jsg::Lock& js) { return cf.serialize(js); } -void Request::serialize( - jsg::Lock& js, jsg::Serializer& serializer, +void Request::serialize(jsg::Lock& js, + jsg::Serializer& serializer, const jsg::TypeHandler& initDictHandler) { serializer.writeLengthDelimited(url); // Our strategy is to construct an initializer dict object and serialize that as a JS object. // This makes the deserialization end really simple (just call the constructor), and it also // gives us extensibility: we can add new fields without having to bump the serialization tag. - serializer.write(js, jsg::JsValue(initDictHandler.wrap(js, RequestInitializerDict { - // GET is the default, so only serialize the method if it's something else. - .method = method == kj::HttpMethod::GET ? jsg::Optional() : kj::str(method), - - .headers = headers.addRef(), - - .body = getBody().map([](jsg::Ref stream) -> Body::Initializer { - // jsg::Ref is one of the possible variants of Body::Initializer. - return kj::mv(stream); - }), - - // "manual" is the default for `redirect`, so only encode if it's not that. - .redirect = redirect == Redirect::MANUAL - ? kj::str(getRedirect()) : kj::Maybe(kj::none), - - // We have to ignore .fetcher for serialization. We can't simply fail if a fetcher is present - // because requests received by the top-level fetch handler actually have .fetcher set to - // the hidden "next" binding, which historically could be different from null (although in - // practice these days it is always the same). We obviously want to be able to serialize - // requests received by the top-level fetch handler so... we have to ignore this. This - // property should probably go away in any case. - - .cf = cf.getRef(js), - - // .mode is unimplemented - // .credentials is unimplemented - // .cache is unimplemented - // .referrer is unimplemented - // .referrerPolicy is unimplemented - // .integrity is required to be empty - - // If an AbortSignal is present, we'll try to serialize it. As of this writing, AbortSignal - // is not serializable, but we could add support for sending it over RPC in the future. - // - // Note we have to double-Maybe this, so that if no signal is present, the property is absent - // instead of `null`. - .signal = signal.map([](jsg::Ref& s) -> kj::Maybe> { - return s.addRef(); - }) - }))); + serializer.write(js, + jsg::JsValue(initDictHandler.wrap(js, + RequestInitializerDict{ + // GET is the default, so only serialize the method if it's something else. + .method = method == kj::HttpMethod::GET ? jsg::Optional() : kj::str(method), + + .headers = headers.addRef(), + + .body = getBody().map([](jsg::Ref stream) -> Body::Initializer { + // jsg::Ref is one of the possible variants of Body::Initializer. + return kj::mv(stream); + }), + + // "manual" is the default for `redirect`, so only encode if it's not that. + .redirect = redirect == Redirect::MANUAL ? kj::str(getRedirect()) + : kj::Maybe(kj::none), + + // We have to ignore .fetcher for serialization. We can't simply fail if a fetcher is present + // because requests received by the top-level fetch handler actually have .fetcher set to + // the hidden "next" binding, which historically could be different from null (although in + // practice these days it is always the same). We obviously want to be able to serialize + // requests received by the top-level fetch handler so... we have to ignore this. This + // property should probably go away in any case. + + .cf = cf.getRef(js), + + // .mode is unimplemented + // .credentials is unimplemented + // .cache is unimplemented + // .referrer is unimplemented + // .referrerPolicy is unimplemented + // .integrity is required to be empty + + // If an AbortSignal is present, we'll try to serialize it. As of this writing, AbortSignal + // is not serializable, but we could add support for sending it over RPC in the future. + // + // Note we have to double-Maybe this, so that if no signal is present, the property is absent + // instead of `null`. + .signal = signal.map([](jsg::Ref& s) -> kj::Maybe> { + return s.addRef(); + })}))); } -jsg::Ref Request::deserialize( - jsg::Lock& js, rpc::SerializationTag tag, jsg::Deserializer& deserializer, +jsg::Ref Request::deserialize(jsg::Lock& js, + rpc::SerializationTag tag, + jsg::Deserializer& deserializer, const jsg::TypeHandler& initDictHandler) { auto url = deserializer.readLengthDelimitedString(); auto init = KJ_ASSERT_NONNULL(initDictHandler.tryUnwrap(js, deserializer.readValue(js))); @@ -1229,12 +1208,15 @@ jsg::Ref Request::deserialize( // ======================================================================================= -Response::Response( - jsg::Lock& js, int statusCode, kj::String statusText, jsg::Ref headers, - CfProperty&& cf, kj::Maybe body, - kj::Array urlList, - kj::Maybe> webSocket, - Response::BodyEncoding bodyEncoding) +Response::Response(jsg::Lock& js, + int statusCode, + kj::String statusText, + jsg::Ref headers, + CfProperty&& cf, + kj::Maybe body, + kj::Array urlList, + kj::Maybe> webSocket, + Response::BodyEncoding bodyEncoding) : Body(kj::mv(body), *headers), statusCode(statusCode), statusText(kj::mv(statusText)), @@ -1249,8 +1231,7 @@ Response::Response( // Defined later in this file. static kj::StringPtr defaultStatusText(uint statusCode); -jsg::Ref Response::constructor( - jsg::Lock& js, +jsg::Ref Response::constructor(jsg::Lock& js, jsg::Optional> optionalBodyInit, jsg::Optional maybeInit) { auto bodyInit = kj::mv(optionalBodyInit).orDefault(kj::none); @@ -1322,8 +1303,8 @@ jsg::Ref Response::constructor( JSG_REQUIRE(statusCode >= 200 && statusCode <= 599, RangeError, "Responses may only be constructed with status codes in the range 200 to 599, inclusive."); } else { - JSG_REQUIRE(statusCode == 101, RangeError, - "Responses with a WebSocket must have status code 101."); + JSG_REQUIRE( + statusCode == 101, RangeError, "Responses with a WebSocket must have status code 101."); } KJ_IF_SOME(s, statusText) { @@ -1359,11 +1340,12 @@ jsg::Ref Response::constructor( auto& context = IoContext::current(); if (context.isInspectorEnabled()) { - context.logWarning(kj::str( - "Constructing a Response with a null body status (", statusCode, ") and a non-null, " + context.logWarning(kj::str("Constructing a Response with a null body status (", statusCode, + ") and a non-null, " "zero-length body. This is technically incorrect, and we recommend you update your " "code to explicitly pass in a `null` body, e.g. `new Response(null, { status: ", - statusCode, ", ... })`. (We continue to allow the zero-length body behavior because it " + statusCode, + ", ... })`. (We continue to allow the zero-length body behavior because it " "was previously the only way to construct a Response with a null body status. This " "behavior may change in the future.)")); } @@ -1374,27 +1356,27 @@ jsg::Ref Response::constructor( } return jsg::alloc(js, statusCode, KJ_ASSERT_NONNULL(kj::mv(statusText)), - kj::mv(headers), kj::mv(cf), kj::mv(body), nullptr, - kj::mv(webSocket), bodyEncoding); + kj::mv(headers), kj::mv(cf), kj::mv(body), nullptr, kj::mv(webSocket), bodyEncoding); } jsg::Ref Response::redirect(jsg::Lock& js, kj::String url, jsg::Optional status) { auto statusCode = status.orDefault(302); if (!isRedirectStatusCode(statusCode)) { JSG_FAIL_REQUIRE(RangeError, - kj::str(statusCode, " is not a redirect status code. " - "It must be one of: 301, 302, 303, 307, or 308.")); + kj::str(statusCode, + " is not a redirect status code. " + "It must be one of: 301, 302, 303, 307, or 308.")); } // TODO(conform): The URL is supposed to be parsed relative to the "current setting's object's API // base URL". kj::String parsedUrl = nullptr; if (FeatureFlags::get(js).getSpecCompliantResponseRedirect()) { - auto parsed = JSG_REQUIRE_NONNULL(jsg::Url::tryParse(url.asPtr()), TypeError, - "Unable to parse URL: ", url); + auto parsed = JSG_REQUIRE_NONNULL( + jsg::Url::tryParse(url.asPtr()), TypeError, "Unable to parse URL: ", url); parsedUrl = kj::str(parsed.getHref()); } else { - auto urlOptions = kj::Url::Options { .percentDecode = false, .allowEmpty = true }; + auto urlOptions = kj::Url::Options{.percentDecode = false, .allowEmpty = true}; auto maybeParsedUrl = kj::Url::tryParse(kj::str(url), kj::Url::REMOTE_HREF, urlOptions); if (maybeParsedUrl == kj::none) { JSG_FAIL_REQUIRE(TypeError, kj::str("Unable to parse URL: ", url)); @@ -1403,8 +1385,8 @@ jsg::Ref Response::redirect(jsg::Lock& js, kj::String url, jsg::Option } if (!kj::HttpHeaders::isValidHeaderValue(parsedUrl)) { - JSG_FAIL_REQUIRE(TypeError, kj::str("Redirect URL cannot contain '\\r', '\\n', or '\\0': ", - url)); + JSG_FAIL_REQUIRE( + TypeError, kj::str("Redirect URL cannot contain '\\r', '\\n', or '\\0': ", url)); } // Build our headers object with `Location` set to the parsed URL. @@ -1414,20 +1396,17 @@ jsg::Ref Response::redirect(jsg::Lock& js, kj::String url, jsg::Option auto statusText = defaultStatusText(statusCode); - return jsg::alloc(js, statusCode, kj::str(statusText), kj::mv(headers), nullptr, - nullptr); + return jsg::alloc( + js, statusCode, kj::str(statusText), kj::mv(headers), nullptr, nullptr); } jsg::Ref Response::json_( - jsg::Lock& js, - jsg::JsValue any, - jsg::Optional maybeInit) { + jsg::Lock& js, jsg::JsValue any, jsg::Optional maybeInit) { const auto maybeSetContentType = [](auto headers) { if (!headers->hasLowerCase("content-type"_kj)) { headers->set( - jsg::ByteString(kj::str("content-type")), - jsg::ByteString(MimeType::JSON.toString())); + jsg::ByteString(kj::str("content-type")), jsg::ByteString(MimeType::JSON.toString())); } return kj::mv(headers); }; @@ -1451,13 +1430,13 @@ jsg::Ref Response::json_( } } KJ_CASE_ONEOF(res, jsg::Ref) { - auto newInit = InitializerDict { + auto newInit = InitializerDict{ .status = res->statusCode, .statusText = kj::str(res->statusText), .headers = maybeSetContentType(Headers::constructor(js, res->headers.addRef())), .cf = res->cf.getRef(js), - .encodeBody = kj::str(res->bodyEncoding == Response::BodyEncoding::MANUAL - ? "manual" : "automatic"), + .encodeBody = + kj::str(res->bodyEncoding == Response::BodyEncoding::MANUAL ? "manual" : "automatic"), }; KJ_IF_SOME(otherWs, res->webSocket) { @@ -1468,7 +1447,7 @@ jsg::Ref Response::json_( } } } else { - maybeInit = InitializerDict { + maybeInit = InitializerDict{ .headers = maybeSetContentType(jsg::alloc()), }; } @@ -1477,8 +1456,8 @@ jsg::Ref Response::json_( } jsg::Ref Response::clone(jsg::Lock& js) { - JSG_REQUIRE(webSocket == kj::none, - TypeError, "Cannot clone a response to a WebSocket handshake."); + JSG_REQUIRE( + webSocket == kj::none, TypeError, "Cannot clone a response to a WebSocket handshake."); auto headersClone = headers->clone(); auto cfClone = cf.deepClone(js); @@ -1487,15 +1466,16 @@ jsg::Ref Response::clone(jsg::Lock& js) { auto urlListClone = KJ_MAP(url, urlList) { return kj::str(url); }; - return jsg::alloc( - js, statusCode, kj::str(statusText), kj::mv(headersClone), kj::mv(cfClone), kj::mv(bodyClone), - kj::mv(urlListClone)); + return jsg::alloc(js, statusCode, kj::str(statusText), kj::mv(headersClone), + kj::mv(cfClone), kj::mv(bodyClone), kj::mv(urlListClone)); } -kj::Promise> Response::send( - jsg::Lock& js, kj::HttpService::Response& outer, SendOptions options, +kj::Promise> Response::send(jsg::Lock& js, + kj::HttpService::Response& outer, + SendOptions options, kj::Maybe maybeReqHeaders) { - JSG_REQUIRE(!getBodyUsed(), TypeError, "Body has already been used. " + JSG_REQUIRE(!getBodyUsed(), TypeError, + "Body has already been used. " "It can only be used once. Use tee() first if you need to read it twice."); // Careful: Keep in mind that the promise we return could be canceled in which case `outer` will @@ -1517,8 +1497,7 @@ kj::Promise> Response::send( // returning a 4xx status code. A 426 status code error _might_ be more appropriate if the // request headers originate from outside the worker developer's control (e.g. a client // application by some other party). - JSG_REQUIRE( - options.allowWebSocket, TypeError, + JSG_REQUIRE(options.allowWebSocket, TypeError, "Worker tried to return a WebSocket in a response to a request " "which did not contain the header \"Upgrade: websocket\"."); @@ -1564,9 +1543,8 @@ kj::Promise> Response::send( } else KJ_IF_SOME(jsBody, getBody()) { auto encoding = getContentEncoding(context, outHeaders, bodyEncoding, FeatureFlags::get(js)); auto maybeLength = jsBody->tryGetLength(encoding); - auto stream = newSystemStream( - outer.send(statusCode, statusText, outHeaders, maybeLength), - encoding); + auto stream = + newSystemStream(outer.send(statusCode, statusText, outHeaders, maybeLength), encoding); // We need to enter the AsyncContextFrame that was captured when the // Response was created before starting the loop. jsg::AsyncContextFrame::Scope scope(js, asyncContext); @@ -1606,45 +1584,47 @@ kj::StringPtr Response::getUrl() { } kj::Maybe> Response::getWebSocket(jsg::Lock& js) { - return webSocket.map([&](jsg::Ref& ptr) { - return ptr.addRef(); - }); + return webSocket.map([&](jsg::Ref& ptr) { return ptr.addRef(); }); } jsg::Optional Response::getCf(jsg::Lock& js) { return cf.get(js); } -void Response::serialize( - jsg::Lock& js, jsg::Serializer& serializer, +void Response::serialize(jsg::Lock& js, + jsg::Serializer& serializer, const jsg::TypeHandler& initDictHandler, const jsg::TypeHandler>>& streamHandler) { serializer.write(js, jsg::JsValue(streamHandler.wrap(js, getBody()))); // As with Request, we serialize the initializer dict as a JS object. - serializer.write(js, jsg::JsValue(initDictHandler.wrap(js, InitializerDict { - .status = statusCode == 200 ? jsg::Optional() : statusCode, - .statusText = statusText == defaultStatusText(statusCode) - ? jsg::Optional() : kj::str(statusText), - .headers = headers.addRef(), - .cf = cf.getRef(js), - - // If a WebSocket is present, we'll try to serialize it. As of this writing, WebSocket - // is not serializable, but we could add support for sending it over RPC in the future. - // - // Note we have to double-Maybe this, so that if no signal is present, the property is absent - // instead of `null`. - .webSocket = webSocket.map([](jsg::Ref& s) -> kj::Maybe> { - return s.addRef(); - }), + serializer.write(js, + jsg::JsValue(initDictHandler.wrap(js, + InitializerDict{ + .status = statusCode == 200 ? jsg::Optional() : statusCode, + .statusText = statusText == defaultStatusText(statusCode) ? jsg::Optional() + : kj::str(statusText), + .headers = headers.addRef(), + .cf = cf.getRef(js), + + // If a WebSocket is present, we'll try to serialize it. As of this writing, WebSocket + // is not serializable, but we could add support for sending it over RPC in the future. + // + // Note we have to double-Maybe this, so that if no signal is present, the property is absent + // instead of `null`. + .webSocket = + webSocket.map([](jsg::Ref& s) -> kj::Maybe> { + return s.addRef(); + }), - .encodeBody = bodyEncoding == BodyEncoding::AUTO - ? jsg::Optional() : kj::str("manual"), - }))); + .encodeBody = bodyEncoding == BodyEncoding::AUTO ? jsg::Optional() + : kj::str("manual"), + }))); } -jsg::Ref Response::deserialize( - jsg::Lock& js, rpc::SerializationTag tag, jsg::Deserializer& deserializer, +jsg::Ref Response::deserialize(jsg::Lock& js, + rpc::SerializationTag tag, + jsg::Deserializer& deserializer, const jsg::TypeHandler& initDictHandler, const jsg::TypeHandler>>& streamHandler) { auto body = KJ_ASSERT_NONNULL(streamHandler.tryUnwrap(js, deserializer.readValue(js))); @@ -1690,7 +1670,7 @@ void FetchEvent::respondWith(jsg::Lock& js, jsg::Promise> pro KJ_SWITCH_ONEOF(state) { KJ_CASE_ONEOF(_, AwaitingRespondWith) { - state = RespondWithCalled { kj::mv(promise) }; + state = RespondWithCalled{kj::mv(promise)}; } KJ_CASE_ONEOF(called, RespondWithCalled) { JSG_FAIL_REQUIRE(DOMInvalidStateError, @@ -1728,29 +1708,30 @@ kj::String uriEncodeControlChars(kj::ArrayPtr bytes) { result.add(b); } else { result.add('%'); - result.add(HEX_DIGITS_URI[b/16]); - result.add(HEX_DIGITS_URI[b%16]); + result.add(HEX_DIGITS_URI[b / 16]); + result.add(HEX_DIGITS_URI[b % 16]); } } result.add('\0'); return kj::String(result.releaseAsArray()); } -jsg::Promise> handleHttpResponse( - jsg::Lock& js, +jsg::Promise> handleHttpResponse(jsg::Lock& js, jsg::Ref fetcher, - jsg::Ref jsRequest, kj::Vector urlList, + jsg::Ref jsRequest, + kj::Vector urlList, kj::HttpClient::Response&& response); -jsg::Promise> handleHttpRedirectResponse( - jsg::Lock& js, +jsg::Promise> handleHttpRedirectResponse(jsg::Lock& js, jsg::Ref fetcher, - jsg::Ref jsRequest, kj::Vector urlList, - uint status, kj::StringPtr location); + jsg::Ref jsRequest, + kj::Vector urlList, + uint status, + kj::StringPtr location); -jsg::Promise> fetchImplNoOutputLock( - jsg::Lock& js, +jsg::Promise> fetchImplNoOutputLock(jsg::Lock& js, jsg::Ref fetcher, - jsg::Ref jsRequest, kj::Vector urlList) { + jsg::Ref jsRequest, + kj::Vector urlList) { KJ_ASSERT(!urlList.empty()); auto& ioContext = IoContext::current(); @@ -1765,14 +1746,14 @@ jsg::Promise> fetchImplNoOutputLock( // TODO(cleanup): Don't convert to HttpClient. Use the HttpService interface instead. This // requires a significant rewrite of the code below. It'll probably get simpler, though? - kj::Own client = asHttpClient(fetcher->getClient( - ioContext, jsRequest->serializeCfBlobJson(js), "fetch"_kjc)); + kj::Own client = + asHttpClient(fetcher->getClient(ioContext, jsRequest->serializeCfBlobJson(js), "fetch"_kjc)); kj::HttpHeaders headers(ioContext.getHeaderTable()); jsRequest->shallowCopyHeadersTo(headers); - kj::String url = uriEncodeControlChars( - urlList.back().toString(kj::Url::HTTP_PROXY_REQUEST).asBytes()); + kj::String url = + uriEncodeControlChars(urlList.back().toString(kj::Url::HTTP_PROXY_REQUEST).asBytes()); if (headers.isWebSocket()) { if (!FeatureFlags::get(js).getWebSocketCompression()) { @@ -1781,18 +1762,16 @@ jsg::Promise> fetchImplNoOutputLock( headers.unset(kj::HttpHeaderId::SEC_WEBSOCKET_EXTENSIONS); } auto webSocketResponse = client->openWebSocket(url, headers); - return ioContext.awaitIo(js, - AbortSignal::maybeCancelWrap(signal, kj::mv(webSocketResponse)), - [fetcher = kj::mv(fetcher), jsRequest = kj::mv(jsRequest), - urlList = kj::mv(urlList), client = kj::mv(client), signal = kj::mv(signal)] - (jsg::Lock& js, kj::HttpClient::WebSocketResponse&& response) mutable - -> jsg::Promise> { + return ioContext.awaitIo(js, AbortSignal::maybeCancelWrap(signal, kj::mv(webSocketResponse)), + [fetcher = kj::mv(fetcher), jsRequest = kj::mv(jsRequest), urlList = kj::mv(urlList), + client = kj::mv(client), signal = kj::mv(signal)]( + jsg::Lock& js, kj::HttpClient::WebSocketResponse&& response) mutable + -> jsg::Promise> { KJ_SWITCH_ONEOF(response.webSocketOrBody) { KJ_CASE_ONEOF(body, kj::Own) { body = body.attach(kj::mv(client)); - return handleHttpResponse( - js, kj::mv(fetcher), kj::mv(jsRequest), kj::mv(urlList), - { response.statusCode, response.statusText, response.headers, kj::mv(body) }); + return handleHttpResponse(js, kj::mv(fetcher), kj::mv(jsRequest), kj::mv(urlList), + {response.statusCode, response.statusText, response.headers, kj::mv(body)}); } KJ_CASE_ONEOF(webSocket, kj::Own) { KJ_ASSERT(response.statusCode == 101); @@ -1804,13 +1783,10 @@ jsg::Promise> fetchImplNoOutputLock( } webSocket = kj::refcounted(kj::mv(webSocket), s->getCanceler()); } - return js.resolvedPromise(makeHttpResponse(js, - jsRequest->getMethodEnum(), kj::mv(urlList), - response.statusCode, response.statusText, *response.headers, - newNullInputStream(), - jsg::alloc(kj::mv(webSocket)), - Response::BodyEncoding::AUTO, - kj::mv(signal))); + return js.resolvedPromise(makeHttpResponse(js, jsRequest->getMethodEnum(), + kj::mv(urlList), response.statusCode, response.statusText, *response.headers, + newNullInputStream(), jsg::alloc(kj::mv(webSocket)), + Response::BodyEncoding::AUTO, kj::mv(signal))); } } KJ_UNREACHABLE; @@ -1844,8 +1820,8 @@ jsg::Promise> fetchImplNoOutputLock( // jsBody is not used directly within the function but is passed in so that // the coroutine frame keeps it alive. - static constexpr auto handleCancelablePump = - [](kj::Promise promise, auto jsBody) -> kj::Promise { + static constexpr auto handleCancelablePump = [](kj::Promise promise, + auto jsBody) -> kj::Promise { try { co_await promise; } catch (...) { @@ -1861,9 +1837,8 @@ jsg::Promise> fetchImplNoOutputLock( // TODO(someday): Allow deferred proxying for bidirectional streaming. ioContext.addWaitUntil(handleCancelablePump( - AbortSignal::maybeCancelWrap(signal, - ioContext.waitForDeferredProxy( - jsBody->pumpTo(js, kj::mv(stream), true))), + AbortSignal::maybeCancelWrap( + signal, ioContext.waitForDeferredProxy(jsBody->pumpTo(js, kj::mv(stream), true))), jsBody.addRef())); } else { nativeRequest = client->request(jsRequest->getMethodEnum(), url, headers, uint64_t(0)); @@ -1871,17 +1846,16 @@ jsg::Promise> fetchImplNoOutputLock( return ioContext.awaitIo(js, AbortSignal::maybeCancelWrap(signal, kj::mv(KJ_ASSERT_NONNULL(nativeRequest).response)) .catch_([](kj::Exception&& exception) -> kj::Promise { - if (exception.getDescription().startsWith("invalid Content-Length header value")) { - return JSG_KJ_EXCEPTION(FAILED, Error, exception.getDescription()); - } else if (exception.getDescription().contains("NOSENTRY script not found")) { - return JSG_KJ_EXCEPTION(FAILED, Error, "Worker not found."); - } - return kj::mv(exception); - }), - [fetcher = kj::mv(fetcher), jsRequest = kj::mv(jsRequest), - urlList = kj::mv(urlList), client = kj::mv(client)] - (jsg::Lock& js, kj::HttpClient::Response&& response) mutable - -> jsg::Promise> { + if (exception.getDescription().startsWith("invalid Content-Length header value")) { + return JSG_KJ_EXCEPTION(FAILED, Error, exception.getDescription()); + } else if (exception.getDescription().contains("NOSENTRY script not found")) { + return JSG_KJ_EXCEPTION(FAILED, Error, "Worker not found."); + } + return kj::mv(exception); + }), + [fetcher = kj::mv(fetcher), jsRequest = kj::mv(jsRequest), urlList = kj::mv(urlList), + client = kj::mv(client)](jsg::Lock& js, + kj::HttpClient::Response&& response) mutable -> jsg::Promise> { response.body = response.body.attach(kj::mv(client)); return handleHttpResponse( js, kj::mv(fetcher), kj::mv(jsRequest), kj::mv(urlList), kj::mv(response)); @@ -1889,17 +1863,17 @@ jsg::Promise> fetchImplNoOutputLock( } } -jsg::Promise> fetchImpl( - jsg::Lock& js, +jsg::Promise> fetchImpl(jsg::Lock& js, jsg::Ref fetcher, - jsg::Ref jsRequest, kj::Vector urlList) { + jsg::Ref jsRequest, + kj::Vector urlList) { auto& context = IoContext::current(); // Optimization: For non-actors, which never have output locks, avoid the overhead of // awaitIo() and such by not going back to the event loop at all. KJ_IF_SOME(promise, context.waitForOutputLocksIfNecessary()) { return context.awaitIo(js, kj::mv(promise), - [fetcher = kj::mv(fetcher), jsRequest = kj::mv(jsRequest), - urlList = kj::mv(urlList)](jsg::Lock& js) mutable { + [fetcher = kj::mv(fetcher), jsRequest = kj::mv(jsRequest), urlList = kj::mv(urlList)]( + jsg::Lock& js) mutable { return fetchImplNoOutputLock(js, kj::mv(fetcher), kj::mv(jsRequest), kj::mv(urlList)); }); } else { @@ -1907,10 +1881,10 @@ jsg::Promise> fetchImpl( } } -jsg::Promise> handleHttpResponse( - jsg::Lock& js, +jsg::Promise> handleHttpResponse(jsg::Lock& js, jsg::Ref fetcher, - jsg::Ref jsRequest, kj::Vector urlList, + jsg::Ref jsRequest, + kj::Vector urlList, kj::HttpClient::Response&& response) { auto signal = jsRequest->getSignal(); @@ -1919,12 +1893,11 @@ jsg::Promise> handleHttpResponse( if ((s)->getAborted()) { return js.rejectedPromise>((s)->getReason(js)); } - response.body = - kj::refcounted(kj::mv(response.body), s->getCanceler()); + response.body = kj::refcounted(kj::mv(response.body), s->getCanceler()); } - if (isRedirectStatusCode(response.statusCode) - && jsRequest->getRedirectEnum() == Request::Redirect::FOLLOW) { + if (isRedirectStatusCode(response.statusCode) && + jsRequest->getRedirectEnum() == Request::Redirect::FOLLOW) { KJ_IF_SOME(l, response.headers->get(kj::HttpHeaderId::LOCATION)) { return handleHttpRedirectResponse( js, kj::mv(fetcher), kj::mv(jsRequest), kj::mv(urlList), response.statusCode, l); @@ -1935,18 +1908,18 @@ jsg::Promise> handleHttpResponse( } auto result = makeHttpResponse(js, jsRequest->getMethodEnum(), kj::mv(urlList), - response.statusCode, response.statusText, *response.headers, - kj::mv(response.body), kj::none, Response::BodyEncoding::AUTO, - kj::mv(signal)); + response.statusCode, response.statusText, *response.headers, kj::mv(response.body), kj::none, + Response::BodyEncoding::AUTO, kj::mv(signal)); return js.resolvedPromise(kj::mv(result)); } -jsg::Promise> handleHttpRedirectResponse( - jsg::Lock& js, +jsg::Promise> handleHttpRedirectResponse(jsg::Lock& js, jsg::Ref fetcher, - jsg::Ref jsRequest, kj::Vector urlList, - uint status, kj::StringPtr location) { + jsg::Ref jsRequest, + kj::Vector urlList, + uint status, + kj::StringPtr location) { // Reconstruct the request body stream for retransmission in the face of a redirect. Before // reconstructing the stream, however, this function: // @@ -1967,10 +1940,11 @@ jsg::Promise> handleHttpRedirectResponse( auto base = urlList.back().toString(); KJ_IF_SOME(parsed, jsg::Url::tryParse(location, base.asPtr())) { auto str = kj::str(parsed.getHref()); - return kj::Url::tryParse(str.asPtr(), kj::Url::Context::REMOTE_HREF, kj::Url::Options { - .percentDecode = false, - .allowEmpty = true, - }); + return kj::Url::tryParse(str.asPtr(), kj::Url::Context::REMOTE_HREF, + kj::Url::Options{ + .percentDecode = false, + .allowEmpty = true, + }); } else { return kj::none; } @@ -1980,8 +1954,8 @@ jsg::Promise> handleHttpRedirectResponse( })(); if (redirectedLocation == kj::none) { - auto exception = JSG_KJ_EXCEPTION(FAILED, TypeError, - "Invalid Location header; unable to follow redirect."); + auto exception = + JSG_KJ_EXCEPTION(FAILED, TypeError, "Invalid Location header; unable to follow redirect."); return js.rejectedPromise>(kj::mv(exception)); } @@ -2045,10 +2019,14 @@ jsg::Promise> handleHttpRedirectResponse( } // namespace -jsg::Ref makeHttpResponse( - jsg::Lock& js, kj::HttpMethod method, kj::Vector urlListParam, - uint statusCode, kj::StringPtr statusText, const kj::HttpHeaders& headers, - kj::Own body, kj::Maybe> webSocket, +jsg::Ref makeHttpResponse(jsg::Lock& js, + kj::HttpMethod method, + kj::Vector urlListParam, + uint statusCode, + kj::StringPtr statusText, + const kj::HttpHeaders& headers, + kj::Own body, + kj::Maybe> webSocket, Response::BodyEncoding bodyEncoding, kj::Maybe> signal) { auto responseHeaders = jsg::alloc(headers, Headers::Guard::RESPONSE); @@ -2064,8 +2042,7 @@ jsg::Ref makeHttpResponse( if (method != kj::HttpMethod::HEAD && !isNullBodyStatusCode(statusCode)) { responseBody = Body::ExtractedBody(jsg::alloc(context, newSystemStream(kj::mv(body), - getContentEncoding(context, headers, bodyEncoding, - FeatureFlags::get(js))))); + getContentEncoding(context, headers, bodyEncoding, FeatureFlags::get(js))))); } // The Fetch spec defines "response URLs" as having no fragments. Since the last URL in the list @@ -2077,15 +2054,13 @@ jsg::Ref makeHttpResponse( } // TODO(someday): Fill response CF blob from somewhere? - return jsg::alloc( - js, statusCode, kj::str(statusText), kj::mv(responseHeaders), - nullptr, kj::mv(responseBody), kj::mv(urlList), kj::mv(webSocket)); + return jsg::alloc(js, statusCode, kj::str(statusText), kj::mv(responseHeaders), nullptr, + kj::mv(responseBody), kj::mv(urlList), kj::mv(webSocket)); } namespace { -jsg::Promise> fetchImplNoOutputLock( - jsg::Lock& js, +jsg::Promise> fetchImplNoOutputLock(jsg::Lock& js, kj::Maybe> fetcher, Request::Info requestOrUrl, jsg::Optional requestInit) { @@ -2126,13 +2101,13 @@ jsg::Promise> fetchImplNoOutputLock( auto data = dataUrl.releaseData(); auto headers = jsg::alloc(); headers->set(jsg::ByteString(kj::str("content-type")), - jsg::ByteString(dataUrl.getMimeType().toString())); + jsg::ByteString(dataUrl.getMimeType().toString())); return js.resolvedPromise(Response::constructor(js, kj::Maybe(kj::mv(data)), - Response::InitializerDict { - .status = 200, - .statusText = kj::str("OK"), - .headers = kj::mv(headers), - })); + Response::InitializerDict{ + .status = 200, + .statusText = kj::str("OK"), + .headers = kj::mv(headers), + })); } urlList.add(actualFetcher->parseUrl(js, jsRequest->getUrl())); @@ -2140,10 +2115,9 @@ jsg::Promise> fetchImplNoOutputLock( }); } -} // namespace +} // namespace -jsg::Promise> fetchImpl( - jsg::Lock& js, +jsg::Promise> fetchImpl(jsg::Lock& js, kj::Maybe> fetcher, Request::Info requestOrUrl, jsg::Optional requestInit) { @@ -2153,7 +2127,7 @@ jsg::Promise> fetchImpl( KJ_IF_SOME(promise, context.waitForOutputLocksIfNecessary()) { return context.awaitIo(js, kj::mv(promise), [fetcher = kj::mv(fetcher), requestOrUrl = kj::mv(requestOrUrl), - requestInit = kj::mv(requestInit)](jsg::Lock& js) mutable { + requestInit = kj::mv(requestInit)](jsg::Lock& js) mutable { return fetchImplNoOutputLock(js, kj::mv(fetcher), kj::mv(requestOrUrl), kj::mv(requestInit)); }); } else { @@ -2166,8 +2140,8 @@ jsg::Ref Fetcher::connect( return connectImpl(js, JSG_THIS, kj::mv(address), kj::mv(options)); } -jsg::Promise> Fetcher::fetch( - jsg::Lock& js, kj::OneOf, kj::String> requestOrUrl, +jsg::Promise> Fetcher::fetch(jsg::Lock& js, + kj::OneOf, kj::String> requestOrUrl, jsg::Optional>> requestInit) { return fetchImpl(js, JSG_THIS, kj::mv(requestOrUrl), kj::mv(requestInit)); } @@ -2189,8 +2163,9 @@ kj::Maybe> Fetcher::getRpcMethod(jsg::Lock& js, kj::Stri // // Reported here: https://github.com/kwhitley/itty-durable/issues/48 } else { - IoContext::current().logWarningOnce(kj::str( - "WARNING: Tried to access method or property '", name, "' on a Service Binding or " + IoContext::current().logWarningOnce(kj::str("WARNING: Tried to access method or property '", + name, + "' on a Service Binding or " "Durable Object stub. Are you trying to use RPC? If so, please enable the 'rpc' compat " "flag or update your compat date to 2024-04-03 or later (see " "https://developers.cloudflare.com/workers/configuration/compatibility-dates/ ). If you " @@ -2223,56 +2198,50 @@ rpc::JsRpcTarget::Client Fetcher::getClientForOneCall( // propagated the exception to any RPC calls that we're waiting on, so we even ignore errors // here -- otherwise they'll end up logged as "uncaught exceptions" even if they were, in fact, // caught elsewhere. - ioContext.addTask(worker->customEvent(kj::mv(event)).attach(kj::mv(worker)) - .then([](auto&&) {}, [](kj::Exception&&) {})); + ioContext.addTask(worker->customEvent(kj::mv(event)).attach(kj::mv(worker)).then([](auto&&) { + }, [](kj::Exception&&) {})); // (Don't extend `path` because we're the root.) return result; } -static jsg::Promise throwOnError(jsg::Lock& js, - kj::StringPtr method, - jsg::Promise> promise) { +static jsg::Promise throwOnError( + jsg::Lock& js, kj::StringPtr method, jsg::Promise> promise) { return promise.then(js, [method](jsg::Lock&, jsg::Ref response) { uint status = response->getStatus(); // TODO(someday): Would be nice to attach the response to the JavaScript error, maybe? Or // should people really use fetch() if they want to inspect error responses? JSG_REQUIRE(status >= 200 && status < 300, Error, - kj::str("HTTP ", method, " request failed: ", response->getStatus(), " ", response->getStatusText())); + kj::str("HTTP ", method, " request failed: ", response->getStatus(), " ", + response->getStatusText())); }); } static jsg::Promise parseResponse( jsg::Lock& js, jsg::Ref response, jsg::Optional type) { auto typeName = - type.map([](const kj::String& s) -> kj::StringPtr { return s; }) - .orDefault("text"); + type.map([](const kj::String& s) -> kj::StringPtr { return s; }).orDefault("text"); if (typeName == "stream") { KJ_IF_SOME(body, response->getBody()) { return js.resolvedPromise(Fetcher::GetResult(kj::mv(body))); } else { // Empty body. - return js.resolvedPromise( - Fetcher::GetResult(jsg::alloc( - IoContext::current(), - newSystemStream(newNullInputStream(), StreamEncoding::IDENTITY)))); + return js.resolvedPromise(Fetcher::GetResult(jsg::alloc( + IoContext::current(), newSystemStream(newNullInputStream(), StreamEncoding::IDENTITY)))); } } if (typeName == "text") { - return response->text(js) - .then(js, [response = kj::mv(response)](jsg::Lock&, auto x) { + return response->text(js).then(js, [response = kj::mv(response)](jsg::Lock&, auto x) { return Fetcher::GetResult(kj::mv(x)); }); } else if (typeName == "arrayBuffer") { - return response->arrayBuffer(js) - .then(js, [response = kj::mv(response)](jsg::Lock&, auto x) { + return response->arrayBuffer(js).then(js, [response = kj::mv(response)](jsg::Lock&, auto x) { return Fetcher::GetResult(kj::mv(x)); }); } else if (typeName == "json") { - return response->json(js) - .then(js, [response = kj::mv(response)](jsg::Lock&, auto x) { + return response->json(js).then(js, [response = kj::mv(response)](jsg::Lock&, auto x) { return Fetcher::GetResult(kj::mv(x)); }); } else { @@ -2288,8 +2257,9 @@ jsg::Promise Fetcher::get( subInit.method = kj::str("GET"); return fetchImpl(js, JSG_THIS, kj::mv(url), kj::mv(subInit)) - .then(js, [type = kj::mv(type)](jsg::Lock& js, jsg::Ref response) mutable - -> jsg::Promise { + .then(js, + [type = kj::mv(type)]( + jsg::Lock& js, jsg::Ref response) mutable -> jsg::Promise { uint status = response->getStatus(); if (status == 404 || status == 410) { return js.resolvedPromise(GetResult(js.v8Ref(js.v8Null()))); @@ -2299,16 +2269,17 @@ jsg::Promise Fetcher::get( // TODO(someday): Would be nice to attach the response to the JavaScript error, maybe? Or // should people really use fetch() if they want to inspect error responses? JSG_FAIL_REQUIRE(Error, - kj::str("HTTP GET request failed: ", response->getStatus(), " ", - response->getStatusText())); + kj::str( + "HTTP GET request failed: ", response->getStatus(), " ", response->getStatusText())); } else { return parseResponse(js, kj::mv(response), kj::mv(type)); } }); } -jsg::Promise Fetcher::put( - jsg::Lock& js, kj::String url, Body::Initializer body, +jsg::Promise Fetcher::put(jsg::Lock& js, + kj::String url, + Body::Initializer body, jsg::Optional options) { // Note that this borrows liberally from fetchImpl(fetcher, request, init, isolate). // This use of evalNow() is obsoleted by the capture_async_api_throws compatibility flag, but @@ -2326,10 +2297,10 @@ jsg::Promise Fetcher::put( // the URL's query parameters. KJ_IF_SOME(o, options) { KJ_IF_SOME(expiration, o.expiration) { - parsedUrl.query.add(kj::Url::QueryParam { kj::str("expiration"), kj::str(expiration) }); + parsedUrl.query.add(kj::Url::QueryParam{kj::str("expiration"), kj::str(expiration)}); } KJ_IF_SOME(expirationTtl, o.expirationTtl) { - parsedUrl.query.add(kj::Url::QueryParam { kj::str("expiration_ttl"), kj::str(expirationTtl) }); + parsedUrl.query.add(kj::Url::QueryParam{kj::str("expiration_ttl"), kj::str(expirationTtl)}); } } @@ -2345,58 +2316,56 @@ jsg::Promise Fetcher::delete_(jsg::Lock& js, kj::String url) { } jsg::Promise Fetcher::queue( - jsg::Lock& js, kj::String queueName, kj::Array messages) { + jsg::Lock& js, kj::String queueName, kj::Array messages) { auto& ioContext = IoContext::current(); auto worker = getClient(ioContext, kj::none, "queue"_kjc); auto encodedMessages = kj::heapArrayBuilder(messages.size()); - for (auto& msg : messages) { + for (auto& msg: messages) { KJ_IF_SOME(b, msg.body) { JSG_REQUIRE(msg.serializedBody == nullptr, TypeError, - "Expected one of body or serializedBody for each message"); - jsg::Serializer serializer(js, jsg::Serializer::Options { - .version = 15, - .omitHeader = false, - }); + "Expected one of body or serializedBody for each message"); + jsg::Serializer serializer(js, + jsg::Serializer::Options{ + .version = 15, + .omitHeader = false, + }); serializer.write(js, jsg::JsValue(b.getHandle(js))); - encodedMessages.add(IncomingQueueMessage{ - .id=kj::mv(msg.id), - .timestamp=msg.timestamp, - .body=serializer.release().data, - .attempts=msg.attempts - }); + encodedMessages.add(IncomingQueueMessage{.id = kj::mv(msg.id), + .timestamp = msg.timestamp, + .body = serializer.release().data, + .attempts = msg.attempts}); } else KJ_IF_SOME(b, msg.serializedBody) { - encodedMessages.add(IncomingQueueMessage{ - .id=kj::mv(msg.id), - .timestamp=msg.timestamp, - .body=kj::mv(b), - .attempts=msg.attempts - }); + encodedMessages.add(IncomingQueueMessage{.id = kj::mv(msg.id), + .timestamp = msg.timestamp, + .body = kj::mv(b), + .attempts = msg.attempts}); } else { JSG_FAIL_REQUIRE(TypeError, "Expected one of body or serializedBody for each message"); } } auto event = kj::refcounted(QueueEvent::Params{ - .queueName=kj::mv(queueName), - .messages=encodedMessages.finish(), + .queueName = kj::mv(queueName), + .messages = encodedMessages.finish(), }); - auto eventRef = kj::addRef(*event); // attempt to work around windows-specific null pointer deref. + auto eventRef = + kj::addRef(*event); // attempt to work around windows-specific null pointer deref. return ioContext.awaitIo(js, worker->customEvent(kj::mv(eventRef)).attach(kj::mv(worker)), - [event=kj::mv(event)](jsg::Lock& js, WorkerInterface::CustomEvent::Result result) { + [event = kj::mv(event)](jsg::Lock& js, WorkerInterface::CustomEvent::Result result) { return Fetcher::QueueResult{ - .outcome=kj::str(result.outcome), - .ackAll=event->getAckAll(), - .retryBatch=event->getRetryBatch(), - .explicitAcks=event->getExplicitAcks(), - .retryMessages=event->getRetryMessages(), + .outcome = kj::str(result.outcome), + .ackAll = event->getAckAll(), + .retryBatch = event->getRetryBatch(), + .explicitAcks = event->getExplicitAcks(), + .retryMessages = event->getRetryMessages(), }; }); } jsg::Promise Fetcher::scheduled( - jsg::Lock& js, jsg::Optional options) { + jsg::Lock& js, jsg::Optional options) { auto& ioContext = IoContext::current(); auto worker = getClient(ioContext, kj::none, "scheduled"_kjc); @@ -2411,12 +2380,12 @@ jsg::Promise Fetcher::scheduled( } } - return ioContext.awaitIo(js, worker->runScheduled(scheduledTime, cron) - .attach(kj::mv(worker), kj::mv(cron)), + return ioContext.awaitIo(js, + worker->runScheduled(scheduledTime, cron).attach(kj::mv(worker), kj::mv(cron)), [](jsg::Lock& js, WorkerInterface::ScheduledResult result) { return Fetcher::ScheduledResult{ - .outcome=kj::str(result.outcome), - .noRetry=!result.retry, + .outcome = kj::str(result.outcome), + .noRetry = !result.retry, }; }); } @@ -2425,7 +2394,8 @@ kj::Own Fetcher::getClient( IoContext& ioContext, kj::Maybe cfStr, kj::ConstString operationName) { KJ_SWITCH_ONEOF(channelOrClientFactory) { KJ_CASE_ONEOF(channel, uint) { - return ioContext.getSubrequestChannel(channel, isInHouse, kj::mv(cfStr), kj::mv(operationName)); + return ioContext.getSubrequestChannel( + channel, isInHouse, kj::mv(cfStr), kj::mv(operationName)); } KJ_CASE_ONEOF(outgoingFactory, IoOwn) { return outgoingFactory->newSingleUseClient(kj::mv(cfStr)); @@ -2442,15 +2412,15 @@ kj::Url Fetcher::parseUrl(jsg::Lock& js, kj::StringPtr url) { // "." and ".." components as well as fragments (stuff after '#'), all of which needs to be // removed/collapsed before the URL is HTTP-ready. Luckily our URL parser does all this if we // tell it the context is REMOTE_HREF. - constexpr auto urlOptions = kj::Url::Options { .percentDecode = false, .allowEmpty = true }; + constexpr auto urlOptions = kj::Url::Options{.percentDecode = false, .allowEmpty = true}; kj::Maybe maybeParsed; if (this->requiresHost == RequiresHostAndProtocol::YES) { maybeParsed = kj::Url::tryParse(url, kj::Url::REMOTE_HREF, urlOptions); } else { // We don't require a protocol nor hostname, but we accept them. The easiest way to implement // this is to parse relative to a dummy URL. - static const kj::Url FAKE = kj::Url::parse( - "https://fake-host/", kj::Url::REMOTE_HREF, urlOptions); + static const kj::Url FAKE = + kj::Url::parse("https://fake-host/", kj::Url::REMOTE_HREF, urlOptions); maybeParsed = FAKE.tryParseRelative(url); } @@ -2467,8 +2437,7 @@ kj::Url Fetcher::parseUrl(jsg::Lock& js, kj::StringPtr url) { JSG_FAIL_REQUIRE(TypeError, kj::str("Fetch API cannot load: ", url)); } - if (p.scheme != nullptr && - '0' <= p.scheme[0] && p.scheme[0] <= '9') { + if (p.scheme != nullptr && '0' <= p.scheme[0] && p.scheme[0] <= '9') { // First character of the scheme is a digit. This is a weird case: Normally the KJ URL // parser would treat a scheme starting with a digit as invalid. But, due to a bug, // `tryParseRelative()` does NOT treat it as invalid. So, we know we took the branch above @@ -2485,17 +2454,20 @@ kj::Url Fetcher::parseUrl(jsg::Lock& js, kj::StringPtr url) { // Include some extra text for ws:// and wss:// specifically, since this is the most common // mistake. more = " Note that fetch() treats WebSockets as a special kind of HTTP request, " - "therefore WebSockets should use 'http:'/'https:', not 'ws:'/'wss:'."; + "therefore WebSockets should use 'http:'/'https:', not 'ws:'/'wss:'."; } else if (p.scheme == "ftp") { // Include some extra text for ftp://, since we see this sometimes. more = " fetch() does not support the FTP protocol."; } - IoContext::current().logWarning(kj::str( - "Worker passed an invalid URL to fetch(). URLs passed to fetch() must begin with " - "either 'http:' or 'https:', not '", p.scheme, ":'. Due to a historical bug, any " - "other protocol used here will be treated the same as 'http:'. We plan to correct " - "this bug in the future, so please update your Worker to use 'http:' or 'https:' for " - "all fetch() URLs.", more)); + IoContext::current().logWarning( + kj::str("Worker passed an invalid URL to fetch(). URLs passed to fetch() must begin with " + "either 'http:' or 'https:', not '", + p.scheme, + ":'. Due to a historical bug, any " + "other protocol used here will be treated the same as 'http:'. We plan to correct " + "this bug in the future, so please update your Worker to use 'http:' or 'https:' for " + "all fetch() URLs.", + more)); } return kj::mv(p); @@ -2507,12 +2479,14 @@ kj::Url Fetcher::parseUrl(jsg::Lock& js, kj::StringPtr url) { static kj::StringPtr defaultStatusText(uint statusCode) { // RFC 7231 recommendations, unless otherwise specified. // https://tools.ietf.org/html/rfc7231#section-6.1 -#define STATUS(code, text) case code: return text##_kj +#define STATUS(code, text) \ + case code: \ + return text##_kj switch (statusCode) { STATUS(100, "Continue"); STATUS(101, "Switching Protocols"); - STATUS(102, "Processing"); // RFC 2518, WebDAV - STATUS(103, "Early Hints"); // RFC 8297 + STATUS(102, "Processing"); // RFC 2518, WebDAV + STATUS(103, "Early Hints"); // RFC 8297 STATUS(200, "OK"); STATUS(201, "Created"); STATUS(202, "Accepted"); @@ -2520,9 +2494,9 @@ static kj::StringPtr defaultStatusText(uint statusCode) { STATUS(204, "No Content"); STATUS(205, "Reset Content"); STATUS(206, "Partial Content"); - STATUS(207, "Multi-Status"); // RFC 4918, WebDAV - STATUS(208, "Already Reported"); // RFC 5842, WebDAV - STATUS(226, "IM Used"); // RFC 3229 + STATUS(207, "Multi-Status"); // RFC 4918, WebDAV + STATUS(208, "Already Reported"); // RFC 5842, WebDAV + STATUS(226, "IM Used"); // RFC 3229 STATUS(300, "Multiple Choices"); STATUS(301, "Moved Permanently"); STATUS(302, "Found"); @@ -2530,7 +2504,7 @@ static kj::StringPtr defaultStatusText(uint statusCode) { STATUS(304, "Not Modified"); STATUS(305, "Use Proxy"); STATUS(307, "Temporary Redirect"); - STATUS(308, "Permanent Redirect"); // RFC 7538 + STATUS(308, "Permanent Redirect"); // RFC 7538 STATUS(400, "Bad Request"); STATUS(401, "Unauthorized"); STATUS(402, "Payment Required"); @@ -2549,27 +2523,27 @@ static kj::StringPtr defaultStatusText(uint statusCode) { STATUS(415, "Unsupported Media Type"); STATUS(416, "Range Not Satisfiable"); STATUS(417, "Expectation Failed"); - STATUS(418, "I'm a teapot"); // RFC 2324 - STATUS(421, "Misdirected Request"); // RFC 7540 - STATUS(422, "Unprocessable Entity"); // RFC 4918, WebDAV - STATUS(423, "Locked"); // RFC 4918, WebDAV - STATUS(424, "Failed Dependency"); // RFC 4918, WebDAV + STATUS(418, "I'm a teapot"); // RFC 2324 + STATUS(421, "Misdirected Request"); // RFC 7540 + STATUS(422, "Unprocessable Entity"); // RFC 4918, WebDAV + STATUS(423, "Locked"); // RFC 4918, WebDAV + STATUS(424, "Failed Dependency"); // RFC 4918, WebDAV STATUS(426, "Upgrade Required"); - STATUS(428, "Precondition Required"); // RFC 6585 - STATUS(429, "Too Many Requests"); // RFC 6585 - STATUS(431, "Request Header Fields Too Large"); // RFC 6585 - STATUS(451, "Unavailable For Legal Reasons"); // RFC 7725 + STATUS(428, "Precondition Required"); // RFC 6585 + STATUS(429, "Too Many Requests"); // RFC 6585 + STATUS(431, "Request Header Fields Too Large"); // RFC 6585 + STATUS(451, "Unavailable For Legal Reasons"); // RFC 7725 STATUS(500, "Internal Server Error"); STATUS(501, "Not Implemented"); STATUS(502, "Bad Gateway"); STATUS(503, "Service Unavailable"); STATUS(504, "Gateway Timeout"); STATUS(505, "HTTP Version Not Supported"); - STATUS(506, "Variant Also Negotiates"); // RFC 2295 - STATUS(507, "Insufficient Storage"); // RFC 4918, WebDAV - STATUS(508, "Loop Detected"); // RFC 5842, WebDAV - STATUS(510, "Not Extended"); // RFC 2774 - STATUS(511, "Network Authentication Required"); // RFC 6585 + STATUS(506, "Variant Also Negotiates"); // RFC 2295 + STATUS(507, "Insufficient Storage"); // RFC 4918, WebDAV + STATUS(508, "Loop Detected"); // RFC 5842, WebDAV + STATUS(510, "Not Extended"); // RFC 2774 + STATUS(511, "Network Authentication Required"); // RFC 6585 default: // If we don't recognize the status code, check which range it falls into and use the status // code class defined by RFC 7231, section 6, as the status text. @@ -2595,8 +2569,10 @@ bool isNullBodyStatusCode(uint statusCode) { case 101: case 204: case 205: - case 304: return true; - default: return false; + case 304: + return true; + default: + return false; } } @@ -2608,8 +2584,10 @@ bool isRedirectStatusCode(uint statusCode) { case 302: case 303: case 307: - case 308: return true; - default: return false; + case 308: + return true; + default: + return false; } } diff --git a/src/workerd/api/hyperdrive.c++ b/src/workerd/api/hyperdrive.c++ index bb1112d47ca..71e25b6d006 100644 --- a/src/workerd/api/hyperdrive.c++ +++ b/src/workerd/api/hyperdrive.c++ @@ -11,21 +11,25 @@ #include namespace workerd::api { -Hyperdrive::Hyperdrive(uint clientIndex, kj::String database, - kj::String user, kj::String password, kj::String scheme) - : clientIndex(clientIndex), database(kj::mv(database)), - user(kj::mv(user)), password(kj::mv(password)), scheme(kj::mv(scheme)) { - kj::byte randomBytes[16]{}; - KJ_ASSERT(RAND_bytes(randomBytes, sizeof(randomBytes)) == 1); - randomHost = kj::str(kj::encodeHex(randomBytes), ".hyperdrive.local"); - } +Hyperdrive::Hyperdrive( + uint clientIndex, kj::String database, kj::String user, kj::String password, kj::String scheme) + : clientIndex(clientIndex), + database(kj::mv(database)), + user(kj::mv(user)), + password(kj::mv(password)), + scheme(kj::mv(scheme)) { + kj::byte randomBytes[16]{}; + KJ_ASSERT(RAND_bytes(randomBytes, sizeof(randomBytes)) == 1); + randomHost = kj::str(kj::encodeHex(randomBytes), ".hyperdrive.local"); +} jsg::Ref Hyperdrive::connect(jsg::Lock& js) { auto connPromise = connectToDb(); auto paf = kj::newPromiseAndFulfiller>(); - auto conn = kj::newPromisedStream(connPromise.then( - [&f = *paf.fulfiller](kj::Own stream) { + auto conn = + kj::newPromisedStream(connPromise + .then([&f = *paf.fulfiller](kj::Own stream) { f.fulfill(kj::none); return kj::mv(stream); }, [&f = *paf.fulfiller](kj::Exception e) { @@ -37,9 +41,8 @@ jsg::Ref Hyperdrive::connect(jsg::Lock& js) { // TODO(someday): Support TLS? It's not at all necessary since we're connecting locally, but // some users may want it anyway. auto nullTlsStarter = kj::heap(); - auto sock = setupSocket(js, kj::mv(conn), kj::str(getHost(), ":", getPort()), - kj::none, kj::mv(nullTlsStarter), false, - kj::str(this->randomHost), false); + auto sock = setupSocket(js, kj::mv(conn), kj::str(getHost(), ":", getPort()), kj::none, + kj::mv(nullTlsStarter), false, kj::str(this->randomHost), false); sock->handleProxyStatus(js, kj::mv(paf.promise)); return sock; } @@ -75,19 +78,19 @@ uint16_t Hyperdrive::getPort() { kj::String Hyperdrive::getConnectionString() { return kj::str(getScheme(), "://", getUser(), ":", getPassword(), "@", getHost(), ":", getPort(), - "/", getDatabase(), "?sslmode=disable"); + "/", getDatabase(), "?sslmode=disable"); } kj::Promise> Hyperdrive::connectToDb() { auto& context = IoContext::current(); - auto service = context.getSubrequestChannel(this->clientIndex, - true, kj::none, "hyperdrive_dev"_kjc); + auto service = + context.getSubrequestChannel(this->clientIndex, true, kj::none, "hyperdrive_dev"_kjc); kj::HttpHeaderTable headerTable; kj::HttpHeaders headers(headerTable); auto connectReq = kj::newHttpClient(*service)->connect( - kj::str(getHost(), ":", getPort()), headers, kj::HttpConnectSettings{}); + kj::str(getHost(), ":", getPort()), headers, kj::HttpConnectSettings{}); auto status = co_await connectReq.status; @@ -98,18 +101,17 @@ kj::Promise> Hyperdrive::connectToDb() { KJ_IF_SOME(e, status.errorBody) { try { auto errorBody = co_await e->readAllText(); - kj::throwFatalException(KJ_EXCEPTION( - FAILED, kj::str("unexpected error connecting to database: ", errorBody))); - } catch (const kj::Exception& e) { kj::throwFatalException( - KJ_EXCEPTION(FAILED, kj::str("unexpected error connecting to database " - "and couldn't read error details: ", e))); + KJ_EXCEPTION(FAILED, kj::str("unexpected error connecting to database: ", errorBody))); + } catch (const kj::Exception& e) { + kj::throwFatalException(KJ_EXCEPTION(FAILED, + kj::str("unexpected error connecting to database " + "and couldn't read error details: ", + e))); } - } - else { - kj::throwFatalException( - KJ_EXCEPTION(FAILED, kj::str("unexpected error connecting to database: ", - status.statusText))); + } else { + kj::throwFatalException(KJ_EXCEPTION( + FAILED, kj::str("unexpected error connecting to database: ", status.statusText))); } } -} // namespace workerd::api::public_beta +} // namespace workerd::api diff --git a/src/workerd/api/hyperdrive.h b/src/workerd/api/hyperdrive.h index bcc6ce124e1..e2db2511854 100644 --- a/src/workerd/api/hyperdrive.h +++ b/src/workerd/api/hyperdrive.h @@ -15,12 +15,15 @@ class Socket; // // Provides the same interface as Hyperdrive while sending connection // traffic directly to postgres -class Hyperdrive : public jsg::Object { +class Hyperdrive: public jsg::Object { public: // `clientIndex` is what to pass to IoContext::getHttpClient() to get an HttpClient // representing this namespace. - explicit Hyperdrive(uint clientIndex, kj::String database, - kj::String user, kj::String password, kj::String scheme); + explicit Hyperdrive(uint clientIndex, + kj::String database, + kj::String user, + kj::String password, + kj::String scheme); jsg::Ref connect(jsg::Lock& js); kj::StringPtr getDatabase(); kj::StringPtr getUser(); @@ -62,6 +65,5 @@ class Hyperdrive : public jsg::Object { kj::Promise> connectToDb(); }; -#define EW_HYPERDRIVE_ISOLATE_TYPES \ - api::Hyperdrive -} // namespace workerd::api +#define EW_HYPERDRIVE_ISOLATE_TYPES api::Hyperdrive +} // namespace workerd::api diff --git a/src/workerd/api/kv.c++ b/src/workerd/api/kv.c++ index d6026c21450..61bf563f13d 100644 --- a/src/workerd/api/kv.c++ +++ b/src/workerd/api/kv.c++ @@ -23,8 +23,8 @@ static void checkForErrorStatus(kj::StringPtr method, const kj::HttpClient::Resp // Manually construct exception so that we can incorporate method and status into the text // that JavaScript sees. kj::throwFatalException(kj::Exception(kj::Exception::Type::FAILED, __FILE__, __LINE__, - kj::str(JSG_EXCEPTION(Error) ": KV ", method, " failed: ", - response.statusCode, ' ', response.statusText))); + kj::str(JSG_EXCEPTION(Error) ": KV ", method, " failed: ", response.statusCode, ' ', + response.statusText))); } } @@ -32,13 +32,13 @@ static void validateKeyName(kj::StringPtr method, kj::StringPtr name) { JSG_REQUIRE(name != "", TypeError, "Key name cannot be empty."); JSG_REQUIRE(name != ".", TypeError, "\".\" is not allowed as a key name."); JSG_REQUIRE(name != "..", TypeError, "\"..\" is not allowed as a key name."); - JSG_REQUIRE(name.size() <= kMaxKeyLength, Error, "KV ", method, " failed: ", - 414, " UTF-8 encoded length of ", name.size(), " exceeds key length limit of ", kMaxKeyLength, "."); + JSG_REQUIRE(name.size() <= kMaxKeyLength, Error, "KV ", method, " failed: ", 414, + " UTF-8 encoded length of ", name.size(), " exceeds key length limit of ", kMaxKeyLength, + "."); } -static void parseListMetadata(jsg::Lock& js, - jsg::JsValue listResponse, - kj::Maybe cacheStatus) { +static void parseListMetadata( + jsg::Lock& js, jsg::JsValue listResponse, kj::Maybe cacheStatus) { static constexpr auto METADATA = "metadata"_kjc; static constexpr auto KEYS = "keys"_kjc; @@ -63,8 +63,7 @@ static void parseListMetadata(jsg::Lock& js, constexpr auto FLPROD_405_HEADER = "CF-KV-FLPROD-405"_kj; -kj::Own KvNamespace::getHttpClient( - IoContext& context, +kj::Own KvNamespace::getHttpClient(IoContext& context, kj::HttpHeaders& headers, kj::OneOf opTypeOrUnknown, kj::StringPtr urlStr) { @@ -102,15 +101,14 @@ kj::Own KvNamespace::getHttpClient( return client; } - -jsg::Promise KvNamespace::get( - jsg::Lock& js, kj::String name, jsg::Optional> options, +jsg::Promise KvNamespace::get(jsg::Lock& js, + kj::String name, + jsg::Optional> options, CompatibilityFlags::Reader flags) { return js.evalNow([&] { auto resp = getWithMetadata(js, kj::mv(name), kj::mv(options)); - return resp.then(js, [](jsg::Lock&, KvNamespace::GetWithMetadataResult result) { - return kj::mv(result.value); - }); + return resp.then(js, + [](jsg::Lock&, KvNamespace::GetWithMetadataResult result) { return kj::mv(result.value); }); }); } @@ -124,7 +122,7 @@ jsg::Promise KvNamespace::getWithMetadata( url.scheme = kj::str("https"); url.host = kj::str("fake-host"); url.path.add(kj::mv(name)); - url.query.add(kj::Url::QueryParam { kj::str("urlencoded"), kj::str("true") }); + url.query.add(kj::Url::QueryParam{kj::str("urlencoded"), kj::str("true")}); kj::Maybe type; KJ_IF_SOME(oneOfOptions, options) { @@ -137,7 +135,7 @@ jsg::Promise KvNamespace::getWithMetadata( type = kj::mv(t); } KJ_IF_SOME(cacheTtl, options.cacheTtl) { - url.query.add(kj::Url::QueryParam { kj::str("cache_ttl"), kj::str(cacheTtl) }); + url.query.add(kj::Url::QueryParam{kj::str("cache_ttl"), kj::str(cacheTtl)}); } } } @@ -149,19 +147,17 @@ jsg::Promise KvNamespace::getWithMetadata( auto client = getHttpClient(context, headers, LimitEnforcer::KvOpType::GET, urlStr); auto request = client->request(kj::HttpMethod::GET, urlStr, headers); - return context.awaitIo(js, - kj::mv(request.response), - [type = kj::mv(type), &context, client = kj::mv(client)] - (jsg::Lock& js, kj::HttpClient::Response&& response) mutable - -> jsg::Promise { - - auto cacheStatus = response.headers->get(context.getHeaderIds().cfCacheStatus) - .map([&](kj::StringPtr cs) { - return jsg::JsRef(js, js.strIntern(cs)); - }); + return context.awaitIo(js, kj::mv(request.response), + [type = kj::mv(type), &context, client = kj::mv(client)]( + jsg::Lock& js, kj::HttpClient::Response&& response) mutable + -> jsg::Promise { + auto cacheStatus = + response.headers->get(context.getHeaderIds().cfCacheStatus).map([&](kj::StringPtr cs) { + return jsg::JsRef(js, js.strIntern(cs)); + }); if (response.statusCode == 404 || response.statusCode == 410) { - return js.resolvedPromise(KvNamespace::GetWithMetadataResult { + return js.resolvedPromise(KvNamespace::GetWithMetadataResult{ .value = kj::none, .metadata = kj::none, .cacheStatus = kj::mv(cacheStatus), @@ -177,19 +173,18 @@ jsg::Promise KvNamespace::getWithMetadata( } auto typeName = - type.map([](const kj::String& s) -> kj::StringPtr { return s; }) - .orDefault("text"); + type.map([](const kj::String& s) -> kj::StringPtr { return s; }).orDefault("text"); auto& context = IoContext::current(); - auto stream = newSystemStream( - response.body.attach(kj::mv(client)), getContentEncoding(context, *response.headers, - Response::BodyEncoding::AUTO, FeatureFlags::get(js))); + auto stream = newSystemStream(response.body.attach(kj::mv(client)), + getContentEncoding( + context, *response.headers, Response::BodyEncoding::AUTO, FeatureFlags::get(js))); jsg::Promise result = nullptr; if (typeName == "stream") { - result = js.resolvedPromise(KvNamespace::GetResult( - jsg::alloc(context, kj::mv(stream)))); + result = js.resolvedPromise( + KvNamespace::GetResult(jsg::alloc(context, kj::mv(stream)))); } else if (typeName == "text") { // NOTE: In theory we should be using awaitIoLegacy() here since ReadableStreamSource is // supposed to handle pending events on its own, but we also know that the HTTP client @@ -197,16 +192,12 @@ jsg::Promise KvNamespace::getWithMetadata( result = context.awaitIo(js, stream->readAllText(context.getLimitEnforcer().getBufferingLimit()) .attach(kj::mv(stream)), - [](jsg::Lock&, kj::String text) { - return KvNamespace::GetResult(kj::mv(text)); - }); + [](jsg::Lock&, kj::String text) { return KvNamespace::GetResult(kj::mv(text)); }); } else if (typeName == "arrayBuffer") { result = context.awaitIo(js, stream->readAllBytes(context.getLimitEnforcer().getBufferingLimit()) .attach(kj::mv(stream)), - [](jsg::Lock&, kj::Array text) { - return KvNamespace::GetResult(kj::mv(text)); - }); + [](jsg::Lock&, kj::Array text) { return KvNamespace::GetResult(kj::mv(text)); }); } else if (typeName == "json") { result = context.awaitIo(js, stream->readAllText(context.getLimitEnforcer().getBufferingLimit()) @@ -220,10 +211,11 @@ jsg::Promise KvNamespace::getWithMetadata( "Unknown response type. Possible types are \"text\", \"arrayBuffer\", " "\"json\", and \"stream\"."); } - return result.then(js, [maybeMeta = kj::mv(maybeMeta), cacheStatus = kj::mv(cacheStatus)] - (jsg::Lock& js, KvNamespace::GetResult result) mutable -> KvNamespace::GetWithMetadataResult { + return result.then(js, + [maybeMeta = kj::mv(maybeMeta), cacheStatus = kj::mv(cacheStatus)](jsg::Lock& js, + KvNamespace::GetResult result) mutable -> KvNamespace::GetWithMetadataResult { kj::Maybe> meta; - KJ_IF_SOME (metaStr, maybeMeta) { + KJ_IF_SOME(metaStr, maybeMeta) { meta = jsg::JsRef(js, jsg::JsValue::fromJson(js, metaStr)); } return KvNamespace::GetWithMetadataResult{ @@ -235,8 +227,8 @@ jsg::Promise KvNamespace::getWithMetadata( }); } -jsg::Promise> KvNamespace::list(jsg::Lock& js, - jsg::Optional options) { +jsg::Promise> KvNamespace::list( + jsg::Lock& js, jsg::Optional options) { return js.evalNow([&] { auto& context = IoContext::current(); @@ -246,17 +238,17 @@ jsg::Promise> KvNamespace::list(jsg::Lock& js, KJ_IF_SOME(o, options) { KJ_IF_SOME(limit, o.limit) { if (limit > 0) { - url.query.add(kj::Url::QueryParam { kj::str("key_count_limit"), kj::str(limit) }); + url.query.add(kj::Url::QueryParam{kj::str("key_count_limit"), kj::str(limit)}); } } KJ_IF_SOME(maybePrefix, o.prefix) { KJ_IF_SOME(prefix, maybePrefix) { - url.query.add(kj::Url::QueryParam { kj::str("prefix"), kj::str(prefix) }); + url.query.add(kj::Url::QueryParam{kj::str("prefix"), kj::str(prefix)}); } } KJ_IF_SOME(maybeCursor, o.cursor) { KJ_IF_SOME(cursor, maybeCursor) { - url.query.add(kj::Url::QueryParam { kj::str("cursor"), kj::str(cursor) }); + url.query.add(kj::Url::QueryParam{kj::str("cursor"), kj::str(cursor)}); } } } @@ -267,25 +259,22 @@ jsg::Promise> KvNamespace::list(jsg::Lock& js, auto client = getHttpClient(context, headers, LimitEnforcer::KvOpType::LIST, urlStr); auto request = client->request(kj::HttpMethod::GET, urlStr, headers); - return context.awaitIo(js, - kj::mv(request.response), - [&context, client = kj::mv(client)] - (jsg::Lock& js, kj::HttpClient::Response&& response) mutable - -> jsg::Promise> { - + return context.awaitIo(js, kj::mv(request.response), + [&context, client = kj::mv(client)](jsg::Lock& js, + kj::HttpClient::Response&& response) mutable -> jsg::Promise> { checkForErrorStatus("GET", response); - kj::Maybe> cacheStatus = [&]() - -> kj::Maybe> { + kj::Maybe> cacheStatus = + [&]() -> kj::Maybe> { KJ_IF_SOME(cs, response.headers->get(context.getHeaderIds().cfCacheStatus)) { return jsg::JsRef(js, js.strIntern(cs)); } return kj::none; }(); - auto stream = newSystemStream( - response.body.attach(kj::mv(client)), getContentEncoding(context, *response.headers, - Response::BodyEncoding::AUTO, FeatureFlags::get(js))); + auto stream = newSystemStream(response.body.attach(kj::mv(client)), + getContentEncoding( + context, *response.headers, Response::BodyEncoding::AUTO, FeatureFlags::get(js))); return context.awaitIo(js, stream->readAllText(context.getLimitEnforcer().getBufferingLimit()) @@ -293,17 +282,15 @@ jsg::Promise> KvNamespace::list(jsg::Lock& js, [cacheStatus = kj::mv(cacheStatus)](jsg::Lock& js, kj::String text) mutable { auto result = jsg::JsValue::fromJson(js, text); parseListMetadata(js, result, - cacheStatus.map([&](jsg::JsRef& cs) -> jsg::JsValue { - return cs.getHandle(js); - })); + cacheStatus.map( + [&](jsg::JsRef& cs) -> jsg::JsValue { return cs.getHandle(js); })); return jsg::JsRef(js, result); }); }); }); } -jsg::Promise KvNamespace::put( - jsg::Lock& js, +jsg::Promise KvNamespace::put(jsg::Lock& js, kj::String name, KvNamespace::PutBody body, jsg::Optional options, @@ -317,7 +304,7 @@ jsg::Promise KvNamespace::put( url.scheme = kj::str("https"); url.host = kj::str("fake-host"); url.path.add(kj::mv(name)); - url.query.add(kj::Url::QueryParam { kj::str("urlencoded"), kj::str("true") }); + url.query.add(kj::Url::QueryParam{kj::str("urlencoded"), kj::str("true")}); kj::HttpHeaders headers(context.getHeaderTable()); @@ -325,10 +312,10 @@ jsg::Promise KvNamespace::put( // the URL's query parameters. KJ_IF_SOME(o, options) { KJ_IF_SOME(expiration, o.expiration) { - url.query.add(kj::Url::QueryParam { kj::str("expiration"), kj::str(expiration) }); + url.query.add(kj::Url::QueryParam{kj::str("expiration"), kj::str(expiration)}); } KJ_IF_SOME(expirationTtl, o.expirationTtl) { - url.query.add(kj::Url::QueryParam { kj::str("expiration_ttl"), kj::str(expirationTtl) }); + url.query.add(kj::Url::QueryParam{kj::str("expiration_ttl"), kj::str(expirationTtl)}); } KJ_IF_SOME(maybeMetadata, o.metadata) { KJ_IF_SOME(metadata, maybeMetadata) { @@ -345,11 +332,11 @@ jsg::Promise KvNamespace::put( supportedBody = kj::mv(text); } KJ_CASE_ONEOF(object, jsg::JsObject) { - supportedBody = JSG_REQUIRE_NONNULL(putTypeHandler.tryUnwrap(js, object), - TypeError, "KV put() accepts only strings, ArrayBuffers, ArrayBufferViews, and " + supportedBody = JSG_REQUIRE_NONNULL(putTypeHandler.tryUnwrap(js, object), TypeError, + "KV put() accepts only strings, ArrayBuffers, ArrayBufferViews, and " "ReadableStreams as values."); - JSG_REQUIRE(!supportedBody.is(), - TypeError, "KV put() accepts only strings, ArrayBuffers, ArrayBufferViews, and " + JSG_REQUIRE(!supportedBody.is(), TypeError, + "KV put() accepts only strings, ArrayBuffers, ArrayBufferViews, and " "ReadableStreams as values."); // TODO(someday): replace this with logic to do something smarter with Objects } @@ -374,13 +361,10 @@ jsg::Promise KvNamespace::put( auto client = getHttpClient(context, headers, LimitEnforcer::KvOpType::PUT, urlStr); - auto promise = context.waitForOutputLocks() - .then([&context, client = kj::mv(client), urlStr = kj::mv(urlStr), - headers = kj::mv(headers), expectedBodySize, - supportedBody = kj::mv(supportedBody)]() mutable { - auto innerReq = client->request( - kj::HttpMethod::PUT, urlStr, - headers, expectedBodySize); + auto promise = context.waitForOutputLocks().then( + [&context, client = kj::mv(client), urlStr = kj::mv(urlStr), headers = kj::mv(headers), + expectedBodySize, supportedBody = kj::mv(supportedBody)]() mutable { + auto innerReq = client->request(kj::HttpMethod::PUT, urlStr, headers, expectedBodySize); struct RefcountedWrapper: public kj::Refcounted { explicit RefcountedWrapper(kj::Own client): client(kj::mv(client)) {} kj::Own client; @@ -398,17 +382,16 @@ jsg::Promise KvNamespace::put( writePromise = req.body->write(data).attach(kj::mv(data)); } KJ_CASE_ONEOF(stream, jsg::Ref) { - writePromise = context.run([ - dest = newSystemStream(kj::mv(req.body), StreamEncoding::IDENTITY, context), - stream = kj::mv(stream)](jsg::Lock& js) mutable { + writePromise = context.run( + [dest = newSystemStream(kj::mv(req.body), StreamEncoding::IDENTITY, context), + stream = kj::mv(stream)](jsg::Lock& js) mutable { return IoContext::current().waitForDeferredProxy( stream->pumpTo(js, kj::mv(dest), true)); }); } } - return writePromise.attach(kj::mv(req.body)) - .then([resp = kj::mv(req.response)]() mutable { + return writePromise.attach(kj::mv(req.body)).then([resp = kj::mv(req.response)]() mutable { return resp.then([](kj::HttpClient::Response&& response) mutable { checkForErrorStatus("PUT", response); @@ -434,11 +417,11 @@ jsg::Promise KvNamespace::delete_(jsg::Lock& js, kj::String name) { auto client = getHttpClient(context, headers, LimitEnforcer::KvOpType::DELETE, urlStr); - auto promise = context.waitForOutputLocks() - .then([headers = kj::mv(headers), client = kj::mv(client), urlStr = kj::mv(urlStr)]() mutable { - return client->request(kj::HttpMethod::DELETE, urlStr, headers, - uint64_t(0)) - .response.then([](kj::HttpClient::Response&& response) mutable { + auto promise = context.waitForOutputLocks().then( + [headers = kj::mv(headers), client = kj::mv(client), urlStr = kj::mv(urlStr)]() mutable { + return client->request(kj::HttpMethod::DELETE, urlStr, headers, uint64_t(0)) + .response + .then([](kj::HttpClient::Response&& response) mutable { checkForErrorStatus("DELETE", response); }).attach(kj::mv(client)); }); diff --git a/src/workerd/api/kv.h b/src/workerd/api/kv.h index 5d75c784e2a..6891eb49552 100644 --- a/src/workerd/api/kv.h +++ b/src/workerd/api/kv.h @@ -8,7 +8,9 @@ #include "streams.h" #include -namespace workerd { class IoContext; } +namespace workerd { +class IoContext; +} namespace workerd::api { // A capability to a KV namespace. @@ -28,7 +30,8 @@ class KvNamespace: public jsg::Object { // representing this namespace. // `additionalHeaders` is what gets appended to every outbound request. explicit KvNamespace(kj::Array additionalHeaders, uint subrequestChannel) - : additionalHeaders(kj::mv(additionalHeaders)), subrequestChannel(subrequestChannel) {} + : additionalHeaders(kj::mv(additionalHeaders)), + subrequestChannel(subrequestChannel) {} struct GetOptions { jsg::Optional type; @@ -41,13 +44,9 @@ class KvNamespace: public jsg::Object { }; using GetResult = kj::Maybe< - kj::OneOf, - kj::Array, - kj::String, - jsg::JsRef>>; + kj::OneOf, kj::Array, kj::String, jsg::JsRef>>; - jsg::Promise get( - jsg::Lock& js, + jsg::Promise get(jsg::Lock& js, kj::String name, jsg::Optional> options, CompatibilityFlags::Reader flags); @@ -66,9 +65,7 @@ class KvNamespace: public jsg::Object { }; jsg::Promise getWithMetadata( - jsg::Lock& js, - kj::String name, - jsg::Optional> options); + jsg::Lock& js, kj::String name, jsg::Optional> options); struct ListOptions { jsg::Optional limit; @@ -100,8 +97,7 @@ class KvNamespace: public jsg::Object { using PutSupportedTypes = kj::OneOf, jsg::Ref>; - jsg::Promise put( - jsg::Lock& js, + jsg::Promise put(jsg::Lock& js, kj::String name, PutBody body, jsg::Optional options, @@ -160,7 +156,7 @@ class KvNamespace: public jsg::Object { }); } - void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { + void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { tracker.trackField("additionalHeaders", additionalHeaders.asPtr()); } @@ -170,23 +166,18 @@ class KvNamespace: public jsg::Object { // name for the HttpClient without any limiter enforcement. // NOTE: The urlStr is added to the headers as a non-owning reference and thus must outlive // the usage of the headers. - kj::Own getHttpClient( - IoContext& context, + kj::Own getHttpClient(IoContext& context, kj::HttpHeaders& headers, kj::OneOf opTypeOrName, - kj::StringPtr urlStr - ); + kj::StringPtr urlStr); private: kj::Array additionalHeaders; uint subrequestChannel; }; -#define EW_KV_ISOLATE_TYPES \ - api::KvNamespace, \ - api::KvNamespace::ListOptions, \ - api::KvNamespace::GetOptions, \ - api::KvNamespace::PutOptions, \ - api::KvNamespace::GetWithMetadataResult +#define EW_KV_ISOLATE_TYPES \ + api::KvNamespace, api::KvNamespace::ListOptions, api::KvNamespace::GetOptions, \ + api::KvNamespace::PutOptions, api::KvNamespace::GetWithMetadataResult // The list of kv.h types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE } // namespace workerd::api diff --git a/src/workerd/api/memory-cache.c++ b/src/workerd/api/memory-cache.c++ index 66c8646c7e5..66e96d26699 100644 --- a/src/workerd/api/memory-cache.c++ +++ b/src/workerd/api/memory-cache.c++ @@ -35,8 +35,7 @@ static bool hasExpired(const kj::Maybe& expiration, bool allowOutsideIoC return false; } -SharedMemoryCache::SharedMemoryCache( - kj::Maybe provider, +SharedMemoryCache::SharedMemoryCache(kj::Maybe provider, kj::StringPtr id, kj::Maybe additionalResizeMemoryLimitHandler) : data(), @@ -183,8 +182,7 @@ void SharedMemoryCache::putWhileLocked(ThreadUnsafeData& data, } void SharedMemoryCache::evictNextWhileLocked( - ThreadUnsafeData& data, - bool allowOutsideIoContext) const { + ThreadUnsafeData& data, bool allowOutsideIoContext) const { // The caller is responsible for ensuring that the cache is not empty already. KJ_REQUIRE(data.cache.size() > 0); @@ -205,8 +203,7 @@ void SharedMemoryCache::evictNextWhileLocked( } void SharedMemoryCache::removeIfExistsWhileLocked( - ThreadUnsafeData& data, - const kj::String& key) const { + ThreadUnsafeData& data, const kj::String& key) const { KJ_IF_SOME(entry, data.cache.find(key)) { // This DOES NOT count as an eviction because it might happen while // replacing the existing cache entry with a new one, when the new one is @@ -226,7 +223,8 @@ kj::Own SharedMemoryCache::create( } SharedMemoryCache::Use::Use(kj::Own cache, const Limits& limits) - : cache(kj::mv(cache)), limits(limits) { + : cache(kj::mv(cache)), + limits(limits) { this->cache->suggest(limits); } @@ -404,8 +402,8 @@ jsg::Promise> MemoryCache::read(jsg::Lock& js, JSG_REQUIRE( !kj::isNaN(expiration), TypeError, "Expiration time must not be NaN."); } - (*callback)(SharedMemoryCache::Use::FallbackResult{ - kj::mv(serialized), result.expiration}); + (*callback)( + SharedMemoryCache::Use::FallbackResult{kj::mv(serialized), result.expiration}); return kj::mv(result.value); }) .catch_(js, @@ -450,8 +448,8 @@ kj::Own MemoryCacheProvider::getInstance( const auto makeCache = [this](kj::Maybe provider, kj::StringPtr id) { // The cache doesn't exist in the map. Let's create it. - auto handler = additionalResizeMemoryLimitHandler.map([]( - const SharedMemoryCache::AdditionalResizeMemoryLimitHandler& handler) + auto handler = additionalResizeMemoryLimitHandler.map( + [](const SharedMemoryCache::AdditionalResizeMemoryLimitHandler& handler) -> SharedMemoryCache::AdditionalResizeMemoryLimitHandler& { return const_cast(handler); }); diff --git a/src/workerd/api/memory-cache.h b/src/workerd/api/memory-cache.h index 1885f0bf0d7..bd2007c7f37 100644 --- a/src/workerd/api/memory-cache.h +++ b/src/workerd/api/memory-cache.h @@ -60,7 +60,9 @@ struct MemoryCacheEntry { // evicted. kj::Own value; - inline size_t size() const { return value->bytes.size(); } + inline size_t size() const { + return value->bytes.size(); + } // The expiration timestamp of this cache entry, usually the time at which the // entry was created plus some TTL. This is measured in milliseconds and @@ -83,7 +85,7 @@ class MemoryCacheProvider; // implementation in the near future. The memcached-based impl would likely be // fairly different from this implementation so quite a few of the details here // are expected to change. -class SharedMemoryCache : public kj::AtomicRefcounted { +class SharedMemoryCache: public kj::AtomicRefcounted { private: struct InProgress; @@ -128,7 +130,9 @@ class SharedMemoryCache : public kj::AtomicRefcounted { }; } - static constexpr Limits min() { return {0, 0, 0}; } + static constexpr Limits min() { + return {0, 0, 0}; + } static Limits max(const Limits& a, const Limits& b) { return Limits{ @@ -143,19 +147,19 @@ class SharedMemoryCache : public kj::AtomicRefcounted { using AdditionalResizeMemoryLimitHandler = kj::Function; - SharedMemoryCache( - kj::Maybe provider, + SharedMemoryCache(kj::Maybe provider, kj::StringPtr id, kj::Maybe additionalResizeMemoryLimitHandler); ~SharedMemoryCache() noexcept(false); - kj::StringPtr getId() const { return id; } + kj::StringPtr getId() const { + return id; + } - static kj::Own create( - kj::Maybe provider, - kj::StringPtr id, - kj::Maybe additionalResizeMemoryLimitHandler); + static kj::Own create(kj::Maybe provider, + kj::StringPtr id, + kj::Maybe additionalResizeMemoryLimitHandler); public: // RAII class that attaches itself to a cache, suggests cache limits to the @@ -284,7 +288,9 @@ class SharedMemoryCache : public kj::AtomicRefcounted { // operations. class KeyCallbacks { public: - inline const kj::String& keyForRow(const MemoryCacheEntry& entry) const { return entry.key; } + inline const kj::String& keyForRow(const MemoryCacheEntry& entry) const { + return entry.key; + } template inline bool matches(const MemoryCacheEntry& e, KeyLike&& key) const { @@ -393,7 +399,9 @@ class SharedMemoryCache : public kj::AtomicRefcounted { // Returns the next liveliness and increments it so that the next call to // this function will return a different value. - inline uint64_t stepLiveliness() { return nextLiveliness++; } + inline uint64_t stepLiveliness() { + return nextLiveliness++; + } // We do not handle integer overflow, but a 64-bit counter should never wrap // around, at least not in the foreseeable future. (Even at a billion cache @@ -406,7 +414,7 @@ class SharedMemoryCache : public kj::AtomicRefcounted { size_t totalValueSize = 0; // The actual cache contents. - kj::Table, // index over keys kj::TreeIndex, // index over liveliness kj::TreeIndex, // index over value sizes @@ -424,7 +432,6 @@ class SharedMemoryCache : public kj::AtomicRefcounted { }; private: - // To ensure thread-safety, all mutable data is guarded by a mutex. Each cache // operation requires an exclusive lock. Even read-only operations need to // update the liveliness of cache entries, which currently requires a lock. @@ -463,7 +470,9 @@ class MemoryCache: public jsg::Object { jsg::NonCoercible key, jsg::Optional optionalFallback); - JSG_RESOURCE_TYPE(MemoryCache) { JSG_METHOD(read); } + JSG_RESOURCE_TYPE(MemoryCache) { + JSG_METHOD(read); + } private: SharedMemoryCache::Use cacheUse; @@ -478,14 +487,12 @@ class MemoryCache: public jsg::Object { // the in memory cache is being used. class MemoryCacheProvider { public: - MemoryCacheProvider( - kj::Maybe - additionalResizeMemoryLimitHandler = kj::none); + MemoryCacheProvider(kj::Maybe + additionalResizeMemoryLimitHandler = kj::none); KJ_DISALLOW_COPY_AND_MOVE(MemoryCacheProvider); ~MemoryCacheProvider() noexcept(false); - kj::Own getInstance( - kj::Maybe cacheId = kj::none) const; + kj::Own getInstance(kj::Maybe cacheId = kj::none) const; void removeInstance(const SharedMemoryCache& instance) const; diff --git a/src/workerd/api/node/async-hooks.c++ b/src/workerd/api/node/async-hooks.c++ index 6fabf3513e3..408231687ef 100644 --- a/src/workerd/api/node/async-hooks.c++ +++ b/src/workerd/api/node/async-hooks.c++ @@ -10,8 +10,7 @@ jsg::Ref AsyncLocalStorage::constructor(jsg::Lock& js) { return jsg::alloc(); } -v8::Local AsyncLocalStorage::run( - jsg::Lock& js, +v8::Local AsyncLocalStorage::run(jsg::Lock& js, v8::Local store, jsg::Function(jsg::Arguments)> callback, jsg::Arguments args) { @@ -20,8 +19,7 @@ v8::Local AsyncLocalStorage::run( return callback(js, kj::mv(args)); } -v8::Local AsyncLocalStorage::exit( - jsg::Lock& js, +v8::Local AsyncLocalStorage::exit(jsg::Lock& js, jsg::Function(jsg::Arguments)> callback, jsg::Arguments args) { // Node.js defines exit as running "a function synchronously outside of a context". @@ -65,38 +63,33 @@ kj::Maybe> tryGetFrameRef(jsg::Lock& js) { } } // namespace -AsyncResource::AsyncResource(jsg::Lock& js) : frame(tryGetFrameRef(js)) {} +AsyncResource::AsyncResource(jsg::Lock& js): frame(tryGetFrameRef(js)) {} jsg::Ref AsyncResource::constructor( - jsg::Lock& js, - jsg::Optional type, - jsg::Optional options) { + jsg::Lock& js, jsg::Optional type, jsg::Optional options) { // The type and options are required as part of the Node.js API compatibility // but our implementation does not currently make use of them at all. It is ok // for us to silently ignore both here. return jsg::alloc(js); } -v8::Local AsyncResource::staticBind( - jsg::Lock& js, +v8::Local AsyncResource::staticBind(jsg::Lock& js, v8::Local fn, jsg::Optional type, jsg::Optional> thisArg, const jsg::TypeHandler>& handler) { - return AsyncResource::constructor(js, kj::mv(type) - .orDefault([] { return kj::str("AsyncResource"); })) - ->bind(js, fn, thisArg, handler); + return AsyncResource::constructor(js, kj::mv(type).orDefault([] { + return kj::str("AsyncResource"); + }))->bind(js, fn, thisArg, handler); } kj::Maybe AsyncResource::getFrame() { - return frame.map([](jsg::Ref& frame) - -> jsg::AsyncContextFrame& { + return frame.map([](jsg::Ref& frame) -> jsg::AsyncContextFrame& { return *(frame.get()); }); } -v8::Local AsyncResource::bind( - jsg::Lock& js, +v8::Local AsyncResource::bind(jsg::Lock& js, v8::Local fn, jsg::Optional> thisArg, const jsg::TypeHandler>& handler) { @@ -114,8 +107,7 @@ v8::Local AsyncResource::bind( return bound; } -v8::Local AsyncResource::runInAsyncScope( - jsg::Lock& js, +v8::Local AsyncResource::runInAsyncScope(jsg::Lock& js, jsg::Function(jsg::Arguments)> fn, jsg::Optional> thisArg, jsg::Arguments args) { diff --git a/src/workerd/api/node/async-hooks.h b/src/workerd/api/node/async-hooks.h index e8bec3f8448..ec9dcdf9203 100644 --- a/src/workerd/api/node/async-hooks.h +++ b/src/workerd/api/node/async-hooks.h @@ -30,19 +30,21 @@ namespace workerd::api::node { // console.log(als.getStore()); // undefined class AsyncLocalStorage final: public jsg::Object { public: - AsyncLocalStorage() : key(kj::refcounted()) {} - ~AsyncLocalStorage() noexcept(false) { key->reset(); } + AsyncLocalStorage(): key(kj::refcounted()) {} + ~AsyncLocalStorage() noexcept(false) { + key->reset(); + } static jsg::Ref constructor(jsg::Lock& js); v8::Local run(jsg::Lock& js, - v8::Local store, - jsg::Function(jsg::Arguments)> callback, - jsg::Arguments args); + v8::Local store, + jsg::Function(jsg::Arguments)> callback, + jsg::Arguments args); v8::Local exit(jsg::Lock& js, - jsg::Function(jsg::Arguments)> callback, - jsg::Arguments args); + jsg::Function(jsg::Arguments)> callback, + jsg::Arguments args); v8::Local getStore(jsg::Lock& js); @@ -89,7 +91,6 @@ class AsyncLocalStorage final: public jsg::Object { kj::Own key; }; - // Note: The AsyncResource class is provided for Node.js backwards compatibility. // The class can be replaced entirely for async context tracking using the // AsyncLocalStorage.bind() and AsyncLocalStorage.snapshot() APIs. @@ -149,34 +150,35 @@ class AsyncResource final: public jsg::Object { // constructor to be a string specifying the resource type, we do not actually use it // for anything. We'll just ignore the value and not store it, but we at least need to // accept the argument and validate that it is a string. - static jsg::Ref constructor(jsg::Lock& js, jsg::Optional type, - jsg::Optional options = kj::none); + static jsg::Ref constructor( + jsg::Lock& js, jsg::Optional type, jsg::Optional options = kj::none); // The Node.js API uses numeric identifiers for all async resources. We do not // implement that part of their API. To prevent subtle bugs, we'll throw explicitly. - inline jsg::Unimplemented asyncId() { return {}; } + inline jsg::Unimplemented asyncId() { + return {}; + } // The Node.js API uses numeric identifiers for all async resources. We do not // implement that part of their API. To prevent subtle bugs, we'll throw explicitly. - inline jsg::Unimplemented triggerAsyncId() { return {}; } + inline jsg::Unimplemented triggerAsyncId() { + return {}; + } - static v8::Local staticBind( - jsg::Lock& js, + static v8::Local staticBind(jsg::Lock& js, v8::Local fn, jsg::Optional type, jsg::Optional> thisArg, const jsg::TypeHandler>& handler); // Binds the given function to this async context. - v8::Local bind( - jsg::Lock& js, + v8::Local bind(jsg::Lock& js, v8::Local fn, jsg::Optional> thisArg, const jsg::TypeHandler>& handler); // Calls the given function within this async context. - v8::Local runInAsyncScope( - jsg::Lock& js, + v8::Local runInAsyncScope(jsg::Lock& js, jsg::Function(jsg::Arguments)> fn, jsg::Optional> thisArg, jsg::Arguments); @@ -194,7 +196,6 @@ class AsyncResource final: public jsg::Object { bind any>(fn: Func): Func; runInAsyncScope(fn: (this: This, ...args: any[]) => Result, thisArg?: This, ...args: any[]): Result; }); - } // Returns the jsg::AsyncContextFrame captured when the AsyncResource was created, if any. @@ -226,10 +227,8 @@ class AsyncHooksModule final: public jsg::Object { } }; -#define EW_NODE_ASYNCHOOKS_ISOLATE_TYPES \ - api::node::AsyncHooksModule, \ - api::node::AsyncResource, \ - api::node::AsyncResource::Options, \ - api::node::AsyncLocalStorage +#define EW_NODE_ASYNCHOOKS_ISOLATE_TYPES \ + api::node::AsyncHooksModule, api::node::AsyncResource, api::node::AsyncResource::Options, \ + api::node::AsyncLocalStorage } // namespace workerd::api::node diff --git a/src/workerd/api/node/buffer-string-search.h b/src/workerd/api/node/buffer-string-search.h index 76cf1c65c20..2109e185d45 100644 --- a/src/workerd/api/node/buffer-string-search.h +++ b/src/workerd/api/node/buffer-string-search.h @@ -36,33 +36,40 @@ namespace stringsearch { template class Vector { - public: +public: Vector(T* data, size_t length, bool isForward) - : start_(data), length_(length), is_forward_(isForward) {} + : start_(data), + length_(length), + is_forward_(isForward) {} // Returns the start of the memory range. // For vector v this is NOT necessarily &v[0], see forward(). - const T* start() const { return start_; } + const T* start() const { + return start_; + } // Returns the length of the vector, in characters. - size_t length() const { return length_; } + size_t length() const { + return length_; + } // Returns true if the Vector is front-to-back, false if back-to-front. // In the latter case, v[0] corresponds to the *end* of the memory range. - bool forward() const { return is_forward_; } + bool forward() const { + return is_forward_; + } // Access individual vector elements - checks bounds in debug mode. T& operator[](size_t index) const { return start_[is_forward_ ? index : (length_ - index - 1)]; } - private: +private: T* start_; size_t length_; bool is_forward_; }; - //--------------------------------------------------------------------- // String Search object. //--------------------------------------------------------------------- @@ -70,7 +77,7 @@ class Vector { // Class holding constants and methods that apply to all string search variants, // independently of subject and pattern char size. class StringSearchBase { - protected: +protected: // Cap on the maximal shift in the Boyer-Moore implementation. By setting a // limit, we can fix the size of tables. For a needle longer than this limit, // search will not be optimal, since we only build tables for a suffix @@ -102,12 +109,11 @@ class StringSearchBase { }; template -class StringSearch : private StringSearchBase { - public: +class StringSearch: private StringSearchBase { +public: typedef stringsearch::Vector Vector; - explicit StringSearch(Vector pattern) - : pattern_(pattern), start_(0) { + explicit StringSearch(Vector pattern): pattern_(pattern), start_(0) { if (pattern.length() >= kBMMaxShift) { start_ = pattern.length() - kBMMaxShift; } @@ -149,12 +155,11 @@ class StringSearch : private StringSearchBase { return kUC16AlphabetSize; } - static_assert(sizeof(Char) == sizeof(uint8_t) || - sizeof(Char) == sizeof(uint16_t), - "sizeof(Char) == sizeof(uint16_t) || sizeof(uint8_t)"); + static_assert(sizeof(Char) == sizeof(uint8_t) || sizeof(Char) == sizeof(uint16_t), + "sizeof(Char) == sizeof(uint16_t) || sizeof(uint8_t)"); } - private: +private: typedef size_t (StringSearch::*SearchFunction)(Vector, size_t); size_t SingleCharSearch(Vector subject, size_t start_index); size_t LinearSearch(Vector subject, size_t start_index); @@ -166,8 +171,7 @@ class StringSearch : private StringSearchBase { void PopulateBoyerMooreTable(); - static inline int CharOccurrence(int* bad_char_occurrence, - Char char_code) { + static inline int CharOccurrence(int* bad_char_occurrence, Char char_code) { if (sizeof(Char) == 1) { return bad_char_occurrence[static_cast(char_code)]; } @@ -191,28 +195,23 @@ class StringSearch : private StringSearchBase { size_t start_; }; - template inline T AlignDown(T value, U alignment) { - return reinterpret_cast( - (reinterpret_cast(value) & ~(alignment - 1))); + return reinterpret_cast((reinterpret_cast(value) & ~(alignment - 1))); } - inline uint8_t GetHighestValueByte(uint16_t character) { - return std::max(static_cast(character & 0xFF), - static_cast(character >> 8)); + return std::max(static_cast(character & 0xFF), static_cast(character >> 8)); } - -inline uint8_t GetHighestValueByte(uint8_t character) { return character; } - +inline uint8_t GetHighestValueByte(uint8_t character) { + return character; +} // Searches for a byte value in a memory buffer, back to front. // Uses memrchr(3) on systems which support it, for speed. // Falls back to a vanilla for loop on non-GNU systems such as Windows. -inline const void* MemrchrFill(const void* haystack, uint8_t needle, - size_t haystack_len) { +inline const void* MemrchrFill(const void* haystack, uint8_t needle, size_t haystack_len) { #ifdef _GNU_SOURCE return memrchr(haystack, needle, haystack_len); #else @@ -226,12 +225,11 @@ inline const void* MemrchrFill(const void* haystack, uint8_t needle, #endif } - // Finds the first occurrence of *two-byte* character pattern[0] in the string // `subject`. Does not check that the whole pattern matches. template -inline size_t FindFirstCharacter(Vector pattern, - Vector subject, size_t index) { +inline size_t FindFirstCharacter( + Vector pattern, Vector subject, size_t index) { const Char pattern_first_char = pattern[0]; const size_t max_n = (subject.length() - pattern.length() + 1); @@ -246,13 +244,10 @@ inline size_t FindFirstCharacter(Vector pattern, // Assert that bytes_to_search won't overflow void_pos = memchr(subject.start() + pos, search_byte, bytes_to_search); } else { - void_pos = MemrchrFill(subject.start() + pattern.length() - 1, - search_byte, - bytes_to_search); + void_pos = MemrchrFill(subject.start() + pattern.length() - 1, search_byte, bytes_to_search); } const Char* char_pos = static_cast(void_pos); - if (char_pos == nullptr) - return subject.length(); + if (char_pos == nullptr) return subject.length(); // Then, for each match, verify that the full two bytes match pattern[0]. char_pos = AlignDown(char_pos, sizeof(Char)); @@ -268,13 +263,11 @@ inline size_t FindFirstCharacter(Vector pattern, return subject.length(); } - // Finds the first occurrence of the byte pattern[0] in string `subject`. // Does not verify that the whole pattern matches. template <> -inline size_t FindFirstCharacter(Vector pattern, - Vector subject, - size_t index) { +inline size_t FindFirstCharacter( + Vector pattern, Vector subject, size_t index) { const uint8_t pattern_first_char = pattern[0]; const size_t subj_len = subject.length(); const size_t max_n = (subject.length() - pattern.length() + 1); @@ -283,9 +276,7 @@ inline size_t FindFirstCharacter(Vector pattern, if (subject.forward()) { pos = memchr(subject.start() + index, pattern_first_char, max_n - index); } else { - pos = MemrchrFill(subject.start() + pattern.length() - 1, - pattern_first_char, - max_n - index); + pos = MemrchrFill(subject.start() + pattern.length() - 1, pattern_first_char, max_n - index); } const uint8_t* char_pos = static_cast(pos); if (char_pos == nullptr) { @@ -301,9 +292,7 @@ inline size_t FindFirstCharacter(Vector pattern, //--------------------------------------------------------------------- template -size_t StringSearch::SingleCharSearch( - Vector subject, - size_t index) { +size_t StringSearch::SingleCharSearch(Vector subject, size_t index) { return FindFirstCharacter(pattern_, subject, index); } @@ -313,14 +302,11 @@ size_t StringSearch::SingleCharSearch( // Simple linear search for short patterns. Never bails out. template -size_t StringSearch::LinearSearch( - Vector subject, - size_t index) { +size_t StringSearch::LinearSearch(Vector subject, size_t index) { const size_t n = subject.length() - pattern_.length(); for (size_t i = index; i <= n; i++) { i = FindFirstCharacter(pattern_, subject, i); - if (i == subject.length()) - return subject.length(); + if (i == subject.length()) return subject.length(); bool matches = true; for (size_t j = 1; j < pattern_.length(); j++) { @@ -341,9 +327,7 @@ size_t StringSearch::LinearSearch( //--------------------------------------------------------------------- template -size_t StringSearch::BoyerMooreSearch( - Vector subject, - size_t start_index) { +size_t StringSearch::BoyerMooreSearch(Vector subject, size_t start_index) { const size_t subject_length = subject.length(); const size_t pattern_length = pattern_.length(); // Only preprocess at most kBMMaxShift last characters of pattern. @@ -377,8 +361,7 @@ size_t StringSearch::BoyerMooreSearch( if (j < start) { // we have matched more than our tables allow us to be smart about. // Fall back on BMH shift. - index += pattern_length - 1 - - CharOccurrence(bad_char_occurrence, last_char); + index += pattern_length - 1 - CharOccurrence(bad_char_occurrence, last_char); } else { int gs_shift = good_suffix_shift[j + 1]; int bc_occ = CharOccurrence(bad_char_occurrence, c); @@ -464,9 +447,7 @@ void StringSearch::PopulateBoyerMooreTable() { //--------------------------------------------------------------------- template -size_t StringSearch::BoyerMooreHorspoolSearch( - Vector subject, - size_t start_index) { +size_t StringSearch::BoyerMooreHorspoolSearch(Vector subject, size_t start_index) { const size_t subject_length = subject.length(); const size_t pattern_length = pattern_.length(); int* char_occurrences = bad_char_shift_table_; @@ -474,9 +455,7 @@ size_t StringSearch::BoyerMooreHorspoolSearch( // How bad we are doing without a good-suffix table. Char last_char = pattern_[pattern_length - 1]; - int last_char_shift = - pattern_length - 1 - - CharOccurrence(char_occurrences, last_char); + int last_char_shift = pattern_length - 1 - CharOccurrence(char_occurrences, last_char); // Perform search size_t index = start_index; // No matches found prior to this index. @@ -548,9 +527,7 @@ void StringSearch::PopulateBoyerMooreHorspoolTable() { // Simple linear search for short patterns, which bails out if the string // isn't found very early in the subject. Upgrades to BoyerMooreHorspool. template -size_t StringSearch::InitialSearch( - Vector subject, - size_t index) { +size_t StringSearch::InitialSearch(Vector subject, size_t index) { const size_t pattern_length = pattern_.length(); // Badness is a count of how much work we have done. When we have // done enough work we decide it's probably worth switching to a better @@ -563,8 +540,7 @@ size_t StringSearch::InitialSearch( badness++; if (badness <= 0) { i = FindFirstCharacter(pattern_, subject, i); - if (i == subject.length()) - return subject.length(); + if (i == subject.length()) return subject.length(); size_t j = 1; do { if (pattern_[j] != subject[i + j]) { @@ -590,9 +566,7 @@ size_t StringSearch::InitialSearch( // object should be constructed once and the Search function then called // for each search. template -size_t SearchString(Vector subject, - Vector pattern, - size_t start_index) { +size_t SearchString(Vector subject, Vector pattern, size_t start_index) { StringSearch search(pattern); return search.Search(subject, start_index); } @@ -603,19 +577,18 @@ namespace workerd::api::node { template size_t SearchString(const Char* haystack, - size_t haystack_length, - const Char* needle, - size_t needle_length, - size_t start_index, - bool is_forward) { + size_t haystack_length, + const Char* needle, + size_t needle_length, + size_t start_index, + bool is_forward) { if (haystack_length < needle_length) return haystack_length; // To do a reverse search (lastIndexOf instead of indexOf) without redundant // code, create two vectors that are reversed views into the input strings. // For example, v_needle[0] would return the *last* character of the needle. // So we're searching for the first instance of rev(needle) in rev(haystack) stringsearch::Vector v_needle(needle, needle_length, is_forward); - stringsearch::Vector v_haystack( - haystack, haystack_length, is_forward); + stringsearch::Vector v_haystack(haystack, haystack_length, is_forward); size_t diff = haystack_length - needle_length; size_t relative_start_index; if (is_forward) { @@ -625,8 +598,7 @@ size_t SearchString(const Char* haystack, } else { relative_start_index = diff - start_index; } - size_t pos = node::stringsearch::SearchString( - v_haystack, v_needle, relative_start_index); + size_t pos = node::stringsearch::SearchString(v_haystack, v_needle, relative_start_index); if (pos == haystack_length) { // not found return pos; @@ -635,10 +607,8 @@ size_t SearchString(const Char* haystack, } template -size_t SearchString(const char* haystack, size_t haystack_length, - const char (&needle)[N]) { - return SearchString( - reinterpret_cast(haystack), haystack_length, +size_t SearchString(const char* haystack, size_t haystack_length, const char (&needle)[N]) { + return SearchString(reinterpret_cast(haystack), haystack_length, reinterpret_cast(needle), N - 1, 0, true); } diff --git a/src/workerd/api/node/buffer-test.c++ b/src/workerd/api/node/buffer-test.c++ index 4959e20c7b6..e807a62ac70 100644 --- a/src/workerd/api/node/buffer-test.c++ +++ b/src/workerd/api/node/buffer-test.c++ @@ -12,8 +12,7 @@ KJ_TEST("node:buffer import without capability") { KJ_EXPECT_LOG(ERROR, "script startup threw exception"); try { - TestFixture fixture({ - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -35,9 +34,7 @@ KJ_TEST("Verify maximum Buffer size") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer, kMaxLength } from 'node:buffer'; try { @@ -67,9 +64,7 @@ KJ_TEST("Create 0-length buffers") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { fetch(request) { @@ -100,9 +95,7 @@ KJ_TEST("new Buffer(string)") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { fetch(request) { @@ -124,9 +117,7 @@ KJ_TEST("Buffer.allocUnsafe(), Buffer.alloc(), Buffer.allocUnsafeSlow()") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -183,9 +174,7 @@ KJ_TEST("Buffer.from(string)") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -207,9 +196,7 @@ KJ_TEST("Buffer.from(string, 'utf8')") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -231,9 +218,7 @@ KJ_TEST("Buffer.from(string, 'ucs2')") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -255,9 +240,7 @@ KJ_TEST("Buffer.from(string, 'hex')") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -285,9 +268,7 @@ KJ_TEST("Buffer.from(string, 'base64')") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -310,9 +291,7 @@ KJ_TEST("new Buffer(string, 'base64')") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -334,9 +313,7 @@ KJ_TEST("Buffer.from(string, 'base64url')") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -358,9 +335,7 @@ KJ_TEST("Buffer.from(Uint8Array)") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -391,9 +366,7 @@ KJ_TEST("new Buffer(Uint8Array)") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -424,9 +397,7 @@ KJ_TEST("Buffer.from(Uint32Array)") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -457,9 +428,7 @@ KJ_TEST("Buffer.from(ArrayBuffer)") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -489,9 +458,7 @@ KJ_TEST("new Buffer(ArrayBuffer)") { flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -515,16 +482,13 @@ KJ_TEST("new Buffer(ArrayBuffer)") { KJ_EXPECT(response.body == "test"); } - KJ_TEST("Buffer.prototype.indexOf/lastIndexOf") { capnp::MallocMessageBuilder message; auto flags = message.initRoot(); flags.setNodeJsCompat(true); flags.setWorkerdExperimental(true); - TestFixture fixture({ - .featureFlags = flags.asReader(), - .mainModuleSource = R"SCRIPT( + TestFixture fixture({.featureFlags = flags.asReader(), .mainModuleSource = R"SCRIPT( import { Buffer } from 'node:buffer'; export default { @@ -563,7 +527,5 @@ KJ_TEST("Buffer.prototype.indexOf/lastIndexOf") { KJ_EXPECT(response.body == "test"); } - } // namespace } // namespace workerd::api - diff --git a/src/workerd/api/node/buffer.c++ b/src/workerd/api/node/buffer.c++ index bc8dad904fc..c432bf1bb2b 100644 --- a/src/workerd/api/node/buffer.c++ +++ b/src/workerd/api/node/buffer.c++ @@ -51,7 +51,7 @@ kj::Array decodeHexTruncated(kj::ArrayPtr text, bool strict = fa } break; } - KJ_IF_SOME(d2, tryFromHexDigit(text[i+1])) { + KJ_IF_SOME(d2, tryFromHexDigit(text[i + 1])) { b |= d2; } else { if (strict) { @@ -65,20 +65,20 @@ kj::Array decodeHexTruncated(kj::ArrayPtr text, bool strict = fa return vec.releaseAsArray(); } -uint32_t writeInto( - jsg::Lock& js, +uint32_t writeInto(jsg::Lock& js, kj::ArrayPtr buffer, jsg::JsString string, uint32_t offset, uint32_t length, Encoding encoding) { auto dest = buffer.slice(offset, kj::min(offset + length, buffer.size())); - if (dest.size() == 0 || string.length(js) == 0) { return 0; } + if (dest.size() == 0 || string.length(js) == 0) { + return 0; + } - static constexpr jsg::JsString::WriteOptions flags = static_cast( - jsg::JsString::MANY_WRITES_EXPECTED | - jsg::JsString::NO_NULL_TERMINATION | - jsg::JsString::REPLACE_INVALID_UTF8); + static constexpr jsg::JsString::WriteOptions flags = + static_cast(jsg::JsString::MANY_WRITES_EXPECTED | + jsg::JsString::NO_NULL_TERMINATION | jsg::JsString::REPLACE_INVALID_UTF8); switch (encoding) { case Encoding::ASCII: @@ -92,8 +92,8 @@ uint32_t writeInto( return result.written; } case Encoding::UTF16LE: { - kj::ArrayPtr buf(reinterpret_cast(dest.begin()), - dest.size() / sizeof(uint16_t)); + kj::ArrayPtr buf( + reinterpret_cast(dest.begin()), dest.size() / sizeof(uint16_t)); auto result = string.writeInto(js, buf, flags); return result.written * sizeof(uint16_t); } @@ -101,17 +101,13 @@ uint32_t writeInto( // Fall-through case Encoding::BASE64URL: { auto str = kj::str(string); - return nbytes::Base64Decode( - dest.asChars().begin(), - dest.size(), - str.begin(), - str.size()); + return nbytes::Base64Decode(dest.asChars().begin(), dest.size(), str.begin(), str.size()); } case Encoding::HEX: { KJ_STACK_ARRAY(kj::byte, buf, string.length(js), 1024, 536870888); static constexpr jsg::JsString::WriteOptions options = - static_cast(jsg::JsString::NO_NULL_TERMINATION | - jsg::JsString::REPLACE_INVALID_UTF8); + static_cast( + jsg::JsString::NO_NULL_TERMINATION | jsg::JsString::REPLACE_INVALID_UTF8); string.writeInto(js, buf, options); auto bytes = decodeHexTruncated(buf, false); auto amountToCopy = kj::min(bytes.size(), dest.size()); @@ -124,17 +120,12 @@ uint32_t writeInto( } kj::Array decodeStringImpl( - jsg::Lock& js, - const jsg::JsString& string, - Encoding encoding, - bool strict = false) { + jsg::Lock& js, const jsg::JsString& string, Encoding encoding, bool strict = false) { auto length = string.length(js); if (length == 0) return kj::Array(); - static constexpr jsg::JsString::WriteOptions options = - static_cast( - jsg::JsString::NO_NULL_TERMINATION | - jsg::JsString::REPLACE_INVALID_UTF8); + static constexpr jsg::JsString::WriteOptions options = static_cast( + jsg::JsString::NO_NULL_TERMINATION | jsg::JsString::REPLACE_INVALID_UTF8); switch (encoding) { case Encoding::ASCII: @@ -164,11 +155,7 @@ kj::Array decodeStringImpl( auto result = string.writeInto(js, buf, options); auto len = result.written; auto dest = kj::heapArray(nbytes::Base64DecodedSize(buf.begin(), len)); - len = nbytes::Base64Decode( - dest.asChars().begin(), - dest.size(), - buf.begin(), - buf.size()); + len = nbytes::Base64Decode(dest.asChars().begin(), dest.size(), buf.begin(), buf.size()); return dest.slice(0, len).attach(kj::mv(dest)); } case Encoding::HEX: { @@ -186,8 +173,7 @@ uint32_t BufferUtil::byteLength(jsg::Lock& js, jsg::JsString str) { return str.utf8Length(js); } -int BufferUtil::compare( - jsg::Lock& js, +int BufferUtil::compare(jsg::Lock& js, kj::Array one, kj::Array two, jsg::Optional maybeOptions) { @@ -212,16 +198,15 @@ int BufferUtil::compare( return 1; else if (ptrOne.size() < ptrTwo.size()) return -1; - else return 0; + else + return 0; } return result > 0 ? 1 : -1; } kj::Array BufferUtil::concat( - jsg::Lock& js, - kj::Array> list, - uint32_t length) { + jsg::Lock& js, kj::Array> list, uint32_t length) { if (length == 0) return kj::Array(); // The Node.js Buffer.concat is interesting in that it doesn't just append @@ -235,7 +220,7 @@ kj::Array BufferUtil::concat( auto dest = kj::heapArray(length); auto view = dest.asPtr(); - for (auto& src : list) { + for (auto& src: list) { if (src.size() == 0) continue; // The amount to copy is the lesser of the remaining space in the destination or // the size of the chunk we're copying. @@ -251,14 +236,11 @@ kj::Array BufferUtil::concat( } kj::Array BufferUtil::decodeString( - jsg::Lock& js, - jsg::JsString string, - EncodingValue encoding) { + jsg::Lock& js, jsg::JsString string, EncodingValue encoding) { return decodeStringImpl(js, string, static_cast(encoding)); } -void BufferUtil::fillImpl( - jsg::Lock& js, +void BufferUtil::fillImpl(jsg::Lock& js, kj::Array buffer, kj::OneOf value, uint32_t start, @@ -293,10 +275,7 @@ namespace { // Computes the offset for starting an indexOf or lastIndexOf search. // Returns either a valid offset in [0...], ie inside the Buffer, // or -1 to signal that there is no possible match. -int32_t indexOfOffset(size_t length, - int32_t offset, - int32_t needle_length, - bool isForward) { +int32_t indexOfOffset(size_t length, int32_t offset, int32_t needle_length, bool isForward) { int32_t len = static_cast(length); if (offset < 0) { if (offset + len >= 0) { @@ -327,8 +306,7 @@ int32_t indexOfOffset(size_t length, } } -jsg::Optional indexOfBuffer( - jsg::Lock& js, +jsg::Optional indexOfBuffer(jsg::Lock& js, kj::ArrayPtr hayStack, jsg::BufferSource needle, int32_t byteOffset, @@ -338,8 +316,7 @@ jsg::Optional indexOfBuffer( auto optOffset = indexOfOffset(hayStack.size(), byteOffset, needle.size(), isForward); if (needle.size() == 0) return optOffset; - if (hayStack.size() == 0 || - optOffset <= -1 || + if (hayStack.size() == 0 || optOffset <= -1 || (isForward && needle.size() + optOffset > hayStack.size()) || needle.size() > hayStack.size()) { return kj::none; @@ -350,22 +327,14 @@ jsg::Optional indexOfBuffer( if (hayStack.size() < 2 || needle.size() < 2) { return kj::none; } - result = SearchString( - reinterpret_cast(hayStack.asChars().begin()), - hayStack.size() / 2, - reinterpret_cast(needle.asArrayPtr().asChars().begin()), - needle.size() / 2, - optOffset / 2, - isForward); + result = SearchString(reinterpret_cast(hayStack.asChars().begin()), + hayStack.size() / 2, + reinterpret_cast(needle.asArrayPtr().asChars().begin()), needle.size() / 2, + optOffset / 2, isForward); result *= 2; } else { - result = SearchString( - hayStack.asBytes().begin(), - hayStack.size(), - needle.asArrayPtr().asBytes().begin(), - needle.size(), - optOffset, - isForward); + result = SearchString(hayStack.asBytes().begin(), hayStack.size(), + needle.asArrayPtr().asBytes().begin(), needle.size(), optOffset, isForward); } if (result == hayStack.size()) return kj::none; @@ -373,8 +342,7 @@ jsg::Optional indexOfBuffer( return result; } -jsg::Optional indexOfString( - jsg::Lock& js, +jsg::Optional indexOfString(jsg::Lock& js, kj::ArrayPtr hayStack, const jsg::JsString& needle, int32_t byteOffset, @@ -385,15 +353,14 @@ jsg::Optional indexOfString( auto decodedNeedle = decodeStringImpl(js, needle, enc); // Round down to the nearest multiple of 2 in case of UCS2 - auto hayStackLength = enc == Encoding::UTF16LE ? hayStack.size() &~ 1 : hayStack.size(); + auto hayStackLength = enc == Encoding::UTF16LE ? hayStack.size() & ~1 : hayStack.size(); auto optOffset = indexOfOffset(hayStackLength, byteOffset, decodedNeedle.size(), isForward); if (decodedNeedle.size() == 0) { return optOffset; } - if (hayStackLength == 0 || - optOffset <= -1 || + if (hayStackLength == 0 || optOffset <= -1 || (isForward && decodedNeedle.size() + optOffset > hayStackLength) || decodedNeedle.size() > hayStackLength) { return kj::none; @@ -405,22 +372,13 @@ jsg::Optional indexOfString( if (hayStack.size() < 2 || decodedNeedle.size() < 2) { return kj::none; } - result = SearchString( - reinterpret_cast(hayStack.asChars().begin()), - hayStack.size() / 2, - reinterpret_cast(decodedNeedle.asChars().begin()), - decodedNeedle.size() / 2, - optOffset / 2, - isForward); + result = SearchString(reinterpret_cast(hayStack.asChars().begin()), + hayStack.size() / 2, reinterpret_cast(decodedNeedle.asChars().begin()), + decodedNeedle.size() / 2, optOffset / 2, isForward); result *= 2; } else { - result = SearchString( - hayStack.asBytes().begin(), - hayStack.size(), - decodedNeedle.asBytes().begin(), - decodedNeedle.size(), - optOffset, - isForward); + result = SearchString(hayStack.asBytes().begin(), hayStack.size(), + decodedNeedle.asBytes().begin(), decodedNeedle.size(), optOffset, isForward); } if (result == hayStackLength) return kj::none; @@ -429,11 +387,7 @@ jsg::Optional indexOfString( } jsg::JsString toStringImpl( - jsg::Lock& js, - kj::ArrayPtr bytes, - uint32_t start, - uint32_t end, - Encoding encoding) { + jsg::Lock& js, kj::ArrayPtr bytes, uint32_t start, uint32_t end, Encoding encoding) { if (end < start) end = start; auto slice = bytes.slice(start, end); if (slice.size() == 0) return js.str(); @@ -454,21 +408,23 @@ jsg::JsString toStringImpl( } case Encoding::UTF16LE: { // TODO(soon): Using just the slice here results in v8 hitting an IsAligned assertion. - auto data = kj::heapArray( - reinterpret_cast(slice.begin()), slice.size() / 2); + auto data = + kj::heapArray(reinterpret_cast(slice.begin()), slice.size() / 2); return js.str(data); } case Encoding::BASE64: { size_t length = simdutf::base64_length_from_binary(slice.size()); auto out = kj::heapArray(length); - simdutf::binary_to_base64(reinterpret_cast(slice.begin()), slice.size(), reinterpret_cast(out.begin())); + simdutf::binary_to_base64(reinterpret_cast(slice.begin()), slice.size(), + reinterpret_cast(out.begin())); return js.str(out); } case Encoding::BASE64URL: { auto options = simdutf::base64_url; size_t length = simdutf::base64_length_from_binary(slice.size(), options); auto out = kj::heapArray(length); - simdutf::binary_to_base64(reinterpret_cast(slice.begin()), slice.size(), reinterpret_cast(out.begin()), options); + simdutf::binary_to_base64(reinterpret_cast(slice.begin()), slice.size(), + reinterpret_cast(out.begin()), options); return js.str(out); } case Encoding::HEX: { @@ -481,8 +437,7 @@ jsg::JsString toStringImpl( } // namespace -jsg::Optional BufferUtil::indexOf( - jsg::Lock& js, +jsg::Optional BufferUtil::indexOf(jsg::Lock& js, kj::Array buffer, kj::OneOf value, int32_t byteOffset, @@ -503,25 +458,27 @@ jsg::Optional BufferUtil::indexOf( void BufferUtil::swap(jsg::Lock& js, kj::Array buffer, int size) { if (buffer.size() <= 1) return; switch (size) { - case 16: { - JSG_REQUIRE(nbytes::SwapBytes16(buffer.asChars().begin(), buffer.size()), Error, "Swap bytes failed"); - break; - } - case 32: { - JSG_REQUIRE(nbytes::SwapBytes32(buffer.asChars().begin(), buffer.size()), Error, "Swap bytes failed"); - break; - } - case 64: { - JSG_REQUIRE(nbytes::SwapBytes64(buffer.asChars().begin(), buffer.size()), Error, "Swap bytes failed"); - break; - } - default: - JSG_FAIL_REQUIRE(Error, "Unreachable"); + case 16: { + JSG_REQUIRE( + nbytes::SwapBytes16(buffer.asChars().begin(), buffer.size()), Error, "Swap bytes failed"); + break; + } + case 32: { + JSG_REQUIRE( + nbytes::SwapBytes32(buffer.asChars().begin(), buffer.size()), Error, "Swap bytes failed"); + break; + } + case 64: { + JSG_REQUIRE( + nbytes::SwapBytes64(buffer.asChars().begin(), buffer.size()), Error, "Swap bytes failed"); + break; + } + default: + JSG_FAIL_REQUIRE(Error, "Unreachable"); } } -jsg::JsString BufferUtil::toString( - jsg::Lock& js, +jsg::JsString BufferUtil::toString(jsg::Lock& js, kj::Array bytes, uint32_t start, uint32_t end, @@ -529,8 +486,7 @@ jsg::JsString BufferUtil::toString( return toStringImpl(js, bytes, start, end, static_cast(encoding)); } -uint32_t BufferUtil::write( - jsg::Lock& js, +uint32_t BufferUtil::write(jsg::Lock& js, kj::Array buffer, jsg::JsString string, uint32_t offset, @@ -582,14 +538,14 @@ uint32_t BufferUtil::write( namespace { inline kj::byte getMissingBytes(kj::ArrayPtr state) { - JSG_REQUIRE(state[BufferUtil::kMissingBytes] <= - BufferUtil::kIncompleteCharactersEnd, Error, "Missing bytes cannot exceed 4"); + JSG_REQUIRE(state[BufferUtil::kMissingBytes] <= BufferUtil::kIncompleteCharactersEnd, Error, + "Missing bytes cannot exceed 4"); return state[BufferUtil::kMissingBytes]; } inline kj::byte getBufferedBytes(kj::ArrayPtr state) { - JSG_REQUIRE(state[BufferUtil::kBufferedBytes] <= - BufferUtil::kIncompleteCharactersEnd, Error, "Buffered bytes cannot exceed 4"); + JSG_REQUIRE(state[BufferUtil::kBufferedBytes] <= BufferUtil::kIncompleteCharactersEnd, Error, + "Buffered bytes cannot exceed 4"); return state[BufferUtil::kBufferedBytes]; } @@ -598,26 +554,23 @@ inline kj::byte* getIncompleteCharacterBuffer(kj::ArrayPtr state) { } inline Encoding getEncoding(kj::ArrayPtr state) { - JSG_REQUIRE(state[BufferUtil::kEncoding] <= static_cast(Encoding::HEX), - Error, "Invalid StringDecoder state"); + JSG_REQUIRE(state[BufferUtil::kEncoding] <= static_cast(Encoding::HEX), Error, + "Invalid StringDecoder state"); return static_cast(state[BufferUtil::kEncoding]); } jsg::JsString getBufferedString(jsg::Lock& js, kj::ArrayPtr state) { JSG_REQUIRE(getBufferedBytes(state) <= BufferUtil::kIncompleteCharactersEnd, Error, - "Invalid StringDecoder state"); - auto ret = toStringImpl(js, state, - BufferUtil::kIncompleteCharactersStart, - BufferUtil::kIncompleteCharactersStart + getBufferedBytes(state), - getEncoding(state)); + "Invalid StringDecoder state"); + auto ret = toStringImpl(js, state, BufferUtil::kIncompleteCharactersStart, + BufferUtil::kIncompleteCharactersStart + getBufferedBytes(state), getEncoding(state)); state[BufferUtil::kBufferedBytes] = 0; return ret; } } // namespace -jsg::JsString BufferUtil::decode(jsg::Lock& js, - kj::Array bytes, - kj::Array state) { +jsg::JsString BufferUtil::decode( + jsg::Lock& js, kj::Array bytes, kj::Array state) { JSG_REQUIRE(state.size() == BufferUtil::kSize, TypeError, "Invalid StringDecoder"); auto enc = getEncoding(state); if (enc == Encoding::ASCII || enc == Encoding::LATIN1 || enc == Encoding::HEX) { @@ -632,8 +585,9 @@ jsg::JsString BufferUtil::decode(jsg::Lock& js, auto nread = bytes.size(); auto data = bytes.begin(); if (getMissingBytes(state) > 0) { - JSG_REQUIRE(getMissingBytes(state) + getBufferedBytes(state) <= - BufferUtil::kIncompleteCharactersEnd, Error, "Invalid StringDecoder state"); + JSG_REQUIRE( + getMissingBytes(state) + getBufferedBytes(state) <= BufferUtil::kIncompleteCharactersEnd, + Error, "Invalid StringDecoder state"); if (enc == Encoding::UTF8) { // For UTF-8, we need special treatment to algin with the V8 decoder: // If an incomplete character is found at a chunk boundary, we use @@ -682,7 +636,7 @@ jsg::JsString BufferUtil::decode(jsg::Lock& js, // This is UTF-8 encoded data and we ended on a non-ASCII UTF-8 byte. // This means we'll need to figure out where the character to which // the byte belongs begins. - for (size_t i = nread - 1; ; --i) { + for (size_t i = nread - 1;; --i) { JSG_REQUIRE(i < nread, Error, "Invalid StringDecoder state"); state[kBufferedBytes]++; if ((data[i] & 0xC0) == 0x80) { @@ -739,8 +693,7 @@ jsg::JsString BufferUtil::decode(jsg::Lock& js, } } else if (enc == Encoding::BASE64 || enc == Encoding::BASE64URL) { state[kBufferedBytes] = nread % 3; - if (state[kBufferedBytes] > 0) - state[kMissingBytes] = 3 - getBufferedBytes(state); + if (state[kBufferedBytes] > 0) state[kMissingBytes] = 3 - getBufferedBytes(state); } if (getBufferedBytes(state) > 0) { @@ -800,16 +753,15 @@ bool BufferUtil::isUtf8(kj::Array buffer) { return simdutf::validate_utf8(buffer.asChars().begin(), buffer.size()); } -kj::Array BufferUtil::transcode(kj::Array source, EncodingValue rawFromEncoding, EncodingValue rawToEncoding) { +kj::Array BufferUtil::transcode( + kj::Array source, EncodingValue rawFromEncoding, EncodingValue rawToEncoding) { auto fromEncoding = static_cast(rawFromEncoding); auto toEncoding = static_cast(rawToEncoding); - JSG_REQUIRE(i18n::canBeTranscoded(fromEncoding) && - i18n::canBeTranscoded(toEncoding), Error, - "Unable to transcode buffer due to unsupported encoding"); + JSG_REQUIRE(i18n::canBeTranscoded(fromEncoding) && i18n::canBeTranscoded(toEncoding), Error, + "Unable to transcode buffer due to unsupported encoding"); return i18n::transcode(source, fromEncoding, toEncoding); } -} // namespace workerd::api::node { - +} // namespace workerd::api::node diff --git a/src/workerd/api/node/buffer.h b/src/workerd/api/node/buffer.h index 042635f114a..641a574cafd 100644 --- a/src/workerd/api/node/buffer.h +++ b/src/workerd/api/node/buffer.h @@ -26,46 +26,42 @@ class BufferUtil final: public jsg::Object { }; int compare(jsg::Lock& js, - kj::Array one, - kj::Array two, - jsg::Optional maybeOptions); + kj::Array one, + kj::Array two, + jsg::Optional maybeOptions); - kj::Array concat(jsg::Lock& js, - kj::Array> list, - uint32_t length); + kj::Array concat(jsg::Lock& js, kj::Array> list, uint32_t length); - kj::Array decodeString(jsg::Lock& js, - jsg::JsString string, - EncodingValue encoding); + kj::Array decodeString(jsg::Lock& js, jsg::JsString string, EncodingValue encoding); void fillImpl(jsg::Lock& js, - kj::Array buffer, - kj::OneOf value, - uint32_t start, - uint32_t end, - jsg::Optional encoding); + kj::Array buffer, + kj::OneOf value, + uint32_t start, + uint32_t end, + jsg::Optional encoding); jsg::Optional indexOf(jsg::Lock& js, - kj::Array buffer, - kj::OneOf value, - int32_t byteOffset, - EncodingValue encoding, - bool isForward); + kj::Array buffer, + kj::OneOf value, + int32_t byteOffset, + EncodingValue encoding, + bool isForward); void swap(jsg::Lock& js, kj::Array buffer, int size); jsg::JsString toString(jsg::Lock& js, - kj::Array bytes, - uint32_t start, - uint32_t end, - EncodingValue encoding); + kj::Array bytes, + uint32_t start, + uint32_t end, + EncodingValue encoding); uint32_t write(jsg::Lock& js, - kj::Array buffer, - jsg::JsString string, - uint32_t offset, - uint32_t length, - EncodingValue encoding); + kj::Array buffer, + jsg::JsString string, + uint32_t offset, + uint32_t length, + EncodingValue encoding); enum NativeDecoderFields { kIncompleteCharactersStart = 0, @@ -76,15 +72,12 @@ class BufferUtil final: public jsg::Object { kSize = 7, }; - jsg::JsString decode(jsg::Lock& js, - kj::Array bytes, - kj::Array state); + jsg::JsString decode(jsg::Lock& js, kj::Array bytes, kj::Array state); jsg::JsString flush(jsg::Lock& js, kj::Array state); bool isAscii(kj::Array bytes); bool isUtf8(kj::Array bytes); - kj::Array transcode(kj::Array source, - EncodingValue rawFromEncoding, - EncodingValue rawToEncoding); + kj::Array transcode( + kj::Array source, EncodingValue rawFromEncoding, EncodingValue rawToEncoding); JSG_RESOURCE_TYPE(BufferUtil) { JSG_METHOD(byteLength); @@ -114,8 +107,6 @@ class BufferUtil final: public jsg::Object { } }; -#define EW_NODE_BUFFER_ISOLATE_TYPES \ - api::node::BufferUtil, \ - api::node::BufferUtil::CompareOptions +#define EW_NODE_BUFFER_ISOLATE_TYPES api::node::BufferUtil, api::node::BufferUtil::CompareOptions } // namespace workerd::api::node diff --git a/src/workerd/api/node/crypto-keys.c++ b/src/workerd/api/node/crypto-keys.c++ index adc08e58989..befb34836d3 100644 --- a/src/workerd/api/node/crypto-keys.c++ +++ b/src/workerd/api/node/crypto-keys.c++ @@ -17,13 +17,14 @@ namespace { class SecretKey final: public CryptoKey::Impl { public: explicit SecretKey(kj::Array keyData) - : Impl(true, CryptoKeyUsageSet::privateKeyMask() | - CryptoKeyUsageSet::publicKeyMask()), + : Impl(true, CryptoKeyUsageSet::privateKeyMask() | CryptoKeyUsageSet::publicKeyMask()), keyData(kj::mv(keyData)) {} - kj::StringPtr getAlgorithmName() const override { return "secret"_kj; } + kj::StringPtr getAlgorithmName() const override { + return "secret"_kj; + } CryptoKey::AlgorithmVariant getAlgorithm(jsg::Lock& js) const override { - return CryptoKey::KeyAlgorithm { .name = "secret"_kj }; + return CryptoKey::KeyAlgorithm{.name = "secret"_kj}; } bool equals(const CryptoKey::Impl& other) const override final { @@ -32,13 +33,12 @@ public: bool equals(const kj::Array& other) const override final { return keyData.size() == other.size() && - CRYPTO_memcmp(keyData.begin(), other.begin(), keyData.size()) == 0; + CRYPTO_memcmp(keyData.begin(), other.begin(), keyData.size()) == 0; } SubtleCrypto::ExportKeyData exportKey(kj::StringPtr format) const override final { - JSG_REQUIRE(format == "raw" || format == "jwk", DOMNotSupportedError, - getAlgorithmName(), " key only supports exporting \"raw\" & \"jwk\", not \"", format, - "\"."); + JSG_REQUIRE(format == "raw" || format == "jwk", DOMNotSupportedError, getAlgorithmName(), + " key only supports exporting \"raw\" & \"jwk\", not \"", format, "\"."); if (format == "jwk") { SubtleCrypto::JsonWebKey jwk; @@ -51,8 +51,12 @@ public: return kj::heapArray(keyData.asPtr()); } - kj::StringPtr jsgGetMemoryName() const override { return "SecretKey"; } - size_t jsgGetMemorySelfSize() const override { return sizeof(SecretKey); } + kj::StringPtr jsgGetMemoryName() const override { + return "SecretKey"; + } + size_t jsgGetMemorySelfSize() const override { + return sizeof(SecretKey); + } void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const override { tracker.trackFieldWithSize("keyData", keyData.size()); } @@ -63,9 +67,7 @@ private: } // namespace kj::OneOf, SubtleCrypto::JsonWebKey> CryptoImpl::exportKey( - jsg::Lock& js, - jsg::Ref key, - jsg::Optional options) { + jsg::Lock& js, jsg::Ref key, jsg::Optional options) { JSG_REQUIRE(key->getExtractable(), TypeError, "Unable to export non-extractable key"); auto& opts = JSG_REQUIRE_NONNULL(options, TypeError, "Options must be an object"); @@ -113,8 +115,8 @@ kj::StringPtr CryptoImpl::getAsymmetricKeyType(jsg::Lock& js, jsg::RefgetType() != "secret"_kj, TypeError, - "Secret key does not have an asymmetric type"); + JSG_REQUIRE( + key->getType() != "secret"_kj, TypeError, "Secret key does not have an asymmetric type"); auto found = mapping.find(key->getAlgorithmName()); if (found != mapping.end()) { return found->second; @@ -127,14 +129,11 @@ jsg::Ref CryptoImpl::createSecretKey(jsg::Lock& js, kj::Array CryptoImpl::createPrivateKey( - jsg::Lock& js, - CreateAsymmetricKeyOptions options) { + jsg::Lock& js, CreateAsymmetricKeyOptions options) { KJ_UNIMPLEMENTED("not implemented"); } -jsg::Ref CryptoImpl::createPublicKey( - jsg::Lock& js, - CreateAsymmetricKeyOptions options) { +jsg::Ref CryptoImpl::createPublicKey(jsg::Lock& js, CreateAsymmetricKeyOptions options) { KJ_UNIMPLEMENTED("not implemented"); } diff --git a/src/workerd/api/node/crypto.c++ b/src/workerd/api/node/crypto.c++ index 7694e69cdd2..5342d10c1e9 100644 --- a/src/workerd/api/node/crypto.c++ +++ b/src/workerd/api/node/crypto.c++ @@ -12,10 +12,10 @@ namespace workerd::api::node { kj::Array CryptoImpl::getHkdf(kj::String hash, - kj::Array key, - kj::Array salt, - kj::Array info, - uint32_t length) { + kj::Array key, + kj::Array salt, + kj::Array info, + uint32_t length) { // The Node.js version of the HKDF is a bit different from the Web Crypto API // version. For one, the length here specifies the number of bytes, whereas // in Web Crypto the length is expressed in the number of bits. Second, the @@ -39,18 +39,18 @@ kj::Array CryptoImpl::getHkdf(kj::String hash, // practical sense is that the maximum value of length is 255 * hash size for // the specific hash algorithm specified. static constexpr size_t kMaxDigestMultiplier = 255; - JSG_REQUIRE(length <= EVP_MD_size(digest) * kMaxDigestMultiplier, RangeError, - "Invalid Hkdf key length"); + JSG_REQUIRE( + length <= EVP_MD_size(digest) * kMaxDigestMultiplier, RangeError, "Invalid Hkdf key length"); return JSG_REQUIRE_NONNULL(hkdf(length, digest, key, salt, info), Error, "Hkdf failed"); } kj::Array CryptoImpl::getPbkdf(jsg::Lock& js, - kj::Array password, - kj::Array salt, - uint32_t num_iterations, - uint32_t keylen, - kj::String name) { + kj::Array password, + kj::Array salt, + uint32_t num_iterations, + uint32_t keylen, + kj::String name) { // The Node.js version of the PBKDF2 is a bit different from the Web Crypto API. // For one, the Node.js implementation allows for a broader range of possible // digest algorithms whereas the Web Crypto API only allows for a few specific ones. @@ -59,7 +59,7 @@ kj::Array CryptoImpl::getPbkdf(jsg::Lock& js, ClearErrorOnReturn clearErrorOnReturn; const EVP_MD* digest = EVP_get_digestbyname(name.begin()); JSG_REQUIRE(digest != nullptr, TypeError, "Invalid Pbkdf2 digest: ", name, - internalDescribeOpensslErrors()); + internalDescribeOpensslErrors()); JSG_REQUIRE(password.size() <= INT32_MAX, RangeError, "Pbkdf2 failed: password is too large"); JSG_REQUIRE(salt.size() <= INT32_MAX, RangeError, "Pbkdf2 failed: salt is too large"); @@ -68,24 +68,24 @@ kj::Array CryptoImpl::getPbkdf(jsg::Lock& js, checkPbkdfLimits(js, num_iterations); // Both pass and salt may be zero length here. - return JSG_REQUIRE_NONNULL(pbkdf2(keylen, num_iterations, digest, password, salt), - Error, "Pbkdf2 failed"); + return JSG_REQUIRE_NONNULL( + pbkdf2(keylen, num_iterations, digest, password, salt), Error, "Pbkdf2 failed"); } kj::Array CryptoImpl::getScrypt(jsg::Lock& js, - kj::Array password, - kj::Array salt, - uint32_t N, - uint32_t r, - uint32_t p, - uint32_t maxmem, - uint32_t keylen) { + kj::Array password, + kj::Array salt, + uint32_t N, + uint32_t r, + uint32_t p, + uint32_t maxmem, + uint32_t keylen) { ClearErrorOnReturn clearErrorOnReturn; JSG_REQUIRE(password.size() <= INT32_MAX, RangeError, "Scrypt failed: password is too large"); JSG_REQUIRE(salt.size() <= INT32_MAX, RangeError, "Scrypt failed: salt is too large"); - return JSG_REQUIRE_NONNULL(scrypt(keylen, N, r, p, maxmem, password, salt), - Error, "Scrypt failed"); + return JSG_REQUIRE_NONNULL( + scrypt(keylen, N, r, p, maxmem, password, salt), Error, "Scrypt failed"); } bool CryptoImpl::verifySpkac(kj::Array input) { @@ -100,9 +100,10 @@ kj::Maybe> CryptoImpl::exportChallenge(kj::Array CryptoImpl::randomPrime(uint32_t size, bool safe, - jsg::Optional> add_buf, - jsg::Optional> rem_buf) { +kj::Array CryptoImpl::randomPrime(uint32_t size, + bool safe, + jsg::Optional> add_buf, + jsg::Optional> rem_buf) { return workerd::api::randomPrime(size, safe, add_buf.map([](kj::Array& buf) { return buf.asPtr(); }), rem_buf.map([](kj::Array& buf) { return buf.asPtr(); })); @@ -114,8 +115,7 @@ bool CryptoImpl::checkPrimeSync(kj::Array bufferView, uint32_t num_che // ====================================================================================== jsg::Ref CryptoImpl::HmacHandle::constructor( - kj::String algorithm, - kj::OneOf, jsg::Ref> key) { + kj::String algorithm, kj::OneOf, jsg::Ref> key) { KJ_SWITCH_ONEOF(key) { KJ_CASE_ONEOF(key_data, kj::Array) { return jsg::alloc(HmacContext(algorithm, key_data.asPtr())); @@ -137,9 +137,7 @@ kj::ArrayPtr CryptoImpl::HmacHandle::digest() { } kj::Array CryptoImpl::HmacHandle::oneshot( - kj::String algorithm, - CryptoImpl::HmacHandle::KeyParam key, - kj::Array data) { + kj::String algorithm, CryptoImpl::HmacHandle::KeyParam key, kj::Array data) { KJ_SWITCH_ONEOF(key) { KJ_CASE_ONEOF(key_data, kj::Array) { HmacContext ctx(algorithm, key_data.asPtr()); @@ -183,9 +181,7 @@ void CryptoImpl::HashHandle::visitForMemoryInfo(jsg::MemoryTracker& tracker) con } kj::Array CryptoImpl::HashHandle::oneshot( - kj::String algorithm, - kj::Array data, - kj::Maybe xofLen) { + kj::String algorithm, kj::Array data, kj::Maybe xofLen) { HashContext ctx(algorithm, xofLen); ctx.update(data); return kj::heapArray(ctx.digest()); @@ -199,12 +195,13 @@ jsg::Ref CryptoImpl::DiffieHellmanGroupHandle(k } jsg::Ref CryptoImpl::DiffieHellmanHandle::constructor( - jsg::Lock &js, kj::OneOf, int> sizeOrKey, + jsg::Lock& js, + kj::OneOf, int> sizeOrKey, kj::OneOf, int> generator) { return jsg::alloc(DiffieHellman(sizeOrKey, generator)); } -CryptoImpl::DiffieHellmanHandle::DiffieHellmanHandle(DiffieHellman dh) : dh(kj::mv(dh)) { +CryptoImpl::DiffieHellmanHandle::DiffieHellmanHandle(DiffieHellman dh): dh(kj::mv(dh)) { verifyError = JSG_REQUIRE_NONNULL(this->dh.check(), Error, "DiffieHellman init failed"); }; @@ -240,6 +237,8 @@ kj::Array CryptoImpl::DiffieHellmanHandle::generateKeys() { return dh.generateKeys(); } -int CryptoImpl::DiffieHellmanHandle::getVerifyError() { return verifyError; } +int CryptoImpl::DiffieHellmanHandle::getVerifyError() { + return verifyError; +} } // namespace workerd::api::node diff --git a/src/workerd/api/node/crypto.h b/src/workerd/api/node/crypto.h index d89f4ab3a31..7e9dc2a5e9c 100644 --- a/src/workerd/api/node/crypto.h +++ b/src/workerd/api/node/crypto.h @@ -16,127 +16,128 @@ class CryptoImpl final: public jsg::Object { public: // DH class DiffieHellmanHandle final: public jsg::Object { - public: - DiffieHellmanHandle(DiffieHellman dh); - - static jsg::Ref constructor( - jsg::Lock& js, - kj::OneOf, int> sizeOrKey, - kj::OneOf, int> generator); - - void setPrivateKey(kj::Array key); - void setPublicKey(kj::Array key); - kj::Array getPublicKey(); - kj::Array getPrivateKey(); - kj::Array getGenerator(); - kj::Array getPrime(); - kj::Array computeSecret(kj::Array key); - kj::Array generateKeys(); - int getVerifyError(); - - JSG_RESOURCE_TYPE(DiffieHellmanHandle) { - JSG_METHOD(setPublicKey); - JSG_METHOD(setPrivateKey); - JSG_METHOD(getPublicKey); - JSG_METHOD(getPrivateKey); - JSG_METHOD(getGenerator); - JSG_METHOD(getPrime); - JSG_METHOD(computeSecret); - JSG_METHOD(generateKeys); - JSG_METHOD(getVerifyError); - }; - - private: - DiffieHellman dh; - int verifyError; + public: + DiffieHellmanHandle(DiffieHellman dh); + + static jsg::Ref constructor(jsg::Lock& js, + kj::OneOf, int> sizeOrKey, + kj::OneOf, int> generator); + + void setPrivateKey(kj::Array key); + void setPublicKey(kj::Array key); + kj::Array getPublicKey(); + kj::Array getPrivateKey(); + kj::Array getGenerator(); + kj::Array getPrime(); + kj::Array computeSecret(kj::Array key); + kj::Array generateKeys(); + int getVerifyError(); + + JSG_RESOURCE_TYPE(DiffieHellmanHandle) { + JSG_METHOD(setPublicKey); + JSG_METHOD(setPrivateKey); + JSG_METHOD(getPublicKey); + JSG_METHOD(getPrivateKey); + JSG_METHOD(getGenerator); + JSG_METHOD(getPrime); + JSG_METHOD(computeSecret); + JSG_METHOD(generateKeys); + JSG_METHOD(getVerifyError); + }; + + private: + DiffieHellman dh; + int verifyError; }; jsg::Ref DiffieHellmanGroupHandle(kj::String name); // Primes - kj::Array randomPrime(uint32_t size, bool safe, - jsg::Optional> add, jsg::Optional> rem); + kj::Array randomPrime(uint32_t size, + bool safe, + jsg::Optional> add, + jsg::Optional> rem); bool checkPrimeSync(kj::Array bufferView, uint32_t num_checks); // Hash class HashHandle final: public jsg::Object { - public: - HashHandle(HashContext ctx) : ctx(kj::mv(ctx)) {} + public: + HashHandle(HashContext ctx): ctx(kj::mv(ctx)) {} - static jsg::Ref constructor(kj::String algorithm, kj::Maybe xofLen); - static kj::Array oneshot(kj::String algorithm, kj::Array data, - kj::Maybe xofLen); + static jsg::Ref constructor(kj::String algorithm, kj::Maybe xofLen); + static kj::Array oneshot( + kj::String algorithm, kj::Array data, kj::Maybe xofLen); - jsg::Ref copy(kj::Maybe xofLen); - int update(kj::Array data); - kj::ArrayPtr digest(); + jsg::Ref copy(kj::Maybe xofLen); + int update(kj::Array data); + kj::ArrayPtr digest(); - JSG_RESOURCE_TYPE(HashHandle) { - JSG_METHOD(update); - JSG_METHOD(digest); - JSG_METHOD(copy); - JSG_STATIC_METHOD(oneshot); - }; + JSG_RESOURCE_TYPE(HashHandle) { + JSG_METHOD(update); + JSG_METHOD(digest); + JSG_METHOD(copy); + JSG_STATIC_METHOD(oneshot); + }; - void visitForMemoryInfo(jsg::MemoryTracker& tracker) const; + void visitForMemoryInfo(jsg::MemoryTracker& tracker) const; - private: - HashContext ctx; + private: + HashContext ctx; }; // Hmac class HmacHandle final: public jsg::Object { - public: - using KeyParam = kj::OneOf, jsg::Ref>; + public: + using KeyParam = kj::OneOf, jsg::Ref>; - HmacHandle(HmacContext ctx) : ctx(kj::mv(ctx)) {}; + HmacHandle(HmacContext ctx): ctx(kj::mv(ctx)) {}; - static jsg::Ref constructor(kj::String algorithm, KeyParam key); + static jsg::Ref constructor(kj::String algorithm, KeyParam key); - // Efficiently implement one-shot hmac that avoids multiple calls - // across the C++/JS boundary. - static kj::Array oneshot(kj::String algorithm, KeyParam key, - kj::Array data); + // Efficiently implement one-shot hmac that avoids multiple calls + // across the C++/JS boundary. + static kj::Array oneshot( + kj::String algorithm, KeyParam key, kj::Array data); - int update(kj::Array data); - kj::ArrayPtr digest(); + int update(kj::Array data); + kj::ArrayPtr digest(); - JSG_RESOURCE_TYPE(HmacHandle) { - JSG_METHOD(update); - JSG_METHOD(digest); - JSG_STATIC_METHOD(oneshot); - }; + JSG_RESOURCE_TYPE(HmacHandle) { + JSG_METHOD(update); + JSG_METHOD(digest); + JSG_STATIC_METHOD(oneshot); + }; - void visitForMemoryInfo(jsg::MemoryTracker& tracker) const; + void visitForMemoryInfo(jsg::MemoryTracker& tracker) const; - private: - HmacContext ctx; + private: + HmacContext ctx; }; // Hkdf kj::Array getHkdf(kj::String hash, - kj::Array key, - kj::Array salt, - kj::Array info, - uint32_t length); + kj::Array key, + kj::Array salt, + kj::Array info, + uint32_t length); // Pbkdf2 kj::Array getPbkdf(jsg::Lock& js, - kj::Array password, - kj::Array salt, - uint32_t num_iterations, - uint32_t keylen, - kj::String name); + kj::Array password, + kj::Array salt, + uint32_t num_iterations, + uint32_t keylen, + kj::String name); // Scrypt kj::Array getScrypt(jsg::Lock& js, - kj::Array password, - kj::Array salt, - uint32_t N, - uint32_t r, - uint32_t p, - uint32_t maxmem, - uint32_t keylen); + kj::Array password, + kj::Array salt, + uint32_t N, + uint32_t r, + uint32_t p, + uint32_t maxmem, + uint32_t keylen); // Keys struct KeyExportOptions { @@ -159,24 +160,24 @@ class CryptoImpl final: public jsg::Object { jsg::Optional primeLength; jsg::Optional generator; jsg::Optional groupName; - jsg::Optional paramEncoding; // one of either 'named' or 'explicit' + jsg::Optional paramEncoding; // one of either 'named' or 'explicit' jsg::Optional publicKeyEncoding; jsg::Optional privateKeyEncoding; JSG_STRUCT(modulusLength, - publicExponent, - hashAlgorithm, - mgf1HashAlgorithm, - saltLength, - divisorLength, - namedCurve, - prime, - primeLength, - generator, - groupName, - paramEncoding, - publicKeyEncoding, - privateKeyEncoding); + publicExponent, + hashAlgorithm, + mgf1HashAlgorithm, + saltLength, + divisorLength, + namedCurve, + prime, + primeLength, + generator, + groupName, + paramEncoding, + publicKeyEncoding, + privateKeyEncoding); }; struct CreateAsymmetricKeyOptions { @@ -196,9 +197,7 @@ class CryptoImpl final: public jsg::Object { CryptoImpl(jsg::Lock&, const jsg::Url&) {} kj::OneOf, SubtleCrypto::JsonWebKey> exportKey( - jsg::Lock& js, - jsg::Ref key, - jsg::Optional options); + jsg::Lock& js, jsg::Ref key, jsg::Optional options); bool equals(jsg::Lock& js, jsg::Ref key, jsg::Ref otherKey); @@ -246,14 +245,9 @@ class CryptoImpl final: public jsg::Object { } }; -#define EW_NODE_CRYPTO_ISOLATE_TYPES \ - api::node::CryptoImpl, \ - api::node::CryptoImpl::DiffieHellmanHandle, \ - api::node::CryptoImpl::HashHandle, \ - api::node::CryptoImpl::HmacHandle, \ - api::node::CryptoImpl::KeyExportOptions, \ - api::node::CryptoImpl::GenerateKeyPairOptions, \ - api::node::CryptoImpl::CreateAsymmetricKeyOptions, \ - EW_CRYPTO_X509_ISOLATE_TYPES +#define EW_NODE_CRYPTO_ISOLATE_TYPES \ + api::node::CryptoImpl, api::node::CryptoImpl::DiffieHellmanHandle, \ + api::node::CryptoImpl::HashHandle, api::node::CryptoImpl::HmacHandle, \ + api::node::CryptoImpl::KeyExportOptions, api::node::CryptoImpl::GenerateKeyPairOptions, \ + api::node::CryptoImpl::CreateAsymmetricKeyOptions, EW_CRYPTO_X509_ISOLATE_TYPES } // namespace workerd::api::node - diff --git a/src/workerd/api/node/diagnostics-channel.c++ b/src/workerd/api/node/diagnostics-channel.c++ index 44487c5cc82..663dd66436c 100644 --- a/src/workerd/api/node/diagnostics-channel.c++ +++ b/src/workerd/api/node/diagnostics-channel.c++ @@ -9,46 +9,48 @@ jsg::Value Channel::identityTransform(jsg::Lock& js, jsg::Value value) { return value.addRef(js); } -Channel::Channel(jsg::Name name) : name(kj::mv(name)) {} +Channel::Channel(jsg::Name name): name(kj::mv(name)) {} -const jsg::Name& Channel::getName() const { return name; } +const jsg::Name& Channel::getName() const { + return name; +} bool Channel::hasSubscribers() { return subscribers.size() != 0; } void Channel::publish(jsg::Lock& js, jsg::Value message) { - for (auto& sub : subscribers) { + for (auto& sub: subscribers) { sub.value(js, message.addRef(js), name.clone(js)); } auto& context = IoContext::current(); KJ_IF_SOME(tracer, context.getWorkerTracer()) { - jsg::Serializer ser(js, jsg::Serializer::Options { - .omitHeader = false, - }); + jsg::Serializer ser(js, + jsg::Serializer::Options{ + .omitHeader = false, + }); ser.write(js, jsg::JsValue(message.getHandle(js))); auto tmp = ser.release(); - JSG_REQUIRE(tmp.sharedArrayBuffers.size() == 0 && - tmp.transferredArrayBuffers.size() == 0, Error, - "Diagnostic events cannot be published with SharedArrayBuffer or " - "transferred ArrayBuffer instances"); + JSG_REQUIRE(tmp.sharedArrayBuffers.size() == 0 && tmp.transferredArrayBuffers.size() == 0, + Error, + "Diagnostic events cannot be published with SharedArrayBuffer or " + "transferred ArrayBuffer instances"); tracer.addDiagnosticChannelEvent(context.now(), name.toString(js), kj::mv(tmp.data)); } } void Channel::subscribe(jsg::Lock& js, jsg::Identified callback) { - subscribers.upsert(kj::mv(callback.identity), - kj::mv(callback.unwrapped), - [&](auto&, auto&&) {}); + subscribers.upsert(kj::mv(callback.identity), kj::mv(callback.unwrapped), [&](auto&, auto&&) {}); } void Channel::unsubscribe(jsg::Lock& js, jsg::Identified callback) { subscribers.erase(callback.identity); } -void Channel::bindStore(jsg::Lock& js, jsg::Ref als, - jsg::Optional maybeTransform) { +void Channel::bindStore(jsg::Lock& js, + jsg::Ref als, + jsg::Optional maybeTransform) { auto key = als->getKey(); KJ_IF_SOME(entry, stores.find(*key)) { KJ_IF_SOME(transform, maybeTransform) { @@ -62,17 +64,11 @@ void Channel::bindStore(jsg::Lock& js, jsg::Ref als, } KJ_IF_SOME(transform, maybeTransform) { - stores.insert({ - .key = kj::mv(key), - .transform = kj::mv(transform) - }); + stores.insert({.key = kj::mv(key), .transform = kj::mv(transform)}); } else { - stores.insert({ - .key = kj::mv(key), - .transform = [](jsg::Lock& js, jsg::Value value) { - return identityTransform(js, kj::mv(value)); - } - }); + stores.insert({.key = kj::mv(key), .transform = [](jsg::Lock& js, jsg::Value value) { + return identityTransform(js, kj::mv(value)); + }}); } } @@ -81,14 +77,14 @@ void Channel::unbindStore(jsg::Lock& js, jsg::Ref als) { stores.eraseMatch(*key); } -v8::Local Channel::runStores( - jsg::Lock& js, jsg::Value message, +v8::Local Channel::runStores(jsg::Lock& js, + jsg::Value message, jsg::Function(jsg::Arguments)> callback, jsg::Optional> maybeReceiver, jsg::Arguments args) { auto storageScopes = KJ_MAP(store, stores) { - return kj::heap(js, *store.key, - store.transform(js, message.addRef(js))); + return kj::heap( + js, *store.key, store.transform(js, message.addRef(js))); }; publish(js, message.addRef(js)); @@ -102,7 +98,7 @@ v8::Local Channel::runStores( } void Channel::visitForGc(jsg::GcVisitor& visitor) { - for (auto& sub : subscribers) { + for (auto& sub: subscribers) { visitor.visit(sub.key, sub.value); } for (auto& store: stores) { @@ -116,15 +112,13 @@ bool DiagnosticsChannelModule::hasSubscribers(jsg::Lock& js, jsg::Name name) { }).orDefault(false); } -void DiagnosticsChannelModule::subscribe(jsg::Lock& js, - jsg::Name name, - jsg::Identified callback) { +void DiagnosticsChannelModule::subscribe( + jsg::Lock& js, jsg::Name name, jsg::Identified callback) { channel(js, kj::mv(name))->subscribe(js, kj::mv(callback)); } -void DiagnosticsChannelModule::unsubscribe(jsg::Lock& js, - jsg::Name name, - jsg::Identified callback) { +void DiagnosticsChannelModule::unsubscribe( + jsg::Lock& js, jsg::Name name, jsg::Identified callback) { KJ_IF_SOME(channel, tryGetChannel(js, name)) { channel.unsubscribe(js, kj::mv(callback)); } @@ -132,9 +126,11 @@ void DiagnosticsChannelModule::unsubscribe(jsg::Lock& js, jsg::Ref DiagnosticsChannelModule::channel(jsg::Lock& js, jsg::Name channel) { kj::String name = channel.toString(js); - return channels.findOrCreate(name, [&, channel=kj::mv(channel)]() mutable -> - kj::HashMap>::Entry{ - return { kj::mv(name), jsg::alloc(kj::mv(channel)) }; + return channels + .findOrCreate(name, + [&, channel = kj::mv(channel)]() mutable + -> kj::HashMap>::Entry { + return {kj::mv(name), jsg::alloc(kj::mv(channel))}; }).addRef(); } @@ -145,24 +141,24 @@ kj::Maybe DiagnosticsChannelModule::tryGetChannel(jsg::Lock& js, jsg:: } void DiagnosticsChannelModule::visitForGc(jsg::GcVisitor& visitor) { - for (auto& channel : channels) { + for (auto& channel: channels) { visitor.visit(channel.value); } } void Channel::visitForMemoryInfo(jsg::MemoryTracker& tracker) const { tracker.trackField("name", name); - for (auto& sub : subscribers) { + for (auto& sub: subscribers) { tracker.trackField("subscribers", sub.key); tracker.trackField("subscribers", sub.value); } - for (auto& store : stores) { + for (auto& store: stores) { tracker.trackField("stores", store); } } void DiagnosticsChannelModule::visitForMemoryInfo(jsg::MemoryTracker& tracker) const { - for (auto& channel : channels) { + for (auto& channel: channels) { tracker.trackField(nullptr, channel.value); } } diff --git a/src/workerd/api/node/diagnostics-channel.h b/src/workerd/api/node/diagnostics-channel.h index 0d121aaf7d7..80cd3831eb8 100644 --- a/src/workerd/api/node/diagnostics-channel.h +++ b/src/workerd/api/node/diagnostics-channel.h @@ -7,7 +7,7 @@ namespace workerd::api::node { -class Channel : public jsg::Object { +class Channel: public jsg::Object { public: using MessageCallback = jsg::Function; using TransformCallback = jsg::Function; @@ -20,11 +20,11 @@ class Channel : public jsg::Object { void publish(jsg::Lock& js, jsg::Value message); void subscribe(jsg::Lock& js, jsg::Identified callback); void unsubscribe(jsg::Lock& js, jsg::Identified callback); - void bindStore(jsg::Lock& js, jsg::Ref als, - jsg::Optional maybeTransform); + void bindStore(jsg::Lock& js, + jsg::Ref als, + jsg::Optional maybeTransform); void unbindStore(jsg::Lock& js, jsg::Ref als); - v8::Local runStores( - jsg::Lock& js, + v8::Local runStores(jsg::Lock& js, jsg::Value message, jsg::Function(jsg::Arguments)> callback, jsg::Optional> maybeReceiver, @@ -45,7 +45,6 @@ class Channel : public jsg::Object { void visitForMemoryInfo(jsg::MemoryTracker& tracker) const; private: - struct StoreEntry { kj::Own key; TransformCallback transform; @@ -75,7 +74,7 @@ class Channel : public jsg::Object { void visitForGc(jsg::GcVisitor& visitor); }; -class DiagnosticsChannelModule : public jsg::Object { +class DiagnosticsChannelModule: public jsg::Object { public: DiagnosticsChannelModule() = default; DiagnosticsChannelModule(jsg::Lock&, const jsg::Url&) {} @@ -83,7 +82,8 @@ class DiagnosticsChannelModule : public jsg::Object { bool hasSubscribers(jsg::Lock& js, jsg::Name name); jsg::Ref channel(jsg::Lock& js, jsg::Name name); void subscribe(jsg::Lock& js, jsg::Name name, jsg::Identified callback); - void unsubscribe(jsg::Lock& js, jsg::Name name, jsg::Identified callback); + void unsubscribe( + jsg::Lock& js, jsg::Name name, jsg::Identified callback); // TODO: Support tracing channels JSG_RESOURCE_TYPE(DiagnosticsChannelModule) { @@ -104,8 +104,7 @@ class DiagnosticsChannelModule : public jsg::Object { void visitForGc(jsg::GcVisitor& visitor); }; -#define EW_NODE_DIAGNOSTICCHANNEL_ISOLATE_TYPES \ - api::node::Channel, \ - api::node::DiagnosticsChannelModule +#define EW_NODE_DIAGNOSTICCHANNEL_ISOLATE_TYPES \ + api::node::Channel, api::node::DiagnosticsChannelModule } // namespace workerd::api::node diff --git a/src/workerd/api/node/i18n.c++ b/src/workerd/api/node/i18n.c++ index 5eb6f878477..a4ad5a201f6 100644 --- a/src/workerd/api/node/i18n.c++ +++ b/src/workerd/api/node/i18n.c++ @@ -32,7 +32,7 @@ namespace { // An isolate has a 128mb memory limit. const int ISOLATE_LIMIT = 134217728; -struct ConverterDisposer : public kj::Disposer { +struct ConverterDisposer: public kj::Disposer { static const ConverterDisposer INSTANCE; void disposeImpl(void* pointer) const override { ucnv_close(reinterpret_cast(pointer)); @@ -43,24 +43,24 @@ const ConverterDisposer ConverterDisposer::INSTANCE; const char* getEncodingName(Encoding input) { switch (input) { - case Encoding::ASCII: - return "us-ascii"; - case Encoding::LATIN1: - return "iso8859-1"; - case Encoding::UTF16LE: - return "utf16le"; - case Encoding::UTF8: - return "utf-8"; - default: - KJ_UNREACHABLE; + case Encoding::ASCII: + return "us-ascii"; + case Encoding::LATIN1: + return "iso8859-1"; + case Encoding::UTF16LE: + return "utf16le"; + case Encoding::UTF8: + return "utf-8"; + default: + KJ_UNREACHABLE; } } -typedef kj::Maybe> (*TranscodeImpl)(kj::ArrayPtr source, - Encoding fromEncoding, Encoding toEncoding); +typedef kj::Maybe> (*TranscodeImpl)( + kj::ArrayPtr source, Encoding fromEncoding, Encoding toEncoding); -kj::Maybe> TranscodeDefault(kj::ArrayPtr source, - Encoding fromEncoding, Encoding toEncoding) { +kj::Maybe> TranscodeDefault( + kj::ArrayPtr source, Encoding fromEncoding, Encoding toEncoding) { Converter to(toEncoding); auto substitute = kj::str(kj::repeat('?', to.minCharSize())); to.setSubstituteChars(substitute); @@ -74,7 +74,7 @@ kj::Maybe> TranscodeDefault(kj::ArrayPtr source, const char* source_ = source.asChars().begin(); UErrorCode status{}; ucnv_convertEx(to.conv(), from.conv(), &target, target + limit, &source_, source_ + source.size(), - nullptr, nullptr, nullptr, nullptr, true, true, &status); + nullptr, nullptr, nullptr, nullptr, true, true, &status); if (U_SUCCESS(status)) { return out.slice(0, target - out.asChars().begin()).attach(kj::mv(out)); } @@ -82,8 +82,8 @@ kj::Maybe> TranscodeDefault(kj::ArrayPtr source, return kj::none; } -kj::Maybe> TranscodeLatin1ToUTF16(kj::ArrayPtr source, - Encoding fromEncoding, Encoding toEncoding) { +kj::Maybe> TranscodeLatin1ToUTF16( + kj::ArrayPtr source, Encoding fromEncoding, Encoding toEncoding) { auto length_in_chars = source.size() * sizeof(UChar); // Workers are limited to 128MB so this isn't actually a realistic concern, but sanity check. JSG_REQUIRE(length_in_chars <= ISOLATE_LIMIT, Error, "Source buffer is too large to transcode"); @@ -101,14 +101,14 @@ kj::Maybe> TranscodeLatin1ToUTF16(kj::ArrayPtr sou return destbuf.slice(0, actual_length).asBytes().attach(kj::mv(destbuf)); } -kj::Maybe> TranscodeFromUTF16(kj::ArrayPtr source, - Encoding fromEncoding, Encoding toEncoding) { +kj::Maybe> TranscodeFromUTF16( + kj::ArrayPtr source, Encoding fromEncoding, Encoding toEncoding) { Converter to(toEncoding); auto substitute = kj::str(kj::repeat('?', to.minCharSize())); to.setSubstituteChars(substitute); - auto utf16_input = kj::arrayPtr(reinterpret_cast(source.begin()), - source.size() / sizeof(UChar)); + auto utf16_input = kj::arrayPtr( + reinterpret_cast(source.begin()), source.size() / sizeof(UChar)); const auto limit = utf16_input.size() * to.maxCharSize(); @@ -118,7 +118,7 @@ kj::Maybe> TranscodeFromUTF16(kj::ArrayPtr source, auto destbuf = kj::heapArray(limit); UErrorCode status{}; auto len = ucnv_fromUChars(to.conv(), destbuf.asChars().begin(), destbuf.size(), - utf16_input.begin(), utf16_input.size(), &status); + utf16_input.begin(), utf16_input.size(), &status); if (U_SUCCESS(status)) { return destbuf.slice(0, len).asBytes().attach(kj::mv(destbuf)); @@ -127,13 +127,13 @@ kj::Maybe> TranscodeFromUTF16(kj::ArrayPtr source, return kj::none; } -kj::Maybe> TranscodeUTF16FromUTF8(kj::ArrayPtr source, - Encoding fromEncoding, Encoding toEncoding) { +kj::Maybe> TranscodeUTF16FromUTF8( + kj::ArrayPtr source, Encoding fromEncoding, Encoding toEncoding) { size_t expected_utf16_length = simdutf::utf16_length_from_utf8(source.asChars().begin(), source.size()); // Workers are limited to 128MB so this isn't actually a realistic concern, but sanity check. JSG_REQUIRE(expected_utf16_length <= ISOLATE_LIMIT, Error, - "Expected UTF-16le length is too large to transcode"); + "Expected UTF-16le length is too large to transcode"); auto destbuf = kj::heapArray(expected_utf16_length); size_t actual_length = @@ -148,8 +148,8 @@ kj::Maybe> TranscodeUTF16FromUTF8(kj::ArrayPtr sou return destbuf.asBytes().attach(kj::mv(destbuf)); } -kj::Maybe> TranscodeUTF8FromUTF16(kj::ArrayPtr source, - Encoding fromEncoding, Encoding toEncoding) { +kj::Maybe> TranscodeUTF8FromUTF16( + kj::ArrayPtr source, Encoding fromEncoding, Encoding toEncoding) { JSG_REQUIRE(source.size() % 2 == 0, Error, "UTF-16le input size should be multiple of 2"); auto utf16_input = kj::arrayPtr(reinterpret_cast(source.begin()), source.size() / 2); @@ -158,12 +158,12 @@ kj::Maybe> TranscodeUTF8FromUTF16(kj::ArrayPtr sou // Workers are limited to 128MB so this isn't actually a realistic concern, but sanity check. JSG_REQUIRE(expected_utf8_length <= ISOLATE_LIMIT, Error, - "Expected UTF-8 length is too large to transcode"); + "Expected UTF-8 length is too large to transcode"); auto destbuf = kj::heapArray(expected_utf8_length); - size_t actual_length = simdutf::convert_utf16le_to_utf8(utf16_input.begin(), utf16_input.size(), - destbuf.asChars().begin()); + size_t actual_length = simdutf::convert_utf16le_to_utf8( + utf16_input.begin(), utf16_input.size(), destbuf.asChars().begin()); JSG_REQUIRE(actual_length == expected_utf8_length, Error, "Expected UTF8 length mismatch"); // simdutf returns 0 for invalid UTF-8 value. @@ -174,7 +174,7 @@ kj::Maybe> TranscodeUTF8FromUTF16(kj::ArrayPtr sou return destbuf.asBytes().attach(kj::mv(destbuf)); } -} // namespace +} // namespace Converter::Converter(Encoding encoding, kj::StringPtr substitute) { UErrorCode status = U_ZERO_ERROR; @@ -213,8 +213,8 @@ void Converter::setSubstituteChars(kj::StringPtr sub) { } } -kj::Array transcode(kj::ArrayPtr source, Encoding fromEncoding, - Encoding toEncoding) { +kj::Array transcode( + kj::ArrayPtr source, Encoding fromEncoding, Encoding toEncoding) { // Optimization: // If both encodings are same, we just return a copy of the buffer. if (fromEncoding == toEncoding) { @@ -225,37 +225,37 @@ kj::Array transcode(kj::ArrayPtr source, Encoding fromEncodi TranscodeImpl transcode_function = &TranscodeDefault; switch (fromEncoding) { - case Encoding::ASCII: - case Encoding::LATIN1: - if (toEncoding == Encoding::UTF16LE) { - transcode_function = &TranscodeLatin1ToUTF16; - } - break; - case Encoding::UTF8: - if (toEncoding == Encoding::UTF16LE) { - transcode_function = &TranscodeUTF16FromUTF8; - } - break; - case Encoding::UTF16LE: - switch (toEncoding) { - case Encoding::UTF16LE: - transcode_function = &TranscodeDefault; + case Encoding::ASCII: + case Encoding::LATIN1: + if (toEncoding == Encoding::UTF16LE) { + transcode_function = &TranscodeLatin1ToUTF16; + } break; case Encoding::UTF8: - transcode_function = &TranscodeUTF8FromUTF16; + if (toEncoding == Encoding::UTF16LE) { + transcode_function = &TranscodeUTF16FromUTF8; + } + break; + case Encoding::UTF16LE: + switch (toEncoding) { + case Encoding::UTF16LE: + transcode_function = &TranscodeDefault; + break; + case Encoding::UTF8: + transcode_function = &TranscodeUTF8FromUTF16; + break; + default: + transcode_function = &TranscodeFromUTF16; + } break; default: - transcode_function = &TranscodeFromUTF16; - } - break; - default: - JSG_FAIL_REQUIRE(Error, "Invalid encoding passed to transcode"); + JSG_FAIL_REQUIRE(Error, "Invalid encoding passed to transcode"); } - return JSG_REQUIRE_NONNULL(transcode_function(source, fromEncoding, toEncoding), Error, - "Unable to transcode buffer"); + return JSG_REQUIRE_NONNULL( + transcode_function(source, fromEncoding, toEncoding), Error, "Unable to transcode buffer"); } -} // namespace i18n +} // namespace i18n -} // namespace workerd::api::node +} // namespace workerd::api::node diff --git a/src/workerd/api/node/i18n.h b/src/workerd/api/node/i18n.h index 604cda5497a..2a5e6c8204b 100644 --- a/src/workerd/api/node/i18n.h +++ b/src/workerd/api/node/i18n.h @@ -31,13 +31,13 @@ namespace i18n { // Used by BufferUtil::transcode. constexpr bool canBeTranscoded(Encoding encoding) noexcept { switch (encoding) { - case Encoding::ASCII: - case Encoding::LATIN1: - case Encoding::UTF16LE: - case Encoding::UTF8: - return true; - default: - return false; + case Encoding::ASCII: + case Encoding::LATIN1: + case Encoding::UTF16LE: + case Encoding::UTF8: + return true; + default: + return false; } } @@ -56,11 +56,11 @@ class Converter final { kj::Own conv_; }; -kj::Array transcode(kj::ArrayPtr source, Encoding fromEncoding, - Encoding toEncoding); +kj::Array transcode( + kj::ArrayPtr source, Encoding fromEncoding, Encoding toEncoding); -} // namespace i18n +} // namespace i18n -} // namespace workerd::api::node +} // namespace workerd::api::node KJ_DECLARE_NON_POLYMORPHIC(UConverter) diff --git a/src/workerd/api/node/node.h b/src/workerd/api/node/node.h index 78bc24114ff..375ddde26ae 100644 --- a/src/workerd/api/node/node.h +++ b/src/workerd/api/node/node.h @@ -18,7 +18,7 @@ namespace workerd::api::node { // To be exposed only as an internal module for use by other built-ins. // TODO(later): Consider moving out of node.h when needed for other // built-ins -class CompatibilityFlags : public jsg::Object { +class CompatibilityFlags: public jsg::Object { public: CompatibilityFlags() = default; CompatibilityFlags(jsg::Lock&, const jsg::Url&) {} @@ -29,21 +29,20 @@ class CompatibilityFlags : public jsg::Object { // literal values on the instance... auto dynamic = capnp::toDynamic(flags); auto schema = dynamic.getSchema(); - for (auto field : schema.getFields()) { + for (auto field: schema.getFields()) { registry.template registerReadonlyInstanceProperty( - field.getProto().getName(), - dynamic.get(field).as()); + field.getProto().getName(), dynamic.get(field).as()); } } }; -#define NODEJS_MODULES(V) \ - V(CompatibilityFlags, "workerd:compatibility-flags") \ - V(AsyncHooksModule, "node-internal:async_hooks") \ - V(BufferUtil, "node-internal:buffer") \ - V(CryptoImpl, "node-internal:crypto") \ - V(UtilModule, "node-internal:util") \ - V(DiagnosticsChannelModule, "node-internal:diagnostics_channel") \ +#define NODEJS_MODULES(V) \ + V(CompatibilityFlags, "workerd:compatibility-flags") \ + V(AsyncHooksModule, "node-internal:async_hooks") \ + V(BufferUtil, "node-internal:buffer") \ + V(CryptoImpl, "node-internal:crypto") \ + V(UtilModule, "node-internal:util") \ + V(DiagnosticsChannelModule, "node-internal:diagnostics_channel") \ V(ZlibUtil, "node-internal:zlib") // Add to the NODEJS_MODULES_EXPERIMENTAL list any currently in-development @@ -56,9 +55,8 @@ bool isNodeJsCompatEnabled(auto featureFlags) { } template -void registerNodeJsCompatModules( - Registry& registry, auto featureFlags) { -#define V(T, N) \ +void registerNodeJsCompatModules(Registry& registry, auto featureFlags) { +#define V(T, N) \ registry.template addBuiltinModule(N, workerd::jsg::ModuleRegistry::Type::INTERNAL); NODEJS_MODULES(V) @@ -82,7 +80,7 @@ void registerNodeJsCompatModules( // need to register the `node:async_hooks` module from the bundle. if (!nodeJsCompatEnabled && featureFlags.getNodeJsAls()) { jsg::Bundle::Reader reader = NODE_BUNDLE; - for (auto module : reader.getModules()) { + for (auto module: reader.getModules()) { auto specifier = module.getName(); if (specifier == "node:async_hooks") { KJ_DASSERT(module.getType() == jsg::ModuleType::BUILTIN); @@ -96,8 +94,9 @@ template kj::Own getInternalNodeJsCompatModuleBundle(auto featureFlags) { jsg::modules::ModuleBundle::BuiltinBuilder builder( jsg::modules::ModuleBundle::BuiltinBuilder::Type::BUILTIN_ONLY); -#define V(M, N) static const auto k##M##Specifier = N##_url; \ - builder.addObject(k##M##Specifier); +#define V(M, N) \ + static const auto k##M##Specifier = N##_url; \ + builder.addObject(k##M##Specifier); NODEJS_MODULES(V) if (featureFlags.getWorkerdExperimental()) { NODEJS_MODULES_EXPERIMENTAL(V) @@ -116,7 +115,7 @@ kj::Own getExternalNodeJsCompatModuleBundle(auto fea // The AsyncLocalStorage API can be enabled independently of the rest // of the nodejs_compat layer. jsg::Bundle::Reader reader = NODE_BUNDLE; - for (auto module : reader.getModules()) { + for (auto module: reader.getModules()) { auto specifier = module.getName(); if (specifier == "node:async_hooks") { KJ_DASSERT(module.getType() == jsg::ModuleType::BUILTIN); @@ -132,12 +131,7 @@ kj::Own getExternalNodeJsCompatModuleBundle(auto fea #undef NODEJS_MODULES } // namespace workerd::api::node -#define EW_NODE_ISOLATE_TYPES \ - api::node::CompatibilityFlags, \ - EW_NODE_BUFFER_ISOLATE_TYPES, \ - EW_NODE_CRYPTO_ISOLATE_TYPES, \ - EW_NODE_DIAGNOSTICCHANNEL_ISOLATE_TYPES, \ - EW_NODE_ASYNCHOOKS_ISOLATE_TYPES, \ - EW_NODE_UTIL_ISOLATE_TYPES, \ - EW_NODE_ZLIB_ISOLATE_TYPES - +#define EW_NODE_ISOLATE_TYPES \ + api::node::CompatibilityFlags, EW_NODE_BUFFER_ISOLATE_TYPES, EW_NODE_CRYPTO_ISOLATE_TYPES, \ + EW_NODE_DIAGNOSTICCHANNEL_ISOLATE_TYPES, EW_NODE_ASYNCHOOKS_ISOLATE_TYPES, \ + EW_NODE_UTIL_ISOLATE_TYPES, EW_NODE_ZLIB_ISOLATE_TYPES diff --git a/src/workerd/api/node/util.c++ b/src/workerd/api/node/util.c++ index e42ef018b8b..53d52df987d 100644 --- a/src/workerd/api/node/util.c++ +++ b/src/workerd/api/node/util.c++ @@ -7,7 +7,7 @@ namespace workerd::api::node { -MIMEParams::MIMEParams(kj::Maybe mimeType) : mimeType(mimeType) {} +MIMEParams::MIMEParams(kj::Maybe mimeType): mimeType(mimeType) {} // Oddly, Node.js allows creating MIMEParams directly but it's not actually // functional. But, to match, we'll go ahead and allow it. @@ -37,8 +37,7 @@ bool MIMEParams::has(kj::String name) { void MIMEParams::set(kj::String name, kj::String value) { KJ_IF_SOME(inner, mimeType) { - JSG_REQUIRE(inner.addParam(name, value), TypeError, - "Not a valid MIME parameter"); + JSG_REQUIRE(inner.addParam(name, value), TypeError, "Not a valid MIME parameter"); } } @@ -52,37 +51,31 @@ kj::String MIMEParams::toString() { jsg::Ref MIMEParams::entries(jsg::Lock&) { kj::Vector> vec; KJ_IF_SOME(inner, mimeType) { - for (const auto& entry : inner.params()) { + for (const auto& entry: inner.params()) { vec.add(kj::arr(kj::str(entry.key), kj::str(entry.value))); } } - return jsg::alloc(IteratorState> { - vec.releaseAsArray() - }); + return jsg::alloc(IteratorState>{vec.releaseAsArray()}); } jsg::Ref MIMEParams::keys(jsg::Lock&) { kj::Vector vec; KJ_IF_SOME(inner, mimeType) { - for (const auto& entry : inner.params()) { + for (const auto& entry: inner.params()) { vec.add(kj::str(entry.key)); } } - return jsg::alloc(IteratorState { - vec.releaseAsArray() - }); + return jsg::alloc(IteratorState{vec.releaseAsArray()}); } jsg::Ref MIMEParams::values(jsg::Lock&) { kj::Vector vec; KJ_IF_SOME(inner, mimeType) { - for (const auto& entry : inner.params()) { + for (const auto& entry: inner.params()) { vec.add(kj::str(entry.value)); } } - return jsg::alloc(IteratorState { - vec.releaseAsArray() - }); + return jsg::alloc(IteratorState{vec.releaseAsArray()}); } MIMEType::MIMEType(MimeType inner) @@ -95,8 +88,8 @@ MIMEType::~MIMEType() noexcept(false) { } jsg::Ref MIMEType::constructor(kj::String input) { - auto parsed = JSG_REQUIRE_NONNULL(MimeType::tryParse(input), TypeError, - "Not a valid MIME type: ", input); + auto parsed = + JSG_REQUIRE_NONNULL(MimeType::tryParse(input), TypeError, "Not a valid MIME type: ", input); return jsg::alloc(kj::mv(parsed)); } @@ -128,11 +121,10 @@ kj::String MIMEType::toString() { return inner.toString(); } -jsg::JsArray UtilModule::getOwnNonIndexProperties(jsg::Lock& js, jsg::JsObject value, - int filter) { +jsg::JsArray UtilModule::getOwnNonIndexProperties(jsg::Lock& js, jsg::JsObject value, int filter) { auto propertyFilter = static_cast(filter); - return value.getPropertyNames(js, jsg::KeyCollectionFilter::OWN_ONLY, propertyFilter, - jsg::IndexFilter::SKIP_INDICES); + return value.getPropertyNames( + js, jsg::KeyCollectionFilter::OWN_ONLY, propertyFilter, jsg::IndexFilter::SKIP_INDICES); } jsg::Optional UtilModule::getPromiseDetails(jsg::JsValue value) { @@ -140,9 +132,9 @@ jsg::Optional UtilModule::getPromiseDetails(jsg::JsV auto state = promise.state(); if (state != jsg::PromiseState::PENDING) { auto result = promise.result(); - return PromiseDetails { .state = state, .result = result }; + return PromiseDetails{.state = state, .result = result}; } else { - return PromiseDetails { .state = state, .result = kj::none }; + return PromiseDetails{.state = state, .result = kj::none}; } } @@ -150,32 +142,32 @@ jsg::Optional UtilModule::getProxyDetails(jsg::JsValue auto proxy = KJ_UNWRAP_OR_RETURN(value.tryCast(), kj::none); auto target = proxy.target(); auto handler = proxy.handler(); - return ProxyDetails { .target = target, .handler = handler }; + return ProxyDetails{.target = target, .handler = handler}; } jsg::Optional UtilModule::previewEntries(jsg::JsValue value) { auto object = KJ_UNWRAP_OR_RETURN(value.tryCast(), kj::none); bool isKeyValue; auto entries = object.previewEntries(&isKeyValue); - return PreviewedEntries { .entries = entries, .isKeyValue = isKeyValue }; + return PreviewedEntries{.entries = entries, .isKeyValue = isKeyValue}; } jsg::JsString UtilModule::getConstructorName(jsg::Lock& js, jsg::JsObject value) { return js.str(value.getConstructorName()); } -#define V(Type) bool UtilModule::is##Type(jsg::JsValue value) { return value.is##Type(); }; - JS_UTIL_IS_TYPES(V) +#define V(Type) \ + bool UtilModule::is##Type(jsg::JsValue value) { \ + return value.is##Type(); \ + }; +JS_UTIL_IS_TYPES(V) #undef V bool UtilModule::isAnyArrayBuffer(jsg::JsValue value) { return value.isArrayBuffer() || value.isSharedArrayBuffer(); } bool UtilModule::isBoxedPrimitive(jsg::JsValue value) { - return value.isNumberObject() || - value.isStringObject() || - value.isBooleanObject() || - value.isBigIntObject() || - value.isSymbolObject(); + return value.isNumberObject() || value.isStringObject() || value.isBooleanObject() || + value.isBigIntObject() || value.isSymbolObject(); } jsg::Name UtilModule::getResourceTypeInspect(jsg::Lock& js) { @@ -194,10 +186,9 @@ jsg::JsValue UtilModule::getBuiltinModule(jsg::Lock& js, kj::String specifier) { if (registry == nullptr) return js.undefined(); auto path = kj::Path::parse(specifier); - KJ_IF_SOME(info, registry->resolve(js, path, kj::none, - jsg::ModuleRegistry::ResolveOption::BUILTIN_ONLY, - jsg::ModuleRegistry::ResolveMethod::IMPORT, - rawSpecifier.asPtr())) { + KJ_IF_SOME(info, + registry->resolve(js, path, kj::none, jsg::ModuleRegistry::ResolveOption::BUILTIN_ONLY, + jsg::ModuleRegistry::ResolveMethod::IMPORT, rawSpecifier.asPtr())) { auto module = info.module.getHandle(js); jsg::instantiateModule(js, module); auto handle = jsg::check(module->Evaluate(js.v8Context())); diff --git a/src/workerd/api/node/util.h b/src/workerd/api/node/util.h index 738c1e0a968..b5c403b58ef 100644 --- a/src/workerd/api/node/util.h +++ b/src/workerd/api/node/util.h @@ -29,19 +29,14 @@ class MIMEParams final: public jsg::Object { void set(kj::String name, kj::String value); kj::String toString(); - JSG_ITERATOR(EntryIterator, entries, - kj::Array, - IteratorState>, - iteratorNext>); - JSG_ITERATOR(KeyIterator, keys, - kj::String, - IteratorState, - iteratorNext); - JSG_ITERATOR(ValueIterator, - values, - kj::String, - IteratorState, - iteratorNext); + JSG_ITERATOR(EntryIterator, + entries, + kj::Array, + IteratorState>, + iteratorNext>); + JSG_ITERATOR(KeyIterator, keys, kj::String, IteratorState, iteratorNext); + JSG_ITERATOR( + ValueIterator, values, kj::String, IteratorState, iteratorNext); JSG_RESOURCE_TYPE(MIMEParams) { JSG_METHOD_NAMED(delete, delete_); @@ -110,44 +105,44 @@ class MIMEType final: public jsg::Object { jsg::Ref params; }; -#define JS_UTIL_IS_TYPES(V) \ - V(ArrayBufferView) \ - V(ArgumentsObject) \ - V(ArrayBuffer) \ - V(AsyncFunction) \ - V(BigInt64Array) \ - V(BigIntObject) \ - V(BigUint64Array) \ - V(BooleanObject) \ - V(DataView) \ - V(Date) \ - V(External) \ - V(Float32Array) \ - V(Float64Array) \ - V(GeneratorFunction) \ - V(GeneratorObject) \ - V(Int8Array) \ - V(Int16Array) \ - V(Int32Array) \ - V(Map) \ - V(MapIterator) \ - V(ModuleNamespaceObject) \ - V(NativeError) \ - V(NumberObject) \ - V(Promise) \ - V(Proxy) \ - V(RegExp) \ - V(Set) \ - V(SetIterator) \ - V(SharedArrayBuffer) \ - V(StringObject) \ - V(SymbolObject) \ - V(TypedArray) \ - V(Uint8Array) \ - V(Uint8ClampedArray) \ - V(Uint16Array) \ - V(Uint32Array) \ - V(WeakMap) \ +#define JS_UTIL_IS_TYPES(V) \ + V(ArrayBufferView) \ + V(ArgumentsObject) \ + V(ArrayBuffer) \ + V(AsyncFunction) \ + V(BigInt64Array) \ + V(BigIntObject) \ + V(BigUint64Array) \ + V(BooleanObject) \ + V(DataView) \ + V(Date) \ + V(External) \ + V(Float32Array) \ + V(Float64Array) \ + V(GeneratorFunction) \ + V(GeneratorObject) \ + V(Int8Array) \ + V(Int16Array) \ + V(Int32Array) \ + V(Map) \ + V(MapIterator) \ + V(ModuleNamespaceObject) \ + V(NativeError) \ + V(NumberObject) \ + V(Promise) \ + V(Proxy) \ + V(RegExp) \ + V(Set) \ + V(SetIterator) \ + V(SharedArrayBuffer) \ + V(StringObject) \ + V(SymbolObject) \ + V(TypedArray) \ + V(Uint8Array) \ + V(Uint8ClampedArray) \ + V(Uint16Array) \ + V(Uint32Array) \ + V(WeakMap) \ V(WeakSet) class UtilModule final: public jsg::Object { @@ -169,7 +164,7 @@ class UtilModule final: public jsg::Object { static constexpr int kRejected = jsg::PromiseState::REJECTED; struct PromiseDetails { - int state; // TODO: can we make this a `jsg::PromiseState` + int state; // TODO: can we make this a `jsg::PromiseState` jsg::Optional result; JSG_STRUCT(state, result); @@ -221,9 +216,9 @@ class UtilModule final: public jsg::Object { JSG_METHOD(previewEntries); JSG_METHOD(getConstructorName); - #define V(Type) JSG_METHOD(is##Type); +#define V(Type) JSG_METHOD(is##Type); JS_UTIL_IS_TYPES(V) - #undef V +#undef V JSG_METHOD(isAnyArrayBuffer); JSG_METHOD(isBoxedPrimitive); @@ -231,18 +226,12 @@ class UtilModule final: public jsg::Object { } }; -#define EW_NODE_UTIL_ISOLATE_TYPES \ - api::node::UtilModule, \ - api::node::UtilModule::PromiseDetails, \ - api::node::UtilModule::ProxyDetails, \ - api::node::UtilModule::PreviewedEntries, \ - api::node::MIMEType, \ - api::node::MIMEParams, \ - api::node::MIMEParams::EntryIterator, \ - api::node::MIMEParams::ValueIterator, \ - api::node::MIMEParams::KeyIterator, \ - api::node::MIMEParams::EntryIterator::Next, \ - api::node::MIMEParams::ValueIterator::Next, \ - api::node::MIMEParams::KeyIterator::Next +#define EW_NODE_UTIL_ISOLATE_TYPES \ + api::node::UtilModule, api::node::UtilModule::PromiseDetails, \ + api::node::UtilModule::ProxyDetails, api::node::UtilModule::PreviewedEntries, \ + api::node::MIMEType, api::node::MIMEParams, api::node::MIMEParams::EntryIterator, \ + api::node::MIMEParams::ValueIterator, api::node::MIMEParams::KeyIterator, \ + api::node::MIMEParams::EntryIterator::Next, api::node::MIMEParams::ValueIterator::Next, \ + api::node::MIMEParams::KeyIterator::Next } // namespace workerd::api::node diff --git a/src/workerd/api/node/zlib-util.c++ b/src/workerd/api/node/zlib-util.c++ index 567d4062d74..f94f1618cd5 100644 --- a/src/workerd/api/node/zlib-util.c++ +++ b/src/workerd/api/node/zlib-util.c++ @@ -8,4 +8,4 @@ uint32_t ZlibUtil::crc32Sync(kj::Array data, uint32_t value) { // Note: Bytef is defined in zlib.h return crc32(value, reinterpret_cast(data.begin()), data.size()); } -} // namespace workerd::api::node +} // namespace workerd::api::node diff --git a/src/workerd/api/node/zlib-util.h b/src/workerd/api/node/zlib-util.h index c5ec664e291..56f0f707949 100644 --- a/src/workerd/api/node/zlib-util.h +++ b/src/workerd/api/node/zlib-util.h @@ -14,7 +14,7 @@ namespace workerd::api::node { // Implements utilities in support of the Node.js Zlib -class ZlibUtil final : public jsg::Object { +class ZlibUtil final: public jsg::Object { public: ZlibUtil() = default; ZlibUtil(jsg::Lock&, const jsg::Url&) {} @@ -35,7 +35,7 @@ class ZlibUtil final : public jsg::Object { static constexpr auto Z_DEFAULT_WINDOWBITS = 15; using ZlibModeValue = uint8_t; - enum class ZlibMode: ZlibModeValue { + enum class ZlibMode : ZlibModeValue { NONE, DEFLATE, INFLATE, @@ -89,8 +89,10 @@ class ZlibUtil final : public jsg::Object { JSG_STATIC_CONSTANT_NAMED(CONST_DEFLATERAW, static_cast(ZlibMode::DEFLATERAW)); JSG_STATIC_CONSTANT_NAMED(CONST_INFLATERAW, static_cast(ZlibMode::INFLATERAW)); JSG_STATIC_CONSTANT_NAMED(CONST_UNZIP, static_cast(ZlibMode::UNZIP)); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODE, static_cast(ZlibMode::BROTLI_DECODE)); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_ENCODE, static_cast(ZlibMode::BROTLI_ENCODE)); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODE, static_cast(ZlibMode::BROTLI_DECODE)); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_ENCODE, static_cast(ZlibMode::BROTLI_ENCODE)); JSG_STATIC_CONSTANT_NAMED(CONST_Z_MIN_WINDOWBITS, Z_MIN_WINDOWBITS); JSG_STATIC_CONSTANT_NAMED(CONST_Z_MAX_WINDOWBITS, Z_MAX_WINDOWBITS); @@ -127,80 +129,80 @@ class ZlibUtil final : public jsg::Object { JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_MIN_INPUT_BLOCK_BITS, BROTLI_MIN_INPUT_BLOCK_BITS); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_MAX_INPUT_BLOCK_BITS, BROTLI_MAX_INPUT_BLOCK_BITS); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING, - BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING); + BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_SIZE_HINT, BROTLI_PARAM_SIZE_HINT); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_LARGE_WINDOW, BROTLI_PARAM_LARGE_WINDOW); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_NPOSTFIX, BROTLI_PARAM_NPOSTFIX); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_NDIRECT, BROTLI_PARAM_NDIRECT); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_RESULT_ERROR, BROTLI_DECODER_RESULT_ERROR); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_RESULT_SUCCESS, BROTLI_DECODER_RESULT_SUCCESS); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT, - BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT, - BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT, BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT, BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION, - BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_PARAM_LARGE_WINDOW, - BROTLI_DECODER_PARAM_LARGE_WINDOW); + BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_PARAM_LARGE_WINDOW, BROTLI_DECODER_PARAM_LARGE_WINDOW); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_NO_ERROR, BROTLI_DECODER_NO_ERROR); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_SUCCESS, BROTLI_DECODER_SUCCESS); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_NEEDS_MORE_INPUT, - BROTLI_DECODER_NEEDS_MORE_INPUT); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_NEEDS_MORE_OUTPUT, - BROTLI_DECODER_NEEDS_MORE_OUTPUT); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_NEEDS_MORE_INPUT, BROTLI_DECODER_NEEDS_MORE_INPUT); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_NEEDS_MORE_OUTPUT, BROTLI_DECODER_NEEDS_MORE_OUTPUT); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE, - BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_RESERVED, - BROTLI_DECODER_ERROR_FORMAT_RESERVED); + BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_FORMAT_RESERVED, BROTLI_DECODER_ERROR_FORMAT_RESERVED); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE, - BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE); + BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET, - BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET); + BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME, - BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_CL_SPACE, - BROTLI_DECODER_ERROR_FORMAT_CL_SPACE); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE, - BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE); + BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_FORMAT_CL_SPACE, BROTLI_DECODER_ERROR_FORMAT_CL_SPACE); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE, BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT, - BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT); + BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1, - BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1); + BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2, - BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_TRANSFORM, - BROTLI_DECODER_ERROR_FORMAT_TRANSFORM); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_DICTIONARY, - BROTLI_DECODER_ERROR_FORMAT_DICTIONARY); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS, - BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_PADDING_1, - BROTLI_DECODER_ERROR_FORMAT_PADDING_1); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_PADDING_2, - BROTLI_DECODER_ERROR_FORMAT_PADDING_2); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_DISTANCE, - BROTLI_DECODER_ERROR_FORMAT_DISTANCE); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET, - BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_INVALID_ARGUMENTS, - BROTLI_DECODER_ERROR_INVALID_ARGUMENTS); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES, - BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS, - BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP, - BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1, - BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2, - BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2); + BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_FORMAT_TRANSFORM, BROTLI_DECODER_ERROR_FORMAT_TRANSFORM); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_FORMAT_DICTIONARY, BROTLI_DECODER_ERROR_FORMAT_DICTIONARY); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS, BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_FORMAT_PADDING_1, BROTLI_DECODER_ERROR_FORMAT_PADDING_1); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_FORMAT_PADDING_2, BROTLI_DECODER_ERROR_FORMAT_PADDING_2); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_FORMAT_DISTANCE, BROTLI_DECODER_ERROR_FORMAT_DISTANCE); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET, BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_INVALID_ARGUMENTS, BROTLI_DECODER_ERROR_INVALID_ARGUMENTS); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS, BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES, - BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES); - JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_UNREACHABLE, - BROTLI_DECODER_ERROR_UNREACHABLE); + BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES); + JSG_STATIC_CONSTANT_NAMED( + CONST_BROTLI_DECODER_ERROR_UNREACHABLE, BROTLI_DECODER_ERROR_UNREACHABLE); }; }; #define EW_NODE_ZLIB_ISOLATE_TYPES api::node::ZlibUtil -} // namespace workerd::api::node +} // namespace workerd::api::node diff --git a/src/workerd/api/pyodide/pyodide.c++ b/src/workerd/api/pyodide/pyodide.c++ index adb9404d437..9383242d973 100644 --- a/src/workerd/api/pyodide/pyodide.c++ +++ b/src/workerd/api/pyodide/pyodide.c++ @@ -9,23 +9,26 @@ namespace workerd::api::pyodide { // singleton that owns bundle -const kj::Maybe PyodideBundleManager::getPyodideBundle(kj::StringPtr version) const { +const kj::Maybe PyodideBundleManager::getPyodideBundle( + kj::StringPtr version) const { KJ_IF_SOME(t, bundles.lockShared()->find(version)) { return t.bundle; } return kj::none; } -void PyodideBundleManager::setPyodideBundleData(kj::String version, kj::Array data) const { - auto wordArray = kj::arrayPtr(reinterpret_cast(data.begin()), - data.size() / sizeof(capnp::word)); +void PyodideBundleManager::setPyodideBundleData( + kj::String version, kj::Array data) const { + auto wordArray = kj::arrayPtr( + reinterpret_cast(data.begin()), data.size() / sizeof(capnp::word)); auto messageReader = kj::heap(wordArray).attach(kj::mv(data)); auto bundle = messageReader->getRoot(); - bundles.lockExclusive()->insert(kj::mv(version), - {.messageReader = kj::mv(messageReader), .bundle = bundle}); + bundles.lockExclusive()->insert( + kj::mv(version), {.messageReader = kj::mv(messageReader), .bundle = bundle}); } -static int readToTarget(kj::ArrayPtr source, int offset, kj::ArrayPtr buf) { +static int readToTarget( + kj::ArrayPtr source, int offset, kj::ArrayPtr buf) { int size = source.size(); if (offset >= size || offset < 0) { return 0; @@ -44,7 +47,7 @@ int PackagesTarReader::read(jsg::Lock& js, int offset, kj::Array buf) kj::Array> PyodideMetadataReader::getNames(jsg::Lock& js) { auto builder = kj::heapArrayBuilder>(this->names.size()); - for (auto i : kj::zeroTo(builder.capacity())) { + for (auto i: kj::zeroTo(builder.capacity())) { builder.add(js, js.str(this->names[i])); } return builder.finish(); @@ -52,7 +55,7 @@ kj::Array> PyodideMetadataReader::getNames(jsg::Lock& kj::Array> PyodideMetadataReader::getRequirements(jsg::Lock& js) { auto builder = kj::heapArrayBuilder>(this->requirements.size()); - for (auto i : kj::zeroTo(builder.capacity())) { + for (auto i: kj::zeroTo(builder.capacity())) { builder.add(js, js.str(this->requirements[i])); } return builder.finish(); @@ -60,7 +63,7 @@ kj::Array> PyodideMetadataReader::getRequirements(jsg: kj::Array PyodideMetadataReader::getSizes(jsg::Lock& js) { auto builder = kj::heapArrayBuilder(this->names.size()); - for (auto i : kj::zeroTo(builder.capacity())) { + for (auto i: kj::zeroTo(builder.capacity())) { builder.add(this->contents[i].size()); } return builder.finish(); @@ -88,50 +91,51 @@ int ArtifactBundler::readMemorySnapshot(int offset, kj::Array buf) { return readToTarget(KJ_REQUIRE_NONNULL(existingSnapshot), offset, buf); } -jsg::Ref makePyodideMetadataReader(Worker::Reader conf, const PythonConfig& pythonConfig) { +jsg::Ref makePyodideMetadataReader( + Worker::Reader conf, const PythonConfig& pythonConfig) { auto modules = conf.getModules(); auto mainModule = kj::str(modules.begin()->getName()); int numFiles = 0; int numRequirements = 0; - for (auto module : modules) { + for (auto module: modules) { switch (module.which()) { - case Worker::Module::TEXT: - case Worker::Module::DATA: - case Worker::Module::JSON: - case Worker::Module::PYTHON_MODULE: - numFiles++; - break; - case Worker::Module::PYTHON_REQUIREMENT: - numRequirements++; - break; - default: - break; + case Worker::Module::TEXT: + case Worker::Module::DATA: + case Worker::Module::JSON: + case Worker::Module::PYTHON_MODULE: + numFiles++; + break; + case Worker::Module::PYTHON_REQUIREMENT: + numRequirements++; + break; + default: + break; } } auto names = kj::heapArrayBuilder(numFiles); auto contents = kj::heapArrayBuilder>(numFiles); auto requirements = kj::heapArrayBuilder(numRequirements); - for (auto module : modules) { + for (auto module: modules) { switch (module.which()) { - case Worker::Module::TEXT: - contents.add(kj::heapArray(module.getText().asBytes())); - break; - case Worker::Module::DATA: - contents.add(kj::heapArray(module.getData().asBytes())); - break; - case Worker::Module::JSON: - contents.add(kj::heapArray(module.getJson().asBytes())); - break; - case Worker::Module::PYTHON_MODULE: - KJ_REQUIRE(module.getName().endsWith(".py")); - contents.add(kj::heapArray(module.getPythonModule().asBytes())); - break; - case Worker::Module::PYTHON_REQUIREMENT: - requirements.add(kj::str(module.getName())); - continue; - default: - continue; + case Worker::Module::TEXT: + contents.add(kj::heapArray(module.getText().asBytes())); + break; + case Worker::Module::DATA: + contents.add(kj::heapArray(module.getData().asBytes())); + break; + case Worker::Module::JSON: + contents.add(kj::heapArray(module.getJson().asBytes())); + break; + case Worker::Module::PYTHON_MODULE: + KJ_REQUIRE(module.getName().endsWith(".py")); + contents.add(kj::heapArray(module.getPythonModule().asBytes())); + break; + case Worker::Module::PYTHON_REQUIREMENT: + requirements.add(kj::str(module.getName())); + continue; + default: + continue; } names.add(kj::str(module.getName())); } @@ -194,4 +198,4 @@ bool hasPythonModules(capnp::List::Reader module return false; } -} // namespace workerd::api::pyodide +} // namespace workerd::api::pyodide diff --git a/src/workerd/api/pyodide/pyodide.h b/src/workerd/api/pyodide/pyodide.h index 637245f967e..8ecb2397012 100644 --- a/src/workerd/api/pyodide/pyodide.h +++ b/src/workerd/api/pyodide/pyodide.h @@ -39,7 +39,7 @@ struct PythonConfig { // A function to read a segment of the tar file into a buffer // Set up this way to avoid copying files that aren't accessed. -class PackagesTarReader : public jsg::Object { +class PackagesTarReader: public jsg::Object { public: PackagesTarReader() = default; @@ -50,10 +50,9 @@ class PackagesTarReader : public jsg::Object { } }; - // A function to read a segment of the tar file into a buffer // Set up this way to avoid copying files that aren't accessed. -class PyodideMetadataReader : public jsg::Object { +class PyodideMetadataReader: public jsg::Object { private: kj::String mainModule; kj::Array names; @@ -66,14 +65,21 @@ class PyodideMetadataReader : public jsg::Object { kj::Maybe> memorySnapshot; public: - PyodideMetadataReader(kj::String mainModule, kj::Array names, - kj::Array> contents, kj::Array requirements, - bool isWorkerd, bool isTracing, - bool snapshotToDisk, - bool createBaselineSnapshot, - kj::Maybe> memorySnapshot) - : mainModule(kj::mv(mainModule)), names(kj::mv(names)), contents(kj::mv(contents)), - requirements(kj::mv(requirements)), isWorkerdFlag(isWorkerd), isTracingFlag(isTracing), + PyodideMetadataReader(kj::String mainModule, + kj::Array names, + kj::Array> contents, + kj::Array requirements, + bool isWorkerd, + bool isTracing, + bool snapshotToDisk, + bool createBaselineSnapshot, + kj::Maybe> memorySnapshot) + : mainModule(kj::mv(mainModule)), + names(kj::mv(names)), + contents(kj::mv(contents)), + requirements(kj::mv(requirements)), + isWorkerdFlag(isWorkerd), + isTracingFlag(isTracing), snapshotToDisk(snapshotToDisk), createBaselineSnapshot(createBaselineSnapshot), memorySnapshot(kj::mv(memorySnapshot)) {} @@ -139,13 +145,13 @@ class PyodideMetadataReader : public jsg::Object { void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { tracker.trackField("mainModule", mainModule); - for (const auto& name : names) { + for (const auto& name: names) { tracker.trackField("name", name); } - for (const auto& content : contents) { + for (const auto& content: contents) { tracker.trackField("content", content); } - for (const auto& requirement : requirements) { + for (const auto& requirement: requirements) { tracker.trackField("requirement", requirement); } } @@ -159,19 +165,19 @@ struct MemorySnapshotResult { // A loaded bundle of artifacts for a particular script id. It can also contain V8 version and // CPU architecture-specific artifacts. The logic for loading these is in getArtifacts. -class ArtifactBundler : public jsg::Object { +class ArtifactBundler: public jsg::Object { public: kj::Maybe storedSnapshot; ArtifactBundler(kj::Maybe> existingSnapshot) : storedSnapshot(kj::none), existingSnapshot(kj::mv(existingSnapshot)), - isValidating(false){}; + isValidating(false) {}; ArtifactBundler(bool isValidating = false) : storedSnapshot(kj::none), existingSnapshot(kj::none), - isValidating(isValidating){}; + isValidating(isValidating) {}; void storeMemorySnapshot(jsg::Lock& js, MemorySnapshotResult snapshot) { KJ_REQUIRE(isValidating); @@ -194,7 +200,6 @@ class ArtifactBundler : public jsg::Object { existingSnapshot = kj::none; } - // Determines whether this ArtifactBundler was created inside the validator. bool isEwValidating() { return isValidating; @@ -212,7 +217,7 @@ class ArtifactBundler : public jsg::Object { } bool isEnabled() { - return false; // TODO(later): Remove this function once we regenerate the bundle. + return false; // TODO(later): Remove this function once we regenerate the bundle. } JSG_RESOURCE_TYPE(ArtifactBundler) { @@ -232,26 +237,24 @@ class ArtifactBundler : public jsg::Object { bool isValidating; }; - -class DisabledInternalJaeger : public jsg::Object { +class DisabledInternalJaeger: public jsg::Object { public: static jsg::Ref create() { return jsg::alloc(); } - JSG_RESOURCE_TYPE(DisabledInternalJaeger) { - } + JSG_RESOURCE_TYPE(DisabledInternalJaeger) {} }; // This cache is used by Pyodide to store wheels fetched over the internet across workerd restarts in local dev only class DiskCache: public jsg::Object { private: - static const kj::Maybe> NULL_CACHE_ROOT; // always set to kj::none + static const kj::Maybe> NULL_CACHE_ROOT; // always set to kj::none - const kj::Maybe> &cacheRoot; + const kj::Maybe>& cacheRoot; public: - DiskCache(): cacheRoot(NULL_CACHE_ROOT) {}; // Disabled disk cache - DiskCache(const kj::Maybe> &cacheRoot): cacheRoot(cacheRoot) {}; + DiskCache(): cacheRoot(NULL_CACHE_ROOT) {}; // Disabled disk cache + DiskCache(const kj::Maybe>& cacheRoot): cacheRoot(cacheRoot) {}; static jsg::Ref makeDisabled() { return jsg::alloc(); @@ -266,29 +269,24 @@ class DiskCache: public jsg::Object { } }; - // A limiter which will throw if the startup is found to exceed limits. The script will still be // able to run for longer than the limit, but an error will be thrown as soon as the startup // finishes. This way we can enforce a Python-specific startup limit. // // TODO(later): stop execution as soon limit is reached, instead of doing so after the fact. -class SimplePythonLimiter : public jsg::Object { +class SimplePythonLimiter: public jsg::Object { private: int startupLimitMs; kj::Maybe> getTimeCb; kj::Maybe startTime; - - public: - SimplePythonLimiter() : - startupLimitMs(0), - getTimeCb(kj::none) {} + SimplePythonLimiter(): startupLimitMs(0), getTimeCb(kj::none) {} - SimplePythonLimiter(int startupLimitMs, kj::Function getTimeCb) : - startupLimitMs(startupLimitMs), - getTimeCb(kj::mv(getTimeCb)) {} + SimplePythonLimiter(int startupLimitMs, kj::Function getTimeCb) + : startupLimitMs(startupLimitMs), + getTimeCb(kj::mv(getTimeCb)) {} static jsg::Ref makeDisabled() { return jsg::alloc(); @@ -320,20 +318,19 @@ class SimplePythonLimiter : public jsg::Object { using Worker = server::config::Worker; -jsg::Ref makePyodideMetadataReader(Worker::Reader conf, const PythonConfig& pythonConfig); +jsg::Ref makePyodideMetadataReader( + Worker::Reader conf, const PythonConfig& pythonConfig); bool hasPythonModules(capnp::List::Reader modules); -#define EW_PYODIDE_ISOLATE_TYPES \ - api::pyodide::PackagesTarReader, \ - api::pyodide::PyodideMetadataReader, \ - api::pyodide::ArtifactBundler, \ - api::pyodide::DiskCache, \ - api::pyodide::DisabledInternalJaeger,\ - api::pyodide::SimplePythonLimiter, \ - api::pyodide::MemorySnapshotResult +#define EW_PYODIDE_ISOLATE_TYPES \ + api::pyodide::PackagesTarReader, api::pyodide::PyodideMetadataReader, \ + api::pyodide::ArtifactBundler, api::pyodide::DiskCache, \ + api::pyodide::DisabledInternalJaeger, api::pyodide::SimplePythonLimiter, \ + api::pyodide::MemorySnapshotResult -template void registerPyodideModules(Registry& registry, auto featureFlags) { +template +void registerPyodideModules(Registry& registry, auto featureFlags) { // We add `pyodide:` packages here including python-entrypoint-helper.js. if (!util::Autogate::isEnabled(util::AutogateKey::PYODIDE_LOAD_EXTERNAL)) { registry.addBuiltinBundle(PYODIDE_BUNDLE, kj::none); @@ -360,4 +357,4 @@ kj::Own getExternalPyodideModuleBundle(auto featureF return builder.finish(); } -} // namespace workerd::api::pyodide +} // namespace workerd::api::pyodide diff --git a/src/workerd/api/queue.c++ b/src/workerd/api/queue.c++ index 37f12ba7fd4..67ec8cdb639 100644 --- a/src/workerd/api/queue.c++ +++ b/src/workerd/api/queue.c++ @@ -49,10 +49,11 @@ struct Serialized { Serialized serializeV8(jsg::Lock& js, const jsg::JsValue& body) { // Use a specific serialization version to avoid sending messages using a new version before all // runtimes at the edge know how to read it. - jsg::Serializer serializer(js, jsg::Serializer::Options { - .version = 15, - .omitHeader = false, - }); + jsg::Serializer serializer(js, + jsg::Serializer::Options{ + .version = 15, + .omitHeader = false, + }); serializer.write(js, jsg::JsValue(body)); kj::Array bytes = serializer.release().data; Serialized result; @@ -69,20 +70,13 @@ enum class SerializeArrayBufferBehavior { }; Serialized serialize(jsg::Lock& js, - const jsg::JsValue& body, - kj::StringPtr contentType, - SerializeArrayBufferBehavior bufferBehavior) { + const jsg::JsValue& body, + kj::StringPtr contentType, + SerializeArrayBufferBehavior bufferBehavior) { if (contentType == IncomingQueueMessage::ContentType::TEXT) { - JSG_REQUIRE( - body.isString(), - TypeError, - kj::str( - "Content Type \"", - IncomingQueueMessage::ContentType::TEXT, - "\" requires a value of type string, but received: ", - body.typeOf(js) - ) - ); + JSG_REQUIRE(body.isString(), TypeError, + kj::str("Content Type \"", IncomingQueueMessage::ContentType::TEXT, + "\" requires a value of type string, but received: ", body.typeOf(js))); kj::String s = body.toString(js); Serialized result; @@ -90,16 +84,9 @@ Serialized serialize(jsg::Lock& js, result.own = kj::mv(s); return kj::mv(result); } else if (contentType == IncomingQueueMessage::ContentType::BYTES) { - JSG_REQUIRE( - body.isArrayBufferView(), - TypeError, - kj::str( - "Content Type \"", - IncomingQueueMessage::ContentType::BYTES, - "\" requires a value of type ArrayBufferView, but received: ", - body.typeOf(js) - ) - ); + JSG_REQUIRE(body.isArrayBufferView(), TypeError, + kj::str("Content Type \"", IncomingQueueMessage::ContentType::BYTES, + "\" requires a value of type ArrayBufferView, but received: ", body.typeOf(js))); jsg::BufferSource source(js, body); if (bufferBehavior == SerializeArrayBufferBehavior::SHALLOW_REFERENCE) { @@ -141,9 +128,8 @@ struct SerializedWithOptions { kj::Maybe delaySeconds; }; -jsg::JsValue deserialize(jsg::Lock& js, - kj::Array body, - kj::Maybe contentType) { +jsg::JsValue deserialize( + jsg::Lock& js, kj::Array body, kj::Maybe contentType) { auto type = contentType.orDefault(IncomingQueueMessage::ContentType::V8); if (type == IncomingQueueMessage::ContentType::TEXT) { @@ -181,9 +167,8 @@ jsg::JsValue deserialize(jsg::Lock& js, rpc::QueueMessage::Reader message) { } } // namespace -kj::Promise WorkerQueue::send(jsg::Lock& js, - jsg::JsValue body, - jsg::Optional options) { +kj::Promise WorkerQueue::send( + jsg::Lock& js, jsg::JsValue body, jsg::Optional options) { auto& context = IoContext::current(); JSG_REQUIRE(!body.isUndefined(), TypeError, "Message body cannot be undefined"); @@ -208,7 +193,8 @@ kj::Promise WorkerQueue::send(jsg::Lock& js, serialized = serialize(js, body, type, SerializeArrayBufferBehavior::DEEP_COPY); } else if (workerd::FeatureFlags::get(js).getQueuesJsonMessages()) { headers.add("X-Msg-Fmt", IncomingQueueMessage::ContentType::JSON); - serialized = serialize(js, body, IncomingQueueMessage::ContentType::JSON, SerializeArrayBufferBehavior::DEEP_COPY); + serialized = serialize( + js, body, IncomingQueueMessage::ContentType::JSON, SerializeArrayBufferBehavior::DEEP_COPY); } else { // TODO(cleanup) send message format header (v8) by default serialized = serializeV8(js, body); @@ -219,17 +205,16 @@ kj::Promise WorkerQueue::send(jsg::Lock& js, // we have to do is provide the end of the path (which is "/message") to send a single message. auto client = context.getHttpClient(subrequestChannel, true, kj::none, "queue_send"_kjc); - auto req = client->request(kj::HttpMethod::POST, - "https://fake-host/message"_kjc, - headers, serialized.data.size()); + auto req = client->request( + kj::HttpMethod::POST, "https://fake-host/message"_kjc, headers, serialized.data.size()); - static constexpr auto handleSend = [](auto req, auto serialized, auto client) - -> kj::Promise { + static constexpr auto handleSend = [](auto req, auto serialized, + auto client) -> kj::Promise { co_await req.body->write(serialized.data); auto response = co_await req.response; - JSG_REQUIRE(response.statusCode == 200, Error, - kj::str("Queue send failed: ", response.statusText)); + JSG_REQUIRE( + response.statusCode == 200, Error, kj::str("Queue send failed: ", response.statusText)); // Read and discard response body, otherwise we might burn the HTTP connection. co_await response.body->readAllBytes().ignoreResult(); @@ -239,8 +224,9 @@ kj::Promise WorkerQueue::send(jsg::Lock& js, .attach(context.registerPendingEvent()); }; -kj::Promise WorkerQueue::sendBatch(jsg::Lock& js, jsg::Sequence batch, - jsg::Optional options) { +kj::Promise WorkerQueue::sendBatch(jsg::Lock& js, + jsg::Sequence batch, + jsg::Optional options) { auto& context = IoContext::current(); JSG_REQUIRE(batch.size() > 0, TypeError, "sendBatch() requires at least one message"); @@ -251,8 +237,7 @@ kj::Promise WorkerQueue::sendBatch(jsg::Lock& js, jsg::Sequence(messageCount); for (auto& message: batch) { auto body = message.body.getHandle(js); - JSG_REQUIRE(!body.isUndefined(), TypeError, - "Message body cannot be undefined"); + JSG_REQUIRE(!body.isUndefined(), TypeError, "Message body cannot be undefined"); SerializedWithOptions item; KJ_IF_SOME(secs, message.delaySeconds) { @@ -261,13 +246,12 @@ kj::Promise WorkerQueue::sendBatch(jsg::Lock& js, jsg::Sequence WorkerQueue::sendBatch(jsg::Lock& js, jsg::Sequencerequest(kj::HttpMethod::POST, - "https://fake-host/batch"_kjc, - headers, body.size()); + auto req = + client->request(kj::HttpMethod::POST, "https://fake-host/batch"_kjc, headers, body.size()); static constexpr auto handleWrite = [](auto req, auto body, auto client) -> kj::Promise { co_await req.body->write(body.asBytes()); auto response = co_await req.response; JSG_REQUIRE(response.statusCode == 200, Error, - kj::str("Queue sendBatch failed: ", response.statusText)); + kj::str("Queue sendBatch failed: ", response.statusText)); // Read and discard response body, otherwise we might burn the HTTP connection. co_await response.body->readAllBytes().ignoreResult(); @@ -353,9 +336,8 @@ kj::Promise WorkerQueue::sendBatch(jsg::Lock& js, jsg::Sequence result) +QueueMessage::QueueMessage( + jsg::Lock& js, rpc::QueueMessage::Reader message, IoPtr result) : id(kj::str(message.getId())), timestamp(message.getTimestampNs() * kj::NANOSECONDS + kj::UNIX_EPOCH), body(deserialize(js, message).addRef(js)), @@ -378,16 +360,16 @@ jsg::JsValue QueueMessage::getBody(jsg::Lock& js) { void QueueMessage::retry(jsg::Optional options) { if (result->ackAll) { - auto msg = kj::str( - "Received a call to retry() on message ", id, " after ackAll() was already called. " + auto msg = kj::str("Received a call to retry() on message ", id, + " after ackAll() was already called. " "Calling retry() on a message after calling ackAll() has no effect."); IoContext::current().logWarning(msg); return; } if (result->explicitAcks.contains(id)) { - auto msg = kj::str( - "Received a call to retry() on message ", id, " after ack() was already called. " + auto msg = kj::str("Received a call to retry() on message ", id, + " after ack() was already called. " "Calling retry() on a message after calling ack() has no effect."); IoContext::current().logWarning(msg); return; @@ -407,25 +389,28 @@ void QueueMessage::ack() { } if (result->retryBatch.retry) { - auto msg = kj::str( - "Received a call to ack() on message ", id, " after retryAll() was already called. " + auto msg = kj::str("Received a call to ack() on message ", id, + " after retryAll() was already called. " "Calling ack() on a message after calling retryAll() has no effect."); IoContext::current().logWarning(msg); return; } if (result->retries.find(id) != kj::none) { - auto msg = kj::str( - "Received a call to ack() on message ", id, " after retry() was already called. " + auto msg = kj::str("Received a call to ack() on message ", id, + " after retry() was already called. " "Calling ack() on a message after calling retry() has no effect."); IoContext::current().logWarning(msg); return; } - result->explicitAcks.findOrCreate(id, [this]() { return kj::heapString(id); } ); + result->explicitAcks.findOrCreate(id, [this]() { return kj::heapString(id); }); } -QueueEvent::QueueEvent(jsg::Lock& js, rpc::EventDispatcher::QueueParams::Reader params, IoPtr result) - : ExtendableEvent("queue"), queueName(kj::heapString(params.getQueueName())), result(result) { +QueueEvent::QueueEvent( + jsg::Lock& js, rpc::EventDispatcher::QueueParams::Reader params, IoPtr result) + : ExtendableEvent("queue"), + queueName(kj::heapString(params.getQueueName())), + result(result) { // Note that we must make deep copies of all data here since the incoming Reader may be // deallocated while JS's GC wrappers still exist. auto incoming = params.getMessages(); @@ -437,7 +422,9 @@ QueueEvent::QueueEvent(jsg::Lock& js, rpc::EventDispatcher::QueueParams::Reader } QueueEvent::QueueEvent(jsg::Lock& js, Params params, IoPtr result) - : ExtendableEvent("queue"), queueName(kj::mv(params.queueName)), result(result) { + : ExtendableEvent("queue"), + queueName(kj::mv(params.queueName)), + result(result) { auto messagesBuilder = kj::heapArrayBuilder>(params.messages.size()); for (auto i: kj::indices(params.messages)) { messagesBuilder.add(jsg::alloc(js, kj::mv(params.messages[i]), result)); @@ -472,11 +459,11 @@ void QueueEvent::ackAll() { } namespace { -jsg::Ref startQueueEvent( - EventTarget& globalEventTarget, +jsg::Ref startQueueEvent(EventTarget& globalEventTarget, kj::OneOf params, IoPtr result, - Worker::Lock& lock, kj::Maybe exportedHandler, + Worker::Lock& lock, + kj::Maybe exportedHandler, const jsg::TypeHandler& handlerHandler) { jsg::Lock& js = lock; // Start a queue event (called from C++, not JS). Similar to startScheduled(), the caller must @@ -492,30 +479,25 @@ jsg::Ref startQueueEvent( } KJ_IF_SOME(h, exportedHandler) { - auto queueHandler = KJ_ASSERT_NONNULL(handlerHandler.tryUnwrap( - lock, h.self.getHandle(lock))); + auto queueHandler = KJ_ASSERT_NONNULL(handlerHandler.tryUnwrap(lock, h.self.getHandle(lock))); KJ_IF_SOME(f, queueHandler.queue) { - auto promise = f(lock, - jsg::alloc(event.addRef()), - jsg::JsValue(h.env.getHandle(js)).addRef(js), - h.getCtx()); - event->waitUntil(promise.then( - [event=event.addRef()]() mutable { event->setCompletionStatus(QueueEvent::CompletedSuccessfully{}); }, - [event=event.addRef()](kj::Exception&& e) mutable { - event->setCompletionStatus(QueueEvent::CompletedWithError{ kj::cp(e) }); - return kj::mv(e); - })); + auto promise = f(lock, jsg::alloc(event.addRef()), + jsg::JsValue(h.env.getHandle(js)).addRef(js), h.getCtx()); + event->waitUntil(promise.then([event = event.addRef()]() mutable { + event->setCompletionStatus(QueueEvent::CompletedSuccessfully{}); + }, [event = event.addRef()](kj::Exception&& e) mutable { + event->setCompletionStatus(QueueEvent::CompletedWithError{kj::cp(e)}); + return kj::mv(e); + })); } else { - lock.logWarningOnce( - "Received a QueueEvent but we lack a handler for QueueEvents. " - "Did you remember to export a queue() function?"); + lock.logWarningOnce("Received a QueueEvent but we lack a handler for QueueEvents. " + "Did you remember to export a queue() function?"); JSG_FAIL_REQUIRE(Error, "Handler does not export a queue() function."); } } else { if (globalEventTarget.getHandlerCount("queue") == 0) { - lock.logWarningOnce( - "Received a QueueEvent but we lack an event listener for queue events. " - "Did you remember to call addEventListener(\"queue\", ...)?"); + lock.logWarningOnce("Received a QueueEvent but we lack an event listener for queue events. " + "Did you remember to call addEventListener(\"queue\", ...)?"); JSG_FAIL_REQUIRE(Error, "No event listener registered for queue messages."); } globalEventTarget.dispatchEventImpl(lock, event.addRef()); @@ -524,7 +506,7 @@ jsg::Ref startQueueEvent( return event.addRef(); } -} +} // namespace kj::Promise QueueCustomEventImpl::run( kj::Own incomingRequest, @@ -552,7 +534,7 @@ kj::Promise QueueCustomEventImpl::run( // Create a custom refcounted type for holding the queueEvent so that we can pass it to the // waitUntil'ed callback safely without worrying about whether this coroutine gets canceled. - struct QueueEventHolder : public kj::Refcounted { + struct QueueEventHolder: public kj::Refcounted { jsg::Ref event = nullptr; }; auto queueEventHolder = kj::refcounted(); @@ -561,14 +543,14 @@ kj::Promise QueueCustomEventImpl::run( // that users can write queue handlers in the old addEventListener("queue", ...) syntax (where we // can't just wait on their addEventListener handler to resolve because it can't be async). context.addWaitUntil(context.run( - [this, entrypointName=entrypointName, &context, queueEvent = kj::addRef(*queueEventHolder), - &metrics = incomingRequest->getMetrics()] - (Worker::Lock& lock) mutable { + [this, entrypointName = entrypointName, &context, queueEvent = kj::addRef(*queueEventHolder), + &metrics = incomingRequest->getMetrics()](Worker::Lock& lock) mutable { jsg::AsyncContextFrame::StorageScope traceScope = context.makeAsyncTraceScope(lock); auto& typeHandler = lock.getWorker().getIsolate().getApi().getQueueTypeHandler(lock); - queueEvent->event = startQueueEvent(lock.getGlobalScope(), kj::mv(params), context.addObject(result), lock, - lock.getExportedHandler(entrypointName, context.getActor()), typeHandler); + queueEvent->event = + startQueueEvent(lock.getGlobalScope(), kj::mv(params), context.addObject(result), lock, + lock.getExportedHandler(entrypointName, context.getActor()), typeHandler); })); // TODO(soon): There's a good chance we'll want a different wall-clock timeout for queue handlers @@ -605,7 +587,7 @@ kj::Promise QueueCustomEventImpl::run( KJ_LOG(WARNING, "NOSENTRY queue event hit timeout", scriptId, status, tasks); } - co_return WorkerInterface::CustomEvent::Result { + co_return WorkerInterface::CustomEvent::Result{ .outcome = completed ? context.waitUntilStatus() : EventOutcome::EXCEEDED_CPU, }; } @@ -646,18 +628,18 @@ kj::Promise QueueCustomEventImpl::sendRpc( } this->result.explicitAcks.clear(); - for (const auto& msgId : respResult.getExplicitAcks()) { + for (const auto& msgId: respResult.getExplicitAcks()) { this->result.explicitAcks.insert(kj::heapString(msgId)); } this->result.retries.clear(); - for (const auto& retry : respResult.getRetryMessages()) { + for (const auto& retry: respResult.getRetryMessages()) { auto& entry = this->result.retries.upsert(kj::heapString(retry.getMsgId()), {}); if (retry.isDelaySeconds()) { entry.value.delaySeconds = retry.getDelaySeconds(); } } - return WorkerInterface::CustomEvent::Result { + return WorkerInterface::CustomEvent::Result{ .outcome = respResult.getOutcome(), }; }); @@ -665,19 +647,19 @@ kj::Promise QueueCustomEventImpl::sendRpc( kj::Array QueueCustomEventImpl::getRetryMessages() const { auto retryMsgs = kj::heapArrayBuilder(result.retries.size()); - for (const auto& entry : result.retries) { - retryMsgs.add(QueueRetryMessage{.msgId = kj::heapString(entry.key), - .delaySeconds = entry.value.delaySeconds}); + for (const auto& entry: result.retries) { + retryMsgs.add(QueueRetryMessage{ + .msgId = kj::heapString(entry.key), .delaySeconds = entry.value.delaySeconds}); } return retryMsgs.finish(); } kj::Array QueueCustomEventImpl::getExplicitAcks() const { auto ackArray = kj::heapArrayBuilder(result.explicitAcks.size()); - for (const auto& msgId : result.explicitAcks) { + for (const auto& msgId: result.explicitAcks) { ackArray.add(kj::heapString(msgId)); } return ackArray.finish(); } -} // namespace workerd::api +} // namespace workerd::api diff --git a/src/workerd/api/queue.h b/src/workerd/api/queue.h index 44cf5e7157e..c94f47ba8ea 100644 --- a/src/workerd/api/queue.h +++ b/src/workerd/api/queue.h @@ -23,8 +23,7 @@ class WorkerQueue: public jsg::Object { public: // `subrequestChannel` is what to pass to IoContext::getHttpClient() to get an HttpClient // representing this queue. - WorkerQueue(uint subrequestChannel) - : subrequestChannel(subrequestChannel) {} + WorkerQueue(uint subrequestChannel): subrequestChannel(subrequestChannel) {} struct SendOptions { // TODO(soon): Support metadata. @@ -68,8 +67,9 @@ class WorkerQueue: public jsg::Object { kj::Promise send(jsg::Lock& js, jsg::JsValue body, jsg::Optional options); - kj::Promise sendBatch(jsg::Lock& js, jsg::Sequence batch, - jsg::Optional options); + kj::Promise sendBatch(jsg::Lock& js, + jsg::Sequence batch, + jsg::Optional options); JSG_RESOURCE_TYPE(WorkerQueue) { JSG_METHOD(send); @@ -156,10 +156,16 @@ class QueueMessage final: public jsg::Object { QueueMessage(jsg::Lock& js, rpc::QueueMessage::Reader message, IoPtr result); QueueMessage(jsg::Lock& js, IncomingQueueMessage message, IoPtr result); - kj::StringPtr getId() { return id; } - kj::Date getTimestamp() { return timestamp; } + kj::StringPtr getId() { + return id; + } + kj::Date getTimestamp() { + return timestamp; + } jsg::JsValue getBody(jsg::Lock& js); - uint16_t getAttempts() { return attempts; }; + uint16_t getAttempts() { + return attempts; + }; void retry(jsg::Optional options); void ack(); @@ -206,13 +212,19 @@ class QueueEvent final: public ExtendableEvent { kj::Array messages; }; - explicit QueueEvent(jsg::Lock& js, rpc::EventDispatcher::QueueParams::Reader params, IoPtr result); + explicit QueueEvent(jsg::Lock& js, + rpc::EventDispatcher::QueueParams::Reader params, + IoPtr result); explicit QueueEvent(jsg::Lock& js, Params params, IoPtr result); static jsg::Ref constructor(kj::String type) = delete; - kj::ArrayPtr> getMessages() { return messages; } - kj::StringPtr getQueueName() { return queueName; } + kj::ArrayPtr> getMessages() { + return messages; + } + kj::StringPtr getQueueName() { + return queueName; + } void retryAll(jsg::Optional options); void ackAll(); @@ -271,15 +283,20 @@ class QueueEvent final: public ExtendableEvent { // Type used when calling a module-exported queue event handler. class QueueController final: public jsg::Object { public: - QueueController(jsg::Ref event) - : event(kj::mv(event)) {} + QueueController(jsg::Ref event): event(kj::mv(event)) {} - kj::ArrayPtr> getMessages() { return event->getMessages(); } - kj::StringPtr getQueueName() { return event->getQueueName(); } + kj::ArrayPtr> getMessages() { + return event->getMessages(); + } + kj::StringPtr getQueueName() { + return event->getQueueName(); + } void retryAll(jsg::Optional options) { event->retryAll(options); } - void ackAll() { event->ackAll(); } + void ackAll() { + event->ackAll(); + } JSG_RESOURCE_TYPE(QueueController) { JSG_READONLY_INSTANCE_PROPERTY(messages, getMessages); @@ -309,8 +326,8 @@ class QueueController final: public jsg::Object { // Extension of ExportedHandler covering queue handlers. struct QueueExportedHandler { typedef kj::Promise QueueHandler(jsg::Ref controller, - jsg::JsRef env, - jsg::Optional> ctx); + jsg::JsRef env, + jsg::Optional> ctx); jsg::LenientOptional> queue; JSG_STRUCT(queue); @@ -322,13 +339,11 @@ class QueueCustomEventImpl final: public WorkerInterface::CustomEvent, public kj kj::OneOf params) : params(kj::mv(params)) {} - kj::Promise run( - kj::Own incomingRequest, + kj::Promise run(kj::Own incomingRequest, kj::Maybe entrypointName, kj::TaskSet& waitUntilTasks) override; - kj::Promise sendRpc( - capnp::HttpOverCapnpFactory& httpOverCapnpFactory, + kj::Promise sendRpc(capnp::HttpOverCapnpFactory& httpOverCapnpFactory, capnp::ByteStreamFactory& byteStreamFactory, kj::TaskSet& waitUntilTasks, rpc::EventDispatcher::Client dispatcher) override; @@ -341,7 +356,9 @@ class QueueCustomEventImpl final: public WorkerInterface::CustomEvent, public kj QueueRetryBatch getRetryBatch() const { return {.retry = result.retryBatch.retry, .delaySeconds = result.retryBatch.delaySeconds}; } - bool getAckAll() const { return result.ackAll; } + bool getAckAll() const { + return result.ackAll; + } kj::Array getRetryMessages() const; kj::Array getExplicitAcks() const; @@ -350,19 +367,10 @@ class QueueCustomEventImpl final: public WorkerInterface::CustomEvent, public kj QueueEventResult result; }; -#define EW_QUEUE_ISOLATE_TYPES \ - api::WorkerQueue, \ - api::WorkerQueue::SendOptions, \ - api::WorkerQueue::SendBatchOptions, \ - api::WorkerQueue::MessageSendRequest, \ - api::IncomingQueueMessage, \ - api::QueueRetryBatch, \ - api::QueueRetryMessage, \ - api::QueueResponse, \ - api::QueueRetryOptions, \ - api::QueueMessage, \ - api::QueueEvent, \ - api::QueueController, \ - api::QueueExportedHandler +#define EW_QUEUE_ISOLATE_TYPES \ + api::WorkerQueue, api::WorkerQueue::SendOptions, api::WorkerQueue::SendBatchOptions, \ + api::WorkerQueue::MessageSendRequest, api::IncomingQueueMessage, api::QueueRetryBatch, \ + api::QueueRetryMessage, api::QueueResponse, api::QueueRetryOptions, api::QueueMessage, \ + api::QueueEvent, api::QueueController, api::QueueExportedHandler } // namespace workerd::api diff --git a/src/workerd/api/r2-admin.c++ b/src/workerd/api/r2-admin.c++ index 6c0242362ff..8290d9c4e6c 100644 --- a/src/workerd/api/r2-admin.c++ +++ b/src/workerd/api/r2-admin.c++ @@ -13,14 +13,15 @@ namespace workerd::api::public_beta { jsg::Ref R2Admin::get(jsg::Lock& js, kj::String bucketName) { KJ_IF_SOME(j, jwt) { - return jsg::alloc(featureFlags, subrequestChannel, kj::mv(bucketName), - kj::str(j), R2Bucket::friend_tag_t{}); + return jsg::alloc( + featureFlags, subrequestChannel, kj::mv(bucketName), kj::str(j), R2Bucket::friend_tag_t{}); } - return jsg::alloc(featureFlags, subrequestChannel, kj::mv(bucketName), R2Bucket::friend_tag_t{}); + return jsg::alloc( + featureFlags, subrequestChannel, kj::mv(bucketName), R2Bucket::friend_tag_t{}); } -jsg::Promise> R2Admin::create(jsg::Lock& js, kj::String name, - const jsg::TypeHandler>& errorType) { +jsg::Promise> R2Admin::create( + jsg::Lock& js, kj::String name, const jsg::TypeHandler>& errorType) { auto& context = IoContext::current(); auto client = context.getHttpClient(subrequestChannel, true, kj::none, "r2_delete"_kjc); @@ -35,22 +36,23 @@ jsg::Promise> R2Admin::create(jsg::Lock& js, kj::String name, createBucketBuilder.setBucket(name); auto requestJson = json.encode(requestBuilder); - auto promise = doR2HTTPPutRequest(kj::mv(client), kj::none, kj::none, - kj::mv(requestJson), nullptr, jwt); + auto promise = + doR2HTTPPutRequest(kj::mv(client), kj::none, kj::none, kj::mv(requestJson), nullptr, jwt); return context.awaitIo(js, kj::mv(promise), - [this, subrequestChannel = subrequestChannel, name = kj::mv(name), &errorType] - (jsg::Lock&, R2Result r2Result) mutable { + [this, subrequestChannel = subrequestChannel, name = kj::mv(name), &errorType]( + jsg::Lock&, R2Result r2Result) mutable { r2Result.throwIfError("createBucket", errorType); - return jsg::alloc(featureFlags, subrequestChannel, kj::mv(name), - R2Bucket::friend_tag_t{}); + return jsg::alloc( + featureFlags, subrequestChannel, kj::mv(name), R2Bucket::friend_tag_t{}); }); } jsg::Promise R2Admin::list(jsg::Lock& js, jsg::Optional options, const jsg::TypeHandler>& retrievedBucketType, - const jsg::TypeHandler>& errorType, CompatibilityFlags::Reader flags) { + const jsg::TypeHandler>& errorType, + CompatibilityFlags::Reader flags) { auto& context = IoContext::current(); auto client = context.getHttpClient(subrequestChannel, true, kj::none, "r2_delete"_kjc); @@ -86,14 +88,14 @@ jsg::Promise R2Admin::list(jsg::Lock& js, json.decode(KJ_ASSERT_NONNULL(r2Result.metadataPayload), responseBuilder); auto buckets = js.map(); - for(auto b: responseBuilder.getBuckets()) { - auto bucket = jsg::alloc(featureFlags, subrequestChannel, - kj::str(b.getName()), - kj::UNIX_EPOCH + b.getCreatedMillisecondsSinceEpoch() * kj::MILLISECONDS); + for (auto b: responseBuilder.getBuckets()) { + auto bucket = + jsg::alloc(featureFlags, subrequestChannel, kj::str(b.getName()), + kj::UNIX_EPOCH + b.getCreatedMillisecondsSinceEpoch() * kj::MILLISECONDS); buckets.set(js, b.getName(), jsg::JsValue(retrievedBucketType.wrap(js, kj::mv(bucket)))); } - ListResult result { + ListResult result{ .buckets = buckets.addRef(js), .truncated = responseBuilder.getTruncated(), }; @@ -105,8 +107,8 @@ jsg::Promise R2Admin::list(jsg::Lock& js, }); } -jsg::Promise R2Admin::delete_(jsg::Lock& js, kj::String name, - const jsg::TypeHandler>& errorType) { +jsg::Promise R2Admin::delete_( + jsg::Lock& js, kj::String name, const jsg::TypeHandler>& errorType) { auto& context = IoContext::current(); auto client = context.getHttpClient(subrequestChannel, true, kj::none, "r2_delete"_kjc); @@ -121,12 +123,12 @@ jsg::Promise R2Admin::delete_(jsg::Lock& js, kj::String name, deleteBucketBuilder.setBucket(name); auto requestJson = json.encode(requestBuilder); - auto promise = doR2HTTPPutRequest(kj::mv(client), kj::none, kj::none, - kj::mv(requestJson), nullptr, jwt); + auto promise = + doR2HTTPPutRequest(kj::mv(client), kj::none, kj::none, kj::mv(requestJson), nullptr, jwt); return context.awaitIo(js, kj::mv(promise), [&errorType](jsg::Lock&, R2Result r2Result) mutable { r2Result.throwIfError("deleteBucket", errorType); }); } -} // namespace workerd::api +} // namespace workerd::api::public_beta diff --git a/src/workerd/api/r2-admin.h b/src/workerd/api/r2-admin.h index 9e325217798..8370aea9416 100644 --- a/src/workerd/api/r2-admin.h +++ b/src/workerd/api/r2-admin.h @@ -27,14 +27,12 @@ class R2Admin: public jsg::Object { // `subrequestChannel` is what to pass to IoContext::getHttpClient() to get an HttpClient // representing this namespace. explicit R2Admin(CompatibilityFlags::Reader featureFlags, uint subrequestChannel) - : featureFlags(featureFlags), subrequestChannel(subrequestChannel) {} + : featureFlags(featureFlags), + subrequestChannel(subrequestChannel) {} // This constructor is intended to be used by the R2CrossAccount binding, which has access to the // friend_tag - R2Admin(FeatureFlags featureFlags, - uint subrequestChannel, - kj::String jwt, - friend_tag_t) + R2Admin(FeatureFlags featureFlags, uint subrequestChannel, kj::String jwt, friend_tag_t) : featureFlags(featureFlags), subrequestChannel(subrequestChannel), jwt(kj::mv(jwt)) {} @@ -48,14 +46,19 @@ class R2Admin: public jsg::Object { class RetrievedBucket: public R2Bucket { public: - RetrievedBucket( - R2Bucket::FeatureFlags featureFlags, uint subrequestChannel, kj::String name, + RetrievedBucket(R2Bucket::FeatureFlags featureFlags, + uint subrequestChannel, + kj::String name, kj::Date created) - : R2Bucket(featureFlags, subrequestChannel, kj::mv(name), R2Bucket::friend_tag_t{}), - created(created) {} + : R2Bucket(featureFlags, subrequestChannel, kj::mv(name), R2Bucket::friend_tag_t{}), + created(created) {} - kj::String getName() const { return kj::str(KJ_ASSERT_NONNULL(adminBucketName())); } - kj::Date getCreated() const { return created; } + kj::String getName() const { + return kj::str(KJ_ASSERT_NONNULL(adminBucketName())); + } + kj::Date getCreated() const { + return created; + } JSG_RESOURCE_TYPE(RetrievedBucket) { JSG_INHERIT(R2Bucket); @@ -77,14 +80,16 @@ class R2Admin: public jsg::Object { JSG_STRUCT(buckets, truncated, cursor); }; - jsg::Promise> create(jsg::Lock& js, kj::String name, - const jsg::TypeHandler>& errorType); + jsg::Promise> create( + jsg::Lock& js, kj::String name, const jsg::TypeHandler>& errorType); jsg::Ref get(jsg::Lock& js, kj::String name); - jsg::Promise delete_(jsg::Lock& js, kj::String bucketName, - const jsg::TypeHandler>& errorType); - jsg::Promise list(jsg::Lock& js, jsg::Optional options, + jsg::Promise delete_( + jsg::Lock& js, kj::String bucketName, const jsg::TypeHandler>& errorType); + jsg::Promise list(jsg::Lock& js, + jsg::Optional options, const jsg::TypeHandler>& retrievedBucketType, - const jsg::TypeHandler>& errorType, CompatibilityFlags::Reader flags); + const jsg::TypeHandler>& errorType, + CompatibilityFlags::Reader flags); JSG_RESOURCE_TYPE(R2Admin) { JSG_METHOD(create); @@ -105,11 +110,9 @@ class R2Admin: public jsg::Object { friend class edgeworker::api::R2CrossAccount; }; -#define EW_R2_PUBLIC_BETA_ADMIN_ISOLATE_TYPES \ - api::public_beta::R2Admin, \ - api::public_beta::R2Admin::RetrievedBucket, \ - api::public_beta::R2Admin::ListOptions, \ - api::public_beta::R2Admin::ListResult +#define EW_R2_PUBLIC_BETA_ADMIN_ISOLATE_TYPES \ + api::public_beta::R2Admin, api::public_beta::R2Admin::RetrievedBucket, \ + api::public_beta::R2Admin::ListOptions, api::public_beta::R2Admin::ListResult // The list of r2-admin.h types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE diff --git a/src/workerd/api/r2-bucket.c++ b/src/workerd/api/r2-bucket.c++ index 2b7982fe796..1428f5919b7 100644 --- a/src/workerd/api/r2-bucket.c++ +++ b/src/workerd/api/r2-bucket.c++ @@ -35,29 +35,28 @@ static jsg::ByteString toUTCString(jsg::Lock& js, kj::Date date) { return js.date(date).toUTCString(js); } -enum class OptionalMetadata: uint16_t { +enum class OptionalMetadata : uint16_t { Http = static_cast(R2ListRequest::IncludeField::HTTP), Custom = static_cast(R2ListRequest::IncludeField::CUSTOM), }; - namespace { void logIfMismatchedChecksumLength( size_t expectedLength, capnp::Data::Reader checksum, R2HeadResponse::Reader responseReader) { if (checksum.size() != expectedLength) { - KJ_LOG(WARNING, "NOSENTRY Checksum is of unexpected length", - expectedLength, checksum.size(), responseReader.getName(), responseReader.getVersion() - ); + KJ_LOG(WARNING, "NOSENTRY Checksum is of unexpected length", expectedLength, checksum.size(), + responseReader.getName(), responseReader.getVersion()); } } -} +} // namespace template concept HeadResultT = std::is_base_of_v; template static jsg::Ref parseObjectMetadata(R2HeadResponse::Reader responseReader, - kj::ArrayPtr expectedOptionalFields, Args&&... args) { + kj::ArrayPtr expectedOptionalFields, + Args&&... args) { // optionalFieldsExpected is initialized by default to HTTP + CUSTOM if the user doesn't specify // anything. If they specify the empty array, then nothing is returned. kj::Date uploaded = @@ -84,29 +83,27 @@ static jsg::Ref parseObjectMetadata(R2HeadResponse::Reader responseReader, m.cacheControl = kj::str(httpFields.getCacheControl()); } if (httpFields.getCacheExpiry() != 0xffffffffffffffff) { - m.cacheExpiry = - kj::UNIX_EPOCH + httpFields.getCacheExpiry() * kj::MILLISECONDS; + m.cacheExpiry = kj::UNIX_EPOCH + httpFields.getCacheExpiry() * kj::MILLISECONDS; } httpMetadata = kj::mv(m); } else if (std::find(expectedOptionalFields.begin(), expectedOptionalFields.end(), - OptionalMetadata::Http) != expectedOptionalFields.end()) { + OptionalMetadata::Http) != expectedOptionalFields.end()) { // HTTP metadata was asked for but the object didn't have anything. httpMetadata = R2Bucket::HttpMetadata{}; } jsg::Optional> customMetadata; if (responseReader.hasCustomFields()) { - customMetadata = jsg::Dict { - .fields = KJ_MAP(field, responseReader.getCustomFields()) { - jsg::Dict::Field item; - item.name = kj::str(field.getK()); - item.value = kj::str(field.getV()); - return item; - } - }; + customMetadata = jsg::Dict{.fields = + KJ_MAP(field, responseReader.getCustomFields()) { + jsg::Dict::Field item; + item.name = kj::str(field.getK()); + item.value = kj::str(field.getV()); + return item; + }}; } else if (std::find(expectedOptionalFields.begin(), expectedOptionalFields.end(), - OptionalMetadata::Custom) != expectedOptionalFields.end()) { + OptionalMetadata::Custom) != expectedOptionalFields.end()) { // Custom metadata was asked for but the object didn't have anything. customMetadata = jsg::Dict{}; } @@ -115,13 +112,14 @@ static jsg::Ref parseObjectMetadata(R2HeadResponse::Reader responseReader, if (responseReader.hasRange()) { auto rangeBuilder = responseReader.getRange(); - range = R2Bucket::Range { + range = R2Bucket::Range{ .offset = static_cast(rangeBuilder.getOffset()), .length = static_cast(rangeBuilder.getLength()), }; } - jsg::Ref checksums = jsg::alloc(kj::none, kj::none, kj::none, kj::none, kj::none); + jsg::Ref checksums = + jsg::alloc(kj::none, kj::none, kj::none, kj::none, kj::none); if (responseReader.hasChecksums()) { R2Checksums::Reader checksumsBuilder = responseReader.getChecksums(); @@ -152,15 +150,17 @@ static jsg::Ref parseObjectMetadata(R2HeadResponse::Reader responseReader, } } - return jsg::alloc(kj::str(responseReader.getName()), - kj::str(responseReader.getVersion()), responseReader.getSize(), - kj::str(responseReader.getEtag()), kj::mv(checksums), uploaded, kj::mv(httpMetadata), - kj::mv(customMetadata), range, kj::str(responseReader.getStorageClass()), kj::fwd(args)...); + return jsg::alloc(kj::str(responseReader.getName()), kj::str(responseReader.getVersion()), + responseReader.getSize(), kj::str(responseReader.getEtag()), kj::mv(checksums), uploaded, + kj::mv(httpMetadata), kj::mv(customMetadata), range, + kj::str(responseReader.getStorageClass()), kj::fwd(args)...); } template -static kj::Maybe> parseObjectMetadata(kj::StringPtr action, R2Result& r2Result, - const jsg::TypeHandler>& errorType, Args&&... args) { +static kj::Maybe> parseObjectMetadata(kj::StringPtr action, + R2Result& r2Result, + const jsg::TypeHandler>& errorType, + Args&&... args) { if (r2Result.objectNotFound()) { return kj::none; } @@ -169,10 +169,9 @@ static kj::Maybe> parseObjectMetadata(kj::StringPtr action, R2Result } // Non-list operations always return these. - std::array expectedFieldsOwned = { OptionalMetadata::Http, OptionalMetadata::Custom }; + std::array expectedFieldsOwned = {OptionalMetadata::Http, OptionalMetadata::Custom}; kj::ArrayPtr expectedFields = { - expectedFieldsOwned.data(), expectedFieldsOwned.size() - }; + expectedFieldsOwned.data(), expectedFieldsOwned.size()}; capnp::MallocMessageBuilder responseMessage; capnp::JsonCodec json; @@ -186,16 +185,19 @@ static kj::Maybe> parseObjectMetadata(kj::StringPtr action, R2Result namespace { -void addEtagsToBuilder(capnp::List::Builder etagListBuilder, kj::ArrayPtr etagArray) { +void addEtagsToBuilder( + capnp::List::Builder etagListBuilder, kj::ArrayPtr etagArray) { R2Bucket::Etag* currentEtag = etagArray.begin(); for (unsigned int i = 0; i < etagArray.size(); i++) { KJ_SWITCH_ONEOF(*currentEtag) { KJ_CASE_ONEOF(e, R2Bucket::WildcardEtag) { etagListBuilder[i].initType().setWildcard(); - } KJ_CASE_ONEOF(e, R2Bucket::StrongEtag) { + } + KJ_CASE_ONEOF(e, R2Bucket::StrongEtag) { etagListBuilder[i].initType().setStrong(); etagListBuilder[i].setValue(e.value); - } KJ_CASE_ONEOF(e, R2Bucket::WeakEtag) { + } + KJ_CASE_ONEOF(e, R2Bucket::WeakEtag) { etagListBuilder[i].initType().setWeak(); etagListBuilder[i].setValue(e.value); } @@ -204,12 +206,12 @@ void addEtagsToBuilder(capnp::List::Builder etagListBuilder, kj::ArrayPt } } -} // namespace +} // namespace template void initOnlyIf(jsg::Lock& js, Builder& builder, Options& o) { KJ_IF_SOME(i, o.onlyIf) { - R2Bucket::UnwrappedConditional c = [&]{ + R2Bucket::UnwrappedConditional c = [&] { KJ_SWITCH_ONEOF(i) { KJ_CASE_ONEOF(conditional, R2Bucket::Conditional) { return R2Bucket::UnwrappedConditional(conditional); @@ -225,29 +227,21 @@ void initOnlyIf(jsg::Lock& js, Builder& builder, Options& o) { KJ_IF_SOME(etagArray, c.etagMatches) { capnp::List::Builder etagMatchList = onlyIfBuilder.initEtagMatches(etagArray.size()); addEtagsToBuilder( - etagMatchList, - kj::arrayPtr(etagArray.begin(), etagArray.size()) - ); + etagMatchList, kj::arrayPtr(etagArray.begin(), etagArray.size())); } KJ_IF_SOME(etagArray, c.etagDoesNotMatch) { auto etagDoesNotMatchList = onlyIfBuilder.initEtagDoesNotMatch(etagArray.size()); addEtagsToBuilder( - etagDoesNotMatchList, - kj::arrayPtr(etagArray.begin(), etagArray.size()) - ); + etagDoesNotMatchList, kj::arrayPtr(etagArray.begin(), etagArray.size())); } KJ_IF_SOME(d, c.uploadedBefore) { - onlyIfBuilder.setUploadedBefore( - (d - kj::UNIX_EPOCH) / kj::MILLISECONDS - ); + onlyIfBuilder.setUploadedBefore((d - kj::UNIX_EPOCH) / kj::MILLISECONDS); if (c.secondsGranularity) { onlyIfBuilder.setSecondsGranularity(true); } } KJ_IF_SOME(d, c.uploadedAfter) { - onlyIfBuilder.setUploadedAfter( - (d - kj::UNIX_EPOCH) / kj::MILLISECONDS - ); + onlyIfBuilder.setUploadedAfter((d - kj::UNIX_EPOCH) / kj::MILLISECONDS); if (c.secondsGranularity) { onlyIfBuilder.setSecondsGranularity(true); } @@ -263,18 +257,18 @@ void initGetOptions(jsg::Lock& js, Builder& builder, Options& o) { KJ_CASE_ONEOF(r, R2Bucket::Range) { auto rangeBuilder = builder.initRange(); KJ_IF_SOME(offset, r.offset) { - JSG_REQUIRE(offset >= 0, RangeError, - "Invalid range. Starting offset (", offset, ") must be greater than or equal to 0."); - JSG_REQUIRE(isWholeNumber(offset), RangeError, - "Invalid range. Starting offset (", offset, ") must be an integer, not floating point."); + JSG_REQUIRE(offset >= 0, RangeError, "Invalid range. Starting offset (", offset, + ") must be greater than or equal to 0."); + JSG_REQUIRE(isWholeNumber(offset), RangeError, "Invalid range. Starting offset (", offset, + ") must be an integer, not floating point."); rangeBuilder.setOffset(static_cast(offset)); } KJ_IF_SOME(length, r.length) { - JSG_REQUIRE(length >= 0, RangeError, - "Invalid range. Length (", length, ") must be greater than or equal to 0."); - JSG_REQUIRE(isWholeNumber(length), RangeError, - "Invalid range. Length (", length, ") must be an integer, not floating point."); + JSG_REQUIRE(length >= 0, RangeError, "Invalid range. Length (", length, + ") must be greater than or equal to 0."); + JSG_REQUIRE(isWholeNumber(length), RangeError, "Invalid range. Length (", length, + ") must be an integer, not floating point."); rangeBuilder.setLength(static_cast(length)); } @@ -282,10 +276,10 @@ void initGetOptions(jsg::Lock& js, Builder& builder, Options& o) { JSG_REQUIRE(r.offset == kj::none, TypeError, "Suffix is incompatible with offset."); JSG_REQUIRE(r.length == kj::none, TypeError, "Suffix is incompatible with length."); - JSG_REQUIRE(suffix >= 0, RangeError, - "Invalid suffix. Suffix (", suffix, ") must be greater than or equal to 0."); - JSG_REQUIRE(isWholeNumber(suffix), RangeError, - "Invalid range. Suffix (", suffix, ") must be an integer, not floating point."); + JSG_REQUIRE(suffix >= 0, RangeError, "Invalid suffix. Suffix (", suffix, + ") must be greater than or equal to 0."); + JSG_REQUIRE(isWholeNumber(suffix), RangeError, "Invalid range. Suffix (", suffix, + ") must be an integer, not floating point."); rangeBuilder.setSuffix(static_cast(suffix)); } @@ -304,8 +298,9 @@ static bool isQuotedEtag(kj::StringPtr etag) { return etag.startsWith("\"") && etag.endsWith("\""); } -jsg::Promise>> R2Bucket::head( - jsg::Lock& js, kj::String name, const jsg::TypeHandler>& errorType, +jsg::Promise>> R2Bucket::head(jsg::Lock& js, + kj::String name, + const jsg::TypeHandler>& errorType, CompatibilityFlags::Reader flags) { return js.evalNow([&] { auto& context = IoContext::current(); @@ -326,8 +321,7 @@ jsg::Promise>> R2Bucket::head( auto requestJson = json.encode(requestBuilder); kj::StringPtr components[1]; auto path = fillR2Path(components, adminBucket); - auto promise = doR2HTTPGetRequest(kj::mv(client), kj::mv(requestJson), path, jwt, - flags); + auto promise = doR2HTTPGetRequest(kj::mv(client), kj::mv(requestJson), path, jwt, flags); return context.awaitIo(js, kj::mv(promise), [&errorType](jsg::Lock&, R2Result r2Result) { return parseObjectMetadata("head", r2Result, errorType); @@ -339,8 +333,11 @@ R2Bucket::FeatureFlags::FeatureFlags(CompatibilityFlags::Reader featureFlags) : listHonorsIncludes(featureFlags.getR2ListHonorIncludeFields()) {} jsg::Promise>, jsg::Ref>> -R2Bucket::get(jsg::Lock& js, kj::String name, jsg::Optional options, - const jsg::TypeHandler>& errorType, CompatibilityFlags::Reader flags) { +R2Bucket::get(jsg::Lock& js, + kj::String name, + jsg::Optional options, + const jsg::TypeHandler>& errorType, + CompatibilityFlags::Reader flags) { return js.evalNow([&] { auto& context = IoContext::current(); @@ -363,12 +360,11 @@ R2Bucket::get(jsg::Lock& js, kj::String name, jsg::Optional options, auto requestJson = json.encode(requestBuilder); kj::StringPtr components[1]; auto path = fillR2Path(components, adminBucket); - auto promise = doR2HTTPGetRequest(kj::mv(client), kj::mv(requestJson), path, jwt, - flags); + auto promise = doR2HTTPGetRequest(kj::mv(client), kj::mv(requestJson), path, jwt, flags); return context.awaitIo(js, kj::mv(promise), - [&context, &errorType](jsg::Lock&, R2Result r2Result) - -> kj::OneOf>, jsg::Ref> { + [&context, &errorType](jsg::Lock&, + R2Result r2Result) -> kj::OneOf>, jsg::Ref> { kj::OneOf>, jsg::Ref> result; if (r2Result.preconditionFailed()) { @@ -376,7 +372,7 @@ R2Bucket::get(jsg::Lock& js, kj::String name, jsg::Optional options, } else { jsg::Ref body = nullptr; - KJ_IF_SOME (s, r2Result.stream) { + KJ_IF_SOME(s, r2Result.stream) { body = jsg::alloc(context, kj::mv(s)); r2Result.stream = kj::none; } @@ -387,15 +383,19 @@ R2Bucket::get(jsg::Lock& js, kj::String name, jsg::Optional options, }); } -jsg::Promise>> -R2Bucket::put(jsg::Lock& js, kj::String name, kj::Maybe value, - jsg::Optional options, const jsg::TypeHandler>& errorType) { +jsg::Promise>> R2Bucket::put(jsg::Lock& js, + kj::String name, + kj::Maybe value, + jsg::Optional options, + const jsg::TypeHandler>& errorType) { return js.evalNow([&] { auto cancelReader = kj::defer([&] { KJ_IF_SOME(v, value) { KJ_SWITCH_ONEOF(v) { KJ_CASE_ONEOF(v, jsg::Ref) { - (*v).cancel(js, js.v8Error(kj::str("Stream cancelled because the associated put operation encountered an error."))); + (*v).cancel(js, + js.v8Error(kj::str( + "Stream cancelled because the associated put operation encountered an error."))); } KJ_CASE_ONEOF_DEFAULT {} } @@ -421,7 +421,8 @@ R2Bucket::put(jsg::Lock& js, kj::String name, kj::Maybe value, bool hashAlreadySpecified = false; const auto verifyHashNotSpecified = [&] { - JSG_REQUIRE(!hashAlreadySpecified, TypeError, "You cannot specify multiple hashing algorithms."); + JSG_REQUIRE( + !hashAlreadySpecified, TypeError, "You cannot specify multiple hashing algorithms."); hashAlreadySpecified = true; }; @@ -476,8 +477,8 @@ R2Bucket::put(jsg::Lock& js, kj::String name, kj::Maybe value, putBuilder.setMd5(bin); } KJ_CASE_ONEOF(hex, jsg::NonCoercible) { - JSG_REQUIRE(hex.value.size() == 32, TypeError, - "MD5 is 32 hex characters, not ", hex.value.size()); + JSG_REQUIRE(hex.value.size() == 32, TypeError, "MD5 is 32 hex characters, not ", + hex.value.size()); const auto decoded = kj::decodeHex(hex.value); JSG_REQUIRE(!decoded.hadErrors, TypeError, "Provided MD5 wasn't a valid hex string"); putBuilder.setMd5(decoded); @@ -492,8 +493,8 @@ R2Bucket::put(jsg::Lock& js, kj::String name, kj::Maybe value, putBuilder.setSha1(bin); } KJ_CASE_ONEOF(hex, jsg::NonCoercible) { - JSG_REQUIRE(hex.value.size() == 40, TypeError, - "SHA-1 is 40 hex characters, not ", hex.value.size()); + JSG_REQUIRE(hex.value.size() == 40, TypeError, "SHA-1 is 40 hex characters, not ", + hex.value.size()); const auto decoded = kj::decodeHex(hex.value); JSG_REQUIRE(!decoded.hadErrors, TypeError, "Provided SHA-1 wasn't a valid hex string"); putBuilder.setSha1(decoded); @@ -508,10 +509,11 @@ R2Bucket::put(jsg::Lock& js, kj::String name, kj::Maybe value, putBuilder.setSha256(bin); } KJ_CASE_ONEOF(hex, jsg::NonCoercible) { - JSG_REQUIRE(hex.value.size() == 64, TypeError, - "SHA-256 is 64 hex characters, not ", hex.value.size()); + JSG_REQUIRE(hex.value.size() == 64, TypeError, "SHA-256 is 64 hex characters, not ", + hex.value.size()); const auto decoded = kj::decodeHex(hex.value); - JSG_REQUIRE(!decoded.hadErrors, TypeError, "Provided SHA-256 wasn't a valid hex string"); + JSG_REQUIRE( + !decoded.hadErrors, TypeError, "Provided SHA-256 wasn't a valid hex string"); putBuilder.setSha256(decoded); } } @@ -524,10 +526,11 @@ R2Bucket::put(jsg::Lock& js, kj::String name, kj::Maybe value, putBuilder.setSha384(bin); } KJ_CASE_ONEOF(hex, jsg::NonCoercible) { - JSG_REQUIRE(hex.value.size() == 96, TypeError, - "SHA-384 is 96 hex characters, not ", hex.value.size()); + JSG_REQUIRE(hex.value.size() == 96, TypeError, "SHA-384 is 96 hex characters, not ", + hex.value.size()); const auto decoded = kj::decodeHex(hex.value); - JSG_REQUIRE(!decoded.hadErrors, TypeError, "Provided SHA-384 wasn't a valid hex string"); + JSG_REQUIRE( + !decoded.hadErrors, TypeError, "Provided SHA-384 wasn't a valid hex string"); putBuilder.setSha384(decoded); } } @@ -540,10 +543,11 @@ R2Bucket::put(jsg::Lock& js, kj::String name, kj::Maybe value, putBuilder.setSha512(bin); } KJ_CASE_ONEOF(hex, jsg::NonCoercible) { - JSG_REQUIRE(hex.value.size() == 128, TypeError, - "SHA-512 is 128 hex characters, not ", hex.value.size()); + JSG_REQUIRE(hex.value.size() == 128, TypeError, "SHA-512 is 128 hex characters, not ", + hex.value.size()); const auto decoded = kj::decodeHex(hex.value); - JSG_REQUIRE(!decoded.hadErrors, TypeError, "Provided SHA-512 wasn't a valid hex string"); + JSG_REQUIRE( + !decoded.hadErrors, TypeError, "Provided SHA-512 wasn't a valid hex string"); putBuilder.setSha512(decoded); } } @@ -558,14 +562,13 @@ R2Bucket::put(jsg::Lock& js, kj::String name, kj::Maybe value, cancelReader.cancel(); kj::StringPtr components[1]; auto path = fillR2Path(components, adminBucket); - auto promise = doR2HTTPPutRequest(kj::mv(client), kj::mv(value), kj::none, - kj::mv(requestJson), path, jwt); + auto promise = + doR2HTTPPutRequest(kj::mv(client), kj::mv(value), kj::none, kj::mv(requestJson), path, jwt); return context.awaitIo(js, kj::mv(promise), [sentHttpMetadata = kj::mv(sentHttpMetadata), - sentCustomMetadata = kj::mv(sentCustomMetadata), - &errorType] - (jsg::Lock& js, R2Result r2Result) mutable -> kj::Maybe> { + sentCustomMetadata = kj::mv(sentCustomMetadata), &errorType]( + jsg::Lock& js, R2Result r2Result) mutable -> kj::Maybe> { if (r2Result.preconditionFailed()) { return kj::none; } else { @@ -580,12 +583,14 @@ R2Bucket::put(jsg::Lock& js, kj::String name, kj::Maybe value, }); } -jsg::Promise> R2Bucket::createMultipartUpload(jsg::Lock& js, kj::String key, - jsg::Optional options, const jsg::TypeHandler>& errorType) { +jsg::Promise> R2Bucket::createMultipartUpload(jsg::Lock& js, + kj::String key, + jsg::Optional options, + const jsg::TypeHandler>& errorType) { return js.evalNow([&] { auto& context = IoContext::current(); - auto client = context.getHttpClient( - clientIndex, true, kj::none, "r2_createMultipartUpload"_kjc); + auto client = + context.getHttpClient(clientIndex, true, kj::none, "r2_createMultipartUpload"_kjc); capnp::JsonCodec json; json.handleByAnnotation(); @@ -647,11 +652,11 @@ jsg::Promise> R2Bucket::createMultipartUpload(jsg::L auto requestJson = json.encode(requestBuilder); kj::StringPtr components[1]; auto path = fillR2Path(components, adminBucket); - auto promise = doR2HTTPPutRequest(kj::mv(client), kj::none, kj::none, kj::mv(requestJson), - path, jwt); + auto promise = + doR2HTTPPutRequest(kj::mv(client), kj::none, kj::none, kj::mv(requestJson), path, jwt); return context.awaitIo(js, kj::mv(promise), - [&errorType, key=kj::mv(key), this] (jsg::Lock& js, R2Result r2Result) mutable { + [&errorType, key = kj::mv(key), this](jsg::Lock& js, R2Result r2Result) mutable { r2Result.throwIfError("createMultipartUpload", errorType); capnp::MallocMessageBuilder responseMessage; @@ -667,11 +672,14 @@ jsg::Promise> R2Bucket::createMultipartUpload(jsg::L } jsg::Ref R2Bucket::resumeMultipartUpload(jsg::Lock& js, - kj::String key, kj::String uploadId, const jsg::TypeHandler>& errorType) { - return jsg::alloc(kj::mv(key), kj::mv(uploadId), JSG_THIS); + kj::String key, + kj::String uploadId, + const jsg::TypeHandler>& errorType) { + return jsg::alloc(kj::mv(key), kj::mv(uploadId), JSG_THIS); } -jsg::Promise R2Bucket::delete_(jsg::Lock& js, kj::OneOf> keys, +jsg::Promise R2Bucket::delete_(jsg::Lock& js, + kj::OneOf> keys, const jsg::TypeHandler>& errorType) { return js.evalNow([&] { auto& context = IoContext::current(); @@ -701,8 +709,8 @@ jsg::Promise R2Bucket::delete_(jsg::Lock& js, kj::OneOf R2Bucket::delete_(jsg::Lock& js, kj::OneOf R2Bucket::list( - jsg::Lock& js, jsg::Optional options, - const jsg::TypeHandler>& errorType, CompatibilityFlags::Reader flags) { +jsg::Promise R2Bucket::list(jsg::Lock& js, + jsg::Optional options, + const jsg::TypeHandler>& errorType, + CompatibilityFlags::Reader flags) { return js.evalNow([&] { auto& context = IoContext::current(); auto client = context.getHttpClient(clientIndex, true, kj::none, "r2_list"_kjc); @@ -802,12 +811,11 @@ jsg::Promise R2Bucket::list( kj::StringPtr components[1]; auto path = fillR2Path(components, adminBucket); - auto promise = doR2HTTPGetRequest(kj::mv(client), kj::mv(requestJson), path, jwt, - flags); + auto promise = doR2HTTPGetRequest(kj::mv(client), kj::mv(requestJson), path, jwt, flags); return context.awaitIo(js, kj::mv(promise), - [expectedOptionalFields = expectedOptionalFields.releaseAsArray(), &errorType] - (jsg::Lock&, R2Result r2Result) { + [expectedOptionalFields = expectedOptionalFields.releaseAsArray(), &errorType]( + jsg::Lock&, R2Result r2Result) { r2Result.throwIfError("list", errorType); R2Bucket::ListResult result; @@ -826,9 +834,8 @@ jsg::Promise R2Bucket::list( result.cursor = kj::str(responseBuilder.getCursor()); } if (responseBuilder.hasDelimitedPrefixes()) { - result.delimitedPrefixes = KJ_MAP(e, responseBuilder.getDelimitedPrefixes()) { - return kj::str(e); - }; + result.delimitedPrefixes = + KJ_MAP(e, responseBuilder.getDelimitedPrefixes()) { return kj::str(e); }; } return kj::mv(result); @@ -838,11 +845,9 @@ jsg::Promise R2Bucket::list( namespace { -kj::Array parseConditionalEtagHeader( - kj::StringPtr condHeader, - kj::Vector etagAccumulator = kj::Vector(), - bool leadingCommaRequired = false -) { +kj::Array parseConditionalEtagHeader(kj::StringPtr condHeader, + kj::Vector etagAccumulator = kj::Vector(), + bool leadingCommaRequired = false) { // Vague recursion termination proof: // Stop condition triggers when no more etags and wildcards are found // => empty string also results in termination @@ -857,14 +862,14 @@ kj::Array parseConditionalEtagHeader( size_t nextComma = condHeader.findFirst(',').orDefault(SIZE_MAX); if (nextQuotation == SIZE_MAX && nextWildcard == SIZE_MAX) { - // Both of these being SIZE_MAX means no more wildcards or double quotes are left in the header. - // When this is the case, there's no more useful etags that can potentially still be extracted. + // Both of these being SIZE_MAX means no more wildcards or double quotes are left in the header. + // When this is the case, there's no more useful etags that can potentially still be extracted. return etagAccumulator.releaseAsArray(); } if (nextComma < nextWildcard && nextComma < nextQuotation && nextComma < nextWeak) { - // Get rid of leading commas, this can happen during recursion because servers must deal with - // empty list elements. E.g.: If-None-Match "abc", , "cdef" should be accepted by the server. + // Get rid of leading commas, this can happen during recursion because servers must deal with + // empty list elements. E.g.: If-None-Match "abc", , "cdef" should be accepted by the server. // This slice is always safe, since we're at most setting start to the last index + 1, // which just results in an empty list if it's out of bounds by 1. return parseConditionalEtagHeader(condHeader.slice(nextComma + 1), kj::mv(etagAccumulator)); @@ -877,15 +882,14 @@ kj::Array parseConditionalEtagHeader( if (firstEncounteredProblem == nextWildcard) { failureReason = kj::str("Encountered a wildcard character '*' instead."); } else if (firstEncounteredProblem == nextQuotation) { - failureReason = kj::str( - "Encountered a double quote character '\"' instead. " - "This would otherwise indicate the start of a new strong etag."); + failureReason = kj::str("Encountered a double quote character '\"' instead. " + "This would otherwise indicate the start of a new strong etag."); } else if (firstEncounteredProblem == nextWeak) { - failureReason = kj::str( - "Encountered a weak quotation character 'W' instead. " - "This would otherwise indicate the start of a new weak etag."); + failureReason = kj::str("Encountered a weak quotation character 'W' instead. " + "This would otherwise indicate the start of a new weak etag."); } else { - KJ_FAIL_ASSERT("We shouldn't be able to reach this point. The above etag parsing code is incorrect."); + KJ_FAIL_ASSERT( + "We shouldn't be able to reach this point. The above etag parsing code is incorrect."); } // Did not find a leading comma, and we expected a leading comma before any further etags @@ -905,32 +909,24 @@ kj::Array parseConditionalEtagHeader( // Find closing quotation mark, instead of going by the next comma. // This is done because commas are allowed in etags, and double quotes are not. kj::Maybe closingQuotation = - condHeader.slice(etagValueStart) - .findFirst('"') - .map([=](size_t cq) { return cq + etagValueStart; }); + condHeader.slice(etagValueStart).findFirst('"').map([=](size_t cq) { + return cq + etagValueStart; + }); KJ_IF_SOME(cq, closingQuotation) { // Slice end is non inclusive, meaning that this drops the closingQuotation from the etag kj::String etagValue = kj::str(condHeader.slice(etagValueStart, cq)); if (nextWeak < nextQuotation) { - JSG_REQUIRE( - condHeader.size() > nextWeak + 2 - && condHeader[nextWeak + 1] == '/' - && nextWeak + 2 == nextQuotation, - Error, - "Weak etags must start with W/ and their value must be quoted" - ); + JSG_REQUIRE(condHeader.size() > nextWeak + 2 && condHeader[nextWeak + 1] == '/' && + nextWeak + 2 == nextQuotation, + Error, "Weak etags must start with W/ and their value must be quoted"); R2Bucket::WeakEtag etag = {kj::mv(etagValue)}; etagAccumulator.add(kj::mv(etag)); } else { R2Bucket::StrongEtag etag = {kj::mv(etagValue)}; etagAccumulator.add(kj::mv(etag)); } - return parseConditionalEtagHeader( - condHeader.slice(cq + 1), - kj::mv(etagAccumulator), - true - ); + return parseConditionalEtagHeader(condHeader.slice(cq + 1), kj::mv(etagAccumulator), true); } else { JSG_FAIL_REQUIRE(Error, "Unclosed double quote for Etag"); } @@ -946,7 +942,7 @@ kj::Array buildSingleStrongEtagArray(kj::StringPtr etagValue) { return etagArrayBuilder.finish(); } -} // namespace +} // namespace R2Bucket::UnwrappedConditional::UnwrappedConditional(jsg::Lock& js, Headers& h) : secondsGranularity(true) { @@ -967,15 +963,15 @@ R2Bucket::UnwrappedConditional::UnwrappedConditional(jsg::Lock& js, Headers& h) } R2Bucket::UnwrappedConditional::UnwrappedConditional(const Conditional& c) - : secondsGranularity(c.secondsGranularity.orDefault(false)) { + : secondsGranularity(c.secondsGranularity.orDefault(false)) { KJ_IF_SOME(e, c.etagMatches) { JSG_REQUIRE(!isQuotedEtag(e.value), TypeError, - "Conditional ETag should not be wrapped in quotes (", e.value, ")."); + "Conditional ETag should not be wrapped in quotes (", e.value, ")."); etagMatches = buildSingleStrongEtagArray(e.value); } KJ_IF_SOME(e, c.etagDoesNotMatch) { JSG_REQUIRE(!isQuotedEtag(e.value), TypeError, - "Conditional ETag should not be wrapped in quotes (", e.value, ")."); + "Conditional ETag should not be wrapped in quotes (", e.value, ")."); etagDoesNotMatch = buildSingleStrongEtagArray(e.value); } KJ_IF_SOME(d, c.uploadedAfter) { @@ -1023,8 +1019,7 @@ R2Bucket::HttpMetadata R2Bucket::HttpMetadata::clone() const { } void R2Bucket::HeadResult::writeHttpMetadata(jsg::Lock& js, Headers& headers) { - JSG_REQUIRE(httpMetadata != kj::none, TypeError, - "HTTP metadata unknown for key `", name, + JSG_REQUIRE(httpMetadata != kj::none, TypeError, "HTTP metadata unknown for key `", name, "`. Did you forget to add 'httpMetadata' to `include` when listing?"); const auto& m = KJ_REQUIRE_NONNULL(httpMetadata); @@ -1050,8 +1045,9 @@ void R2Bucket::HeadResult::writeHttpMetadata(jsg::Lock& js, Headers& headers) { jsg::Promise> R2Bucket::GetResult::arrayBuffer(jsg::Lock& js) { return js.evalNow([&] { - JSG_REQUIRE(!body->isDisturbed(), TypeError, "Body has already been used. " - "It can only be used once. Use tee() first if you need to read it twice."); + JSG_REQUIRE(!body->isDisturbed(), TypeError, + "Body has already been used. " + "It can only be used once. Use tee() first if you need to read it twice."); auto& context = IoContext::current(); return body->getController().readAllBytes(js, context.getLimitEnforcer().getBufferingLimit()); @@ -1061,8 +1057,9 @@ jsg::Promise> R2Bucket::GetResult::arrayBuffer(jsg::Lock& js jsg::Promise R2Bucket::GetResult::text(jsg::Lock& js) { // Copy-pasted from http.c++ return js.evalNow([&] { - JSG_REQUIRE(!body->isDisturbed(), TypeError, "Body has already been used. " - "It can only be used once. Use tee() first if you need to read it twice."); + JSG_REQUIRE(!body->isDisturbed(), TypeError, + "Body has already been used. " + "It can only be used once. Use tee() first if you need to read it twice."); auto& context = IoContext::current(); // A common mistake is to call .text() on non-text content, e.g. because you're implementing a @@ -1081,18 +1078,17 @@ jsg::Promise R2Bucket::GetResult::text(jsg::Lock& js) { jsg::Promise R2Bucket::GetResult::json(jsg::Lock& js) { // Copy-pasted from http.c++ - return text(js).then(js, [](jsg::Lock& js, kj::String text) { - return js.parseJson(text); - }); + return text(js).then(js, [](jsg::Lock& js, kj::String text) { return js.parseJson(text); }); } jsg::Promise> R2Bucket::GetResult::blob(jsg::Lock& js) { // Copy-pasted from http.c++ return arrayBuffer(js).then(js, [this](jsg::Lock& js, kj::Array buffer) { // httpMetadata can't be null because GetResult always populates it. - kj::String contentType = KJ_REQUIRE_NONNULL(httpMetadata).contentType - .map([](const auto& str) { return kj::str(str); }) - .orDefault(nullptr); + kj::String contentType = KJ_REQUIRE_NONNULL(httpMetadata) + .contentType.map([](const auto& str) { + return kj::str(str); + }).orDefault(nullptr); return jsg::alloc(js, kj::mv(buffer), kj::mv(contentType)); }); } @@ -1107,16 +1103,18 @@ R2Bucket::StringChecksums R2Bucket::Checksums::toJSON() { }; } -kj::Array cloneByteArray(const kj::Array &arr) { +kj::Array cloneByteArray(const kj::Array& arr) { return kj::heapArray(arr.asPtr()); } -kj::Maybe> parseHeadResultWrapper( - kj::StringPtr action, R2Result& r2Result, const jsg::TypeHandler>& errorType) { - return parseObjectMetadata(action, r2Result, errorType); +kj::Maybe> parseHeadResultWrapper(kj::StringPtr action, + R2Result& r2Result, + const jsg::TypeHandler>& errorType) { + return parseObjectMetadata(action, r2Result, errorType); } -kj::ArrayPtr fillR2Path(kj::StringPtr pathStorage[1], const kj::Maybe& bucket) { +kj::ArrayPtr fillR2Path( + kj::StringPtr pathStorage[1], const kj::Maybe& bucket) { int numComponents = 0; KJ_IF_SOME(b, bucket) { @@ -1126,5 +1124,4 @@ kj::ArrayPtr fillR2Path(kj::StringPtr pathStorage[1], const kj::M return kj::arrayPtr(pathStorage, numComponents); } - -} // namespace workerd::api::public_beta +} // namespace workerd::api::public_beta diff --git a/src/workerd/api/r2-bucket.h b/src/workerd/api/r2-bucket.h index 757be54d5b1..c1be7e3ea14 100644 --- a/src/workerd/api/r2-bucket.h +++ b/src/workerd/api/r2-bucket.h @@ -13,13 +13,14 @@ #include namespace workerd::api { - class Headers; +class Headers; } namespace workerd::api::public_beta { kj::Array cloneByteArray(const kj::Array& arr); -kj::ArrayPtr fillR2Path(kj::StringPtr pathStorage[1], const kj::Maybe& bucket); +kj::ArrayPtr fillR2Path( + kj::StringPtr pathStorage[1], const kj::Maybe& bucket); class R2MultipartUpload; @@ -38,13 +39,20 @@ class R2Bucket: public jsg::Object { // `clientIndex` is what to pass to IoContext::getHttpClient() to get an HttpClient // representing this namespace. explicit R2Bucket(CompatibilityFlags::Reader featureFlags, uint clientIndex) - : featureFlags(featureFlags), clientIndex(clientIndex) {} + : featureFlags(featureFlags), + clientIndex(clientIndex) {} explicit R2Bucket(FeatureFlags featureFlags, uint clientIndex, kj::String bucket, friend_tag_t) - : featureFlags(featureFlags), clientIndex(clientIndex), adminBucket(kj::mv(bucket)) {} + : featureFlags(featureFlags), + clientIndex(clientIndex), + adminBucket(kj::mv(bucket)) {} - explicit R2Bucket(FeatureFlags featureFlags, uint clientIndex, kj::String bucket, kj::String jwt, friend_tag_t) - : featureFlags(featureFlags), clientIndex(clientIndex), adminBucket(kj::mv(bucket)), jwt(kj::mv(jwt)) {} + explicit R2Bucket( + FeatureFlags featureFlags, uint clientIndex, kj::String bucket, kj::String jwt, friend_tag_t) + : featureFlags(featureFlags), + clientIndex(clientIndex), + adminBucket(kj::mv(bucket)), + jwt(kj::mv(jwt)) {} struct Range { jsg::Optional offset; @@ -91,24 +99,32 @@ class R2Bucket: public jsg::Object { class Checksums: public jsg::Object { public: - Checksums( - jsg::Optional> md5, - jsg::Optional> sha1, - jsg::Optional> sha256, - jsg::Optional> sha384, - jsg::Optional> sha512 - ): - md5(kj::mv(md5)), - sha1(kj::mv(sha1)), - sha256(kj::mv(sha256)), - sha384(kj::mv(sha384)), - sha512(kj::mv(sha512)) {} - - jsg::Optional> getMd5() const { return md5.map(cloneByteArray); } - jsg::Optional> getSha1() const { return sha1.map(cloneByteArray); } - jsg::Optional> getSha256() const { return sha256.map(cloneByteArray); } - jsg::Optional> getSha384() const { return sha384.map(cloneByteArray); } - jsg::Optional> getSha512() const { return sha512.map(cloneByteArray); } + Checksums(jsg::Optional> md5, + jsg::Optional> sha1, + jsg::Optional> sha256, + jsg::Optional> sha384, + jsg::Optional> sha512) + : md5(kj::mv(md5)), + sha1(kj::mv(sha1)), + sha256(kj::mv(sha256)), + sha384(kj::mv(sha384)), + sha512(kj::mv(sha512)) {} + + jsg::Optional> getMd5() const { + return md5.map(cloneByteArray); + } + jsg::Optional> getSha1() const { + return sha1.map(cloneByteArray); + } + jsg::Optional> getSha256() const { + return sha256.map(cloneByteArray); + } + jsg::Optional> getSha384() const { + return sha384.map(cloneByteArray); + } + jsg::Optional> getSha512() const { + return sha512.map(cloneByteArray); + } StringChecksums toJSON(); @@ -147,8 +163,12 @@ class R2Bucket: public jsg::Object { jsg::Optional cacheControl; jsg::Optional cacheExpiry; - JSG_STRUCT(contentType, contentLanguage, contentDisposition, - contentEncoding, cacheControl, cacheExpiry); + JSG_STRUCT(contentType, + contentLanguage, + contentDisposition, + contentEncoding, + cacheControl, + cacheExpiry); JSG_STRUCT_TS_OVERRIDE(R2HTTPMetadata); HttpMetadata clone() const; @@ -173,7 +193,8 @@ class R2Bucket: public jsg::Object { jsg::Optional, jsg::NonCoercible>> sha512; jsg::Optional storageClass; - JSG_STRUCT(onlyIf, httpMetadata, customMetadata, md5, sha1, sha256, sha384, sha512, storageClass); + JSG_STRUCT( + onlyIf, httpMetadata, customMetadata, md5, sha1, sha256, sha384, sha512, storageClass); JSG_STRUCT_TS_OVERRIDE(R2PutOptions); }; @@ -188,24 +209,51 @@ class R2Bucket: public jsg::Object { class HeadResult: public jsg::Object { public: - HeadResult(kj::String name, kj::String version, double size, - kj::String etag, jsg::Ref checksums, kj::Date uploaded, - jsg::Optional httpMetadata, - jsg::Optional> customMetadata, jsg::Optional range, - kj::String storageClass): - name(kj::mv(name)), version(kj::mv(version)), size(size), etag(kj::mv(etag)), - checksums(kj::mv(checksums)), uploaded(uploaded), httpMetadata(kj::mv(httpMetadata)), - customMetadata(kj::mv(customMetadata)), range(kj::mv(range)), - storageClass(kj::mv(storageClass)) {} - - kj::String getName() const { return kj::str(name); } - kj::String getVersion() const { return kj::str(version); } - double getSize() const { return size; } - kj::String getEtag() const { return kj::str(etag); } - kj::String getHttpEtag() const { return kj::str('"', etag, '"'); } - jsg::Ref getChecksums() { return checksums.addRef();} - kj::Date getUploaded() const { return uploaded; } - kj::StringPtr getStorageClass() const { return storageClass; } + HeadResult(kj::String name, + kj::String version, + double size, + kj::String etag, + jsg::Ref checksums, + kj::Date uploaded, + jsg::Optional httpMetadata, + jsg::Optional> customMetadata, + jsg::Optional range, + kj::String storageClass) + : name(kj::mv(name)), + version(kj::mv(version)), + size(size), + etag(kj::mv(etag)), + checksums(kj::mv(checksums)), + uploaded(uploaded), + httpMetadata(kj::mv(httpMetadata)), + customMetadata(kj::mv(customMetadata)), + range(kj::mv(range)), + storageClass(kj::mv(storageClass)) {} + + kj::String getName() const { + return kj::str(name); + } + kj::String getVersion() const { + return kj::str(version); + } + double getSize() const { + return size; + } + kj::String getEtag() const { + return kj::str(etag); + } + kj::String getHttpEtag() const { + return kj::str('"', etag, '"'); + } + jsg::Ref getChecksums() { + return checksums.addRef(); + } + kj::Date getUploaded() const { + return uploaded; + } + kj::StringPtr getStorageClass() const { + return storageClass; + } jsg::Optional getHttpMetadata() const { return httpMetadata.map([](const HttpMetadata& m) { return m.clone(); }); @@ -214,17 +262,17 @@ class R2Bucket: public jsg::Object { const jsg::Optional> getCustomMetadata() const { return customMetadata.map([](const jsg::Dict& m) { return jsg::Dict{ - .fields = KJ_MAP(f, m.fields) { - return jsg::Dict::Field{ - .name = kj::str(f.name), .value = kj::str(f.value) - }; - }, + .fields = + KJ_MAP(f, m.fields) { + return jsg::Dict::Field{.name = kj::str(f.name), .value = kj::str(f.value)}; + }, }; }); } - - jsg::Optional getRange() { return range; } + jsg::Optional getRange() { + return range; + } void writeHttpMetadata(jsg::Lock& js, Headers& headers); @@ -270,13 +318,27 @@ class R2Bucket: public jsg::Object { class GetResult: public HeadResult { public: - GetResult(kj::String name, kj::String version, double size, - kj::String etag, jsg::Ref checksums, kj::Date uploaded, jsg::Optional httpMetadata, - jsg::Optional> customMetadata, jsg::Optional range, kj::String storageClass, - jsg::Ref body) - : HeadResult( - kj::mv(name), kj::mv(version), size, kj::mv(etag), kj::mv(checksums), uploaded, - kj::mv(KJ_ASSERT_NONNULL(httpMetadata)), kj::mv(KJ_ASSERT_NONNULL(customMetadata)), range, kj::mv(storageClass)), + GetResult(kj::String name, + kj::String version, + double size, + kj::String etag, + jsg::Ref checksums, + kj::Date uploaded, + jsg::Optional httpMetadata, + jsg::Optional> customMetadata, + jsg::Optional range, + kj::String storageClass, + jsg::Ref body) + : HeadResult(kj::mv(name), + kj::mv(version), + size, + kj::mv(etag), + kj::mv(checksums), + uploaded, + kj::mv(KJ_ASSERT_NONNULL(httpMetadata)), + kj::mv(KJ_ASSERT_NONNULL(customMetadata)), + range, + kj::mv(storageClass)), body(kj::mv(body)) {} jsg::Ref getBody() { @@ -308,6 +370,7 @@ class R2Bucket: public jsg::Object { void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { tracker.trackField("body", body); } + private: jsg::Ref body; }; @@ -344,34 +407,35 @@ class R2Bucket: public jsg::Object { // from `R2BucketListOptions` to `R2ListOptions`. }; - jsg::Promise>> head( - jsg::Lock& js, kj::String key, - const jsg::TypeHandler>& errorType, CompatibilityFlags::Reader flags - ); - jsg::Promise>, jsg::Ref>> get( - jsg::Lock& js, kj::String key, jsg::Optional options, - const jsg::TypeHandler>& errorType, CompatibilityFlags::Reader flags - ); + jsg::Promise>> head(jsg::Lock& js, + kj::String key, + const jsg::TypeHandler>& errorType, + CompatibilityFlags::Reader flags); + jsg::Promise>, jsg::Ref>> get(jsg::Lock& js, + kj::String key, + jsg::Optional options, + const jsg::TypeHandler>& errorType, + CompatibilityFlags::Reader flags); jsg::Promise>> put(jsg::Lock& js, - kj::String key, kj::Maybe value, jsg::Optional options, - const jsg::TypeHandler>& errorType - ); - jsg::Promise> createMultipartUpload( - jsg::Lock& js, kj::String key, jsg::Optional options, - const jsg::TypeHandler>& errorType - ); - jsg::Ref resumeMultipartUpload( - jsg::Lock& js, kj::String key, kj::String uploadId, - const jsg::TypeHandler>& errorType - ); - jsg::Promise delete_( - jsg::Lock& js, kj::OneOf> keys, - const jsg::TypeHandler>& errorType - ); - jsg::Promise list( - jsg::Lock& js, jsg::Optional options, - const jsg::TypeHandler>& errorType, CompatibilityFlags::Reader flags - ); + kj::String key, + kj::Maybe value, + jsg::Optional options, + const jsg::TypeHandler>& errorType); + jsg::Promise> createMultipartUpload(jsg::Lock& js, + kj::String key, + jsg::Optional options, + const jsg::TypeHandler>& errorType); + jsg::Ref resumeMultipartUpload(jsg::Lock& js, + kj::String key, + kj::String uploadId, + const jsg::TypeHandler>& errorType); + jsg::Promise delete_(jsg::Lock& js, + kj::OneOf> keys, + const jsg::TypeHandler>& errorType); + jsg::Promise list(jsg::Lock& js, + jsg::Optional options, + const jsg::TypeHandler>& errorType, + CompatibilityFlags::Reader flags); JSG_RESOURCE_TYPE(R2Bucket, CompatibilityFlags::Reader flags) { JSG_METHOD(head); @@ -462,7 +526,6 @@ class R2Bucket: public jsg::Object { // Non-generic wrapper avoid moving the parseObjectMetadata implementation into this header file // by making use of dynamic dispatch. kj::Maybe> parseHeadResultWrapper( - kj::StringPtr action, R2Result& r2Result, const jsg::TypeHandler>& errorType); + kj::StringPtr action, R2Result& r2Result, const jsg::TypeHandler>& errorType); } // namespace workerd::api::public_beta - diff --git a/src/workerd/api/r2-multipart.c++ b/src/workerd/api/r2-multipart.c++ index 6e6d9f175e9..b8073ea3939 100644 --- a/src/workerd/api/r2-multipart.c++ +++ b/src/workerd/api/r2-multipart.c++ @@ -15,17 +15,17 @@ namespace workerd::api::public_beta { -jsg::Promise R2MultipartUpload::uploadPart( - jsg::Lock& js, - int partNumber, - R2PutValue value, - const jsg::TypeHandler>& errorType) { +jsg::Promise R2MultipartUpload::uploadPart(jsg::Lock& js, + int partNumber, + R2PutValue value, + const jsg::TypeHandler>& errorType) { return js.evalNow([&] { JSG_REQUIRE(partNumber >= 1 && partNumber <= 10000, TypeError, - "Part number must be between 1 and 10000 (inclusive). Actual value was: ", partNumber); + "Part number must be between 1 and 10000 (inclusive). Actual value was: ", partNumber); auto& context = IoContext::current(); - auto client = context.getHttpClient(this->bucket->clientIndex, true, kj::none, "r2_uploadPart"_kjc); + auto client = + context.getHttpClient(this->bucket->clientIndex, true, kj::none, "r2_uploadPart"_kjc); capnp::JsonCodec json; json.handleByAnnotation(); @@ -46,12 +46,11 @@ jsg::Promise R2MultipartUpload::uploadPart( kj::StringPtr components[1]; auto path = fillR2Path(components, this->bucket->adminBucket); - auto promise = doR2HTTPPutRequest(kj::mv(client), kj::mv(value), kj::none, - kj::mv(requestJson), path, kj::none); + auto promise = doR2HTTPPutRequest( + kj::mv(client), kj::mv(value), kj::none, kj::mv(requestJson), path, kj::none); - return context.awaitIo(js, kj::mv(promise), - [&errorType, partNumber] - (jsg::Lock& js, R2Result r2Result) mutable { + return context.awaitIo( + js, kj::mv(promise), [&errorType, partNumber](jsg::Lock& js, R2Result r2Result) mutable { r2Result.throwIfError("uploadPart", errorType); capnp::MallocMessageBuilder responseMessage; @@ -61,19 +60,19 @@ jsg::Promise R2MultipartUpload::uploadPart( json.decode(KJ_ASSERT_NONNULL(r2Result.metadataPayload), responseBuilder); kj::String etag = kj::str(responseBuilder.getEtag()); - UploadedPart uploadedPart = { partNumber, kj::mv(etag) }; + UploadedPart uploadedPart = {partNumber, kj::mv(etag)}; return uploadedPart; }); }); } -jsg::Promise> R2MultipartUpload::complete( - jsg::Lock& js, - kj::Array uploadedParts, - const jsg::TypeHandler>& errorType) { +jsg::Promise> R2MultipartUpload::complete(jsg::Lock& js, + kj::Array uploadedParts, + const jsg::TypeHandler>& errorType) { return js.evalNow([&] { auto& context = IoContext::current(); - auto client = context.getHttpClient(this->bucket->clientIndex, true, kj::none, "r2_completeMultipartUpload"_kjc); + auto client = context.getHttpClient( + this->bucket->clientIndex, true, kj::none, "r2_completeMultipartUpload"_kjc); capnp::JsonCodec json; json.handleByAnnotation(); @@ -81,7 +80,8 @@ jsg::Promise> R2MultipartUpload::complete( auto requestBuilder = requestMessage.initRoot(); requestBuilder.setVersion(VERSION_PUBLIC_BETA); - auto completeMultipartUploadBuilder = requestBuilder.initPayload().initCompleteMultipartUpload(); + auto completeMultipartUploadBuilder = + requestBuilder.initPayload().initCompleteMultipartUpload(); completeMultipartUploadBuilder.setObject(key); completeMultipartUploadBuilder.setUploadId(uploadId); @@ -91,7 +91,7 @@ jsg::Promise> R2MultipartUpload::complete( for (unsigned int i = 0; i < uploadedParts.size(); i++) { int partNumber = currentPart->partNumber; JSG_REQUIRE(partNumber >= 1 && partNumber <= 10000, TypeError, - "Part number must be between 1 and 10000 (inclusive). Actual value was: ", partNumber); + "Part number must be between 1 and 10000 (inclusive). Actual value was: ", partNumber); partsList[i].setPart(partNumber); partsList[i].setEtag(currentPart->etag); currentPart = std::next(currentPart); @@ -101,26 +101,28 @@ jsg::Promise> R2MultipartUpload::complete( kj::StringPtr components[1]; auto path = fillR2Path(components, this->bucket->adminBucket); - auto promise = doR2HTTPPutRequest(kj::mv(client), kj::none, kj::none, kj::mv(requestJson), - path, kj::none); + auto promise = + doR2HTTPPutRequest(kj::mv(client), kj::none, kj::none, kj::mv(requestJson), path, kj::none); - return context.awaitIo(js, kj::mv(promise), - [&errorType] - (jsg::Lock& js, R2Result r2Result) mutable { + return context.awaitIo( + js, kj::mv(promise), [&errorType](jsg::Lock& js, R2Result r2Result) mutable { auto parsedObject = parseHeadResultWrapper("completeMultipartUpload", r2Result, errorType); KJ_IF_SOME(obj, parsedObject) { return obj.addRef(); } else { - KJ_FAIL_ASSERT("Shouldn't happen, multipart completion should either error or return an object"); + KJ_FAIL_ASSERT( + "Shouldn't happen, multipart completion should either error or return an object"); } }); }); } -jsg::Promise R2MultipartUpload::abort(jsg::Lock& js, const jsg::TypeHandler>& errorType) { +jsg::Promise R2MultipartUpload::abort( + jsg::Lock& js, const jsg::TypeHandler>& errorType) { return js.evalNow([&] { auto& context = IoContext::current(); - auto client = context.getHttpClient(this->bucket->clientIndex, true, kj::none, "r2_abortMultipartUpload"_kjc); + auto client = context.getHttpClient( + this->bucket->clientIndex, true, kj::none, "r2_abortMultipartUpload"_kjc); capnp::JsonCodec json; json.handleByAnnotation(); @@ -137,8 +139,8 @@ jsg::Promise R2MultipartUpload::abort(jsg::Lock& js, const jsg::TypeHandle kj::StringPtr components[1]; auto path = fillR2Path(components, this->bucket->adminBucket); - auto promise = doR2HTTPPutRequest(kj::mv(client), kj::none, kj::none, kj::mv(requestJson), - path, kj::none); + auto promise = + doR2HTTPPutRequest(kj::mv(client), kj::none, kj::none, kj::mv(requestJson), path, kj::none); return context.awaitIo(js, kj::mv(promise), [&errorType](jsg::Lock& js, R2Result r) { if (r.objectNotFound()) { @@ -149,4 +151,4 @@ jsg::Promise R2MultipartUpload::abort(jsg::Lock& js, const jsg::TypeHandle }); }); } -} +} // namespace workerd::api::public_beta diff --git a/src/workerd/api/r2-multipart.h b/src/workerd/api/r2-multipart.h index c3160d62436..8a5af5ba869 100644 --- a/src/workerd/api/r2-multipart.h +++ b/src/workerd/api/r2-multipart.h @@ -11,54 +11,59 @@ namespace workerd::api::public_beta { class R2MultipartUpload: public jsg::Object { - public: - struct UploadedPart { - int partNumber; - kj::String etag; +public: + struct UploadedPart { + int partNumber; + kj::String etag; - JSG_STRUCT(partNumber, etag); - JSG_STRUCT_TS_OVERRIDE(R2UploadedPart); - }; + JSG_STRUCT(partNumber, etag); + JSG_STRUCT_TS_OVERRIDE(R2UploadedPart); + }; - R2MultipartUpload(kj::String key, kj::String uploadId, jsg::Ref bucket): - key(kj::mv(key)), uploadId(kj::mv(uploadId)), bucket(kj::mv(bucket)) {} + R2MultipartUpload(kj::String key, kj::String uploadId, jsg::Ref bucket) + : key(kj::mv(key)), + uploadId(kj::mv(uploadId)), + bucket(kj::mv(bucket)) {} - kj::StringPtr getKey() const { return kj::StringPtr(key); } - kj::StringPtr getUploadId() const { return kj::StringPtr(uploadId); } + kj::StringPtr getKey() const { + return kj::StringPtr(key); + } + kj::StringPtr getUploadId() const { + return kj::StringPtr(uploadId); + } - jsg::Promise uploadPart( - jsg::Lock& js, int partNumber, R2PutValue value, - const jsg::TypeHandler>& errorType - ); - jsg::Promise abort(jsg::Lock& js, const jsg::TypeHandler>& errorType); - jsg::Promise> complete( - jsg::Lock& js, kj::Array uploadedParts, - const jsg::TypeHandler>& errorType - ); + jsg::Promise uploadPart(jsg::Lock& js, + int partNumber, + R2PutValue value, + const jsg::TypeHandler>& errorType); + jsg::Promise abort(jsg::Lock& js, const jsg::TypeHandler>& errorType); + jsg::Promise> complete(jsg::Lock& js, + kj::Array uploadedParts, + const jsg::TypeHandler>& errorType); - JSG_RESOURCE_TYPE(R2MultipartUpload) { - JSG_LAZY_READONLY_INSTANCE_PROPERTY(key, getKey); - JSG_LAZY_READONLY_INSTANCE_PROPERTY(uploadId, getUploadId); - JSG_METHOD(uploadPart); - JSG_METHOD(abort); - JSG_METHOD(complete); - } + JSG_RESOURCE_TYPE(R2MultipartUpload) { + JSG_LAZY_READONLY_INSTANCE_PROPERTY(key, getKey); + JSG_LAZY_READONLY_INSTANCE_PROPERTY(uploadId, getUploadId); + JSG_METHOD(uploadPart); + JSG_METHOD(abort); + JSG_METHOD(complete); + } - void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { - tracker.trackField("key", key); - tracker.trackField("uploadId", uploadId); - tracker.trackField("bucket", bucket); - } + void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { + tracker.trackField("key", key); + tracker.trackField("uploadId", uploadId); + tracker.trackField("bucket", bucket); + } - protected: - kj::String key; - kj::String uploadId; - jsg::Ref bucket; +protected: + kj::String key; + kj::String uploadId; + jsg::Ref bucket; - private: - void visitForGc(jsg::GcVisitor& visitor) { - visitor.visit(bucket); - } +private: + void visitForGc(jsg::GcVisitor& visitor) { + visitor.visit(bucket); + } }; -} +} // namespace workerd::api::public_beta diff --git a/src/workerd/api/r2-rpc.c++ b/src/workerd/api/r2-rpc.c++ index 5a8131e513d..c0731e3c415 100644 --- a/src/workerd/api/r2-rpc.c++ +++ b/src/workerd/api/r2-rpc.c++ @@ -35,8 +35,8 @@ kj::Maybe R2Result::v4ErrorCode() { return kj::none; } -void R2Result::throwIfError(kj::StringPtr action, - const jsg::TypeHandler>& errorType) { +void R2Result::throwIfError( + kj::StringPtr action, const jsg::TypeHandler>& errorType) { KJ_IF_SOME(e, toThrow) { // TODO(soon): Once jsg::JsPromise exists, switch to using that to tunnel out the exception. As // it stands today, unfortunately, all we can send back to the user is a message. R2Error isn't @@ -50,8 +50,7 @@ void R2Result::throwIfError(kj::StringPtr action, isolate->ThrowException(errorType.wrapRef(kj::mv(*e))); throw jsg::JsExceptionThrown(); #else - JSG_FAIL_REQUIRE(Error, kj::str( - action, ": ", e.get()->getMessage(), " (", e->v4Code, ')')); + JSG_FAIL_REQUIRE(Error, kj::str(action, ": ", e.get()->getMessage(), " (", e->v4Code, ')')); #endif } } @@ -61,7 +60,7 @@ kj::String getFakeUrl(kj::ArrayPtr path) { kj::Url url; url.scheme = kj::str("https"); url.host = kj::str("fake-host"); - for (const auto& p : path) { + for (const auto& p: path) { url.path.add(kj::str(p)); } return url.toString(kj::Url::Context::HTTP_PROXY_REQUEST); @@ -69,10 +68,10 @@ kj::String getFakeUrl(kj::ArrayPtr path) { } // namespace kj::Promise doR2HTTPGetRequest(kj::Own client, - kj::String metadataPayload, - kj::ArrayPtr path, - kj::Maybe jwt, - CompatibilityFlags::Reader flags) { + kj::String metadataPayload, + kj::ArrayPtr path, + kj::Maybe jwt, + CompatibilityFlags::Reader flags) { auto& context = IoContext::current(); auto url = getFakeUrl(path); @@ -84,13 +83,10 @@ kj::Promise doR2HTTPGetRequest(kj::Own client, requestHeaders.set(headerIds.authorization, kj::str("Bearer ", j)); } - static auto constexpr processStream = [](kj::StringPtr metadata, - kj::HttpClient::Response& response, - kj::Own client, - CompatibilityFlags::Reader flags, - IoContext& context) -> kj::Promise { - auto stream = newSystemStream( - response.body.attach(kj::mv(client)), + static auto constexpr processStream = + [](kj::StringPtr metadata, kj::HttpClient::Response& response, kj::Own client, + CompatibilityFlags::Reader flags, IoContext& context) -> kj::Promise { + auto stream = newSystemStream(response.body.attach(kj::mv(client)), getContentEncoding(context, *response.headers, Response::BodyEncoding::AUTO, flags), context); auto metadataSize = atoi((metadata).cStr()); @@ -105,14 +101,12 @@ kj::Promise doR2HTTPGetRequest(kj::Own client, auto metadataReadLength = co_await stream->tryRead(metadataBuffer.begin(), metadataSize, metadataSize); - KJ_ASSERT(metadataReadLength == metadataBuffer.size(), - "R2 metadata buffer not read fully/overflow?"); + KJ_ASSERT( + metadataReadLength == metadataBuffer.size(), "R2 metadata buffer not read fully/overflow?"); - co_return R2Result { - .httpStatus = response.statusCode, + co_return R2Result{.httpStatus = response.statusCode, .metadataPayload = kj::mv(metadataBuffer), - .stream = kj::mv(stream) - }; + .stream = kj::mv(stream)}; }; auto request = client->request(kj::HttpMethod::GET, url, requestHeaders, (uint64_t)0); @@ -123,11 +117,12 @@ kj::Promise doR2HTTPGetRequest(kj::Own client, // Error responses should have a cfR2ErrorHeader but don't always. If there // isn't one, we'll use a generic error. if (response.headers->get(headerIds.cfR2ErrorHeader) == kj::none) { - LOG_WARNING_ONCE("R2 error response does not contain the CF-R2-Error header.", - response.statusCode); + LOG_WARNING_ONCE( + "R2 error response does not contain the CF-R2-Error header.", response.statusCode); } - auto error = response.headers->get(headerIds.cfR2ErrorHeader).orDefault( - "{\"version\":0,\"v4code\":0,\"message\":\"Unspecified error\"}"_kj); + auto error = + response.headers->get(headerIds.cfR2ErrorHeader) + .orDefault("{\"version\":0,\"v4code\":0,\"message\":\"Unspecified error\"}"_kj); R2Result result = { .httpStatus = response.statusCode, @@ -146,16 +141,16 @@ kj::Promise doR2HTTPGetRequest(kj::Own client, KJ_IF_SOME(m, response.headers->get(headerIds.cfBlobMetadataSize)) { co_return co_await processStream(m, response, kj::mv(client), flags, context); } else { - co_return R2Result { .httpStatus = response.statusCode }; + co_return R2Result{.httpStatus = response.statusCode}; } } kj::Promise doR2HTTPPutRequest(kj::Own client, - kj::Maybe supportedBody, - kj::Maybe streamSize, - kj::String metadataPayload, - kj::ArrayPtr path, - kj::Maybe jwt) { + kj::Maybe supportedBody, + kj::Maybe streamSize, + kj::String metadataPayload, + kj::ArrayPtr path, + kj::Maybe jwt) { // NOTE: A lot of code here is duplicated with kv.c++. Maybe it can be refactored to be more // reusable? auto& context = IoContext::current(); @@ -175,8 +170,10 @@ kj::Promise doR2HTTPPutRequest(kj::Own client, "Provided readable stream must have a known length (request/response body or readable " "half of FixedLengthStream)"); JSG_REQUIRE(streamSize.orDefault(KJ_ASSERT_NONNULL(expectedBodySize)) == expectedBodySize, - RangeError, "Provided stream length (", streamSize.orDefault(-1), ") doesn't match what " - "the stream reports (", KJ_ASSERT_NONNULL(expectedBodySize), ")"); + RangeError, "Provided stream length (", streamSize.orDefault(-1), + ") doesn't match what " + "the stream reports (", + KJ_ASSERT_NONNULL(expectedBodySize), ")"); } KJ_CASE_ONEOF(text, jsg::NonCoercible) { expectedBodySize = text.value.size(); @@ -226,9 +223,8 @@ kj::Promise doR2HTTPPutRequest(kj::Own client, // start running the pump within the IoContex/isolate lock. co_await context.run( [dest = newSystemStream(kj::mv(request.body), StreamEncoding::IDENTITY, context), - stream = kj::mv(stream)](jsg::Lock& js) mutable { - return IoContext::current().waitForDeferredProxy( - stream->pumpTo(js, kj::mv(dest), true)); + stream = kj::mv(stream)](jsg::Lock& js) mutable { + return IoContext::current().waitForDeferredProxy(stream->pumpTo(js, kj::mv(dest), true)); }); } } @@ -241,13 +237,14 @@ kj::Promise doR2HTTPPutRequest(kj::Own client, // isn't one, we'll use a generic error. auto& headerIds = context.getHeaderIds(); if (response.headers->get(headerIds.cfR2ErrorHeader) == kj::none) { - LOG_WARNING_ONCE("R2 error response does not contain the CF-R2-Error header.", - response.statusCode); + LOG_WARNING_ONCE( + "R2 error response does not contain the CF-R2-Error header.", response.statusCode); } - auto error = response.headers->get(headerIds.cfR2ErrorHeader).orDefault( - "{\"version\":0,\"v4code\":0,\"message\":\"Unspecified error\"}"_kj); + auto error = + response.headers->get(headerIds.cfR2ErrorHeader) + .orDefault("{\"version\":0,\"v4code\":0,\"message\":\"Unspecified error\"}"_kj); - co_return R2Result { + co_return R2Result{ .httpStatus = response.statusCode, .toThrow = toError(response.statusCode, error), }; diff --git a/src/workerd/api/r2-rpc.h b/src/workerd/api/r2-rpc.h index 1e45dce242c..62bf13d8d51 100644 --- a/src/workerd/api/r2-rpc.h +++ b/src/workerd/api/r2-rpc.h @@ -21,10 +21,18 @@ class R2Error: public jsg::Object { public: R2Error(uint v4Code, kj::String message): v4Code(v4Code), message(kj::mv(message)) {} - constexpr kj::StringPtr getName() const { return "R2Error"_kj; } - uint getV4Code() const { return v4Code; } - kj::StringPtr getMessage() const { return message; } - kj::StringPtr getAction() const { return KJ_ASSERT_NONNULL(action); } + constexpr kj::StringPtr getName() const { + return "R2Error"_kj; + } + uint getV4Code() const { + return v4Code; + } + kj::StringPtr getMessage() const { + return message; + } + kj::StringPtr getAction() const { + return KJ_ASSERT_NONNULL(action); + } jsg::JsValue getStack(jsg::Lock& js); JSG_RESOURCE_TYPE(R2Error) { @@ -53,8 +61,10 @@ class R2Error: public jsg::Object { friend struct R2Result; }; -using R2PutValue = kj::OneOf, kj::Array, - jsg::NonCoercible, jsg::Ref>; +using R2PutValue = kj::OneOf, + kj::Array, + jsg::NonCoercible, + jsg::Ref>; struct R2Result { uint httpStatus; @@ -78,14 +88,13 @@ struct R2Result { void throwIfError(kj::StringPtr action, const jsg::TypeHandler>& errorType); }; -kj::Promise doR2HTTPGetRequest( - kj::Own client, +kj::Promise doR2HTTPGetRequest(kj::Own client, kj::String metadataPayload, kj::ArrayPtr path, - kj::Maybe jwt, CompatibilityFlags::Reader flags); + kj::Maybe jwt, + CompatibilityFlags::Reader flags); -kj::Promise doR2HTTPPutRequest( - kj::Own client, +kj::Promise doR2HTTPPutRequest(kj::Own client, kj::Maybe value, kj::Maybe streamSize, // Deprecated. For internal beta API only. @@ -93,4 +102,4 @@ kj::Promise doR2HTTPPutRequest( kj::ArrayPtr path, kj::Maybe jwt); -} // namespace workerd::api +} // namespace workerd::api diff --git a/src/workerd/api/r2.h b/src/workerd/api/r2.h index 23dad20800b..37d95230838 100644 --- a/src/workerd/api/r2.h +++ b/src/workerd/api/r2.h @@ -7,24 +7,15 @@ #include "r2-bucket.h" #include "r2-multipart.h" - namespace workerd::api::public_beta { - #define EW_R2_PUBLIC_BETA_ISOLATE_TYPES \ - api::R2Error, \ - api::public_beta::R2Bucket, \ - api::public_beta::R2MultipartUpload, \ - api::public_beta::R2MultipartUpload::UploadedPart, \ - api::public_beta::R2Bucket::HeadResult, \ - api::public_beta::R2Bucket::GetResult, \ - api::public_beta::R2Bucket::Range, \ - api::public_beta::R2Bucket::Conditional, \ - api::public_beta::R2Bucket::GetOptions, \ - api::public_beta::R2Bucket::PutOptions, \ - api::public_beta::R2Bucket::MultipartOptions, \ - api::public_beta::R2Bucket::Checksums, \ - api::public_beta::R2Bucket::StringChecksums, \ - api::public_beta::R2Bucket::HttpMetadata, \ - api::public_beta::R2Bucket::ListOptions, \ - api::public_beta::R2Bucket::ListResult - // The list of r2 types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE -} +#define EW_R2_PUBLIC_BETA_ISOLATE_TYPES \ + api::R2Error, api::public_beta::R2Bucket, api::public_beta::R2MultipartUpload, \ + api::public_beta::R2MultipartUpload::UploadedPart, api::public_beta::R2Bucket::HeadResult, \ + api::public_beta::R2Bucket::GetResult, api::public_beta::R2Bucket::Range, \ + api::public_beta::R2Bucket::Conditional, api::public_beta::R2Bucket::GetOptions, \ + api::public_beta::R2Bucket::PutOptions, api::public_beta::R2Bucket::MultipartOptions, \ + api::public_beta::R2Bucket::Checksums, api::public_beta::R2Bucket::StringChecksums, \ + api::public_beta::R2Bucket::HttpMetadata, api::public_beta::R2Bucket::ListOptions, \ + api::public_beta::R2Bucket::ListResult +// The list of r2 types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE +} // namespace workerd::api::public_beta diff --git a/src/workerd/api/rtti.c++ b/src/workerd/api/rtti.c++ index bfff1eb5f32..42a5960cb66 100644 --- a/src/workerd/api/rtti.c++ +++ b/src/workerd/api/rtti.c++ @@ -43,42 +43,42 @@ #define EW_WEBGPU_ISOLATE_TYPES #endif -#define EW_TYPE_GROUP_FOR_EACH(F) \ - F("dom-exception", jsg::DOMException) \ - F("global-scope", EW_GLOBAL_SCOPE_ISOLATE_TYPES) \ - F("durable-objects", EW_ACTOR_ISOLATE_TYPES) \ - F("durable-objects-state", EW_ACTOR_STATE_ISOLATE_TYPES) \ - F("analytics-engine", EW_ANALYTICS_ENGINE_ISOLATE_TYPES) \ - F("basics", EW_BASICS_ISOLATE_TYPES) \ - F("blob", EW_BLOB_ISOLATE_TYPES) \ - F("cache", EW_CACHE_ISOLATE_TYPES) \ - F("crypto", EW_CRYPTO_ISOLATE_TYPES) \ - F("encoding", EW_ENCODING_ISOLATE_TYPES) \ - F("events", EW_EVENTS_ISOLATE_TYPES) \ - F("form-data", EW_FORMDATA_ISOLATE_TYPES) \ - F("html-rewriter", EW_HTML_REWRITER_ISOLATE_TYPES) \ - F("http", EW_HTTP_ISOLATE_TYPES) \ - F("hyperdrive", EW_HYPERDRIVE_ISOLATE_TYPES) \ - F("unsafe", EW_UNSAFE_ISOLATE_TYPES) \ - F("memory-cache", EW_MEMORY_CACHE_ISOLATE_TYPES) \ - F("pyodide", EW_PYODIDE_ISOLATE_TYPES) \ - F("kv", EW_KV_ISOLATE_TYPES) \ - F("queue", EW_QUEUE_ISOLATE_TYPES) \ - F("r2-admin", EW_R2_PUBLIC_BETA_ADMIN_ISOLATE_TYPES) \ - F("r2", EW_R2_PUBLIC_BETA_ISOLATE_TYPES) \ - F("worker-rpc", EW_WORKER_RPC_ISOLATE_TYPES) \ - F("scheduled", EW_SCHEDULED_ISOLATE_TYPES) \ - F("streams", EW_STREAMS_ISOLATE_TYPES) \ - F("trace", EW_TRACE_ISOLATE_TYPES) \ - F("url", EW_URL_ISOLATE_TYPES) \ - F("url-standard", EW_URL_STANDARD_ISOLATE_TYPES) \ - F("url-pattern", EW_URLPATTERN_ISOLATE_TYPES) \ - F("websocket", EW_WEBSOCKET_ISOLATE_TYPES) \ - F("sql", EW_SQL_ISOLATE_TYPES) \ - F("sockets", EW_SOCKETS_ISOLATE_TYPES) \ - F("node", EW_NODE_ISOLATE_TYPES) \ - F("rtti", EW_RTTI_ISOLATE_TYPES) \ - F("webgpu", EW_WEBGPU_ISOLATE_TYPES) \ +#define EW_TYPE_GROUP_FOR_EACH(F) \ + F("dom-exception", jsg::DOMException) \ + F("global-scope", EW_GLOBAL_SCOPE_ISOLATE_TYPES) \ + F("durable-objects", EW_ACTOR_ISOLATE_TYPES) \ + F("durable-objects-state", EW_ACTOR_STATE_ISOLATE_TYPES) \ + F("analytics-engine", EW_ANALYTICS_ENGINE_ISOLATE_TYPES) \ + F("basics", EW_BASICS_ISOLATE_TYPES) \ + F("blob", EW_BLOB_ISOLATE_TYPES) \ + F("cache", EW_CACHE_ISOLATE_TYPES) \ + F("crypto", EW_CRYPTO_ISOLATE_TYPES) \ + F("encoding", EW_ENCODING_ISOLATE_TYPES) \ + F("events", EW_EVENTS_ISOLATE_TYPES) \ + F("form-data", EW_FORMDATA_ISOLATE_TYPES) \ + F("html-rewriter", EW_HTML_REWRITER_ISOLATE_TYPES) \ + F("http", EW_HTTP_ISOLATE_TYPES) \ + F("hyperdrive", EW_HYPERDRIVE_ISOLATE_TYPES) \ + F("unsafe", EW_UNSAFE_ISOLATE_TYPES) \ + F("memory-cache", EW_MEMORY_CACHE_ISOLATE_TYPES) \ + F("pyodide", EW_PYODIDE_ISOLATE_TYPES) \ + F("kv", EW_KV_ISOLATE_TYPES) \ + F("queue", EW_QUEUE_ISOLATE_TYPES) \ + F("r2-admin", EW_R2_PUBLIC_BETA_ADMIN_ISOLATE_TYPES) \ + F("r2", EW_R2_PUBLIC_BETA_ISOLATE_TYPES) \ + F("worker-rpc", EW_WORKER_RPC_ISOLATE_TYPES) \ + F("scheduled", EW_SCHEDULED_ISOLATE_TYPES) \ + F("streams", EW_STREAMS_ISOLATE_TYPES) \ + F("trace", EW_TRACE_ISOLATE_TYPES) \ + F("url", EW_URL_ISOLATE_TYPES) \ + F("url-standard", EW_URL_STANDARD_ISOLATE_TYPES) \ + F("url-pattern", EW_URLPATTERN_ISOLATE_TYPES) \ + F("websocket", EW_WEBSOCKET_ISOLATE_TYPES) \ + F("sql", EW_SQL_ISOLATE_TYPES) \ + F("sockets", EW_SOCKETS_ISOLATE_TYPES) \ + F("node", EW_NODE_ISOLATE_TYPES) \ + F("rtti", EW_RTTI_ISOLATE_TYPES) \ + F("webgpu", EW_WEBGPU_ISOLATE_TYPES) \ F("eventsource", EW_EVENTSOURCE_ISOLATE_TYPES) namespace workerd::api { @@ -87,18 +87,19 @@ namespace { struct EncoderModuleRegistryImpl { struct CppModuleContents { - CppModuleContents(kj::String structureName) : structureName(kj::mv(structureName)) {} + CppModuleContents(kj::String structureName): structureName(kj::mv(structureName)) {} kj::String structureName; }; struct TypeScriptModuleContents { - TypeScriptModuleContents(kj::StringPtr tsDeclarations) : tsDeclarations(tsDeclarations) {} + TypeScriptModuleContents(kj::StringPtr tsDeclarations): tsDeclarations(tsDeclarations) {} kj::StringPtr tsDeclarations; }; struct ModuleInfo { - ModuleInfo(kj::StringPtr specifier, jsg::ModuleType type, kj::OneOf contents) + ModuleInfo(kj::StringPtr specifier, + jsg::ModuleType type, + kj::OneOf contents) : specifier(specifier), type(type), contents(kj::mv(contents)) {} @@ -108,46 +109,48 @@ struct EncoderModuleRegistryImpl { kj::OneOf contents; }; - void addBuiltinBundle(jsg::Bundle::Reader bundle, kj::Maybe maybeFilter = kj::none) { + void addBuiltinBundle( + jsg::Bundle::Reader bundle, kj::Maybe maybeFilter = kj::none) { for (auto module: bundle.getModules()) { if (module.getType() == maybeFilter.orDefault(module.getType())) addBuiltinModule(module); } } void addBuiltinModule(jsg::Module::Reader module) { - TypeScriptModuleContents contents (module.getTsDeclaration()); - ModuleInfo info (module.getName(), module.getType(), kj::mv(contents)); + TypeScriptModuleContents contents(module.getTsDeclaration()); + ModuleInfo info(module.getName(), module.getType(), kj::mv(contents)); modules.add(kj::mv(info)); } template - void addBuiltinModule(kj::StringPtr specifier, jsg::ModuleRegistry::Type type = jsg::ModuleRegistry::Type::BUILTIN) { + void addBuiltinModule(kj::StringPtr specifier, + jsg::ModuleRegistry::Type type = jsg::ModuleRegistry::Type::BUILTIN) { auto structureName = jsg::fullyQualifiedTypeName(typeid(T)); - CppModuleContents contents (kj::mv(structureName)); - ModuleInfo info (specifier, type, kj::mv(contents)); + CppModuleContents contents(kj::mv(structureName)); + ModuleInfo info(specifier, type, kj::mv(contents)); modules.add(kj::mv(info)); } kj::Vector modules; }; -CompatibilityFlags::Reader compileFlags(capnp::MessageBuilder &message, kj::StringPtr compatDate, - bool experimental, kj::ArrayPtr compatFlags) { +CompatibilityFlags::Reader compileFlags(capnp::MessageBuilder &message, + kj::StringPtr compatDate, + bool experimental, + kj::ArrayPtr compatFlags) { // Based on src/workerd/io/compatibility-date-test.c++ auto orphanage = message.getOrphanage(); - auto flagListOrphan = - orphanage.newOrphan>(compatFlags.size()); + auto flagListOrphan = orphanage.newOrphan>(compatFlags.size()); auto flagList = flagListOrphan.get(); - for (auto i : kj::indices(compatFlags)) { + for (auto i: kj::indices(compatFlags)) { flagList.set(i, compatFlags.begin()[i]); } auto output = message.initRoot(); SimpleWorkerErrorReporter errorReporter; - compileCompatibilityFlags(compatDate, flagList.asReader(), output, - errorReporter, experimental, - CompatibilityDateValidation::FUTURE_FOR_TEST); + compileCompatibilityFlags(compatDate, flagList.asReader(), output, errorReporter, experimental, + CompatibilityDateValidation::FUTURE_FOR_TEST); if (!errorReporter.errors.empty()) { // TODO(someday): throw an `AggregateError` containing all errors @@ -172,8 +175,7 @@ CompatibilityFlags::Reader compileAllFlags(capnp::MessageBuilder &message) { enableFlagName = annotation.getValue().getText(); // Exclude nodejs_compat, since the type generation scripts don't support node:* imports // TODO: Figure out typing for node compat - isNode = enableFlagName == "nodejs_compat" || - enableFlagName == "nodejs_compat_v2"; + isNode = enableFlagName == "nodejs_compat" || enableFlagName == "nodejs_compat_v2"; } } @@ -186,7 +188,9 @@ CompatibilityFlags::Reader compileAllFlags(capnp::MessageBuilder &message) { struct TypesEncoder { public: TypesEncoder(): compatFlags(kj::heapArray(0)) {} - TypesEncoder(kj::String compatDate, kj::Array compatFlags): compatDate(kj::mv(compatDate)), compatFlags(kj::mv(compatFlags)) {} + TypesEncoder(kj::String compatDate, kj::Array compatFlags) + : compatDate(kj::mv(compatDate)), + compatFlags(kj::mv(compatFlags)) {} kj::Array encode() { capnp::MallocMessageBuilder flagsMessage; @@ -222,7 +226,7 @@ public: unsigned int i = 0; auto modulesBuilder = root.initModules(registry.modules.size()); for (auto moduleBuilder: modulesBuilder) { - auto& module = registry.modules[i++]; + auto &module = registry.modules[i++]; moduleBuilder.setSpecifier(module.specifier); KJ_SWITCH_ONEOF(module.contents) { KJ_CASE_ONEOF(contents, EncoderModuleRegistryImpl::CppModuleContents) { @@ -242,15 +246,15 @@ public: private: template void writeStructure(jsg::rtti::Builder &builder, - capnp::List::Builder structures) { + capnp::List::Builder structures) { auto reader = builder.structure(); structures.setWithCaveats(structureIndex++, reader); } template - void writeGroup( - capnp::List::Builder &groups, - jsg::rtti::Builder &builder, kj::StringPtr name) { + void writeGroup(capnp::List::Builder &groups, + jsg::rtti::Builder &builder, + kj::StringPtr name) { auto group = groups[groupsIndex++]; group.setName(name); @@ -268,7 +272,7 @@ private: unsigned int structureIndex = 0; }; -} // namespace +} // namespace kj::Array RTTIModule::exportTypes(kj::String compatDate, kj::Array compatFlags) { TypesEncoder encoder(kj::mv(compatDate), kj::mv(compatFlags)); @@ -280,4 +284,4 @@ kj::Array RTTIModule::exportExperimentalTypes() { return encoder.encode(); } -} // namespace workerd::api +} // namespace workerd::api diff --git a/src/workerd/api/rtti.h b/src/workerd/api/rtti.h index 5b3e8ba934c..3548a45429a 100644 --- a/src/workerd/api/rtti.h +++ b/src/workerd/api/rtti.h @@ -30,8 +30,8 @@ class RTTIModule final: public jsg::Object { template void registerRTTIModule(Registry& registry) { - registry.template addBuiltinModule("workerd:rtti", - workerd::jsg::ModuleRegistry::Type::BUILTIN); + registry.template addBuiltinModule( + "workerd:rtti", workerd::jsg::ModuleRegistry::Type::BUILTIN); } template @@ -45,4 +45,4 @@ kj::Own getExternalRttiModuleBundle(auto featureFlag #define EW_RTTI_ISOLATE_TYPES api::RTTIModule -} // namespace workerd::api +} // namespace workerd::api diff --git a/src/workerd/api/scheduled.c++ b/src/workerd/api/scheduled.c++ index 110d84b2a92..f451e2d0ff6 100644 --- a/src/workerd/api/scheduled.c++ +++ b/src/workerd/api/scheduled.c++ @@ -7,10 +7,12 @@ namespace workerd::api { ScheduledEvent::ScheduledEvent(double scheduledTime, kj::StringPtr cron) - : ExtendableEvent("scheduled"), scheduledTime(scheduledTime), cron(kj::str(cron)) {} + : ExtendableEvent("scheduled"), + scheduledTime(scheduledTime), + cron(kj::str(cron)) {} void ScheduledEvent::noRetry() { IoContext::current().setNoRetryScheduled(); } -} // namespace workerd::api +} // namespace workerd::api diff --git a/src/workerd/api/scheduled.h b/src/workerd/api/scheduled.h index c64c346e036..ad7f6484eea 100644 --- a/src/workerd/api/scheduled.h +++ b/src/workerd/api/scheduled.h @@ -15,16 +15,20 @@ class ScheduledEvent final: public ExtendableEvent { static jsg::Ref constructor(kj::String type) = delete; - double getScheduledTime() { return scheduledTime; } - kj::StringPtr getCron() { return cron; } + double getScheduledTime() { + return scheduledTime; + } + kj::StringPtr getCron() { + return cron; + } void noRetry(); JSG_RESOURCE_TYPE(ScheduledEvent) { - JSG_INHERIT(ExtendableEvent); + JSG_INHERIT(ExtendableEvent); - JSG_READONLY_INSTANCE_PROPERTY(scheduledTime, getScheduledTime); - JSG_READONLY_INSTANCE_PROPERTY(cron, getCron); - JSG_METHOD(noRetry); + JSG_READONLY_INSTANCE_PROPERTY(scheduledTime, getScheduledTime); + JSG_READONLY_INSTANCE_PROPERTY(cron, getCron); + JSG_METHOD(noRetry); } void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { @@ -39,12 +43,17 @@ class ScheduledEvent final: public ExtendableEvent { // Type used when calling a module-exported scheduled event handler. class ScheduledController final: public jsg::Object { public: - ScheduledController(jsg::Ref event) - : event(kj::mv(event)) {} + ScheduledController(jsg::Ref event): event(kj::mv(event)) {} - double getScheduledTime() { return event->getScheduledTime(); } - kj::StringPtr getCron() { return event->getCron(); } - void noRetry() { event->noRetry(); } + double getScheduledTime() { + return event->getScheduledTime(); + } + kj::StringPtr getCron() { + return event->getCron(); + } + void noRetry() { + event->noRetry(); + } JSG_RESOURCE_TYPE(ScheduledController) { JSG_READONLY_INSTANCE_PROPERTY(scheduledTime, getScheduledTime); @@ -64,8 +73,6 @@ class ScheduledController final: public jsg::Object { } }; -#define EW_SCHEDULED_ISOLATE_TYPES \ - api::ScheduledEvent, \ - api::ScheduledController +#define EW_SCHEDULED_ISOLATE_TYPES api::ScheduledEvent, api::ScheduledController // The list of scheduled.h types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE -} // namespace workerd::api +} // namespace workerd::api diff --git a/src/workerd/api/sockets.c++ b/src/workerd/api/sockets.c++ index ff2a5413c52..1ac5ab51df3 100644 --- a/src/workerd/api/sockets.c++ +++ b/src/workerd/api/sockets.c++ @@ -23,16 +23,17 @@ bool isValidHost(kj::StringPtr host) { return false; } - for (auto i : kj::indices(host)) { + for (auto i: kj::indices(host)) { switch (host[i]) { case '-': case '.': case '_': - case '[': case ']': case ':': // For IPv6. + case '[': + case ']': + case ':': // For IPv6. break; default: - if ((host[i] >= 'a' && host[i] <= 'z') || - (host[i] >= 'A' && host[i] <= 'Z') || + if ((host[i] >= 'a' && host[i] <= 'z') || (host[i] >= 'A' && host[i] <= 'Z') || (host[i] >= '0' && host[i] <= '9')) { break; } @@ -51,8 +52,8 @@ SecureTransportKind parseSecureTransport(SocketOptions& opts) { } else if (value == "on"_kj) { return SecureTransportKind::ON; } else { - JSG_FAIL_REQUIRE(TypeError, - kj::str("Unsupported value in secureTransport socket option: ", value)); + JSG_FAIL_REQUIRE( + TypeError, kj::str("Unsupported value in secureTransport socket option: ", value)); } } @@ -72,12 +73,16 @@ kj::Maybe getWritableHighWaterMark(jsg::Optional& opts) return kj::none; } -} // namespace +} // namespace -jsg::Ref setupSocket( - jsg::Lock& js, kj::Own connection, kj::String remoteAddress, - jsg::Optional options, kj::Own tlsStarter, - bool isSecureSocket, kj::String domain, bool isDefaultFetchPort) { +jsg::Ref setupSocket(jsg::Lock& js, + kj::Own connection, + kj::String remoteAddress, + jsg::Optional options, + kj::Own tlsStarter, + bool isSecureSocket, + kj::String domain, + bool isDefaultFetchPort) { auto& ioContext = IoContext::current(); // Disconnection handling is annoyingly complicated: @@ -104,16 +109,16 @@ jsg::Ref setupSocket( // disconnected promise and then resolves some other JS resolver, `closedResolver`. auto disconnectedPaf = kj::newPromiseAndFulfiller(); auto& disconnectedFulfiller = *disconnectedPaf.fulfiller; - auto deferredCancelDisconnected = kj::defer( - [fulfiller=kj::mv(disconnectedPaf.fulfiller)]() mutable { + auto deferredCancelDisconnected = + kj::defer([fulfiller = kj::mv(disconnectedPaf.fulfiller)]() mutable { // In case the `whenWriteDisconected()` listener task is canceled without fulfilling the // fulfiller, we want to silently fulfill it. This will happen when the Socket is GC'd. fulfiller->fulfill(true); }); static auto constexpr handleDisconnected = - [](kj::AsyncIoStream& connection, kj::PromiseFulfiller& fulfiller) - -> kj::Promise { + [](kj::AsyncIoStream& connection, + kj::PromiseFulfiller& fulfiller) -> kj::Promise { try { co_await connection.whenWriteDisconnected(); fulfiller.fulfill(false); @@ -124,13 +129,14 @@ jsg::Ref setupSocket( }; auto watchForDisconnectTask = handleDisconnected(*connection, disconnectedFulfiller) - .attach(kj::mv(deferredCancelDisconnected)); + .attach(kj::mv(deferredCancelDisconnected)); auto closedPrPair = js.newPromiseAndResolver(); closedPrPair.promise.markAsHandled(js); - ioContext.awaitIo(js, kj::mv(disconnectedPaf.promise)).then(js, - [resolver = closedPrPair.resolver.addRef(js)](jsg::Lock& js, bool canceled) mutable { + ioContext.awaitIo(js, kj::mv(disconnectedPaf.promise)) + .then( + js, [resolver = closedPrPair.resolver.addRef(js)](jsg::Lock& js, bool canceled) mutable { // We want to silently ignore the canceled case, without ever resolving anything. Note that // if the application actually fetches the `closed` promise, then the JSG glue will prevent // the socket from being GC'd until that promise resolves, so it won't be canceled. @@ -152,25 +158,13 @@ jsg::Ref setupSocket( } auto openedPrPair = js.newPromiseAndResolver(); openedPrPair.promise.markAsHandled(js); - auto writable = jsg::alloc( - ioContext, kj::mv(sysStreams.writable), - getWritableHighWaterMark(options), - openedPrPair.promise.whenResolved(js)); - - auto result = jsg::alloc( - js, ioContext, - kj::mv(refcountedConnection), - kj::mv(remoteAddress), - kj::mv(readable), - kj::mv(writable), - kj::mv(closedPrPair), - kj::mv(watchForDisconnectTask), - kj::mv(options), - kj::mv(tlsStarter), - isSecureSocket, - kj::mv(domain), - isDefaultFetchPort, - kj::mv(openedPrPair)); + auto writable = jsg::alloc(ioContext, kj::mv(sysStreams.writable), + getWritableHighWaterMark(options), openedPrPair.promise.whenResolved(js)); + + auto result = jsg::alloc(js, ioContext, kj::mv(refcountedConnection), + kj::mv(remoteAddress), kj::mv(readable), kj::mv(writable), kj::mv(closedPrPair), + kj::mv(watchForDisconnectTask), kj::mv(options), kj::mv(tlsStarter), isSecureSocket, + kj::mv(domain), isDefaultFetchPort, kj::mv(openedPrPair)); KJ_IF_SOME(p, eofPromise) { result->handleReadableEof(js, kj::mv(p)); @@ -178,8 +172,9 @@ jsg::Ref setupSocket( return result; } -jsg::Ref connectImplNoOutputLock( - jsg::Lock& js, kj::Maybe> fetcher, AnySocketAddress address, +jsg::Ref connectImplNoOutputLock(jsg::Lock& js, + kj::Maybe> fetcher, + AnySocketAddress address, jsg::Optional options) { auto& ioContext = IoContext::current(); @@ -194,8 +189,8 @@ jsg::Ref connectImplNoOutputLock( // We need just the hostname part of the address, i.e. we want to strip out the port. // We do this using the standard URL parser since it will handle IPv6 for us as well. auto input = kj::str("fake://", str); - auto url = JSG_REQUIRE_NONNULL(jsg::Url::tryParse(input.asPtr()), - TypeError, "Specified address could not be parsed."); + auto url = JSG_REQUIRE_NONNULL( + jsg::Url::tryParse(input.asPtr()), TypeError, "Specified address could not be parsed."); auto host = url.getHostname(); auto port = url.getPort(); JSG_REQUIRE(host != ""_kj, TypeError, "Specified address is missing hostname."); @@ -233,30 +228,28 @@ jsg::Ref connectImplNoOutputLock( KJ_IF_SOME(fn, ioContext.getCurrentLock().getWorker().getConnectOverride(addressStr)) { return fn(js); } - actualFetcher = jsg::alloc( - IoContext::NULL_CLIENT_CHANNEL, Fetcher::RequiresHostAndProtocol::YES); + actualFetcher = + jsg::alloc(IoContext::NULL_CLIENT_CHANNEL, Fetcher::RequiresHostAndProtocol::YES); } CfProperty cf; - kj::Own client = actualFetcher->getClient( - ioContext, cf.serialize(js), "connect"_kjc); + kj::Own client = + actualFetcher->getClient(ioContext, cf.serialize(js), "connect"_kjc); // Set up the connection. auto headers = kj::heap(ioContext.getHeaderTable()); auto httpClient = asHttpClient(kj::mv(client)); - kj::HttpConnectSettings httpConnectSettings = { .useTls = false }; + kj::HttpConnectSettings httpConnectSettings = {.useTls = false}; KJ_IF_SOME(opts, options) { - httpConnectSettings.useTls = - parseSecureTransport(opts) == SecureTransportKind::ON; + httpConnectSettings.useTls = parseSecureTransport(opts) == SecureTransportKind::ON; } kj::Own tlsStarter = kj::heap(); httpConnectSettings.tlsStarter = tlsStarter; auto request = httpClient->connect(addressStr, *headers, httpConnectSettings); request.connection = request.connection.attach(kj::mv(httpClient)); - auto result = setupSocket( - js, kj::mv(request.connection), kj::mv(addressStr), kj::mv(options), kj::mv(tlsStarter), - httpConnectSettings.useTls, kj::mv(domain), isDefaultFetchPort); + auto result = setupSocket(js, kj::mv(request.connection), kj::mv(addressStr), kj::mv(options), + kj::mv(tlsStarter), httpConnectSettings.useTls, kj::mv(domain), isDefaultFetchPort); // `handleProxyStatus` needs an initialised refcount to use `JSG_THIS`, hence it cannot be // called in Socket's constructor. Also it's only necessary when creating a Socket as a result of // a `connect`. @@ -264,8 +257,9 @@ jsg::Ref connectImplNoOutputLock( return result; } -jsg::Ref connectImpl( - jsg::Lock& js, kj::Maybe> fetcher, AnySocketAddress address, +jsg::Ref connectImpl(jsg::Lock& js, + kj::Maybe> fetcher, + AnySocketAddress address, jsg::Optional options) { // TODO(soon): Doesn't this need to check for the presence of an output lock, and if it finds one // then wait on it, before calling into connectImplNoOutputLock? @@ -282,27 +276,29 @@ jsg::Promise Socket::close(jsg::Lock& js) { readable->getController().setPendingClosure(); // Wait until the socket connects (successfully or otherwise) - return openedPromiseCopy.whenResolved(js).then(js, [this](jsg::Lock& js) { + return openedPromiseCopy.whenResolved(js) + .then(js, + [this](jsg::Lock& js) { if (!writable->getController().isClosedOrClosing()) { return writable->getController().flush(js); } else { return js.resolvedPromise(); } - }).then(js, [this](jsg::Lock& js) { + }) + .then(js, + [this](jsg::Lock& js) { // Forcibly abort the readable/writable streams. auto cancelPromise = readable->getController().cancel(js, kj::none); auto abortPromise = writable->getController().abort(js, kj::none); // The below is effectively `Promise.all(cancelPromise, abortPromise)` - return cancelPromise.then(js, - [abortPromise = kj::mv(abortPromise)](jsg::Lock& js) mutable { + return cancelPromise.then(js, [abortPromise = kj::mv(abortPromise)](jsg::Lock& js) mutable { return kj::mv(abortPromise); }); - }).then(js, [this](jsg::Lock& js) { + }) + .then(js, [this](jsg::Lock& js) { resolveFulfiller(js, kj::none); return js.resolvedPromise(); - }).catch_(js, [this](jsg::Lock& js, jsg::Value err) { - errorHandler(js, kj::mv(err)); - }); + }).catch_(js, [this](jsg::Lock& js, jsg::Value err) { errorHandler(js, kj::mv(err)); }); } jsg::Ref Socket::startTls(jsg::Lock& js, jsg::Optional tlsOptions) { @@ -312,8 +308,8 @@ jsg::Ref Socket::startTls(jsg::Lock& js, jsg::Optional tlsOp auto invalidOptKindMsg = "The `secureTransport` socket option must be set to 'starttls' for startTls to be used."; KJ_IF_SOME(opts, options) { - JSG_REQUIRE(parseSecureTransport(opts) == SecureTransportKind::STARTTLS, - TypeError, invalidOptKindMsg); + JSG_REQUIRE( + parseSecureTransport(opts) == SecureTransportKind::STARTTLS, TypeError, invalidOptKindMsg); } else { JSG_FAIL_REQUIRE(TypeError, invalidOptKindMsg); } @@ -325,9 +321,10 @@ jsg::Ref Socket::startTls(jsg::Lock& js, jsg::Optional tlsOp // // Detach the AsyncIoStream from the Writable/Readable streams and make them unusable. auto& context = IoContext::current(); - auto secureStreamPromise = context.awaitJs(js, writable->flush(js).then(js, - [this, domain = kj::heapString(domain), tlsOptions = kj::mv(tlsOptions), - tlsStarter = kj::mv(tlsStarter)](jsg::Lock& js) mutable { + auto secureStreamPromise = context.awaitJs(js, + writable->flush(js).then(js, + [this, domain = kj::heapString(domain), tlsOptions = kj::mv(tlsOptions), + tlsStarter = kj::mv(tlsStarter)](jsg::Lock& js) mutable { writable->detach(js); readable = readable->detach(js, true); closedResolver.resolve(js); @@ -343,32 +340,30 @@ jsg::Ref Socket::startTls(jsg::Lock& js, jsg::Optional tlsOp // the request's IoContext has ended then `tlsStarter` will be null. This can happen if the // flush operation is taking a particularly long time (EW-8538), so we throw a JSG error if // that's the case. - JSG_REQUIRE(*tlsStarter != nullptr, TypeError, - "The request has finished before startTls completed."); - auto secureStream = KJ_ASSERT_NONNULL(*tlsStarter)(acceptedHostname).then( - [stream = connectionStream->addWrappedRef()]() mutable -> kj::Own { - return kj::mv(stream); - }); + JSG_REQUIRE( + *tlsStarter != nullptr, TypeError, "The request has finished before startTls completed."); + auto secureStream = KJ_ASSERT_NONNULL(*tlsStarter)(acceptedHostname) + .then([stream = connectionStream->addWrappedRef()]() mutable + -> kj::Own { return kj::mv(stream); }); return kj::newPromisedStream(kj::mv(secureStream)); })); // The existing tlsStarter gets consumed and we won't need it again. Pass in an empty tlsStarter // to `setupSocket`. auto newTlsStarter = kj::heap(); - return setupSocket(js, kj::newPromisedStream(kj::mv(secureStreamPromise)), - kj::str(remoteAddress), kj::mv(options), kj::mv(newTlsStarter), true, - kj::mv(domain), isDefaultFetchPort); + return setupSocket(js, kj::newPromisedStream(kj::mv(secureStreamPromise)), kj::str(remoteAddress), + kj::mv(options), kj::mv(newTlsStarter), true, kj::mv(domain), isDefaultFetchPort); } void Socket::handleProxyStatus( jsg::Lock& js, kj::Promise status) { auto& context = IoContext::current(); - auto result = context.awaitIo(js, - status.catch_([](kj::Exception&& e) { - LOG_ERROR_PERIODICALLY("Socket proxy disconnected abruptly", e); - return kj::HttpClient::ConnectRequest::Status(500, nullptr, kj::Own()); - }), - [this, self = JSG_THIS](jsg::Lock& js, kj::HttpClient::ConnectRequest::Status&& status) -> void { + auto result = context.awaitIo(js, status.catch_([](kj::Exception&& e) { + LOG_ERROR_PERIODICALLY("Socket proxy disconnected abruptly", e); + return kj::HttpClient::ConnectRequest::Status(500, nullptr, kj::Own()); + }), + [this, self = JSG_THIS]( + jsg::Lock& js, kj::HttpClient::ConnectRequest::Status&& status) -> void { if (status.statusCode < 200 || status.statusCode >= 300) { // If the status indicates an unsucessful connection we need to reject the `closeFulfiller` // with an exception. This will reject the socket's `closed` promise. @@ -381,10 +376,11 @@ void Socket::handleProxyStatus( } else { // In our implementation we do not expose the local address at all simply // because there's no useful value we can provide. - openedResolver.resolve(js, SocketInfo{ - .remoteAddress = kj::str(remoteAddress), - .localAddress = kj::none, - }); + openedResolver.resolve(js, + SocketInfo{ + .remoteAddress = kj::str(remoteAddress), + .localAddress = kj::none, + }); } }); result.markAsHandled(js); @@ -397,21 +393,22 @@ void Socket::handleProxyStatus(jsg::Lock& js, kj::Promise kj::Maybe { - LOG_ERROR_PERIODICALLY("Socket proxy disconnected abruptly", e); - return KJ_EXCEPTION(FAILED, "connectResult raised an error"); - }), - [this, self = JSG_THIS](jsg::Lock& js, kj::Maybe result) -> void { + auto result = + context.awaitIo(js, connectResult.catch_([](kj::Exception&& e) -> kj::Maybe { + LOG_ERROR_PERIODICALLY("Socket proxy disconnected abruptly", e); + return KJ_EXCEPTION(FAILED, "connectResult raised an error"); + }), + [this, self = JSG_THIS](jsg::Lock& js, kj::Maybe result) -> void { if (result != kj::none) { handleProxyError(js, JSG_KJ_EXCEPTION(FAILED, Error, "connection attempt failed")); } else { // In our implementation we do not expose the local address at all simply // because there's no useful value we can provide. - openedResolver.resolve(js, SocketInfo{ - .remoteAddress = kj::str(remoteAddress), - .localAddress = kj::none, - }); + openedResolver.resolve(js, + SocketInfo{ + .remoteAddress = kj::str(remoteAddress), + .localAddress = kj::none, + }); } }); result.markAsHandled(js); @@ -427,10 +424,12 @@ void Socket::handleProxyError(jsg::Lock& js, kj::Exception e) { void Socket::handleReadableEof(jsg::Lock& js, jsg::Promise onEof) { KJ_ASSERT(!getAllowHalfOpen(options)); // Listen for EOF on the ReadableStream. - onEof.then(js, - JSG_VISITABLE_LAMBDA((ref=JSG_THIS), (ref), (jsg::Lock& js) { - return ref->maybeCloseWriteSide(js); - })).markAsHandled(js); + onEof + .then( + js, + JSG_VISITABLE_LAMBDA( + (ref = JSG_THIS), (ref), (jsg::Lock& js) { return ref->maybeCloseWriteSide(js); })) + .markAsHandled(js); } jsg::Promise Socket::maybeCloseWriteSide(jsg::Lock& js) { @@ -449,12 +448,16 @@ jsg::Promise Socket::maybeCloseWriteSide(jsg::Lock& js) { // below by calling `close` on the WritableStream which ensures that any data pending on it // is flushed. Then once the `close` either completes or fails we can be sure that any data has // been flushed. - return writable->getController().close(js).catch_(js, - JSG_VISITABLE_LAMBDA((ref=JSG_THIS), (ref), (jsg::Lock& js, jsg::Value&& exc) { - ref->closedResolver.reject(js, exc.getHandle(js)); - })).then(js, JSG_VISITABLE_LAMBDA((ref=JSG_THIS), (ref), (jsg::Lock& js) { - ref->closedResolver.resolve(js); - })); + return writable->getController() + .close(js) + .catch_(js, + JSG_VISITABLE_LAMBDA((ref = JSG_THIS), (ref), + (jsg::Lock& js, jsg::Value&& exc) { + ref->closedResolver.reject(js, exc.getHandle(js)); + })) + .then(js, JSG_VISITABLE_LAMBDA((ref = JSG_THIS), (ref), (jsg::Lock& js) { + ref->closedResolver.resolve(js); + })); } } // namespace workerd::api diff --git a/src/workerd/api/sockets.h b/src/workerd/api/sockets.h index d7b373150df..94be522cde7 100644 --- a/src/workerd/api/sockets.h +++ b/src/workerd/api/sockets.h @@ -57,16 +57,23 @@ struct TlsOptions { class Socket: public jsg::Object { public: - Socket(jsg::Lock& js, IoContext& context, + Socket(jsg::Lock& js, + IoContext& context, kj::Own>> connectionStream, - kj::String remoteAddress, jsg::Ref readableParam, - jsg::Ref writable, jsg::PromiseResolverPair closedPrPair, - kj::Promise watchForDisconnectTask, jsg::Optional options, - kj::Own tlsStarter, bool isSecureSocket, - kj::String domain, bool isDefaultFetchPort, + kj::String remoteAddress, + jsg::Ref readableParam, + jsg::Ref writable, + jsg::PromiseResolverPair closedPrPair, + kj::Promise watchForDisconnectTask, + jsg::Optional options, + kj::Own tlsStarter, + bool isSecureSocket, + kj::String domain, + bool isDefaultFetchPort, jsg::PromiseResolverPair openedPrPair) : connectionStream(context.addObject(kj::mv(connectionStream))), - readable(kj::mv(readableParam)), writable(kj::mv(writable)), + readable(kj::mv(readableParam)), + writable(kj::mv(writable)), closedResolver(kj::mv(closedPrPair.resolver)), closedPromiseCopy(closedPrPair.promise.whenResolved(js)), closedPromise(kj::mv(closedPrPair.promise)), @@ -80,10 +87,14 @@ class Socket: public jsg::Object { openedResolver(kj::mv(openedPrPair.resolver)), openedPromiseCopy(openedPrPair.promise.whenResolved(js)), openedPromise(kj::mv(openedPrPair.promise)), - isClosing(false) { }; + isClosing(false) {}; - jsg::Ref getReadable() { return readable.addRef(); } - jsg::Ref getWritable() { return writable.addRef(); } + jsg::Ref getReadable() { + return readable.addRef(); + } + jsg::Ref getWritable() { + return writable.addRef(); + } jsg::MemoizedIdentity>& getClosed() { return closedPromise; } @@ -107,8 +118,7 @@ class Socket: public jsg::Object { // The first variant is useful for connections established using HTTP connect. The latter is for // connections established any other way, where the lack of an exception indicates we connected // successfully. - void handleProxyStatus( - jsg::Lock& js, kj::Promise status); + void handleProxyStatus(jsg::Lock& js, kj::Promise status); // Sets up relevant callbacks to handle the case when the proxy rejects our connection. // The first variant is useful for connections established using HTTP connect. The latter is for @@ -129,12 +139,10 @@ class Socket: public jsg::Object { } void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { - tracker.trackFieldWithSize("connectionStream", - sizeof(IoOwn>>)); - tracker.trackFieldWithSize("tlsStarter", - sizeof(IoOwn)); - tracker.trackFieldWithSize("watchForDisconnectTask", - sizeof(IoOwn>)); + tracker.trackFieldWithSize( + "connectionStream", sizeof(IoOwn>>)); + tracker.trackFieldWithSize("tlsStarter", sizeof(IoOwn)); + tracker.trackFieldWithSize("watchForDisconnectTask", sizeof(IoOwn>)); tracker.trackField("readable", readable); tracker.trackField("writable", writable); tracker.trackField("closedResolver", closedResolver); @@ -202,25 +210,28 @@ class Socket: public jsg::Object { }; void visitForGc(jsg::GcVisitor& visitor) { - visitor.visit(readable, writable, closedResolver, - closedPromiseCopy, closedPromise, - openedResolver, openedPromiseCopy, - openedPromise); + visitor.visit(readable, writable, closedResolver, closedPromiseCopy, closedPromise, + openedResolver, openedPromiseCopy, openedPromise); } }; -jsg::Ref setupSocket( - jsg::Lock& js, kj::Own connection, +jsg::Ref setupSocket(jsg::Lock& js, + kj::Own connection, kj::String remoteAddress, - jsg::Optional options, kj::Own tlsStarter, - bool isSecureSocket, kj::String domain, bool isDefaultFetchPort); - -jsg::Ref connectImplNoOutputLock( - jsg::Lock& js, kj::Maybe> fetcher, AnySocketAddress address, + jsg::Optional options, + kj::Own tlsStarter, + bool isSecureSocket, + kj::String domain, + bool isDefaultFetchPort); + +jsg::Ref connectImplNoOutputLock(jsg::Lock& js, + kj::Maybe> fetcher, + AnySocketAddress address, jsg::Optional options); -jsg::Ref connectImpl( - jsg::Lock& js, kj::Maybe> fetcher, AnySocketAddress address, +jsg::Ref connectImpl(jsg::Lock& js, + kj::Maybe> fetcher, + AnySocketAddress address, jsg::Optional options); class SocketsModule final: public jsg::Object { @@ -228,8 +239,8 @@ class SocketsModule final: public jsg::Object { SocketsModule() = default; SocketsModule(jsg::Lock&, const jsg::Url&) {} - jsg::Ref connect(jsg::Lock& js, AnySocketAddress address, - jsg::Optional options) { + jsg::Ref connect( + jsg::Lock& js, AnySocketAddress address, jsg::Optional options) { return connectImpl(js, kj::none, kj::mv(address), kj::mv(options)); } @@ -239,10 +250,9 @@ class SocketsModule final: public jsg::Object { }; template -void registerSocketsModule( - Registry& registry, auto featureFlags) { - registry.template addBuiltinModule("cloudflare-internal:sockets", - workerd::jsg::ModuleRegistry::Type::INTERNAL); +void registerSocketsModule(Registry& registry, auto featureFlags) { + registry.template addBuiltinModule( + "cloudflare-internal:sockets", workerd::jsg::ModuleRegistry::Type::INTERNAL); } template @@ -254,13 +264,9 @@ kj::Own getInternalSocketModuleBundle(auto featureFl return builder.finish(); } -#define EW_SOCKETS_ISOLATE_TYPES \ - api::Socket, \ - api::SocketOptions, \ - api::SocketAddress, \ - api::TlsOptions, \ - api::SocketsModule, \ - api::SocketInfo +#define EW_SOCKETS_ISOLATE_TYPES \ + api::Socket, api::SocketOptions, api::SocketAddress, api::TlsOptions, api::SocketsModule, \ + api::SocketInfo // The list of sockets.h types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE } // namespace workerd::api diff --git a/src/workerd/api/sql.c++ b/src/workerd/api/sql.c++ index e7a51a20d0c..4dea3dd1049 100644 --- a/src/workerd/api/sql.c++ +++ b/src/workerd/api/sql.c++ @@ -9,12 +9,13 @@ namespace workerd::api { SqlStorage::SqlStorage(SqliteDatabase& sqlite, jsg::Ref storage) - : sqlite(IoContext::current().addObject(sqlite)), storage(kj::mv(storage)) {} + : sqlite(IoContext::current().addObject(sqlite)), + storage(kj::mv(storage)) {} SqlStorage::~SqlStorage() {} -jsg::Ref SqlStorage::exec(jsg::Lock& js, kj::String querySql, - jsg::Arguments bindings) { +jsg::Ref SqlStorage::exec( + jsg::Lock& js, kj::String querySql, jsg::Arguments bindings) { SqliteDatabase::Regulator& regulator = *this; return jsg::alloc(*sqlite, regulator, querySql, kj::mv(bindings)); } @@ -22,7 +23,8 @@ jsg::Ref SqlStorage::exec(jsg::Lock& js, kj::String querySql SqlStorage::IngestResult SqlStorage::ingest(jsg::Lock& js, kj::String querySql) { SqliteDatabase::Regulator& regulator = *this; auto result = sqlite->ingestSql(regulator, querySql); - return IngestResult(kj::str(result.remainder), result.rowsRead, result.rowsWritten, result.statementCount); + return IngestResult( + kj::str(result.remainder), result.rowsRead, result.rowsWritten, result.statementCount); } jsg::Ref SqlStorage::prepare(jsg::Lock& js, kj::String query) { @@ -30,10 +32,9 @@ jsg::Ref SqlStorage::prepare(jsg::Lock& js, kj::String qu } double SqlStorage::getDatabaseSize() { - int64_t pages = execMemoized( - pragmaPageCount, - "select (select * from pragma_page_count) - (select * from pragma_freelist_count);" - ).getInt64(0); + int64_t pages = execMemoized(pragmaPageCount, + "select (select * from pragma_page_count) - (select * from pragma_freelist_count);") + .getInt64(0); return pages * getPageSize(); } @@ -60,16 +61,16 @@ bool SqlStorage::allowTransactions() const { return false; } -SqlStorage::Cursor::State::State( - kj::RefcountedWrapper& statement, +SqlStorage::Cursor::State::State(kj::RefcountedWrapper& statement, kj::Array bindingsParam) : dependency(statement.addWrappedRef()), bindings(kj::mv(bindingsParam)), query(statement.getWrapped().run(mapBindings(bindings).asPtr())) {} -SqlStorage::Cursor::State::State( - SqliteDatabase& db, SqliteDatabase::Regulator& regulator, - kj::StringPtr sqlCode, kj::Array bindingsParam) +SqlStorage::Cursor::State::State(SqliteDatabase& db, + SqliteDatabase::Regulator& regulator, + kj::StringPtr sqlCode, + kj::Array bindingsParam) : bindings(kj::mv(bindingsParam)), query(db.run(regulator, sqlCode, mapBindings(bindings).asPtr())) {} @@ -123,18 +124,14 @@ jsg::Ref SqlStorage::Cursor::rows(jsg::Lock& js kj::Maybe SqlStorage::Cursor::rowIteratorNext( jsg::Lock& js, jsg::Ref& obj) { auto names = obj->cachedColumnNames.get(); - return iteratorImpl(js, obj, - [&](State& state, uint i, Value&& value) { + return iteratorImpl(js, obj, [&](State& state, uint i, Value&& value) { return RowDict::Field{ // A little trick here: We know there are no HandleScopes on the stack between JSG and here, // so we can return a dict keyed by local handles, which avoids constructing new V8Refs here // which would be relatively slower. .name = names[i].getHandle(js), - .value = kj::mv(value) - }; - }).map([&](kj::Array&& fields) { - return RowDict { .fields = kj::mv(fields) }; - }); + .value = kj::mv(value)}; + }).map([&](kj::Array&& fields) { return RowDict{.fields = kj::mv(fields)}; }); } jsg::Ref SqlStorage::Cursor::raw(jsg::Lock&) { @@ -147,9 +144,7 @@ jsg::Ref SqlStorage::Cursor::raw(jsg::Lock&) { kj::Array> SqlStorage::Cursor::getColumnNames(jsg::Lock& js) { KJ_IF_SOME(s, state) { cachedColumnNames.ensureInitialized(js, s->query); - return KJ_MAP(name, this->cachedColumnNames.get()) { - return name.addRef(js); - }; + return KJ_MAP(name, this->cachedColumnNames.get()) { return name.addRef(js); }; } else { JSG_FAIL_REQUIRE(Error, "Cannot call .getColumnNames after Cursor iterator has been consumed."); } @@ -157,16 +152,13 @@ kj::Array> SqlStorage::Cursor::getColumnNames(jsg::Loc kj::Maybe> SqlStorage::Cursor::rawIteratorNext( jsg::Lock& js, jsg::Ref& obj) { - return iteratorImpl(js, obj, - [&](State& state, uint i, Value&& value) { - return kj::mv(value); - }); + return iteratorImpl(js, obj, [&](State& state, uint i, Value&& value) { return kj::mv(value); }); } template auto SqlStorage::Cursor::iteratorImpl(jsg::Lock& js, jsg::Ref& obj, Func&& func) - -> kj::Maybe(), uint(), kj::instance()))>> { + -> kj::Maybe< + kj::Array(), uint(), kj::instance()))>> { using Element = decltype(func(kj::instance(), uint(), kj::instance())); auto& state = *KJ_UNWRAP_OR(obj->state, { @@ -230,7 +222,7 @@ auto SqlStorage::Cursor::iteratorImpl(jsg::Lock& js, jsg::Ref& obj, Func SqlStorage::Statement::Statement(SqliteDatabase::Statement&& statement) : statement(IoContext::current().addObject( - kj::refcountedWrapper(kj::mv(statement)))) {} + kj::refcountedWrapper(kj::mv(statement)))) {} kj::Array SqlStorage::Cursor::mapBindings( kj::ArrayPtr values) { @@ -284,15 +276,14 @@ jsg::Ref SqlStorage::Statement::run(jsg::Arguments", - sizeof(IoPtr)); + tracker.trackFieldWithSize("IoPtr", sizeof(IoPtr)); if (pragmaPageCount != kj::none) { - tracker.trackFieldWithSize("IoPtr", - sizeof(IoPtr)); + tracker.trackFieldWithSize( + "IoPtr", sizeof(IoPtr)); } if (pragmaGetMaxPageCount != kj::none) { - tracker.trackFieldWithSize("IoPtr", - sizeof(IoPtr)); + tracker.trackFieldWithSize( + "IoPtr", sizeof(IoPtr)); } } diff --git a/src/workerd/api/sql.h b/src/workerd/api/sql.h index fc19ce2855e..b60f9f2bdef 100644 --- a/src/workerd/api/sql.h +++ b/src/workerd/api/sql.h @@ -67,9 +67,9 @@ class SqlStorage final: public jsg::Object, private SqliteDatabase::Regulator { kj::Maybe> pragmaGetMaxPageCount; template - SqliteDatabase::Query execMemoized( - kj::Maybe>& slot, - const char (&sqlCode)[size], Params&&... params) { + SqliteDatabase::Query execMemoized(kj::Maybe>& slot, + const char (&sqlCode)[size], + Params&&... params) { // Run a (trusted) statement, preparing it on the first call and reusing the prepared version // for future calls. @@ -77,8 +77,7 @@ class SqlStorage final: public jsg::Object, private SqliteDatabase::Regulator { KJ_IF_SOME(s, slot) { stmt = &*s; } else { - stmt = &*slot.emplace(IoContext::current().addObject( - kj::heap(sqlite->prepare(sqlCode)))); + stmt = &*slot.emplace(IoContext::current().addObject(kj::heap(sqlite->prepare(sqlCode)))); } return stmt->run(kj::fwd(params)...); } @@ -94,6 +93,7 @@ class SqlStorage final: public jsg::Object, private SqliteDatabase::Regulator { class SqlStorage::Cursor final: public jsg::Object { class CachedColumnNames; + public: template Cursor(Params&&... params) @@ -144,13 +144,15 @@ class SqlStorage::Cursor final: public jsg::Object { // TODO(perf): Can we further cache the V8 object layout information for a row? public: // Get the cached names. ensureInitialized() must have been called previously. - kj::ArrayPtr> get() { return KJ_REQUIRE_NONNULL(names); } + kj::ArrayPtr> get() { + return KJ_REQUIRE_NONNULL(names); + } void ensureInitialized(jsg::Lock& js, SqliteDatabase::Query& source); JSG_MEMORY_INFO(cachedColumnNames) { KJ_IF_SOME(list, names) { - for (const auto& name : list) { + for (const auto& name: list) { tracker.trackField(nullptr, name); } } @@ -161,7 +163,7 @@ class SqlStorage::Cursor final: public jsg::Object { }; struct State { - // Refcount on the SqliteDatabase::Statement underlying the query, if any. + // Refcount on the SqliteDatabase::Statement underlying the query, if any. kj::Own dependency; // The bindings that were used to construct `query`. We have to keep these alive until the query @@ -173,9 +175,11 @@ class SqlStorage::Cursor final: public jsg::Object { bool isFirst = true; State(kj::RefcountedWrapper& statement, - kj::Array bindings); - State(SqliteDatabase& db, SqliteDatabase::Regulator& regulator, - kj::StringPtr sqlCode, kj::Array bindings); + kj::Array bindings); + State(SqliteDatabase& db, + SqliteDatabase::Regulator& regulator, + kj::StringPtr sqlCode, + kj::Array bindings); }; // Nulled out when query is done or canceled. @@ -214,8 +218,8 @@ class SqlStorage::Cursor final: public jsg::Object { static kj::Maybe> rawIteratorNext(jsg::Lock& js, jsg::Ref& obj); template static auto iteratorImpl(jsg::Lock& js, jsg::Ref& obj, Func&& func) - -> kj::Maybe(), uint(), kj::instance()))>>; + -> kj::Maybe< + kj::Array(), uint(), kj::instance()))>>; friend class Statement; }; @@ -231,8 +235,7 @@ class SqlStorage::Statement final: public jsg::Object { } void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { - tracker.trackFieldWithSize( - "IoOwn>", + tracker.trackFieldWithSize("IoOwn>", sizeof(IoOwn>)); tracker.trackField("cachedColumnNames", cachedColumnNames); } @@ -252,8 +255,10 @@ class SqlStorage::Statement final: public jsg::Object { struct SqlStorage::IngestResult { IngestResult(kj::String remainder, double rowsRead, double rowsWritten, double statementCount) - : remainder(kj::mv(remainder)), rowsRead(rowsRead), rowsWritten(rowsWritten), - statementCount(statementCount) {} + : remainder(kj::mv(remainder)), + rowsRead(rowsRead), + rowsWritten(rowsWritten), + statementCount(statementCount) {} kj::String remainder; double rowsRead; @@ -263,16 +268,11 @@ struct SqlStorage::IngestResult { JSG_STRUCT(remainder, rowsRead, rowsWritten, statementCount); }; - -#define EW_SQL_ISOLATE_TYPES \ - api::SqlStorage, \ - api::SqlStorage::Statement, \ - api::SqlStorage::Cursor, \ - api::SqlStorage::IngestResult, \ - api::SqlStorage::Cursor::RowIterator, \ - api::SqlStorage::Cursor::RowIterator::Next, \ - api::SqlStorage::Cursor::RawIterator, \ - api::SqlStorage::Cursor::RawIterator::Next +#define EW_SQL_ISOLATE_TYPES \ + api::SqlStorage, api::SqlStorage::Statement, api::SqlStorage::Cursor, \ + api::SqlStorage::IngestResult, api::SqlStorage::Cursor::RowIterator, \ + api::SqlStorage::Cursor::RowIterator::Next, api::SqlStorage::Cursor::RawIterator, \ + api::SqlStorage::Cursor::RawIterator::Next // The list of sql.h types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE } // namespace workerd::api diff --git a/src/workerd/api/streams.h b/src/workerd/api/streams.h index fadb72acaa1..4ed082f041d 100644 --- a/src/workerd/api/streams.h +++ b/src/workerd/api/streams.h @@ -15,41 +15,22 @@ namespace workerd::api { -#define EW_STREAMS_ISOLATE_TYPES \ - api::StreamQueuingStrategy, \ - api::UnderlyingSink, \ - api::UnderlyingSource, \ - api::Transformer, \ - api::PipeToOptions, \ - api::ReadResult, \ - api::ReadableStream, \ - api::ReadableStreamDefaultReader, \ - api::ReadableStreamBYOBReader, \ - api::ReadableStreamBYOBReader::ReadableStreamBYOBReaderReadOptions, \ - api::ReadableStream::GetReaderOptions, \ - api::ReadableStreamBYOBRequest, \ - api::ReadableStreamDefaultController, \ - api::ReadableByteStreamController, \ - api::WritableStreamDefaultController, \ - api::TransformStreamDefaultController, \ - api::ReadableStream::Transform, \ - api::WritableStream, \ - api::WritableStreamDefaultWriter, \ - api::TransformStream, \ - api::FixedLengthStream, \ - api::IdentityTransformStream, \ - api::IdentityTransformStream::QueuingStrategy, \ - api::ReadableStream::ValuesOptions, \ - api::ReadableStream::ReadableStreamAsyncIterator, \ - api::ReadableStream::ReadableStreamAsyncIterator::Next, \ - api::CompressionStream, \ - api::DecompressionStream, \ - api::TextEncoderStream, \ - api::TextDecoderStream, \ - api::TextDecoderStream::TextDecoderStreamInit, \ - api::ByteLengthQueuingStrategy, \ - api::CountQueuingStrategy, \ - api::QueuingStrategyInit +#define EW_STREAMS_ISOLATE_TYPES \ + api::StreamQueuingStrategy, api::UnderlyingSink, api::UnderlyingSource, api::Transformer, \ + api::PipeToOptions, api::ReadResult, api::ReadableStream, api::ReadableStreamDefaultReader, \ + api::ReadableStreamBYOBReader, \ + api::ReadableStreamBYOBReader::ReadableStreamBYOBReaderReadOptions, \ + api::ReadableStream::GetReaderOptions, api::ReadableStreamBYOBRequest, \ + api::ReadableStreamDefaultController, api::ReadableByteStreamController, \ + api::WritableStreamDefaultController, api::TransformStreamDefaultController, \ + api::ReadableStream::Transform, api::WritableStream, api::WritableStreamDefaultWriter, \ + api::TransformStream, api::FixedLengthStream, api::IdentityTransformStream, \ + api::IdentityTransformStream::QueuingStrategy, api::ReadableStream::ValuesOptions, \ + api::ReadableStream::ReadableStreamAsyncIterator, \ + api::ReadableStream::ReadableStreamAsyncIterator::Next, api::CompressionStream, \ + api::DecompressionStream, api::TextEncoderStream, api::TextDecoderStream, \ + api::TextDecoderStream::TextDecoderStreamInit, api::ByteLengthQueuingStrategy, \ + api::CountQueuingStrategy, api::QueuingStrategyInit // The list of streams.h types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE } // namespace workerd::api diff --git a/src/workerd/api/streams/common.c++ b/src/workerd/api/streams/common.c++ index 31538adff84..15bc15706cf 100644 --- a/src/workerd/api/streams/common.c++ +++ b/src/workerd/api/streams/common.c++ @@ -7,23 +7,16 @@ namespace workerd::api { WritableStreamController::PendingAbort::PendingAbort( - jsg::Lock& js, - jsg::PromiseResolverPair prp, - v8::Local reason, - bool reject) + jsg::Lock& js, jsg::PromiseResolverPair prp, v8::Local reason, bool reject) : resolver(kj::mv(prp.resolver)), promise(kj::mv(prp.promise)), reason(js.v8Ref(reason)), reject(reject) {} WritableStreamController::PendingAbort::PendingAbort( - jsg::Lock& js, - v8::Local reason, bool reject) - : WritableStreamController::PendingAbort( - js, - js.newPromiseAndResolver(), - reason, - reject) {} + jsg::Lock& js, v8::Local reason, bool reject) + : WritableStreamController::PendingAbort(js, js.newPromiseAndResolver(), reason, reject) { +} void WritableStreamController::PendingAbort::complete(jsg::Lock& js) { if (reject) { @@ -37,8 +30,7 @@ void WritableStreamController::PendingAbort::fail(jsg::Lock& js, v8::Local(js, resolver, reason); } -kj::Maybe -WritableStreamController::PendingAbort::dequeue( +kj::Maybe WritableStreamController::PendingAbort::dequeue( kj::Maybe& maybePendingAbort) { return kj::mv(maybePendingAbort); } diff --git a/src/workerd/api/streams/common.h b/src/workerd/api/streams/common.h index 70f31bc90a7..d070acc63cf 100644 --- a/src/workerd/api/streams/common.h +++ b/src/workerd/api/streams/common.h @@ -58,8 +58,8 @@ struct StreamQueuingStrategy { }; struct UnderlyingSource { - using Controller = kj::OneOf, - jsg::Ref>; + using Controller = + kj::OneOf, jsg::Ref>; using StartAlgorithm = jsg::Promise(Controller); using PullAlgorithm = jsg::Promise(Controller); using CancelAlgorithm = jsg::Promise(v8::Local reason); @@ -189,10 +189,9 @@ struct Transformer { class WritableStreamSink { public: - virtual kj::Promise write(kj::ArrayPtr buffer) - KJ_WARN_UNUSED_RESULT = 0; - virtual kj::Promise write(kj::ArrayPtr> pieces) - KJ_WARN_UNUSED_RESULT = 0; + virtual kj::Promise write(kj::ArrayPtr buffer) KJ_WARN_UNUSED_RESULT = 0; + virtual kj::Promise write( + kj::ArrayPtr> pieces) KJ_WARN_UNUSED_RESULT = 0; virtual kj::Promise end() KJ_WARN_UNUSED_RESULT = 0; // Must call to flush and finish the stream. @@ -209,7 +208,9 @@ class WritableStreamSink { // promises that all future writes will use this encoding. The default implementation returns // IDENTITY, which is always correct since that's the encoding write()s should have used if // this weren't called at all. - virtual StreamEncoding disownEncodingResponsibility() { return StreamEncoding::IDENTITY; } + virtual StreamEncoding disownEncodingResponsibility() { + return StreamEncoding::IDENTITY; + } }; class ReadableStreamSource { @@ -226,7 +227,9 @@ class ReadableStreamSource { // If pumpTo() pumps to a system stream, what is the best encoding for that system steram to // use? This is just a hint. - virtual StreamEncoding getPreferredEncoding() { return StreamEncoding::IDENTITY; }; + virtual StreamEncoding getPreferredEncoding() { + return StreamEncoding::IDENTITY; + }; virtual kj::Maybe tryGetLength(StreamEncoding encoding); @@ -273,13 +276,13 @@ struct PipeToOptions { }; namespace StreamStates { - struct Closed {}; - using Errored = jsg::Value; - struct Erroring { - jsg::Value reason; +struct Closed {}; +using Errored = jsg::Value; +struct Erroring { + jsg::Value reason; - Erroring(jsg::Value reason) : reason(kj::mv(reason)) {} - }; + Erroring(jsg::Value reason): reason(kj::mv(reason)) {} +}; } // namespace StreamStates // A ReadableStreamController provides the underlying implementation for a ReadableStream. @@ -333,9 +336,7 @@ class ReadableStreamController { // The Reader will hold a reference to the controller that will be cleared when the reader // is released or destroyed. The controller is guaranteed to either outlive or detach the // reader so the ReadableStreamController& reference should remain valid. - virtual void attach( - ReadableStreamController& controller, - jsg::Promise closedPromise) = 0; + virtual void attach(ReadableStreamController& controller, jsg::Promise closedPromise) = 0; // When a Reader lock is released, the controller will signal to the reader that it has been // detached. @@ -385,7 +386,7 @@ class ReadableStreamController { class BranchPtr { public: - inline BranchPtr(Branch* branch) : inner(branch) { + inline BranchPtr(Branch* branch): inner(branch) { KJ_ASSERT(inner != nullptr); } BranchPtr(BranchPtr&& other) = default; @@ -393,7 +394,9 @@ class ReadableStreamController { BranchPtr(BranchPtr& other) = default; BranchPtr& operator=(BranchPtr&) = default; - inline void doClose(jsg::Lock& js) { inner->doClose(js); } + inline void doClose(jsg::Lock& js) { + inner->doClose(js); + } inline void doError(jsg::Lock& js, v8::Local reason) { inner->doError(js, reason); @@ -403,10 +406,13 @@ class ReadableStreamController { inner->handleData(js, kj::mv(result)); } - inline uint hashCode() { return kj::hashCode(inner); } + inline uint hashCode() { + return kj::hashCode(inner); + } inline bool operator==(BranchPtr& other) const { return inner == other.inner; } + private: Branch* inner; }; @@ -437,8 +443,7 @@ class ReadableStreamController { virtual void cancel(jsg::Lock& js, v8::Local reason) = 0; virtual void close(jsg::Lock& js) = 0; virtual void error(jsg::Lock& js, v8::Local reason) = 0; - virtual void release(jsg::Lock& js, - kj::Maybe> maybeError = kj::none) = 0; + virtual void release(jsg::Lock& js, kj::Maybe> maybeError = kj::none) = 0; virtual kj::Maybe> tryPumpTo(WritableStreamSink& sink, bool end) = 0; virtual jsg::Promise read(jsg::Lock& js) = 0; }; @@ -458,22 +463,17 @@ class ReadableStreamController { // specified to provide a v8::ArrayBuffer to be filled by the read operation. If the ByobOptions // are provided and the stream is not byte-oriented, the operation will return a rejected promise. virtual kj::Maybe> read( - jsg::Lock& js, - kj::Maybe byobOptions) = 0; + jsg::Lock& js, kj::Maybe byobOptions) = 0; // The pipeTo implementation fully consumes the stream by directing all of its data at the // destination. Controllers should try to be as efficient as possible here. For instance, if // a ReadableStreamInternalController is piping to a WritableStreamInternalController, then // a more efficient kj pipe should be possible. virtual jsg::Promise pipeTo( - jsg::Lock& js, - WritableStreamController& destination, - PipeToOptions options) = 0; + jsg::Lock& js, WritableStreamController& destination, PipeToOptions options) = 0; // Indicates that the consumer no longer has any interest in the streams data. - virtual jsg::Promise cancel( - jsg::Lock& js, - jsg::Optional> reason) = 0; + virtual jsg::Promise cancel(jsg::Lock& js, jsg::Optional> reason) = 0; // Branches the ReadableStreamController into two ReadableStream instances that will receive // this streams data. The specific details of how the branching occurs is entirely up to the @@ -522,17 +522,18 @@ class ReadableStreamController { virtual kj::Maybe tryGetLength(StreamEncoding encoding) = 0; - virtual void setup( - jsg::Lock& js, + virtual void setup(jsg::Lock& js, jsg::Optional maybeUnderlyingSource, jsg::Optional maybeQueuingStrategy) {} virtual kj::Promise> pumpTo( - jsg::Lock& js, kj::Own sink, bool end) = 0; + jsg::Lock& js, kj::Own sink, bool end) = 0; // If pumpTo() pumps to a system stream, what is the best encoding for that system steram to // use? This is just a hint. - virtual StreamEncoding getPreferredEncoding() { return StreamEncoding::IDENTITY; } + virtual StreamEncoding getPreferredEncoding() { + return StreamEncoding::IDENTITY; + } virtual kj::Own detach(jsg::Lock& js, bool ignoreDisturbed) = 0; @@ -547,8 +548,7 @@ class ReadableStreamController { kj::Own newReadableStreamJsController(); kj::Own newReadableStreamInternalController( - IoContext& ioContext, - kj::Own source); + IoContext& ioContext, kj::Own source); // A WritableStreamController provides the underlying implementation for a WritableStream. // We will generally have two implementations: @@ -592,8 +592,7 @@ class WritableStreamController { // // The controller is guaranteed to either outlive the Writer or will detach the Writer so the // WritableStreamController& reference should always remain valid. - virtual void attach( - WritableStreamController& controller, + virtual void attach(WritableStreamController& controller, jsg::Promise closedPromise, jsg::Promise readyPromise) = 0; @@ -613,9 +612,9 @@ class WritableStreamController { bool reject = false; PendingAbort(jsg::Lock& js, - jsg::PromiseResolverPair prp, - v8::Local reason, - bool reject); + jsg::PromiseResolverPair prp, + v8::Local reason, + bool reject); PendingAbort(jsg::Lock& js, v8::Local reason, bool reject); @@ -657,8 +656,7 @@ class WritableStreamController { // The controller implementation will determine what kind of JavaScript data // it is capable of writing, returning a rejected promise if the written // data type is not supported. - virtual jsg::Promise write(jsg::Lock& js, - jsg::Optional> value) = 0; + virtual jsg::Promise write(jsg::Lock& js, jsg::Optional> value) = 0; // Indicates that no additional data will be written to the controller. All // existing pending writes should be allowed to complete. @@ -669,24 +667,19 @@ class WritableStreamController { virtual jsg::Promise flush(jsg::Lock& js, bool markAsHandled = false) = 0; // Immediately interrupts existing pending writes and errors the stream. - virtual jsg::Promise abort( - jsg::Lock& js, - jsg::Optional> reason) = 0; + virtual jsg::Promise abort(jsg::Lock& js, jsg::Optional> reason) = 0; // The tryPipeFrom attempts to establish a data pipe where source's data // is delivered to this WritableStreamController as efficiently as possible. virtual kj::Maybe> tryPipeFrom( - jsg::Lock& js, - jsg::Ref source, - PipeToOptions options) = 0; + jsg::Lock& js, jsg::Ref source, PipeToOptions options) = 0; // Only byte-oriented WritableStreamController implementations will have a WritableStreamSink // that can be detached using removeSink. A nullptr should be returned by any controller that // does not support removing the sink. After the WritableStreamSink has been released, all other // methods on the controller should fail with an exception as the WritableStreamSink should be // the only way to interact with the underlying sink. - virtual kj::Maybe> removeSink( - jsg::Lock& js) = 0 ; + virtual kj::Maybe> removeSink(jsg::Lock& js) = 0; // Detaches the WritableStreamController from it's underlying implementation, leaving the // writable stream locked and in a state where no further writes can be made. @@ -711,8 +704,8 @@ class WritableStreamController { virtual void visitForGc(jsg::GcVisitor& visitor) {}; virtual void setup(jsg::Lock& js, - jsg::Optional underlyingSink, - jsg::Optional queuingStrategy) {} + jsg::Optional underlyingSink, + jsg::Optional queuingStrategy) {} virtual bool isClosedOrClosing() = 0; virtual bool isErrored() = 0; @@ -731,8 +724,7 @@ class WritableStreamController { }; kj::Own newWritableStreamJsController(); -kj::Own newWritableStreamInternalController( - IoContext& ioContext, +kj::Own newWritableStreamInternalController(IoContext& ioContext, kj::Own source, kj::Maybe maybeHighWaterMark = kj::none, kj::Maybe> maybeClosureWaitable = kj::none); @@ -744,8 +736,7 @@ struct Locked {}; // is used internally to represent the locked state in the ReadableStreamController. class ReaderLocked { public: - ReaderLocked( - ReadableStreamController::Reader& reader, + ReaderLocked(ReadableStreamController::Reader& reader, jsg::Promise::Resolver closedFulfiller, kj::Maybe> canceler = kj::none) : reader(reader), @@ -754,7 +745,9 @@ class ReaderLocked { ReaderLocked(ReaderLocked&&) = default; ~ReaderLocked() noexcept(false) { - KJ_IF_SOME(r, reader) { r.detach(); } + KJ_IF_SOME(r, reader) { + r.detach(); + } } KJ_DISALLOW_COPY(ReaderLocked); @@ -782,8 +775,7 @@ class ReaderLocked { JSG_MEMORY_INFO(ReaderLocked) { tracker.trackField("closedFulfiller", closedFulfiller); - tracker.trackFieldWithSize("IoOwn", - sizeof(IoOwn)); + tracker.trackFieldWithSize("IoOwn", sizeof(IoOwn)); } private: @@ -796,8 +788,7 @@ class ReaderLocked { // is used internally to represent the locked state in the WritableStreamController. class WriterLocked { public: - WriterLocked( - WritableStreamController::Writer& writer, + WriterLocked(WritableStreamController::Writer& writer, jsg::Promise::Resolver closedFulfiller, kj::Maybe::Resolver> readyFulfiller = kj::none) : writer(writer), @@ -806,7 +797,9 @@ class WriterLocked { WriterLocked(WriterLocked&&) = default; ~WriterLocked() noexcept(false) { - KJ_IF_SOME(w, writer) { w.detach(); } + KJ_IF_SOME(w, writer) { + w.detach(); + } } void visitForGc(jsg::GcVisitor& visitor) { @@ -851,9 +844,7 @@ class WriterLocked { template void maybeResolvePromise( - jsg::Lock& js, - kj::Maybe::Resolver>& maybeResolver, - T&& t) { + jsg::Lock& js, kj::Maybe::Resolver>& maybeResolver, T&& t) { KJ_IF_SOME(resolver, maybeResolver) { resolver.resolve(js, kj::fwd(t)); maybeResolver = nullptr; @@ -861,8 +852,7 @@ void maybeResolvePromise( } inline void maybeResolvePromise( - jsg::Lock& js, - kj::Maybe::Resolver>& maybeResolver) { + jsg::Lock& js, kj::Maybe::Resolver>& maybeResolver) { KJ_IF_SOME(resolver, maybeResolver) { resolver.resolve(js); maybeResolver = kj::none; @@ -870,8 +860,7 @@ inline void maybeResolvePromise( } template -void maybeRejectPromise( - jsg::Lock& js, +void maybeRejectPromise(jsg::Lock& js, kj::Maybe::Resolver>& maybeResolver, v8::Local reason) { KJ_IF_SOME(resolver, maybeResolver) { @@ -882,9 +871,7 @@ void maybeRejectPromise( template jsg::Promise rejectedMaybeHandledPromise( - jsg::Lock& js, - v8::Local reason, - bool handled) { + jsg::Lock& js, v8::Local reason, bool handled) { auto prp = js.newPromiseAndResolver(); if (handled) { prp.promise.markAsHandled(js); diff --git a/src/workerd/api/streams/compression.c++ b/src/workerd/api/streams/compression.c++ index 78c9ff45788..6c3cb189301 100644 --- a/src/workerd/api/streams/compression.c++ +++ b/src/workerd/api/streams/compression.c++ @@ -30,16 +30,13 @@ public: kj::ArrayPtr buffer; }; - explicit Context(Mode mode, kj::StringPtr format, ContextFlags flags) : - mode(mode), strictCompression(flags) { + explicit Context(Mode mode, kj::StringPtr format, ContextFlags flags) + : mode(mode), + strictCompression(flags) { int result = Z_OK; switch (mode) { case Mode::COMPRESS: - result = deflateInit2( - &ctx, - Z_DEFAULT_COMPRESSION, - Z_DEFLATED, - getWindowBits(format), + result = deflateInit2(&ctx, Z_DEFAULT_COMPRESSION, Z_DEFLATED, getWindowBits(format), 8, // memLevel = 8 is the default Z_DEFAULT_STRATEGY); break; @@ -79,15 +76,13 @@ public: switch (mode) { case Mode::COMPRESS: result = deflate(&ctx, flush); - JSG_REQUIRE(result == Z_OK || result == Z_BUF_ERROR || result == Z_STREAM_END, - Error, - "Compression failed."); + JSG_REQUIRE(result == Z_OK || result == Z_BUF_ERROR || result == Z_STREAM_END, Error, + "Compression failed."); break; case Mode::DECOMPRESS: result = inflate(&ctx, flush); - JSG_REQUIRE(result == Z_OK || result == Z_BUF_ERROR || result == Z_STREAM_END, - Error, - "Decompression failed."); + JSG_REQUIRE(result == Z_OK || result == Z_BUF_ERROR || result == Z_STREAM_END, Error, + "Decompression failed."); if (strictCompression == ContextFlags::STRICT) { // The spec requires that a TypeError is produced if there is trailing data after the end @@ -95,16 +90,16 @@ public: JSG_REQUIRE(!(result == Z_STREAM_END && ctx.avail_in > 0), TypeError, "Trailing bytes after end of compressed data"); // Same applies to closing a stream before the complete decompressed data is available. - JSG_REQUIRE(!(flush == Z_FINISH && result == Z_BUF_ERROR && - ctx.avail_out == sizeof(buffer)), TypeError, - "Called close() on a decompression stream with incomplete data"); + JSG_REQUIRE( + !(flush == Z_FINISH && result == Z_BUF_ERROR && ctx.avail_out == sizeof(buffer)), + TypeError, "Called close() on a decompression stream with incomplete data"); } break; default: KJ_UNREACHABLE; } - return Result { + return Result{ .success = result == Z_OK, .buffer = kj::arrayPtr(buffer, sizeof(buffer) - ctx.avail_out), }; @@ -121,9 +116,12 @@ private: static constexpr auto GZIP = 16; static constexpr auto DEFLATE = 15; static constexpr auto DEFLATE_RAW = -15; - if (format == "gzip") return DEFLATE + GZIP; - else if (format == "deflate") return DEFLATE; - else if (format == "deflate-raw") return DEFLATE_RAW; + if (format == "gzip") + return DEFLATE + GZIP; + else if (format == "deflate") + return DEFLATE; + else if (format == "deflate-raw") + return DEFLATE_RAW; KJ_UNREACHABLE; } @@ -140,7 +138,7 @@ private: // used to track the amount of data that has not been read back yet. class LazyBuffer { public: - LazyBuffer() : valid_size_(0) {} + LazyBuffer(): valid_size_(0) {} // Return a chunk of data and mark it as invalid. The returned chunk remains valid until data is // shifted, cleared or destructor is called. maybeShift() should be called after the returned data @@ -228,10 +226,8 @@ public: } KJ_CASE_ONEOF(open, Open) { if (pieces.size() == 0) return kj::READY_NOW; - return write(pieces[0]) - .then([this, pieces = pieces.slice(1)]() mutable { - return write(pieces); - }); + return write(pieces[0]).then( + [this, pieces = pieces.slice(1)]() mutable { return write(pieces); }); } } KJ_UNREACHABLE; @@ -255,16 +251,14 @@ public: // There might still be data in the output buffer remaining to read. if (output.empty()) return size_t(0); return tryReadInternal( - kj::arrayPtr(reinterpret_cast(buffer), maxBytes), - minBytes); + kj::arrayPtr(reinterpret_cast(buffer), maxBytes), minBytes); } KJ_CASE_ONEOF(exception, kj::Exception) { return kj::cp(exception); } KJ_CASE_ONEOF(open, Open) { return tryReadInternal( - kj::arrayPtr(reinterpret_cast(buffer), maxBytes), - minBytes); + kj::arrayPtr(reinterpret_cast(buffer), maxBytes), minBytes); } } KJ_UNREACHABLE; @@ -316,7 +310,7 @@ private: // Otherwise, create a pending read. auto promise = kj::newPromiseAndFulfiller(); - auto pendingRead = PendingRead { + auto pendingRead = PendingRead{ .buffer = dest, .minBytes = minBytes, .filled = 0, @@ -443,37 +437,33 @@ private: jsg::Ref CompressionStream::constructor(jsg::Lock& js, kj::String format) { JSG_REQUIRE(format == "deflate" || format == "gzip" || format == "deflate-raw", TypeError, - "The compression format must be either 'deflate', 'deflate-raw' or 'gzip'."); + "The compression format must be either 'deflate', 'deflate-raw' or 'gzip'."); - auto readableSide = - kj::refcounted>(kj::mv(format), - Context::ContextFlags::NONE); + auto readableSide = kj::refcounted>( + kj::mv(format), Context::ContextFlags::NONE); auto writableSide = kj::addRef(*readableSide); auto& ioContext = IoContext::current(); - return jsg::alloc( - jsg::alloc(ioContext, kj::mv(readableSide)), - jsg::alloc(ioContext, kj::mv(writableSide))); + return jsg::alloc(jsg::alloc(ioContext, kj::mv(readableSide)), + jsg::alloc(ioContext, kj::mv(writableSide))); } jsg::Ref DecompressionStream::constructor(jsg::Lock& js, kj::String format) { JSG_REQUIRE(format == "deflate" || format == "gzip" || format == "deflate-raw", TypeError, - "The compression format must be either 'deflate', 'deflate-raw' or 'gzip'."); + "The compression format must be either 'deflate', 'deflate-raw' or 'gzip'."); auto readableSide = - kj::refcounted>( - kj::mv(format), - FeatureFlags::get(js).getStrictCompression() ? - Context::ContextFlags::STRICT : - Context::ContextFlags::NONE); + kj::refcounted>(kj::mv(format), + FeatureFlags::get(js).getStrictCompression() ? Context::ContextFlags::STRICT + : Context::ContextFlags::NONE); auto writableSide = kj::addRef(*readableSide); auto& ioContext = IoContext::current(); return jsg::alloc( - jsg::alloc(ioContext, kj::mv(readableSide)), - jsg::alloc(ioContext, kj::mv(writableSide))); + jsg::alloc(ioContext, kj::mv(readableSide)), + jsg::alloc(ioContext, kj::mv(writableSide))); } } // namespace workerd::api diff --git a/src/workerd/api/streams/compression.h b/src/workerd/api/streams/compression.h index 5b254935426..ed5332a94c4 100644 --- a/src/workerd/api/streams/compression.h +++ b/src/workerd/api/streams/compression.h @@ -18,8 +18,8 @@ class CompressionStream: public TransformStream { JSG_RESOURCE_TYPE(CompressionStream) { JSG_INHERIT(TransformStream); - JSG_TS_OVERRIDE(extends TransformStream { - constructor(format: "gzip" | "deflate" | "deflate-raw"); + JSG_TS_OVERRIDE(extends TransformStream { constructor(format + : "gzip" | "deflate" | "deflate-raw"); }); } }; @@ -33,8 +33,8 @@ class DecompressionStream: public TransformStream { JSG_RESOURCE_TYPE(DecompressionStream) { JSG_INHERIT(TransformStream); - JSG_TS_OVERRIDE(extends TransformStream { - constructor(format: "gzip" | "deflate" | "deflate-raw"); + JSG_TS_OVERRIDE(extends TransformStream { constructor(format + : "gzip" | "deflate" | "deflate-raw"); }); } }; diff --git a/src/workerd/api/streams/encoding.c++ b/src/workerd/api/streams/encoding.c++ index def60fed5d3..c038e76bb6c 100644 --- a/src/workerd/api/streams/encoding.c++ +++ b/src/workerd/api/streams/encoding.c++ @@ -18,51 +18,40 @@ private: } // namespace jsg::Ref TextEncoderStream::constructor(jsg::Lock& js) { - auto transformer = TransformStream::constructor( - js, - Transformer { - .transform = jsg::Function( - [](jsg::Lock& js, auto chunk, auto controller) { - auto str = jsg::check(chunk->ToString(js.v8Context())); - auto maybeBuffer = v8::ArrayBuffer::MaybeNew(js.v8Isolate, str->Utf8Length(js.v8Isolate)); - JSG_ASSERT(!maybeBuffer.IsEmpty(), RangeError, - "Cannot allocate space for TextEncoder.encode"); - auto buffer = maybeBuffer.ToLocalChecked(); - - auto bytes = jsg::asBytes(buffer).releaseAsChars(); - [[maybe_unused]] int read = 0; - [[maybe_unused]] auto written = str->WriteUtf8( - js.v8Isolate, - bytes.begin(), - bytes.size(), - &read, - v8::String::NO_NULL_TERMINATION | v8::String::REPLACE_INVALID_UTF8); - - KJ_DASSERT(written == buffer->ByteLength()); - KJ_DASSERT(read == str->Length()); - controller->enqueue(js, v8::Uint8Array::New(buffer, 0, buffer->ByteLength())); - return js.resolvedPromise(); - })}, - StreamQueuingStrategy {}, - StreamQueuingStrategy {}); + auto transformer = TransformStream::constructor(js, + Transformer{.transform = jsg::Function( + [](jsg::Lock& js, auto chunk, auto controller) { + auto str = jsg::check(chunk->ToString(js.v8Context())); + auto maybeBuffer = v8::ArrayBuffer::MaybeNew(js.v8Isolate, str->Utf8Length(js.v8Isolate)); + JSG_ASSERT(!maybeBuffer.IsEmpty(), RangeError, "Cannot allocate space for TextEncoder.encode"); + auto buffer = maybeBuffer.ToLocalChecked(); + + auto bytes = jsg::asBytes(buffer).releaseAsChars(); + [[maybe_unused]] int read = 0; + [[maybe_unused]] auto written = str->WriteUtf8(js.v8Isolate, bytes.begin(), bytes.size(), &read, + v8::String::NO_NULL_TERMINATION | v8::String::REPLACE_INVALID_UTF8); + + KJ_DASSERT(written == buffer->ByteLength()); + KJ_DASSERT(read == str->Length()); + controller->enqueue(js, v8::Uint8Array::New(buffer, 0, buffer->ByteLength())); + return js.resolvedPromise(); + })}, + StreamQueuingStrategy{}, StreamQueuingStrategy{}); return jsg::alloc(transformer->getReadable(), transformer->getWritable()); } -TextDecoderStream::TextDecoderStream( - jsg::Ref decoder, +TextDecoderStream::TextDecoderStream(jsg::Ref decoder, jsg::Ref readable, jsg::Ref writable) : TransformStream(kj::mv(readable), kj::mv(writable)), decoder(kj::mv(decoder)) {} jsg::Ref TextDecoderStream::constructor( - jsg::Lock& js, - jsg::Optional label, - jsg::Optional options) { + jsg::Lock& js, jsg::Optional label, jsg::Optional options) { auto decoder = TextDecoder::constructor(kj::mv(label), options.map([](auto& opts) { - return TextDecoder::ConstructorOptions { + return TextDecoder::ConstructorOptions{ .fatal = opts.fatal.orDefault(true), .ignoreBOM = opts.ignoreBOM.orDefault(false), }; @@ -70,38 +59,28 @@ jsg::Ref TextDecoderStream::constructor( // The controller will store c++ references to both the readable and writable // streams underlying controllers. - auto transformer = TransformStream::constructor( - js, - Transformer { - .transform = jsg::Function( - JSG_VISITABLE_LAMBDA((decoder = decoder.addRef()), - (decoder), - (jsg::Lock& js, auto chunk, auto controller) { - jsg::BufferSource source(js, chunk); - controller->enqueue(js, JSG_REQUIRE_NONNULL( - decoder->decodePtr(js, source.asArrayPtr(), false), - TypeError, - "Failed to decode input.")); - return js.resolvedPromise(); - })), - .flush = jsg::Function( - JSG_VISITABLE_LAMBDA((decoder = decoder.addRef()), - (decoder), - (jsg::Lock& js, auto controller) { - controller->enqueue(js, JSG_REQUIRE_NONNULL( - decoder->decodePtr(js, kj::ArrayPtr(), true), - TypeError, - "Failed to decode input.")); - return js.resolvedPromise(); - })) - }, - StreamQueuingStrategy {}, - StreamQueuingStrategy {}); + auto transformer = TransformStream::constructor(js, + Transformer{.transform = jsg::Function( JSG_VISITABLE_LAMBDA( + (decoder = decoder.addRef()), (decoder), + (jsg::Lock& js, auto chunk, auto controller) { + jsg::BufferSource source(js, chunk); + controller->enqueue(js, + JSG_REQUIRE_NONNULL(decoder->decodePtr(js, source.asArrayPtr(), false), + TypeError, "Failed to decode input.")); + return js.resolvedPromise(); + })), + .flush = jsg::Function( + JSG_VISITABLE_LAMBDA((decoder = decoder.addRef()), (decoder), + (jsg::Lock& js, auto controller) { + controller->enqueue(js, + JSG_REQUIRE_NONNULL(decoder->decodePtr(js, kj::ArrayPtr(), true), + TypeError, "Failed to decode input.")); + return js.resolvedPromise(); + }))}, + StreamQueuingStrategy{}, StreamQueuingStrategy{}); return jsg::alloc( - kj::mv(decoder), - transformer->getReadable(), - transformer->getWritable()); + kj::mv(decoder), transformer->getReadable(), transformer->getWritable()); } kj::StringPtr TextDecoderStream::getEncoding() { diff --git a/src/workerd/api/streams/encoding.h b/src/workerd/api/streams/encoding.h index 0b192e026be..1d651de01b2 100644 --- a/src/workerd/api/streams/encoding.h +++ b/src/workerd/api/streams/encoding.h @@ -17,7 +17,9 @@ class TextEncoderStream: public TransformStream { static jsg::Ref constructor(jsg::Lock& js); - kj::StringPtr getEncoding() { return "utf-8"_kj; } + kj::StringPtr getEncoding() { + return "utf-8"_kj; + } JSG_RESOURCE_TYPE(TextEncoderStream) { JSG_INHERIT(TransformStream); @@ -38,13 +40,11 @@ class TextDecoderStream: public TransformStream { }; TextDecoderStream(jsg::Ref decoder, - jsg::Ref readable, - jsg::Ref writable); + jsg::Ref readable, + jsg::Ref writable); static jsg::Ref constructor( - jsg::Lock& js, - jsg::Optional label, - jsg::Optional options); + jsg::Lock& js, jsg::Optional label, jsg::Optional options); kj::StringPtr getEncoding(); bool getFatal(); diff --git a/src/workerd/api/streams/internal-test.c++ b/src/workerd/api/streams/internal-test.c++ index 87d0f58ac27..63c06d5f486 100644 --- a/src/workerd/api/streams/internal-test.c++ +++ b/src/workerd/api/streams/internal-test.c++ @@ -14,9 +14,9 @@ namespace workerd::api { namespace { template -class FooStream : public ReadableStreamSource { +class FooStream: public ReadableStreamSource { public: - FooStream() : ptr(&data[0]), remaining_(size) { + FooStream(): ptr(&data[0]), remaining_(size) { KJ_ASSERT(RAND_bytes(data, size) == 1); } kj::Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) { @@ -32,13 +32,21 @@ public: return amount; } - kj::ArrayPtr buf() { return data; } + kj::ArrayPtr buf() { + return data; + } - size_t remaining() { return remaining_; } + size_t remaining() { + return remaining_; + } - size_t numreads() { return numreads_; } + size_t numreads() { + return numreads_; + } - size_t maxMaxBytesSeen() { return maxMaxBytesSeen_; } + size_t maxMaxBytesSeen() { + return maxMaxBytesSeen_; + } private: uint8_t data[size]; @@ -49,7 +57,7 @@ private: }; template -class BarStream : public FooStream { +class BarStream: public FooStream { public: kj::Maybe tryGetLength(StreamEncoding encoding) { return size; @@ -64,7 +72,8 @@ KJ_TEST("test") { // number of reads should be 3, and each allocation should be 4096 FooStream<10000> stream; - stream.readAllBytes(10001).then([&](auto bytes) { + stream.readAllBytes(10001) + .then([&](auto bytes) { KJ_ASSERT(bytes.size() == 10000); KJ_ASSERT(bytes == stream.buf().first(10000)); }).wait(waitScope); @@ -81,7 +90,8 @@ KJ_TEST("test (text)") { // number of reads should be 3, and each allocation should be 4096 FooStream<10000> stream; - stream.readAllText(10001).then([&](auto bytes) { + stream.readAllText(10001) + .then([&](auto bytes) { KJ_ASSERT(bytes.size() == 10000); KJ_ASSERT(bytes.asBytes() == stream.buf().first(10000)); }).wait(waitScope); @@ -98,7 +108,8 @@ KJ_TEST("test2") { // only one read. BarStream<10000> stream; - stream.readAllBytes(10001).then([&](auto bytes) { + stream.readAllBytes(10001) + .then([&](auto bytes) { KJ_ASSERT(bytes.size() == 10000); KJ_ASSERT(bytes == stream.buf().first(10000)); }).wait(waitScope); @@ -115,7 +126,8 @@ KJ_TEST("test2 (text)") { // only one read. BarStream<10000> stream; - stream.readAllText(10001).then([&](auto bytes) { + stream.readAllText(10001) + .then([&](auto bytes) { KJ_ASSERT(bytes.size() == 10000); KJ_ASSERT(bytes.asBytes() == stream.buf().first(10000)); }).wait(waitScope); @@ -128,7 +140,7 @@ KJ_TEST("zero-length stream") { kj::EventLoop loop; kj::WaitScope waitScope(loop); - class Zero : public ReadableStreamSource { + class Zero: public ReadableStreamSource { public: kj::Promise tryRead(void*, size_t, size_t) { return (size_t)0; @@ -148,7 +160,7 @@ KJ_TEST("lying stream") { kj::EventLoop loop; kj::WaitScope waitScope(loop); - class Dishonest : public FooStream<10000> { + class Dishonest: public FooStream<10000> { public: kj::Maybe tryGetLength(StreamEncoding encoding) { return (size_t)10; @@ -156,7 +168,8 @@ KJ_TEST("lying stream") { }; Dishonest stream; - stream.readAllBytes(10001).then([&](kj::Array bytes) { + stream.readAllBytes(10001) + .then([&](kj::Array bytes) { // The stream lies! it says there are only 10 bytes but there are more. // oh well, we at least make sure we get the right result. KJ_ASSERT(bytes.size() == 10000); @@ -170,7 +183,7 @@ KJ_TEST("honest small stream") { kj::EventLoop loop; kj::WaitScope waitScope(loop); - class HonestSmall : public FooStream<100> { + class HonestSmall: public FooStream<100> { public: kj::Maybe tryGetLength(StreamEncoding encoding) { return (size_t)100; @@ -194,28 +207,30 @@ KJ_TEST("WritableStreamInternalController queue size assertion") { flags.setWorkerdExperimental(true); flags.setStreamsJavaScriptControllers(true); - TestFixture fixture({ - .featureFlags = flags.asReader()}); + TestFixture fixture({.featureFlags = flags.asReader()}); - class MySink final : public WritableStreamSink { + class MySink final: public WritableStreamSink { public: - kj::Promise write(kj::ArrayPtr buffer) override { return kj::READY_NOW; } + kj::Promise write(kj::ArrayPtr buffer) override { + return kj::READY_NOW; + } kj::Promise write(kj::ArrayPtr> pieces) override { return kj::READY_NOW; } - kj::Promise end() override { return kj::READY_NOW; } + kj::Promise end() override { + return kj::READY_NOW; + } void abort(kj::Exception reason) override {} }; fixture.runInIoContext([&](const TestFixture::Environment& env) { - // Make sure that while an internal sink is being piped into, no other writes are // allowed to be queued. jsg::Ref source = ReadableStream::constructor(env.js, kj::none, kj::none); jsg::Ref sink = jsg::alloc(env.context, kj::heap()); - auto pipeTo = source->pipeTo(env.js, sink.addRef(), PipeToOptions { .preventClose = true }); + auto pipeTo = source->pipeTo(env.js, sink.addRef(), PipeToOptions{.preventClose = true}); KJ_ASSERT(sink->isLocked()); try { @@ -232,12 +247,13 @@ KJ_TEST("WritableStreamInternalController queue size assertion") { bool writeFailed = false; - auto write = sink->getController().write(env.js, buffersource.getHandle(env.js)) - .catch_(env.js, [&](jsg::Lock& js, jsg::Value value) { + auto write = sink->getController() + .write(env.js, buffersource.getHandle(env.js)) + .catch_(env.js, [&](jsg::Lock& js, jsg::Value value) { writeFailed = true; auto ex = js.exceptionToKj(kj::mv(value)); - KJ_ASSERT(ex.getDescription() == - "jsg.TypeError: This WritableStream is currently being piped to."); + KJ_ASSERT( + ex.getDescription() == "jsg.TypeError: This WritableStream is currently being piped to."); }); source->getController().cancel(env.js, kj::none); diff --git a/src/workerd/api/streams/internal.c++ b/src/workerd/api/streams/internal.c++ index bdf8a7b61a0..de892b1d3c2 100644 --- a/src/workerd/api/streams/internal.c++ +++ b/src/workerd/api/streams/internal.c++ @@ -25,9 +25,8 @@ namespace { } } - kj::throwFatalException( - kj::Exception(kj::Exception::Type::FAILED, __FILE__, __LINE__, - kj::str(JSG_EXCEPTION(TypeError) ": ", message))); + kj::throwFatalException(kj::Exception(kj::Exception::Type::FAILED, __FILE__, __LINE__, + kj::str(JSG_EXCEPTION(TypeError) ": ", message))); } kj::Promise pumpTo(ReadableStreamSource& input, WritableStreamSink& output, bool end) { @@ -50,8 +49,7 @@ kj::Promise pumpTo(ReadableStreamSource& input, WritableStreamSink& output // Modified from AllReader in kj/async-io.c++. class AllReader final { public: - explicit AllReader(ReadableStreamSource& input, uint64_t limit) - : input(input), limit(limit) { + explicit AllReader(ReadableStreamSource& input, uint64_t limit): input(input), limit(limit) { JSG_REQUIRE(limit > 0, TypeError, "Memory limit exceeded before EOF."); KJ_IF_SOME(length, input.tryGetLength(StreamEncoding::IDENTITY)) { // Oh hey, we might be able to bail early. @@ -139,9 +137,8 @@ private: // is well behaved. // If the stream does report a length, once we've read that number of bytes, we'll // fallback to the conservativeAllocation. - uint64_t amountToRead = kj::min(limit, - kj::min(MAX_BUFFER_CHUNK, - maybeLength.orDefault(DEFAULT_BUFFER_CHUNK))); + uint64_t amountToRead = + kj::min(limit, kj::min(MAX_BUFFER_CHUNK, maybeLength.orDefault(DEFAULT_BUFFER_CHUNK))); // amountToRead can be zero if the stream reported a zero-length. While the stream could // be lying about it's length, let's skip reading anything in this case. if (amountToRead > 0) { @@ -230,27 +227,24 @@ private: } }; -kj::Exception reasonToException( - jsg::Lock& js, +kj::Exception reasonToException(jsg::Lock& js, jsg::Optional> maybeReason, kj::String defaultDescription = kj::str(JSG_EXCEPTION(Error) ": Stream was cancelled.")) { KJ_IF_SOME(reason, maybeReason) { return js.exceptionToKj(js.v8Ref(reason)); } else { // We get here if the caller is something like `r.cancel()` (or `r.cancel(undefined)`). - return kj::Exception(kj::Exception::Type::FAILED, __FILE__, __LINE__, - kj::mv(defaultDescription)); + return kj::Exception( + kj::Exception::Type::FAILED, __FILE__, __LINE__, kj::mv(defaultDescription)); } } - // ======================================================================================= // Adapt ReadableStreamSource to kj::AsyncInputStream's interface for use with `kj::newTee()`. class TeeAdapter final: public kj::AsyncInputStream { public: - explicit TeeAdapter(kj::Own inner) - : inner(kj::mv(inner)) {} + explicit TeeAdapter(kj::Own inner): inner(kj::mv(inner)) {} kj::Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { return inner->tryRead(buffer, minBytes, maxBytes); @@ -266,8 +260,7 @@ private: class TeeBranch final: public ReadableStreamSource { public: - explicit TeeBranch(kj::Own inner) - : inner(kj::mv(inner)) {} + explicit TeeBranch(kj::Own inner): inner(kj::mv(inner)) {} kj::Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { return inner->tryRead(buffer, minBytes, maxBytes); @@ -355,10 +348,9 @@ static const WarningAggregator::Key unusedStreamBranchKey; class WarnIfUnusedStream final: public ReadableStreamSource { public: - class UnusedStreamWarningContext final : public WarningAggregator::WarningContext { + class UnusedStreamWarningContext final: public WarningAggregator::WarningContext { public: - UnusedStreamWarningContext(jsg::Lock& js) - : exception(jsg::JsRef(js, js.error(""_kjc))) {} + UnusedStreamWarningContext(jsg::Lock& js): exception(jsg::JsRef(js, js.error(""_kjc))) {} kj::String toString(jsg::Lock& js) override { auto handle = exception.getHandle(js); @@ -372,27 +364,26 @@ public: }; static kj::Own createWarningAggregator(IoContext& context) { - return kj::atomicRefcounted(context, - [](jsg::Lock& js, kj::Array> warnings) { + return kj::atomicRefcounted( + context, [](jsg::Lock& js, kj::Array> warnings) { StringBuffer<1024> message(1024); if (warnings.size() > 1) { - message.append(kj::str(warnings.size()), - " ReadableStream branches were created but never consumed. "); + message.append( + kj::str(warnings.size()), " ReadableStream branches were created but never consumed. "); } else { message.append("A ReadableStream branch was created but never consumed. "); } - message.append( - "Such branches can be created, for instance, by calling the tee() " - "method on a ReadableStream, or by calling the clone() method on a " - "Request or Response object. If a branch is created but never consumed, " - "it can force the runtime to buffer the entire body of the stream in " - "memory, which may cause the Worker to exceed its memory limit and be " - "terminated. To avoid this, ensure that all branches created are consumed.\n"); + message.append("Such branches can be created, for instance, by calling the tee() " + "method on a ReadableStream, or by calling the clone() method on a " + "Request or Response object. If a branch is created but never consumed, " + "it can force the runtime to buffer the entire body of the stream in " + "memory, which may cause the Worker to exceed its memory limit and be " + "terminated. To avoid this, ensure that all branches created are consumed.\n"); if (warnings.size() > 1) { for (int n = 0; n < warnings.size(); n++) { auto& warning = warnings[n]; - message.append("\n ", kj::str(n + 1) , ". ", warning->toString(js), "\n"); + message.append("\n ", kj::str(n + 1), ". ", warning->toString(js), "\n"); } } else { message.append("\n * ", warnings[0]->toString(js), "\n"); @@ -402,11 +393,9 @@ public: }); } - explicit WarnIfUnusedStream(jsg::Lock& js, - kj::Own inner, - IoContext& ioContext) - : warningAggregator(ioContext.getWarningAggregator( - unusedStreamBranchKey, + explicit WarnIfUnusedStream( + jsg::Lock& js, kj::Own inner, IoContext& ioContext) + : warningAggregator(ioContext.getWarningAggregator(unusedStreamBranchKey, [](IoContext& context) { return createWarningAggregator(context); })), warningContext(kj::heap(js)), inner(kj::mv(inner)) {} @@ -445,8 +434,11 @@ public: } ~WarnIfUnusedStream() { - if (!wasRead) { warningAggregator->add(kj::mv(warningContext)); } + if (!wasRead) { + warningAggregator->add(kj::mv(warningContext)); + } } + private: kj::Own warningAggregator; kj::Own warningContext; @@ -454,7 +446,7 @@ private: // Used for tracking if this body was ever used. bool wasRead = false; }; -} // namespace +} // namespace // ======================================================================================= @@ -507,8 +499,7 @@ jsg::Ref ReadableStreamInternalController::addRef() { } kj::Maybe> ReadableStreamInternalController::read( - jsg::Lock& js, - kj::Maybe maybeByobOptions) { + jsg::Lock& js, kj::Maybe maybeByobOptions) { if (isPendingClosure) { return js.rejectedPromise( @@ -560,12 +551,12 @@ kj::Maybe> ReadableStreamInternalController::read( return js.rejectedPromise( js.v8TypeError("Unable to allocate memory for read"_kj)); } - return js.resolvedPromise(ReadResult { + return js.resolvedPromise(ReadResult{ .value = js.v8Ref(v8::Uint8Array::New(theStore, 0, 0).As()), .done = true, }); } - return js.resolvedPromise(ReadResult { .done = true }); + return js.resolvedPromise(ReadResult{.done = true}); } KJ_CASE_ONEOF(errored, StreamStates::Errored) { return js.rejectedPromise(errored.addRef(js)); @@ -578,9 +569,8 @@ kj::Maybe> ReadableStreamInternalController::read( // TransformStream implementation is primarily (only?) used for constructing manually // streamed Responses, and no teed ReadableStream has ever supported them. if (readPending) { - return js.rejectedPromise( - js.v8TypeError( - "This ReadableStream only supports a single pending read request at a time."_kj)); + return js.rejectedPromise(js.v8TypeError( + "This ReadableStream only supports a single pending read request at a time."_kj)); } readPending = true; @@ -593,9 +583,8 @@ kj::Maybe> ReadableStreamInternalController::read( auto ptr = static_cast(theStore->Data()); auto bytes = kj::arrayPtr(ptr + byteOffset, byteLength); - auto promise = kj::evalNow([&] { - return readable->tryRead(bytes.begin(), atLeast, bytes.size()); - }); + auto promise = + kj::evalNow([&] { return readable->tryRead(bytes.begin(), atLeast, bytes.size()); }); KJ_IF_SOME(readerLock, readState.tryGet()) { promise = KJ_ASSERT_NONNULL(readerLock.getCanceler())->wrap(kj::mv(promise)); } @@ -609,11 +598,11 @@ kj::Maybe> ReadableStreamInternalController::read( // no need to drop the isolate lock and take it again every time some data is read/written. // That's a larger refactor, though. auto& ioContext = IoContext::current(); - return ioContext.awaitIoLegacy(js, kj::mv(promise)).then(js, - ioContext.addFunctor( - [this,store = js.v8Ref(store), byteOffset, byteLength, - isByob = maybeByobOptions != kj::none] - (jsg::Lock& js, size_t amount) mutable -> jsg::Promise { + return ioContext.awaitIoLegacy(js, kj::mv(promise)) + .then(js, + ioContext.addFunctor([this, store = js.v8Ref(store), byteOffset, byteLength, + isByob = maybeByobOptions != kj::none](jsg::Lock& js, + size_t amount) mutable -> jsg::Promise { readPending = false; KJ_ASSERT(amount <= byteLength); if (amount == 0) { @@ -627,37 +616,34 @@ kj::Maybe> ReadableStreamInternalController::read( // When using the BYOB reader, we must return a sized-0 Uint8Array that is backed // by the ArrayBuffer passed in the options. auto u8 = v8::Uint8Array::New(store.getHandle(js), 0, 0); - return js.resolvedPromise(ReadResult { + return js.resolvedPromise(ReadResult{ .value = js.v8Ref(u8.As()), .done = true, }); } - return js.resolvedPromise(ReadResult { .done = true }); + return js.resolvedPromise(ReadResult{.done = true}); } // Return a slice so the script can see how many bytes were read. - return js.resolvedPromise(ReadResult { - .value = js.v8Ref(v8::Uint8Array::New(store.getHandle(js), byteOffset, amount) - .As()), - .done = false - }); - }), ioContext.addFunctor( - [this](jsg::Lock& js, jsg::Value reason) -> jsg::Promise { + return js.resolvedPromise(ReadResult{ + .value = js.v8Ref( + v8::Uint8Array::New(store.getHandle(js), byteOffset, amount).As()), + .done = false}); + }), + ioContext.addFunctor( + [this](jsg::Lock& js, jsg::Value reason) -> jsg::Promise { readPending = false; if (!state.is()) { doError(js, reason.getHandle(js)); } return js.rejectedPromise(kj::mv(reason)); })); - } } KJ_UNREACHABLE; } jsg::Promise ReadableStreamInternalController::pipeTo( - jsg::Lock& js, - WritableStreamController& destination, - PipeToOptions options) { + jsg::Lock& js, WritableStreamController& destination, PipeToOptions options) { KJ_DASSERT(!isLockedToReader()); KJ_DASSERT(!destination.isLockedToWriter()); @@ -668,9 +654,8 @@ jsg::Promise ReadableStreamInternalController::pipeTo( } disturbed = true; - KJ_IF_SOME(promise, destination.tryPipeFrom(js, - KJ_ASSERT_NONNULL(owner).addRef(), - kj::mv(options))) { + KJ_IF_SOME(promise, + destination.tryPipeFrom(js, KJ_ASSERT_NONNULL(owner).addRef(), kj::mv(options))) { return kj::mv(promise); } @@ -679,8 +664,7 @@ jsg::Promise ReadableStreamInternalController::pipeTo( } jsg::Promise ReadableStreamInternalController::cancel( - jsg::Lock& js, - jsg::Optional> maybeReason) { + jsg::Lock& js, jsg::Optional> maybeReason) { disturbed = true; KJ_IF_SOME(errored, state.tryGet()) { @@ -693,8 +677,7 @@ jsg::Promise ReadableStreamInternalController::cancel( } void ReadableStreamInternalController::doCancel( - jsg::Lock& js, - jsg::Optional> maybeReason) { + jsg::Lock& js, jsg::Optional> maybeReason) { auto exception = reasonToException(js, maybeReason); KJ_IF_SOME(locked, readState.tryGet()) { KJ_IF_SOME(canceler, locked.getCanceler()) { @@ -726,48 +709,44 @@ void ReadableStreamInternalController::doError(jsg::Lock& js, v8::Local(); disturbed = true; KJ_SWITCH_ONEOF(state) { KJ_CASE_ONEOF(closed, StreamStates::Closed) { // Create two closed ReadableStreams. - return Tee { - .branch1 = - jsg::alloc(kj::heap(closed)), - .branch2 = - jsg::alloc(kj::heap(closed)), + return Tee{ + .branch1 = jsg::alloc(kj::heap(closed)), + .branch2 = jsg::alloc(kj::heap(closed)), }; } KJ_CASE_ONEOF(errored, StreamStates::Errored) { // Create two errored ReadableStreams. - return Tee { - .branch1 = - jsg::alloc(kj::heap( - errored.addRef(js))), - .branch2 = - jsg::alloc(kj::heap( - errored.addRef(js))), + return Tee{ + .branch1 = jsg::alloc( + kj::heap(errored.addRef(js))), + .branch2 = jsg::alloc( + kj::heap(errored.addRef(js))), }; } KJ_CASE_ONEOF(readable, Readable) { auto& ioContext = IoContext::current(); - auto makeTee = - [&](kj::Own b1, kj::Own b2) -> Tee { - doClose(js); - if (ioContext.isInspectorEnabled()) { - b1 = kj::heap(js, kj::mv(b1), ioContext); - b2 = kj::heap(js, kj::mv(b2), ioContext); - } - return Tee { - .branch1 = jsg::alloc(ioContext, kj::mv(b1)), - .branch2 = jsg::alloc(ioContext, kj::mv(b2)), - }; - }; + auto makeTee = [&](kj::Own b1, + kj::Own b2) -> Tee { + doClose(js); + if (ioContext.isInspectorEnabled()) { + b1 = kj::heap(js, kj::mv(b1), ioContext); + b2 = kj::heap(js, kj::mv(b2), ioContext); + } + return Tee{ + .branch1 = jsg::alloc(ioContext, kj::mv(b1)), + .branch2 = jsg::alloc(ioContext, kj::mv(b2)), + }; + }; auto bufferLimit = ioContext.getLimitEnforcer().getBufferingLimit(); KJ_IF_SOME(tee, readable->tryTee(bufferLimit)) { @@ -777,8 +756,7 @@ ReadableStreamController::Tee ReadableStreamInternalController::tee(jsg::Lock& j auto tee = kj::newTee(kj::heap(kj::mv(readable)), bufferLimit); - return makeTee( - kj::heap(newTeeErrorAdapter(kj::mv(tee.branches[0]))), + return makeTee(kj::heap(newTeeErrorAdapter(kj::mv(tee.branches[0]))), kj::heap(newTeeErrorAdapter(kj::mv(tee.branches[1])))); } } @@ -788,8 +766,8 @@ ReadableStreamController::Tee ReadableStreamInternalController::tee(jsg::Lock& j kj::Maybe> ReadableStreamInternalController::removeSource( jsg::Lock& js, bool ignoreDisturbed) { - JSG_REQUIRE(!isLockedToReader(), TypeError, - "This ReadableStream is currently locked to a reader."); + JSG_REQUIRE( + !isLockedToReader(), TypeError, "This ReadableStream is currently locked to a reader."); JSG_REQUIRE(!disturbed || ignoreDisturbed, TypeError, "This ReadableStream is disturbed."); readState.init(); @@ -831,8 +809,8 @@ bool ReadableStreamInternalController::lockReader(jsg::Lock& js, Reader& reader) auto prp = js.newPromiseAndResolver(); prp.promise.markAsHandled(js); - auto lock = ReaderLocked(reader, kj::mv(prp.resolver), - IoContext::current().addObject(kj::heap())); + auto lock = ReaderLocked( + reader, kj::mv(prp.resolver), IoContext::current().addObject(kj::heap())); KJ_SWITCH_ONEOF(state) { KJ_CASE_ONEOF(closed, StreamStates::Closed) { @@ -852,17 +830,15 @@ bool ReadableStreamInternalController::lockReader(jsg::Lock& js, Reader& reader) } void ReadableStreamInternalController::releaseReader( - Reader& reader, - kj::Maybe maybeJs) { + Reader& reader, kj::Maybe maybeJs) { KJ_IF_SOME(locked, readState.tryGet()) { KJ_ASSERT(&locked.getReader() == &reader); KJ_IF_SOME(js, maybeJs) { KJ_IF_SOME(canceler, locked.getCanceler()) { JSG_REQUIRE(canceler->isEmpty(), TypeError, - "Cannot call releaseLock() on a reader with outstanding read promises."); + "Cannot call releaseLock() on a reader with outstanding read promises."); } - maybeRejectPromise(js, - locked.getClosedFulfiller(), + maybeRejectPromise(js, locked.getClosedFulfiller(), js.v8TypeError("This ReadableStream reader has been released."_kj)); } locked.clear(); @@ -894,15 +870,13 @@ jsg::Ref WritableStreamInternalController::addRef() { } jsg::Promise WritableStreamInternalController::write( - jsg::Lock& js, - jsg::Optional> value) { + jsg::Lock& js, jsg::Optional> value) { if (isPendingClosure) { return js.rejectedPromise( js.v8TypeError("This WritableStream belongs to an object that is closing."_kj)); } if (isClosedOrClosing()) { - return js.rejectedPromise( - js.v8TypeError("This WritableStream has been closed."_kj)); + return js.rejectedPromise(js.v8TypeError("This WritableStream has been closed."_kj)); } if (isPiping()) { return js.rejectedPromise( @@ -956,17 +930,16 @@ jsg::Promise WritableStreamInternalController::write( auto prp = js.newPromiseAndResolver(); increaseCurrentWriteBufferSize(js, byteLength); - auto ptr = kj::ArrayPtr(static_cast(store->Data()) + byteOffset, - byteLength); - queue.push_back(WriteEvent { - .outputLock = IoContext::current().waitForOutputLocksIfNecessaryIoOwn(), - .event = Write { - .promise = kj::mv(prp.resolver), - .totalBytes = store->ByteLength(), - .ownBytes = js.v8Ref(v8::ArrayBuffer::New(js.v8Isolate, kj::mv(store))), - .bytes = ptr, - } - }); + auto ptr = + kj::ArrayPtr(static_cast(store->Data()) + byteOffset, byteLength); + queue.push_back( + WriteEvent{.outputLock = IoContext::current().waitForOutputLocksIfNecessaryIoOwn(), + .event = Write{ + .promise = kj::mv(prp.resolver), + .totalBytes = store->ByteLength(), + .ownBytes = js.v8Ref(v8::ArrayBuffer::New(js.v8Isolate, kj::mv(store))), + .bytes = ptr, + }}); ensureWriting(js); return kj::mv(prp.promise); @@ -977,8 +950,7 @@ jsg::Promise WritableStreamInternalController::write( } void WritableStreamInternalController::increaseCurrentWriteBufferSize( - jsg::Lock& js, - uint64_t amount) { + jsg::Lock& js, uint64_t amount) { currentWriteBufferSize += amount; KJ_IF_SOME(highWaterMark, maybeHighWaterMark) { int64_t amount = highWaterMark - currentWriteBufferSize; @@ -995,11 +967,14 @@ void WritableStreamInternalController::increaseCurrentWriteBufferSize( if (warnAboutExcessiveBackpressure && (currentWriteBufferSize >= 2 * highWaterMark)) { excessiveBackpressureWarningCount++; auto warning = kj::str("A WritableStream is experiencing excessive backpressure. " - "The current write buffer size is ", currentWriteBufferSize, - " bytes, which is greater than or equal to double the high water mark " - "of ", highWaterMark, " bytes. Streams that consistently exceed the " - "configured high water mark may cause excessive memory usage. ", - "(Count ", excessiveBackpressureWarningCount, ")"); + "The current write buffer size is ", + currentWriteBufferSize, + " bytes, which is greater than or equal to double the high water mark " + "of ", + highWaterMark, + " bytes. Streams that consistently exceed the " + "configured high water mark may cause excessive memory usage. ", + "(Count ", excessiveBackpressureWarningCount, ")"); js.logWarning(warning); warnAboutExcessiveBackpressure = false; } @@ -1007,8 +982,7 @@ void WritableStreamInternalController::increaseCurrentWriteBufferSize( } void WritableStreamInternalController::decreaseCurrentWriteBufferSize( - jsg::Lock& js, - uint64_t amount) { + jsg::Lock& js, uint64_t amount) { currentWriteBufferSize -= amount; KJ_IF_SOME(highWaterMark, maybeHighWaterMark) { int64_t amount = highWaterMark - currentWriteBufferSize; @@ -1062,10 +1036,9 @@ jsg::Promise WritableStreamInternalController::closeImpl(jsg::Lock& js, bo if (markAsHandled) { prp.promise.markAsHandled(js); } - queue.push_back(WriteEvent { - .outputLock = IoContext::current().waitForOutputLocksIfNecessaryIoOwn(), - .event = Close { .promise = kj::mv(prp.resolver) } - }); + queue.push_back( + WriteEvent{.outputLock = IoContext::current().waitForOutputLocksIfNecessaryIoOwn(), + .event = Close{.promise = kj::mv(prp.resolver)}}); ensureWriting(js); return kj::mv(prp.promise); } @@ -1074,9 +1047,7 @@ jsg::Promise WritableStreamInternalController::closeImpl(jsg::Lock& js, bo KJ_UNREACHABLE; } -jsg::Promise WritableStreamInternalController::close( - jsg::Lock& js, - bool markAsHandled) { +jsg::Promise WritableStreamInternalController::close(jsg::Lock& js, bool markAsHandled) { KJ_IF_SOME(closureWaitable, maybeClosureWaitable) { // If we're already waiting on the closure waitable, then we do not want to try scheduling // it again, let's just wait for the existing one to be resolved. @@ -1084,14 +1055,13 @@ jsg::Promise WritableStreamInternalController::close( return closureWaitable.whenResolved(js); } waitingOnClosureWritableAlready = true; - auto promise = closureWaitable - .then(js, [markAsHandled, this](jsg::Lock& js) { - return closeImpl(js, markAsHandled); - }, [](jsg::Lock& js, jsg::Value) { - // Ignore rejection as it will be reported in the Socket's `closed`/`opened` promises - // instead. - return js.resolvedPromise(); - }); + auto promise = closureWaitable.then(js, [markAsHandled, this](jsg::Lock& js) { + return closeImpl(js, markAsHandled); + }, [](jsg::Lock& js, jsg::Value) { + // Ignore rejection as it will be reported in the Socket's `closed`/`opened` promises + // instead. + return js.resolvedPromise(); + }); maybeClosureWaitable = promise.whenResolved(js); return kj::mv(promise); } else { @@ -1099,9 +1069,7 @@ jsg::Promise WritableStreamInternalController::close( } } -jsg::Promise WritableStreamInternalController::flush( - jsg::Lock& js, - bool markAsHandled) { +jsg::Promise WritableStreamInternalController::flush(jsg::Lock& js, bool markAsHandled) { if (isClosedOrClosing()) { auto reason = js.v8TypeError("This WritableStream has been closed."_kj); return rejectedMaybeHandledPromise(js, reason, markAsHandled); @@ -1125,10 +1093,9 @@ jsg::Promise WritableStreamInternalController::flush( if (markAsHandled) { prp.promise.markAsHandled(js); } - queue.push_back(WriteEvent { - .outputLock = IoContext::current().waitForOutputLocksIfNecessaryIoOwn(), - .event = Flush { .promise = kj::mv(prp.resolver) } - }); + queue.push_back( + WriteEvent{.outputLock = IoContext::current().waitForOutputLocksIfNecessaryIoOwn(), + .event = Flush{.promise = kj::mv(prp.resolver)}}); ensureWriting(js); return kj::mv(prp.promise); } @@ -1138,8 +1105,7 @@ jsg::Promise WritableStreamInternalController::flush( } jsg::Promise WritableStreamInternalController::abort( - jsg::Lock& js, - jsg::Optional> maybeReason) { + jsg::Lock& js, jsg::Optional> maybeReason) { // While it may be confusing to users to throw `undefined` rather than a more helpful Error here, // doing so is required by the relevant spec: // https://streams.spec.whatwg.org/#writable-stream-abort @@ -1147,9 +1113,7 @@ jsg::Promise WritableStreamInternalController::abort( } jsg::Promise WritableStreamInternalController::doAbort( - jsg::Lock& js, - v8::Local reason, - AbortOptions options) { + jsg::Lock& js, v8::Local reason, AbortOptions options) { // If maybePendingAbort is set, then the returned abort promise will be rejected // with the specified error once the abort is completed, otherwise the promise will // be resolved with undefined. @@ -1176,17 +1140,15 @@ jsg::Promise WritableStreamInternalController::doAbort( // immediately and an immediately resolved or rejected promise will be returned. writable->abort(kj::cp(exception)); drain(js, reason); - return options.reject ? - rejectedMaybeHandledPromise(js, reason, options.handled) : - js.resolvedPromise(); + return options.reject ? rejectedMaybeHandledPromise(js, reason, options.handled) + : js.resolvedPromise(); } if (queue.empty()) { writable->abort(kj::cp(exception)); doError(js, reason); - return options.reject ? - rejectedMaybeHandledPromise(js, reason, options.handled) : - js.resolvedPromise(); + return options.reject ? rejectedMaybeHandledPromise(js, reason, options.handled) + : js.resolvedPromise(); } maybePendingAbort = PendingAbort(js, reason, options.reject); @@ -1197,15 +1159,12 @@ jsg::Promise WritableStreamInternalController::doAbort( return kj::mv(promise); } - return options.reject ? - rejectedMaybeHandledPromise(js, reason, options.handled) : - js.resolvedPromise(); + return options.reject ? rejectedMaybeHandledPromise(js, reason, options.handled) + : js.resolvedPromise(); } kj::Maybe> WritableStreamInternalController::tryPipeFrom( - jsg::Lock& js, - jsg::Ref source, - PipeToOptions options) { + jsg::Lock& js, jsg::Ref source, PipeToOptions options) { // The ReadableStream source here can be either a JavaScript-backed ReadableStream // or ReadableStreamSource-backed. @@ -1238,7 +1197,7 @@ kj::Maybe> WritableStreamInternalController::tryPipeFrom( KJ_ASSERT_NONNULL(source->getController().tryPipeLock(KJ_ASSERT_NONNULL(owner).addRef())); // Let's also acquire the destination pipe lock. - writeState = PipeLocked{ *source }; + writeState = PipeLocked{*source}; // If the source has errored, the spec requires us to reject the pipe promise and, if preventAbort // is false, error the destination (Propagate error forward). The errored source will be unlocked @@ -1247,7 +1206,7 @@ kj::Maybe> WritableStreamInternalController::tryPipeFrom( sourceLock.release(js); if (!preventAbort) { if (state.tryGet>() != kj::none) { - return doAbort(js, errored, { .reject = true, .handled = pipeThrough }); + return doAbort(js, errored, {.reject = true, .handled = pipeThrough}); } } @@ -1314,26 +1273,23 @@ kj::Maybe> WritableStreamInternalController::tryPipeFrom( if (pipeThrough) { prp.promise.markAsHandled(js); } - queue.push_back(WriteEvent { + queue.push_back(WriteEvent{ .outputLock = IoContext::current().waitForOutputLocksIfNecessaryIoOwn(), - .event = Pipe { - .parent = *this, + .event = Pipe{.parent = *this, .source = sourceLock, .promise = kj::mv(prp.resolver), .preventAbort = preventAbort, .preventClose = preventClose, .preventCancel = preventCancel, - .maybeSignal = kj::mv(options.signal) - }, + .maybeSignal = kj::mv(options.signal)}, }); ensureWriting(js); return kj::mv(prp.promise); } -kj::Maybe> WritableStreamInternalController::removeSink( - jsg::Lock& js) { - JSG_REQUIRE(!isLockedToWriter(), TypeError, - "This WritableStream is currently locked to a writer."); +kj::Maybe> WritableStreamInternalController::removeSink(jsg::Lock& js) { + JSG_REQUIRE( + !isLockedToWriter(), TypeError, "This WritableStream is currently locked to a writer."); JSG_REQUIRE(!isClosedOrClosing(), TypeError, "This WritableStream is closed."); writeState.init(); @@ -1357,8 +1313,8 @@ kj::Maybe> WritableStreamInternalController::removeS } void WritableStreamInternalController::detach(jsg::Lock& js) { - JSG_REQUIRE(!isLockedToWriter(), TypeError, - "This WritableStream is currently locked to a writer."); + JSG_REQUIRE( + !isLockedToWriter(), TypeError, "This WritableStream is currently locked to a writer."); JSG_REQUIRE(!isClosedOrClosing(), TypeError, "This WritableStream is closed."); writeState.init(); @@ -1382,8 +1338,12 @@ void WritableStreamInternalController::detach(jsg::Lock& js) { kj::Maybe WritableStreamInternalController::getDesiredSize() { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) { return 0; } - KJ_CASE_ONEOF(errored, StreamStates::Errored) { return kj::none; } + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + return 0; + } + KJ_CASE_ONEOF(errored, StreamStates::Errored) { + return kj::none; + } KJ_CASE_ONEOF(writable, IoOwn) { KJ_IF_SOME(highWaterMark, maybeHighWaterMark) { return highWaterMark - currentWriteBufferSize; @@ -1428,13 +1388,11 @@ bool WritableStreamInternalController::lockWriter(jsg::Lock& js, Writer& writer) } void WritableStreamInternalController::releaseWriter( - Writer& writer, - kj::Maybe maybeJs) { + Writer& writer, kj::Maybe maybeJs) { KJ_IF_SOME(locked, writeState.tryGet()) { KJ_ASSERT(&locked.getWriter() == &writer); KJ_IF_SOME(js, maybeJs) { - maybeRejectPromise(js, - locked.getClosedFulfiller(), + maybeRejectPromise(js, locked.getClosedFulfiller(), js.v8TypeError("This WritableStream writer has been released."_kj)); } locked.clear(); @@ -1497,15 +1455,12 @@ void WritableStreamInternalController::ensureWriting(jsg::Lock& js) { } jsg::Promise WritableStreamInternalController::writeLoop( - jsg::Lock& js, - IoContext& ioContext) { + jsg::Lock& js, IoContext& ioContext) { if (queue.empty()) { return js.resolvedPromise(); } else KJ_IF_SOME(promise, queue.front().outputLock) { return ioContext.awaitIo(js, kj::mv(*promise), - [this](jsg::Lock& js) -> jsg::Promise { - return writeLoopAfterFrontOutputLock(js); - }); + [this](jsg::Lock& js) -> jsg::Promise { return writeLoopAfterFrontOutputLock(js); }); } else { return writeLoopAfterFrontOutputLock(js); } @@ -1519,9 +1474,7 @@ void WritableStreamInternalController::finishClose(jsg::Lock& js) { doClose(js); } -void WritableStreamInternalController::finishError( - jsg::Lock& js, - v8::Local reason) { +void WritableStreamInternalController::finishError(jsg::Lock& js, v8::Local reason) { KJ_IF_SOME(pendingAbort, PendingAbort::dequeue(maybePendingAbort)) { // In this case, and only this case, we ignore any pending rejection // that may be stored in the pendingAbort. The current exception takes @@ -1532,8 +1485,7 @@ void WritableStreamInternalController::finishError( doError(js, reason); } -jsg::Promise WritableStreamInternalController::writeLoopAfterFrontOutputLock( - jsg::Lock& js) { +jsg::Promise WritableStreamInternalController::writeLoopAfterFrontOutputLock(jsg::Lock& js) { auto& ioContext = IoContext::current(); // This helper function is just used to enhance the assert logging when checking @@ -1541,16 +1493,24 @@ jsg::Promise WritableStreamInternalController::writeLoopAfterFrontOutputLo static constexpr auto inspectQueue = [](auto& queue, kj::StringPtr name) { if (queue.size() > 1) { kj::Vector events; - for (auto& event : queue) { + for (auto& event: queue) { KJ_SWITCH_ONEOF(event.event) { - KJ_CASE_ONEOF(write, Write) { events.add(kj::str("Write")); } - KJ_CASE_ONEOF(flush, Flush) { events.add(kj::str("Flush")); } - KJ_CASE_ONEOF(close, Close) { events.add(kj::str("Close")); } - KJ_CASE_ONEOF(pipe, Pipe) { events.add(kj::str("Pipe")); } + KJ_CASE_ONEOF(write, Write) { + events.add(kj::str("Write")); + } + KJ_CASE_ONEOF(flush, Flush) { + events.add(kj::str("Flush")); + } + KJ_CASE_ONEOF(close, Close) { + events.add(kj::str("Close")); + } + KJ_CASE_ONEOF(pipe, Pipe) { + events.add(kj::str("Pipe")); + } } } return kj::str("Too many events in internal writablestream queue: ", - kj::delimited(kj::mv(events), ", ")); + kj::delimited(kj::mv(events), ", ")); } return kj::String(); }; @@ -1626,32 +1586,32 @@ jsg::Promise WritableStreamInternalController::writeLoopAfterFrontOutputLo // jsg::Promises and not kj::Promises, so that it doesn't look like I/O at all, and there's // no need to drop the isolate lock and take it again every time some data is read/written. // That's a larger refactor, though. - return ioContext.awaitIoLegacy(js, writable->canceler.wrap(kj::mv(promise))).then(js, - ioContext.addFunctor( - [this, check, maybeAbort, amountToWrite](jsg::Lock& js) -> jsg::Promise { + return ioContext.awaitIoLegacy(js, writable->canceler.wrap(kj::mv(promise))) + .then(js, + ioContext.addFunctor( + [this, check, maybeAbort, amountToWrite](jsg::Lock& js) -> jsg::Promise { auto& request = check(); maybeResolvePromise(js, request.promise); decreaseCurrentWriteBufferSize(js, amountToWrite); queue.pop_front(); maybeAbort(js, request); return writeLoop(js, IoContext::current()); - }), ioContext.addFunctor( - [this, check, maybeAbort, amountToWrite](jsg::Lock& js, jsg::Value reason) - -> jsg::Promise { - auto handle = reason.getHandle(js); - auto& request = check(); - auto& writable = state.get>(); - decreaseCurrentWriteBufferSize(js, amountToWrite); - maybeRejectPromise(js, request.promise, handle); - queue.pop_front(); - if (!maybeAbort(js, request)) { - auto ex = js.exceptionToKj(reason.addRef(js)); - writable->abort(kj::mv(ex)); - drain(js, handle); - } - return js.resolvedPromise(); + }), + ioContext.addFunctor([this, check, maybeAbort, amountToWrite]( + jsg::Lock& js, jsg::Value reason) -> jsg::Promise { + auto handle = reason.getHandle(js); + auto& request = check(); + auto& writable = state.get>(); + decreaseCurrentWriteBufferSize(js, amountToWrite); + maybeRejectPromise(js, request.promise, handle); + queue.pop_front(); + if (!maybeAbort(js, request)) { + auto ex = js.exceptionToKj(reason.addRef(js)); + writable->abort(kj::mv(ex)); + drain(js, handle); } - )); + return js.resolvedPromise(); + })); } KJ_CASE_ONEOF(request, Pipe) { // The destination should still be Writable, because the only way to transition to an @@ -1700,11 +1660,10 @@ jsg::Promise WritableStreamInternalController::writeLoopAfterFrontOutputLo // ReadableStream is JavaScript-backed and we need to setup a JavaScript-promise read/write // loop to pass the data into the destination. - const auto handlePromise = - [this, &ioContext, check = makeChecker(request), preventAbort = request.preventAbort] - (jsg::Lock& js, auto promise) { - return promise.then(js, - ioContext.addFunctor([this, check](jsg::Lock& js) mutable { + const auto handlePromise = [this, &ioContext, check = makeChecker(request), + preventAbort = request.preventAbort]( + jsg::Lock& js, auto promise) { + return promise.then(js, ioContext.addFunctor([this, check](jsg::Lock& js) mutable { // Under some conditions, the clean up has already happened. if (queue.empty()) return js.resolvedPromise(); @@ -1739,8 +1698,9 @@ jsg::Promise WritableStreamInternalController::writeLoopAfterFrontOutputLo writeState.init(); } return js.resolvedPromise(); - }), ioContext.addFunctor([this, check, preventAbort] - (jsg::Lock& js, jsg::Value reason) mutable { + }), + ioContext.addFunctor( + [this, check, preventAbort](jsg::Lock& js, jsg::Value reason) mutable { auto handle = reason.getHandle(js); auto& request = check(); maybeRejectPromise(js, request.promise, handle); @@ -1762,9 +1722,10 @@ jsg::Promise WritableStreamInternalController::writeLoopAfterFrontOutputLo }; KJ_IF_SOME(promise, request.source.tryPumpTo(*writable->sink, !request.preventClose)) { - return handlePromise(js, ioContext.awaitIo(js, - writable->canceler.wrap( - AbortSignal::maybeCancelWrap(request.maybeSignal, kj::mv(promise))))); + return handlePromise(js, + ioContext.awaitIo(js, + writable->canceler.wrap( + AbortSignal::maybeCancelWrap(request.maybeSignal, kj::mv(promise))))); } // The ReadableStream is JavaScript-backed. We can still pipe the data but it's going to be @@ -1779,14 +1740,14 @@ jsg::Promise WritableStreamInternalController::writeLoopAfterFrontOutputLo auto& writable = state.get>(); auto check = makeChecker(request); - return ioContext.awaitIo(js, writable->canceler.wrap( - writable->sink->end())).then(js, - ioContext.addFunctor([this, check](jsg::Lock& js) { + return ioContext.awaitIo(js, writable->canceler.wrap(writable->sink->end())) + .then(js, ioContext.addFunctor([this, check](jsg::Lock& js) { auto& request = check(); maybeResolvePromise(js, request.promise); queue.pop_front(); finishClose(js); - }), ioContext.addFunctor([this, check](jsg::Lock& js, jsg::Value reason) { + }), + ioContext.addFunctor([this, check](jsg::Lock& js, jsg::Value reason) { auto handle = reason.getHandle(js); auto& request = check(); maybeRejectPromise(js, request.promise, handle); @@ -1871,7 +1832,8 @@ jsg::Promise WritableStreamInternalController::Pipe::write(v8::Localcanceler.wrap(writable->sink->write(kj::arrayPtr(data, byteLength))) - .attach(js.v8Ref(v8::ArrayBuffer::New(js.v8Isolate, store))), [](jsg::Lock&){}); + .attach(js.v8Ref(v8::ArrayBuffer::New(js.v8Isolate, store))), + [](jsg::Lock&) {}); } jsg::Promise WritableStreamInternalController::Pipe::pipeLoop(jsg::Lock& js) { @@ -1931,12 +1893,12 @@ jsg::Promise WritableStreamInternalController::Pipe::pipeLoop(jsg::Lock& j if (!parent.isClosedOrClosing()) { // We'll only be here if the sink is in the Writable state. auto& ioContext = IoContext::current(); - return ioContext.awaitIo(js, - parent.state.get>()->sink->end(), [](jsg::Lock&){}).then(js, - ioContext.addFunctor([this](jsg::Lock& js) { parent.finishClose(js); }), - ioContext.addFunctor([this](jsg::Lock& js, jsg::Value reason) { - parent.finishError(js, reason.getHandle(js)); - })); + return ioContext + .awaitIo(js, parent.state.get>()->sink->end(), [](jsg::Lock&) {}) + .then(js, ioContext.addFunctor([this](jsg::Lock& js) { parent.finishClose(js); }), + ioContext.addFunctor([this](jsg::Lock& js, jsg::Value reason) { + parent.finishError(js, reason.getHandle(js)); + })); } parent.writeState.init(); } @@ -1957,8 +1919,7 @@ jsg::Promise WritableStreamInternalController::Pipe::pipeLoop(jsg::Lock& j } return source.read(js).then(js, - ioContext.addFunctor( - [this](jsg::Lock& js, ReadResult result) -> jsg::Promise { + ioContext.addFunctor([this](jsg::Lock& js, ReadResult result) -> jsg::Promise { if (checkSignal(js) || result.done) { return js.resolvedPromise(); } @@ -1969,8 +1930,7 @@ jsg::Promise WritableStreamInternalController::Pipe::pipeLoop(jsg::Lock& j KJ_IF_SOME(value, result.value) { auto handle = value.getHandle(js); if (handle->IsArrayBuffer() || handle->IsArrayBufferView()) { - return write(handle).then(js, - [this](jsg::Lock& js) -> jsg::Promise { + return write(handle).then(js, [this](jsg::Lock& js) -> jsg::Promise { // The signal will be checked again at the start of the next loop iteration. return pipeLoop(js); }, [this](jsg::Lock& js, jsg::Value reason) -> jsg::Promise { @@ -1987,7 +1947,8 @@ jsg::Promise WritableStreamInternalController::Pipe::pipeLoop(jsg::Lock& j writable->abort(kj::mv(ex)); // The error condition will be handled at the start of the next iteration. return pipeLoop(js); - }), ioContext.addFunctor([this](jsg::Lock& js, jsg::Value reason) -> jsg::Promise { + }), + ioContext.addFunctor([this](jsg::Lock& js, jsg::Value reason) -> jsg::Promise { // The error will be processed and propagated in the next iteration. return pipeLoop(js); })); @@ -2018,7 +1979,7 @@ void WritableStreamInternalController::drain(jsg::Lock& js, v8::Local } void WritableStreamInternalController::visitForGc(jsg::GcVisitor& visitor) { - for (auto& event : queue) { + for (auto& event: queue) { KJ_SWITCH_ONEOF(event.event) { KJ_CASE_ONEOF(write, Write) { visitor.visit(write.promise); @@ -2070,8 +2031,7 @@ kj::Maybe> ReadableStreamInternalController::PipeLocked::tr } void ReadableStreamInternalController::PipeLocked::cancel( - jsg::Lock& js, - v8::Local reason) { + jsg::Lock& js, v8::Local reason) { if (inner.state.is()) { inner.doCancel(js, reason); } @@ -2082,14 +2042,12 @@ void ReadableStreamInternalController::PipeLocked::close(jsg::Lock& js) { } void ReadableStreamInternalController::PipeLocked::error( - jsg::Lock& js, - v8::Local reason) { + jsg::Lock& js, v8::Local reason) { inner.doError(js, reason); } void ReadableStreamInternalController::PipeLocked::release( - jsg::Lock& js, - kj::Maybe> maybeError) { + jsg::Lock& js, kj::Maybe> maybeError) { KJ_IF_SOME(error, maybeError) { cancel(js, error); } @@ -2097,8 +2055,7 @@ void ReadableStreamInternalController::PipeLocked::release( } kj::Maybe> ReadableStreamInternalController::PipeLocked::tryPumpTo( - WritableStreamSink& sink, - bool end) { + WritableStreamSink& sink, bool end) { // This is safe because the caller should have already checked isClosed and tryGetErrored // and handled those before calling tryPumpTo. auto& readable = KJ_ASSERT_NONNULL(inner.state.tryGet()); @@ -2110,11 +2067,10 @@ jsg::Promise ReadableStreamInternalController::PipeLocked::read(jsg: } jsg::Promise> ReadableStreamInternalController::readAllBytes( - jsg::Lock& js, - uint64_t limit) { + jsg::Lock& js, uint64_t limit) { if (isLockedToReader()) { - return js.rejectedPromise>(KJ_EXCEPTION(FAILED, - "jsg.TypeError: This ReadableStream is currently locked to a reader.")); + return js.rejectedPromise>(KJ_EXCEPTION( + FAILED, "jsg.TypeError: This ReadableStream is currently locked to a reader.")); } if (isPendingClosure) { return js.rejectedPromise>( @@ -2137,11 +2093,10 @@ jsg::Promise> ReadableStreamInternalController::readAllBytes( } jsg::Promise ReadableStreamInternalController::readAllText( - jsg::Lock& js, - uint64_t limit) { + jsg::Lock& js, uint64_t limit) { if (isLockedToReader()) { - return js.rejectedPromise(KJ_EXCEPTION(FAILED, - "jsg.TypeError: This ReadableStream is currently locked to a reader.")); + return js.rejectedPromise(KJ_EXCEPTION( + FAILED, "jsg.TypeError: This ReadableStream is currently locked to a reader.")); } if (isPendingClosure) { return js.rejectedPromise( @@ -2165,17 +2120,23 @@ jsg::Promise ReadableStreamInternalController::readAllText( kj::Maybe ReadableStreamInternalController::tryGetLength(StreamEncoding encoding) { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) { return uint64_t(0); } - KJ_CASE_ONEOF(errored, StreamStates::Errored) { return kj::none; } - KJ_CASE_ONEOF(readable, Readable) { return readable->tryGetLength(encoding); } + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + return uint64_t(0); + } + KJ_CASE_ONEOF(errored, StreamStates::Errored) { + return kj::none; + } + KJ_CASE_ONEOF(readable, Readable) { + return readable->tryGetLength(encoding); + } } KJ_UNREACHABLE; } kj::Own ReadableStreamInternalController::detach( jsg::Lock& js, bool ignoreDetached) { - return newReadableStreamInternalController(IoContext::current(), - KJ_ASSERT_NONNULL(removeSource(js, ignoreDetached))); + return newReadableStreamInternalController( + IoContext::current(), KJ_ASSERT_NONNULL(removeSource(js, ignoreDetached))); } kj::Promise> ReadableStreamInternalController::pumpTo( @@ -2188,7 +2149,8 @@ kj::Promise> ReadableStreamInternalController::pumpTo( bool done = false; Holder(kj::Own sink, kj::Own source) - : sink(kj::mv(sink)), source(kj::mv(source)) {} + : sink(kj::mv(sink)), + source(kj::mv(source)) {} ~Holder() noexcept(false) { if (!done) { // It appears the pump was canceled. We should make sure this propagates back to the @@ -2205,12 +2167,12 @@ kj::Promise> ReadableStreamInternalController::pumpTo( }; auto holder = kj::refcounted(kj::mv(sink), kj::mv(source)); - return holder->source->pumpTo(*holder->sink, end).then( - [&holder=*holder](DeferredProxy proxy) mutable -> DeferredProxy { + return holder->source->pumpTo(*holder->sink, end) + .then([&holder = *holder](DeferredProxy proxy) mutable -> DeferredProxy { proxy.proxyTask = proxy.proxyTask.attach(kj::addRef(holder)); holder.done = true; return kj::mv(proxy); - }, [&holder=*holder](kj::Exception&& ex) mutable { + }, [&holder = *holder](kj::Exception&& ex) mutable { holder.sink->abort(kj::cp(ex)); holder.source->cancel(kj::cp(ex)); holder.done = true; @@ -2234,9 +2196,7 @@ StreamEncoding ReadableStreamInternalController::getPreferredEncoding() { } kj::Promise IdentityTransformStreamImpl::tryRead( - void* buffer, - size_t minBytes, - size_t maxBytes) { + void* buffer, size_t minBytes, size_t maxBytes) { size_t total = 0; while (total < minBytes) { // TODO(perf): tryReadInternal was written assuming minBytes would always be 1 but we've now @@ -2264,13 +2224,13 @@ kj::Promise IdentityTransformStreamImpl::tryReadInternal(void* buffer, s KJ_IF_SOME(l, limit) { promise = promise.then([this, &l = l](size_t amount) -> kj::Promise { if (amount > l) { - auto exception = JSG_KJ_EXCEPTION(FAILED, TypeError, - "Attempt to write too many bytes through a FixedLengthStream."); + auto exception = JSG_KJ_EXCEPTION( + FAILED, TypeError, "Attempt to write too many bytes through a FixedLengthStream."); cancel(exception); return kj::mv(exception); } else if (amount == 0 && l != 0) { - auto exception = JSG_KJ_EXCEPTION(FAILED, TypeError, - "FixedLengthStream did not see all expected bytes before close()."); + auto exception = JSG_KJ_EXCEPTION( + FAILED, TypeError, "FixedLengthStream did not see all expected bytes before close()."); cancel(exception); return kj::mv(exception); } @@ -2283,8 +2243,7 @@ kj::Promise IdentityTransformStreamImpl::tryReadInternal(void* buffer, s } kj::Promise> IdentityTransformStreamImpl::pumpTo( - WritableStreamSink& output, - bool end) { + WritableStreamSink& output, bool end) { #ifdef KJ_NO_RTTI // Yes, I'm paranoid. static_assert(!KJ_NO_RTTI, "Need RTTI for correctness"); @@ -2365,7 +2324,7 @@ void IdentityTransformStreamImpl::abort(kj::Exception reason) { // IF the fulfiller is not waiting, the write promise was already // canceled and no one is waiting on it. KJ_ASSERT(!request.fulfiller->isWaiting(), - "abort() is supposed to wait for any pending write() to finish"); + "abort() is supposed to wait for any pending write() to finish"); } KJ_CASE_ONEOF(exception, kj::Exception) { // Already errored. @@ -2388,7 +2347,7 @@ kj::Promise IdentityTransformStreamImpl::readHelper(kj::ArrayPtr(); - state = ReadRequest { bytes, kj::mv(paf.fulfiller) }; + state = ReadRequest{bytes, kj::mv(paf.fulfiller)}; return kj::mv(paf.promise); } KJ_CASE_ONEOF(request, ReadRequest) { @@ -2433,7 +2392,7 @@ kj::Promise IdentityTransformStreamImpl::writeHelper(kj::ArrayPtr(); - state = WriteRequest { bytes, kj::mv(paf.fulfiller) }; + state = WriteRequest{bytes, kj::mv(paf.fulfiller)}; return kj::mv(paf.promise); } KJ_CASE_ONEOF(request, ReadRequest) { @@ -2474,7 +2433,7 @@ kj::Promise IdentityTransformStreamImpl::writeHelper(kj::ArrayPtrfulfill(request.bytes.size()); auto paf = kj::newPromiseAndFulfiller(); - state = WriteRequest { bytes, kj::mv(paf.fulfiller) }; + state = WriteRequest{bytes, kj::mv(paf.fulfiller)}; return kj::mv(paf.promise); } KJ_CASE_ONEOF(request, WriteRequest) { @@ -2492,32 +2451,29 @@ kj::Promise IdentityTransformStreamImpl::writeHelper(kj::ArrayPtr newReadableStreamInternalController( - IoContext& ioContext, - kj::Own source) { + IoContext& ioContext, kj::Own source) { return kj::heap(ioContext.addObject(kj::mv(source))); } -kj::Own newWritableStreamInternalController( - IoContext& ioContext, +kj::Own newWritableStreamInternalController(IoContext& ioContext, kj::Own sink, kj::Maybe maybeHighWaterMark, kj::Maybe> maybeClosureWaitable) { return kj::heap( - kj::mv(sink), - maybeHighWaterMark, - kj::mv(maybeClosureWaitable)); + kj::mv(sink), maybeHighWaterMark, kj::mv(maybeClosureWaitable)); } kj::StringPtr WritableStreamInternalController::jsgGetMemoryName() const { return "WritableStreamInternalController"_kjc; } -size_t WritableStreamInternalController::jsgGetMemorySelfSize() const { +size_t WritableStreamInternalController::jsgGetMemorySelfSize() const { return sizeof(WritableStreamInternalController); } void WritableStreamInternalController::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } KJ_CASE_ONEOF(errored, StreamStates::Errored) { tracker.trackField("error", errored); } @@ -2525,8 +2481,7 @@ void WritableStreamInternalController::jsgGetMemoryInfo(jsg::MemoryTracker& trac // Ideally we'd be able to track the size of any pending writes held in the sink's // queue but since it is behind an IoOwn and we won't be holding the IoContext here, // we can't. - tracker.trackFieldWithSize("IoOwn", - sizeof(IoOwn)); + tracker.trackFieldWithSize("IoOwn", sizeof(IoOwn)); } } KJ_IF_SOME(writerLocked, writeState.tryGet()) { @@ -2535,7 +2490,7 @@ void WritableStreamInternalController::jsgGetMemoryInfo(jsg::MemoryTracker& trac tracker.trackField("pendingAbort", maybePendingAbort); tracker.trackField("maybeClosureWaitable", maybeClosureWaitable); - for (auto& event : queue) { + for (auto& event: queue) { tracker.trackField("event", event); } } @@ -2562,7 +2517,8 @@ size_t ReadableStreamInternalController::jsgGetMemorySelfSize() const { void ReadableStreamInternalController::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } KJ_CASE_ONEOF(error, StreamStates::Errored) { tracker.trackField("error", error); } @@ -2570,13 +2526,15 @@ void ReadableStreamInternalController::jsgGetMemoryInfo(jsg::MemoryTracker& trac // Ideally we'd be able to track the size of any pending reads held in the source's // queue but since it is behind an IoOwn and we won't be holding the IoContext here, // we can't. - tracker.trackFieldWithSize("IoOwn", - sizeof(IoOwn)); + tracker.trackFieldWithSize( + "IoOwn", sizeof(IoOwn)); } } KJ_SWITCH_ONEOF(readState) { - KJ_CASE_ONEOF(unlocked, Unlocked) {} - KJ_CASE_ONEOF(locked, Locked) {} + KJ_CASE_ONEOF(unlocked, Unlocked) { + } + KJ_CASE_ONEOF(locked, Locked) { + } KJ_CASE_ONEOF(pipeLocked, PipeLocked) { tracker.trackField("pipeLocked", pipeLocked); } diff --git a/src/workerd/api/streams/internal.h b/src/workerd/api/streams/internal.h index 8cd5eb85940..cb759c2522e 100644 --- a/src/workerd/api/streams/internal.h +++ b/src/workerd/api/streams/internal.h @@ -35,12 +35,10 @@ class ReadableStreamInternalController: public ReadableStreamController { public: using Readable = IoOwn; - explicit ReadableStreamInternalController(StreamStates::Closed closed) - : state(closed) {} + explicit ReadableStreamInternalController(StreamStates::Closed closed): state(closed) {} explicit ReadableStreamInternalController(StreamStates::Errored errored) : state(kj::mv(errored)) {} - explicit ReadableStreamInternalController(Readable readable) - : state(kj::mv(readable)) {} + explicit ReadableStreamInternalController(Readable readable): state(kj::mv(readable)) {} KJ_DISALLOW_COPY_AND_MOVE(ReadableStreamInternalController); @@ -52,22 +50,22 @@ class ReadableStreamInternalController: public ReadableStreamController { jsg::Ref addRef() override; - bool isByteOriented() const override { return true; } + bool isByteOriented() const override { + return true; + } kj::Maybe> read( - jsg::Lock& js, - kj::Maybe byobOptions) override; + jsg::Lock& js, kj::Maybe byobOptions) override; - jsg::Promise pipeTo(jsg::Lock& js, - WritableStreamController& destination, - PipeToOptions options) override; + jsg::Promise pipeTo( + jsg::Lock& js, WritableStreamController& destination, PipeToOptions options) override; - jsg::Promise cancel(jsg::Lock& js, - jsg::Optional> reason) override; + jsg::Promise cancel(jsg::Lock& js, jsg::Optional> reason) override; Tee tee(jsg::Lock& js) override; - kj::Maybe> removeSource(jsg::Lock& js, bool ignoreDisturbed=false); + kj::Maybe> removeSource( + jsg::Lock& js, bool ignoreDisturbed = false); bool isClosedOrErrored() const override { return state.is() || state.is(); @@ -77,9 +75,13 @@ class ReadableStreamInternalController: public ReadableStreamController { return state.is(); } - bool isDisturbed() override { return disturbed; } + bool isDisturbed() override { + return disturbed; + } - bool isLockedToReader() const override { return !readState.is(); } + bool isLockedToReader() const override { + return !readState.is(); + } bool lockReader(jsg::Lock& js, Reader& reader) override; @@ -95,9 +97,8 @@ class ReadableStreamInternalController: public ReadableStreamController { kj::Maybe tryGetLength(StreamEncoding encoding) override; - kj::Promise> pumpTo(jsg::Lock& js, - kj::Own sink, - bool end) override; + kj::Promise> pumpTo( + jsg::Lock& js, kj::Own sink, bool end) override; StreamEncoding getPreferredEncoding() override; @@ -116,11 +117,9 @@ class ReadableStreamInternalController: public ReadableStreamController { void doClose(jsg::Lock& js); void doError(jsg::Lock& js, v8::Local reason); - class PipeLocked : public PipeController { + class PipeLocked: public PipeController { public: - PipeLocked( - ReadableStreamInternalController& inner, - jsg::Ref ref) + PipeLocked(ReadableStreamInternalController& inner, jsg::Ref ref) : inner(inner), ref(kj::mv(ref)) {} @@ -140,7 +139,9 @@ class ReadableStreamInternalController: public ReadableStreamController { jsg::Promise read(jsg::Lock& js) override; - void visitForGc(jsg::GcVisitor& visitor) { visitor.visit(ref); } + void visitForGc(jsg::GcVisitor& visitor) { + visitor.visit(ref); + } kj::StringPtr jsgGetMemoryName() const; size_t jsgGetMemorySelfSize() const; @@ -171,12 +172,11 @@ class WritableStreamInternalController: public WritableStreamController { struct Writable { kj::Own sink; kj::Canceler canceler; - Writable(kj::Own sink) : sink(kj::mv(sink)) {} + Writable(kj::Own sink): sink(kj::mv(sink)) {} void abort(kj::Exception&& ex); }; - explicit WritableStreamInternalController(StreamStates::Closed closed) - : state(closed) {} + explicit WritableStreamInternalController(StreamStates::Closed closed): state(closed) {} explicit WritableStreamInternalController(StreamStates::Errored errored) : state(kj::mv(errored)) {} explicit WritableStreamInternalController(kj::Own writable, @@ -184,8 +184,7 @@ class WritableStreamInternalController: public WritableStreamController { kj::Maybe> maybeClosureWaitable = kj::none) : state(IoContext::current().addObject(kj::heap(kj::mv(writable)))), maybeHighWaterMark(maybeHighWaterMark), - maybeClosureWaitable(kj::mv(maybeClosureWaitable)) { -} + maybeClosureWaitable(kj::mv(maybeClosureWaitable)) {} WritableStreamInternalController(WritableStreamInternalController&& other) = default; WritableStreamInternalController& operator=(WritableStreamInternalController&& other) = default; @@ -207,16 +206,16 @@ class WritableStreamInternalController: public WritableStreamController { jsg::Promise abort(jsg::Lock& js, jsg::Optional> reason) override; kj::Maybe> tryPipeFrom( - jsg::Lock& js, - jsg::Ref source, - PipeToOptions options) override; + jsg::Lock& js, jsg::Ref source, PipeToOptions options) override; kj::Maybe> removeSink(jsg::Lock& js) override; void detach(jsg::Lock& js) override; kj::Maybe getDesiredSize() override; - bool isLockedToWriter() const override { return !writeState.is(); } + bool isLockedToWriter() const override { + return !writeState.is(); + } bool lockWriter(jsg::Lock& js, Writer& writer) override; @@ -237,7 +236,9 @@ class WritableStreamInternalController: public WritableStreamController { bool isPiping(); bool isErrored() override; - inline bool isByteOriented() const override { return true; } + inline bool isByteOriented() const override { + return true; + } void setPendingClosure() override { isPendingClosure = true; @@ -246,19 +247,16 @@ class WritableStreamInternalController: public WritableStreamController { kj::StringPtr jsgGetMemoryName() const override; size_t jsgGetMemorySelfSize() const override; void jsgGetMemoryInfo(jsg::MemoryTracker& info) const override; -private: +private: struct AbortOptions { bool reject = false; bool handled = false; }; jsg::Promise doAbort(jsg::Lock& js, - v8::Local reason, - AbortOptions options = { - .reject = false, - .handled = false - }); + v8::Local reason, + AbortOptions options = {.reject = false, .handled = false}); void doClose(jsg::Lock& js); void doError(jsg::Lock& js, v8::Local reason); void ensureWriting(jsg::Lock& js); @@ -352,14 +350,21 @@ class WritableStreamInternalController: public WritableStreamController { JSG_MEMORY_INFO(WriteEvent) { if (outputLock != kj::none) { - tracker.trackFieldWithSize("outputLock", - sizeof(IoOwn>)); + tracker.trackFieldWithSize("outputLock", sizeof(IoOwn>)); } KJ_SWITCH_ONEOF(event) { - KJ_CASE_ONEOF(w, Write) { tracker.trackField("inner", w); } - KJ_CASE_ONEOF(p, Pipe) { tracker.trackField("inner", p); } - KJ_CASE_ONEOF(c, Close) { tracker.trackField("inner", c); } - KJ_CASE_ONEOF(f, Flush) { tracker.trackField("inner", f); } + KJ_CASE_ONEOF(w, Write) { + tracker.trackField("inner", w); + } + KJ_CASE_ONEOF(p, Pipe) { + tracker.trackField("inner", p); + } + KJ_CASE_ONEOF(c, Close) { + tracker.trackField("inner", c); + } + KJ_CASE_ONEOF(f, Flush) { + tracker.trackField("inner", f); + } } } }; @@ -378,8 +383,7 @@ class IdentityTransformStreamImpl: public kj::Refcounted, // TODO(soon): Reimplement this in terms of kj::OneWayPipe, so we can optimize pumpTo(). public: - explicit IdentityTransformStreamImpl(kj::Maybe limit = kj::none) - : limit(limit) {} + explicit IdentityTransformStreamImpl(kj::Maybe limit = kj::none): limit(limit) {} ~IdentityTransformStreamImpl() noexcept(false) { // Due to the different natures of JS and C++ disposal, there is no point in enforcing the limit diff --git a/src/workerd/api/streams/queue-test.c++ b/src/workerd/api/streams/queue-test.c++ index 56f1af65581..0f98b60fabf 100644 --- a/src/workerd/api/streams/queue-test.c++ +++ b/src/workerd/api/streams/queue-test.c++ @@ -19,11 +19,8 @@ JSG_DECLARE_ISOLATE_TYPE(QueueIsolate, QueueContext); void preamble(auto callback) { QueueIsolate isolate(v8System, kj::heap()); isolate.runInLockScope([&](QueueIsolate::Lock& lock) { - JSG_WITHIN_CONTEXT_SCOPE(lock, - lock.newContext().getHandle(lock), - [&](jsg::Lock& js) { - callback(js); - }); + JSG_WITHIN_CONTEXT_SCOPE(lock, lock.newContext().getHandle(lock), + [&](jsg::Lock& js) { callback(js); }); }); } @@ -47,7 +44,7 @@ struct MustNotCall; // the test to fail. // TODO(cleanup): Consider adding this to jsg-test.h -template +template struct MustCall { using Func = jsg::Function; Func fn; @@ -64,8 +61,8 @@ struct MustCall { auto unwindDetector = unwindDetectorMutex.lockExclusive(); if (!unwindDetector->isUnwinding()) { KJ_ASSERT(called == expected, - kj::str("MustCall function was not called ", expected, - " times. [actual: ", called , "]"), location); + kj::str("MustCall function was not called ", expected, " times. [actual: ", called, "]"), + location); } } @@ -75,30 +72,29 @@ struct MustCall { } }; -template +template struct MustNotCall { - MustNotCall(kj::SourceLocation location = kj::SourceLocation()) : location(location) {} + MustNotCall(kj::SourceLocation location = kj::SourceLocation()): location(location) {} kj::SourceLocation location; - Ret operator()(jsg::Lock&, Args...args) { + Ret operator()(jsg::Lock&, Args... args) { KJ_FAIL_REQUIRE("MustNotCall function was called!", location); } }; auto read(jsg::Lock& js, auto& consumer) { auto prp = js.newPromiseAndResolver(); - consumer.read(js, ValueQueue::ReadRequest { .resolver = kj::mv(prp.resolver) }); + consumer.read(js, ValueQueue::ReadRequest{.resolver = kj::mv(prp.resolver)}); return kj::mv(prp.promise); } auto byobRead(jsg::Lock& js, auto& consumer, int size) { auto prp = js.newPromiseAndResolver(); - consumer.read(js, ByteQueue::ReadRequest( - kj::mv(prp.resolver), - { - .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, size)), - .type = ByteQueue::ReadRequest::Type::BYOB, - } - )); + consumer.read(js, + ByteQueue::ReadRequest(kj::mv(prp.resolver), + { + .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, size)), + .type = ByteQueue::ReadRequest::Type::BYOB, + })); return kj::mv(prp.promise); }; @@ -172,7 +168,7 @@ KJ_TEST("ValueQueue with single consumer") { KJ_ASSERT(queue.desiredSize() == 0); auto prp = js.newPromiseAndResolver(); - consumer.read(js, ValueQueue::ReadRequest { .resolver = kj::mv(prp.resolver) }); + consumer.read(js, ValueQueue::ReadRequest{.resolver = kj::mv(prp.resolver)}); MustCall readContinuation([&](jsg::Lock& js, auto&& result) -> auto { KJ_ASSERT(!result.done); @@ -250,8 +246,7 @@ KJ_TEST("ValueQueue with multiple consumers") { return js.resolvedPromise(); }); - read(js, consumer1).then(js, read1Continuation) - .then(js, read2Continuation); + read(js, consumer1).then(js, read1Continuation).then(js, read2Continuation); js.runMicrotasks(); @@ -263,8 +258,7 @@ KJ_TEST("ValueQueue with multiple consumers") { KJ_ASSERT(queue.desiredSize() == 0); KJ_ASSERT(queue.size() == 0); - read(js, consumer1).then(js, close1Continuation) - .then(js, close2Continuation); + read(js, consumer1).then(js, close1Continuation).then(js, close2Continuation); js.runMicrotasks(); }); @@ -374,8 +368,7 @@ KJ_TEST("ByteQueue basics work") { KJ_ASSERT(queue.desiredSize() == 2); KJ_ASSERT(queue.size() == 0); - auto entry = kj::heap( - jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4))); + auto entry = kj::heap(jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4))); queue.push(js, kj::mv(entry)); @@ -387,8 +380,8 @@ KJ_TEST("ByteQueue basics work") { queue.close(js); try { - auto entry = kj::heap( - jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4))); + auto entry = + kj::heap(jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4))); queue.push(js, kj::mv(entry)); KJ_FAIL_ASSERT("The queue push after close should have failed."); } catch (kj::Exception& ex) { @@ -409,8 +402,8 @@ KJ_TEST("ByteQueue erroring works") { KJ_ASSERT(queue.desiredSize() == 0); try { - auto entry = kj::heap( - jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4))); + auto entry = + kj::heap(jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4))); queue.push(js, kj::mv(entry)); KJ_FAIL_ASSERT("The queue push after close should have failed."); } catch (kj::Exception& ex) { @@ -430,8 +423,7 @@ KJ_TEST("ByteQueue with single consumer") { auto store = jsg::BackingStore::alloc(js, 4); store.asArrayPtr().fill('a'); - auto entry = kj::heap( - jsg::BufferSource(js, kj::mv(store))); + auto entry = kj::heap(jsg::BufferSource(js, kj::mv(store))); queue.push(js, kj::mv(entry)); // The item was pushed into the consumer. @@ -442,12 +434,11 @@ KJ_TEST("ByteQueue with single consumer") { KJ_ASSERT(queue.desiredSize() == -2); auto prp = js.newPromiseAndResolver(); - consumer.read(js, ByteQueue::ReadRequest( - kj::mv(prp.resolver), - { - .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4)), - } - )); + consumer.read(js, + ByteQueue::ReadRequest(kj::mv(prp.resolver), + { + .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4)), + })); MustCall readContinuation([&](jsg::Lock& js, auto&& result) -> auto { KJ_ASSERT(!result.done); @@ -480,13 +471,12 @@ KJ_TEST("ByteQueue with single byob consumer") { ByteQueue::Consumer consumer(queue); auto prp = js.newPromiseAndResolver(); - consumer.read(js, ByteQueue::ReadRequest( - kj::mv(prp.resolver), - { - .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4)), - .type = ByteQueue::ReadRequest::Type::BYOB, - } - )); + consumer.read(js, + ByteQueue::ReadRequest(kj::mv(prp.resolver), + { + .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4)), + .type = ByteQueue::ReadRequest::Type::BYOB, + })); MustCall readContinuation([&](jsg::Lock& js, auto&& result) -> auto { KJ_ASSERT(!result.done); @@ -535,13 +525,12 @@ KJ_TEST("ByteQueue with byob consumer and default consumer") { ByteQueue::Consumer consumer2(queue); auto prp = js.newPromiseAndResolver(); - consumer1.read(js, ByteQueue::ReadRequest( - kj::mv(prp.resolver), - { - .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4)), - .type = ByteQueue::ReadRequest::Type::BYOB, - } - )); + consumer1.read(js, + ByteQueue::ReadRequest(kj::mv(prp.resolver), + { + .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4)), + .type = ByteQueue::ReadRequest::Type::BYOB, + })); MustCall readContinuation([&](jsg::Lock& js, auto&& result) -> auto { KJ_ASSERT(!result.done); @@ -602,13 +591,12 @@ KJ_TEST("ByteQueue with byob consumer and default consumer") { }); auto prp2 = js.newPromiseAndResolver(); - consumer2.read(js, ByteQueue::ReadRequest( - kj::mv(prp2.resolver), - { - .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4)), - .type = ByteQueue::ReadRequest::Type::DEFAULT, - } - )); + consumer2.read(js, + ByteQueue::ReadRequest(kj::mv(prp2.resolver), + { + .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 4)), + .type = ByteQueue::ReadRequest::Type::DEFAULT, + })); prp2.promise.then(js, read2Continuation); js.runMicrotasks(); @@ -779,8 +767,7 @@ KJ_TEST("ByteQueue with multiple byob consumers (multi-reads)") { // reads processed. byobRead(js, consumer1, 4).then(js, readConsumer1); byobRead(js, consumer1, 4).then(js, secondReadBothConsumers); - byobRead(js, consumer2, 4).then(js, readConsumer2) - .then(js, secondReadBothConsumers); + byobRead(js, consumer2, 4).then(js, readConsumer2).then(js, secondReadBothConsumers); // Although there are four distinct reads happening, // there should only be two actual BYOB requests @@ -858,8 +845,7 @@ KJ_TEST("ByteQueue with multiple byob consumers (multi-reads, 2)") { // All reads will be fulfilled correctly even tho there are only two BYOB reads // responded to. - byobRead(js, consumer2, 4).then(js, readConsumer2) - .then(js, secondReadBothConsumers); + byobRead(js, consumer2, 4).then(js, readConsumer2).then(js, secondReadBothConsumers); byobRead(js, consumer1, 4).then(js, readConsumer1); byobRead(js, consumer1, 4).then(js, secondReadBothConsumers); @@ -898,20 +884,18 @@ KJ_TEST("ByteQueue with default consumer with atLeast") { const auto read = [&](jsg::Lock& js, uint atLeast) { auto prp = js.newPromiseAndResolver(); - consumer.read(js, ByteQueue::ReadRequest( - kj::mv(prp.resolver), - { - .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 5)), - .atLeast = atLeast, - } - )); + consumer.read(js, + ByteQueue::ReadRequest(kj::mv(prp.resolver), + { + .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 5)), + .atLeast = atLeast, + })); return kj::mv(prp.promise); }; const auto push = [&](auto store) { try { - queue.push(js, kj::heap( - jsg::BufferSource(js, kj::mv(store)))); + queue.push(js, kj::heap(jsg::BufferSource(js, kj::mv(store)))); } catch (kj::Exception& ex) { KJ_DBG(ex.getDescription()); } @@ -945,8 +929,7 @@ KJ_TEST("ByteQueue with default consumer with atLeast") { return js.resolvedPromise(kj::mv(result)); }); - read(js, 5).then(js, readContinuation) - .then(js, read2Continuation); + read(js, 5).then(js, readContinuation).then(js, read2Continuation); auto store1 = jsg::BackingStore::alloc(js, 2); store1.asArrayPtr()[0] = 1; @@ -989,20 +972,18 @@ KJ_TEST("ByteQueue with multiple default consumers with atLeast (same rate)") { const auto read = [&](jsg::Lock& js, auto& consumer, uint atLeast = 1) { auto prp = js.newPromiseAndResolver(); - consumer.read(js, ByteQueue::ReadRequest( - kj::mv(prp.resolver), - { - .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 5)), - .atLeast = atLeast, - } - )); + consumer.read(js, + ByteQueue::ReadRequest(kj::mv(prp.resolver), + { + .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 5)), + .atLeast = atLeast, + })); return kj::mv(prp.promise); }; const auto push = [&](auto store) { try { - queue.push(js, kj::heap( - jsg::BufferSource(js, kj::mv(store)))); + queue.push(js, kj::heap(jsg::BufferSource(js, kj::mv(store)))); } catch (kj::Exception& ex) { KJ_DBG(ex.getDescription()); } @@ -1053,10 +1034,8 @@ KJ_TEST("ByteQueue with multiple default consumers with atLeast (same rate)") { return js.resolvedPromise(kj::mv(result)); }, 2); - read(js, consumer1, 5).then(js, read1Continuation) - .then(js, readFinalContinuation); - read(js, consumer2, 5).then(js, read2Continuation) - .then(js, readFinalContinuation); + read(js, consumer1, 5).then(js, read1Continuation).then(js, readFinalContinuation); + read(js, consumer2, 5).then(js, read2Continuation).then(js, readFinalContinuation); auto store1 = jsg::BackingStore::alloc(js, 2); store1.asArrayPtr()[0] = 1; @@ -1099,20 +1078,18 @@ KJ_TEST("ByteQueue with multiple default consumers with atLeast (different rate) const auto read = [&](jsg::Lock& js, auto& consumer, uint atLeast = 1) { auto prp = js.newPromiseAndResolver(); - consumer.read(js, ByteQueue::ReadRequest( - kj::mv(prp.resolver), - { - .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 5)), - .atLeast = atLeast, - } - )); + consumer.read(js, + ByteQueue::ReadRequest(kj::mv(prp.resolver), + { + .store = jsg::BufferSource(js, jsg::BackingStore::alloc(js, 5)), + .atLeast = atLeast, + })); return kj::mv(prp.promise); }; const auto push = [&](auto store) { try { - queue.push(js, kj::heap( - jsg::BufferSource(js, kj::mv(store)))); + queue.push(js, kj::heap(jsg::BufferSource(js, kj::mv(store)))); } catch (kj::Exception& ex) { KJ_DBG(ex.getDescription()); } @@ -1182,8 +1159,7 @@ KJ_TEST("ByteQueue with multiple default consumers with atLeast (different rate) read(js, consumer1).then(js, read1FinalContinuation); // Consumer 2 will read serially with a larger minimum chunk... - read(js, consumer2, 5).then(js, read2Continuation) - .then(js, read2FinalContinuation); + read(js, consumer2, 5).then(js, read2Continuation).then(js, read2FinalContinuation); auto store1 = jsg::BackingStore::alloc(js, 2); store1.asArrayPtr()[0] = 1; diff --git a/src/workerd/api/streams/queue.c++ b/src/workerd/api/streams/queue.c++ index d6ff0ebc4fe..2c9d4a7e648 100644 --- a/src/workerd/api/streams/queue.c++ +++ b/src/workerd/api/streams/queue.c++ @@ -14,11 +14,11 @@ namespace workerd::api { #pragma region ValueQueue::ReadRequest void ValueQueue::ReadRequest::resolveAsDone(jsg::Lock& js) { - resolver.resolve(js, ReadResult { .done = true }); + resolver.resolve(js, ReadResult{.done = true}); } void ValueQueue::ReadRequest::resolve(jsg::Lock& js, jsg::Value value) { - resolver.resolve(js, ReadResult { .value = kj::mv(value), .done = false }); + resolver.resolve(js, ReadResult{.value = kj::mv(value), .done = false}); } void ValueQueue::ReadRequest::reject(jsg::Lock& js, jsg::Value& value) { @@ -29,14 +29,15 @@ void ValueQueue::ReadRequest::reject(jsg::Lock& js, jsg::Value& value) { #pragma region ValueQueue::Entry -ValueQueue::Entry::Entry(jsg::Value value, size_t size) - : value(kj::mv(value)), size(size) {} +ValueQueue::Entry::Entry(jsg::Value value, size_t size): value(kj::mv(value)), size(size) {} jsg::Value ValueQueue::Entry::getValue(jsg::Lock& js) { return value.addRef(js); } -size_t ValueQueue::Entry::getSize() const { return size; } +size_t ValueQueue::Entry::getSize() const { + return size; +} void ValueQueue::Entry::visitForGc(jsg::GcVisitor& visitor) { visitor.visit(value); @@ -51,7 +52,7 @@ kj::Own ValueQueue::Entry::clone(jsg::Lock& js) { } ValueQueue::QueueEntry ValueQueue::QueueEntry::clone(jsg::Lock& js) { - return QueueEntry { .entry = entry->clone(js) }; + return QueueEntry{.entry = entry->clone(js)}; } #pragma endregion ValueQueue::QueueEntry @@ -59,24 +60,24 @@ ValueQueue::QueueEntry ValueQueue::QueueEntry::clone(jsg::Lock& js) { #pragma region ValueQueue::Consumer ValueQueue::Consumer::Consumer( - ValueQueue& queue, - kj::Maybe stateListener) + ValueQueue& queue, kj::Maybe stateListener) : impl(queue.impl, stateListener) {} ValueQueue::Consumer::Consumer( - QueueImpl& impl, - kj::Maybe stateListener) + QueueImpl& impl, kj::Maybe stateListener) : impl(impl, stateListener) {} -void ValueQueue::Consumer::cancel( - jsg::Lock& js, - jsg::Optional> maybeReason) { +void ValueQueue::Consumer::cancel(jsg::Lock& js, jsg::Optional> maybeReason) { impl.cancel(js, maybeReason); } -void ValueQueue::Consumer::close(jsg::Lock& js) { impl.close(js); }; +void ValueQueue::Consumer::close(jsg::Lock& js) { + impl.close(js); +}; -bool ValueQueue::Consumer::empty() { return impl.empty(); } +bool ValueQueue::Consumer::empty() { + return impl.empty(); +} void ValueQueue::Consumer::error(jsg::Lock& js, jsg::Value reason) { impl.error(js, kj::mv(reason)); @@ -90,13 +91,16 @@ void ValueQueue::Consumer::push(jsg::Lock& js, kj::Own entry) { impl.push(js, kj::mv(entry)); } -void ValueQueue::Consumer::reset() { impl.reset(); }; +void ValueQueue::Consumer::reset() { + impl.reset(); +}; -size_t ValueQueue::Consumer::size() { return impl.size(); } +size_t ValueQueue::Consumer::size() { + return impl.size(); +} kj::Own ValueQueue::Consumer::clone( - jsg::Lock& js, - kj::Maybe stateListener) { + jsg::Lock& js, kj::Maybe stateListener) { auto consumer = kj::heap(impl.queue, stateListener); impl.cloneTo(js, consumer->impl); return kj::mv(consumer); @@ -116,36 +120,39 @@ void ValueQueue::Consumer::visitForGc(jsg::GcVisitor& visitor) { #pragma endregion ValueQueue::Consumer -ValueQueue::ValueQueue(size_t highWaterMark) : impl(highWaterMark) {} +ValueQueue::ValueQueue(size_t highWaterMark): impl(highWaterMark) {} void ValueQueue::close(jsg::Lock& js) { impl.close(js); } -ssize_t ValueQueue::desiredSize() const { return impl.desiredSize(); } +ssize_t ValueQueue::desiredSize() const { + return impl.desiredSize(); +} void ValueQueue::error(jsg::Lock& js, jsg::Value reason) { impl.error(js, kj::mv(reason)); } -void ValueQueue::maybeUpdateBackpressure() { impl.maybeUpdateBackpressure(); } +void ValueQueue::maybeUpdateBackpressure() { + impl.maybeUpdateBackpressure(); +} void ValueQueue::push(jsg::Lock& js, kj::Own entry) { impl.push(js, kj::mv(entry)); } -size_t ValueQueue::size() const { return impl.size(); } +size_t ValueQueue::size() const { + return impl.size(); +} void ValueQueue::handlePush( - jsg::Lock& js, - ConsumerImpl::Ready& state, - QueueImpl& queue, - kj::Own entry) { + jsg::Lock& js, ConsumerImpl::Ready& state, QueueImpl& queue, kj::Own entry) { // If there are no pending reads, just add the entry to the buffer and return, adjusting // the size of the queue in the process. if (state.readRequests.empty()) { state.queueTotalSize += entry->getSize(); - state.buffer.push_back(QueueEntry { .entry = kj::mv(entry) }); + state.buffer.push_back(QueueEntry{.entry = kj::mv(entry)}); return; } @@ -155,8 +162,7 @@ void ValueQueue::handlePush( state.readRequests.pop_front(); } -void ValueQueue::handleRead( - jsg::Lock& js, +void ValueQueue::handleRead(jsg::Lock& js, ConsumerImpl::Ready& state, ConsumerImpl& consumer, QueueImpl& queue, @@ -166,7 +172,8 @@ void ValueQueue::handleRead( if (state.queueTotalSize > 0 && state.buffer.empty()) { // Is our queue accounting correct? LOG_WARNING_ONCE("ValueQueue::handleRead encountered a queueTotalSize > 0 " - "with an empty buffer. This should not happen.", state.queueTotalSize); + "with an empty buffer. This should not happen.", + state.queueTotalSize); } if (state.readRequests.empty() && !state.buffer.empty()) { auto& entry = state.buffer.front(); @@ -180,8 +187,10 @@ void ValueQueue::handleRead( // warning so we can investigate. // Note that we do not want to remove the close sentinel here so that the next call to // maybeDrainAndSetState will see it and handle the transition to the closed state. - KJ_LOG(ERROR, "ValueQueue::handleRead encountered a close sentinel in the queue " - "with queueTotalSize > 0. This should not happen.", state.queueTotalSize); + KJ_LOG(ERROR, + "ValueQueue::handleRead encountered a close sentinel in the queue " + "with queueTotalSize > 0. This should not happen.", + state.queueTotalSize); request.resolveAsDone(js); return; } @@ -210,16 +219,15 @@ void ValueQueue::handleRead( } bool ValueQueue::handleMaybeClose( - jsg::Lock&js, - ConsumerImpl::Ready& state, - ConsumerImpl& consumer, - QueueImpl& queue) { + jsg::Lock& js, ConsumerImpl::Ready& state, ConsumerImpl& consumer, QueueImpl& queue) { // If the value queue is not yet empty we have to keep waiting for more reads to consume it. // Return false to indicate that we cannot close yet. return false; } -size_t ValueQueue::getConsumerCount() { return impl.getConsumerCount(); } +size_t ValueQueue::getConsumerCount() { + return impl.getConsumerCount(); +} bool ValueQueue::wantsRead() const { return impl.wantsRead(); @@ -251,8 +259,7 @@ void maybeInvalidateByobRequest(kj::Maybe& req) { } // namespace ByteQueue::ReadRequest::ReadRequest( - jsg::Promise::Resolver resolver, - ByteQueue::ReadRequest::PullInto pullInto) + jsg::Promise::Resolver resolver, ByteQueue::ReadRequest::PullInto pullInto) : resolver(kj::mv(resolver)), pullInto(kj::mv(pullInto)) {} @@ -265,28 +272,20 @@ void ByteQueue::ReadRequest::resolveAsDone(jsg::Lock& js) { // There's been at least some data written, we need to respond but not // set done to true since that's what the streams spec requires. pullInto.store.trim(js, pullInto.store.size() - pullInto.filled); - resolver.resolve(js, ReadResult { - .value = js.v8Ref(pullInto.store.getHandle(js)), - .done = false - }); + resolver.resolve( + js, ReadResult{.value = js.v8Ref(pullInto.store.getHandle(js)), .done = false}); } else { // Otherwise, we set the length to zero pullInto.store.trim(js, pullInto.store.size()); KJ_ASSERT(pullInto.store.size() == 0); - resolver.resolve(js, ReadResult { - .value = js.v8Ref(pullInto.store.getHandle(js)), - .done = true - }); + resolver.resolve(js, ReadResult{.value = js.v8Ref(pullInto.store.getHandle(js)), .done = true}); } maybeInvalidateByobRequest(byobReadRequest); } void ByteQueue::ReadRequest::resolve(jsg::Lock& js) { pullInto.store.trim(js, pullInto.store.size() - pullInto.filled); - resolver.resolve(js, ReadResult { - .value = js.v8Ref(pullInto.store.getHandle(js)), - .done = false - }); + resolver.resolve(js, ReadResult{.value = js.v8Ref(pullInto.store.getHandle(js)), .done = false}); maybeInvalidateByobRequest(byobReadRequest); } @@ -296,8 +295,7 @@ void ByteQueue::ReadRequest::reject(jsg::Lock& js, jsg::Value& value) { } kj::Own ByteQueue::ReadRequest::makeByobReadRequest( - ConsumerImpl& consumer, - QueueImpl& queue) { + ConsumerImpl& consumer, QueueImpl& queue) { auto req = kj::heap(*this, consumer, queue); byobReadRequest = *req; return kj::mv(req); @@ -307,11 +305,15 @@ kj::Own ByteQueue::ReadRequest::makeByobReadRequest( #pragma region ByteQueue::Entry -ByteQueue::Entry::Entry(jsg::BufferSource store) : store(kj::mv(store)) {} +ByteQueue::Entry::Entry(jsg::BufferSource store): store(kj::mv(store)) {} -kj::ArrayPtr ByteQueue::Entry::toArrayPtr() { return store.asArrayPtr(); } +kj::ArrayPtr ByteQueue::Entry::toArrayPtr() { + return store.asArrayPtr(); +} -size_t ByteQueue::Entry::getSize() const { return store.size(); } +size_t ByteQueue::Entry::getSize() const { + return store.size(); +} kj::Own ByteQueue::Entry::clone(jsg::Lock& js) { return kj::heap(store.clone(js)); @@ -324,7 +326,7 @@ void ByteQueue::Entry::visitForGc(jsg::GcVisitor& visitor) {} #pragma region ByteQueue::QueueEntry ByteQueue::QueueEntry ByteQueue::QueueEntry::clone(jsg::Lock& js) { - return QueueEntry { + return QueueEntry{ .entry = entry->clone(js), .offset = offset, }; @@ -335,24 +337,24 @@ ByteQueue::QueueEntry ByteQueue::QueueEntry::clone(jsg::Lock& js) { #pragma region ByteQueue::Consumer ByteQueue::Consumer::Consumer( - ByteQueue& queue, - kj::Maybe stateListener) + ByteQueue& queue, kj::Maybe stateListener) : impl(queue.impl, stateListener) {} ByteQueue::Consumer::Consumer( - QueueImpl& impl, - kj::Maybe stateListener) + QueueImpl& impl, kj::Maybe stateListener) : impl(impl, stateListener) {} -void ByteQueue::Consumer::cancel( - jsg::Lock& js, - jsg::Optional> maybeReason) { +void ByteQueue::Consumer::cancel(jsg::Lock& js, jsg::Optional> maybeReason) { impl.cancel(js, maybeReason); } -void ByteQueue::Consumer::close(jsg::Lock& js) { impl.close(js); } +void ByteQueue::Consumer::close(jsg::Lock& js) { + impl.close(js); +} -bool ByteQueue::Consumer::empty() const { return impl.empty(); } +bool ByteQueue::Consumer::empty() const { + return impl.empty(); +} void ByteQueue::Consumer::error(jsg::Lock& js, jsg::Value reason) { impl.error(js, kj::mv(reason)); @@ -366,13 +368,16 @@ void ByteQueue::Consumer::push(jsg::Lock& js, kj::Own entry) { impl.push(js, kj::mv(entry)); } -void ByteQueue::Consumer::reset() { impl.reset(); } +void ByteQueue::Consumer::reset() { + impl.reset(); +} -size_t ByteQueue::Consumer::size() const { return impl.size(); } +size_t ByteQueue::Consumer::size() const { + return impl.size(); +} kj::Own ByteQueue::Consumer::clone( - jsg::Lock& js, - kj::Maybe stateListener) { + jsg::Lock& js, kj::Maybe stateListener) { auto consumer = kj::heap(impl.queue, stateListener); impl.cloneTo(js, consumer->impl); return kj::mv(consumer); @@ -406,9 +411,8 @@ void ByteQueue::ByobRequest::invalidate() { } bool ByteQueue::ByobRequest::isPartiallyFulfilled() { - return !isInvalidated() && - getRequest().pullInto.filled > 0 && - getRequest().pullInto.store.getElementSize() > 1; + return !isInvalidated() && getRequest().pullInto.filled > 0 && + getRequest().pullInto.store.getElementSize() > 1; } bool ByteQueue::ByobRequest::respond(jsg::Lock& js, size_t amount) { @@ -425,7 +429,7 @@ bool ByteQueue::ByobRequest::respond(jsg::Lock& js, size_t amount) { // The amount cannot be more than the total space in the request store. JSG_REQUIRE(req.pullInto.filled + amount <= req.pullInto.store.size(), RangeError, - kj::str("Too many bytes [", amount ,"] in response to a BYOB read request.")); + kj::str("Too many bytes [", amount, "] in response to a BYOB read request.")); auto sourcePtr = req.pullInto.store.asArrayPtr(); @@ -501,15 +505,12 @@ bool ByteQueue::ByobRequest::respondWithNewView(jsg::Lock& js, jsg::BufferSource auto amount = view.size(); JSG_REQUIRE(view.canDetach(js), TypeError, "Unable to use non-detachable ArrayBuffer."); - JSG_REQUIRE(req.pullInto.store.getOffset() + req.pullInto.filled == view.getOffset(), - RangeError, - "The given view has an invalid byte offset."); - JSG_REQUIRE(req.pullInto.store.size() == view.underlyingArrayBufferSize(js), - RangeError, - "The underlying ArrayBuffer is not the correct length."); - JSG_REQUIRE(req.pullInto.filled + amount <= req.pullInto.store.size(), - RangeError, - "The view is not the correct length."); + JSG_REQUIRE(req.pullInto.store.getOffset() + req.pullInto.filled == view.getOffset(), RangeError, + "The given view has an invalid byte offset."); + JSG_REQUIRE(req.pullInto.store.size() == view.underlyingArrayBufferSize(js), RangeError, + "The underlying ArrayBuffer is not the correct length."); + JSG_REQUIRE(req.pullInto.filled + amount <= req.pullInto.store.size(), RangeError, + "The view is not the correct length."); req.pullInto.store = jsg::BufferSource(js, view.detach(js)); return respond(js, amount); @@ -524,17 +525,17 @@ size_t ByteQueue::ByobRequest::getAtLeast() const { v8::Local ByteQueue::ByobRequest::getView(jsg::Lock& js) { KJ_IF_SOME(req, request) { - return req.pullInto.store.getTypedViewSlice(js, - req.pullInto.filled, - req.pullInto.store.size() - ).getHandle(js).As(); + return req.pullInto.store + .getTypedViewSlice(js, req.pullInto.filled, req.pullInto.store.size()) + .getHandle(js) + .As(); } return v8::Local(); } #pragma endregion ByteQueue::ByobRequest -ByteQueue::ByteQueue(size_t highWaterMark) : impl(highWaterMark) {} +ByteQueue::ByteQueue(size_t highWaterMark): impl(highWaterMark) {} void ByteQueue::close(jsg::Lock& js) { KJ_IF_SOME(ready, impl.state.tryGet()) { @@ -547,7 +548,9 @@ void ByteQueue::close(jsg::Lock& js) { impl.close(js); } -ssize_t ByteQueue::desiredSize() const { return impl.desiredSize(); } +ssize_t ByteQueue::desiredSize() const { + return impl.desiredSize(); +} void ByteQueue::error(jsg::Lock& js, jsg::Value reason) { impl.error(js, kj::mv(reason)); @@ -559,12 +562,8 @@ void ByteQueue::maybeUpdateBackpressure() { // take of them from time to time since. Since maybeUpdateBackpressure // is going to be called regularly while the queue is actively in use, // this is as good a place to clean them out as any. - auto pivot KJ_UNUSED = std::remove_if( - state.pendingByobReadRequests.begin(), - state.pendingByobReadRequests.end(), - [](auto& item) { - return item->isInvalidated(); - }); + auto pivot KJ_UNUSED = std::remove_if(state.pendingByobReadRequests.begin(), + state.pendingByobReadRequests.end(), [](auto& item) { return item->isInvalidated(); }); } impl.maybeUpdateBackpressure(); } @@ -573,16 +572,15 @@ void ByteQueue::push(jsg::Lock& js, kj::Own entry) { impl.push(js, kj::mv(entry)); } -size_t ByteQueue::size() const { return impl.size(); } +size_t ByteQueue::size() const { + return impl.size(); +} void ByteQueue::handlePush( - jsg::Lock& js, - ConsumerImpl::Ready& state, - QueueImpl& queue, - kj::Own newEntry) { + jsg::Lock& js, ConsumerImpl::Ready& state, QueueImpl& queue, kj::Own newEntry) { const auto bufferData = [&](size_t offset) { state.queueTotalSize += newEntry->getSize() - offset; - state.buffer.emplace_back(QueueEntry { + state.buffer.emplace_back(QueueEntry{ .entry = kj::mv(newEntry), .offset = offset, }); @@ -633,7 +631,7 @@ void ByteQueue::handlePush( auto sourceSize = sourcePtr.size() - entry.offset; auto destPtr = pending.pullInto.store.asArrayPtr().begin() + pending.pullInto.filled; - auto destAmount = pending.pullInto.store.size() - pending.pullInto.filled; + auto destAmount = pending.pullInto.store.size() - pending.pullInto.filled; // sourceSize is the amount of data remaining in the current entry to copy. // destAmount is the amount of space remaining to be filled in the pending read. @@ -675,8 +673,8 @@ void ByteQueue::handlePush( // destination pullInto by taking the lesser of amountAvailable and // destination pullInto size - filled (which gives us the amount of space // remaining in the destination). - auto amountToCopy = kj::min(amountAvailable, - pending.pullInto.store.size() - pending.pullInto.filled); + auto amountToCopy = + kj::min(amountAvailable, pending.pullInto.store.size() - pending.pullInto.filled); // The amountToCopy should not be more than the entry size minus the entryOffset // (which is the amount of data remaining to be consumed in the current entry). @@ -685,7 +683,7 @@ void ByteQueue::handlePush( // The amountToCopy plus pending.pullInto.filled should be more than or equal to atLeast // and less than or equal pending.pullInto.store.size(). KJ_REQUIRE(amountToCopy + pending.pullInto.filled >= pending.pullInto.atLeast && - amountToCopy + pending.pullInto.filled <= pending.pullInto.store.size()); + amountToCopy + pending.pullInto.filled <= pending.pullInto.store.size()); // Awesome, so now we safely copy amountToCopy bytes from the current entry into // the remaining space in pending.pullInto.store, befing careful to account for @@ -693,9 +691,8 @@ void ByteQueue::handlePush( // where we start copying. auto entryPtr = newEntry->toArrayPtr(); auto destPtr = pending.pullInto.store.asArrayPtr().begin() + pending.pullInto.filled; - std::copy(entryPtr.begin() + entryOffset, - entryPtr.begin() + entryOffset + amountToCopy, - destPtr); + std::copy( + entryPtr.begin() + entryOffset, entryPtr.begin() + entryOffset + amountToCopy, destPtr); // Yay! this pending read has been fulfilled. There might be more tho. Let's adjust // the amountAvailable and continue trying to consume data. @@ -724,8 +721,7 @@ void ByteQueue::handlePush( bufferData(entryOffset); } -void ByteQueue::handleRead( - jsg::Lock& js, +void ByteQueue::handleRead(jsg::Lock& js, ConsumerImpl::Ready& state, ConsumerImpl& consumer, QueueImpl& queue, @@ -764,8 +760,8 @@ void ByteQueue::handleRead( // The amount to copy is the lesser of the current entry size minus // offset and the data remaining in the destination to fill. auto entrySize = entry.entry->getSize(); - auto amountToCopy = kj::min(entrySize - entry.offset, - request.pullInto.store.size() - request.pullInto.filled); + auto amountToCopy = kj::min( + entrySize - entry.offset, request.pullInto.store.size() - request.pullInto.filled); auto elementSize = request.pullInto.store.getElementSize(); if (amountToCopy > elementSize) { amountToCopy -= amountToCopy % elementSize; @@ -861,10 +857,7 @@ void ByteQueue::handleRead( } bool ByteQueue::handleMaybeClose( - jsg::Lock&js, - ConsumerImpl::Ready& state, - ConsumerImpl& consumer, - QueueImpl& queue) { + jsg::Lock& js, ConsumerImpl::Ready& state, ConsumerImpl& consumer, QueueImpl& queue) { // This is called when we know that we are closing and we still have data in // the queue. We want to see if we can drain as much of it into pending reads // as possible. If we're able to drain all of it, then yay! We can go ahead and @@ -1047,10 +1040,12 @@ bool ByteQueue::wantsRead() const { return impl.wantsRead(); } -size_t ByteQueue::getConsumerCount() { return impl.getConsumerCount(); } +size_t ByteQueue::getConsumerCount() { + return impl.getConsumerCount(); +} void ByteQueue::visitForGc(jsg::GcVisitor& visitor) {} #pragma endregion ByteQueue -} // namespace workerd::api +} // namespace workerd::api diff --git a/src/workerd/api/streams/queue.h b/src/workerd/api/streams/queue.h index d3722a20e84..2533fc20621 100644 --- a/src/workerd/api/streams/queue.h +++ b/src/workerd/api/streams/queue.h @@ -151,7 +151,7 @@ class QueueImpl final { using Entry = typename Self::Entry; using State = typename Self::State; - explicit QueueImpl(size_t highWaterMark) : highWaterMark(highWaterMark) {} + explicit QueueImpl(size_t highWaterMark): highWaterMark(highWaterMark) {} QueueImpl(QueueImpl&&) = default; QueueImpl& operator=(QueueImpl&&) = default; @@ -163,7 +163,7 @@ class QueueImpl final { // We copy the list of consumers in case the consumers remove themselves // from the queue during the close callback, invalidating the iterator. auto consumers = ready.consumers; - for (auto consumer : consumers) { + for (auto consumer: consumers) { consumer->close(js); } state.template init(); @@ -187,7 +187,7 @@ class QueueImpl final { // We copy the list of consumers in case the consumers remove themselves // from the queue during the error callback, invalidating the iterator. auto consumers = ready.consumers; - for (auto consumer : consumers) { + for (auto consumer: consumers) { consumer->error(js, reason.addRef(js)); } state = kj::mv(reason); @@ -200,7 +200,7 @@ class QueueImpl final { void maybeUpdateBackpressure() { totalQueueSize = 0; KJ_IF_SOME(ready, state.template tryGet()) { - for (auto consumer : ready.consumers) { + for (auto consumer: ready.consumers) { totalQueueSize = kj::max(totalQueueSize, consumer->size()); } } @@ -211,13 +211,11 @@ class QueueImpl final { // If the entry type is byteOriented and has not been fully consumed by pending consume // operations, then any left over data will be pushed into the consumer's buffer. // Asserts if the queue is closed or errored. - void push(jsg::Lock& js, - kj::Own entry, - kj::Maybe skipConsumer = kj::none) { - auto& ready = KJ_REQUIRE_NONNULL(state.template tryGet(), - "The queue is closed or errored."); + void push(jsg::Lock& js, kj::Own entry, kj::Maybe skipConsumer = kj::none) { + auto& ready = + KJ_REQUIRE_NONNULL(state.template tryGet(), "The queue is closed or errored."); - for (auto consumer : ready.consumers) { + for (auto consumer: ready.consumers) { KJ_IF_SOME(skip, skipConsumer) { if (&skip == consumer) { continue; @@ -229,23 +227,35 @@ class QueueImpl final { } // The current size of consumer with the most stored data. - size_t size() const { return totalQueueSize; } + size_t size() const { + return totalQueueSize; + } size_t getConsumerCount() const { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, Closed) { return 0; } - KJ_CASE_ONEOF(errored, Errored) { return 0; } - KJ_CASE_ONEOF(ready, Ready) { return ready.consumers.size(); } + KJ_CASE_ONEOF(closed, Closed) { + return 0; + } + KJ_CASE_ONEOF(errored, Errored) { + return 0; + } + KJ_CASE_ONEOF(ready, Ready) { + return ready.consumers.size(); + } } KJ_UNREACHABLE; } bool wantsRead() const { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, Closed) { return false; } - KJ_CASE_ONEOF(errored, Errored) { return false; } + KJ_CASE_ONEOF(closed, Closed) { + return false; + } + KJ_CASE_ONEOF(errored, Errored) { + return false; + } KJ_CASE_ONEOF(ready, Ready) { - for (auto consumer : ready.consumers) { + for (auto consumer: ready.consumers) { if (consumer->hasReadRequests()) return true; } return false; @@ -313,7 +323,7 @@ class ConsumerImpl final { // updated. struct UpdateBackpressureScope final { QueueImpl& queue; - UpdateBackpressureScope(QueueImpl& queue) : queue(queue) {}; + UpdateBackpressureScope(QueueImpl& queue): queue(queue) {}; ~UpdateBackpressureScope() noexcept(false) { queue.maybeUpdateBackpressure(); } @@ -325,7 +335,8 @@ class ConsumerImpl final { using QueueEntry = typename Self::QueueEntry; ConsumerImpl(QueueImpl& queue, kj::Maybe stateListener = kj::none) - : queue(queue), stateListener(stateListener) { + : queue(queue), + stateListener(stateListener) { queue.addConsumer(this); } @@ -340,10 +351,12 @@ class ConsumerImpl final { void cancel(jsg::Lock& js, jsg::Optional> maybeReason) { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, Closed) {} - KJ_CASE_ONEOF(errored, Errored) {} + KJ_CASE_ONEOF(closed, Closed) { + } + KJ_CASE_ONEOF(errored, Errored) { + } KJ_CASE_ONEOF(ready, Ready) { - for (auto& request : ready.readRequests) { + for (auto& request: ready.readRequests) { request.resolveAsDone(js); } state.template init(); @@ -352,11 +365,11 @@ class ConsumerImpl final { } void close(jsg::Lock& js) { - // If we are already closed or errored, then we do nothing here. + // If we are already closed or errored, then we do nothing here. KJ_IF_SOME(ready, state.template tryGet()) { // If we are not already closing, enqueue a Close sentinel. if (!isClosing()) { - ready.buffer.push_back(Close {}); + ready.buffer.push_back(Close{}); } // Then check to see if we need to drain pending reads and @@ -365,7 +378,9 @@ class ConsumerImpl final { } } - inline bool empty() const { return size() == 0; } + inline bool empty() const { + return size() == 0; + } void error(jsg::Lock& js, jsg::Value reason) { // If we are already closed or errored, then we do nothing here. @@ -376,8 +391,8 @@ class ConsumerImpl final { } void push(jsg::Lock& js, kj::Own entry) { - auto& ready = KJ_REQUIRE_NONNULL(state.template tryGet(), - "The consumer is either closed or errored."); + auto& ready = KJ_REQUIRE_NONNULL( + state.template tryGet(), "The consumer is either closed or errored."); KJ_REQUIRE(!isClosing(), "The consumer is already closing."); // If the size of the entry is zero, do nothing. @@ -416,9 +431,15 @@ class ConsumerImpl final { // The current total calculated size of the consumer's internal buffer. size_t size() const { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(e, Errored) { return 0; } - KJ_CASE_ONEOF(c, Closed) { return 0; } - KJ_CASE_ONEOF(r, Ready) { return r.queueTotalSize; } + KJ_CASE_ONEOF(e, Errored) { + return 0; + } + KJ_CASE_ONEOF(c, Closed) { + return 0; + } + KJ_CASE_ONEOF(r, Ready) { + return r.queueTotalSize; + } } KJ_UNREACHABLE; } @@ -455,7 +476,7 @@ class ConsumerImpl final { for (auto& item: ready.buffer) { KJ_SWITCH_ONEOF(item) { KJ_CASE_ONEOF(c, Close) { - otherReady.buffer.push_back(Close {}); + otherReady.buffer.push_back(Close{}); } KJ_CASE_ONEOF(entry, QueueEntry) { otherReady.buffer.push_back(entry.clone(js)); @@ -468,8 +489,12 @@ class ConsumerImpl final { bool hasReadRequests() const { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, Closed) { return false; } - KJ_CASE_ONEOF(errored, Errored) { return false; } + KJ_CASE_ONEOF(closed, Closed) { + return false; + } + KJ_CASE_ONEOF(errored, Errored) { + return false; + } KJ_CASE_ONEOF(ready, Ready) { return !ready.readRequests.empty(); } @@ -479,10 +504,12 @@ class ConsumerImpl final { void cancelPendingReads(jsg::Lock& js, jsg::JsValue reason) { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, Closed) {} - KJ_CASE_ONEOF(errored, Errored) {} + KJ_CASE_ONEOF(closed, Closed) { + } + KJ_CASE_ONEOF(errored, Errored) { + } KJ_CASE_ONEOF(ready, Ready) { - for (auto& request : ready.readRequests) { + for (auto& request: ready.readRequests) { request.resolver.reject(js, reason); } ready.readRequests.clear(); @@ -492,19 +519,20 @@ class ConsumerImpl final { void visitForGc(jsg::GcVisitor& visitor) { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, Closed) {} + KJ_CASE_ONEOF(closed, Closed) { + } KJ_CASE_ONEOF(errored, Errored) { // Technically we shouldn't really have to gc visit the stored error here but there // should not be any harm in doing so. visitor.visit(errored); } KJ_CASE_ONEOF(ready, Ready) { - // There's no reason to gc visit the promise resolver or buffer here and it is - // potentially problematic if we do. Since the read requests are queued, if we - // gc visit it once, remove it from the queue, and gc happens to kick in before - // we access the resolver, then v8 could determine that the resolver or buffered - // entries are no longer reachable via tracing and free them before we can - // actually try to access the held resolver. + // There's no reason to gc visit the promise resolver or buffer here and it is + // potentially problematic if we do. Since the read requests are queued, if we + // gc visit it once, remove it from the queue, and gc happens to kick in before + // we access the resolver, then v8 could determine that the resolver or buffered + // entries are no longer reachable via tracing and free them before we can + // actually try to access the held resolver. } } } @@ -537,8 +565,12 @@ class ConsumerImpl final { // Closing state is determined by whether there is a Close sentinel that has been // pushed into the end of Ready state buffer. KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(c, Closed) { return false; } - KJ_CASE_ONEOF(e, Errored) { return false; } + KJ_CASE_ONEOF(c, Closed) { + return false; + } + KJ_CASE_ONEOF(e, Errored) { + return false; + } KJ_CASE_ONEOF(r, Ready) { if (r.buffer.empty()) { return false; @@ -557,7 +589,7 @@ class ConsumerImpl final { // If maybeReason != nullptr, then we are draining because of an error. // In that case, we want to reset/clear the buffer and reject any remaining // pending read requests using the given reason. - for (auto& request : ready.readRequests) { + for (auto& request: ready.readRequests) { request.reject(js, reason); } state = reason.addRef(js); @@ -575,13 +607,13 @@ class ConsumerImpl final { // if it can drain the remaining data into pending reads. If handleMaybeClose // returns false, then it could not and we can't yet close. If it returns true, // yay! Our queue is empty and we can continue closing down. - KJ_ASSERT(!empty()); // We're still not empty + KJ_ASSERT(!empty()); // We're still not empty return; } KJ_ASSERT(empty()); - KJ_REQUIRE(ready.buffer.size() == 1); // The close should be the only item remaining. - for (auto& request : ready.readRequests) { + KJ_REQUIRE(ready.buffer.size() == 1); // The close should be the only item remaining. + for (auto& request: ready.readRequests) { request.resolveAsDone(js); } state.template init(); @@ -682,8 +714,8 @@ class ValueQueue final { size_t size(); - kj::Own clone(jsg::Lock& js, - kj::Maybe stateListener = kj::none); + kj::Own clone( + jsg::Lock& js, kj::Maybe stateListener = kj::none); bool hasReadRequests(); void cancelPendingReads(jsg::Lock& js, jsg::JsValue reason); @@ -729,19 +761,15 @@ class ValueQueue final { private: QueueImpl impl; - static void handlePush(jsg::Lock& js, - ConsumerImpl::Ready& state, - QueueImpl& queue, - kj::Own entry); + static void handlePush( + jsg::Lock& js, ConsumerImpl::Ready& state, QueueImpl& queue, kj::Own entry); static void handleRead(jsg::Lock& js, - ConsumerImpl::Ready& state, - ConsumerImpl& consumer, - QueueImpl& queue, - ReadRequest request); - static bool handleMaybeClose(jsg::Lock& js, - ConsumerImpl::Ready& state, - ConsumerImpl& consumer, - QueueImpl& queue); + ConsumerImpl::Ready& state, + ConsumerImpl& consumer, + QueueImpl& queue, + ReadRequest request); + static bool handleMaybeClose( + jsg::Lock& js, ConsumerImpl::Ready& state, ConsumerImpl& consumer, QueueImpl& queue); friend ConsumerImpl; }; @@ -749,7 +777,6 @@ class ValueQueue final { // ============================================================================ // Byte queue - class ByteQueue final { public: using ConsumerImpl = ConsumerImpl; @@ -776,8 +803,7 @@ class ByteQueue final { } } pullInto; - ReadRequest(jsg::Promise::Resolver resolver, - PullInto pullInto); + ReadRequest(jsg::Promise::Resolver resolver, PullInto pullInto); ReadRequest(ReadRequest&&) = default; ReadRequest& operator=(ReadRequest&&) = default; ~ReadRequest() noexcept(false); @@ -801,10 +827,7 @@ class ByteQueue final { // the ByobRequest is no longer usable and should be discarded. class ByobRequest final { public: - ByobRequest( - ReadRequest& request, - ConsumerImpl& consumer, - QueueImpl& queue) + ByobRequest(ReadRequest& request, ConsumerImpl& consumer, QueueImpl& queue) : request(request), consumer(consumer), queue(queue) {} @@ -813,7 +836,9 @@ class ByteQueue final { ~ByobRequest() noexcept(false); - inline ReadRequest& getRequest() { return KJ_ASSERT_NONNULL(request); } + inline ReadRequest& getRequest() { + return KJ_ASSERT_NONNULL(request); + } bool respond(jsg::Lock& js, size_t amount); @@ -823,7 +848,9 @@ class ByteQueue final { // The term "invalidate" is adopted from the streams spec for handling BYOB requests. void invalidate(); - inline bool isInvalidated() const { return request == kj::none; } + inline bool isInvalidated() const { + return request == kj::none; + } bool isPartiallyFulfilled(); @@ -843,7 +870,7 @@ class ByteQueue final { std::deque> pendingByobReadRequests; JSG_MEMORY_INFO(ByteQueue::State) { - for (auto& request : pendingByobReadRequests) { + for (auto& request: pendingByobReadRequests) { tracker.trackField("pendingByobReadRequest", request); } } @@ -907,8 +934,8 @@ class ByteQueue final { size_t size() const; - kj::Own clone(jsg::Lock& js, - kj::Maybe stateListener = kj::none); + kj::Own clone( + jsg::Lock& js, kj::Maybe stateListener = kj::none); bool hasReadRequests(); void cancelPendingReads(jsg::Lock& js, jsg::JsValue reason); @@ -961,19 +988,15 @@ class ByteQueue final { private: QueueImpl impl; - static void handlePush(jsg::Lock& js, - ConsumerImpl::Ready& state, - QueueImpl& queue, - kj::Own entry); + static void handlePush( + jsg::Lock& js, ConsumerImpl::Ready& state, QueueImpl& queue, kj::Own entry); static void handleRead(jsg::Lock& js, - ConsumerImpl::Ready& state, - ConsumerImpl& consumer, - QueueImpl& queue, - ReadRequest request); - static bool handleMaybeClose(jsg::Lock& js, - ConsumerImpl::Ready& state, - ConsumerImpl& consumer, - QueueImpl& queue); + ConsumerImpl::Ready& state, + ConsumerImpl& consumer, + QueueImpl& queue, + ReadRequest request); + static bool handleMaybeClose( + jsg::Lock& js, ConsumerImpl::Ready& state, ConsumerImpl& consumer, QueueImpl& queue); friend ConsumerImpl; friend class Consumer; @@ -992,8 +1015,10 @@ size_t QueueImpl::jsgGetMemorySelfSize() const { template void QueueImpl::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(ready, Ready) {} - KJ_CASE_ONEOF(closed, Closed) {} + KJ_CASE_ONEOF(ready, Ready) { + } + KJ_CASE_ONEOF(closed, Closed) { + } KJ_CASE_ONEOF(errored, Errored) { tracker.trackField("error", errored); } @@ -1013,7 +1038,8 @@ size_t ConsumerImpl::jsgGetMemorySelfSize() const { template void ConsumerImpl::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(close, Closed) {} + KJ_CASE_ONEOF(close, Closed) { + } KJ_CASE_ONEOF(error, Errored) { tracker.trackField("error", error); } @@ -1035,7 +1061,7 @@ size_t ConsumerImpl::Ready::jsgGetMemorySelfSize() const { template void ConsumerImpl::Ready::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { - for (auto& entry : buffer) { + for (auto& entry: buffer) { KJ_SWITCH_ONEOF(entry) { KJ_CASE_ONEOF(c, Close) { tracker.trackFieldWithSize("pendingClose", sizeof(Close)); @@ -1046,7 +1072,7 @@ void ConsumerImpl::Ready::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) co } } - for (auto& request : readRequests) { + for (auto& request: readRequests) { tracker.trackField("pendingRead", request); } } @@ -1099,4 +1125,4 @@ void ByteQueue::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { tracker.trackField("impl", impl); } -} // workerd::api +} // namespace workerd::api diff --git a/src/workerd/api/streams/readable.c++ b/src/workerd/api/streams/readable.c++ index c0a85e26686..a0be942a0b6 100644 --- a/src/workerd/api/streams/readable.c++ +++ b/src/workerd/api/streams/readable.c++ @@ -12,9 +12,9 @@ namespace workerd::api { -ReaderImpl::ReaderImpl(ReadableStreamController::Reader& reader) : - ioContext(tryGetIoContext()), - reader(reader) {} +ReaderImpl::ReaderImpl(ReadableStreamController::Reader& reader) + : ioContext(tryGetIoContext()), + reader(reader) {} ReaderImpl::~ReaderImpl() noexcept(false) { KJ_IF_SOME(stream, state.tryGet()) { @@ -51,8 +51,7 @@ void ReaderImpl::detach() { } jsg::Promise ReaderImpl::cancel( - jsg::Lock& js, - jsg::Optional> maybeReason) { + jsg::Lock& js, jsg::Optional> maybeReason) { KJ_SWITCH_ONEOF(state) { KJ_CASE_ONEOF(i, Initial) { KJ_FAIL_ASSERT("this reader was never attached"); @@ -88,8 +87,7 @@ void ReaderImpl::lockToStream(jsg::Lock& js, ReadableStream& stream) { } jsg::Promise ReaderImpl::read( - jsg::Lock& js, - kj::Maybe byobOptions) { + jsg::Lock& js, kj::Maybe byobOptions) { KJ_SWITCH_ONEOF(state) { KJ_CASE_ONEOF(i, Initial) { KJ_FAIL_ASSERT("this reader was never attached"); @@ -101,20 +99,16 @@ jsg::Promise ReaderImpl::read( if (options.byteLength == 0) { return js.rejectedPromise( - js.v8TypeError( - "You must call read() on a \"byob\" reader with a positive-sized " - "TypedArray object."_kj)); + js.v8TypeError("You must call read() on a \"byob\" reader with a positive-sized " + "TypedArray object."_kj)); } if (atLeast == 0) { - return js.rejectedPromise( - js.v8TypeError(kj::str( - "Requested invalid minimum number of bytes to read (", atLeast, ")."))); + return js.rejectedPromise(js.v8TypeError( + kj::str("Requested invalid minimum number of bytes to read (", atLeast, ")."))); } if (atLeast > options.byteLength) { - return js.rejectedPromise( - js.v8TypeError(kj::str( - "Minimum bytes to read (", atLeast, - ") exceeds size of buffer (", options.byteLength, ")."))); + return js.rejectedPromise(js.v8TypeError(kj::str("Minimum bytes to read (", + atLeast, ") exceeds size of buffer (", options.byteLength, ")."))); } jsg::BufferSource source(js, options.bufferView.getHandle(js)); @@ -173,27 +167,24 @@ void ReaderImpl::visitForGc(jsg::GcVisitor& visitor) { // ====================================================================================== -ReadableStreamDefaultReader::ReadableStreamDefaultReader() : impl(*this) {} +ReadableStreamDefaultReader::ReadableStreamDefaultReader(): impl(*this) {} jsg::Ref ReadableStreamDefaultReader::constructor( - jsg::Lock& js, - jsg::Ref stream) { - JSG_REQUIRE(!stream->isLocked(), TypeError, - "This ReadableStream is currently locked to a reader."); + jsg::Lock& js, jsg::Ref stream) { + JSG_REQUIRE( + !stream->isLocked(), TypeError, "This ReadableStream is currently locked to a reader."); auto reader = jsg::alloc(); reader->lockToStream(js, *stream); return kj::mv(reader); } void ReadableStreamDefaultReader::attach( - ReadableStreamController& controller, - jsg::Promise closedPromise){ + ReadableStreamController& controller, jsg::Promise closedPromise) { impl.attach(controller, kj::mv(closedPromise)); } jsg::Promise ReadableStreamDefaultReader::cancel( - jsg::Lock& js, - jsg::Optional> maybeReason) { + jsg::Lock& js, jsg::Optional> maybeReason) { return impl.cancel(js, kj::mv(maybeReason)); } @@ -223,17 +214,16 @@ void ReadableStreamDefaultReader::visitForGc(jsg::GcVisitor& visitor) { // ====================================================================================== -ReadableStreamBYOBReader::ReadableStreamBYOBReader() : impl(*this) {} +ReadableStreamBYOBReader::ReadableStreamBYOBReader(): impl(*this) {} jsg::Ref ReadableStreamBYOBReader::constructor( - jsg::Lock& js, - jsg::Ref stream) { - JSG_REQUIRE(!stream->isLocked(), TypeError, - "This ReadableStream is currently locked to a reader."); + jsg::Lock& js, jsg::Ref stream) { + JSG_REQUIRE( + !stream->isLocked(), TypeError, "This ReadableStream is currently locked to a reader."); if (!stream->getController().isClosedOrErrored()) { JSG_REQUIRE(stream->getController().isByteOriented(), TypeError, - "This ReadableStream does not support BYOB reads."); + "This ReadableStream does not support BYOB reads."); } auto reader = jsg::alloc(); @@ -242,14 +232,12 @@ jsg::Ref ReadableStreamBYOBReader::constructor( } void ReadableStreamBYOBReader::attach( - ReadableStreamController& controller, - jsg::Promise closedPromise) { + ReadableStreamController& controller, jsg::Promise closedPromise) { impl.attach(controller, kj::mv(closedPromise)); } jsg::Promise ReadableStreamBYOBReader::cancel( - jsg::Lock& js, - jsg::Optional> maybeReason) { + jsg::Lock& js, jsg::Optional> maybeReason) { return impl.cancel(js, kj::mv(maybeReason)); } @@ -265,12 +253,11 @@ void ReadableStreamBYOBReader::lockToStream(jsg::Lock& js, ReadableStream& strea impl.lockToStream(js, stream); } -jsg::Promise ReadableStreamBYOBReader::read( - jsg::Lock& js, +jsg::Promise ReadableStreamBYOBReader::read(jsg::Lock& js, v8::Local byobBuffer, jsg::Optional maybeOptions) { - static const ReadableStreamBYOBReaderReadOptions defaultOptions {}; - auto options = ReadableStreamController::ByobOptions { + static const ReadableStreamBYOBReaderReadOptions defaultOptions{}; + auto options = ReadableStreamController::ByobOptions{ .bufferView = js.v8Ref(byobBuffer), .byteOffset = byobBuffer->ByteOffset(), .byteLength = byobBuffer->ByteLength(), @@ -281,10 +268,8 @@ jsg::Promise ReadableStreamBYOBReader::read( } jsg::Promise ReadableStreamBYOBReader::readAtLeast( - jsg::Lock& js, - int minBytes, - v8::Local byobBuffer) { - auto options = ReadableStreamController::ByobOptions { + jsg::Lock& js, int minBytes, v8::Local byobBuffer) { + auto options = ReadableStreamController::ByobOptions{ .bufferView = js.v8Ref(byobBuffer), .byteOffset = byobBuffer->ByteOffset(), .byteLength = byobBuffer->ByteLength(), @@ -304,9 +289,7 @@ void ReadableStreamBYOBReader::visitForGc(jsg::GcVisitor& visitor) { // ====================================================================================== -ReadableStream::ReadableStream( - IoContext& ioContext, - kj::Own source) +ReadableStream::ReadableStream(IoContext& ioContext, kj::Own source) : ReadableStream(newReadableStreamInternalController(ioContext, kj::mv(source))) {} ReadableStream::ReadableStream(kj::Own controller) @@ -323,11 +306,17 @@ void ReadableStream::visitForGc(jsg::GcVisitor& visitor) { } } -jsg::Ref ReadableStream::addRef() { return JSG_THIS; } +jsg::Ref ReadableStream::addRef() { + return JSG_THIS; +} -bool ReadableStream::isDisturbed() { return getController().isDisturbed(); } +bool ReadableStream::isDisturbed() { + return getController().isDisturbed(); +} -bool ReadableStream::isLocked() { return getController().isLockedToReader(); } +bool ReadableStream::isLocked() { + return getController().isLockedToReader(); +} jsg::Promise ReadableStream::onEof(jsg::Lock& js) { eofResolverPair = js.newPromiseAndResolver(); @@ -345,8 +334,7 @@ ReadableStreamController& ReadableStream::getController() { } jsg::Promise ReadableStream::cancel( - jsg::Lock& js, - jsg::Optional> maybeReason) { + jsg::Lock& js, jsg::Optional> maybeReason) { if (isLocked()) { return js.rejectedPromise( js.v8TypeError("This ReadableStream is currently locked to a reader."_kj)); @@ -355,15 +343,14 @@ jsg::Promise ReadableStream::cancel( } ReadableStream::Reader ReadableStream::getReader( - jsg::Lock& js, - jsg::Optional options) { + jsg::Lock& js, jsg::Optional options) { JSG_REQUIRE(!isLocked(), TypeError, "This ReadableStream is currently locked to a reader."); bool isByob = false; KJ_IF_SOME(o, options) { KJ_IF_SOME(mode, o.mode) { - JSG_REQUIRE(mode == "byob", RangeError, - "mode must be undefined or 'byob' in call to getReader()."); + JSG_REQUIRE( + mode == "byob", RangeError, "mode must be undefined or 'byob' in call to getReader()."); // No need to check that the ReadableStream implementation is a byte stream: the first // invocation of read() will do that for us and throw if necessary. Also, we should really // just support reading non-byte streams with BYOB readers. @@ -378,41 +365,37 @@ ReadableStream::Reader ReadableStream::getReader( } jsg::Ref ReadableStream::values( - jsg::Lock& js, - jsg::Optional options) { - static const auto defaultOptions = ValuesOptions {}; - return jsg::alloc(AsyncIteratorState { - .ioContext = ioContext, + jsg::Lock& js, jsg::Optional options) { + static const auto defaultOptions = ValuesOptions{}; + return jsg::alloc(AsyncIteratorState{.ioContext = ioContext, .reader = ReadableStreamDefaultReader::constructor(js, JSG_THIS), - .preventCancel = options.orDefault(defaultOptions).preventCancel.orDefault(false) - }); + .preventCancel = options.orDefault(defaultOptions).preventCancel.orDefault(false)}); } jsg::Ref ReadableStream::pipeThrough( - jsg::Lock& js, - Transform transform, - jsg::Optional maybeOptions) { + jsg::Lock& js, Transform transform, jsg::Optional maybeOptions) { auto& controller = getController(); auto& destination = transform.writable->getController(); - JSG_REQUIRE(!isLocked(), TypeError, - "This ReadableStream is currently locked to a reader."); + JSG_REQUIRE(!isLocked(), TypeError, "This ReadableStream is currently locked to a reader."); JSG_REQUIRE(!destination.isLockedToWriter(), TypeError, - "This WritableStream is currently locked to a writer."); + "This WritableStream is currently locked to a writer."); auto options = kj::mv(maybeOptions).orDefault({}); options.pipeThrough = true; - controller.pipeTo(js, destination, kj::mv(options)).then(js, - JSG_VISITABLE_LAMBDA((self = JSG_THIS), (self), (jsg::Lock& js) { - return js.resolvedPromise(); - }), JSG_VISITABLE_LAMBDA((self = JSG_THIS), (self), (jsg::Lock& js, auto&& exception) { - return js.rejectedPromise(kj::mv(exception)); - })).markAsHandled(js); + controller.pipeTo(js, destination, kj::mv(options)) + .then(js, + JSG_VISITABLE_LAMBDA( + (self = JSG_THIS), (self), (jsg::Lock& js) { return js.resolvedPromise(); }), + JSG_VISITABLE_LAMBDA((self = JSG_THIS), (self), + (jsg::Lock& js, auto&& exception) { + return js.rejectedPromise(kj::mv(exception)); + })) + .markAsHandled(js); return kj::mv(transform.readable); } -jsg::Promise ReadableStream::pipeTo( - jsg::Lock& js, +jsg::Promise ReadableStream::pipeTo(jsg::Lock& js, jsg::Ref destination, jsg::Optional maybeOptions) { if (isLocked()) { @@ -452,10 +435,9 @@ jsg::Optional ReadableStream::inspectLength() { } jsg::Promise> ReadableStream::nextFunction( - jsg::Lock& js, - AsyncIteratorState& state) { - return state.reader->read(js).then(js, - [reader = state.reader.addRef()](jsg::Lock& js, ReadResult result) mutable { + jsg::Lock& js, AsyncIteratorState& state) { + return state.reader->read(js).then( + js, [reader = state.reader.addRef()](jsg::Lock& js, ReadResult result) mutable { if (result.done) { reader->releaseLock(js); return js.resolvedPromise(kj::Maybe(kj::none)); @@ -465,21 +447,17 @@ jsg::Promise> ReadableStream::nextFunction( } jsg::Promise ReadableStream::returnFunction( - jsg::Lock& js, - AsyncIteratorState& state, - jsg::Optional value) { + jsg::Lock& js, AsyncIteratorState& state, jsg::Optional value) { if (state.reader.get() != nullptr) { auto reader = kj::mv(state.reader); if (!state.preventCancel) { - auto promise = reader->cancel(js, value.map([&](jsg::Value& v) { - return v.getHandle(js); - })); + auto promise = reader->cancel(js, value.map([&](jsg::Value& v) { return v.getHandle(js); })); reader->releaseLock(js); - return promise.then(js, JSG_VISITABLE_LAMBDA((reader = kj::mv(reader)), - (reader), (jsg::Lock& js) { - // Ensure that the reader is not garbage collected until the cancel promise resolves. - return js.resolvedPromise(); - })); + return promise.then(js, + JSG_VISITABLE_LAMBDA((reader = kj::mv(reader)), (reader), (jsg::Lock& js) { + // Ensure that the reader is not garbage collected until the cancel promise resolves. + return js.resolvedPromise(); + })); } reader->releaseLock(js); @@ -488,7 +466,8 @@ jsg::Promise ReadableStream::returnFunction( } jsg::Ref ReadableStream::detach(jsg::Lock& js, bool ignoreDisturbed) { - JSG_REQUIRE(!isDisturbed() || ignoreDisturbed, TypeError, "The ReadableStream has already been read."); + JSG_REQUIRE( + !isDisturbed() || ignoreDisturbed, TypeError, "The ReadableStream has already been read."); JSG_REQUIRE(!isLocked(), TypeError, "The ReadableStream has been locked to a reader."); return jsg::alloc(getController().detach(js, ignoreDisturbed)); } @@ -498,25 +477,21 @@ kj::Maybe ReadableStream::tryGetLength(StreamEncoding encoding) { } kj::Promise> ReadableStream::pumpTo( - jsg::Lock& js, - kj::Own sink, - bool end) { - JSG_REQUIRE(IoContext::hasCurrent(), Error, - "Unable to consume this ReadableStream outside of a request"); + jsg::Lock& js, kj::Own sink, bool end) { + JSG_REQUIRE( + IoContext::hasCurrent(), Error, "Unable to consume this ReadableStream outside of a request"); JSG_REQUIRE(!isLocked(), TypeError, "The ReadableStream has been locked to a reader."); return getController().pumpTo(js, kj::mv(sink), end); } -jsg::Ref ReadableStream::constructor( - jsg::Lock& js, +jsg::Ref ReadableStream::constructor(jsg::Lock& js, jsg::Optional underlyingSource, jsg::Optional queuingStrategy) { - JSG_REQUIRE(FeatureFlags::get(js).getStreamsJavaScriptControllers(), - Error, - "To use the new ReadableStream() constructor, enable the " - "streams_enable_constructors compatibility flag. " - "Refer to the docs for more information: https://developers.cloudflare.com/workers/platform/compatibility-dates/#compatibility-flags"); + JSG_REQUIRE(FeatureFlags::get(js).getStreamsJavaScriptControllers(), Error, + "To use the new ReadableStream() constructor, enable the " + "streams_enable_constructors compatibility flag. " + "Refer to the docs for more information: https://developers.cloudflare.com/workers/platform/compatibility-dates/#compatibility-flags"); auto stream = jsg::alloc(newReadableStreamJsController()); stream->getController().setup(js, kj::mv(underlyingSource), kj::mv(queuingStrategy)); return kj::mv(stream); @@ -542,9 +517,10 @@ namespace { // wrap the two ends of the pipe in special adapters that track whether end() was called. class ExplicitEndOutputPipeAdapter final: public capnp::ExplicitEndOutputStream { public: - ExplicitEndOutputPipeAdapter(kj::Own inner, - kj::Own> ended) - : inner(kj::mv(inner)), ended(kj::mv(ended)) {} + ExplicitEndOutputPipeAdapter( + kj::Own inner, kj::Own> ended) + : inner(kj::mv(inner)), + ended(kj::mv(ended)) {} kj::Promise write(kj::ArrayPtr buffer) override { return KJ_REQUIRE_NONNULL(inner)->write(buffer); @@ -577,9 +553,11 @@ private: class ExplicitEndInputPipeAdapter final: public kj::AsyncInputStream { public: ExplicitEndInputPipeAdapter(kj::Own inner, - kj::Own> ended, - kj::Maybe expectedLength) - : inner(kj::mv(inner)), ended(kj::mv(ended)), expectedLength(expectedLength) {} + kj::Own> ended, + kj::Maybe expectedLength) + : inner(kj::mv(inner)), + ended(kj::mv(ended)), + expectedLength(expectedLength) {} kj::Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { size_t result = co_await inner->tryRead(buffer, minBytes, maxBytes); @@ -627,7 +605,8 @@ private: class NoDeferredProxyReadableStream final: public ReadableStreamSource { public: NoDeferredProxyReadableStream(kj::Own inner, IoContext& ioctx) - : inner(kj::mv(inner)), ioctx(ioctx) {} + : inner(kj::mv(inner)), + ioctx(ioctx) {} kj::Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { return inner->tryRead(buffer, minBytes, maxBytes); @@ -655,12 +634,10 @@ public: kj::Maybe tryTee(uint64_t limit) override { return inner->tryTee(limit).map([&](Tee tee) { - return Tee { - .branches = { - kj::heap(kj::mv(tee.branches[0]), ioctx), - kj::heap(kj::mv(tee.branches[1]), ioctx), - } - }; + return Tee{.branches = { + kj::heap(kj::mv(tee.branches[0]), ioctx), + kj::heap(kj::mv(tee.branches[1]), ioctx), + }}; }); } @@ -708,8 +685,8 @@ void ReadableStream::serialize(jsg::Lock& js, jsg::Serializer& serializer) { auto sink = newSystemStream(kj::mv(kjStream), encoding, ioctx); - ioctx.addTask(ioctx.waitForDeferredProxy(pumpTo(js, kj::mv(sink), true)) - .catch_([](kj::Exception&& e) { + ioctx.addTask( + ioctx.waitForDeferredProxy(pumpTo(js, kj::mv(sink), true)).catch_([](kj::Exception&& e) { // Errors in pumpTo() are automatically propagated to the source and destination. We don't // want to throw them from here since it'll cause an uncaught exception to be reported, even // if the application actually does handle it! @@ -718,8 +695,8 @@ void ReadableStream::serialize(jsg::Lock& js, jsg::Serializer& serializer) { jsg::Ref ReadableStream::deserialize( jsg::Lock& js, rpc::SerializationTag tag, jsg::Deserializer& deserializer) { - auto& handler = KJ_REQUIRE_NONNULL(deserializer.getExternalHandler(), - "got ReadableStream on non-RPC serialized object?"); + auto& handler = KJ_REQUIRE_NONNULL( + deserializer.getExternalHandler(), "got ReadableStream on non-RPC serialized object?"); auto externalHandler = dynamic_cast(&handler); KJ_REQUIRE(externalHandler != nullptr, "got ReadableStream on non-RPC serialized object?"); @@ -729,8 +706,8 @@ jsg::Ref ReadableStream::deserialize( auto rs = reader.getReadableStream(); auto encoding = rs.getEncoding(); - KJ_REQUIRE(static_cast(encoding) < - capnp::Schema::from().getEnumerants().size(), + KJ_REQUIRE( + static_cast(encoding) < capnp::Schema::from().getEnumerants().size(), "unknown StreamEncoding received from peer"); auto& ioctx = IoContext::current(); @@ -746,19 +723,22 @@ jsg::Ref ReadableStream::deserialize( auto endedFlag = kj::refcounted>(false); auto out = kj::heap(kj::mv(pipe.out), kj::addRef(*endedFlag)); - auto in = kj::heap( - kj::mv(pipe.in), kj::mv(endedFlag), expectedLength); + auto in = + kj::heap(kj::mv(pipe.in), kj::mv(endedFlag), expectedLength); externalHandler->setLastStream(ioctx.getByteStreamFactory().kjToCapnp(kj::mv(out))); return jsg::alloc(ioctx, - kj::heap( - newSystemStream(kj::mv(in), encoding, ioctx), ioctx)); + kj::heap(newSystemStream(kj::mv(in), encoding, ioctx), ioctx)); } -kj::StringPtr ReaderImpl::jsgGetMemoryName() const { return "ReaderImpl"_kjc; } +kj::StringPtr ReaderImpl::jsgGetMemoryName() const { + return "ReaderImpl"_kjc; +} -size_t ReaderImpl::jsgGetMemorySelfSize() const { return sizeof(ReaderImpl); } +size_t ReaderImpl::jsgGetMemorySelfSize() const { + return sizeof(ReaderImpl); +} void ReaderImpl::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { KJ_IF_SOME(stream, state.tryGet()) { diff --git a/src/workerd/api/streams/standard-test.c++ b/src/workerd/api/streams/standard-test.c++ index 702109e86fc..2ebf1ecc0a8 100644 --- a/src/workerd/api/streams/standard-test.c++ +++ b/src/workerd/api/streams/standard-test.c++ @@ -17,11 +17,8 @@ JSG_DECLARE_ISOLATE_TYPE(RsIsolate, RsContext, ReadResult); void preamble(auto callback) { RsIsolate isolate(v8System, kj::heap()); isolate.runInLockScope([&](RsIsolate::Lock& lock) { - JSG_WITHIN_CONTEXT_SCOPE(lock, - lock.newContext().getHandle(lock), - [&](jsg::Lock& js) { - callback(js); - }); + JSG_WITHIN_CONTEXT_SCOPE( + lock, lock.newContext().getHandle(lock), [&](jsg::Lock& js) { callback(js); }); }); } @@ -46,37 +43,41 @@ KJ_TEST("ReadableStream read all text (value readable)") { preamble([](jsg::Lock& js) { uint checked = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - rs->getController().setup(js, UnderlyingSource { - .pull = [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + rs->getController().setup(js, + UnderlyingSource{ + .pull = + [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + // Because we're using a value-based stream, two enqueue operations will + // require at least three reads to complete: one for the first chunk, 'hello, ', + // one for the second chunk, 'world!', and one to signal close. + KJ_SWITCH_ONEOF(controller) { // Because we're using a value-based stream, two enqueue operations will // require at least three reads to complete: one for the first chunk, 'hello, ', // one for the second chunk, 'world!', and one to signal close. - KJ_SWITCH_ONEOF(controller) { - // Because we're using a value-based stream, two enqueue operations will - // require at least three reads to complete: one for the first chunk, 'hello, ', - // one for the second chunk, 'world!', and one to signal close. - KJ_CASE_ONEOF(c, jsg::Ref) { - checked++; - c->enqueue(js, toBytes(js, kj::str("Hello, "))); - c->enqueue(js, toBytes(js, kj::str("world!"))); - c->close(js); - return js.resolvedPromise(); - } - KJ_CASE_ONEOF(c, jsg::Ref) {} + KJ_CASE_ONEOF(c, jsg::Ref) { + checked++; + c->enqueue(js, toBytes(js, kj::str("Hello, "))); + c->enqueue(js, toBytes(js, kj::str("world!"))); + c->close(js); + return js.resolvedPromise(); + } + KJ_CASE_ONEOF(c, jsg::Ref) { } - KJ_UNREACHABLE; } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + KJ_UNREACHABLE; + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllText(js, 20) - .then(js, [&](jsg::Lock& js, kj::String&& text) { - KJ_ASSERT(text == "Hello, world!"_kjc); - checked++; - }); + auto promise = + rs->getController().readAllText(js, 20).then(js, [&](jsg::Lock& js, kj::String&& text) { + KJ_ASSERT(text == "Hello, world!"_kjc); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -100,37 +101,41 @@ KJ_TEST("ReadableStream read all text, rs ref held (value readable)") { preamble([](jsg::Lock& js) { uint checked = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - rs->getController().setup(js, UnderlyingSource { - .pull = [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + rs->getController().setup(js, + UnderlyingSource{ + .pull = + [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + // Because we're using a value-based stream, two enqueue operations will + // require at least three reads to complete: one for the first chunk, 'hello, ', + // one for the second chunk, 'world!', and one to signal close. + KJ_SWITCH_ONEOF(controller) { // Because we're using a value-based stream, two enqueue operations will // require at least three reads to complete: one for the first chunk, 'hello, ', // one for the second chunk, 'world!', and one to signal close. - KJ_SWITCH_ONEOF(controller) { - // Because we're using a value-based stream, two enqueue operations will - // require at least three reads to complete: one for the first chunk, 'hello, ', - // one for the second chunk, 'world!', and one to signal close. - KJ_CASE_ONEOF(c, jsg::Ref) { - checked++; - c->enqueue(js, toBytes(js, kj::str("Hello, "))); - c->enqueue(js, toBytes(js, kj::str("world!"))); - c->close(js); - return js.resolvedPromise(); - } - KJ_CASE_ONEOF(c, jsg::Ref) {} + KJ_CASE_ONEOF(c, jsg::Ref) { + checked++; + c->enqueue(js, toBytes(js, kj::str("Hello, "))); + c->enqueue(js, toBytes(js, kj::str("world!"))); + c->close(js); + return js.resolvedPromise(); + } + KJ_CASE_ONEOF(c, jsg::Ref) { } - KJ_UNREACHABLE; } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + KJ_UNREACHABLE; + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllText(js, 20) - .then(js, [&](jsg::Lock& js, kj::String&& text) { - KJ_ASSERT(text == "Hello, world!"_kjc); - checked++; - }); + auto promise = + rs->getController().readAllText(js, 20).then(js, [&](jsg::Lock& js, kj::String&& text) { + KJ_ASSERT(text == "Hello, world!"_kjc); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -150,38 +155,42 @@ KJ_TEST("ReadableStream read all text (byte readable)") { preamble([](jsg::Lock& js) { uint checked = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - rs->getController().setup(js, UnderlyingSource { - .type = kj::str("bytes"), - .pull = [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + rs->getController().setup(js, + UnderlyingSource{ + .type = kj::str("bytes"), + .pull = + [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + // Because we're using a value-based stream, two enqueue operations will + // require at least three reads to complete: one for the first chunk, 'hello, ', + // one for the second chunk, 'world!', and one to signal close. + KJ_SWITCH_ONEOF(controller) { // Because we're using a value-based stream, two enqueue operations will // require at least three reads to complete: one for the first chunk, 'hello, ', // one for the second chunk, 'world!', and one to signal close. - KJ_SWITCH_ONEOF(controller) { - // Because we're using a value-based stream, two enqueue operations will - // require at least three reads to complete: one for the first chunk, 'hello, ', - // one for the second chunk, 'world!', and one to signal close. - KJ_CASE_ONEOF(c, jsg::Ref) { - checked++; - c->enqueue(js, toBufferSource(js, kj::str("Hello, "))); - c->enqueue(js, toBufferSource(js, kj::str("world!"))); - c->close(js); - return js.resolvedPromise(); - } - KJ_CASE_ONEOF(c, jsg::Ref) {} + KJ_CASE_ONEOF(c, jsg::Ref) { + checked++; + c->enqueue(js, toBufferSource(js, kj::str("Hello, "))); + c->enqueue(js, toBufferSource(js, kj::str("world!"))); + c->close(js); + return js.resolvedPromise(); + } + KJ_CASE_ONEOF(c, jsg::Ref) { } - KJ_UNREACHABLE; } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + KJ_UNREACHABLE; + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllText(js, 20) - .then(js, [&](jsg::Lock& js, kj::String&& text) { - KJ_ASSERT(text == "Hello, world!"_kjc); - checked++; - }); + auto promise = + rs->getController().readAllText(js, 20).then(js, [&](jsg::Lock& js, kj::String&& text) { + KJ_ASSERT(text == "Hello, world!"_kjc); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -205,37 +214,41 @@ KJ_TEST("ReadableStream read all bytes (value readable)") { preamble([](jsg::Lock& js) { uint checked = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - rs->getController().setup(js, UnderlyingSource { - .pull = [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + rs->getController().setup(js, + UnderlyingSource{ + .pull = + [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + // Because we're using a value-based stream, two enqueue operations will + // require at least three reads to complete: one for the first chunk, 'hello, ', + // one for the second chunk, 'world!', and one to signal close. + KJ_SWITCH_ONEOF(controller) { // Because we're using a value-based stream, two enqueue operations will // require at least three reads to complete: one for the first chunk, 'hello, ', // one for the second chunk, 'world!', and one to signal close. - KJ_SWITCH_ONEOF(controller) { - // Because we're using a value-based stream, two enqueue operations will - // require at least three reads to complete: one for the first chunk, 'hello, ', - // one for the second chunk, 'world!', and one to signal close. - KJ_CASE_ONEOF(c, jsg::Ref) { - checked++; - c->enqueue(js, toBytes(js, kj::str("Hello, "))); - c->enqueue(js, toBytes(js, kj::str("world!"))); - c->close(js); - return js.resolvedPromise(); - } - KJ_CASE_ONEOF(c, jsg::Ref) {} + KJ_CASE_ONEOF(c, jsg::Ref) { + checked++; + c->enqueue(js, toBytes(js, kj::str("Hello, "))); + c->enqueue(js, toBytes(js, kj::str("world!"))); + c->close(js); + return js.resolvedPromise(); + } + KJ_CASE_ONEOF(c, jsg::Ref) { } - KJ_UNREACHABLE; } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + KJ_UNREACHABLE; + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllBytes(js, 20) - .then(js, [&](jsg::Lock& js, kj::Array&& text) { - KJ_ASSERT(text == "Hello, world!"_kjc.asBytes()); - checked++; - }); + auto promise = rs->getController().readAllBytes(js, 20).then( + js, [&](jsg::Lock& js, kj::Array&& text) { + KJ_ASSERT(text == "Hello, world!"_kjc.asBytes()); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -259,38 +272,42 @@ KJ_TEST("ReadableStream read all bytes (byte readable)") { preamble([](jsg::Lock& js) { uint checked = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - rs->getController().setup(js, UnderlyingSource { - .type = kj::str("bytes"), - .pull = [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + rs->getController().setup(js, + UnderlyingSource{ + .type = kj::str("bytes"), + .pull = + [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + // Because we're using a value-based stream, two enqueue operations will + // require at least three reads to complete: one for the first chunk, 'hello, ', + // one for the second chunk, 'world!', and one to signal close. + KJ_SWITCH_ONEOF(controller) { // Because we're using a value-based stream, two enqueue operations will // require at least three reads to complete: one for the first chunk, 'hello, ', // one for the second chunk, 'world!', and one to signal close. - KJ_SWITCH_ONEOF(controller) { - // Because we're using a value-based stream, two enqueue operations will - // require at least three reads to complete: one for the first chunk, 'hello, ', - // one for the second chunk, 'world!', and one to signal close. - KJ_CASE_ONEOF(c, jsg::Ref) { - checked++; - c->enqueue(js, toBufferSource(js, kj::str("Hello, "))); - c->enqueue(js, toBufferSource(js, kj::str("world!"))); - c->close(js); - return js.resolvedPromise(); - } - KJ_CASE_ONEOF(c, jsg::Ref) {} + KJ_CASE_ONEOF(c, jsg::Ref) { + checked++; + c->enqueue(js, toBufferSource(js, kj::str("Hello, "))); + c->enqueue(js, toBufferSource(js, kj::str("world!"))); + c->close(js); + return js.resolvedPromise(); + } + KJ_CASE_ONEOF(c, jsg::Ref) { } - KJ_UNREACHABLE; } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + KJ_UNREACHABLE; + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllBytes(js, 20) - .then(js, [&](jsg::Lock& js, kj::Array&& text) { - KJ_ASSERT(text == "Hello, world!"_kjc.asBytes()); - checked++; - }); + auto promise = rs->getController().readAllBytes(js, 20).then( + js, [&](jsg::Lock& js, kj::Array&& text) { + KJ_ASSERT(text == "Hello, world!"_kjc.asBytes()); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -315,54 +332,46 @@ KJ_TEST("ReadableStream read all bytes (value readable, more reads)") { uint checked = 0; uint counter = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - auto chunks = kj::arr( - kj::str("H"), - kj::str("e"), - kj::str("l"), - kj::str("l"), - kj::str("o"), - kj::str(","), - kj::str(" "), - kj::str("w"), - kj::str("o"), - kj::str("r"), - kj::str("l"), - kj::str("d"), - kj::str("!") - ); - rs->getController().setup(js, UnderlyingSource { - .pull = [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + auto chunks = kj::arr(kj::str("H"), kj::str("e"), kj::str("l"), kj::str("l"), + kj::str("o"), kj::str(","), kj::str(" "), kj::str("w"), kj::str("o"), kj::str("r"), + kj::str("l"), kj::str("d"), kj::str("!")); + rs->getController().setup(js, + UnderlyingSource{ + .pull = + [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + // Because we're using a value-based stream, two enqueue operations will + // require at least three reads to complete: one for the first chunk, 'hello, ', + // one for the second chunk, 'world!', and one to signal close. + KJ_SWITCH_ONEOF(controller) { // Because we're using a value-based stream, two enqueue operations will // require at least three reads to complete: one for the first chunk, 'hello, ', // one for the second chunk, 'world!', and one to signal close. - KJ_SWITCH_ONEOF(controller) { - // Because we're using a value-based stream, two enqueue operations will - // require at least three reads to complete: one for the first chunk, 'hello, ', - // one for the second chunk, 'world!', and one to signal close. - KJ_CASE_ONEOF(c, jsg::Ref) { - checked++; - c->enqueue(js, toBytes(js, kj::mv(chunks[counter++]))); - if (counter == chunks.size()) { - c->close(js); - } - - return js.resolvedPromise(); + KJ_CASE_ONEOF(c, jsg::Ref) { + checked++; + c->enqueue(js, toBytes(js, kj::mv(chunks[counter++]))); + if (counter == chunks.size()) { + c->close(js); } - KJ_CASE_ONEOF(c, jsg::Ref) {} + + return js.resolvedPromise(); + } + KJ_CASE_ONEOF(c, jsg::Ref) { } - KJ_UNREACHABLE; } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + KJ_UNREACHABLE; + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllBytes(js, 20) - .then(js, [&](jsg::Lock& js, kj::Array&& text) { - KJ_ASSERT(text == "Hello, world!"_kjc.asBytes()); - checked++; - }); + auto promise = rs->getController().readAllBytes(js, 20).then( + js, [&](jsg::Lock& js, kj::Array&& text) { + KJ_ASSERT(text == "Hello, world!"_kjc.asBytes()); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -387,55 +396,47 @@ KJ_TEST("ReadableStream read all bytes (byte readable, more reads)") { uint checked = 0; uint counter = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - auto chunks = kj::arr( - kj::str("H"), - kj::str("e"), - kj::str("l"), - kj::str("l"), - kj::str("o"), - kj::str(","), - kj::str(" "), - kj::str("w"), - kj::str("o"), - kj::str("r"), - kj::str("l"), - kj::str("d"), - kj::str("!") - ); - rs->getController().setup(js, UnderlyingSource { - .type = kj::str("bytes"), - .pull = [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + auto chunks = kj::arr(kj::str("H"), kj::str("e"), kj::str("l"), kj::str("l"), + kj::str("o"), kj::str(","), kj::str(" "), kj::str("w"), kj::str("o"), kj::str("r"), + kj::str("l"), kj::str("d"), kj::str("!")); + rs->getController().setup(js, + UnderlyingSource{ + .type = kj::str("bytes"), + .pull = + [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + // Because we're using a value-based stream, two enqueue operations will + // require at least three reads to complete: one for the first chunk, 'hello, ', + // one for the second chunk, 'world!', and one to signal close. + KJ_SWITCH_ONEOF(controller) { // Because we're using a value-based stream, two enqueue operations will // require at least three reads to complete: one for the first chunk, 'hello, ', // one for the second chunk, 'world!', and one to signal close. - KJ_SWITCH_ONEOF(controller) { - // Because we're using a value-based stream, two enqueue operations will - // require at least three reads to complete: one for the first chunk, 'hello, ', - // one for the second chunk, 'world!', and one to signal close. - KJ_CASE_ONEOF(c, jsg::Ref) { - checked++; - c->enqueue(js, toBufferSource(js, kj::mv(chunks[counter++]))); - if (counter == chunks.size()) { - c->close(js); - } - - return js.resolvedPromise(); + KJ_CASE_ONEOF(c, jsg::Ref) { + checked++; + c->enqueue(js, toBufferSource(js, kj::mv(chunks[counter++]))); + if (counter == chunks.size()) { + c->close(js); } - KJ_CASE_ONEOF(c, jsg::Ref) {} + + return js.resolvedPromise(); + } + KJ_CASE_ONEOF(c, jsg::Ref) { } - KJ_UNREACHABLE; } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + KJ_UNREACHABLE; + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllBytes(js, 20) - .then(js, [&](jsg::Lock& js, kj::Array&& text) { - KJ_ASSERT(text == "Hello, world!"_kjc.asBytes()); - checked++; - }); + auto promise = rs->getController().readAllBytes(js, 20).then( + js, [&](jsg::Lock& js, kj::Array&& text) { + KJ_ASSERT(text == "Hello, world!"_kjc.asBytes()); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -461,53 +462,55 @@ KJ_TEST("ReadableStream read all bytes (byte readable, large data)") { uint counter = 0; auto rs = jsg::alloc(newReadableStreamJsController()); static constexpr uint BASE = 4097; - auto chunks = kj::arr>( - kj::heapArray(BASE), - kj::heapArray(BASE * 2), - kj::heapArray(BASE * 4) - ); + auto chunks = kj::arr>(kj::heapArray(BASE), + kj::heapArray(BASE * 2), kj::heapArray(BASE * 4)); chunks[0].asPtr().fill('A'); chunks[1].asPtr().fill('B'); chunks[2].asPtr().fill('C'); - rs->getController().setup(js, UnderlyingSource { - .type = kj::str("bytes"), - .pull = [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + rs->getController().setup(js, + UnderlyingSource{ + .type = kj::str("bytes"), + .pull = + [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + // Because we're using a value-based stream, two enqueue operations will + // require at least three reads to complete: one for the first chunk, 'hello, ', + // one for the second chunk, 'world!', and one to signal close. + KJ_SWITCH_ONEOF(controller) { // Because we're using a value-based stream, two enqueue operations will // require at least three reads to complete: one for the first chunk, 'hello, ', // one for the second chunk, 'world!', and one to signal close. - KJ_SWITCH_ONEOF(controller) { - // Because we're using a value-based stream, two enqueue operations will - // require at least three reads to complete: one for the first chunk, 'hello, ', - // one for the second chunk, 'world!', and one to signal close. - KJ_CASE_ONEOF(c, jsg::Ref) { - checked++; - c->enqueue(js, toBufferSource(js, kj::mv(chunks[counter++]))); - if (counter == chunks.size()) { - c->close(js); - } - - return js.resolvedPromise(); + KJ_CASE_ONEOF(c, jsg::Ref) { + checked++; + c->enqueue(js, toBufferSource(js, kj::mv(chunks[counter++]))); + if (counter == chunks.size()) { + c->close(js); } - KJ_CASE_ONEOF(c, jsg::Ref) {} + + return js.resolvedPromise(); + } + KJ_CASE_ONEOF(c, jsg::Ref) { } - KJ_UNREACHABLE; } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + KJ_UNREACHABLE; + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllBytes(js, (BASE * 7) + 1) - .then(js, [&](jsg::Lock& js, kj::Array&& text) { - kj::byte check[BASE * 7]{}; - kj::arrayPtr(check).first(BASE).fill('A'); - kj::arrayPtr(check).slice(BASE).first(BASE * 2).fill('B'); - kj::arrayPtr(check).slice(BASE * 3).fill('C'); - KJ_ASSERT(text.size() == BASE * 7); - KJ_ASSERT(check == text); - checked++; - }); + auto promise = rs->getController() + .readAllBytes(js, (BASE * 7) + 1) + .then(js, [&](jsg::Lock& js, kj::Array&& text) { + kj::byte check[BASE * 7]{}; + kj::arrayPtr(check).first(BASE).fill('A'); + kj::arrayPtr(check).slice(BASE).first(BASE * 2).fill('B'); + kj::arrayPtr(check).slice(BASE * 3).fill('C'); + KJ_ASSERT(text.size() == BASE * 7); + KJ_ASSERT(check == text); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -534,43 +537,46 @@ KJ_TEST("ReadableStream read all bytes (value readable, wrong type)") { preamble([](jsg::Lock& js) { uint checked = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - rs->getController().setup(js, UnderlyingSource { - .pull = [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + rs->getController().setup(js, + UnderlyingSource{ + .pull = + [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + // Because we're using a value-based stream, two enqueue operations will + // require at least three reads to complete: one for the first chunk, 'hello, ', + // one for the second chunk, 'world!', and one to signal close. + KJ_SWITCH_ONEOF(controller) { // Because we're using a value-based stream, two enqueue operations will // require at least three reads to complete: one for the first chunk, 'hello, ', // one for the second chunk, 'world!', and one to signal close. - KJ_SWITCH_ONEOF(controller) { - // Because we're using a value-based stream, two enqueue operations will - // require at least three reads to complete: one for the first chunk, 'hello, ', - // one for the second chunk, 'world!', and one to signal close. - KJ_CASE_ONEOF(c, jsg::Ref) { - c->enqueue(js, js.str("wrong type"_kjc)); - checked++; - return js.resolvedPromise(); - } - KJ_CASE_ONEOF(c, jsg::Ref) {} + KJ_CASE_ONEOF(c, jsg::Ref) { + c->enqueue(js, js.str("wrong type"_kjc)); + checked++; + return js.resolvedPromise(); + } + KJ_CASE_ONEOF(c, jsg::Ref) { } - KJ_UNREACHABLE; - }, - .cancel = [&](jsg::Lock& js, auto reason) -> jsg::Promise { - KJ_ASSERT(kj::str(reason) == "TypeError: This ReadableStream did not return bytes."); - checked++; - return js.resolvedPromise(); } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + KJ_UNREACHABLE; + }, + .cancel = [&](jsg::Lock& js, auto reason) -> jsg::Promise { + KJ_ASSERT(kj::str(reason) == "TypeError: This ReadableStream did not return bytes."); + checked++; + return js.resolvedPromise(); + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllBytes(js, 20) - .then(js, [](jsg::Lock& js, kj::Array&& text) { - KJ_UNREACHABLE; - }, [&](jsg::Lock& js, jsg::Value&& exception) { - KJ_ASSERT(kj::str(exception.getHandle(js)) == - "TypeError: This ReadableStream did not return bytes."); - checked++; - }); + auto promise = rs->getController().readAllBytes(js, 20).then(js, + [](jsg::Lock& js, kj::Array&& text) { KJ_UNREACHABLE; }, + [&](jsg::Lock& js, jsg::Value&& exception) { + KJ_ASSERT(kj::str(exception.getHandle(js)) == + "TypeError: This ReadableStream did not return bytes."); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -593,38 +599,40 @@ KJ_TEST("ReadableStream read all bytes (value readable, to many bytes)") { preamble([](jsg::Lock& js) { uint checked = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - rs->getController().setup(js, UnderlyingSource { - .pull = [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + rs->getController().setup(js, + UnderlyingSource{ + .pull = + [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + // Because we're using a value-based stream, two enqueue operations will + // require at least three reads to complete: one for the first chunk, 'hello, ', + // one for the second chunk, 'world!', and one to signal close. + KJ_SWITCH_ONEOF(controller) { // Because we're using a value-based stream, two enqueue operations will // require at least three reads to complete: one for the first chunk, 'hello, ', // one for the second chunk, 'world!', and one to signal close. - KJ_SWITCH_ONEOF(controller) { - // Because we're using a value-based stream, two enqueue operations will - // require at least three reads to complete: one for the first chunk, 'hello, ', - // one for the second chunk, 'world!', and one to signal close. - KJ_CASE_ONEOF(c, jsg::Ref) { - c->enqueue(js, toBytes(js, kj::str("123456789012345678901"))); - checked++; - return js.resolvedPromise(); - } - KJ_CASE_ONEOF(c, jsg::Ref) {} + KJ_CASE_ONEOF(c, jsg::Ref) { + c->enqueue(js, toBytes(js, kj::str("123456789012345678901"))); + checked++; + return js.resolvedPromise(); + } + KJ_CASE_ONEOF(c, jsg::Ref) { } - KJ_UNREACHABLE; } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + KJ_UNREACHABLE; + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllBytes(js, 20) - .then(js, [](jsg::Lock& js, kj::Array&& text) { - KJ_UNREACHABLE; - }, [&](jsg::Lock& js, jsg::Value&& exception) { - KJ_ASSERT(kj::str(exception.getHandle(js)) == - "TypeError: Memory limit exceeded before EOF."); - checked++; - }); + auto promise = rs->getController().readAllBytes(js, 20).then(js, + [](jsg::Lock& js, kj::Array&& text) { KJ_UNREACHABLE; }, + [&](jsg::Lock& js, jsg::Value&& exception) { + KJ_ASSERT(kj::str(exception.getHandle(js)) == "TypeError: Memory limit exceeded before EOF."); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -647,39 +655,41 @@ KJ_TEST("ReadableStream read all bytes (byte readable, to many bytes)") { preamble([](jsg::Lock& js) { uint checked = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - rs->getController().setup(js, UnderlyingSource { - .type = kj::str("bytes"), - .pull = [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + rs->getController().setup(js, + UnderlyingSource{ + .type = kj::str("bytes"), + .pull = + [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + // Because we're using a value-based stream, two enqueue operations will + // require at least three reads to complete: one for the first chunk, 'hello, ', + // one for the second chunk, 'world!', and one to signal close. + KJ_SWITCH_ONEOF(controller) { // Because we're using a value-based stream, two enqueue operations will // require at least three reads to complete: one for the first chunk, 'hello, ', // one for the second chunk, 'world!', and one to signal close. - KJ_SWITCH_ONEOF(controller) { - // Because we're using a value-based stream, two enqueue operations will - // require at least three reads to complete: one for the first chunk, 'hello, ', - // one for the second chunk, 'world!', and one to signal close. - KJ_CASE_ONEOF(c, jsg::Ref) { - c->enqueue(js, toBufferSource(js, kj::str("123456789012345678901"))); - checked++; - return js.resolvedPromise(); - } - KJ_CASE_ONEOF(c, jsg::Ref) {} + KJ_CASE_ONEOF(c, jsg::Ref) { + c->enqueue(js, toBufferSource(js, kj::str("123456789012345678901"))); + checked++; + return js.resolvedPromise(); + } + KJ_CASE_ONEOF(c, jsg::Ref) { } - KJ_UNREACHABLE; } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + KJ_UNREACHABLE; + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllBytes(js, 20) - .then(js, [](jsg::Lock& js, kj::Array&& text) { - KJ_UNREACHABLE; - }, [&](jsg::Lock& js, jsg::Value&& exception) { - KJ_ASSERT(kj::str(exception.getHandle(js)) == - "TypeError: Memory limit exceeded before EOF."); - checked++; - }); + auto promise = rs->getController().readAllBytes(js, 20).then(js, + [](jsg::Lock& js, kj::Array&& text) { KJ_UNREACHABLE; }, + [&](jsg::Lock& js, jsg::Value&& exception) { + KJ_ASSERT(kj::str(exception.getHandle(js)) == "TypeError: Memory limit exceeded before EOF."); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -702,25 +712,27 @@ KJ_TEST("ReadableStream read all bytes (byte readable, failed read)") { preamble([](jsg::Lock& js) { uint checked = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - rs->getController().setup(js, UnderlyingSource { - .type = kj::str("bytes"), - .pull = [&](jsg::Lock& js, UnderlyingSource::Controller controller) { - checked++; - return js.rejectedPromise(js.error("boom")); - } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + rs->getController().setup(js, + UnderlyingSource{ + .type = kj::str("bytes"), + .pull = + [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + checked++; + return js.rejectedPromise(js.error("boom")); + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllBytes(js, 20) - .then(js, [](jsg::Lock& js, kj::Array&& text) { - KJ_UNREACHABLE; - }, [&](jsg::Lock& js, jsg::Value&& exception) { - KJ_ASSERT(kj::str(exception.getHandle(js)) == "Error: boom"); - checked++; - }); + auto promise = rs->getController().readAllBytes(js, 20).then(js, + [](jsg::Lock& js, kj::Array&& text) { KJ_UNREACHABLE; }, + [&](jsg::Lock& js, jsg::Value&& exception) { + KJ_ASSERT(kj::str(exception.getHandle(js)) == "Error: boom"); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -743,24 +755,26 @@ KJ_TEST("ReadableStream read all bytes (value readable, failed read)") { preamble([](jsg::Lock& js) { uint checked = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - rs->getController().setup(js, UnderlyingSource { - .pull = [&](jsg::Lock& js, UnderlyingSource::Controller controller) { - checked++; - return js.rejectedPromise(js.error("boom")); - } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + rs->getController().setup(js, + UnderlyingSource{ + .pull = + [&](jsg::Lock& js, UnderlyingSource::Controller controller) { + checked++; + return js.rejectedPromise(js.error("boom")); + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllBytes(js, 20) - .then(js, [](jsg::Lock& js, kj::Array&& text) { - KJ_UNREACHABLE; - }, [&](jsg::Lock& js, jsg::Value&& exception) { - KJ_ASSERT(kj::str(exception.getHandle(js)) == "Error: boom"); - checked++; - }); + auto promise = rs->getController().readAllBytes(js, 20).then(js, + [](jsg::Lock& js, kj::Array&& text) { KJ_UNREACHABLE; }, + [&](jsg::Lock& js, jsg::Value&& exception) { + KJ_ASSERT(kj::str(exception.getHandle(js)) == "Error: boom"); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -783,25 +797,27 @@ KJ_TEST("ReadableStream read all bytes (byte readable, failed start)") { preamble([](jsg::Lock& js) { uint checked = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - rs->getController().setup(js, UnderlyingSource { - .type = kj::str("bytes"), - .start = [&](jsg::Lock& js, UnderlyingSource::Controller controller) -> jsg::Promise { - checked++; - return js.rejectedPromise(js.error("boom")); - } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + rs->getController().setup(js, + UnderlyingSource{ + .type = kj::str("bytes"), + .start = [&](jsg::Lock& js, + UnderlyingSource::Controller controller) -> jsg::Promise { + checked++; + return js.rejectedPromise(js.error("boom")); + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllBytes(js, 20) - .then(js, [](jsg::Lock& js, kj::Array&& text) { - KJ_UNREACHABLE; - }, [&](jsg::Lock& js, jsg::Value&& exception) { - KJ_ASSERT(kj::str(exception.getHandle(js)) == "Error: boom"); - checked++; - }); + auto promise = rs->getController().readAllBytes(js, 20).then(js, + [](jsg::Lock& js, kj::Array&& text) { KJ_UNREACHABLE; }, + [&](jsg::Lock& js, jsg::Value&& exception) { + KJ_ASSERT(kj::str(exception.getHandle(js)) == "Error: boom"); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); @@ -824,25 +840,27 @@ KJ_TEST("ReadableStream read all bytes (byte readable, failed start 2)") { preamble([](jsg::Lock& js) { uint checked = 0; auto rs = jsg::alloc(newReadableStreamJsController()); - rs->getController().setup(js, UnderlyingSource { - .type = kj::str("bytes"), - .start = [&](jsg::Lock& js, UnderlyingSource::Controller controller) -> jsg::Promise { - checked++; - JSG_FAIL_REQUIRE(Error, "boom"); - } - // Setting a highWaterMark of 0 means the pull function above will not be called - // immediately on creation of the stream, but only when the first read in the - // readall call below happens. - }, StreamQueuingStrategy { .highWaterMark = 0 }); + rs->getController().setup(js, + UnderlyingSource{ + .type = kj::str("bytes"), + .start = [&](jsg::Lock& js, + UnderlyingSource::Controller controller) -> jsg::Promise { + checked++; + JSG_FAIL_REQUIRE(Error, "boom"); + } + // Setting a highWaterMark of 0 means the pull function above will not be called + // immediately on creation of the stream, but only when the first read in the + // readall call below happens. + }, + StreamQueuingStrategy{.highWaterMark = 0}); // Starts a read loop of javascript promises. - auto promise = rs->getController().readAllBytes(js, 20) - .then(js, [](jsg::Lock& js, kj::Array&& text) { - KJ_UNREACHABLE; - }, [&](jsg::Lock& js, jsg::Value&& exception) { - KJ_ASSERT(kj::str(exception.getHandle(js)) == "Error: boom"); - checked++; - }); + auto promise = rs->getController().readAllBytes(js, 20).then(js, + [](jsg::Lock& js, kj::Array&& text) { KJ_UNREACHABLE; }, + [&](jsg::Lock& js, jsg::Value&& exception) { + KJ_ASSERT(kj::str(exception.getHandle(js)) == "Error: boom"); + checked++; + }); // Reading left the stream locked and disturbed KJ_ASSERT(rs->isLocked()); diff --git a/src/workerd/api/streams/standard.c++ b/src/workerd/api/streams/standard.c++ index 71d2202d363..4e7b607d46b 100644 --- a/src/workerd/api/streams/standard.c++ +++ b/src/workerd/api/streams/standard.c++ @@ -18,7 +18,7 @@ using ByobController = jsg::Ref; namespace { struct ValueReadable; struct ByteReadable; -} +} // namespace // ======================================================================================= // The Unlocked, Locked, ReaderLocked, and WriterLocked structs @@ -44,7 +44,9 @@ public: using PipeController = ReadableStreamController::PipeController; using Reader = ReadableStreamController::Reader; - bool isLockedToReader() const { return !state.template is(); } + bool isLockedToReader() const { + return !state.template is(); + } bool lockReader(jsg::Lock& js, Controller& self, Reader& reader); @@ -56,9 +58,7 @@ public: void onClose(jsg::Lock& js); void onError(jsg::Lock& js, v8::Local reason); - kj::Maybe tryPipeLock( - Controller& self, - jsg::Ref destination); + kj::Maybe tryPipeLock(Controller& self, jsg::Ref destination); void visitForGc(jsg::GcVisitor& visitor); @@ -70,8 +70,10 @@ public: } void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(locked, Locked) {} - KJ_CASE_ONEOF(unlocked, Unlocked) {} + KJ_CASE_ONEOF(locked, Locked) { + } + KJ_CASE_ONEOF(unlocked, Unlocked) { + } KJ_CASE_ONEOF(pipeLocked, PipeLocked) { tracker.trackField("pipeLocked", pipeLocked); } @@ -85,9 +87,12 @@ private: class PipeLocked final: public PipeController { public: explicit PipeLocked(Controller& inner, jsg::Ref ref) - : inner(inner), writableStreamRef(kj::mv(ref)) {} + : inner(inner), + writableStreamRef(kj::mv(ref)) {} - bool isClosed() override { return inner.state.template is(); } + bool isClosed() override { + return inner.state.template is(); + } kj::Maybe> tryGetErrored(jsg::Lock& js) override { KJ_IF_SOME(errored, inner.state.template tryGet()) { @@ -110,8 +115,7 @@ private: inner.doError(js, reason); } - void release(jsg::Lock& js, - kj::Maybe> maybeError = kj::none) override { + void release(jsg::Lock& js, kj::Maybe> maybeError = kj::none) override { KJ_IF_SOME(error, maybeError) { cancel(js, error); } @@ -122,7 +126,7 @@ private: jsg::Promise read(jsg::Lock& js) override; - void visitForGc(jsg::GcVisitor& visitor) ; + void visitForGc(jsg::GcVisitor& visitor); JSG_MEMORY_INFO(PipeLocked) { tracker.trackField("writableStreamRef", writableStreamRef); @@ -156,15 +160,15 @@ public: void visitForGc(jsg::GcVisitor& visitor); - bool pipeLock(WritableStream& owner, - jsg::Ref source, - PipeToOptions& options); + bool pipeLock(WritableStream& owner, jsg::Ref source, PipeToOptions& options); void releasePipeLock(); JSG_MEMORY_INFO(WritableLockImpl) { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(unlocked, Unlocked) {} - KJ_CASE_ONEOF(locked, Locked) {} + KJ_CASE_ONEOF(unlocked, Unlocked) { + } + KJ_CASE_ONEOF(locked, Locked) { + } KJ_CASE_ONEOF(writerLocked, WriterLocked) { tracker.trackField("writerLocked", writerLocked); } @@ -184,9 +188,7 @@ private: bool pipeThrough; kj::Maybe> maybeSignal; - kj::Maybe> checkSignal( - jsg::Lock& js, - Controller& self); + kj::Maybe> checkSignal(jsg::Lock& js, Controller& self); JSG_MEMORY_INFO(PipeLocked) { tracker.trackField("readableStreamRef", readableStreamRef); @@ -218,10 +220,7 @@ bool ReadableLockImpl::lock() { } template -bool ReadableLockImpl::lockReader( - jsg::Lock& js, - Controller& self, - Reader& reader) { +bool ReadableLockImpl::lockReader(jsg::Lock& js, Controller& self, Reader& reader) { if (isLockedToReader()) { return false; } @@ -244,17 +243,17 @@ bool ReadableLockImpl::lockReader( template void ReadableLockImpl::releaseReader( - Controller& self, - Reader& reader, - kj::Maybe maybeJs) { + Controller& self, Reader& reader, kj::Maybe maybeJs) { KJ_IF_SOME(locked, state.template tryGet()) { KJ_ASSERT(&locked.getReader() == &reader); KJ_IF_SOME(js, maybeJs) { auto reason = js.typeError("This ReadableStream reader has been released."_kj); KJ_SWITCH_ONEOF(self.state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} - KJ_CASE_ONEOF(errored, StreamStates::Errored) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } + KJ_CASE_ONEOF(errored, StreamStates::Errored) { + } KJ_CASE_ONEOF(consumer, kj::Own) { consumer->cancelPendingReads(js, reason); } @@ -283,8 +282,7 @@ void ReadableLockImpl::releaseReader( template kj::Maybe ReadableLockImpl::tryPipeLock( - Controller& self, - jsg::Ref destination) { + Controller& self, jsg::Ref destination) { if (isLockedToReader()) { return kj::none; } @@ -295,8 +293,10 @@ kj::Maybe ReadableLockImpl void ReadableLockImpl::visitForGc(jsg::GcVisitor& visitor) { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(locked, Locked) {} - KJ_CASE_ONEOF(locked, Unlocked) {} + KJ_CASE_ONEOF(locked, Locked) { + } + KJ_CASE_ONEOF(locked, Unlocked) { + } KJ_CASE_ONEOF(locked, PipeLocked) { visitor.visit(locked); } @@ -323,8 +323,10 @@ void ReadableLockImpl::onClose(jsg::Lock& js) { KJ_CASE_ONEOF(locked, ReadableLockImpl::PipeLocked) { state.template init(); } - KJ_CASE_ONEOF(locked, Locked) {} - KJ_CASE_ONEOF(locked, Unlocked) {} + KJ_CASE_ONEOF(locked, Locked) { + } + KJ_CASE_ONEOF(locked, Unlocked) { + } } } @@ -345,8 +347,10 @@ void ReadableLockImpl::onError(jsg::Lock& js, v8::Local r KJ_CASE_ONEOF(locked, ReadableLockImpl::PipeLocked) { state.template init(); } - KJ_CASE_ONEOF(locked, Locked) {} - KJ_CASE_ONEOF(locked, Unlocked) {} + KJ_CASE_ONEOF(locked, Locked) { + } + KJ_CASE_ONEOF(locked, Unlocked) { + } } } @@ -363,7 +367,7 @@ jsg::Promise ReadableLockImpl::PipeLocked::read(jsg::Loc } template -void ReadableLockImpl::PipeLocked::visitForGc(jsg::GcVisitor &visitor) { +void ReadableLockImpl::PipeLocked::visitForGc(jsg::GcVisitor& visitor) { visitor.visit(writableStreamRef); } @@ -406,23 +410,22 @@ bool WritableLockImpl::lockWriter(jsg::Lock& js, Controller& self, W template void WritableLockImpl::releaseWriter( - Controller& self, - Writer& writer, - kj::Maybe maybeJs) { + Controller& self, Writer& writer, kj::Maybe maybeJs) { auto& locked = state.template get(); KJ_ASSERT(&locked.getWriter() == &writer); KJ_IF_SOME(js, maybeJs) { KJ_SWITCH_ONEOF(self.state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} - KJ_CASE_ONEOF(errored, StreamStates::Errored) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } + KJ_CASE_ONEOF(errored, StreamStates::Errored) { + } KJ_CASE_ONEOF(controller, jsg::Ref) { - controller->cancelPendingWrites(js, - js.typeError("This WritableStream writer has been released."_kjc)); + controller->cancelPendingWrites( + js, js.typeError("This WritableStream writer has been released."_kjc)); } } - maybeRejectPromise(js, - locked.getClosedFulfiller(), + maybeRejectPromise(js, locked.getClosedFulfiller(), js.v8TypeError("This WritableStream writer has been released."_kjc)); } locked.clear(); @@ -439,16 +442,14 @@ void WritableLockImpl::releaseWriter( template bool WritableLockImpl::pipeLock( - WritableStream& owner, - jsg::Ref source, - PipeToOptions& options) { + WritableStream& owner, jsg::Ref source, PipeToOptions& options) { if (isLockedToWriter()) { return false; } auto& sourceLock = KJ_ASSERT_NONNULL(source->getController().tryPipeLock(owner.addRef())); - state.template init(PipeLocked { + state.template init(PipeLocked{ .source = sourceLock, .readableStreamRef = kj::mv(source), .preventAbort = options.preventAbort.orDefault(false), @@ -470,8 +471,10 @@ void WritableLockImpl::releasePipeLock() { template void WritableLockImpl::visitForGc(jsg::GcVisitor& visitor) { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(locked, Unlocked) {} - KJ_CASE_ONEOF(locked, Locked) {} + KJ_CASE_ONEOF(locked, Unlocked) { + } + KJ_CASE_ONEOF(locked, Locked) { + } KJ_CASE_ONEOF(locked, WriterLocked) { visitor.visit(locked); } @@ -486,8 +489,7 @@ void WritableLockImpl::visitForGc(jsg::GcVisitor& visitor) { template kj::Maybe> WritableLockImpl::PipeLocked::checkSignal( - jsg::Lock& js, - Controller& self) { + jsg::Lock& js, Controller& self) { KJ_IF_SOME(signal, maybeSignal) { if ((signal)->getAborted()) { auto reason = signal->getReason(js); @@ -497,13 +499,8 @@ kj::Maybe> WritableLockImpl::PipeLocked::checkSig source.release(js); } if (!preventAbort) { - return self.abort(js, reason).then(js, - JSG_VISITABLE_LAMBDA((this, reason = reason.addRef(js), ref = self.addRef()), - (reason, ref), (jsg::Lock& js) { - return rejectedMaybeHandledPromise( - js, - reason.getHandle(js), - pipeThrough); + return self.abort(js, reason).then(js, JSG_VISITABLE_LAMBDA((this, reason = reason.addRef(js), ref = self.addRef()), (reason, ref), (jsg::Lock& js) { + return rejectedMaybeHandledPromise(js, reason.getHandle(js), pipeThrough); })); } return rejectedMaybeHandledPromise(js, reason, pipeThrough); @@ -515,19 +512,15 @@ kj::Maybe> WritableLockImpl::PipeLocked::checkSig auto maybeAddFunctor(jsg::Lock& js, auto promise, auto onSuccess, auto onFailure) { if (IoContext::hasCurrent()) { auto& ioContext = IoContext::current(); - return promise.then(js, ioContext.addFunctor(kj::mv(onSuccess)), - ioContext.addFunctor(kj::mv(onFailure))); + return promise.then( + js, ioContext.addFunctor(kj::mv(onSuccess)), ioContext.addFunctor(kj::mv(onFailure))); } else { return promise.then(js, kj::mv(onSuccess), kj::mv(onFailure)); } } jsg::Promise maybeRunAlgorithm( - jsg::Lock& js, - auto& maybeAlgorithm, - auto&& onSuccess, - auto&& onFailure, - auto&&...args) { + jsg::Lock& js, auto& maybeAlgorithm, auto&& onSuccess, auto&& onFailure, auto&&... args) { // The algorithm is a JavaScript function mapped through jsg::Function. // It is expected to return a Promise mapped via jsg::Promise. If the // function returns synchronously, the jsg::Promise wrapper ensures @@ -548,22 +541,19 @@ jsg::Promise maybeRunAlgorithm( return js.tryCatch([&] { if (IoContext::hasCurrent()) { auto& ioContext = IoContext::current(); - return js.tryCatch([&] { - return algorithm(js, kj::fwd(args)...); - }, [&](jsg::Value&& exception) { - return js.rejectedPromise(kj::mv(exception)); - }).then(js, ioContext.addFunctor(kj::mv(onSuccess)), - ioContext.addFunctor(kj::mv(onFailure))); + return js + .tryCatch([&] { return algorithm(js, kj::fwd(args)...); }, + [&](jsg::Value&& exception) { return js.rejectedPromise(kj::mv(exception)); }) + .then(js, ioContext.addFunctor(kj::mv(onSuccess)), + ioContext.addFunctor(kj::mv(onFailure))); } else { - return js.tryCatch([&] { - return algorithm(js, kj::fwd(args)...); - }, [&](jsg::Value&& exception) { + return js + .tryCatch([&] { return algorithm(js, kj::fwd(args)...); }, + [&](jsg::Value&& exception) { return js.rejectedPromise(kj::mv(exception)); }).then(js, kj::mv(onSuccess), kj::mv(onFailure)); } - }, [&](jsg::Value&& exception) { - return js.rejectedPromise(kj::mv(exception)); - }); + }, [&](jsg::Value&& exception) { return js.rejectedPromise(kj::mv(exception)); }); } // If the algorithm does not exist, we just handle it as a success and move on. @@ -571,8 +561,8 @@ jsg::Promise maybeRunAlgorithm( return js.resolvedPromise(); } -int getHighWaterMark(const UnderlyingSource& underlyingSource, - const StreamQueuingStrategy& queuingStrategy) { +int getHighWaterMark( + const UnderlyingSource& underlyingSource, const StreamQueuingStrategy& queuingStrategy) { bool isBytes = underlyingSource.type.map([](auto& s) { return s == "bytes"; }).orDefault(false); return queuingStrategy.highWaterMark.orDefault(isBytes ? 0 : 1); } @@ -586,8 +576,7 @@ int getHighWaterMark(const UnderlyingSource& underlyingSource, // incremented until the read operation completes and deferring // a state change until it is 0 template -jsg::Promise deferControllerStateChange( - jsg::Lock& js, +jsg::Promise deferControllerStateChange(jsg::Lock& js, Controller& controller, kj::FunctionParam()> readCallback) { bool decrementCount = true; @@ -668,8 +657,7 @@ public: jsg::Ref addRef() override; - void setup( - jsg::Lock& js, + void setup(jsg::Lock& js, jsg::Optional maybeUnderlyingSource, jsg::Optional maybeQueuingStrategy) override; @@ -680,9 +668,7 @@ public: // is still pending, the ReadableStream will be no longer usable and any // data still in the queue will be dropped. Pending read requests will be // rejected if a reason is given, or resolved with no data otherwise. - jsg::Promise cancel( - jsg::Lock& js, - jsg::Optional> reason) override; + jsg::Promise cancel(jsg::Lock& js, jsg::Optional> reason) override; void doClose(jsg::Lock& js); @@ -708,16 +694,13 @@ public: kj::Maybe getDesiredSize(); jsg::Promise pipeTo( - jsg::Lock& js, - WritableStreamController& destination, - PipeToOptions options) override; + jsg::Lock& js, WritableStreamController& destination, PipeToOptions options) override; - kj::Promise> pumpTo(jsg::Lock& js, kj::Own, bool end) - override; + kj::Promise> pumpTo( + jsg::Lock& js, kj::Own, bool end) override; kj::Maybe> read( - jsg::Lock& js, - kj::Maybe byobOptions) override; + jsg::Lock& js, kj::Maybe byobOptions) override; // See the comment for releaseReader in common.h for details on the use of maybeJs void releaseReader(Reader& reader, kj::Maybe maybeJs) override; @@ -754,9 +737,10 @@ private: kj::Maybe owner; kj::OneOf, - kj::Own> state = StreamStates::Closed(); + StreamStates::Errored, + kj::Own, + kj::Own> + state = StreamStates::Closed(); kj::Maybe expectedLength = kj::none; @@ -784,10 +768,9 @@ private: friend ReadableLockImpl::PipeLocked; template - friend jsg::Promise deferControllerStateChange( - jsg::Lock& js, - Controller& controller, - kj::FunctionParam()> readCallback); + friend jsg::Promise deferControllerStateChange(jsg::Lock& js, + Controller& controller, + kj::FunctionParam()> readCallback); }; // The WritableStreamJsController provides the implementation of custom @@ -807,8 +790,7 @@ public: KJ_DISALLOW_COPY_AND_MOVE(WritableStreamJsController); - jsg::Promise abort(jsg::Lock& js, - jsg::Optional> reason) override; + jsg::Promise abort(jsg::Lock& js, jsg::Optional> reason) override; jsg::Ref addRef() override; @@ -833,7 +815,9 @@ public: bool isStarted(); - inline bool isWritable() const { return state.is(); } + inline bool isWritable() const { + return state.is(); + } bool lockWriter(jsg::Lock& js, Writer& writer) override; @@ -849,27 +833,25 @@ public: void setOwnerRef(WritableStream& stream) override; - void setup( - jsg::Lock& js, + void setup(jsg::Lock& js, jsg::Optional maybeUnderlyingSink, jsg::Optional maybeQueuingStrategy) override; kj::Maybe> tryPipeFrom( - jsg::Lock& js, - jsg::Ref source, - PipeToOptions options) override; + jsg::Lock& js, jsg::Ref source, PipeToOptions options) override; void updateBackpressure(jsg::Lock& js, bool backpressure); - jsg::Promise write(jsg::Lock& js, - jsg::Optional> value) override; + jsg::Promise write(jsg::Lock& js, jsg::Optional> value) override; void visitForGc(jsg::GcVisitor& visitor) override; bool isClosedOrClosing() override; bool isErrored() override; - inline bool isByteOriented() const override { return false; } + inline bool isByteOriented() const override { + return false; + } void setPendingClosure() override { KJ_UNIMPLEMENTED("only implemented for WritableStreamInternalController"); @@ -901,8 +883,7 @@ kj::Own newWritableStreamJsController() { template ReadableImpl::ReadableImpl( - UnderlyingSource underlyingSource, - StreamQueuingStrategy queuingStrategy) + UnderlyingSource underlyingSource, StreamQueuingStrategy queuingStrategy) : state(Queue(getHighWaterMark(underlyingSource, queuingStrategy))), algorithms(kj::mv(underlyingSource), kj::mv(queuingStrategy)) {} @@ -917,12 +898,12 @@ void ReadableImpl::start(jsg::Lock& js, jsg::Ref self) { pullIfNeeded(js, kj::mv(self)); }); - auto onFailure = JSG_VISITABLE_LAMBDA((this, self = self.addRef()), (self), - (jsg::Lock& js, jsg::Value reason) { - started = true; - starting = false; - doError(js, kj::mv(reason)); - }); + auto onFailure = JSG_VISITABLE_LAMBDA( + (this, self = self.addRef()), (self), (jsg::Lock& js, jsg::Value reason) { + started = true; + starting = false; + doError(js, kj::mv(reason)); + }); maybeRunAlgorithm(js, algorithms.start, kj::mv(onSuccess), kj::mv(onFailure), kj::mv(self)); algorithms.start = kj::none; @@ -931,8 +912,12 @@ void ReadableImpl::start(jsg::Lock& js, jsg::Ref self) { template size_t ReadableImpl::consumerCount() { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) { return 0; } - KJ_CASE_ONEOF(errored, StreamStates::Errored) { return 0; } + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + return 0; + } + KJ_CASE_ONEOF(errored, StreamStates::Errored) { + return 0; + } KJ_CASE_ONEOF(queue, Queue) { return queue.getConsumerCount(); } @@ -942,9 +927,7 @@ size_t ReadableImpl::consumerCount() { template jsg::Promise ReadableImpl::cancel( - jsg::Lock& js, - jsg::Ref self, - v8::Local reason) { + jsg::Lock& js, jsg::Ref self, v8::Local reason) { KJ_SWITCH_ONEOF(state) { KJ_CASE_ONEOF(closed, StreamStates::Closed) { // We are already closed. There's nothing to cancel. @@ -977,7 +960,7 @@ jsg::Promise ReadableImpl::cancel( } auto prp = js.newPromiseAndResolver(); - maybePendingCancel = PendingCancel { + maybePendingCancel = PendingCancel{ .fulfiller = kj::mv(prp.resolver), .promise = kj::mv(prp.promise), }; @@ -1000,32 +983,29 @@ bool ReadableImpl::canCloseOrEnqueue() { // that they called cancel. What we do want to do here, tho, is close the implementation // and trigger the cancel algorithm. template -void ReadableImpl::doCancel( - jsg::Lock& js, - jsg::Ref self, - v8::Local reason) { +void ReadableImpl::doCancel(jsg::Lock& js, jsg::Ref self, v8::Local reason) { state.template init(); auto onSuccess = JSG_VISITABLE_LAMBDA((this, self = self.addRef()), (self), (jsg::Lock& js) { doClose(js); KJ_IF_SOME(pendingCancel, maybePendingCancel) { - maybeResolvePromise(js, pendingCancel.fulfiller); + maybeResolvePromise(js, pendingCancel.fulfiller); } else { - // Else block to avert dangling else compiler warning. - } - }); - auto onFailure = JSG_VISITABLE_LAMBDA((this, self = self.addRef()), (self), - (jsg::Lock& js, jsg::Value reason) { - // We do not call doError() here because there's really no point. Everything - // that cares about the state of this controller impl has signaled that it - // no longer cares and has gone away. - doClose(js); - KJ_IF_SOME(pendingCancel, maybePendingCancel) { - maybeRejectPromise(js, pendingCancel.fulfiller, reason.getHandle(js)); - } else { - // Else block to avert dangling else compiler warning. + // Else block to avert dangling else compiler warning. } }); + auto onFailure = JSG_VISITABLE_LAMBDA( + (this, self = self.addRef()), (self), (jsg::Lock& js, jsg::Value reason) { + // We do not call doError() here because there's really no point. Everything + // that cares about the state of this controller impl has signaled that it + // no longer cares and has gone away. + doClose(js); + KJ_IF_SOME(pendingCancel, maybePendingCancel) { + maybeRejectPromise(js, pendingCancel.fulfiller, reason.getHandle(js)); + } else { + // Else block to avert dangling else compiler warning. + } + }); maybeRunAlgorithm(js, algorithms.cancel, kj::mv(onSuccess), kj::mv(onFailure), reason); } @@ -1044,8 +1024,8 @@ void ReadableImpl::close(jsg::Lock& js) { auto& queue = state.template get(); if (queue.hasPartiallyFulfilledRead()) { - auto error = js.v8Ref(js.v8TypeError( - "This ReadableStream was closed with a partial read pending.")); + auto error = + js.v8Ref(js.v8TypeError("This ReadableStream was closed with a partial read pending.")); doError(js, error.addRef(js)); js.throwException(kj::mv(error)); return; @@ -1127,16 +1107,16 @@ void ReadableImpl::pullIfNeeded(jsg::Lock& js, jsg::Ref self) { auto onSuccess = JSG_VISITABLE_LAMBDA((this, self = self.addRef()), (self), (jsg::Lock& js) { pulling = false; if (pullAgain) { - pullAgain = false; - pullIfNeeded(js, kj::mv(self)); + pullAgain = false; + pullIfNeeded(js, kj::mv(self)); } }); - auto onFailure = JSG_VISITABLE_LAMBDA((this, self = self.addRef()), (self), - (jsg::Lock& js, jsg::Value reason) { - pulling = false; - doError(js, kj::mv(reason)); - }); + auto onFailure = JSG_VISITABLE_LAMBDA( + (this, self = self.addRef()), (self), (jsg::Lock& js, jsg::Value reason) { + pulling = false; + doError(js, kj::mv(reason)); + }); maybeRunAlgorithm(js, algorithms.pull, kj::mv(onSuccess), kj::mv(onFailure), self.addRef()); } @@ -1144,7 +1124,8 @@ void ReadableImpl::pullIfNeeded(jsg::Lock& js, jsg::Ref self) { template void ReadableImpl::visitForGc(jsg::GcVisitor& visitor) { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } KJ_CASE_ONEOF(errored, StreamStates::Errored) { visitor.visit(errored); } @@ -1159,8 +1140,8 @@ void ReadableImpl::visitForGc(jsg::GcVisitor& visitor) { } template -kj::Own::Consumer> -ReadableImpl::getConsumer(kj::Maybe::StateListener&> listener) { +kj::Own::Consumer> ReadableImpl::getConsumer( + kj::Maybe::StateListener&> listener) { auto& queue = state.template get(); return kj::heap::Consumer>(queue, listener); } @@ -1174,9 +1155,7 @@ WritableImpl::WritableImpl(WritableStream& owner) template jsg::Promise WritableImpl::abort( - jsg::Lock& js, - jsg::Ref self, - v8::Local reason) { + jsg::Lock& js, jsg::Ref self, v8::Local reason) { signal->triggerAbort(js, jsg::JsValue(reason)); // We have to check this again after the AbortSignal is triggered. @@ -1196,11 +1175,7 @@ jsg::Promise WritableImpl::abort( reason = js.v8Undefined(); } - KJ_DEFER( - if (!wasAlreadyErroring) { - startErroring(js, kj::mv(self), reason); - } - ); + KJ_DEFER(if (!wasAlreadyErroring) { startErroring(js, kj::mv(self), reason); }); maybePendingAbort = PendingAbort(js, reason, wasAlreadyErroring); return KJ_ASSERT_NONNULL(maybePendingAbort).whenResolved(js); @@ -1238,14 +1213,13 @@ void WritableImpl::advanceQueueIfNeeded(jsg::Lock& js, jsg::Ref self KJ_ASSERT_NONNULL(closeRequest); inFlightClose = kj::mv(closeRequest); - auto onSuccess = JSG_VISITABLE_LAMBDA((this, self = self.addRef()), (self), (jsg::Lock& js) { - finishInFlightClose(js, kj::mv(self)); - }); + auto onSuccess = JSG_VISITABLE_LAMBDA((this, self = self.addRef()), (self), + (jsg::Lock& js) { finishInFlightClose(js, kj::mv(self)); }); auto onFailure = JSG_VISITABLE_LAMBDA( (this, self = self.addRef()), (self), (jsg::Lock& js, jsg::Value reason) { - finishInFlightClose(js, kj::mv(self), reason.getHandle(js)); - }); + finishInFlightClose(js, kj::mv(self), reason.getHandle(js)); + }); maybeRunAlgorithm(js, algorithms.close, kj::mv(onSuccess), kj::mv(onFailure)); } @@ -1258,36 +1232,32 @@ void WritableImpl::advanceQueueIfNeeded(jsg::Lock& js, jsg::Ref self auto size = req.size; inFlightWrite = kj::mv(req); - auto onSuccess = JSG_VISITABLE_LAMBDA( - (this, self = self.addRef(), size), (self), (jsg::Lock& js) { - amountBuffered -= size; - finishInFlightWrite(js, self.addRef()); - KJ_ASSERT(isWritable() || state.template is()); - if (!isCloseQueuedOrInFlight() && isWritable()) { - updateBackpressure(js); - } - advanceQueueIfNeeded(js, kj::mv(self)); - }); + auto onSuccess = + JSG_VISITABLE_LAMBDA((this, self = self.addRef(), size), (self), (jsg::Lock& js) { + amountBuffered -= size; + finishInFlightWrite(js, self.addRef()); + KJ_ASSERT(isWritable() || state.template is()); + if (!isCloseQueuedOrInFlight() && isWritable()) { + updateBackpressure(js); + } + advanceQueueIfNeeded(js, kj::mv(self)); + }); - auto onFailure = JSG_VISITABLE_LAMBDA((this, self = self.addRef(), size), (self), - (jsg::Lock& js, jsg::Value reason) { - amountBuffered -= size; - finishInFlightWrite(js, kj::mv(self), reason.getHandle(js)); - }); + auto onFailure = JSG_VISITABLE_LAMBDA( + (this, self = self.addRef(), size), (self), (jsg::Lock& js, jsg::Value reason) { + amountBuffered -= size; + finishInFlightWrite(js, kj::mv(self), reason.getHandle(js)); + }); - maybeRunAlgorithm(js, - algorithms.write, - kj::mv(onSuccess), - kj::mv(onFailure), - value.getHandle(js), - self.addRef()); + maybeRunAlgorithm(js, algorithms.write, kj::mv(onSuccess), kj::mv(onFailure), value.getHandle(js), + self.addRef()); } template jsg::Promise WritableImpl::close(jsg::Lock& js, jsg::Ref self) { KJ_ASSERT(isWritable() || state.template is()); - JSG_REQUIRE(!isCloseQueuedOrInFlight(), TypeError, - "Cannot close a writer that is already being closed"); + JSG_REQUIRE( + !isCloseQueuedOrInFlight(), TypeError, "Cannot close a writer that is already being closed"); auto prp = js.newPromiseAndResolver(); closeRequest = kj::mv(prp.resolver); @@ -1304,9 +1274,7 @@ jsg::Promise WritableImpl::close(jsg::Lock& js, jsg::Ref self) template void WritableImpl::dealWithRejection( - jsg::Lock& js, - jsg::Ref self, - v8::Local reason) { + jsg::Lock& js, jsg::Ref self, v8::Local reason) { if (isWritable()) { return startErroring(js, kj::mv(self), reason); } @@ -1352,10 +1320,7 @@ void WritableImpl::doError(jsg::Lock& js, v8::Local reason) { } template -void WritableImpl::error( - jsg::Lock& js, - jsg::Ref self, - v8::Local reason) { +void WritableImpl::error(jsg::Lock& js, jsg::Ref self, v8::Local reason) { if (isWritable()) { algorithms.clear(); startErroring(js, kj::mv(self), reason); @@ -1388,12 +1353,12 @@ void WritableImpl::finishErroring(jsg::Lock& js, jsg::Ref self) { rejectCloseAndClosedPromiseIfNeeded(js); }); - auto onFailure = JSG_VISITABLE_LAMBDA((this, self = self.addRef()), (self), - (jsg::Lock& js, jsg::Value reason) { - auto& pendingAbort = KJ_ASSERT_NONNULL(maybePendingAbort); - pendingAbort.fail(js, reason.getHandle(js)); - rejectCloseAndClosedPromiseIfNeeded(js); - }); + auto onFailure = JSG_VISITABLE_LAMBDA( + (this, self = self.addRef()), (self), (jsg::Lock& js, jsg::Value reason) { + auto& pendingAbort = KJ_ASSERT_NONNULL(maybePendingAbort); + pendingAbort.fail(js, reason.getHandle(js)); + rejectCloseAndClosedPromiseIfNeeded(js); + }); maybeRunAlgorithm(js, algorithms.abort, kj::mv(onSuccess), kj::mv(onFailure), reason); return; @@ -1403,9 +1368,7 @@ void WritableImpl::finishErroring(jsg::Lock& js, jsg::Ref self) { template void WritableImpl::finishInFlightClose( - jsg::Lock& js, - jsg::Ref self, - kj::Maybe> maybeReason) { + jsg::Lock& js, jsg::Ref self, kj::Maybe> maybeReason) { algorithms.clear(); KJ_ASSERT_NONNULL(inFlightClose); KJ_ASSERT(isWritable() || state.template is()); @@ -1436,9 +1399,7 @@ void WritableImpl::finishInFlightClose( template void WritableImpl::finishInFlightWrite( - jsg::Lock& js, - jsg::Ref self, - kj::Maybe> maybeReason) { + jsg::Lock& js, jsg::Ref self, kj::Maybe> maybeReason) { auto& write = KJ_ASSERT_NONNULL(inFlightWrite); KJ_IF_SOME(reason, maybeReason) { @@ -1460,16 +1421,14 @@ bool WritableImpl::isCloseQueuedOrInFlight() { template void WritableImpl::rejectCloseAndClosedPromiseIfNeeded(jsg::Lock& js) { algorithms.clear(); - auto reason = - KJ_ASSERT_NONNULL(state.template tryGet()).getHandle(js); + auto reason = KJ_ASSERT_NONNULL(state.template tryGet()).getHandle(js); maybeRejectPromise(js, closeRequest, reason); PendingAbort::dequeue(maybePendingAbort); doError(js, reason); } template -void WritableImpl::setup( - jsg::Lock& js, +void WritableImpl::setup(jsg::Lock& js, jsg::Ref self, UnderlyingSink underlyingSink, StreamQueuingStrategy queuingStrategy) { @@ -1487,13 +1446,13 @@ void WritableImpl::setup( KJ_ASSERT(isWritable() || state.template is()); if (isWritable()) { - // Only resolve the ready promise if an abort is not pending. - // It will have been rejected already. - KJ_IF_SOME(owner, tryGetOwner()) { - owner.maybeResolveReadyPromise(js); - } else { - // Else block to avert dangling else compiler warning. - } + // Only resolve the ready promise if an abort is not pending. + // It will have been rejected already. + KJ_IF_SOME(owner, tryGetOwner()) { + owner.maybeResolveReadyPromise(js); + } else { + // Else block to avert dangling else compiler warning. + } } started = true; @@ -1501,19 +1460,19 @@ void WritableImpl::setup( advanceQueueIfNeeded(js, kj::mv(self)); }); - auto onFailure = JSG_VISITABLE_LAMBDA((this, self = self.addRef()), (self), - (jsg::Lock& js, jsg::Value reason) { - auto handle = reason.getHandle(js); - KJ_ASSERT(isWritable() || state.template is()); - KJ_IF_SOME(owner, tryGetOwner()) { - owner.maybeRejectReadyPromise(js, handle); - } else { - // Else block to avert dangling else compiler warning. - } - started = true; - starting = false; - dealWithRejection(js, kj::mv(self), handle); - }); + auto onFailure = JSG_VISITABLE_LAMBDA( + (this, self = self.addRef()), (self), (jsg::Lock& js, jsg::Value reason) { + auto handle = reason.getHandle(js); + KJ_ASSERT(isWritable() || state.template is()); + KJ_IF_SOME(owner, tryGetOwner()) { + owner.maybeRejectReadyPromise(js, handle); + } else { + // Else block to avert dangling else compiler warning. + } + started = true; + starting = false; + dealWithRejection(js, kj::mv(self), handle); + }); backpressure = getDesiredSize() < 0; @@ -1522,9 +1481,7 @@ void WritableImpl::setup( template void WritableImpl::startErroring( - jsg::Lock& js, - jsg::Ref self, - v8::Local reason) { + jsg::Lock& js, jsg::Ref self, v8::Local reason) { KJ_ASSERT(isWritable()); KJ_IF_SOME(owner, tryGetOwner()) { owner.maybeRejectReadyPromise(js, reason); @@ -1552,12 +1509,12 @@ void WritableImpl::updateBackpressure(jsg::Lock& js) { if (warnAboutExcessiveBackpressure && (amountBuffered >= warningMultiplier * highWaterMark)) { excessiveBackpressureWarningCount++; auto warning = kj::str("A WritableStream is experiencing excessive backpressure. " - "The current write buffer size is ", amountBuffered, - ", which is greater than or equal to ", warningMultiplier, - " times the high water mark of ", highWaterMark, - ". Streams that consistently exceed the configured high water ", - "mark may cause excessive memory usage. ", - "(Count ", excessiveBackpressureWarningCount, ")"); + "The current write buffer size is ", + amountBuffered, ", which is greater than or equal to ", warningMultiplier, + " times the high water mark of ", highWaterMark, + ". Streams that consistently exceed the configured high water ", + "mark may cause excessive memory usage. ", "(Count ", excessiveBackpressureWarningCount, + ")"); js.logWarning(warning); warnAboutExcessiveBackpressure = false; } @@ -1574,16 +1531,12 @@ void WritableImpl::updateBackpressure(jsg::Lock& js) { template jsg::Promise WritableImpl::write( - jsg::Lock& js, - jsg::Ref self, - v8::Local value) { + jsg::Lock& js, jsg::Ref self, v8::Local value) { size_t size = 1; KJ_IF_SOME(sizeFunc, algorithms.size) { kj::Maybe failure; - js.tryCatch([&] { - size = sizeFunc(js, value); - }, [&](jsg::Value exception) { + js.tryCatch([&] { size = sizeFunc(js, value); }, [&](jsg::Value exception) { startErroring(js, self.addRef(), exception.getHandle(js)); failure = kj::mv(exception); }); @@ -1607,7 +1560,7 @@ jsg::Promise WritableImpl::write( KJ_ASSERT(isWritable()); auto prp = js.newPromiseAndResolver(); - writeRequests.push_back(WriteRequest { + writeRequests.push_back(WriteRequest{ .resolver = kj::mv(prp.resolver), .value = js.v8Ref(value), .size = size, @@ -1620,10 +1573,12 @@ jsg::Promise WritableImpl::write( } template -void WritableImpl::visitForGc(jsg::GcVisitor &visitor) { +void WritableImpl::visitForGc(jsg::GcVisitor& visitor) { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} - KJ_CASE_ONEOF(writable, Writable) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } + KJ_CASE_ONEOF(writable, Writable) { + } KJ_CASE_ONEOF(error, StreamStates::Errored) { visitor.visit(error); } @@ -1631,12 +1586,7 @@ void WritableImpl::visitForGc(jsg::GcVisitor &visitor) { visitor.visit(erroring.reason); } } - visitor.visit(inFlightWrite, - inFlightClose, - closeRequest, - algorithms, - signal, - maybePendingAbort); + visitor.visit(inFlightWrite, inFlightClose, closeRequest, algorithms, signal, maybePendingAbort); visitor.visitAll(writeRequests); } @@ -1647,7 +1597,7 @@ bool WritableImpl::isWritable() const { template void WritableImpl::cancelPendingWrites(jsg::Lock& js, jsg::JsValue reason) { - for (auto& write : writeRequests) { + for (auto& write: writeRequests) { write.resolver.reject(js, reason); } writeRequests.clear(); @@ -1663,22 +1613,20 @@ struct ReadableState { ReadableStreamJsController& owner; ReadableState(Controller controller, - kj::Own consumer, - ReadableStreamJsController& owner) + kj::Own consumer, + ReadableStreamJsController& owner) : controller(kj::mv(controller)), consumer(kj::mv(consumer)), owner(owner) {} ReadableState(Controller controller, - typename Queue::ConsumerImpl::StateListener& listener, - ReadableStreamJsController& owner) - : ReadableState(controller.addRef(), - controller->getConsumer(listener), - owner) {} + typename Queue::ConsumerImpl::StateListener& listener, + ReadableStreamJsController& owner) + : ReadableState(controller.addRef(), controller->getConsumer(listener), owner) {} ReadableState clone(jsg::Lock& js, - typename Queue::ConsumerImpl::StateListener& listener, - ReadableStreamJsController& owner) { + typename Queue::ConsumerImpl::StateListener& listener, + ReadableStreamJsController& owner) { return ReadableState(controller.addRef(), consumer->clone(js, listener), owner); } }; @@ -1701,8 +1649,7 @@ struct ValueReadable final: private api::ValueQueue::ConsumerImpl::StateListener } } - ValueReadable(DefaultController controller, - ReadableStreamJsController& owner) + ValueReadable(DefaultController controller, ReadableStreamJsController& owner) : state(State(kj::mv(controller), *this, owner)) {} ValueReadable(jsg::Lock& js, ReadableStreamJsController& owner, ValueReadable& other) @@ -1728,14 +1675,15 @@ struct ValueReadable final: private api::ValueQueue::ConsumerImpl::StateListener jsg::Promise read(jsg::Lock& js) { KJ_IF_SOME(s, state) { auto prp = js.newPromiseAndResolver(); - s.consumer->read(js, ValueQueue::ReadRequest { - .resolver = kj::mv(prp.resolver), - }); + s.consumer->read(js, + ValueQueue::ReadRequest{ + .resolver = kj::mv(prp.resolver), + }); return kj::mv(prp.promise); } // We are canceled! There's nothing to do. - return js.resolvedPromise(ReadResult { .done = true }); + return js.resolvedPromise(ReadResult{.done = true}); } jsg::Promise cancel(jsg::Lock& js, jsg::Optional> maybeReason) { @@ -1780,7 +1728,9 @@ struct ValueReadable final: private api::ValueQueue::ConsumerImpl::StateListener // Called by the consumer when it has a queued pending read and needs // data to be provided to fulfill it. We need to notify the controller // to initiate pulling to provide the data. - KJ_IF_SOME(s, state) { s.controller->pull(js); } + KJ_IF_SOME(s, state) { + s.controller->pull(js); + } } kj::Maybe getDesiredSize() { @@ -1818,9 +1768,8 @@ struct ByteReadable final: private api::ByteQueue::ConsumerImpl::StateListener { } } - ByteReadable(ByobController controller, - ReadableStreamJsController& owner, - int autoAllocateChunkSize) + ByteReadable( + ByobController controller, ReadableStreamJsController& owner, int autoAllocateChunkSize) : state(State(kj::mv(controller), *this, owner)), autoAllocateChunkSize(autoAllocateChunkSize) {} @@ -1846,8 +1795,7 @@ struct ByteReadable final: private api::ByteQueue::ConsumerImpl::StateListener { } jsg::Promise read( - jsg::Lock& js, - kj::Maybe byobOptions) { + jsg::Lock& js, kj::Maybe byobOptions) { KJ_IF_SOME(s, state) { auto prp = js.newPromiseAndResolver(); @@ -1858,25 +1806,23 @@ struct ByteReadable final: private api::ByteQueue::ConsumerImpl::StateListener { // with the element size. No matter what, atLeast cannot be less than 1. auto atLeast = kj::max(source.getElementSize(), byob.atLeast.orDefault(1)); atLeast = kj::max(1, atLeast - (atLeast % source.getElementSize())); - s.consumer->read(js, ByteQueue::ReadRequest( - kj::mv(prp.resolver), - { - .store = jsg::BufferSource(js, source.detach(js)), - .atLeast = atLeast, - .type = ByteQueue::ReadRequest::Type::BYOB, - } - )); + s.consumer->read(js, + ByteQueue::ReadRequest(kj::mv(prp.resolver), + { + .store = jsg::BufferSource(js, source.detach(js)), + .atLeast = atLeast, + .type = ByteQueue::ReadRequest::Type::BYOB, + })); } else { KJ_IF_SOME(store, jsg::BufferSource::tryAlloc(js, autoAllocateChunkSize)) { // Ensure that the handle is created here so that the size of the buffer // is accounted for in the isolate memory tracking. - s.consumer->read(js, ByteQueue::ReadRequest( - kj::mv(prp.resolver), - { - .store = kj::mv(store), - .type = ByteQueue::ReadRequest::Type::BYOB, - } - )); + s.consumer->read(js, + ByteQueue::ReadRequest(kj::mv(prp.resolver), + { + .store = kj::mv(store), + .type = ByteQueue::ReadRequest::Type::BYOB, + })); } else { prp.resolver.reject(js, js.v8Error("Failed to allocate buffer for read.")); } @@ -1892,12 +1838,12 @@ struct ByteReadable final: private api::ByteQueue::ConsumerImpl::StateListener { jsg::BufferSource source(js, byob.bufferView.getHandle(js)); auto store = source.detach(js); store.consume(store.size()); - return js.resolvedPromise(ReadResult { + return js.resolvedPromise(ReadResult{ .value = js.v8Ref(store.createHandle(js)), .done = true, }); } else { - return js.resolvedPromise(ReadResult { .done = true }); + return js.resolvedPromise(ReadResult{.done = true}); } } @@ -1922,20 +1868,26 @@ struct ByteReadable final: private api::ByteQueue::ConsumerImpl::StateListener { void onConsumerClose(jsg::Lock& js) override { // Note that the owner may drop this readable in doClose so it // is not safe to access anything on this after calling doClose. - KJ_IF_SOME(s, state) { s.owner.doClose(js); } + KJ_IF_SOME(s, state) { + s.owner.doClose(js); + } } void onConsumerError(jsg::Lock& js, jsg::Value reason) override { // Note that the owner may drop this readable in doClose so it // is not safe to access anything on this after calling doError. - KJ_IF_SOME(s, state) { s.owner.doError(js, reason.getHandle(js)); }; + KJ_IF_SOME(s, state) { + s.owner.doError(js, reason.getHandle(js)); + }; } // Called by the consumer when it has a queued pending read and needs // data to be provided to fulfill it. We need to notify the controller // to initiate pulling to provide the data. void onConsumerWantsData(jsg::Lock& js) override { - KJ_IF_SOME(s, state) { s.controller->pull(js); } + KJ_IF_SOME(s, state) { + s.controller->pull(js); + } } kj::Maybe getDesiredSize() { @@ -1958,8 +1910,7 @@ struct ByteReadable final: private api::ByteQueue::ConsumerImpl::StateListener { // ======================================================================================= ReadableStreamDefaultController::ReadableStreamDefaultController( - UnderlyingSource underlyingSource, - StreamQueuingStrategy queuingStrategy) + UnderlyingSource underlyingSource, StreamQueuingStrategy queuingStrategy) : ioContext(tryGetIoContext()), impl(kj::mv(underlyingSource), kj::mv(queuingStrategy)) {} @@ -1992,8 +1943,7 @@ void ReadableStreamDefaultController::visitForGc(jsg::GcVisitor& visitor) { } jsg::Promise ReadableStreamDefaultController::cancel( - jsg::Lock& js, - jsg::Optional> maybeReason) { + jsg::Lock& js, jsg::Optional> maybeReason) { return impl.cancel(js, JSG_THIS, maybeReason.orDefault([&] { return js.v8Undefined(); })); } @@ -2002,8 +1952,7 @@ void ReadableStreamDefaultController::close(jsg::Lock& js) { } void ReadableStreamDefaultController::enqueue( - jsg::Lock& js, - jsg::Optional> chunk) { + jsg::Lock& js, jsg::Optional> chunk) { auto value = chunk.orDefault(js.v8Undefined()); JSG_REQUIRE(impl.canCloseOrEnqueue(), TypeError, "Unable to enqueue"); @@ -2011,9 +1960,7 @@ void ReadableStreamDefaultController::enqueue( size_t size = 1; bool errored = false; KJ_IF_SOME(sizeFunc, impl.algorithms.size) { - js.tryCatch([&] { - size = sizeFunc(js, value); - }, [&](jsg::Value exception) { + js.tryCatch([&] { size = sizeFunc(js, value); }, [&](jsg::Value exception) { impl.doError(js, kj::mv(exception)); errored = true; }); @@ -2043,9 +1990,7 @@ kj::Own ReadableStreamDefaultController::getConsumer( // ====================================================================================== ReadableStreamBYOBRequest::Impl::Impl( - jsg::Lock& js, - kj::Own readRequest, - ByobController controller) + jsg::Lock& js, kj::Own readRequest, ByobController controller) : readRequest(kj::mv(readRequest)), controller(kj::mv(controller)), view(js.v8Ref(this->readRequest->getView(js))) {} @@ -2056,15 +2001,13 @@ void ReadableStreamBYOBRequest::Impl::updateView(jsg::Lock& js) { } void ReadableStreamBYOBRequest::visitForGc(jsg::GcVisitor& visitor) { - KJ_IF_SOME(impl, maybeImpl) { - visitor.visit(impl.view, impl.controller); - } + KJ_IF_SOME(impl, maybeImpl) { + visitor.visit(impl.view, impl.controller); } +} ReadableStreamBYOBRequest::ReadableStreamBYOBRequest( - jsg::Lock& js, - kj::Own readRequest, - ByobController controller) + jsg::Lock& js, kj::Own readRequest, ByobController controller) : ioContext(tryGetIoContext()), maybeImpl(Impl(js, kj::mv(readRequest), kj::mv(controller))) {} @@ -2094,15 +2037,13 @@ void ReadableStreamBYOBRequest::invalidate(jsg::Lock& js) { } void ReadableStreamBYOBRequest::respond(jsg::Lock& js, int bytesWritten) { - auto& impl = JSG_REQUIRE_NONNULL(maybeImpl, - TypeError, - "This ReadableStreamBYOBRequest has been invalidated."); + auto& impl = JSG_REQUIRE_NONNULL( + maybeImpl, TypeError, "This ReadableStreamBYOBRequest has been invalidated."); JSG_REQUIRE(impl.view.getHandle(js)->ByteLength() > 0, TypeError, "Cannot respond with a zero-length or detached view"); if (!impl.controller->canCloseOrEnqueue()) { - JSG_REQUIRE(bytesWritten == 0, - TypeError, - "The bytesWritten must be zero after the stream is closed."); + JSG_REQUIRE( + bytesWritten == 0, TypeError, "The bytesWritten must be zero after the stream is closed."); KJ_ASSERT(impl.readRequest->isInvalidated()); invalidate(js); } else { @@ -2114,9 +2055,8 @@ void ReadableStreamBYOBRequest::respond(jsg::Lock& js, int bytesWritten) { auto entry = kj::heap(jsg::BufferSource(js, source.detach(js))); impl.controller->impl.enqueue(js, kj::mv(entry), impl.controller.addRef()); } else { - JSG_REQUIRE(bytesWritten > 0, - TypeError, - "The bytesWritten must be more than zero while the stream is open."); + JSG_REQUIRE(bytesWritten > 0, TypeError, + "The bytesWritten must be more than zero while the stream is open."); if (impl.readRequest->respond(js, bytesWritten)) { // The read request was fulfilled, we need to invalidate. shouldInvalidate = true; @@ -2135,13 +2075,11 @@ void ReadableStreamBYOBRequest::respond(jsg::Lock& js, int bytesWritten) { } void ReadableStreamBYOBRequest::respondWithNewView(jsg::Lock& js, jsg::BufferSource view) { - auto& impl = JSG_REQUIRE_NONNULL(maybeImpl, - TypeError, - "This ReadableStreamBYOBRequest has been invalidated."); + auto& impl = JSG_REQUIRE_NONNULL( + maybeImpl, TypeError, "This ReadableStreamBYOBRequest has been invalidated."); if (!impl.controller->canCloseOrEnqueue()) { - JSG_REQUIRE(view.size() == 0, - TypeError, - "The view byte length must be zero after the stream is closed."); + JSG_REQUIRE(view.size() == 0, TypeError, + "The view byte length must be zero after the stream is closed."); KJ_ASSERT(impl.readRequest->isInvalidated()); invalidate(js); } else { @@ -2152,9 +2090,8 @@ void ReadableStreamBYOBRequest::respondWithNewView(jsg::Lock& js, jsg::BufferSou auto entry = kj::heap(jsg::BufferSource(js, view.detach(js))); impl.controller->impl.enqueue(js, kj::mv(entry), impl.controller.addRef()); } else { - JSG_REQUIRE(view.size() > 0, - TypeError, - "The view byte length must be more than zero while the stream is open."); + JSG_REQUIRE(view.size() > 0, TypeError, + "The view byte length must be more than zero while the stream is open."); if (impl.readRequest->respondWithNewView(js, kj::mv(view))) { // The read request was fulfilled, we need to invalidate. shouldInvalidate = true; @@ -2183,11 +2120,9 @@ bool ReadableStreamBYOBRequest::isPartiallyFulfilled() { // ====================================================================================== ReadableByteStreamController::ReadableByteStreamController( - UnderlyingSource underlyingSource, - StreamQueuingStrategy queuingStrategy) + UnderlyingSource underlyingSource, StreamQueuingStrategy queuingStrategy) : ioContext(tryGetIoContext()), - impl(kj::mv(underlyingSource), - kj::mv(queuingStrategy)) {} + impl(kj::mv(underlyingSource), kj::mv(queuingStrategy)) {} void ReadableByteStreamController::start(jsg::Lock& js) { impl.start(js, JSG_THIS); @@ -2210,8 +2145,7 @@ void ReadableByteStreamController::visitForGc(jsg::GcVisitor& visitor) { } jsg::Promise ReadableByteStreamController::cancel( - jsg::Lock& js, - jsg::Optional> maybeReason) { + jsg::Lock& js, jsg::Optional> maybeReason) { KJ_IF_SOME(byobRequest, maybeByobRequest) { if (impl.consumerCount() == 1) { byobRequest->invalidate(js); @@ -2230,8 +2164,7 @@ void ReadableByteStreamController::close(jsg::Lock& js) { void ReadableByteStreamController::enqueue(jsg::Lock& js, jsg::BufferSource chunk) { JSG_REQUIRE(chunk.size() > 0, TypeError, "Cannot enqueue a zero-length ArrayBuffer."); - JSG_REQUIRE(chunk.canDetach(js), TypeError, - "The provided ArrayBuffer must be detachable."); + JSG_REQUIRE(chunk.canDetach(js), TypeError, "The provided ArrayBuffer must be detachable."); JSG_REQUIRE(impl.canCloseOrEnqueue(), TypeError, "This ReadableByteStreamController is closed."); KJ_IF_SOME(byobRequest, maybeByobRequest) { @@ -2249,22 +2182,20 @@ void ReadableByteStreamController::error(jsg::Lock& js, v8::Local rea impl.doError(js, js.v8Ref(reason)); } -kj::Maybe> -ReadableByteStreamController::getByobRequest(jsg::Lock& js) { +kj::Maybe> ReadableByteStreamController::getByobRequest( + jsg::Lock& js) { if (maybeByobRequest == kj::none) { KJ_IF_SOME(queue, impl.state.tryGet()) { KJ_IF_SOME(pendingByob, queue.nextPendingByobReadRequest()) { - maybeByobRequest = jsg::alloc(js, - kj::mv(pendingByob), JSG_THIS); + maybeByobRequest = jsg::alloc(js, kj::mv(pendingByob), JSG_THIS); } } else { return kj::none; } } - return maybeByobRequest.map([&](jsg::Ref& req) { - return req.addRef(); - }); + return maybeByobRequest.map( + [&](jsg::Ref& req) { return req.addRef(); }); } // When a consumer receives a read request, but does not have the data available to @@ -2281,31 +2212,30 @@ kj::Own ReadableByteStreamController::getConsumer( // ====================================================================================== -ReadableStreamJsController::ReadableStreamJsController() : ioContext(tryGetIoContext()) {} +ReadableStreamJsController::ReadableStreamJsController(): ioContext(tryGetIoContext()) {} ReadableStreamJsController::ReadableStreamJsController(StreamStates::Closed closed) - : ioContext(tryGetIoContext()), state(closed) {} + : ioContext(tryGetIoContext()), + state(closed) {} ReadableStreamJsController::ReadableStreamJsController(StreamStates::Errored errored) - : ioContext(tryGetIoContext()), state(kj::mv(errored)) {} + : ioContext(tryGetIoContext()), + state(kj::mv(errored)) {} -ReadableStreamJsController::ReadableStreamJsController( - jsg::Lock& js, - ValueReadable& consumer) - : ioContext(tryGetIoContext()), state(consumer.clone(js, *this)) {} +ReadableStreamJsController::ReadableStreamJsController(jsg::Lock& js, ValueReadable& consumer) + : ioContext(tryGetIoContext()), + state(consumer.clone(js, *this)) {} -ReadableStreamJsController::ReadableStreamJsController( - jsg::Lock& js, - ByteReadable& consumer) - : ioContext(tryGetIoContext()), state(consumer.clone(js, *this)) {} +ReadableStreamJsController::ReadableStreamJsController(jsg::Lock& js, ByteReadable& consumer) + : ioContext(tryGetIoContext()), + state(consumer.clone(js, *this)) {} jsg::Ref ReadableStreamJsController::addRef() { return KJ_REQUIRE_NONNULL(owner).addRef(); } jsg::Promise ReadableStreamJsController::cancel( - jsg::Lock& js, - jsg::Optional> maybeReason) { + jsg::Lock& js, jsg::Optional> maybeReason) { disturbed = true; const auto doCancel = [&](auto& consumer) { @@ -2358,12 +2288,12 @@ void ReadableStreamJsController::doClose(jsg::Lock& js) { } } - // As with doClose(), doError() finalizes the error state of this ReadableStream. - // The connection to the underlying controller is released with no further action. - // This method is triggered by the underlying controller as a result of that controller - // erroring. We detach ourselves from the underlying controller by releasing the ValueReadable - // or ByteReadable in the state and changing that to errored. - // We also clean up other state here. +// As with doClose(), doError() finalizes the error state of this ReadableStream. +// The connection to the underlying controller is released with no further action. +// This method is triggered by the underlying controller as a result of that controller +// erroring. We detach ourselves from the underlying controller by releasing the ValueReadable +// or ByteReadable in the state and changing that to errored. +// We also clean up other state here. void ReadableStreamJsController::doError(jsg::Lock& js, v8::Local reason) { if (isReadPending()) { setPendingState(js.v8Ref(reason)); @@ -2391,7 +2321,9 @@ bool ReadableStreamJsController::isClosed() const { return state.is(); } -bool ReadableStreamJsController::isDisturbed() { return disturbed; } +bool ReadableStreamJsController::isDisturbed() { + return disturbed; +} bool ReadableStreamJsController::isLockedToReader() const { return lock.isLockedToReader(); @@ -2402,9 +2334,7 @@ bool ReadableStreamJsController::lockReader(jsg::Lock& js, Reader& reader) { } jsg::Promise ReadableStreamJsController::pipeTo( - jsg::Lock& js, - WritableStreamController& destination, - PipeToOptions options) { + jsg::Lock& js, WritableStreamController& destination, PipeToOptions options) { KJ_DASSERT(!isLockedToReader()); KJ_DASSERT(!destination.isLockedToWriter()); @@ -2418,8 +2348,7 @@ jsg::Promise ReadableStreamJsController::pipeTo( } kj::Maybe> ReadableStreamJsController::read( - jsg::Lock& js, - kj::Maybe maybeByobOptions) { + jsg::Lock& js, kj::Maybe maybeByobOptions) { disturbed = true; KJ_IF_SOME(byobOptions, maybeByobOptions) { @@ -2452,7 +2381,7 @@ kj::Maybe> ReadableStreamJsController::read( auto source = jsg::BufferSource(js, byobOptions.bufferView.getHandle(js)); auto store = source.detach(js); store.consume(store.size()); - return js.resolvedPromise(ReadResult { + return js.resolvedPromise(ReadResult{ .value = js.v8Ref(store.createHandle(js)), .done = true, }); @@ -2464,7 +2393,7 @@ kj::Maybe> ReadableStreamJsController::read( KJ_CASE_ONEOF(closed, StreamStates::Closed) { // The closed state for BYOB reads is handled in the maybeByobOptions check above. KJ_ASSERT(maybeByobOptions == kj::none); - return js.resolvedPromise(ReadResult { .done = true }); + return js.resolvedPromise(ReadResult{.done = true}); } KJ_CASE_ONEOF(errored, StreamStates::Errored) { return js.rejectedPromise(errored.addRef(js)); @@ -2476,7 +2405,7 @@ kj::Maybe> ReadableStreamJsController::read( KJ_CASE_ONEOF(closed, StreamStates::Closed) { // The closed state for BYOB reads is handled in the maybeByobOptions check above. KJ_ASSERT(maybeByobOptions == kj::none); - return js.resolvedPromise(ReadResult { .done = true }); + return js.resolvedPromise(ReadResult{.done = true}); } KJ_CASE_ONEOF(errored, StreamStates::Errored) { return js.rejectedPromise(errored.addRef(js)); @@ -2485,22 +2414,17 @@ kj::Maybe> ReadableStreamJsController::read( // The ReadableStreamDefaultController does not support ByobOptions. // It should never happen, but let's make sure. KJ_ASSERT(maybeByobOptions == kj::none); - return deferControllerStateChange(js, *this, [&]() mutable { - return consumer->read(js); - }); + return deferControllerStateChange(js, *this, [&]() mutable { return consumer->read(js); }); } KJ_CASE_ONEOF(consumer, kj::Own) { - return deferControllerStateChange(js, *this, [&]() mutable { - return consumer->read(js, kj::mv(maybeByobOptions)); - }); + return deferControllerStateChange( + js, *this, [&]() mutable { return consumer->read(js, kj::mv(maybeByobOptions)); }); } } KJ_UNREACHABLE; } -void ReadableStreamJsController::releaseReader( - Reader& reader, - kj::Maybe maybeJs) { +void ReadableStreamJsController::releaseReader(Reader& reader, kj::Maybe maybeJs) { lock.releaseReader(*this, reader, maybeJs); } @@ -2514,7 +2438,7 @@ ReadableStreamController::Tee ReadableStreamJsController::tee(jsg::Lock& js) { KJ_IF_SOME(pendingState, maybePendingState) { KJ_SWITCH_ONEOF(pendingState) { KJ_CASE_ONEOF(closed, StreamStates::Closed) { - return Tee { + return Tee{ .branch1 = jsg::alloc( kj::heap(StreamStates::Closed())), .branch2 = jsg::alloc( @@ -2522,11 +2446,11 @@ ReadableStreamController::Tee ReadableStreamJsController::tee(jsg::Lock& js) { }; } KJ_CASE_ONEOF(errored, StreamStates::Errored) { - return Tee { - .branch1 = jsg::alloc(kj::heap( - errored.addRef(js))), - .branch2 = jsg::alloc(kj::heap( - errored.addRef(js))), + return Tee{ + .branch1 = + jsg::alloc(kj::heap(errored.addRef(js))), + .branch2 = + jsg::alloc(kj::heap(errored.addRef(js))), }; } } @@ -2534,7 +2458,7 @@ ReadableStreamController::Tee ReadableStreamJsController::tee(jsg::Lock& js) { KJ_SWITCH_ONEOF(state) { KJ_CASE_ONEOF(closed, StreamStates::Closed) { - return Tee { + return Tee{ .branch1 = jsg::alloc( kj::heap(StreamStates::Closed())), .branch2 = jsg::alloc( @@ -2542,18 +2466,18 @@ ReadableStreamController::Tee ReadableStreamJsController::tee(jsg::Lock& js) { }; } KJ_CASE_ONEOF(errored, StreamStates::Errored) { - return Tee { - .branch1 = jsg::alloc(kj::heap( - errored.addRef(js))), - .branch2 = jsg::alloc(kj::heap( - errored.addRef(js))), + return Tee{ + .branch1 = + jsg::alloc(kj::heap(errored.addRef(js))), + .branch2 = + jsg::alloc(kj::heap(errored.addRef(js))), }; } KJ_CASE_ONEOF(consumer, kj::Own) { KJ_DEFER(state.init()); // We create two additional streams that clone this stream's consumer state, // then close this stream's consumer. - return Tee { + return Tee{ .branch1 = jsg::alloc(kj::heap(js, *consumer)), .branch2 = jsg::alloc(kj::heap(js, *consumer)), }; @@ -2562,7 +2486,7 @@ ReadableStreamController::Tee ReadableStreamJsController::tee(jsg::Lock& js) { KJ_DEFER(state.init()); // We create two additional streams that clone this stream's consumer state, // then close this stream's consumer. - return Tee { + return Tee{ .branch1 = jsg::alloc(kj::heap(js, *consumer)), .branch2 = jsg::alloc(kj::heap(js, *consumer)), }; @@ -2576,8 +2500,7 @@ void ReadableStreamJsController::setOwnerRef(ReadableStream& stream) { owner = &stream; } -void ReadableStreamJsController::setup( - jsg::Lock& js, +void ReadableStreamJsController::setup(jsg::Lock& js, jsg::Optional maybeUnderlyingSource, jsg::Optional maybeQueuingStrategy) { auto underlyingSource = kj::mv(maybeUnderlyingSource).orDefault({}); @@ -2590,22 +2513,19 @@ void ReadableStreamJsController::setup( auto autoAllocateChunkSize = underlyingSource.autoAllocateChunkSize.orDefault( UnderlyingSource::DEFAULT_AUTO_ALLOCATE_CHUNK_SIZE); - auto controller = jsg::alloc( - kj::mv(underlyingSource), - kj::mv(queuingStrategy)); + auto controller = + jsg::alloc(kj::mv(underlyingSource), kj::mv(queuingStrategy)); - JSG_REQUIRE(autoAllocateChunkSize > 0, - TypeError, - "The autoAllocateChunkSize option cannot be zero."); + JSG_REQUIRE( + autoAllocateChunkSize > 0, TypeError, "The autoAllocateChunkSize option cannot be zero."); state = kj::heap(controller.addRef(), *this, autoAllocateChunkSize); controller->start(js); } else { - JSG_REQUIRE(type == "", TypeError, - kj::str("\"", type, "\" is not a valid type of ReadableStream.")); + JSG_REQUIRE( + type == "", TypeError, kj::str("\"", type, "\" is not a valid type of ReadableStream.")); auto controller = jsg::alloc( - kj::mv(underlyingSource), - kj::mv(queuingStrategy)); + kj::mv(underlyingSource), kj::mv(queuingStrategy)); state = kj::heap(controller.addRef(), *this); controller->start(js); } @@ -2619,7 +2539,8 @@ kj::Maybe ReadableStreamJsController: void ReadableStreamJsController::visitForGc(jsg::GcVisitor& visitor) { KJ_IF_SOME(pendingState, maybePendingState) { KJ_SWITCH_ONEOF(pendingState) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } KJ_CASE_ONEOF(error, StreamStates::Errored) { visitor.visit(error); } @@ -2627,7 +2548,8 @@ void ReadableStreamJsController::visitForGc(jsg::GcVisitor& visitor) { } KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } KJ_CASE_ONEOF(error, StreamStates::Errored) { visitor.visit(error); } @@ -2647,8 +2569,12 @@ kj::Maybe ReadableStreamJsController::getDesiredSize() { } KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) { return kj::none; } - KJ_CASE_ONEOF(errored, StreamStates::Errored) { return kj::none; } + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + return kj::none; + } + KJ_CASE_ONEOF(errored, StreamStates::Errored) { + return kj::none; + } KJ_CASE_ONEOF(consumer, kj::Own) { return consumer->getDesiredSize(); } @@ -2662,15 +2588,16 @@ kj::Maybe ReadableStreamJsController::getDesiredSize() { kj::Maybe> ReadableStreamJsController::isErrored(jsg::Lock& js) { KJ_IF_SOME(pendingState, maybePendingState) { KJ_SWITCH_ONEOF(pendingState) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) { return kj::none; } + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + return kj::none; + } KJ_CASE_ONEOF(error, StreamStates::Errored) { return error.getHandle(js); } } } - return state.tryGet().map([&](jsg::Value& reason) { - return reason.getHandle(js); - }); + return state.tryGet().map( + [&](jsg::Value& reason) { return reason.getHandle(js); }); } bool ReadableStreamJsController::canCloseOrEnqueue() { @@ -2679,8 +2606,12 @@ bool ReadableStreamJsController::canCloseOrEnqueue() { } KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) { return false; } - KJ_CASE_ONEOF(errored, StreamStates::Errored) { return false; } + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + return false; + } + KJ_CASE_ONEOF(errored, StreamStates::Errored) { + return false; + } KJ_CASE_ONEOF(consumer, kj::Own) { return consumer->canCloseOrEnqueue(); } @@ -2692,18 +2623,24 @@ bool ReadableStreamJsController::canCloseOrEnqueue() { } bool ReadableStreamJsController::hasBackpressure() { - KJ_IF_SOME(size, getDesiredSize()) { return size <= 0; } + KJ_IF_SOME(size, getDesiredSize()) { + return size <= 0; + } return false; } -kj::Maybe> -ReadableStreamJsController::getController() { +kj::Maybe> ReadableStreamJsController:: + getController() { if (maybePendingState != kj::none) { return kj::none; } KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) { return kj::none; } - KJ_CASE_ONEOF(errored, StreamStates::Errored) { return kj::none; } + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + return kj::none; + } + KJ_CASE_ONEOF(errored, StreamStates::Errored) { + return kj::none; + } KJ_CASE_ONEOF(consumer, kj::Own) { return consumer->getControllerRef(); } @@ -2721,9 +2658,7 @@ class AllReader { public: using PartList = kj::Array>; - AllReader(jsg::Ref stream, uint64_t limit) - : state(kj::mv(stream)), - limit(limit) {} + AllReader(jsg::Ref stream, uint64_t limit): state(kj::mv(stream)), limit(limit) {} KJ_DISALLOW_COPY_AND_MOVE(AllReader); jsg::Promise> allBytes(jsg::Lock& js) { @@ -2745,7 +2680,8 @@ public: void visitForGc(jsg::GcVisitor& visitor) { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } KJ_CASE_ONEOF(errored, StreamStates::Errored) { visitor.visit(errored); } @@ -2774,7 +2710,8 @@ private: // and are passed into to promise returned by this method. It is the responsibility // of the caller to ensure that the AllReader instance is kept alive until the // promise is settled. - auto onSuccess = [this,&readable](jsg::Lock& js, ReadResult result) -> jsg::Promise{ + auto onSuccess = [this, &readable]( + jsg::Lock& js, ReadResult result) -> jsg::Promise { if (result.done) { state.template init(); return loop(js); @@ -2787,9 +2724,8 @@ private: auto error = js.v8TypeError("This ReadableStream did not return bytes."); auto rs = kj::mv(readable); state.template init(js.v8Ref(error)); - return rs->getController().cancel(js, error).then(js, [&](jsg::Lock& js) { - return loop(js); - }); + return rs->getController().cancel(js, error).then( + js, [&](jsg::Lock& js) { return loop(js); }); } jsg::BufferSource bufferSource(js, handle); @@ -2804,9 +2740,8 @@ private: auto error = js.v8TypeError("Memory limit exceeded before EOF."); auto rs = kj::mv(readable); state.template init(js.v8Ref(error)); - return rs->getController().cancel(js, error).then(js, [&](jsg::Lock& js) { - return loop(js); - }); + return rs->getController().cancel(js, error).then( + js, [&](jsg::Lock& js) { return loop(js); }); } runningTotal += backing.size(); @@ -2820,10 +2755,8 @@ private: return loop(js); }; - return maybeAddFunctor(js, - KJ_ASSERT_NONNULL(readable->getController().read(js, kj::none)), - kj::mv(onSuccess), - kj::mv(onFailure)); + return maybeAddFunctor(js, KJ_ASSERT_NONNULL(readable->getController().read(js, kj::none)), + kj::mv(onSuccess), kj::mv(onFailure)); } } KJ_UNREACHABLE; @@ -2845,11 +2778,11 @@ private: class PumpToReader { public: PumpToReader(jsg::Ref stream, kj::Own sink, bool end) - : ioContext(IoContext::current()), - state(kj::mv(stream)), - sink(kj::mv(sink)), - self(kj::refcounted>(kj::Badge{}, *this)), - end(end) {} + : ioContext(IoContext::current()), + state(kj::mv(stream)), + sink(kj::mv(sink)), + self(kj::refcounted>(kj::Badge{}, *this)), + end(end) {} KJ_DISALLOW_COPY_AND_MOVE(PumpToReader); ~PumpToReader() noexcept(false) { @@ -2875,8 +2808,8 @@ public: // are always accessed from the right IoContext. The WeakRef ensures that if the // PumpToReader is freed while the JS continuation is pending, there won't be a dangling // reference. - return ioContext.awaitJs(js, - pumpLoop(js, ioContext, kj::mv(readable), ioContext.addObject(self->addRef()))); + return ioContext.awaitJs( + js, pumpLoop(js, ioContext, kj::mv(readable), ioContext.addObject(self->addRef()))); } KJ_CASE_ONEOF(pumping, Pumping) { return KJ_EXCEPTION(FAILED, "pumping is already in progress"); @@ -2901,12 +2834,10 @@ private: bool end; bool isErroredOrClosed() { - return state.template is() || - state.template is(); + return state.template is() || state.template is(); } - jsg::Promise pumpLoop( - jsg::Lock& js, + jsg::Promise pumpLoop(jsg::Lock& js, IoContext& ioContext, jsg::Ref readable, IoOwn> pumpToReader) { @@ -2917,9 +2848,8 @@ private: KJ_UNREACHABLE; } KJ_CASE_ONEOF(closed, StreamStates::Closed) { - return end ? - ioContext.awaitIoLegacy(js, sink->end().attach(kj::mv(sink))) : - js.resolvedPromise(); + return end ? ioContext.awaitIoLegacy(js, sink->end().attach(kj::mv(sink))) + : js.resolvedPromise(); } KJ_CASE_ONEOF(errored, kj::Exception) { if (end) { @@ -2928,10 +2858,10 @@ private: return js.rejectedPromise(kj::cp(errored)); } KJ_CASE_ONEOF(pumping, Pumping) { - using Result = kj::OneOf, // Bytes to write were returned. - StreamStates::Closed, // Readable indicated done. - jsg::Value>; // There was an error. + using Result = kj::OneOf, // Bytes to write were returned. + StreamStates::Closed, // Readable indicated done. + jsg::Value>; // There was an error. // The flow here is relatively straightforward but the ownership of // readable/pumpToReader is fairly complicated. @@ -2972,14 +2902,13 @@ private: // case and handle appropriately (generally by canceling the readable // and exiting the loop). return KJ_ASSERT_NONNULL(readable->getController().read(js, kj::none)) - .then(js, ioContext.addFunctor( - [byteStream=readable->getController().isByteOriented()] - (auto& js, ReadResult result) mutable -> Result { - + .then(js, + ioContext.addFunctor([byteStream = readable->getController().isByteOriented()]( + auto& js, ReadResult result) mutable -> Result { if (result.done) { // Indicate to the outer promise that the readable is done. // There's nothing further to do. - return StreamStates::Closed (); + return StreamStates::Closed(); } // If we're not done, the result value must be interpretable as @@ -2992,7 +2921,7 @@ private: jsg::BufferSource bufferSource(js, handle); if (bufferSource.size() == 0) { // Weird, but allowed. We'll skip it. - return Pumping {}; + return Pumping{}; } if (byteStream) { @@ -3006,106 +2935,105 @@ private: } KJ_UNREACHABLE; - }), [](auto& js, jsg::Value exception) mutable -> Result { - return kj::mv(exception); - }).then(js, ioContext.addFunctor( - JSG_VISITABLE_LAMBDA( - (readable=kj::mv(readable),pumpToReader=kj::mv(pumpToReader)), - (readable), - (jsg::Lock& js, Result result) mutable { - KJ_IF_SOME(reader, pumpToReader->tryGet()) { - // Oh good, if we got here it means we're in the right IoContext and - // the PumpToReader is still alive. Let's process the result. - reader.ioContext.requireCurrentOrThrowJs(); - auto& ioContext = IoContext::current(); - KJ_SWITCH_ONEOF(result) { + }), + [](auto& js, jsg::Value exception) mutable -> Result { return kj::mv(exception); }) + .then(js, ioContext.addFunctor( JSG_VISITABLE_LAMBDA((readable = kj::mv(readable), pumpToReader = kj::mv(pumpToReader)), (readable), (jsg::Lock & js, Result result) mutable { + KJ_IF_SOME(reader, pumpToReader->tryGet()) { + // Oh good, if we got here it means we're in the right IoContext and + // the PumpToReader is still alive. Let's process the result. + reader.ioContext.requireCurrentOrThrowJs(); + auto& ioContext = IoContext::current(); + KJ_SWITCH_ONEOF(result) { KJ_CASE_ONEOF(bytes, kj::Array) { - // We received bytes to write. Do so... - auto promise = reader.sink->write(bytes).attach(kj::mv(bytes)); - // Wrap the write promise in a canceler that will be triggered when the - // PumpToReader is dropped. While the write promise is pending, it is - // possible for the promise that is holding the PumpToReader to be - // dropped causing the hold on the sink to be released. If that is - // released while the write is still pending we can end up with an - // error further up the destruct chain. - return ioContext.awaitIo(js, reader.canceler.wrap(kj::mv(promise))).then(js, - [](jsg::Lock& js) -> kj::Maybe { - // The write completed successfully. - return kj::Maybe(kj::none); - }, [](jsg::Lock& js, jsg::Value exception) mutable -> kj::Maybe { - // The write failed. - return kj::mv(exception); - }).then(js, ioContext.addFunctor( - JSG_VISITABLE_LAMBDA( - (readable=readable.addRef(),pumpToReader=kj::mv(pumpToReader)), - (readable), - (jsg::Lock& js, kj::Maybe maybeException) mutable { - KJ_IF_SOME(reader, pumpToReader->tryGet()) { - auto& ioContext = reader.ioContext; - ioContext.requireCurrentOrThrowJs(); - // Oh good, if we got here it means we're in the right IoContext and - // the PumpToReader is still alive. - KJ_IF_SOME(exception, maybeException) { - if (!reader.isErroredOrClosed()) { - reader.state.init(js.exceptionToKj(kj::mv(exception))); - } - } else { - // Else block to avert dangling else compiler warning. - } - return reader.pumpLoop(js, ioContext, readable.addRef(), kj::mv(pumpToReader)); - } else { - // If we got here, we're in the right IoContext but the PumpToReader - // has been destroyed. Let's cancel the readable as the last step. - return readable->getController().cancel(js, - maybeException.map([&](jsg::Value& ex) { - return ex.getHandle(js); - })); - } - }))); + // We received bytes to write. Do so... + auto promise = reader.sink->write(bytes).attach(kj::mv(bytes)); + // Wrap the write promise in a canceler that will be triggered when the + // PumpToReader is dropped. While the write promise is pending, it is + // possible for the promise that is holding the PumpToReader to be + // dropped causing the hold on the sink to be released. If that is + // released while the write is still pending we can end up with an + // error further up the destruct chain. + return ioContext.awaitIo(js, reader.canceler.wrap(kj::mv(promise))) + .then(js, + [](jsg::Lock& js) -> kj::Maybe { + // The write completed successfully. + return kj::Maybe(kj::none); + }, + [](jsg::Lock& js, jsg::Value exception) mutable -> kj::Maybe { + // The write failed. + return kj::mv(exception); + }) + .then(js, + ioContext.addFunctor(JSG_VISITABLE_LAMBDA( + (readable = readable.addRef(), pumpToReader = kj::mv(pumpToReader)), + (readable), + (jsg::Lock & js, kj::Maybe maybeException) mutable { + KJ_IF_SOME(reader, pumpToReader->tryGet()) { + auto& ioContext = reader.ioContext; + ioContext.requireCurrentOrThrowJs(); + // Oh good, if we got here it means we're in the right IoContext and + // the PumpToReader is still alive. + KJ_IF_SOME(exception, maybeException) { + if (!reader.isErroredOrClosed()) { + reader.state.init(js.exceptionToKj(kj::mv(exception))); + } + } else { + // Else block to avert dangling else compiler warning. + } + return reader.pumpLoop( + js, ioContext, readable.addRef(), kj::mv(pumpToReader)); + } else { + // If we got here, we're in the right IoContext but the PumpToReader + // has been destroyed. Let's cancel the readable as the last step. + return readable->getController().cancel(js, + maybeException.map( + [&](jsg::Value& ex) { return ex.getHandle(js); })); + } + }))); } KJ_CASE_ONEOF(pumping, Pumping) { - // If we got here, a zero-length buffer was provided by the read and we're - // just going to ignore it and keep going. + // If we got here, a zero-length buffer was provided by the read and we're + // just going to ignore it and keep going. } KJ_CASE_ONEOF(closed, StreamStates::Closed) { - // If we got here, the read signaled that we're done. Close the reader and - // pump one more time to shut things down. - if (!reader.isErroredOrClosed()) { - reader.state.init(); - } + // If we got here, the read signaled that we're done. Close the reader and + // pump one more time to shut things down. + if (!reader.isErroredOrClosed()) { + reader.state.init(); + } } KJ_CASE_ONEOF(exception, jsg::Value) { - // If we got here, the read signaled an exception. Either the read failed or - // provided something other than bytes. Error the reader and pump one more - // time to shut things down. - if (!reader.isErroredOrClosed()) { - reader.state.init(js.exceptionToKj(kj::mv(exception))); - } + // If we got here, the read signaled an exception. Either the read failed or + // provided something other than bytes. Error the reader and pump one more + // time to shut things down. + if (!reader.isErroredOrClosed()) { + reader.state.init(js.exceptionToKj(kj::mv(exception))); } - } - return reader.pumpLoop(js, ioContext, readable.addRef(), kj::mv(pumpToReader)); - } else { - // If we got here, we're in the right IoContext but the PumpToReader has been - // freed. There's nothing we can do except cleanup. - KJ_SWITCH_ONEOF(result) { + } + } + return reader.pumpLoop(js, ioContext, readable.addRef(), kj::mv(pumpToReader)); + } else { + // If we got here, we're in the right IoContext but the PumpToReader has been + // freed. There's nothing we can do except cleanup. + KJ_SWITCH_ONEOF(result) { KJ_CASE_ONEOF(bytes, kj::Array) { - return readable->getController().cancel(js, kj::none); + return readable->getController().cancel(js, kj::none); } KJ_CASE_ONEOF(pumping, Pumping) { - return readable->getController().cancel(js, kj::none); + return readable->getController().cancel(js, kj::none); } KJ_CASE_ONEOF(closed, StreamStates::Closed) { - // We do not have to cancel the readable in this case because it has already - // signaled that it is done. There's nothing to cancel. - return js.resolvedPromise(); + // We do not have to cancel the readable in this case because it has already + // signaled that it is done. There's nothing to cancel. + return js.resolvedPromise(); } KJ_CASE_ONEOF(exception, jsg::Value) { - return readable->getController().cancel(js, exception.getHandle(js)); + return readable->getController().cancel(js, exception.getHandle(js)); } - } - } - KJ_UNREACHABLE; - }))); + } + } + KJ_UNREACHABLE; + }))); } } KJ_UNREACHABLE; @@ -3114,12 +3042,10 @@ private: } // namespace template -jsg::Promise ReadableStreamJsController::readAll( - jsg::Lock& js, - uint64_t limit) { +jsg::Promise ReadableStreamJsController::readAll(jsg::Lock& js, uint64_t limit) { if (isLockedToReader()) { - return js.rejectedPromise(KJ_EXCEPTION(FAILED, - "jsg.TypeError: This ReadableStream is currently locked to a reader.")); + return js.rejectedPromise(KJ_EXCEPTION( + FAILED, "jsg.TypeError: This ReadableStream is currently locked to a reader.")); } disturbed = true; @@ -3139,19 +3065,17 @@ jsg::Promise ReadableStreamJsController::readAll( })(); return maybeAddFunctor(js, kj::mv(promise), - // reader is a gc visitable type that holds a reference to either the stream - // or an error. Accordingly, we wrap it in a visitable lambda attached as a - // continuation on the promise to ensure that it is gc visited and kept alive until - // the promise settles. - JSG_VISITABLE_LAMBDA( - (reader=kj::mv(reader)), - (reader), - (jsg::Lock& js, T result) -> jsg::Promise { - return js.resolvedPromise(kj::mv(result)); - }), - [](jsg::Lock& js, jsg::Value exception) -> jsg::Promise { - return js.rejectedPromise(kj::mv(exception)); - }); + // reader is a gc visitable type that holds a reference to either the stream + // or an error. Accordingly, we wrap it in a visitable lambda attached as a + // continuation on the promise to ensure that it is gc visited and kept alive until + // the promise settles. + JSG_VISITABLE_LAMBDA((reader = kj::mv(reader)), (reader), + (jsg::Lock & js, T result)->jsg::Promise { + return js.resolvedPromise(kj::mv(result)); + }), + [](jsg::Lock& js, jsg::Value exception) -> jsg::Promise { + return js.rejectedPromise(kj::mv(exception)); + }); }; KJ_SWITCH_ONEOF(state) { @@ -3172,14 +3096,11 @@ jsg::Promise ReadableStreamJsController::readAll( } jsg::Promise> ReadableStreamJsController::readAllBytes( - jsg::Lock& js, - uint64_t limit) { + jsg::Lock& js, uint64_t limit) { return readAll>(js, limit); } -jsg::Promise ReadableStreamJsController::readAllText( - jsg::Lock& js, - uint64_t limit) { +jsg::Promise ReadableStreamJsController::readAllText(jsg::Lock& js, uint64_t limit) { return readAll(js, limit); } @@ -3223,9 +3144,7 @@ kj::Maybe ReadableStreamJsController::tryGetLength(StreamEncoding enco } kj::Promise> ReadableStreamJsController::pumpTo( - jsg::Lock& js, - kj::Own sink, - bool end) { + jsg::Lock& js, kj::Own sink, bool end) { KJ_ASSERT(IoContext::hasCurrent(), "Unable to consume this ReadableStream outside of a request"); KJ_REQUIRE(!isLockedToReader(), "This ReadableStream is currently locked to a reader."); disturbed = true; @@ -3262,13 +3181,12 @@ kj::Promise> ReadableStreamJsController::pumpTo( // ====================================================================================== -WritableStreamDefaultController::WritableStreamDefaultController( - WritableStream& owner) - : ioContext(tryGetIoContext()), impl(owner) {} +WritableStreamDefaultController::WritableStreamDefaultController(WritableStream& owner) + : ioContext(tryGetIoContext()), + impl(owner) {} jsg::Promise WritableStreamDefaultController::abort( - jsg::Lock& js, - v8::Local reason) { + jsg::Lock& js, v8::Local reason) { return impl.abort(js, JSG_THIS, reason); } @@ -3281,8 +3199,7 @@ jsg::Promise WritableStreamDefaultController::close(jsg::Lock& js) { } void WritableStreamDefaultController::error( - jsg::Lock& js, - jsg::Optional> reason) { + jsg::Lock& js, jsg::Optional> reason) { impl.error(js, JSG_THIS, reason.orDefault(js.v8Undefined())); } @@ -3302,15 +3219,12 @@ kj::Maybe> WritableStreamDefaultController::isErroring(jsg: } void WritableStreamDefaultController::setup( - jsg::Lock& js, - UnderlyingSink underlyingSink, - StreamQueuingStrategy queuingStrategy) { + jsg::Lock& js, UnderlyingSink underlyingSink, StreamQueuingStrategy queuingStrategy) { impl.setup(js, JSG_THIS, kj::mv(underlyingSink), kj::mv(queuingStrategy)); } jsg::Promise WritableStreamDefaultController::write( - jsg::Lock& js, - v8::Local value) { + jsg::Lock& js, v8::Local value) { return impl.write(js, JSG_THIS, value); } @@ -3319,18 +3233,18 @@ void WritableStreamDefaultController::cancelPendingWrites(jsg::Lock& js, jsg::Js } // ====================================================================================== -WritableStreamJsController::WritableStreamJsController() - : ioContext(tryGetIoContext()) {} +WritableStreamJsController::WritableStreamJsController(): ioContext(tryGetIoContext()) {} WritableStreamJsController::WritableStreamJsController(StreamStates::Closed closed) - : ioContext(tryGetIoContext()), state(closed) {} + : ioContext(tryGetIoContext()), + state(closed) {} WritableStreamJsController::WritableStreamJsController(StreamStates::Errored errored) - : ioContext(tryGetIoContext()), state(kj::mv(errored)) {} + : ioContext(tryGetIoContext()), + state(kj::mv(errored)) {} jsg::Promise WritableStreamJsController::abort( - jsg::Lock& js, - jsg::Optional> reason) { + jsg::Lock& js, jsg::Optional> reason) { // The spec requires that if abort is called multiple times, it is supposed to return the same // promise each time. That's a bit cumbersome here with jsg::Promise so we intentionally just // return a continuation branch off the same promise. @@ -3371,9 +3285,7 @@ jsg::Promise WritableStreamJsController::close(jsg::Lock& js, bool markAsH KJ_SWITCH_ONEOF(state) { KJ_CASE_ONEOF(closed, StreamStates::Closed) { return rejectedMaybeHandledPromise( - js, - js.v8TypeError("This WritableStream has been closed."_kj), - markAsHandled); + js, js.v8TypeError("This WritableStream has been closed."_kj), markAsHandled); } KJ_CASE_ONEOF(errored, StreamStates::Errored) { return rejectedMaybeHandledPromise(js, errored.getHandle(js), markAsHandled); @@ -3427,8 +3339,7 @@ kj::Maybe> WritableStreamJsController::isErroring(jsg::Lock return kj::none; } -kj::Maybe> WritableStreamJsController::isErroredOrErroring( - jsg::Lock& js) { +kj::Maybe> WritableStreamJsController::isErroredOrErroring(jsg::Lock& js) { KJ_IF_SOME(err, state.tryGet()) { return err.getHandle(js); } @@ -3450,7 +3361,9 @@ bool WritableStreamJsController::isStarted() { KJ_UNREACHABLE; } -bool WritableStreamJsController::isLocked() const { return isLockedToWriter(); } +bool WritableStreamJsController::isLocked() const { + return isLockedToWriter(); +} bool WritableStreamJsController::isLockedToWriter() const { return !lock.state.is(); @@ -3461,8 +3374,7 @@ bool WritableStreamJsController::lockWriter(jsg::Lock& js, Writer& writer) { } void WritableStreamJsController::maybeRejectReadyPromise( - jsg::Lock& js, - v8::Local reason) { + jsg::Lock& js, v8::Local reason) { KJ_IF_SOME(writerLock, lock.state.tryGet()) { if (writerLock.getReadyFulfiller() != kj::none) { maybeRejectPromise(js, writerLock.getReadyFulfiller(), reason); @@ -3481,9 +3393,7 @@ void WritableStreamJsController::maybeResolveReadyPromise(jsg::Lock& js) { } } -void WritableStreamJsController::releaseWriter( - Writer& writer, - kj::Maybe maybeJs) { +void WritableStreamJsController::releaseWriter(Writer& writer, kj::Maybe maybeJs) { lock.releaseWriter(*this, writer, maybeJs); } @@ -3498,8 +3408,7 @@ void WritableStreamJsController::setOwnerRef(WritableStream& stream) { owner = stream; } -void WritableStreamJsController::setup( - jsg::Lock& js, +void WritableStreamJsController::setup(jsg::Lock& js, jsg::Optional maybeUnderlyingSink, jsg::Optional maybeQueuingStrategy) { auto underlyingSink = kj::mv(maybeUnderlyingSink).orDefault({}); @@ -3509,11 +3418,9 @@ void WritableStreamJsController::setup( } kj::Maybe> WritableStreamJsController::tryPipeFrom( - jsg::Lock& js, - jsg::Ref source, - PipeToOptions options) { - JSG_REQUIRE_NONNULL(ioContext, Error, - "Unable to pipe to a WritableStream created outside of a request"); + jsg::Lock& js, jsg::Ref source, PipeToOptions options) { + JSG_REQUIRE_NONNULL( + ioContext, Error, "Unable to pipe to a WritableStream created outside of a request"); // The ReadableStream source here can be either a JavaScript-backed ReadableStream // or ReadableStreamSource-backed. In either case, however, this WritableStream is @@ -3526,7 +3433,7 @@ kj::Maybe> WritableStreamJsController::tryPipeFrom( // Let's also acquire the destination pipe lock. lock.pipeLock(KJ_ASSERT_NONNULL(owner), kj::mv(source), options); - return pipeLoop(js).then(js, JSG_VISITABLE_LAMBDA((ref = addRef()), (ref), (auto& js) {})); + return pipeLoop(js).then(js, JSG_VISITABLE_LAMBDA((ref = addRef()), (ref), (auto& js){})); } jsg::Promise WritableStreamJsController::pipeLoop(jsg::Lock& js) { @@ -3550,13 +3457,10 @@ jsg::Promise WritableStreamJsController::pipeLoop(jsg::Lock& js) { source.release(js); lock.releasePipeLock(); if (!preventAbort) { - auto onSuccess = JSG_VISITABLE_LAMBDA((pipeThrough, reason = js.v8Ref(errored)), - (reason), (jsg::Lock& js) { - return rejectedMaybeHandledPromise( - js, - reason.getHandle(js), - pipeThrough); - }); + auto onSuccess = JSG_VISITABLE_LAMBDA( + (pipeThrough, reason = js.v8Ref(errored)), (reason), (jsg::Lock& js) { + return rejectedMaybeHandledPromise(js, reason.getHandle(js), pipeThrough); + }); auto promise = abort(js, errored); if (IoContext::hasCurrent()) { return promise.then(js, IoContext::current().addFunctor(kj::mv(onSuccess))); @@ -3623,31 +3527,31 @@ jsg::Promise WritableStreamJsController::pipeLoop(jsg::Lock& js) { // source (again, depending on options). If the write operation is successful, // we call pipeLoop again to move on to the next iteration. - auto onSuccess = JSG_VISITABLE_LAMBDA( - (this,ref=addRef(), preventCancel,pipeThrough,&source), - (ref),(jsg::Lock& js, ReadResult result) -> jsg::Promise { - auto maybePipeLock = lock.tryGetPipe(); - if (maybePipeLock == kj::none) return js.resolvedPromise(); - auto& pipeLock = KJ_REQUIRE_NONNULL(maybePipeLock); + auto onSuccess = JSG_VISITABLE_LAMBDA((this, ref = addRef(), preventCancel, pipeThrough, &source), + (ref), (jsg::Lock & js, ReadResult result)->jsg::Promise { + auto maybePipeLock = lock.tryGetPipe(); + if (maybePipeLock == kj::none) return js.resolvedPromise(); + auto& pipeLock = KJ_REQUIRE_NONNULL(maybePipeLock); - KJ_IF_SOME(promise, pipeLock.checkSignal(js, *this)) { - lock.releasePipeLock(); - return kj::mv(promise); - } else {} // Trailing else() is squash compiler warning + KJ_IF_SOME(promise, pipeLock.checkSignal(js, *this)) { + lock.releasePipeLock(); + return kj::mv(promise); + } else { + } // Trailing else() is squash compiler warning - if (result.done) { - // We'll handle the close at the start of the next iteration. - return pipeLoop(js); - } + if (result.done) { + // We'll handle the close at the start of the next iteration. + return pipeLoop(js); + } - auto onSuccess = JSG_VISITABLE_LAMBDA( - (this, ref=addRef()), (ref), (jsg::Lock& js) { + auto onSuccess = JSG_VISITABLE_LAMBDA( + (this, ref=addRef()), (ref) , (jsg::Lock& js) { return pipeLoop(js); - }); + } ); - auto onFailure = JSG_VISITABLE_LAMBDA( + auto onFailure = JSG_VISITABLE_LAMBDA( (ref=addRef(),&source, preventCancel, pipeThrough), - (ref), (jsg::Lock& js, jsg::Value value) { + (ref) , (jsg::Lock& js, jsg::Value value) { // The write failed. We handle it here because the pipe lock will have been released. auto reason = value.getHandle(js); if (!preventCancel) { @@ -3656,22 +3560,19 @@ jsg::Promise WritableStreamJsController::pipeLoop(jsg::Lock& js) { source.release(js); } return rejectedMaybeHandledPromise(js, reason, pipeThrough); - }); + } ); - auto promise = write(js, result.value.map([&](jsg::Value& value) { - return value.getHandle(js); - })); + auto promise = + write(js, result.value.map([&](jsg::Value& value) { return value.getHandle(js); })); - return maybeAddFunctor(js, kj::mv(promise), kj::mv(onSuccess), kj::mv(onFailure)); - }); + return maybeAddFunctor(js, kj::mv(promise), kj::mv(onSuccess), kj::mv(onFailure)); + }); - auto onFailure = JSG_VISITABLE_LAMBDA( - (this, ref=addRef()), - (ref), - (jsg::Lock& js, jsg::Value value) { - // The read failed. We will handle the error at the start of the next iteration. - return pipeLoop(js); - }); + auto onFailure = + JSG_VISITABLE_LAMBDA((this, ref = addRef()), (ref), (jsg::Lock& js, jsg::Value value) { + // The read failed. We will handle the error at the start of the next iteration. + return pipeLoop(js); + }); return maybeAddFunctor(js, pipeLock.source.read(js), kj::mv(onSuccess), kj::mv(onFailure)); } @@ -3693,12 +3594,10 @@ void WritableStreamJsController::updateBackpressure(jsg::Lock& js, bool backpres } jsg::Promise WritableStreamJsController::write( - jsg::Lock& js, - jsg::Optional> value) { + jsg::Lock& js, jsg::Optional> value) { KJ_SWITCH_ONEOF(state) { KJ_CASE_ONEOF(closed, StreamStates::Closed) { - return js.rejectedPromise( - js.v8TypeError("This WritableStream has been closed."_kj)); + return js.rejectedPromise(js.v8TypeError("This WritableStream has been closed."_kj)); } KJ_CASE_ONEOF(errored, StreamStates::Errored) { return js.rejectedPromise(errored.addRef(js)); @@ -3712,7 +3611,8 @@ jsg::Promise WritableStreamJsController::write( void WritableStreamJsController::visitForGc(jsg::GcVisitor& visitor) { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } KJ_CASE_ONEOF(error, StreamStates::Errored) { visitor.visit(error); } @@ -3726,8 +3626,8 @@ void WritableStreamJsController::visitForGc(jsg::GcVisitor& visitor) { // ======================================================================================= TransformStreamDefaultController::TransformStreamDefaultController(jsg::Lock& js) - : ioContext(tryGetIoContext()), - startPromise(js.newPromiseAndResolver()) {} + : ioContext(tryGetIoContext()), + startPromise(js.newPromiseAndResolver()) {} kj::Maybe TransformStreamDefaultController::getDesiredSize() { KJ_IF_SOME(readableController, tryGetReadableController()) { @@ -3736,17 +3636,12 @@ kj::Maybe TransformStreamDefaultController::getDesiredSize() { return kj::none; } -void TransformStreamDefaultController::enqueue( - jsg::Lock& js, - v8::Local chunk) { - auto& readableController = JSG_REQUIRE_NONNULL( - tryGetReadableController(), TypeError, +void TransformStreamDefaultController::enqueue(jsg::Lock& js, v8::Local chunk) { + auto& readableController = JSG_REQUIRE_NONNULL(tryGetReadableController(), TypeError, "The readable side of this TransformStream is no longer readable."); JSG_REQUIRE(readableController.canCloseOrEnqueue(), TypeError, "The readable side of this TransformStream is no longer readable."); - js.tryCatch([&] { - readableController.enqueue(js, chunk); - }, [&](jsg::Value exception) { + js.tryCatch([&] { readableController.enqueue(js, chunk); }, [&](jsg::Value exception) { errorWritableAndUnblockWrite(js, exception.getHandle(js)); js.throwException(kj::mv(exception)); }); @@ -3774,8 +3669,7 @@ void TransformStreamDefaultController::terminate(jsg::Lock& js) { } jsg::Promise TransformStreamDefaultController::write( - jsg::Lock& js, - v8::Local chunk) { + jsg::Lock& js, v8::Local chunk) { KJ_IF_SOME(writableController, tryGetWritableController()) { KJ_IF_SOME(error, writableController.isErroredOrErroring(js)) { return js.rejectedPromise(error); @@ -3802,63 +3696,64 @@ jsg::Promise TransformStreamDefaultController::write( } return performTransform(js, chunk); } else { - return js.rejectedPromise(KJ_EXCEPTION(FAILED, - "jsg.TypeError: Writing to the TransformStream failed.")); + return js.rejectedPromise( + KJ_EXCEPTION(FAILED, "jsg.TypeError: Writing to the TransformStream failed.")); } } jsg::Promise TransformStreamDefaultController::abort( - jsg::Lock& js, - v8::Local reason) { + jsg::Lock& js, v8::Local reason) { KJ_IF_SOME(finish, algorithms.maybeFinish) { return finish.whenResolved(js); } - return algorithms.maybeFinish.emplace(maybeRunAlgorithm(js, algorithms.cancel, - JSG_VISITABLE_LAMBDA( - (this, ref=JSG_THIS, reason = jsg::JsRef(js, jsg::JsValue(reason))), - (ref, reason), - (jsg::Lock& js) -> jsg::Promise { - // If the readable side is errored, return a rejected promise with the stored error - KJ_IF_SOME(controller, tryGetReadableController()) { - KJ_IF_SOME(error, controller.getMaybeErrorState(js)) { - return js.rejectedPromise(kj::mv(error)); - } else {} // Else block to avert dangling else compiler warning. - } else {} // Else block to avert dangling else compiler warning. - - // Otherwise... error with the given reason and resolve the abort promise - error(js, reason.getHandle(js)); - return js.resolvedPromise(); - }), JSG_VISITABLE_LAMBDA( - (this, ref=JSG_THIS), - (ref), - (jsg::Lock& js, jsg::Value reason) -> jsg::Promise { - error(js, reason.getHandle(js)); - return js.rejectedPromise(kj::mv(reason)); - }), jsg::JsValue(reason))).whenResolved(js); + return algorithms.maybeFinish + .emplace(maybeRunAlgorithm(js, algorithms.cancel, + JSG_VISITABLE_LAMBDA( + (this, ref = JSG_THIS, reason = jsg::JsRef(js, jsg::JsValue(reason))), (ref, reason), + (jsg::Lock & js)->jsg::Promise { + // If the readable side is errored, return a rejected promise with the stored error + KJ_IF_SOME(controller, tryGetReadableController()) { + KJ_IF_SOME(error, controller.getMaybeErrorState(js)) { + return js.rejectedPromise(kj::mv(error)); + } else { + } // Else block to avert dangling else compiler warning. + } else { + } // Else block to avert dangling else compiler warning. + + // Otherwise... error with the given reason and resolve the abort promise + error(js, reason.getHandle(js)); + return js.resolvedPromise(); + }), + JSG_VISITABLE_LAMBDA((this, ref = JSG_THIS), (ref), + (jsg::Lock & js, jsg::Value reason)->jsg::Promise { + error(js, reason.getHandle(js)); + return js.rejectedPromise(kj::mv(reason)); + }), + jsg::JsValue(reason))) + .whenResolved(js); } jsg::Promise TransformStreamDefaultController::close(jsg::Lock& js) { - auto onSuccess = JSG_VISITABLE_LAMBDA( - (ref=JSG_THIS), (ref), (jsg::Lock& js) -> jsg::Promise { - KJ_IF_SOME(readableController, ref->tryGetReadableController()) { - // Allows for a graceful close of the readable side. Close will - // complete once all of the queued data is read or the stream - // errors. - readableController.close(js); - } else { - // Else block to avert dangling else compiler warning. - } - return js.resolvedPromise(); - }); + auto onSuccess = + JSG_VISITABLE_LAMBDA((ref = JSG_THIS), (ref), (jsg::Lock & js)->jsg::Promise { + KJ_IF_SOME(readableController, ref->tryGetReadableController()) { + // Allows for a graceful close of the readable side. Close will + // complete once all of the queued data is read or the stream + // errors. + readableController.close(js); + } else { + // Else block to avert dangling else compiler warning. + } + return js.resolvedPromise(); + }); auto onFailure = JSG_VISITABLE_LAMBDA( - (ref=JSG_THIS),(ref),(jsg::Lock& js, jsg::Value reason) -> jsg::Promise { - ref->error(js, reason.getHandle(js)); - return js.rejectedPromise(kj::mv(reason)); - }); + (ref = JSG_THIS), (ref), (jsg::Lock & js, jsg::Value reason)->jsg::Promise { + ref->error(js, reason.getHandle(js)); + return js.rejectedPromise(kj::mv(reason)); + }); - return maybeRunAlgorithm( - js, algorithms.flush, kj::mv(onSuccess), kj::mv(onFailure), JSG_THIS); + return maybeRunAlgorithm(js, algorithms.flush, kj::mv(onSuccess), kj::mv(onFailure), JSG_THIS); } jsg::Promise TransformStreamDefaultController::pull(jsg::Lock& js) { @@ -3868,55 +3763,47 @@ jsg::Promise TransformStreamDefaultController::pull(jsg::Lock& js) { } jsg::Promise TransformStreamDefaultController::cancel( - jsg::Lock& js, - v8::Local reason) { + jsg::Lock& js, v8::Local reason) { KJ_IF_SOME(finish, algorithms.maybeFinish) { return finish.whenResolved(js); } - return algorithms.maybeFinish.emplace(maybeRunAlgorithm(js, algorithms.cancel, - JSG_VISITABLE_LAMBDA( - (this, ref=JSG_THIS, reason = jsg::JsRef(js, jsg::JsValue(reason))), - (ref, reason), - (jsg::Lock& js) -> jsg::Promise { - readable = kj::none; - errorWritableAndUnblockWrite(js, reason.getHandle(js)); - return js.resolvedPromise(); - }), JSG_VISITABLE_LAMBDA( - (this, ref=JSG_THIS), - (ref), - (jsg::Lock& js, jsg::Value reason) -> jsg::Promise { - readable = kj::none; - errorWritableAndUnblockWrite(js, reason.getHandle(js)); - return js.rejectedPromise(kj::mv(reason)); - }), jsg::JsValue(reason))).whenResolved(js); + return algorithms.maybeFinish + .emplace(maybeRunAlgorithm(js, algorithms.cancel, + JSG_VISITABLE_LAMBDA( + (this, ref = JSG_THIS, reason = jsg::JsRef(js, jsg::JsValue(reason))), (ref, reason), + (jsg::Lock & js)->jsg::Promise { + readable = kj::none; + errorWritableAndUnblockWrite(js, reason.getHandle(js)); + return js.resolvedPromise(); + }), + JSG_VISITABLE_LAMBDA((this, ref = JSG_THIS), (ref), + (jsg::Lock & js, jsg::Value reason)->jsg::Promise { + readable = kj::none; + errorWritableAndUnblockWrite(js, reason.getHandle(js)); + return js.rejectedPromise(kj::mv(reason)); + }), + jsg::JsValue(reason))) + .whenResolved(js); } jsg::Promise TransformStreamDefaultController::performTransform( - jsg::Lock& js, - v8::Local chunk) { + jsg::Lock& js, v8::Local chunk) { if (algorithms.transform != kj::none) { - return maybeRunAlgorithm( - js, - algorithms.transform, - [](jsg::Lock& js) -> jsg::Promise { - return js.resolvedPromise(); - }, - JSG_VISITABLE_LAMBDA( - (ref=JSG_THIS),(ref),(jsg::Lock& js, jsg::Value reason) -> jsg::Promise { - ref->error(js, reason.getHandle(js)); - return js.rejectedPromise(kj::mv(reason)); - }), - chunk, - JSG_THIS); + return maybeRunAlgorithm(js, algorithms.transform, + [](jsg::Lock& js) -> jsg::Promise { return js.resolvedPromise(); }, + JSG_VISITABLE_LAMBDA((ref = JSG_THIS), (ref), + (jsg::Lock & js, jsg::Value reason)->jsg::Promise { + ref->error(js, reason.getHandle(js)); + return js.rejectedPromise(kj::mv(reason)); + }), + chunk, JSG_THIS); } // If we got here, there is no transform algorithm. Per the spec, the default // behavior then is to just pass along the value untransformed. return js.tryCatch([&] { enqueue(js, chunk); return js.resolvedPromise(); - }, [&](jsg::Value exception) { - return js.rejectedPromise(kj::mv(exception)); - }); + }, [&](jsg::Value exception) { return js.rejectedPromise(kj::mv(exception)); }); } void TransformStreamDefaultController::setBackpressure(jsg::Lock& js, bool newBackpressure) { @@ -3930,8 +3817,7 @@ void TransformStreamDefaultController::setBackpressure(jsg::Lock& js, bool newBa } void TransformStreamDefaultController::errorWritableAndUnblockWrite( - jsg::Lock& js, - v8::Local reason) { + jsg::Lock& js, v8::Local reason) { algorithms.clear(); KJ_IF_SOME(writableController, tryGetWritableController()) { if (writableController.isWritable()) { @@ -3951,8 +3837,7 @@ void TransformStreamDefaultController::visitForGc(jsg::GcVisitor& visitor) { visitor.visit(writable, readable, startPromise.resolver, startPromise.promise, algorithms); } -void TransformStreamDefaultController::init( - jsg::Lock& js, +void TransformStreamDefaultController::init(jsg::Lock& js, jsg::Ref& readable, jsg::Ref& writable, jsg::Optional maybeTransformer) { @@ -3975,9 +3860,9 @@ void TransformStreamDefaultController::init( // TransformStreams but does not yet define them. For now, we are limiting our implementation // here to only support value-based transforms. JSG_REQUIRE(transformer.readableType == nullptr, TypeError, - "transformer.readableType must be undefined."); + "transformer.readableType must be undefined."); JSG_REQUIRE(transformer.writableType == nullptr, TypeError, - "transformer.writableType must be undefined."); + "transformer.writableType must be undefined."); KJ_IF_SOME(transform, transformer.transform) { algorithms.transform = kj::mv(transform); @@ -3993,28 +3878,26 @@ void TransformStreamDefaultController::init( setBackpressure(js, true); - maybeRunAlgorithm( - js, - transformer.start, - JSG_VISITABLE_LAMBDA((ref=JSG_THIS), (ref), (jsg::Lock& js) { - ref->startPromise.resolver.resolve(js); - }), - JSG_VISITABLE_LAMBDA((ref=JSG_THIS), (ref), (jsg::Lock& js, jsg::Value reason) { - ref->startPromise.resolver.reject(js, reason.getHandle(js)); - }), + maybeRunAlgorithm(js, transformer.start, + JSG_VISITABLE_LAMBDA( + (ref = JSG_THIS), (ref), (jsg::Lock& js) { ref->startPromise.resolver.resolve(js); }), + JSG_VISITABLE_LAMBDA((ref = JSG_THIS), (ref), + (jsg::Lock& js, jsg::Value reason) { + ref->startPromise.resolver.reject(js, reason.getHandle(js)); + }), JSG_THIS); } -kj::Maybe -TransformStreamDefaultController::tryGetReadableController() { +kj::Maybe TransformStreamDefaultController:: + tryGetReadableController() { KJ_IF_SOME(controller, readable) { return *controller; } return kj::none; } -kj::Maybe -TransformStreamDefaultController::tryGetWritableController() { +kj::Maybe TransformStreamDefaultController:: + tryGetWritableController() { KJ_IF_SOME(w, writable) { return static_cast(w->getController()); } @@ -4036,14 +3919,16 @@ void WritableImpl::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { tracker.trackField("signal", signal); KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } KJ_CASE_ONEOF(error, StreamStates::Errored) { tracker.trackField("error", error); } KJ_CASE_ONEOF(erroring, StreamStates::Erroring) { tracker.trackField("erroring", erroring.reason); } - KJ_CASE_ONEOF(writable, Writable) {} + KJ_CASE_ONEOF(writable, Writable) { + } } tracker.trackField("abortAlgorithm", algorithms.abort); @@ -4051,7 +3936,7 @@ void WritableImpl::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { tracker.trackField("writeAlgorithm", algorithms.write); tracker.trackField("sizeAlgorithm", algorithms.size); - for (auto& request : writeRequests) { + for (auto& request: writeRequests) { tracker.trackField("pendingWrite", request); } @@ -4071,7 +3956,8 @@ size_t WritableStreamJsController::jsgGetMemorySelfSize() const { void WritableStreamJsController::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } KJ_CASE_ONEOF(error, StreamStates::Errored) { tracker.trackField("error", error); } @@ -4097,7 +3983,8 @@ size_t ReadableStreamJsController::jsgGetMemorySelfSize() const { void ReadableStreamJsController::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } KJ_CASE_ONEOF(error, StreamStates::Errored) { tracker.trackField("error", error); } @@ -4113,7 +4000,8 @@ void ReadableStreamJsController::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) c KJ_IF_SOME(pendingState, maybePendingState) { KJ_SWITCH_ONEOF(pendingState) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } KJ_CASE_ONEOF(error, StreamStates::Errored) { tracker.trackField("pendingError", error); } @@ -4134,7 +4022,8 @@ size_t ReadableImpl::jsgGetMemorySelfSize() const { template void ReadableImpl::jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const { KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(closed, StreamStates::Closed) {} + KJ_CASE_ONEOF(closed, StreamStates::Closed) { + } KJ_CASE_ONEOF(error, StreamStates::Errored) { tracker.trackField("error", error); } @@ -4169,45 +4058,48 @@ void TransformStreamDefaultController::visitForMemoryInfo(jsg::MemoryTracker& tr // ====================================================================================== -jsg::Ref ReadableStream::from(jsg::Lock& js, - jsg::AsyncGenerator generator) { +jsg::Ref ReadableStream::from( + jsg::Lock& js, jsg::AsyncGenerator generator) { // AsyncGenerator is not a refcounted type, so we need to wrap it in a refcounted // struct so that we can keep it alive through the various promise branches below. - struct RefcountedGenerator : public kj::Refcounted { + struct RefcountedGenerator: public kj::Refcounted { jsg::AsyncGenerator generator; - RefcountedGenerator(jsg::AsyncGenerator generator) - : generator(kj::mv(generator)) {} + RefcountedGenerator(jsg::AsyncGenerator generator): generator(kj::mv(generator)) {} }; auto rcGenerator = kj::refcounted(kj::mv(generator)); - return constructor(js, UnderlyingSource { - .pull = [generator=kj::addRef(*rcGenerator)](jsg::Lock& js, auto controller) mutable { - auto& c = controller.template get(); - return generator->generator.next(js).then(js, - JSG_VISITABLE_LAMBDA( - (controller=c.addRef(), generator=kj::addRef(*generator)), - (controller), - (jsg::Lock& js, kj::Maybe value) { - KJ_IF_SOME(v, value) { - controller->enqueue(js, v.getHandle(js)); - } else { - controller->close(js); - } - return js.resolvedPromise(); - }), JSG_VISITABLE_LAMBDA( - (controller=c.addRef(), generator=kj::addRef(*generator)), - (controller), - (jsg::Lock& js, jsg::Value reason) { - controller->error(js, reason.getHandle(js)); - return js.rejectedPromise(kj::mv(reason)); - })); - }, - .cancel = [generator=kj::addRef(*rcGenerator)](jsg::Lock& js, auto reason) mutable { - return generator->generator.return_(js, kj::none) - .then(js, [genertor=kj::mv(generator)](auto& lock) {}); - }, - }, StreamQueuingStrategy { .highWaterMark = 0, }); + return constructor(js, + UnderlyingSource{ + .pull = + [generator = kj::addRef(*rcGenerator)](jsg::Lock& js, auto controller) mutable { + auto& c = controller.template get(); + return generator->generator.next(js).then(js, + JSG_VISITABLE_LAMBDA((controller = c.addRef(), generator = kj::addRef(*generator)), + (controller), + (jsg::Lock& js, kj::Maybe value) { + KJ_IF_SOME(v, value) { + controller->enqueue(js, v.getHandle(js)); + } else { + controller->close(js); + } + return js.resolvedPromise(); + }), + JSG_VISITABLE_LAMBDA((controller = c.addRef(), generator = kj::addRef(*generator)), + (controller), (jsg::Lock& js, jsg::Value reason) { + controller->error(js, reason.getHandle(js)); + return js.rejectedPromise(kj::mv(reason)); + })); + }, + .cancel = + [generator = kj::addRef(*rcGenerator)](jsg::Lock& js, auto reason) mutable { + return generator->generator.return_(js, kj::none) + .then(js, [genertor = kj::mv(generator)](auto& lock) {}); + }, + }, + StreamQueuingStrategy{ + .highWaterMark = 0, + }); } } // namespace workerd::api diff --git a/src/workerd/api/streams/standard.h b/src/workerd/api/streams/standard.h index 3f6027ad4da..6d0221ba0e2 100644 --- a/src/workerd/api/streams/standard.h +++ b/src/workerd/api/streams/standard.h @@ -134,16 +134,13 @@ class ReadableImpl { using Entry = typename Self::QueueType::Entry; using StateListener = typename Self::QueueType::ConsumerImpl::StateListener; - ReadableImpl(UnderlyingSource underlyingSource, - StreamQueuingStrategy queuingStrategy); + ReadableImpl(UnderlyingSource underlyingSource, StreamQueuingStrategy queuingStrategy); // Invokes the start algorithm to initialize the underlying source. void start(jsg::Lock& js, jsg::Ref self); // If the readable is not already closed or errored, initiates a cancellation. - jsg::Promise cancel(jsg::Lock& js, - jsg::Ref self, - v8::Local maybeReason); + jsg::Promise cancel(jsg::Lock& js, jsg::Ref self, v8::Local maybeReason); // True if the readable is not closed, not errored, and close has not already been requested. bool canCloseOrEnqueue(); @@ -268,9 +265,7 @@ class WritableImpl { WritableImpl(WritableStream& owner); - jsg::Promise abort(jsg::Lock& js, - jsg::Ref self, - v8::Local reason); + jsg::Promise abort(jsg::Lock& js, jsg::Ref self, v8::Local reason); void advanceQueueIfNeeded(jsg::Lock& js, jsg::Ref self); @@ -289,14 +284,10 @@ class WritableImpl { void finishErroring(jsg::Lock& js, jsg::Ref self); void finishInFlightClose( - jsg::Lock& js, - jsg::Ref self, - kj::Maybe> reason = kj::none); + jsg::Lock& js, jsg::Ref self, kj::Maybe> reason = kj::none); void finishInFlightWrite( - jsg::Lock& js, - jsg::Ref self, - kj::Maybe> reason = kj::none); + jsg::Lock& js, jsg::Ref self, kj::Maybe> reason = kj::none); ssize_t getDesiredSize(); @@ -306,8 +297,7 @@ class WritableImpl { kj::Maybe tryGetOwner(); - void setup( - jsg::Lock& js, + void setup(jsg::Lock& js, jsg::Ref self, UnderlyingSink underlyingSink, StreamQueuingStrategy queuingStrategy); @@ -336,7 +326,6 @@ class WritableImpl { void jsgGetMemoryInfo(jsg::MemoryTracker& tracker) const; private: - struct Algorithms { kj::Maybe> abort; kj::Maybe> close; @@ -369,10 +358,8 @@ class WritableImpl { // try tracing each other. kj::Maybe>> owner; jsg::Ref signal; - kj::OneOf state = Writable(); + kj::OneOf state = + Writable(); Algorithms algorithms; bool started = false; bool starting = false; @@ -402,13 +389,12 @@ class ReadableStreamDefaultController: public jsg::Object { using QueueType = ValueQueue; using ReadableImpl = ReadableImpl; - ReadableStreamDefaultController(UnderlyingSource underlyingSource, - StreamQueuingStrategy queuingStrategy); + ReadableStreamDefaultController( + UnderlyingSource underlyingSource, StreamQueuingStrategy queuingStrategy); void start(jsg::Lock& js); - jsg::Promise cancel(jsg::Lock& js, - jsg::Optional> maybeReason); + jsg::Promise cancel(jsg::Lock& js, jsg::Optional> maybeReason); void close(jsg::Lock& js); @@ -464,8 +450,7 @@ class ReadableStreamDefaultController: public jsg::Object { // object name. class ReadableStreamBYOBRequest: public jsg::Object { public: - ReadableStreamBYOBRequest( - jsg::Lock& js, + ReadableStreamBYOBRequest(jsg::Lock& js, kj::Own readRequest, jsg::Ref controller); @@ -505,8 +490,8 @@ class ReadableStreamBYOBRequest: public jsg::Object { jsg::V8Ref view; Impl(jsg::Lock& js, - kj::Own readRequest, - jsg::Ref controller); + kj::Own readRequest, + jsg::Ref controller); void updateView(jsg::Lock& js); }; @@ -525,13 +510,12 @@ class ReadableByteStreamController: public jsg::Object { using QueueType = ByteQueue; using ReadableImpl = ReadableImpl; - ReadableByteStreamController(UnderlyingSource underlyingSource, - StreamQueuingStrategy queuingStrategy); + ReadableByteStreamController( + UnderlyingSource underlyingSource, StreamQueuingStrategy queuingStrategy); void start(jsg::Lock& js); - jsg::Promise cancel(jsg::Lock& js, - jsg::Optional> maybeReason); + jsg::Promise cancel(jsg::Lock& js, jsg::Optional> maybeReason); void close(jsg::Lock& js); @@ -598,12 +582,11 @@ class WritableStreamDefaultController: public jsg::Object { kj::Maybe> isErroring(jsg::Lock& js); - bool isStarted() { return impl.started; } + bool isStarted() { + return impl.started; + } - void setup( - jsg::Lock& js, - UnderlyingSink underlyingSink, - StreamQueuingStrategy queuingStrategy); + void setup(jsg::Lock& js, UnderlyingSink underlyingSink, StreamQueuingStrategy queuingStrategy); jsg::Promise write(jsg::Lock& js, v8::Local value); @@ -638,9 +621,9 @@ class TransformStreamDefaultController: public jsg::Object { TransformStreamDefaultController(jsg::Lock& js); void init(jsg::Lock& js, - jsg::Ref& readable, - jsg::Ref& writable, - jsg::Optional maybeTransformer); + jsg::Ref& readable, + jsg::Ref& writable, + jsg::Optional maybeTransformer); // The startPromise is used by both the readable and writable sides in their respective // start algorithms. The promise itself is resolved within the init function when the @@ -699,10 +682,8 @@ class TransformStreamDefaultController: public jsg::Object { } }; - void errorWritableAndUnblockWrite(jsg::Lock& js, - v8::Local reason); - jsg::Promise performTransform(jsg::Lock& js, - v8::Local chunk); + void errorWritableAndUnblockWrite(jsg::Lock& js, v8::Local reason); + jsg::Promise performTransform(jsg::Lock& js, v8::Local chunk); void setBackpressure(jsg::Lock& js, bool newBackpressure); kj::Maybe ioContext; diff --git a/src/workerd/api/streams/transform.c++ b/src/workerd/api/streams/transform.c++ index f5f19a805c4..c83e2a2b56b 100644 --- a/src/workerd/api/streams/transform.c++ +++ b/src/workerd/api/streams/transform.c++ @@ -11,17 +11,16 @@ namespace workerd::api { namespace { - template +template jsg::Function maybeAddFunctor(auto t) { if (IoContext::hasCurrent()) { return jsg::Function(IoContext::current().addFunctor(kj::mv(t))); } return jsg::Function(kj::mv(t)); } -} +} // namespace -jsg::Ref TransformStream::constructor( - jsg::Lock& js, +jsg::Ref TransformStream::constructor(jsg::Lock& js, jsg::Optional maybeTransformer, jsg::Optional maybeWritableStrategy, jsg::Optional maybeReadableStrategy) { @@ -48,67 +47,46 @@ jsg::Ref TransformStream::constructor( // to zero if a strategy is not given. This effectively means that writes/reads will be // one to one as long as the writer is respecting backpressure signals. If buffering // occurs, it will happen in the writable side of the transform stream. - auto readableStrategy = kj::mv(maybeReadableStrategy).orDefault(StreamQueuingStrategy { - .highWaterMark = 0, - }); + auto readableStrategy = kj::mv(maybeReadableStrategy) + .orDefault(StreamQueuingStrategy{ + .highWaterMark = 0, + }); - auto readable = ReadableStream::constructor( - js, - UnderlyingSource { + auto readable = ReadableStream::constructor(js, + UnderlyingSource{ .type = kj::none, .autoAllocateChunkSize = kj::none, - .start = maybeAddFunctor(JSG_VISITABLE_LAMBDA( - (controller = controller.addRef()), - (controller), - (jsg::Lock& js, auto c) mutable { - return controller->getStartPromise(js); - })), - .pull = maybeAddFunctor(JSG_VISITABLE_LAMBDA( - (controller = controller.addRef()), - (controller), - (jsg::Lock& js, auto c) mutable { - return controller->pull(js); - })), + .start = maybeAddFunctor( + JSG_VISITABLE_LAMBDA((controller = controller.addRef()), (controller), + (jsg::Lock & js, auto c) mutable { return controller->getStartPromise(js); })), + .pull = maybeAddFunctor( + JSG_VISITABLE_LAMBDA((controller = controller.addRef()), (controller), + (jsg::Lock & js, auto c) mutable { return controller->pull(js); })), .cancel = maybeAddFunctor(JSG_VISITABLE_LAMBDA( - (controller = controller.addRef()), - (controller), - (jsg::Lock& js, auto reason) mutable { - return controller->cancel(js, reason); - })), - .expectedLength = transformer.expectedLength.map([](uint64_t expectedLength) { - return expectedLength; - }), + (controller = controller.addRef()), (controller), + (jsg::Lock & js, auto reason) mutable { return controller->cancel(js, reason); })), + .expectedLength = transformer.expectedLength.map( + [](uint64_t expectedLength) { return expectedLength; }), }, kj::mv(readableStrategy)); - auto writable = WritableStream::constructor( - js, - UnderlyingSink { + auto writable = WritableStream::constructor(js, + UnderlyingSink{ .type = kj::none, - .start = maybeAddFunctor(JSG_VISITABLE_LAMBDA( - (controller = controller.addRef()), - (controller), - (jsg::Lock& js, auto c) mutable { - return controller->getStartPromise(js); - })), - .write = maybeAddFunctor(JSG_VISITABLE_LAMBDA( - (controller = controller.addRef()), - (controller), - (jsg::Lock& js, auto chunk, auto c) mutable { - return controller->write(js, chunk); - })), - .abort = maybeAddFunctor(JSG_VISITABLE_LAMBDA( - (controller = controller.addRef()), - (controller), - (jsg::Lock& js, auto reason) mutable { - return controller->abort(js, reason); - })), - .close = maybeAddFunctor(JSG_VISITABLE_LAMBDA( - (controller = controller.addRef()), - (controller), - (jsg::Lock& js) mutable { - return controller->close(js); - })), + .start = maybeAddFunctor( + JSG_VISITABLE_LAMBDA((controller = controller.addRef()), (controller), + (jsg::Lock & js, auto c) mutable { return controller->getStartPromise(js); })), + .write = maybeAddFunctor( + JSG_VISITABLE_LAMBDA((controller = controller.addRef()), (controller), + (jsg::Lock & js, auto chunk, auto c) mutable { + return controller->write(js, chunk); + })), + .abort = maybeAddFunctor( + JSG_VISITABLE_LAMBDA((controller = controller.addRef()), (controller), + (jsg::Lock & js, auto reason) mutable { return controller->abort(js, reason); })), + .close = maybeAddFunctor( + JSG_VISITABLE_LAMBDA((controller = controller.addRef()), (controller), + (jsg::Lock & js) mutable { return controller->close(js); })), }, kj::mv(maybeWritableStrategy)); @@ -122,8 +100,7 @@ jsg::Ref TransformStream::constructor( // The old implementation just defers to IdentityTransformStream. If any of the arguments // are specified we throw because it's most likely that they want the standard implementation // but the compatibility flag is not set. - if (maybeTransformer != kj::none || - maybeWritableStrategy != kj::none || + if (maybeTransformer != kj::none || maybeWritableStrategy != kj::none || maybeReadableStrategy != kj::none) { IoContext::current().logWarningOnce( "To use the new TransformStream() constructor with a " @@ -135,8 +112,7 @@ jsg::Ref TransformStream::constructor( } jsg::Ref IdentityTransformStream::constructor( - jsg::Lock& js, - jsg::Optional maybeQueuingStrategy) { + jsg::Lock& js, jsg::Optional maybeQueuingStrategy) { auto& ioContext = IoContext::current(); auto pipe = newIdentityPipe(); @@ -146,13 +122,11 @@ jsg::Ref IdentityTransformStream::constructor( maybeHighWaterMark = queuingStrategy.highWaterMark; } - return jsg::alloc( - jsg::alloc(ioContext, kj::mv(pipe.in)), + return jsg::alloc(jsg::alloc(ioContext, kj::mv(pipe.in)), jsg::alloc(ioContext, kj::mv(pipe.out), maybeHighWaterMark)); } -jsg::Ref FixedLengthStream::constructor( - jsg::Lock& js, +jsg::Ref FixedLengthStream::constructor(jsg::Lock& js, uint64_t expectedLength, jsg::Optional maybeQueuingStrategy) { constexpr uint64_t MAX_SAFE_INTEGER = (1ull << 53) - 1; @@ -166,23 +140,18 @@ jsg::Ref FixedLengthStream::constructor( kj::Maybe maybeHighWaterMark = kj::none; // For a FixedLengthStream we do not want a highWaterMark higher than the expectedLength. KJ_IF_SOME(queuingStrategy, maybeQueuingStrategy) { - maybeHighWaterMark = queuingStrategy.highWaterMark.map([&](uint64_t highWaterMark) { - return kj::min(expectedLength, highWaterMark); - }); + maybeHighWaterMark = queuingStrategy.highWaterMark.map( + [&](uint64_t highWaterMark) { return kj::min(expectedLength, highWaterMark); }); } - return jsg::alloc( - jsg::alloc(ioContext, kj::mv(pipe.in)), + return jsg::alloc(jsg::alloc(ioContext, kj::mv(pipe.in)), jsg::alloc(ioContext, kj::mv(pipe.out), maybeHighWaterMark)); } OneWayPipe newIdentityPipe(kj::Maybe expectedLength) { auto readableSide = kj::refcounted(expectedLength); auto writableSide = kj::addRef(*readableSide); - return OneWayPipe { - .in = kj::mv(readableSide), - .out = kj::mv(writableSide) - }; + return OneWayPipe{.in = kj::mv(readableSide), .out = kj::mv(writableSide)}; } } // namespace workerd::api diff --git a/src/workerd/api/streams/transform.h b/src/workerd/api/streams/transform.h index 42fe5da086e..0ca35b92a38 100644 --- a/src/workerd/api/streams/transform.h +++ b/src/workerd/api/streams/transform.h @@ -22,14 +22,11 @@ namespace workerd::api { // the TransformStream implements standardized behavior. class TransformStream: public jsg::Object { public: - explicit TransformStream( - jsg::Ref readable, - jsg::Ref writable) + explicit TransformStream(jsg::Ref readable, jsg::Ref writable) : readable(kj::mv(readable)), writable(kj::mv(writable)) {} - static jsg::Ref constructor( - jsg::Lock& js, + static jsg::Ref constructor(jsg::Lock& js, jsg::Optional maybeTransformer, jsg::Optional maybeWritableStrategy, jsg::Optional maybeReadableStrategy); @@ -92,8 +89,7 @@ class IdentityTransformStream: public TransformStream { }; static jsg::Ref constructor( - jsg::Lock& js, - jsg::Optional queuingStrategy = kj::none); + jsg::Lock& js, jsg::Optional queuingStrategy = kj::none); JSG_RESOURCE_TYPE(IdentityTransformStream) { JSG_INHERIT(TransformStream); @@ -109,8 +105,7 @@ class FixedLengthStream: public IdentityTransformStream { public: using IdentityTransformStream::IdentityTransformStream; - static jsg::Ref constructor( - jsg::Lock& js, + static jsg::Ref constructor(jsg::Lock& js, uint64_t expectedLength, jsg::Optional queuingStrategy = kj::none); diff --git a/src/workerd/api/streams/writable.c++ b/src/workerd/api/streams/writable.c++ index c5e317f7cf4..2f472922dde 100644 --- a/src/workerd/api/streams/writable.c++ +++ b/src/workerd/api/streams/writable.c++ @@ -9,8 +9,7 @@ namespace workerd::api { -WritableStreamDefaultWriter::WritableStreamDefaultWriter() - : ioContext(tryGetIoContext()) {} +WritableStreamDefaultWriter::WritableStreamDefaultWriter(): ioContext(tryGetIoContext()) {} WritableStreamDefaultWriter::~WritableStreamDefaultWriter() noexcept(false) { KJ_IF_SOME(stream, state.tryGet()) { @@ -19,18 +18,16 @@ WritableStreamDefaultWriter::~WritableStreamDefaultWriter() noexcept(false) { } jsg::Ref WritableStreamDefaultWriter::constructor( - jsg::Lock& js, - jsg::Ref stream) { - JSG_REQUIRE(!stream->isLocked(), TypeError, - "This WritableStream is currently locked to a writer."); + jsg::Lock& js, jsg::Ref stream) { + JSG_REQUIRE( + !stream->isLocked(), TypeError, "This WritableStream is currently locked to a writer."); auto writer = jsg::alloc(); writer->lockToStream(js, *stream); return kj::mv(writer); } jsg::Promise WritableStreamDefaultWriter::abort( - jsg::Lock& js, - jsg::Optional> reason) { + jsg::Lock& js, jsg::Optional> reason) { KJ_SWITCH_ONEOF(state) { KJ_CASE_ONEOF(i, Initial) { KJ_FAIL_ASSERT("this writer was never attached"); @@ -54,8 +51,7 @@ jsg::Promise WritableStreamDefaultWriter::abort( KJ_UNREACHABLE; } -void WritableStreamDefaultWriter::attach( - WritableStreamController& controller, +void WritableStreamDefaultWriter::attach(WritableStreamController& controller, jsg::Promise closedPromise, jsg::Promise readyPromise) { KJ_ASSERT(state.is()); @@ -82,8 +78,7 @@ jsg::Promise WritableStreamDefaultWriter::close(jsg::Lock& js) { js.v8TypeError("This WritableStream writer has been released."_kj)); } KJ_CASE_ONEOF(c, StreamStates::Closed) { - return js.rejectedPromise( - js.v8TypeError("This WritableStream has been closed."_kj)); + return js.rejectedPromise(js.v8TypeError("This WritableStream has been closed."_kj)); } } KJ_UNREACHABLE; @@ -187,8 +182,7 @@ jsg::Promise WritableStreamDefaultWriter::write(jsg::Lock& js, v8::Local( - js.v8TypeError("This WritableStream has been closed."_kj)); + return js.rejectedPromise(js.v8TypeError("This WritableStream has been closed."_kj)); } } KJ_UNREACHABLE; @@ -219,13 +213,12 @@ void WritableStreamDefaultWriter::visitForGc(jsg::GcVisitor& visitor) { // ====================================================================================== -WritableStream::WritableStream( - IoContext& ioContext, +WritableStream::WritableStream(IoContext& ioContext, kj::Own sink, kj::Maybe maybeHighWaterMark, kj::Maybe> maybeClosureWaitable) - : WritableStream(newWritableStreamInternalController(ioContext, kj::mv(sink), - maybeHighWaterMark, kj::mv(maybeClosureWaitable))) {} + : WritableStream(newWritableStreamInternalController( + ioContext, kj::mv(sink), maybeHighWaterMark, kj::mv(maybeClosureWaitable))) {} WritableStream::WritableStream(kj::Own controller) : ioContext(tryGetIoContext()), @@ -233,20 +226,24 @@ WritableStream::WritableStream(kj::Own controller) getController().setOwnerRef(*this); } -jsg::Ref WritableStream::addRef() { return JSG_THIS; } +jsg::Ref WritableStream::addRef() { + return JSG_THIS; +} void WritableStream::visitForGc(jsg::GcVisitor& visitor) { visitor.visit(getController()); } -bool WritableStream::isLocked() { return getController().isLockedToWriter(); } +bool WritableStream::isLocked() { + return getController().isLockedToWriter(); +} -WritableStreamController& WritableStream::getController() { return *controller; } +WritableStreamController& WritableStream::getController() { + return *controller; +} kj::Own WritableStream::removeSink(jsg::Lock& js) { - return JSG_REQUIRE_NONNULL( - getController().removeSink(js), - TypeError, + return JSG_REQUIRE_NONNULL(getController().removeSink(js), TypeError, "This WritableStream does not have a WritableStreamSink"); } @@ -255,8 +252,7 @@ void WritableStream::detach(jsg::Lock& js) { } jsg::Promise WritableStream::abort( - jsg::Lock& js, - jsg::Optional> reason) { + jsg::Lock& js, jsg::Optional> reason) { if (isLocked()) { return js.rejectedPromise( js.v8TypeError("This WritableStream is currently locked to a writer."_kj)); @@ -284,15 +280,13 @@ jsg::Ref WritableStream::getWriter(jsg::Lock& js) { return WritableStreamDefaultWriter::constructor(js, JSG_THIS); } -jsg::Ref WritableStream::constructor( - jsg::Lock& js, +jsg::Ref WritableStream::constructor(jsg::Lock& js, jsg::Optional underlyingSink, jsg::Optional queuingStrategy) { - JSG_REQUIRE(FeatureFlags::get(js).getStreamsJavaScriptControllers(), - Error, - "To use the new WritableStream() constructor, enable the " - "streams_enable_constructors compatibility flag. " - "Refer to the docs for more information: https://developers.cloudflare.com/workers/platform/compatibility-dates/#compatibility-flags"); + JSG_REQUIRE(FeatureFlags::get(js).getStreamsJavaScriptControllers(), Error, + "To use the new WritableStream() constructor, enable the " + "streams_enable_constructors compatibility flag. " + "Refer to the docs for more information: https://developers.cloudflare.com/workers/platform/compatibility-dates/#compatibility-flags"); auto stream = jsg::alloc(newWritableStreamJsController()); stream->getController().setup(js, kj::mv(underlyingSink), kj::mv(queuingStrategy)); return kj::mv(stream); @@ -303,8 +297,7 @@ namespace { // Wrapper around `WritableStreamSink` that makes it suitable for passing off to capnp RPC. class WritableStreamRpcAdapter final: public capnp::ExplicitEndOutputStream { public: - WritableStreamRpcAdapter(kj::Own inner) - : inner(kj::mv(inner)) {} + WritableStreamRpcAdapter(kj::Own inner): inner(kj::mv(inner)) {} ~WritableStreamRpcAdapter() noexcept(false) { weakRef->invalidate(); doneFulfiller->fulfill(); @@ -357,9 +350,7 @@ private: kj::Badge(), *this); WritableStreamSink& getInner() { - return *KJ_UNWRAP_OR(inner, { - kj::throwFatalException(cancellationException()); - }); + return *KJ_UNWRAP_OR(inner, { kj::throwFatalException(cancellationException()); }); } static kj::Exception cancellationException() { @@ -377,7 +368,8 @@ private: class WritableStreamJsRpcAdapter final: public capnp::ExplicitEndOutputStream { public: WritableStreamJsRpcAdapter(IoContext& context, jsg::Ref writer) - : context(context), writer(kj::mv(writer)) {} + : context(context), + writer(kj::mv(writer)) {} ~WritableStreamJsRpcAdapter() noexcept(false) { weakRef->invalidate(); @@ -406,13 +398,11 @@ public: // hopefully improve the situation here. if (!ended) { KJ_IF_SOME(writer, this->writer) { - context.addTask(context.run( - [writer=kj::mv(writer), exception=cancellationException()] - (Worker::Lock& lock) mutable { + context.addTask(context.run([writer = kj::mv(writer), exception = cancellationException()]( + Worker::Lock& lock) mutable { jsg::Lock& js = lock; auto ex = js.exceptionToJs(kj::mv(exception)); - return IoContext::current().awaitJs(lock, - writer->abort(lock, ex.getHandle(js))); + return IoContext::current().awaitJs(lock, writer->abort(lock, ex.getHandle(js))); })); } } @@ -432,13 +422,12 @@ public: } auto w = kj::mv(obj.writer); KJ_IF_SOME(writer, w) { - obj.context.addTask(obj.context.run( - [writer=kj::mv(writer), exception=cancellationException()] - (Worker::Lock& lock) mutable { + obj.context.addTask( + obj.context.run([writer = kj::mv(writer), exception = cancellationException()]( + Worker::Lock& lock) mutable { jsg::Lock& js = lock; auto ex = js.exceptionToJs(kj::mv(exception)); - return IoContext::current().awaitJs(lock, - writer->abort(lock, ex.getHandle(js))); + return IoContext::current().awaitJs(lock, writer->abort(lock, ex.getHandle(js))); })); } } @@ -463,7 +452,7 @@ public: return KJ_EXCEPTION(FAILED, "Write after stream has been closed."); } auto amount = 0; - for (auto& piece : pieces) { + for (auto& piece: pieces) { amount += piece.size(); } if (amount == 0) return kj::READY_NOW; @@ -475,7 +464,7 @@ public: // for the ArrayBuffer remains valid. auto source = KJ_ASSERT_NONNULL(jsg::BufferSource::tryAlloc(lock, amount)); auto ptr = source.asArrayPtr(); - for (auto& piece : pieces) { + for (auto& piece: pieces) { KJ_DASSERT(ptr.size() > 0); KJ_DASSERT(piece.size() <= ptr.size()); if (piece.size() == 0) continue; @@ -573,9 +562,8 @@ void WritableStream::serialize(jsg::Lock& js, jsg::Serializer& serializer) { auto capnpStream = ioctx.getByteStreamFactory().kjToCapnp(kj::mv(wrapper)); - externalHandler->write( - [capnpStream = kj::mv(capnpStream), encoding] - (rpc::JsValue::External::Builder builder) mutable { + externalHandler->write([capnpStream = kj::mv(capnpStream), encoding]( + rpc::JsValue::External::Builder builder) mutable { auto ws = builder.initWritableStream(); ws.setByteStream(kj::mv(capnpStream)); ws.setEncoding(encoding); @@ -593,8 +581,7 @@ void WritableStream::serialize(jsg::Lock& js, jsg::Serializer& serializer) { auto capnpStream = ioctx.getByteStreamFactory().kjToCapnp(kj::mv(wrapper)); externalHandler->write( - [capnpStream = kj::mv(capnpStream)] - (rpc::JsValue::External::Builder builder) mutable { + [capnpStream = kj::mv(capnpStream)](rpc::JsValue::External::Builder builder) mutable { auto ws = builder.initWritableStream(); ws.setByteStream(kj::mv(capnpStream)); ws.setEncoding(StreamEncoding::IDENTITY); @@ -604,8 +591,8 @@ void WritableStream::serialize(jsg::Lock& js, jsg::Serializer& serializer) { jsg::Ref WritableStream::deserialize( jsg::Lock& js, rpc::SerializationTag tag, jsg::Deserializer& deserializer) { - auto& handler = KJ_REQUIRE_NONNULL(deserializer.getExternalHandler(), - "got WritableStream on non-RPC serialized object?"); + auto& handler = KJ_REQUIRE_NONNULL( + deserializer.getExternalHandler(), "got WritableStream on non-RPC serialized object?"); auto externalHandler = dynamic_cast(&handler); KJ_REQUIRE(externalHandler != nullptr, "got WritableStream on non-RPC serialized object?"); @@ -615,8 +602,8 @@ jsg::Ref WritableStream::deserialize( auto ws = reader.getWritableStream(); auto encoding = ws.getEncoding(); - KJ_REQUIRE(static_cast(encoding) < - capnp::Schema::from().getEnumerants().size(), + KJ_REQUIRE( + static_cast(encoding) < capnp::Schema::from().getEnumerants().size(), "unknown StreamEncoding received from peer"); IoContext& ioctx = IoContext::current(); diff --git a/src/workerd/api/streams/writable.h b/src/workerd/api/streams/writable.h index a7bdd39b7eb..0c2055b409f 100644 --- a/src/workerd/api/streams/writable.h +++ b/src/workerd/api/streams/writable.h @@ -9,8 +9,7 @@ namespace workerd::api { -class WritableStreamDefaultWriter: public jsg::Object, - public WritableStreamController::Writer { +class WritableStreamDefaultWriter: public jsg::Object, public WritableStreamController::Writer { public: explicit WritableStreamDefaultWriter(); @@ -19,8 +18,7 @@ class WritableStreamDefaultWriter: public jsg::Object, // JavaScript API static jsg::Ref constructor( - jsg::Lock& js, - jsg::Ref stream); + jsg::Lock& js, jsg::Ref stream); jsg::MemoizedIdentity>& getClosed(); jsg::MemoizedIdentity>& getReady(); @@ -65,8 +63,7 @@ class WritableStreamDefaultWriter: public jsg::Object, // Internal API - void attach( - WritableStreamController& controller, + void attach(WritableStreamController& controller, jsg::Promise closedPromise, jsg::Promise readyPromise) override; @@ -102,12 +99,14 @@ class WritableStreamDefaultWriter: public jsg::Object, class WritableStream: public jsg::Object { public: explicit WritableStream(IoContext& ioContext, - kj::Own sink, - kj::Maybe maybeHighWaterMark = kj::none, - kj::Maybe> maybeClosureWaitable = kj::none); + kj::Own sink, + kj::Maybe maybeHighWaterMark = kj::none, + kj::Maybe> maybeClosureWaitable = kj::none); explicit WritableStream(kj::Own controller); - ~WritableStream() noexcept(false) { weakRef->invalidate(); } + ~WritableStream() noexcept(false) { + weakRef->invalidate(); + } WritableStreamController& getController(); @@ -125,8 +124,7 @@ class WritableStream: public jsg::Object { // --------------------------------------------------------------------------- // JS interface - static jsg::Ref constructor( - jsg::Lock& js, + static jsg::Ref constructor(jsg::Lock& js, jsg::Optional underlyingSink, jsg::Optional queuingStrategy); @@ -178,7 +176,9 @@ class WritableStream: public jsg::Object { kj::Own> weakRef = kj::refcounted>(kj::Badge(), *this); - kj::Own> addWeakRef() { return weakRef->addRef(); } + kj::Own> addWeakRef() { + return weakRef->addRef(); + } void visitForGc(jsg::GcVisitor& visitor); diff --git a/src/workerd/api/system-streams.c++ b/src/workerd/api/system-streams.c++ index 8ecafc7b162..bb6918e0ff7 100644 --- a/src/workerd/api/system-streams.c++ +++ b/src/workerd/api/system-streams.c++ @@ -19,14 +19,16 @@ namespace { // stream and whether or not it requires pending event registration. class EncodedAsyncInputStream final: public ReadableStreamSource { public: - explicit EncodedAsyncInputStream(kj::Own inner, StreamEncoding encoding, - IoContext& context); + explicit EncodedAsyncInputStream( + kj::Own inner, StreamEncoding encoding, IoContext& context); // Read bytes in identity encoding. If the stream is not already in identity encoding, it will be // converted to identity encoding via an appropriate stream wrapper. kj::Promise tryRead(void* buffer, size_t minBytes, size_t maxBytes) override; - StreamEncoding getPreferredEncoding() override { return encoding; } + StreamEncoding getPreferredEncoding() override { + return encoding; + } // Return the number of bytes, if known, which this input stream will produce if the sink is known // to be of a particular encoding. @@ -56,36 +58,32 @@ private: EncodedAsyncInputStream::EncodedAsyncInputStream( kj::Own inner, StreamEncoding encoding, IoContext& context) - : inner(kj::mv(inner)), encoding(encoding), ioContext(context) {} + : inner(kj::mv(inner)), + encoding(encoding), + ioContext(context) {} kj::Promise EncodedAsyncInputStream::tryRead( void* buffer, size_t minBytes, size_t maxBytes) { ensureIdentityEncoding(); return kj::evalNow([&]() { - return inner->tryRead(buffer, minBytes, maxBytes) - .attach(ioContext.registerPendingEvent()); + return inner->tryRead(buffer, minBytes, maxBytes).attach(ioContext.registerPendingEvent()); }).catch_([](kj::Exception&& exception) -> kj::Promise { - KJ_IF_SOME(e, translateKjException(exception, { - { "gzip compressed stream ended prematurely"_kj, - "Gzip compressed stream ended prematurely."_kj }, - { "gzip decompression failed"_kj, - "Gzip decompression failed." }, - { "brotli state allocation failed"_kj, - "Brotli state allocation failed." }, - { "invalid brotli window size"_kj, - "Invalid brotli window size." }, - { "invalid brotli compression level"_kj, - "Invalid brotli compression level." }, - { "brotli window size too big"_kj, - "Brotli window size too big." }, - { "brotli decompression failed"_kj, - "Brotli decompression failed." }, - { "brotli compression failed"_kj, - "Brotli compression failed." }, - { "brotli compressed stream ended prematurely"_kj, - "Brotli compressed stream ended prematurely." }, - })) { + KJ_IF_SOME(e, + translateKjException(exception, + { + {"gzip compressed stream ended prematurely"_kj, + "Gzip compressed stream ended prematurely."_kj}, + {"gzip decompression failed"_kj, "Gzip decompression failed."}, + {"brotli state allocation failed"_kj, "Brotli state allocation failed."}, + {"invalid brotli window size"_kj, "Invalid brotli window size."}, + {"invalid brotli compression level"_kj, "Invalid brotli compression level."}, + {"brotli window size too big"_kj, "Brotli window size too big."}, + {"brotli decompression failed"_kj, "Brotli decompression failed."}, + {"brotli compression failed"_kj, "Brotli compression failed."}, + {"brotli compressed stream ended prematurely"_kj, + "Brotli compressed stream ended prematurely."}, + })) { return kj::mv(e); } @@ -148,8 +146,8 @@ void EncodedAsyncInputStream::ensureIdentityEncoding() { // does, it is important for us to release it as soon as end() or abort() are called. class EncodedAsyncOutputStream final: public WritableStreamSink { public: - explicit EncodedAsyncOutputStream(kj::Own inner, StreamEncoding encoding, - IoContext& context); + explicit EncodedAsyncOutputStream( + kj::Own inner, StreamEncoding encoding, IoContext& context); kj::Promise write(kj::ArrayPtr buffer) override; kj::Promise write(kj::ArrayPtr> pieces) override; @@ -176,8 +174,11 @@ private: // I use a OneOf here rather than probing with downcasts because end() must be called for // correctness rather than for optimization. I "know" this code will never be compiled w/o RTTI, // but I'm paranoid. - kj::OneOf, kj::Own, - kj::Own, Ended> inner; + kj::OneOf, + kj::Own, + kj::Own, + Ended> + inner; StreamEncoding encoding; @@ -186,7 +187,9 @@ private: EncodedAsyncOutputStream::EncodedAsyncOutputStream( kj::Own inner, StreamEncoding encoding, IoContext& context) - : inner(kj::mv(inner)), encoding(encoding), ioContext(context) {} + : inner(kj::mv(inner)), + encoding(encoding), + ioContext(context) {} kj::Promise EncodedAsyncOutputStream::write(kj::ArrayPtr buffer) { // Alternatively, we could throw here but this is erring on the side of leniency. @@ -204,8 +207,7 @@ kj::Promise EncodedAsyncOutputStream::write( ensureIdentityEncoding(); - return getInner().write(pieces) - .attach(ioContext.registerPendingEvent()); + return getInner().write(pieces).attach(ioContext.registerPendingEvent()); } kj::Maybe>> EncodedAsyncOutputStream::tryPumpFrom( @@ -215,7 +217,7 @@ kj::Maybe>> EncodedAsyncOutputStream::tryPumpFro // pump into it, just return an immediately resolved promise. Alternatively // we could throw here. if (inner.is()) { - return kj::Promise>(DeferredProxy { kj::READY_NOW }); + return kj::Promise>(DeferredProxy{kj::READY_NOW}); } KJ_IF_SOME(nativeInput, kj::dynamicDowncastIfAvailable(input)) { @@ -251,13 +253,14 @@ kj::Maybe>> EncodedAsyncOutputStream::tryPumpFro KJ_CASE_ONEOF(br, kj::Own) { promise = promise.then([&br = br]() { return br->end(); }); } - KJ_CASE_ONEOF(e, Ended) {} + KJ_CASE_ONEOF(e, Ended) { + } } } // Since this is a system stream, the pump task is eligible to be deferred past IoContext // lifetime! - return kj::Promise>(DeferredProxy { kj::mv(promise) }); + return kj::Promise>(DeferredProxy{kj::mv(promise)}); } return kj::none; @@ -291,7 +294,8 @@ kj::Promise EncodedAsyncOutputStream::end() { KJ_CASE_ONEOF(br, kj::Own) { promise = br->end().attach(kj::mv(br)); } - KJ_CASE_ONEOF(e, Ended) {} + KJ_CASE_ONEOF(e, Ended) { + } } inner.init(); @@ -353,24 +357,22 @@ kj::Own newSystemStream( return kj::heap(kj::mv(inner), encoding, context); } -SystemMultiStream newSystemMultiStream( - kj::Own stream, IoContext& context) { +SystemMultiStream newSystemMultiStream(kj::Own stream, IoContext& context) { auto wrapped = kj::refcountedWrapper(kj::mv(stream)); - return { - .readable = kj::heap( - wrapped->addWrappedRef(), StreamEncoding::IDENTITY, context), + return {.readable = kj::heap( + wrapped->addWrappedRef(), StreamEncoding::IDENTITY, context), .writable = kj::heap( - wrapped->addWrappedRef(), StreamEncoding::IDENTITY, context) - }; + wrapped->addWrappedRef(), StreamEncoding::IDENTITY, context)}; } ContentEncodingOptions::ContentEncodingOptions(CompatibilityFlags::Reader flags) : brotliEnabled(flags.getBrotliContentEncoding()) {} -StreamEncoding getContentEncoding(IoContext& context, const kj::HttpHeaders& headers, - Response::BodyEncoding bodyEncoding, - ContentEncodingOptions options) { +StreamEncoding getContentEncoding(IoContext& context, + const kj::HttpHeaders& headers, + Response::BodyEncoding bodyEncoding, + ContentEncodingOptions options) { if (bodyEncoding == Response::BodyEncoding::MANUAL) { return StreamEncoding::IDENTITY; } diff --git a/src/workerd/api/system-streams.h b/src/workerd/api/system-streams.h index d4ce89d8d1b..bdcbce6a43e 100644 --- a/src/workerd/api/system-streams.h +++ b/src/workerd/api/system-streams.h @@ -21,15 +21,15 @@ namespace workerd::api { // heap objects, as the stream is allowed to outlive the isolate, especially in the case of // deferred proxying. If the inner stream for some reason contains JS references, you'll need // to provide your own implementation of ReadableStreamSource. -kj::Own newSystemStream( - kj::Own inner, StreamEncoding encoding, +kj::Own newSystemStream(kj::Own inner, + StreamEncoding encoding, IoContext& context = IoContext::current()); // A WritableStreamSink which automatically encodes its underlying stream. // // NOTE: As with the other overload of newSystemStream(), `inner` must be wholly owned. -kj::Own newSystemStream( - kj::Own inner, StreamEncoding encoding, +kj::Own newSystemStream(kj::Own inner, + StreamEncoding encoding, IoContext& context = IoContext::current()); struct SystemMultiStream { @@ -49,8 +49,9 @@ struct ContentEncodingOptions { // Get the Content-Encoding header from an HttpHeaders object as a StreamEncoding enum. Unsupported // encodings return IDENTITY. -StreamEncoding getContentEncoding(IoContext& context, const kj::HttpHeaders& headers, - Response::BodyEncoding bodyEncoding = Response::BodyEncoding::AUTO, - ContentEncodingOptions options = {}); +StreamEncoding getContentEncoding(IoContext& context, + const kj::HttpHeaders& headers, + Response::BodyEncoding bodyEncoding = Response::BodyEncoding::AUTO, + ContentEncodingOptions options = {}); } // namespace workerd::api diff --git a/src/workerd/api/trace.c++ b/src/workerd/api/trace.c++ index fd80089e564..0e4f484c511 100644 --- a/src/workerd/api/trace.c++ +++ b/src/workerd/api/trace.c++ @@ -19,9 +19,7 @@ namespace workerd::api { TailEvent::TailEvent(jsg::Lock& js, kj::StringPtr type, kj::ArrayPtr> events) : ExtendableEvent(kj::str(type)), - events(KJ_MAP(e, events) -> jsg::Ref { - return jsg::alloc(js, *e); - }) {} + events(KJ_MAP(e, events) -> jsg::Ref { return jsg::alloc(js, *e); }) {} kj::Array> TailEvent::getEvents() { return KJ_MAP(e, events) -> jsg::Ref { return e.addRef(); }; @@ -55,12 +53,17 @@ double getTraceDiagnosticChannelEventTimestamp(const Trace::DiagnosticChannelEve } kj::String getTraceLogLevel(const Trace::Log& log) { - switch (log.logLevel) { - case LogLevel::DEBUG_: return kj::str("debug"); - case LogLevel::INFO: return kj::str("info"); - case LogLevel::LOG: return kj::str("log"); - case LogLevel::WARN: return kj::str("warn"); - case LogLevel::ERROR: return kj::str("error"); + switch (log.logLevel) { + case LogLevel::DEBUG_: + return kj::str("debug"); + case LogLevel::INFO: + return kj::str("info"); + case LogLevel::LOG: + return kj::str("log"); + case LogLevel::WARN: + return kj::str("warn"); + case LogLevel::ERROR: + return kj::str("error"); } KJ_UNREACHABLE; } @@ -70,9 +73,7 @@ jsg::V8Ref getTraceLogMessage(jsg::Lock& js, const Trace::Log& log) } kj::Array> getTraceLogs(jsg::Lock& js, const Trace& trace) { - return KJ_MAP(x, trace.logs) -> jsg::Ref { - return jsg::alloc(js, trace, x); - }; + return KJ_MAP(x, trace.logs) -> jsg::Ref { return jsg::alloc(js, trace, x); }; } kj::Array> getTraceDiagnosticChannelEvents( @@ -95,9 +96,7 @@ double getTraceExceptionTimestamp(const Trace::Exception& ex) { } kj::Array> getTraceExceptions(const Trace& trace) { - return KJ_MAP(x, trace.exceptions) -> jsg::Ref { - return jsg::alloc(trace, x); - }; + return KJ_MAP(x, trace.exceptions) -> jsg::Ref { return jsg::alloc(trace, x); }; } jsg::Optional> getTraceScriptTags(const Trace& trace) { @@ -117,9 +116,7 @@ kj::String getTraceOutcome(const Trace& trace) { } kj::Own getFetchRequestDetail( - jsg::Lock& js, - const Trace& trace, - const Trace::FetchEventInfo& eventInfo) { + jsg::Lock& js, const Trace& trace, const Trace::FetchEventInfo& eventInfo) { const auto getCf = [&]() -> jsg::Optional> { const auto& cfJson = eventInfo.cfJson; if (cfJson.size() > 0) { @@ -135,17 +132,15 @@ kj::Own getFetchRequestDetail( }; return kj::refcounted( - getCf(), - getHeaders(), - kj::str(eventInfo.method), - kj::str(eventInfo.url)); + getCf(), getHeaders(), kj::str(eventInfo.method), kj::str(eventInfo.url)); } kj::Maybe getTraceEvent(jsg::Lock& js, const Trace& trace) { KJ_IF_SOME(e, trace.eventInfo) { KJ_SWITCH_ONEOF(e) { KJ_CASE_ONEOF(fetch, Trace::FetchEventInfo) { - return kj::Maybe(jsg::alloc(js, trace, fetch, trace.fetchResponseInfo)); + return kj::Maybe( + jsg::alloc(js, trace, fetch, trace.fetchResponseInfo)); } KJ_CASE_ONEOF(jsRpc, Trace::JsRpcEventInfo) { return kj::Maybe(jsg::alloc(trace, jsRpc)); @@ -207,15 +202,33 @@ TraceItem::TraceItem(jsg::Lock& js, const Trace& trace) kj::Maybe TraceItem::getEvent(jsg::Lock& js) { return eventInfo.map([](auto& info) -> TraceItem::EventInfo { KJ_SWITCH_ONEOF(info) { - KJ_CASE_ONEOF(info, jsg::Ref) { return info.addRef(); } - KJ_CASE_ONEOF(info, jsg::Ref) { return info.addRef(); } - KJ_CASE_ONEOF(info, jsg::Ref) { return info.addRef(); } - KJ_CASE_ONEOF(info, jsg::Ref) { return info.addRef(); } - KJ_CASE_ONEOF(info, jsg::Ref) { return info.addRef(); } - KJ_CASE_ONEOF(info, jsg::Ref) { return info.addRef(); } - KJ_CASE_ONEOF(info, jsg::Ref) { return info.addRef(); } - KJ_CASE_ONEOF(info, jsg::Ref) { return info.addRef(); } - KJ_CASE_ONEOF(info, jsg::Ref) { return info.addRef(); } + KJ_CASE_ONEOF(info, jsg::Ref) { + return info.addRef(); + } + KJ_CASE_ONEOF(info, jsg::Ref) { + return info.addRef(); + } + KJ_CASE_ONEOF(info, jsg::Ref) { + return info.addRef(); + } + KJ_CASE_ONEOF(info, jsg::Ref) { + return info.addRef(); + } + KJ_CASE_ONEOF(info, jsg::Ref) { + return info.addRef(); + } + KJ_CASE_ONEOF(info, jsg::Ref) { + return info.addRef(); + } + KJ_CASE_ONEOF(info, jsg::Ref) { + return info.addRef(); + } + KJ_CASE_ONEOF(info, jsg::Ref) { + return info.addRef(); + } + KJ_CASE_ONEOF(info, jsg::Ref) { + return info.addRef(); + } } KJ_UNREACHABLE; }); @@ -254,28 +267,34 @@ jsg::Optional TraceItem::getDispatchNamespace() { } jsg::Optional> TraceItem::getScriptTags() { - return scriptTags.map([](kj::Array& tags) { - return KJ_MAP(t, tags) -> kj::StringPtr { return t; }; - }); + return scriptTags.map( + [](kj::Array& tags) { return KJ_MAP(t, tags) -> kj::StringPtr { return t; }; }); } -kj::StringPtr TraceItem::getOutcome() { return outcome; } +kj::StringPtr TraceItem::getOutcome() { + return outcome; +} -bool TraceItem::getTruncated() { return truncated; } +bool TraceItem::getTruncated() { + return truncated; +} -uint TraceItem::getCpuTime() { return cpuTime; } +uint TraceItem::getCpuTime() { + return cpuTime; +} -uint TraceItem::getWallTime() { return wallTime; } +uint TraceItem::getWallTime() { + return wallTime; +} TraceItem::FetchEventInfo::FetchEventInfo(jsg::Lock& js, - const Trace& trace, - const Trace::FetchEventInfo& eventInfo, - kj::Maybe responseInfo) + const Trace& trace, + const Trace::FetchEventInfo& eventInfo, + kj::Maybe responseInfo) : request(jsg::alloc(js, trace, eventInfo)), response(responseInfo.map([&](auto& info) { return jsg::alloc(trace, info); })) {} -TraceItem::FetchEventInfo::Request::Detail::Detail( - jsg::Optional> cf, +TraceItem::FetchEventInfo::Request::Detail::Detail(jsg::Optional> cf, kj::Array headers, kj::String method, kj::String url) @@ -288,51 +307,44 @@ jsg::Ref TraceItem::FetchEventInfo::getReque return request.addRef(); } -jsg::Optional> TraceItem::FetchEventInfo::getResponse() { +jsg::Optional> TraceItem::FetchEventInfo:: + getResponse() { return response.map([](auto& ref) mutable -> jsg::Ref { return ref.addRef(); }); } -TraceItem::FetchEventInfo::Request::Request(jsg::Lock& js, - const Trace& trace, - const Trace::FetchEventInfo& eventInfo) +TraceItem::FetchEventInfo::Request::Request( + jsg::Lock& js, const Trace& trace, const Trace::FetchEventInfo& eventInfo) : detail(getFetchRequestDetail(js, trace, eventInfo)) {} TraceItem::FetchEventInfo::Request::Request(Detail& detail, bool redacted) - : redacted(redacted), detail(kj::addRef(detail)) {} + : redacted(redacted), + detail(kj::addRef(detail)) {} jsg::Optional> TraceItem::FetchEventInfo::Request::getCf(jsg::Lock& js) { - return detail->cf.map([&](jsg::V8Ref& obj) { - return obj.addRef(js); - }); + return detail->cf.map([&](jsg::V8Ref& obj) { return obj.addRef(js); }); } jsg::Dict TraceItem::FetchEventInfo::Request::getHeaders() { auto shouldRedact = [](kj::StringPtr name) { return ( - //(name == "authorization"_kj) || // covered below - (name == "cookie"_kj) || - (name == "set-cookie"_kj) || - name.contains("auth"_kjc) || - name.contains("jwt"_kjc) || - name.contains("key"_kjc) || - name.contains("secret"_kjc) || - name.contains("token"_kjc) - ); + //(name == "authorization"_kj) || // covered below + (name == "cookie"_kj) || (name == "set-cookie"_kj) || name.contains("auth"_kjc) || + name.contains("jwt"_kjc) || name.contains("key"_kjc) || name.contains("secret"_kjc) || + name.contains("token"_kjc)); }; using HeaderDict = jsg::Dict; auto builder = kj::heapArrayBuilder(detail->headers.size()); for (const auto& header: detail->headers) { auto v = (redacted && shouldRedact(header.name)) ? "REDACTED"_kj : header.value; - builder.add(HeaderDict::Field { - jsg::ByteString(kj::str(header.name)), - jsg::ByteString(kj::str(v))}); + builder.add( + HeaderDict::Field{jsg::ByteString(kj::str(header.name)), jsg::ByteString(kj::str(v))}); } // TODO(conform): Better to return a frozen JS Object? - return HeaderDict{ builder.finish() }; + return HeaderDict{builder.finish()}; } kj::StringPtr TraceItem::FetchEventInfo::Request::getMethod() { @@ -347,24 +359,24 @@ jsg::Ref TraceItem::FetchEventInfo::Request: return jsg::alloc(*detail, false /* details are not redacted */); } -TraceItem::FetchEventInfo::Response::Response(const Trace& trace, - const Trace::FetchResponseInfo& responseInfo) +TraceItem::FetchEventInfo::Response::Response( + const Trace& trace, const Trace::FetchResponseInfo& responseInfo) : status(responseInfo.statusCode) {} uint16_t TraceItem::FetchEventInfo::Response::getStatus() { return status; } -TraceItem::JsRpcEventInfo::JsRpcEventInfo(const Trace& trace, - const Trace::JsRpcEventInfo& eventInfo) +TraceItem::JsRpcEventInfo::JsRpcEventInfo( + const Trace& trace, const Trace::JsRpcEventInfo& eventInfo) : rpcMethod(kj::str(eventInfo.methodName)) {} kj::StringPtr TraceItem::JsRpcEventInfo::getRpcMethod() { return rpcMethod; } -TraceItem::ScheduledEventInfo::ScheduledEventInfo(const Trace& trace, - const Trace::ScheduledEventInfo& eventInfo) +TraceItem::ScheduledEventInfo::ScheduledEventInfo( + const Trace& trace, const Trace::ScheduledEventInfo& eventInfo) : scheduledTime(eventInfo.scheduledTime), cron(kj::str(eventInfo.cron)) {} @@ -375,16 +387,16 @@ kj::StringPtr TraceItem::ScheduledEventInfo::getCron() { return cron; } -TraceItem::AlarmEventInfo::AlarmEventInfo(const Trace& trace, - const Trace::AlarmEventInfo& eventInfo) - : scheduledTime(eventInfo.scheduledTime) {} +TraceItem::AlarmEventInfo::AlarmEventInfo( + const Trace& trace, const Trace::AlarmEventInfo& eventInfo) + : scheduledTime(eventInfo.scheduledTime) {} kj::Date TraceItem::AlarmEventInfo::getScheduledTime() { return scheduledTime; } -TraceItem::QueueEventInfo::QueueEventInfo(const Trace& trace, - const Trace::QueueEventInfo& eventInfo) +TraceItem::QueueEventInfo::QueueEventInfo( + const Trace& trace, const Trace::QueueEventInfo& eventInfo) : queueName(kj::str(eventInfo.queueName)), batchSize(eventInfo.batchSize) {} @@ -396,8 +408,8 @@ uint32_t TraceItem::QueueEventInfo::getBatchSize() { return batchSize; } -TraceItem::EmailEventInfo::EmailEventInfo(const Trace& trace, - const Trace::EmailEventInfo& eventInfo) +TraceItem::EmailEventInfo::EmailEventInfo( + const Trace& trace, const Trace::EmailEventInfo& eventInfo) : mailFrom(kj::str(eventInfo.mailFrom)), rcptTo(kj::str(eventInfo.rcptTo)), rawSize(eventInfo.rawSize) {} @@ -421,11 +433,11 @@ kj::Array> getConsumedEventsFromEve }; } -TraceItem::TailEventInfo::TailEventInfo(const Trace& trace, - const Trace::TraceEventInfo& eventInfo) +TraceItem::TailEventInfo::TailEventInfo(const Trace& trace, const Trace::TraceEventInfo& eventInfo) : consumedEvents(getConsumedEventsFromEventInfo(eventInfo)) {} -kj::Array> TraceItem::TailEventInfo::getConsumedEvents() { +kj::Array> TraceItem::TailEventInfo:: + getConsumedEvents() { return KJ_MAP(consumedEvent, consumedEvents) -> jsg::Ref { return consumedEvent.addRef(); }; @@ -439,8 +451,7 @@ kj::Maybe TraceItem::TailEventInfo::TailItem::getScriptName() { } TraceDiagnosticChannelEvent::TraceDiagnosticChannelEvent( - const Trace& trace, - const Trace::DiagnosticChannelEvent& eventInfo) + const Trace& trace, const Trace::DiagnosticChannelEvent& eventInfo) : timestamp(getTraceDiagnosticChannelEventTimestamp(eventInfo)), channel(kj::heapString(eventInfo.channel)), message(kj::heapArray(eventInfo.message)) {} @@ -455,7 +466,9 @@ jsg::JsValue TraceDiagnosticChannelEvent::getMessage(jsg::Lock& js) { return des.readValue(js); } -double TraceDiagnosticChannelEvent::getTimestamp() { return timestamp; } +double TraceDiagnosticChannelEvent::getTimestamp() { + return timestamp; +} ScriptVersion::ScriptVersion(workerd::ScriptVersion::Reader version) : id{[&]() -> kj::Maybe { @@ -480,30 +493,24 @@ ScriptVersion::ScriptVersion(const ScriptVersion& other) tag{other.tag.map([](const auto& tag) { return kj::str(tag); })}, message{other.message.map([](const auto& message) { return kj::str(message); })} {} -TraceItem::CustomEventInfo::CustomEventInfo(const Trace& trace, - const Trace::CustomEventInfo& eventInfo) +TraceItem::CustomEventInfo::CustomEventInfo( + const Trace& trace, const Trace::CustomEventInfo& eventInfo) : eventInfo(eventInfo) {} TraceItem::HibernatableWebSocketEventInfo::HibernatableWebSocketEventInfo( - const Trace& trace, - const Trace::HibernatableWebSocketEventInfo::Message& eventInfo) - : eventType( - jsg::alloc(trace, eventInfo)) {} + const Trace& trace, const Trace::HibernatableWebSocketEventInfo::Message& eventInfo) + : eventType(jsg::alloc(trace, eventInfo)) {} TraceItem::HibernatableWebSocketEventInfo::HibernatableWebSocketEventInfo( - const Trace& trace, - const Trace::HibernatableWebSocketEventInfo::Close& eventInfo) - : eventType( - jsg::alloc(trace, eventInfo)) {} + const Trace& trace, const Trace::HibernatableWebSocketEventInfo::Close& eventInfo) + : eventType(jsg::alloc(trace, eventInfo)) {} TraceItem::HibernatableWebSocketEventInfo::HibernatableWebSocketEventInfo( - const Trace& trace, - const Trace::HibernatableWebSocketEventInfo::Error& eventInfo) - : eventType( - jsg::alloc(trace, eventInfo)) {} + const Trace& trace, const Trace::HibernatableWebSocketEventInfo::Error& eventInfo) + : eventType(jsg::alloc(trace, eventInfo)) {} -TraceItem::HibernatableWebSocketEventInfo::Type - TraceItem::HibernatableWebSocketEventInfo::getEvent() { +TraceItem::HibernatableWebSocketEventInfo::Type TraceItem::HibernatableWebSocketEventInfo:: + getEvent() { KJ_SWITCH_ONEOF(eventType) { KJ_CASE_ONEOF(m, jsg::Ref) { return m.addRef(); @@ -565,15 +572,15 @@ jsg::Optional TraceException::getStack(jsg::Lock& js) { return stack; } -TraceMetrics::TraceMetrics(uint cpuTime, uint wallTime) : cpuTime(cpuTime), wallTime(wallTime) {} +TraceMetrics::TraceMetrics(uint cpuTime, uint wallTime): cpuTime(cpuTime), wallTime(wallTime) {} jsg::Ref UnsafeTraceMetrics::fromTrace(jsg::Ref item) { return jsg::alloc(item->getCpuTime(), item->getWallTime()); } namespace { -kj::Promise sendTracesToExportedHandler( - kj::Own incomingRequest, kj::Maybe entrypointNamePtr, +kj::Promise sendTracesToExportedHandler(kj::Own incomingRequest, + kj::Maybe entrypointNamePtr, kj::ArrayPtr> traces) { // Mark the request as delivered because we're about to run some JS. incomingRequest->delivered(); @@ -590,9 +597,8 @@ kj::Promise sendTracesToExportedHandler( // and its members until this task completes. auto entrypointName = entrypointNamePtr.map([](auto s) { return kj::str(s); }); try { - co_await context.run( - [&context, traces=mapAddRef(traces), entrypointName=kj::mv(entrypointName)] - (Worker::Lock& lock) mutable { + co_await context.run([&context, traces = mapAddRef(traces), + entrypointName = kj::mv(entrypointName)](Worker::Lock& lock) mutable { jsg::AsyncContextFrame::StorageScope traceScope = context.makeAsyncTraceScope(lock); auto handler = lock.getExportedHandler(entrypointName, context.getActor()); @@ -617,24 +623,22 @@ kj::Promise sendTracesToExportedHandler( } } // namespace -auto TraceCustomEventImpl::run( - kj::Own incomingRequest, kj::Maybe entrypointNamePtr, - kj::TaskSet& waitUntilTasks) - -> kj::Promise { +auto TraceCustomEventImpl::run(kj::Own incomingRequest, + kj::Maybe entrypointNamePtr, + kj::TaskSet& waitUntilTasks) -> kj::Promise { // Don't bother to wait around for the handler to run, just hand it off to the waitUntil tasks. waitUntilTasks.add( sendTracesToExportedHandler(kj::mv(incomingRequest), entrypointNamePtr, traces)); - return Result { + return Result{ .outcome = EventOutcome::OK, }; } -auto TraceCustomEventImpl::sendRpc( - capnp::HttpOverCapnpFactory& httpOverCapnpFactory, - capnp::ByteStreamFactory& byteStreamFactory, - kj::TaskSet& waitUntilTasks, - workerd::rpc::EventDispatcher::Client dispatcher) -> kj::Promise { +auto TraceCustomEventImpl::sendRpc(capnp::HttpOverCapnpFactory& httpOverCapnpFactory, + capnp::ByteStreamFactory& byteStreamFactory, + kj::TaskSet& waitUntilTasks, + workerd::rpc::EventDispatcher::Client dispatcher) -> kj::Promise { auto req = dispatcher.sendTracesRequest(); auto out = req.initTraces(traces.size()); for (auto i: kj::indices(traces)) { @@ -644,13 +648,13 @@ auto TraceCustomEventImpl::sendRpc( waitUntilTasks.add(req.send().ignoreResult()); // As long as we sent it, we consider the result to be okay. - co_return Result { + co_return Result{ .outcome = workerd::EventOutcome::OK, }; } void TailEvent::visitForMemoryInfo(jsg::MemoryTracker& tracker) const { - for (const auto& event : events) { + for (const auto& event: events) { tracker.trackField(nullptr, event); } } @@ -687,7 +691,7 @@ void TraceItem::visitForMemoryInfo(jsg::MemoryTracker& tracker) const { } } } - for (const auto& log : logs) { + for (const auto& log: logs) { tracker.trackField("log", log); } for (const auto& exception: exceptions) { @@ -713,7 +717,7 @@ void TraceItem::FetchEventInfo::visitForMemoryInfo(jsg::MemoryTracker& tracker) } void TraceItem::TailEventInfo::visitForMemoryInfo(jsg::MemoryTracker& tracker) const { - for (const auto& event : consumedEvents) { + for (const auto& event: consumedEvents) { tracker.trackField(nullptr, event); } } diff --git a/src/workerd/api/trace.h b/src/workerd/api/trace.h index 13a1c4ab614..2f33e18c8d3 100644 --- a/src/workerd/api/trace.h +++ b/src/workerd/api/trace.h @@ -79,14 +79,15 @@ class TraceItem final: public jsg::Object { explicit TraceItem(jsg::Lock& js, const Trace& trace); typedef kj::OneOf, - jsg::Ref, - jsg::Ref, - jsg::Ref, - jsg::Ref, - jsg::Ref, - jsg::Ref, - jsg::Ref, - jsg::Ref> EventInfo; + jsg::Ref, + jsg::Ref, + jsg::Ref, + jsg::Ref, + jsg::Ref, + jsg::Ref, + jsg::Ref, + jsg::Ref> + EventInfo; kj::Maybe getEvent(jsg::Lock& js); kj::Maybe getEventTimestamp(); @@ -161,9 +162,9 @@ class TraceItem::FetchEventInfo final: public jsg::Object { class Response; explicit FetchEventInfo(jsg::Lock& js, - const Trace& trace, - const Trace::FetchEventInfo& eventInfo, - kj::Maybe responseInfo); + const Trace& trace, + const Trace::FetchEventInfo& eventInfo, + kj::Maybe responseInfo); jsg::Ref getRequest(); jsg::Optional> getResponse(); @@ -183,20 +184,20 @@ class TraceItem::FetchEventInfo final: public jsg::Object { class TraceItem::FetchEventInfo::Request final: public jsg::Object { public: - struct Detail : public kj::Refcounted { + struct Detail: public kj::Refcounted { jsg::Optional> cf; kj::Array headers; kj::String method; kj::String url; Detail(jsg::Optional> cf, - kj::Array headers, - kj::String method, - kj::String url); + kj::Array headers, + kj::String method, + kj::String url); JSG_MEMORY_INFO(Detail) { tracker.trackField("cf", cf); - for (const auto& header : headers) { + for (const auto& header: headers) { tracker.trackField(nullptr, header); } tracker.trackField("method", method); @@ -395,12 +396,12 @@ class TraceItem::HibernatableWebSocketEventInfo final: public jsg::Object { class Close; class Error; - explicit HibernatableWebSocketEventInfo(const Trace& trace, - const Trace::HibernatableWebSocketEventInfo::Message& eventInfo); - explicit HibernatableWebSocketEventInfo(const Trace& trace, - const Trace::HibernatableWebSocketEventInfo::Close& eventInfo); - explicit HibernatableWebSocketEventInfo(const Trace& trace, - const Trace::HibernatableWebSocketEventInfo::Error& eventInfo); + explicit HibernatableWebSocketEventInfo( + const Trace& trace, const Trace::HibernatableWebSocketEventInfo::Message& eventInfo); + explicit HibernatableWebSocketEventInfo( + const Trace& trace, const Trace::HibernatableWebSocketEventInfo::Close& eventInfo); + explicit HibernatableWebSocketEventInfo( + const Trace& trace, const Trace::HibernatableWebSocketEventInfo::Error& eventInfo); using Type = kj::OneOf, jsg::Ref, jsg::Ref>; @@ -418,11 +419,14 @@ class TraceItem::HibernatableWebSocketEventInfo final: public jsg::Object { class TraceItem::HibernatableWebSocketEventInfo::Message final: public jsg::Object { public: - explicit Message(const Trace& trace, - const Trace::HibernatableWebSocketEventInfo::Message& eventInfo): eventInfo(eventInfo) {} + explicit Message( + const Trace& trace, const Trace::HibernatableWebSocketEventInfo::Message& eventInfo) + : eventInfo(eventInfo) {} static constexpr kj::StringPtr webSocketEventType = "message"_kj; - kj::StringPtr getWebSocketEventType() { return webSocketEventType; } + kj::StringPtr getWebSocketEventType() { + return webSocketEventType; + } JSG_RESOURCE_TYPE(Message) { JSG_READONLY_INSTANCE_PROPERTY(webSocketEventType, getWebSocketEventType); @@ -434,11 +438,13 @@ class TraceItem::HibernatableWebSocketEventInfo::Message final: public jsg::Obje class TraceItem::HibernatableWebSocketEventInfo::Close final: public jsg::Object { public: - explicit Close(const Trace& trace, - const Trace::HibernatableWebSocketEventInfo::Close& eventInfo): eventInfo(eventInfo) {} + explicit Close(const Trace& trace, const Trace::HibernatableWebSocketEventInfo::Close& eventInfo) + : eventInfo(eventInfo) {} static constexpr kj::StringPtr webSocketEventType = "close"_kj; - kj::StringPtr getWebSocketEventType() { return webSocketEventType; } + kj::StringPtr getWebSocketEventType() { + return webSocketEventType; + } uint16_t getCode(); bool getWasClean(); @@ -455,11 +461,13 @@ class TraceItem::HibernatableWebSocketEventInfo::Close final: public jsg::Object class TraceItem::HibernatableWebSocketEventInfo::Error final: public jsg::Object { public: - explicit Error(const Trace& trace, - const Trace::HibernatableWebSocketEventInfo::Error& eventInfo): eventInfo(eventInfo) {} + explicit Error(const Trace& trace, const Trace::HibernatableWebSocketEventInfo::Error& eventInfo) + : eventInfo(eventInfo) {} static constexpr kj::StringPtr webSocketEventType = "error"_kj; - kj::StringPtr getWebSocketEventType() { return webSocketEventType; } + kj::StringPtr getWebSocketEventType() { + return webSocketEventType; + } JSG_RESOURCE_TYPE(Error) { JSG_READONLY_INSTANCE_PROPERTY(webSocketEventType, getWebSocketEventType); @@ -482,8 +490,7 @@ class TraceItem::CustomEventInfo final: public jsg::Object { class TraceDiagnosticChannelEvent final: public jsg::Object { public: explicit TraceDiagnosticChannelEvent( - const Trace& trace, - const Trace::DiagnosticChannelEvent& eventInfo); + const Trace& trace, const Trace::DiagnosticChannelEvent& eventInfo); double getTimestamp(); kj::StringPtr getChannel(); @@ -559,12 +566,16 @@ class TraceException final: public jsg::Object { kj::Maybe stack; }; -class TraceMetrics final : public jsg::Object { +class TraceMetrics final: public jsg::Object { public: explicit TraceMetrics(uint cpuTime, uint wallTime); - uint getCPUTime() { return cpuTime; }; - uint getWallTime() { return wallTime; }; + uint getCPUTime() { + return cpuTime; + }; + uint getWallTime() { + return wallTime; + }; JSG_RESOURCE_TYPE(TraceMetrics) { JSG_READONLY_INSTANCE_PROPERTY(cpuTime, getCPUTime); @@ -572,6 +583,7 @@ class TraceMetrics final : public jsg::Object { JSG_TS_ROOT(); } + private: uint cpuTime; uint wallTime; @@ -592,15 +604,14 @@ class TraceCustomEventImpl final: public WorkerInterface::CustomEvent { public: TraceCustomEventImpl( uint16_t typeId, kj::TaskSet& waitUntilTasks, kj::Array> traces) - : typeId(typeId), traces(kj::mv(traces)) {} + : typeId(typeId), + traces(kj::mv(traces)) {} - kj::Promise run( - kj::Own incomingRequest, + kj::Promise run(kj::Own incomingRequest, kj::Maybe entrypointName, kj::TaskSet& waitUntilTasks) override; - kj::Promise sendRpc( - capnp::HttpOverCapnpFactory& httpOverCapnpFactory, + kj::Promise sendRpc(capnp::HttpOverCapnpFactory& httpOverCapnpFactory, capnp::ByteStreamFactory& byteStreamFactory, kj::TaskSet& waitUntilTasks, rpc::EventDispatcher::Client dispatcher) override; @@ -614,30 +625,18 @@ class TraceCustomEventImpl final: public WorkerInterface::CustomEvent { kj::Array> traces; }; -#define EW_TRACE_ISOLATE_TYPES \ - api::ScriptVersion, \ - api::TailEvent, \ - api::TraceItem, \ - api::TraceItem::AlarmEventInfo, \ - api::TraceItem::CustomEventInfo, \ - api::TraceItem::ScheduledEventInfo, \ - api::TraceItem::QueueEventInfo, \ - api::TraceItem::EmailEventInfo, \ - api::TraceItem::TailEventInfo, \ - api::TraceItem::TailEventInfo::TailItem, \ - api::TraceItem::FetchEventInfo, \ - api::TraceItem::FetchEventInfo::Request, \ - api::TraceItem::FetchEventInfo::Response, \ - api::TraceItem::JsRpcEventInfo, \ - api::TraceItem::HibernatableWebSocketEventInfo, \ - api::TraceItem::HibernatableWebSocketEventInfo::Message, \ - api::TraceItem::HibernatableWebSocketEventInfo::Close, \ - api::TraceItem::HibernatableWebSocketEventInfo::Error, \ - api::TraceLog, \ - api::TraceException, \ - api::TraceDiagnosticChannelEvent, \ - api::TraceMetrics, \ - api::UnsafeTraceMetrics +#define EW_TRACE_ISOLATE_TYPES \ + api::ScriptVersion, api::TailEvent, api::TraceItem, api::TraceItem::AlarmEventInfo, \ + api::TraceItem::CustomEventInfo, api::TraceItem::ScheduledEventInfo, \ + api::TraceItem::QueueEventInfo, api::TraceItem::EmailEventInfo, \ + api::TraceItem::TailEventInfo, api::TraceItem::TailEventInfo::TailItem, \ + api::TraceItem::FetchEventInfo, api::TraceItem::FetchEventInfo::Request, \ + api::TraceItem::FetchEventInfo::Response, api::TraceItem::JsRpcEventInfo, \ + api::TraceItem::HibernatableWebSocketEventInfo, \ + api::TraceItem::HibernatableWebSocketEventInfo::Message, \ + api::TraceItem::HibernatableWebSocketEventInfo::Close, \ + api::TraceItem::HibernatableWebSocketEventInfo::Error, api::TraceLog, api::TraceException, \ + api::TraceDiagnosticChannelEvent, api::TraceMetrics, api::UnsafeTraceMetrics // The list of trace.h types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE } // namespace workerd::api diff --git a/src/workerd/api/unsafe.c++ b/src/workerd/api/unsafe.c++ index bf81e80fb66..ae2a0755726 100644 --- a/src/workerd/api/unsafe.c++ +++ b/src/workerd/api/unsafe.c++ @@ -13,7 +13,7 @@ static constexpr auto ASYNC_FN_SUFFIX = "}"_kjc; inline kj::StringPtr getName(jsg::Optional& name, kj::StringPtr def) { return name.map([](kj::String& str) { return str.asPtr(); }).orDefault(def); } -} // namespace +} // namespace jsg::JsValue UnsafeEval::eval(jsg::Lock& js, kj::String script, jsg::Optional name) { js.setAllowEval(true); @@ -22,10 +22,11 @@ jsg::JsValue UnsafeEval::eval(jsg::Lock& js, kj::String script, jsg::Optional name, - jsg::Arguments> args, - const jsg::TypeHandler& handler) { +UnsafeEval::UnsafeEvalFunction UnsafeEval::newFunction(jsg::Lock& js, + jsg::JsString script, + jsg::Optional name, + jsg::Arguments> args, + const jsg::TypeHandler& handler) { js.setAllowEval(true); KJ_DEFER(js.setAllowEval(false)); @@ -33,21 +34,20 @@ UnsafeEval::newFunction(jsg::Lock& js, jsg::JsString script, jsg::Optional(arg.getHandle(js)); - }; + auto argNames = KJ_MAP(arg, args) { return v8::Local(arg.getHandle(js)); }; - auto fn = jsg::check(v8::ScriptCompiler::CompileFunction(js.v8Context(), &source, argNames.size(), - argNames.begin(), 0, nullptr)); + auto fn = jsg::check(v8::ScriptCompiler::CompileFunction( + js.v8Context(), &source, argNames.size(), argNames.begin(), 0, nullptr)); fn->SetName(nameStr); return KJ_ASSERT_NONNULL(handler.tryUnwrap(js, fn)); } -UnsafeEval::UnsafeEvalFunction -UnsafeEval::newAsyncFunction(jsg::Lock& js, jsg::JsString script, jsg::Optional name, - jsg::Arguments> args, - const jsg::TypeHandler& handler) { +UnsafeEval::UnsafeEvalFunction UnsafeEval::newAsyncFunction(jsg::Lock& js, + jsg::JsString script, + jsg::Optional name, + jsg::Arguments> args, + const jsg::TypeHandler& handler) { js.setAllowEval(true); KJ_DEFER(js.setAllowEval(false)); @@ -69,7 +69,7 @@ UnsafeEval::newAsyncFunction(jsg::Lock& js, jsg::JsString script, jsg::Optional< auto prepared = v8::String::Concat(js.v8Isolate, js.strIntern(ASYNC_FN_PREFIX), nameStr); prepared = v8::String::Concat(js.v8Isolate, prepared, js.strIntern(ASYNC_FN_ARG_OPEN)); - for (auto& arg : args) { + for (auto& arg: args) { prepared = v8::String::Concat(js.v8Isolate, prepared, arg.getHandle(js)); prepared = v8::String::Concat(js.v8Isolate, prepared, js.strIntern(",")); } @@ -102,8 +102,8 @@ jsg::JsValue UnsafeEval::newWasmModule(jsg::Lock& js, kj::Array src) { jsg::Promise UnsafeModule::abortAllDurableObjects(jsg::Lock& js) { auto& context = IoContext::current(); // Abort all actors asynchronously to avoid recursively taking isolate lock in actor destructor - auto promise = kj::evalLater([&] () { return context.abortAllActors(); }); + auto promise = kj::evalLater([&]() { return context.abortAllActors(); }); return context.awaitIo(js, kj::mv(promise)); } -} // namespace workerd::api +} // namespace workerd::api diff --git a/src/workerd/api/unsafe.h b/src/workerd/api/unsafe.h index bd6d3e29cdf..8cb3083edc5 100644 --- a/src/workerd/api/unsafe.h +++ b/src/workerd/api/unsafe.h @@ -33,8 +33,7 @@ class UnsafeEval: public jsg::Object { // const fn = env.unsafe.newFunction('return m', 'foo', 'm'); // console.log(fn(1)); // prints 1 // - UnsafeEvalFunction newFunction( - jsg::Lock& js, + UnsafeEvalFunction newFunction(jsg::Lock& js, jsg::JsString script, jsg::Optional name, jsg::Arguments> args, @@ -46,8 +45,7 @@ class UnsafeEval: public jsg::Object { // and will appear in stack traces for any errors thrown. An optional list of // arguments names can be passed in. If your function needs to use the await // key, use this instead of newFunction. - UnsafeEvalFunction newAsyncFunction( - jsg::Lock& js, + UnsafeEvalFunction newAsyncFunction(jsg::Lock& js, jsg::JsString script, jsg::Optional name, jsg::Arguments> args, @@ -76,18 +74,18 @@ class UnsafeModule: public jsg::Object { template void registerUnsafeModule(Registry& registry) { - registry.template addBuiltinModule("workerd:unsafe", - workerd::jsg::ModuleRegistry::Type::BUILTIN); - registry.template addBuiltinModule("workerd:unsafe-eval", - workerd::jsg::ModuleRegistry::Type::BUILTIN); + registry.template addBuiltinModule( + "workerd:unsafe", workerd::jsg::ModuleRegistry::Type::BUILTIN); + registry.template addBuiltinModule( + "workerd:unsafe-eval", workerd::jsg::ModuleRegistry::Type::BUILTIN); } -#define EW_UNSAFE_ISOLATE_TYPES api::UnsafeEval, \ - api::UnsafeModule +#define EW_UNSAFE_ISOLATE_TYPES api::UnsafeEval, api::UnsafeModule -template void registerUnsafeModules(Registry& registry, auto featureFlags) { - registry.template addBuiltinModule("internal:unsafe-eval", - workerd::jsg::ModuleRegistry::Type::INTERNAL); +template +void registerUnsafeModules(Registry& registry, auto featureFlags) { + registry.template addBuiltinModule( + "internal:unsafe-eval", workerd::jsg::ModuleRegistry::Type::INTERNAL); } template @@ -110,4 +108,4 @@ kj::Own getExternalUnsafeModuleBundle(auto featureFl builder.addObject(kUnsafeSpecifier); return builder.finish(); } -} // namespace workerd::api +} // namespace workerd::api diff --git a/src/workerd/api/url-standard.c++ b/src/workerd/api/url-standard.c++ index 648fa0da9b6..0404fc87af4 100644 --- a/src/workerd/api/url-standard.c++ +++ b/src/workerd/api/url-standard.c++ @@ -33,12 +33,10 @@ jsg::Url parseImpl(kj::StringPtr url, kj::Maybe maybeBase) { } // namespace jsg::Ref URL::constructor(kj::String url, jsg::Optional base) { - return jsg::alloc( - kj::mv(url), - base.map([](kj::String& base) { return base.asPtr(); })); + return jsg::alloc(kj::mv(url), base.map([](kj::String& base) { return base.asPtr(); })); } -URL::URL(kj::StringPtr url, kj::Maybe base) : inner(parseImpl(url, base)) {} +URL::URL(kj::StringPtr url, kj::Maybe base): inner(parseImpl(url, base)) {} URL::~URL() noexcept(false) { KJ_IF_SOME(searchParams, maybeSearchParams) { @@ -67,40 +65,70 @@ kj::ArrayPtr URL::getHref() { void URL::setHref(kj::String value) { inner.setHref(value); - KJ_IF_SOME(searchParams, maybeSearchParams) { + KJ_IF_SOME(searchParams, maybeSearchParams) { searchParams->reset(); } } -kj::ArrayPtr URL::getProtocol() { return inner.getProtocol(); } +kj::ArrayPtr URL::getProtocol() { + return inner.getProtocol(); +} -void URL::setProtocol(kj::String value) { inner.setProtocol(value); } +void URL::setProtocol(kj::String value) { + inner.setProtocol(value); +} -kj::ArrayPtr URL::getUsername() { return inner.getUsername(); } +kj::ArrayPtr URL::getUsername() { + return inner.getUsername(); +} -void URL::setUsername(kj::String value) { inner.setUsername(value); } +void URL::setUsername(kj::String value) { + inner.setUsername(value); +} -kj::ArrayPtr URL::getPassword() { return inner.getPassword(); } +kj::ArrayPtr URL::getPassword() { + return inner.getPassword(); +} -void URL::setPassword(kj::String value) { inner.setPassword(value); } +void URL::setPassword(kj::String value) { + inner.setPassword(value); +} -kj::ArrayPtr URL::getHost() { return inner.getHost(); } +kj::ArrayPtr URL::getHost() { + return inner.getHost(); +} -void URL::setHost(kj::String value) { inner.setHost(value); } +void URL::setHost(kj::String value) { + inner.setHost(value); +} -kj::ArrayPtr URL::getHostname() { return inner.getHostname(); } +kj::ArrayPtr URL::getHostname() { + return inner.getHostname(); +} -void URL::setHostname(kj::String value) { inner.setHostname(value); } +void URL::setHostname(kj::String value) { + inner.setHostname(value); +} -kj::ArrayPtr URL::getPort() { return inner.getPort(); } +kj::ArrayPtr URL::getPort() { + return inner.getPort(); +} -void URL::setPort(kj::String value) { inner.setPort(kj::Maybe(value.asPtr())); } +void URL::setPort(kj::String value) { + inner.setPort(kj::Maybe(value.asPtr())); +} -kj::ArrayPtr URL::getPathname() { return inner.getPathname(); } +kj::ArrayPtr URL::getPathname() { + return inner.getPathname(); +} -void URL::setPathname(kj::String value) { inner.setPathname(value); } +void URL::setPathname(kj::String value) { + inner.setPathname(value); +} -kj::ArrayPtr URL::getSearch() { return inner.getSearch(); } +kj::ArrayPtr URL::getSearch() { + return inner.getSearch(); +} void URL::setSearch(kj::String value) { inner.setSearch(kj::Maybe(value.asPtr())); @@ -109,9 +137,13 @@ void URL::setSearch(kj::String value) { } } -kj::ArrayPtr URL::getHash() { return inner.getHash(); } +kj::ArrayPtr URL::getHash() { + return inner.getHash(); +} -void URL::setHash(kj::String hash) { inner.setHash(kj::Maybe(hash.asPtr())); } +void URL::setHash(kj::String hash) { + inner.setHash(kj::Maybe(hash.asPtr())); +} void URL::visitForGc(jsg::GcVisitor& visitor) { visitor.visit(maybeSearchParams); @@ -123,7 +155,7 @@ jsg::UrlSearchParams initSearchParams(const URLSearchParams::Initializer& init) KJ_SWITCH_ONEOF(init) { KJ_CASE_ONEOF(pairs, URLSearchParams::StringPairs) { jsg::UrlSearchParams params; - for (auto& item : pairs) { + for (auto& item: pairs) { JSG_REQUIRE(item.size() == 2, TypeError, "Invalid URL search params sequence."); params.append(item[0], item[1]); } @@ -131,14 +163,14 @@ jsg::UrlSearchParams initSearchParams(const URLSearchParams::Initializer& init) } KJ_CASE_ONEOF(dict, jsg::Dict) { jsg::UrlSearchParams params; - for (auto& item : dict.fields) { + for (auto& item: dict.fields) { params.append(item.name, item.value); } return kj::mv(params); } KJ_CASE_ONEOF(str, kj::String) { - return JSG_REQUIRE_NONNULL(jsg::UrlSearchParams::tryParse(str), TypeError, - "Invalid URL search params string."); + return JSG_REQUIRE_NONNULL( + jsg::UrlSearchParams::tryParse(str), TypeError, "Invalid URL search params string."); } } KJ_UNREACHABLE; @@ -146,8 +178,8 @@ jsg::UrlSearchParams initSearchParams(const URLSearchParams::Initializer& init) jsg::UrlSearchParams initFromSearch(kj::Maybe>& maybeQuery) { KJ_IF_SOME(query, maybeQuery) { - return JSG_REQUIRE_NONNULL(jsg::UrlSearchParams::tryParse(query), TypeError, - "Invalid URL search params string."); + return JSG_REQUIRE_NONNULL( + jsg::UrlSearchParams::tryParse(query), TypeError, "Invalid URL search params string."); } return jsg::UrlSearchParams(); } @@ -157,10 +189,11 @@ jsg::Ref URLSearchParams::constructor(jsg::Optional(kj::mv(init).orDefault(kj::str())); } -URLSearchParams::URLSearchParams(Initializer initializer) : inner(initSearchParams(initializer)) {} +URLSearchParams::URLSearchParams(Initializer initializer): inner(initSearchParams(initializer)) {} -URLSearchParams::URLSearchParams(kj::Maybe> maybeQuery, - URL& url) : inner(initFromSearch(maybeQuery)), maybeUrl(url) {} +URLSearchParams::URLSearchParams(kj::Maybe> maybeQuery, URL& url) + : inner(initFromSearch(maybeQuery)), + maybeUrl(url) {} uint URLSearchParams::getSize() { return inner.size(); @@ -247,27 +280,23 @@ jsg::Ref URLSearchParams::values(jsg::Lock&) { } kj::Maybe>> URLSearchParams::entryIteratorNext( - jsg::Lock& js, - URLSearchParams::IteratorState& state) { + jsg::Lock& js, URLSearchParams::IteratorState& state) { return state.inner.next().map([](const jsg::UrlSearchParams::EntryIterator::Entry& entry) { return kj::arr(entry.key, entry.value); }); } kj::Maybe> URLSearchParams::keyIteratorNext( - jsg::Lock& js, - URLSearchParams::IteratorState& state) { + jsg::Lock& js, URLSearchParams::IteratorState& state) { return state.inner.next(); } kj::Maybe> URLSearchParams::valueIteratorNext( - jsg::Lock& js, - URLSearchParams::IteratorState& state) { + jsg::Lock& js, URLSearchParams::IteratorState& state) { return state.inner.next(); } -void URLSearchParams::forEach( - jsg::Lock& js, +void URLSearchParams::forEach(jsg::Lock& js, jsg::Function)> callback, jsg::Optional thisArg) { auto receiver = js.undefined(); @@ -281,12 +310,10 @@ void URLSearchParams::forEach( auto entries = inner.getEntries(); while (entries.hasNext()) { auto next = KJ_ASSERT_NONNULL(entries.next()); - kj::String value(const_cast(next.value.begin()), - next.value.size(), - kj::NullArrayDisposer::instance); - kj::String key(const_cast(next.key.begin()), - next.key.size(), - kj::NullArrayDisposer::instance); + kj::String value( + const_cast(next.value.begin()), next.value.size(), kj::NullArrayDisposer::instance); + kj::String key( + const_cast(next.key.begin()), next.key.size(), kj::NullArrayDisposer::instance); callback(js, value, key, JSG_THIS); } } @@ -295,5 +322,4 @@ kj::String URLSearchParams::toString() { return kj::str(inner); } -} // workerd::api::url - +} // namespace workerd::api::url diff --git a/src/workerd/api/url.c++ b/src/workerd/api/url.c++ index 24bd0fd71d2..d3baf243978 100644 --- a/src/workerd/api/url.c++ +++ b/src/workerd/api/url.c++ @@ -20,18 +20,18 @@ namespace { bool isSpecialScheme(kj::StringPtr scheme) { // TODO(cleanup): Move this to kj::Url. static const std::set specialSchemes{ - "ftp", "file", "gopher", "http", "https", "ws", "wss"}; + "ftp", "file", "gopher", "http", "https", "ws", "wss"}; return specialSchemes.count(scheme); } kj::Maybe defaultPortForScheme(kj::StringPtr scheme) { - static const std::map defaultPorts { - { "ftp", "21" }, - { "gopher", "70" }, - { "http", "80" }, - { "https", "443" }, - { "ws", "80" }, - { "wss", "443" }, + static const std::map defaultPorts{ + {"ftp", "21"}, + {"gopher", "70"}, + {"http", "80"}, + {"https", "443"}, + {"ws", "80"}, + {"wss", "443"}, }; auto port = defaultPorts.find(scheme); if (port != defaultPorts.end()) { @@ -119,12 +119,13 @@ kj::String kjUrlToString(const kj::Url& url) { // with the situation for now. Rather than expose these errors to the user as opaque internal // errors (and nag us via Sentry), we get our hands dirty with some string matching, in the // hopes of helping users work around the bugs. - KJ_IF_SOME(e, translateKjException(exception, { - { "invalid hostname when stringifying URL"_kj, - "Invalid hostname when stringifying URL."_kj }, - { "invalid name in URL path"_kj, - "Invalid pathname when stringifying URL."_kj }, - })) { + KJ_IF_SOME(e, + translateKjException(exception, + { + {"invalid hostname when stringifying URL"_kj, + "Invalid hostname when stringifying URL."_kj}, + {"invalid name in URL path"_kj, "Invalid pathname when stringifying URL."_kj}, + })) { kj::throwFatalException(kj::mv(e)); } @@ -144,13 +145,13 @@ kj::String kjUrlToString(const kj::Url& url) { jsg::Ref URL::constructor(kj::String url, jsg::Optional base) { KJ_IF_SOME(b, base) { - auto baseUrl = JSG_REQUIRE_NONNULL(kj::Url::tryParse(kj::mv(b)), - TypeError, "Invalid base URL string."); - return jsg::alloc(JSG_REQUIRE_NONNULL(baseUrl.tryParseRelative(kj::mv(url)), - TypeError, "Invalid relative URL string.")); + auto baseUrl = + JSG_REQUIRE_NONNULL(kj::Url::tryParse(kj::mv(b)), TypeError, "Invalid base URL string."); + return jsg::alloc(JSG_REQUIRE_NONNULL( + baseUrl.tryParseRelative(kj::mv(url)), TypeError, "Invalid relative URL string.")); } - return jsg::alloc(JSG_REQUIRE_NONNULL(kj::Url::tryParse(kj::mv(url)), - TypeError, "Invalid URL string.")); + return jsg::alloc( + JSG_REQUIRE_NONNULL(kj::Url::tryParse(kj::mv(url)), TypeError, "Invalid URL string.")); } URL::URL(kj::Url&& u): url(kj::refcounted(kj::mv(u))) { @@ -343,9 +344,8 @@ void URL::setPort(kj::String value) { kj::String URL::getPathname() { if (url->path.size() > 0) { - auto components = KJ_MAP(component, url->path) { - return kj::str('/', kj::encodeUriPath(component)); - }; + auto components = + KJ_MAP(component, url->path) { return kj::str('/', kj::encodeUriPath(component)); }; return kj::str(kj::strArray(components, ""), url->hasTrailingSlash ? "/" : ""); } else if (url->hasTrailingSlash || isSpecialScheme(url->scheme)) { // Special URLs have non-empty paths by definition, regardless of the value of hasTrailingSlash. @@ -433,10 +433,10 @@ void URL::setSearch(kj::String value) { // // See step 1.3.1 of https://url.spec.whatwg.org/#query-state KJ_IF_SOME(key, trySplit(part, '=')) { - newQuery.add(kj::Url::QueryParam { percentDecodeQuery(key, err), - percentDecodeQuery(part, err) }); + newQuery.add( + kj::Url::QueryParam{percentDecodeQuery(key, err), percentDecodeQuery(part, err)}); } else { - newQuery.add(kj::Url::QueryParam { percentDecodeQuery(part, err), nullptr }); + newQuery.add(kj::Url::QueryParam{percentDecodeQuery(part, err), nullptr}); } } @@ -497,14 +497,15 @@ jsg::Ref URLSearchParams::constructor( } KJ_CASE_ONEOF(dict, jsg::Dict) { searchParams->url->query = KJ_MAP(entry, dict.fields) { - return kj::Url::QueryParam { kj::mv(entry.name), kj::mv(entry.value) }; + return kj::Url::QueryParam{kj::mv(entry.name), kj::mv(entry.value)}; }; } KJ_CASE_ONEOF(arrayOfArrays, kj::Array>) { searchParams->url->query = KJ_MAP(entry, arrayOfArrays) { - JSG_REQUIRE(entry.size() == 2, TypeError, "To initialize a URLSearchParams object " + JSG_REQUIRE(entry.size() == 2, TypeError, + "To initialize a URLSearchParams object " "from an array-of-arrays, each inner array must have exactly two elements."); - return kj::Url::QueryParam { kj::mv(entry[0]), kj::mv(entry[1]) }; + return kj::Url::QueryParam{kj::mv(entry[0]), kj::mv(entry[1])}; }; } } @@ -514,12 +515,12 @@ jsg::Ref URLSearchParams::constructor( } void URLSearchParams::append(kj::String name, kj::String value) { - url->query.add(kj::Url::QueryParam { kj::mv(name), kj::mv(value) }); + url->query.add(kj::Url::QueryParam{kj::mv(name), kj::mv(value)}); } void URLSearchParams::delete_(kj::String name) { - auto pivot = std::remove_if(url->query.begin(), url->query.end(), - [&name](const auto& kv) { return kv.name == name; }); + auto pivot = std::remove_if( + url->query.begin(), url->query.end(), [&name](const auto& kv) { return kv.name == name; }); url->query.truncate(pivot - url->query.begin()); } @@ -574,17 +575,15 @@ void URLSearchParams::sort() { // ffi ef ac 83 | fb03 // 🌈 f0 9f 8c 88 | d83c df08 - std::stable_sort(url->query.begin(), url->query.end(), - [](const auto& left, const auto& right) { - auto leftUtf16 = kj::encodeUtf16(left.name.asArray()); - auto rightUtf16 = kj::encodeUtf16(right.name.asArray()); - return std::lexicographical_compare(leftUtf16.begin(), leftUtf16.end(), - rightUtf16.begin(), rightUtf16.end()); - }); + std::stable_sort(url->query.begin(), url->query.end(), [](const auto& left, const auto& right) { + auto leftUtf16 = kj::encodeUtf16(left.name.asArray()); + auto rightUtf16 = kj::encodeUtf16(right.name.asArray()); + return std::lexicographical_compare( + leftUtf16.begin(), leftUtf16.end(), rightUtf16.begin(), rightUtf16.end()); + }); } -void URLSearchParams::forEach( - jsg::Lock& js, +void URLSearchParams::forEach(jsg::Lock& js, jsg::Function)> callback, jsg::Optional thisArg) { auto receiver = js.v8Undefined(); @@ -608,15 +607,15 @@ void URLSearchParams::forEach( } jsg::Ref URLSearchParams::entries(jsg::Lock&) { - return jsg::alloc(IteratorState { JSG_THIS }); + return jsg::alloc(IteratorState{JSG_THIS}); } jsg::Ref URLSearchParams::keys(jsg::Lock&) { - return jsg::alloc(IteratorState { JSG_THIS }); + return jsg::alloc(IteratorState{JSG_THIS}); } jsg::Ref URLSearchParams::values(jsg::Lock&) { - return jsg::alloc(IteratorState { JSG_THIS }); + return jsg::alloc(IteratorState{JSG_THIS}); } kj::String URLSearchParams::toString() { diff --git a/src/workerd/api/urlpattern.c++ b/src/workerd/api/urlpattern.c++ index db07c9ece32..71434b15766 100644 --- a/src/workerd/api/urlpattern.c++ +++ b/src/workerd/api/urlpattern.c++ @@ -8,14 +8,13 @@ namespace workerd::api { namespace { -jsg::JsRef compileRegex(jsg::Lock& js, - const jsg::UrlPattern::Component& component, - bool ignoreCase) { +jsg::JsRef compileRegex( + jsg::Lock& js, const jsg::UrlPattern::Component& component, bool ignoreCase) { return js.tryCatch([&] { jsg::Lock::RegExpFlags flags = jsg::Lock::RegExpFlags::kUNICODE; if (ignoreCase) { - flags = static_cast(flags | - static_cast(jsg::Lock::RegExpFlags::kIGNORE_CASE)); + flags = static_cast( + flags | static_cast(jsg::Lock::RegExpFlags::kIGNORE_CASE)); } return jsg::JsRef(js, js.regexp(component.getRegex(), flags)); }, [&](auto reason) -> jsg::JsRef { @@ -36,13 +35,11 @@ jsg::Ref create(jsg::Lock& js, jsg::UrlPattern pattern) { #undef V #define V(_, var) , kj::mv(var) - return jsg::alloc(kj::mv(pattern) - URL_PATTERN_COMPONENTS(V)); + return jsg::alloc(kj::mv(pattern) URL_PATTERN_COMPONENTS(V)); #undef V } -kj::Maybe execRegex( - jsg::Lock& js, +kj::Maybe execRegex(jsg::Lock& js, jsg::JsRef& regex, kj::ArrayPtr nameList, kj::StringPtr input) { @@ -57,16 +54,16 @@ kj::Maybe execRegex( while (index < length) { auto value = array.get(js, index); - fields.add(Groups::Field { + fields.add(Groups::Field{ .name = kj::str(nameList[index - 1]), .value = value.isUndefined() ? kj::str() : kj::str(value), }); index++; } - return URLPattern::URLPatternComponentResult { + return URLPattern::URLPatternComponentResult{ .input = kj::str(input), - .groups = Groups { .fields = fields.releaseAsArray() }, + .groups = Groups{.fields = fields.releaseAsArray()}, }; } @@ -74,8 +71,7 @@ kj::Maybe execRegex( } } // namespace -URLPattern::URLPattern( - jsg::UrlPattern inner, +URLPattern::URLPattern(jsg::UrlPattern inner, jsg::JsRef protocolRegex, jsg::JsRef usernameRegex, jsg::JsRef passwordRegex, @@ -95,18 +91,34 @@ URLPattern::URLPattern( hashRegex(kj::mv(hashRegex)) {} void URLPattern::visitForGc(jsg::GcVisitor& visitor) { - visitor.visit(protocolRegex, usernameRegex, passwordRegex, hostnameRegex, - portRegex, pathnameRegex, searchRegex, hashRegex); + visitor.visit(protocolRegex, usernameRegex, passwordRegex, hostnameRegex, portRegex, + pathnameRegex, searchRegex, hashRegex); } -kj::StringPtr URLPattern::getProtocol() { return inner.getProtocol().getPattern(); } -kj::StringPtr URLPattern::getUsername() { return inner.getUsername().getPattern(); } -kj::StringPtr URLPattern::getPassword() { return inner.getPassword().getPattern(); } -kj::StringPtr URLPattern::getHostname() { return inner.getHostname().getPattern(); } -kj::StringPtr URLPattern::getPort() { return inner.getPort().getPattern(); } -kj::StringPtr URLPattern::getPathname() { return inner.getPathname().getPattern(); } -kj::StringPtr URLPattern::getSearch() { return inner.getSearch().getPattern(); } -kj::StringPtr URLPattern::getHash() { return inner.getHash().getPattern(); } +kj::StringPtr URLPattern::getProtocol() { + return inner.getProtocol().getPattern(); +} +kj::StringPtr URLPattern::getUsername() { + return inner.getUsername().getPattern(); +} +kj::StringPtr URLPattern::getPassword() { + return inner.getPassword().getPattern(); +} +kj::StringPtr URLPattern::getHostname() { + return inner.getHostname().getPattern(); +} +kj::StringPtr URLPattern::getPort() { + return inner.getPort().getPattern(); +} +kj::StringPtr URLPattern::getPathname() { + return inner.getPathname().getPattern(); +} +kj::StringPtr URLPattern::getSearch() { + return inner.getSearch().getPattern(); +} +kj::StringPtr URLPattern::getHash() { + return inner.getHash().getPattern(); +} URLPattern::URLPatternInit::operator jsg::UrlPattern::Init() { return { @@ -122,18 +134,18 @@ URLPattern::URLPatternInit::operator jsg::UrlPattern::Init() { }; } -jsg::Ref URLPattern::constructor( - jsg::Lock& js, +jsg::Ref URLPattern::constructor(jsg::Lock& js, jsg::Optional input, jsg::Optional baseURL, jsg::Optional patternOptions) { auto options = patternOptions.orDefault({}); - KJ_SWITCH_ONEOF(kj::mv(input).orDefault(URLPatternInit {})) { + KJ_SWITCH_ONEOF(kj::mv(input).orDefault(URLPatternInit{})) { KJ_CASE_ONEOF(str, kj::String) { - KJ_SWITCH_ONEOF(jsg::UrlPattern::tryCompile(str.asPtr(), jsg::UrlPattern::CompileOptions { - .baseUrl = baseURL.map([](kj::String& str) { return str.asPtr(); }), - .ignoreCase = options.ignoreCase.orDefault(false), - })) { + KJ_SWITCH_ONEOF(jsg::UrlPattern::tryCompile(str.asPtr(), + jsg::UrlPattern::CompileOptions{ + .baseUrl = baseURL.map([](kj::String& str) { return str.asPtr(); }), + .ignoreCase = options.ignoreCase.orDefault(false), + })) { KJ_CASE_ONEOF(err, kj::String) { JSG_FAIL_REQUIRE(TypeError, kj::mv(err)); } @@ -143,9 +155,10 @@ jsg::Ref URLPattern::constructor( } } KJ_CASE_ONEOF(init, URLPatternInit) { - KJ_SWITCH_ONEOF(jsg::UrlPattern::tryCompile(init, jsg::UrlPattern::CompileOptions { - .ignoreCase = options.ignoreCase.orDefault(false), - })) { + KJ_SWITCH_ONEOF(jsg::UrlPattern::tryCompile(init, + jsg::UrlPattern::CompileOptions{ + .ignoreCase = options.ignoreCase.orDefault(false), + })) { KJ_CASE_ONEOF(err, kj::String) { JSG_FAIL_REQUIRE(TypeError, kj::mv(err)); } @@ -159,16 +172,12 @@ jsg::Ref URLPattern::constructor( } bool URLPattern::test( - jsg::Lock& js, - jsg::Optional input, - jsg::Optional baseURL) { + jsg::Lock& js, jsg::Optional input, jsg::Optional baseURL) { return exec(js, kj::mv(input), kj::mv(baseURL)) != kj::none; } kj::Maybe URLPattern::exec( - jsg::Lock& js, - jsg::Optional maybeInput, - jsg::Optional maybeBase) { + jsg::Lock& js, jsg::Optional maybeInput, jsg::Optional maybeBase) { auto input = kj::mv(maybeInput).orDefault(URLPattern::URLPatternInit()); kj::Vector inputs(2); @@ -183,8 +192,9 @@ kj::Maybe URLPattern::exec( KJ_SWITCH_ONEOF(input) { KJ_CASE_ONEOF(string, kj::String) { - KJ_IF_SOME(url, jsg::Url::tryParse(string.asPtr(), - maybeBase.map([](kj::String& s) { return s.asPtr(); }))) { + KJ_IF_SOME(url, jsg::Url::tryParse(string.asPtr(), maybeBase.map([](kj::String& s) { + return s.asPtr(); + }))) { auto p = url.getProtocol(); protocol = kj::str(p.slice(0, p.size() - 1)); username = kj::str(url.getUsername()); @@ -198,12 +208,14 @@ kj::Maybe URLPattern::exec( return kj::none; } inputs.add(kj::mv(string)); - KJ_IF_SOME(base, maybeBase) { inputs.add(kj::mv(base)); } + KJ_IF_SOME(base, maybeBase) { + inputs.add(kj::mv(base)); + } } KJ_CASE_ONEOF(i, URLPattern::URLPatternInit) { - JSG_REQUIRE(maybeBase == kj::none, TypeError, - "A baseURL is not allowed when input is an object."); - inputs.add(URLPattern::URLPatternInit { + JSG_REQUIRE( + maybeBase == kj::none, TypeError, "A baseURL is not allowed when input is an object."); + inputs.add(URLPattern::URLPatternInit{ .protocol = i.protocol.map([](kj::String& str) { return kj::str(str); }), .username = i.username.map([](kj::String& str) { return kj::str(str); }), .password = i.password.map([](kj::String& str) { return kj::str(str); }), @@ -228,8 +240,7 @@ kj::Maybe URLPattern::exec( }; jsg::UrlPattern::ProcessInitOptions options = { - .mode = jsg::UrlPattern::ProcessInitOptions::Mode::URL - }; + .mode = jsg::UrlPattern::ProcessInitOptions::Mode::URL}; KJ_SWITCH_ONEOF(jsg::UrlPattern::processInit(kj::mv(init), kj::mv(options))) { KJ_CASE_ONEOF(err, kj::String) { @@ -258,18 +269,14 @@ kj::Maybe URLPattern::exec( auto searchExecResult = execRegex(js, searchRegex, inner.getSearch().getNames(), search); auto hashExecResult = execRegex(js, hashRegex, inner.getHash().getNames(), hash); - if (protocolExecResult == kj::none || - usernameExecResult == kj::none || - passwordExecResult == kj::none || - hostnameExecResult == kj::none || - portExecResult == kj::none || - pathnameExecResult == kj::none || - searchExecResult == kj::none || - hashExecResult == kj::none) { + if (protocolExecResult == kj::none || usernameExecResult == kj::none || + passwordExecResult == kj::none || hostnameExecResult == kj::none || + portExecResult == kj::none || pathnameExecResult == kj::none || + searchExecResult == kj::none || hashExecResult == kj::none) { return kj::none; } - return URLPattern::URLPatternResult { + return URLPattern::URLPatternResult{ .inputs = inputs.releaseAsArray(), .protocol = kj::mv(KJ_REQUIRE_NONNULL(protocolExecResult)), .username = kj::mv(KJ_REQUIRE_NONNULL(usernameExecResult)), diff --git a/src/workerd/api/urlpattern.h b/src/workerd/api/urlpattern.h index a1b6fdb13c7..d6653bf9e32 100644 --- a/src/workerd/api/urlpattern.h +++ b/src/workerd/api/urlpattern.h @@ -9,14 +9,14 @@ namespace workerd::api { -#define URL_PATTERN_COMPONENTS(V) \ - V(Protocol, protocol) \ - V(Username, username) \ - V(Password, password) \ - V(Hostname, hostname) \ - V(Port, port) \ - V(Pathname, pathname) \ - V(Search, search) \ +#define URL_PATTERN_COMPONENTS(V) \ + V(Protocol, protocol) \ + V(Username, username) \ + V(Password, password) \ + V(Hostname, hostname) \ + V(Port, port) \ + V(Pathname, pathname) \ + V(Search, search) \ V(Hash, hash) // URLPattern is a Web Platform standard API for matching URLs against a @@ -75,28 +75,21 @@ class URLPattern final: public jsg::Object { JSG_STRUCT(ignoreCase); }; - explicit URLPattern( - jsg::UrlPattern inner -#define V(_, name) ,jsg::JsRef name##Regex - URL_PATTERN_COMPONENTS(V) + explicit URLPattern(jsg::UrlPattern inner +#define V(_, name) , jsg::JsRef name##Regex + URL_PATTERN_COMPONENTS(V) #undef V - ); + ); - static jsg::Ref constructor( - jsg::Lock& js, + static jsg::Ref constructor(jsg::Lock& js, jsg::Optional input, jsg::Optional baseURL, jsg::Optional patternOptions); kj::Maybe exec( - jsg::Lock& js, - jsg::Optional input, - jsg::Optional baseURL); + jsg::Lock& js, jsg::Optional input, jsg::Optional baseURL); - bool test( - jsg::Lock& js, - jsg::Optional input, - jsg::Optional baseURL); + bool test(jsg::Lock& js, jsg::Optional input, jsg::Optional baseURL); #define V(name, _) kj::StringPtr get##name(); URL_PATTERN_COMPONENTS(V) @@ -123,11 +116,8 @@ class URLPattern final: public jsg::Object { void visitForGc(jsg::GcVisitor& visitor); }; -#define EW_URLPATTERN_ISOLATE_TYPES \ - api::URLPattern, \ - api::URLPattern::URLPatternInit, \ - api::URLPattern::URLPatternComponentResult, \ - api::URLPattern::URLPatternResult, \ - api::URLPattern::URLPatternOptions +#define EW_URLPATTERN_ISOLATE_TYPES \ + api::URLPattern, api::URLPattern::URLPatternInit, api::URLPattern::URLPatternComponentResult, \ + api::URLPattern::URLPatternResult, api::URLPattern::URLPatternOptions } // namespace workerd::api diff --git a/src/workerd/api/util-test.c++ b/src/workerd/api/util-test.c++ index 3f9a1ab915b..cefe35514d3 100644 --- a/src/workerd/api/util-test.c++ +++ b/src/workerd/api/util-test.c++ @@ -26,11 +26,9 @@ KJ_TEST("redactUrl can detect hex ids") { expectUnredacted("https://domain/path?a=1&b=2"_kj); expectRedacted( - "https://domain/0123456789abcdef0123456789abcdef/x"_kj, - "https://domain/REDACTED/x"_kj); + "https://domain/0123456789abcdef0123456789abcdef/x"_kj, "https://domain/REDACTED/x"_kj); expectRedacted( - "https://domain/0123456789abcdef-0123456789abcdef/x"_kj, - "https://domain/REDACTED/x"_kj); + "https://domain/0123456789abcdef-0123456789abcdef/x"_kj, "https://domain/REDACTED/x"_kj); // not long enough: expectUnredacted("https://domain/0123456789abcdef0123456789abcde/x"_kj); @@ -62,156 +60,99 @@ KJ_TEST("readContentTypeParameter can fetch boundary parameter") { // normal expectContentTypeParameter( - "multipart/form-data; boundary=\"__boundary__\""_kj, - "boundary"_kj, - "__boundary__"_kj - ); + "multipart/form-data; boundary=\"__boundary__\""_kj, "boundary"_kj, "__boundary__"_kj); // multiple params - expectContentTypeParameter( - "multipart/form-data; charset=utf-8; boundary=\"__boundary__\""_kj, - "boundary"_kj, - "__boundary__"_kj - ); + expectContentTypeParameter("multipart/form-data; charset=utf-8; boundary=\"__boundary__\""_kj, + "boundary"_kj, "__boundary__"_kj); - // param name inside value of other param + // param name inside value of other param expectContentTypeParameter( - "multipart/form-data; charset=\"boundary=;\"; boundary=\"__boundary__\""_kj, - "boundary"_kj, - "__boundary__"_kj - ); + "multipart/form-data; charset=\"boundary=;\"; boundary=\"__boundary__\""_kj, "boundary"_kj, + "__boundary__"_kj); // ensure param is not found KJ_ASSERT(readContentTypeParameter( - "multipart/form-data; charset=\"boundary=;\"; boundary=\"__boundary__\""_kj, - "boundary1"_kj - ) == kj::none); + "multipart/form-data; charset=\"boundary=;\"; boundary=\"__boundary__\""_kj, + "boundary1"_kj) == kj::none); // no quotes expectContentTypeParameter( - "multipart/form-data; charset=\"boundary=;\"; boundary=__boundary__"_kj, - "boundary"_kj, - "__boundary__"_kj - ); + "multipart/form-data; charset=\"boundary=;\"; boundary=__boundary__"_kj, "boundary"_kj, + "__boundary__"_kj); // attribute names are case-insensitive, but values are not expectContentTypeParameter( - "multipart/form-data; charset=\"boundary=;\"; boundary=__Boundary__"_kj, - "Boundary"_kj, - "__Boundary__"_kj - ); + "multipart/form-data; charset=\"boundary=;\"; boundary=__Boundary__"_kj, "Boundary"_kj, + "__Boundary__"_kj); // different order - expectContentTypeParameter( - "multipart/form-data; boundary=\"__boundary__\"; charset=utf-8"_kj, - "boundary"_kj, - "__boundary__"_kj - ); + expectContentTypeParameter("multipart/form-data; boundary=\"__boundary__\"; charset=utf-8"_kj, + "boundary"_kj, "__boundary__"_kj); // bogus parameter - expectContentTypeParameter( - "multipart/form-data; foo=123; boundary=\"__boundary__\""_kj, - "boundary"_kj, - "__boundary__"_kj - ); + expectContentTypeParameter("multipart/form-data; foo=123; boundary=\"__boundary__\""_kj, + "boundary"_kj, "__boundary__"_kj); // quoted-string expectContentTypeParameter( - R"(multipart/form-data; foo="\"boundary=bar\""; boundary="realboundary")", - "boundary"_kj, - "realboundary"_kj - ); + R"(multipart/form-data; foo="\"boundary=bar\""; boundary="realboundary")", "boundary"_kj, + "realboundary"_kj); // handle non-closing quotes expectContentTypeParameter( - R"(multipart/form-data; charset="boundary=;\"; boundary="__boundary__")", - "boundary"_kj, - "__boundary__"_kj); + R"(multipart/form-data; charset="boundary=;\"; boundary="__boundary__")", "boundary"_kj, + "__boundary__"_kj); expectContentTypeParameter( - R"(multipart/form-data; charset="boundary=;"; boundary="__boundary__\")", - "boundary"_kj, - "__boundary__"_kj); + R"(multipart/form-data; charset="boundary=;"; boundary="__boundary__\")", "boundary"_kj, + "__boundary__"_kj); expectContentTypeParameter( - R"(multipart/form-data; charset=\"boundary=;\"; boundary=\"__boundary__\")", - "boundary"_kj, - R"(\"__boundary__\")"); + R"(multipart/form-data; charset=\"boundary=;\"; boundary=\"__boundary__\")", "boundary"_kj, + R"(\"__boundary__\")"); // spurious whitespace before ; expectContentTypeParameter( - "multipart/form-data; boundary=asdf ;foo=bar"_kj, - "boundary"_kj, - "asdf"_kj - ); + "multipart/form-data; boundary=asdf ;foo=bar"_kj, "boundary"_kj, "asdf"_kj); // spurious whitespace before ; with quotes expectContentTypeParameter( - "multipart/form-data; boundary=\"asdf\" ;foo=bar"_kj, - "boundary"_kj, - "asdf"_kj - ); + "multipart/form-data; boundary=\"asdf\" ;foo=bar"_kj, "boundary"_kj, "asdf"_kj); // all whitespace - KJ_ASSERT(readContentTypeParameter( - "multipart/form-data; boundary= ;foo=bar"_kj, - "boundary"_kj - ) == kj::none); + KJ_ASSERT(readContentTypeParameter("multipart/form-data; boundary= ;foo=bar"_kj, "boundary"_kj) == + kj::none); // all whitespace with quotes - KJ_ASSERT(readContentTypeParameter( - "multipart/form-data; boundary="" ;foo=bar"_kj, - "boundary"_kj - ) == kj::none); + KJ_ASSERT(readContentTypeParameter("multipart/form-data; boundary=" + " ;foo=bar"_kj, + "boundary"_kj) == kj::none); // terminal escape character after quote - KJ_ASSERT(readContentTypeParameter( - R"(multipart/form-data; foo="\)", - "boundary"_kj - ) == kj::none); + KJ_ASSERT(readContentTypeParameter(R"(multipart/form-data; foo="\)", "boundary"_kj) == kj::none); // space before value - expectContentTypeParameter( - "multipart/form-data; boundary= a"_kj, - "boundary"_kj, - " a"_kj - ); + expectContentTypeParameter("multipart/form-data; boundary= a"_kj, "boundary"_kj, " a"_kj); // space before value with quotes - expectContentTypeParameter( - "multipart/form-data; boundary=\" a\""_kj, - "boundary"_kj, - " a"_kj - ); + expectContentTypeParameter("multipart/form-data; boundary=\" a\""_kj, "boundary"_kj, " a"_kj); // space before ; on another param expectContentTypeParameter( - "multipart/form-data; foo=\"bar\" ;boundary=asdf"_kj, - "boundary"_kj, - "asdf"_kj - ); + "multipart/form-data; foo=\"bar\" ;boundary=asdf"_kj, "boundary"_kj, "asdf"_kj); // space before ; on another param with quotes expectContentTypeParameter( - "multipart/form-data; foo=\"bar\" ;boundary=\"asdf\""_kj, - "boundary"_kj, - "asdf"_kj - ); + "multipart/form-data; foo=\"bar\" ;boundary=\"asdf\""_kj, "boundary"_kj, "asdf"_kj); // space before ; on another param no quotes expectContentTypeParameter( - "multipart/form-data; foo=bar ;boundary=asdf"_kj, - "boundary"_kj, - "asdf"_kj - ); + "multipart/form-data; foo=bar ;boundary=asdf"_kj, "boundary"_kj, "asdf"_kj); // space before ; on another param quotes on wanted param expectContentTypeParameter( - "multipart/form-data; foo=bar ;boundary=\"asdf\""_kj, - "boundary"_kj, - "asdf"_kj - ); - + "multipart/form-data; foo=bar ;boundary=\"asdf\""_kj, "boundary"_kj, "asdf"_kj); } } // namespace diff --git a/src/workerd/api/util.c++ b/src/workerd/api/util.c++ index 2adb50233a5..ba9da01d3fa 100644 --- a/src/workerd/api/util.c++ +++ b/src/workerd/api/util.c++ @@ -54,8 +54,9 @@ kj::String toUpper(kj::String&& str) { return kj::mv(str); } -void parseQueryString(kj::Vector& query, kj::ArrayPtr text, - bool skipLeadingQuestionMark) { +void parseQueryString(kj::Vector& query, + kj::ArrayPtr text, + bool skipLeadingQuestionMark) { if (skipLeadingQuestionMark && text.size() > 0 && text[0] == '?') { text = text.slice(1, text.size()); } @@ -64,22 +65,19 @@ void parseQueryString(kj::Vector& query, kj::ArrayPtr& query, kj::ArrayPtr rawText, - bool skipLeadingQuestionMark = false); +void parseQueryString(kj::Vector& query, + kj::ArrayPtr rawText, + bool skipLeadingQuestionMark = false); // TODO(cleanup): Would be really nice to move this to kj-url. // Given the value of a Content-Type header, returns the value of a single expected parameter. @@ -58,8 +57,7 @@ void parseQueryString(kj::Vector& query, kj::ArrayPtr readContentTypeParameter(kj::StringPtr contentType, - kj::StringPtr param); +kj::Maybe readContentTypeParameter(kj::StringPtr contentType, kj::StringPtr param); // TODO(cleanup): Replace this function with a full kj::MimeType parser. // ======================================================================================= @@ -78,8 +76,7 @@ struct ErrorTranslation { // user. While crude, we can string match to provide cleaned up exception messages. This O(n) // function helps you do that. kj::Maybe translateKjException( - const kj::Exception& exception, - std::initializer_list translations); + const kj::Exception& exception, std::initializer_list translations); // ======================================================================================= diff --git a/src/workerd/api/web-socket.c++ b/src/workerd/api/web-socket.c++ index 6f8df65ace4..2a2b62b542e 100644 --- a/src/workerd/api/web-socket.c++ +++ b/src/workerd/api/web-socket.c++ @@ -20,23 +20,20 @@ kj::StringPtr KJ_STRINGIFY(const WebSocket::NativeState& state) { KJ_SWITCH_ONEOF(state) { KJ_CASE_ONEOF(ac, WebSocket::AwaitingConnection) return "AwaitingConnection"; KJ_CASE_ONEOF(aaoc, WebSocket::AwaitingAcceptanceOrCoupling) - return "AwaitingAcceptanceOrCoupling"; + return "AwaitingAcceptanceOrCoupling"; KJ_CASE_ONEOF(a, WebSocket::Accepted) return "Accepted"; KJ_CASE_ONEOF(r, WebSocket::Released) return "Released"; } KJ_UNREACHABLE; } -IoOwn WebSocket::initNative( - IoContext& ioContext, +IoOwn WebSocket::initNative(IoContext& ioContext, kj::WebSocket& ws, kj::Array tags, bool closedOutgoingConn) { auto nativeObj = kj::heap(); - nativeObj->state.init(Accepted::Hibernatable { - .ws = ws, - .tagsRef = kj::mv(tags) }, - *nativeObj, ioContext); + nativeObj->state.init( + Accepted::Hibernatable{.ws = ws, .tagsRef = kj::mv(tags)}, *nativeObj, ioContext); // We might have called `close()` when this WebSocket was previously active. // If so, we want to prevent any future calls to `send()`. nativeObj->closedOutgoing = closedOutgoingConn; @@ -44,34 +41,29 @@ IoOwn WebSocket::initNative( return ioContext.addObject(kj::mv(nativeObj)); } -WebSocket::WebSocket(jsg::Lock& js, - IoContext& ioContext, - kj::WebSocket& ws, - HibernationPackage package) - : weakRef(kj::refcounted>(kj::Badge {}, *this)), +WebSocket::WebSocket( + jsg::Lock& js, IoContext& ioContext, kj::WebSocket& ws, HibernationPackage package) + : weakRef(kj::refcounted>(kj::Badge{}, *this)), url(kj::mv(package.url)), protocol(kj::mv(package.protocol)), extensions(kj::mv(package.extensions)), serializedAttachment(kj::mv(package.serializedAttachment)), - farNative( - initNative(ioContext, - ws, - kj::mv(KJ_REQUIRE_NONNULL(package.maybeTags)), - package.closedOutgoingConnection)), + farNative(initNative(ioContext, + ws, + kj::mv(KJ_REQUIRE_NONNULL(package.maybeTags)), + package.closedOutgoingConnection)), outgoingMessages(IoContext::current().addObject(kj::heap())) {} - // This constructor is used when reinstantiating a websocket that had been hibernating, which is - // why we can go straight to the Accepted state. However, note that we are actually in the - // `Hibernatable` "sub-state"! +// This constructor is used when reinstantiating a websocket that had been hibernating, which is +// why we can go straight to the Accepted state. However, note that we are actually in the +// `Hibernatable` "sub-state"! jsg::Ref WebSocket::hibernatableFromNative( - jsg::Lock& js, - kj::WebSocket& ws, - HibernationPackage package) { + jsg::Lock& js, kj::WebSocket& ws, HibernationPackage package) { return jsg::alloc(js, IoContext::current(), ws, kj::mv(package)); } WebSocket::WebSocket(kj::Own native) - : weakRef(kj::refcounted>(kj::Badge {}, *this)), + : weakRef(kj::refcounted>(kj::Badge{}, *this)), url(kj::none), farNative(nullptr), outgoingMessages(IoContext::current().addObject(kj::heap())) { @@ -81,7 +73,7 @@ WebSocket::WebSocket(kj::Own native) } WebSocket::WebSocket(kj::String url) - : weakRef(kj::refcounted>(kj::Badge {}, *this)), + : weakRef(kj::refcounted>(kj::Badge{}, *this)), url(kj::mv(url)), farNative(nullptr), outgoingMessages(IoContext::current().addObject(kj::heap())) { @@ -94,16 +86,17 @@ void WebSocket::initConnection(jsg::Lock& js, kj::Promise prom) auto& canceler = KJ_ASSERT_NONNULL(farNative->state.tryGet()).canceler; - IoContext::current().awaitIo(js, canceler.wrap(kj::mv(prom)), - [this, self = JSG_THIS](jsg::Lock& js, PackedWebSocket packedSocket) mutable { + IoContext::current() + .awaitIo(js, canceler.wrap(kj::mv(prom)), + [this, self = JSG_THIS](jsg::Lock& js, PackedWebSocket packedSocket) mutable { auto& native = *farNative; KJ_IF_SOME(pending, native.state.tryGet()) { // We've succeessfully established our web socket, we do not need to cancel anything. pending.canceler.release(); } - native.state.init(AwaitingAcceptanceOrCoupling{ - IoContext::current().addObject(kj::mv(packedSocket.ws))}); + native.state.init( + AwaitingAcceptanceOrCoupling{IoContext::current().addObject(kj::mv(packedSocket.ws))}); // both `protocol` and `extensions` start off as empty strings. // They become null if the connection is established and no protocol/extension was chosen. @@ -132,8 +125,7 @@ void WebSocket::initConnection(jsg::Lock& js, kj::Promise prom) reportError(js, jsg::JsValue(e.getHandle(js)).addRef(js)); dispatchEventImpl(js, - jsg::alloc(1006, kj::str("Failed to establish websocket connection"), - false)); + jsg::alloc(1006, kj::str("Failed to establish websocket connection"), false)); }); // Note that in this attach we pass a strong reference to the WebSocket. The reference will be // dropped when either the connection promise completes or the IoContext is torn down, @@ -148,14 +140,14 @@ bool validProtoToken(const kj::StringPtr protocol) { return false; } - for (auto& c : protocol) { + for (auto& c: protocol) { // Note that this also includes separators 0x20 (SP) and 0x09 (HT), so we don't need to check // for them below. if (c < 0x21 || 0x7E < c) { return false; } - switch(c) { + switch (c) { case '(': case ')': case '<': @@ -180,10 +172,9 @@ bool validProtoToken(const kj::StringPtr protocol) { return true; } -} // namespace +} // namespace -jsg::Ref WebSocket::constructor( - jsg::Lock& js, +jsg::Ref WebSocket::constructor(jsg::Lock& js, kj::String url, jsg::Optional, kj::String>> protocols) { @@ -191,9 +182,8 @@ jsg::Ref WebSocket::constructor( // Check if we have a valid URL kj::Url urlRecord; - kj::Maybe maybeException = kj::runCatchingExceptions([&]() { - urlRecord = kj::Url::parse(url); - }); + kj::Maybe maybeException = + kj::runCatchingExceptions([&]() { urlRecord = kj::Url::parse(url); }); constexpr auto wsErr = "WebSocket Constructor: "_kj; @@ -208,8 +198,8 @@ jsg::Ref WebSocket::constructor( urlRecord.scheme = kj::str("https"); } - JSG_REQUIRE(urlRecord.fragment == kj::none, DOMSyntaxError, wsErr, - "The url fragment must be empty."); + JSG_REQUIRE( + urlRecord.fragment == kj::none, DOMSyntaxError, wsErr, "The url fragment must be empty."); kj::HttpHeaders headers(context.getHeaderTable()); auto client = context.getHttpClient(0, false, kj::none, "WebSocket::constructor"_kjc); @@ -221,13 +211,13 @@ jsg::Ref WebSocket::constructor( KJ_SWITCH_ONEOF(variant) { KJ_CASE_ONEOF(proto, kj::String) { - JSG_REQUIRE(validProtoToken(proto), DOMSyntaxError, wsErr, - "The protocol header token is invalid."); + JSG_REQUIRE( + validProtoToken(proto), DOMSyntaxError, wsErr, "The protocol header token is invalid."); protoString = kj::mv(proto); } KJ_CASE_ONEOF(protoArr, kj::Array) { - JSG_REQUIRE(kj::size(protoArr) > 0, DOMSyntaxError, wsErr, - "The protocols array cannot be empty."); + JSG_REQUIRE( + kj::size(protoArr) > 0, DOMSyntaxError, wsErr, "The protocols array cannot be empty."); // Search for duplicates by checking for their presence in the set. kj::HashSet present; @@ -259,13 +249,14 @@ jsg::Ref WebSocket::constructor( headers.unset(kj::HttpHeaderId::SEC_WEBSOCKET_EXTENSIONS); } - auto prom = ([](auto& context, auto connUrl, auto headers, auto client) - -> kj::Promise { + auto prom = + ([](auto& context, auto connUrl, auto headers, auto client) -> kj::Promise { auto response = co_await client->openWebSocket(connUrl, headers); JSG_REQUIRE(response.statusCode == 101, TypeError, "Failed to establish the WebSocket connection: expected server to reply with HTTP " - "status code 101 (switching protocols), but received ", response.statusCode, " instead."); + "status code 101 (switching protocols), but received ", + response.statusCode, " instead."); KJ_SWITCH_ONEOF(response.webSocketOrBody) { KJ_CASE_ONEOF(webSocket, kj::Own) { @@ -283,15 +274,13 @@ jsg::Ref WebSocket::constructor( maybeExtensions = kj::str(extensions); } - co_return PackedWebSocket{ - .ws = webSocket.attach(kj::mv(client)), + co_return PackedWebSocket{.ws = webSocket.attach(kj::mv(client)), .proto = kj::mv(maybeProto), - .extensions = kj::mv(maybeExtensions) - }; + .extensions = kj::mv(maybeExtensions)}; } KJ_CASE_ONEOF(body, kj::Own) { - JSG_FAIL_REQUIRE(TypeError, - "Worker received body in a response to a request for a WebSocket."); + JSG_FAIL_REQUIRE( + TypeError, "Worker received body in a response to a request for a WebSocket."); } } KJ_UNREACHABLE @@ -302,7 +291,8 @@ jsg::Ref WebSocket::constructor( return ws; } -kj::Promise> WebSocket::couple(kj::Own other, RequestObserver& request) { +kj::Promise> WebSocket::couple( + kj::Own other, RequestObserver& request) { auto& native = *farNative; JSG_REQUIRE(!native.state.is(), TypeError, "Can't return WebSocket in a Response if it was created with `new WebSocket()`"); @@ -310,8 +300,8 @@ kj::Promise> WebSocket::couple(kj::Own other, "Can't return WebSocket that was already used in a response."); KJ_IF_SOME(state, native.state.tryGet()) { if (state.isHibernatable()) { - JSG_FAIL_REQUIRE(TypeError, - "Can't return WebSocket in a Response after calling acceptWebSocket()."); + JSG_FAIL_REQUIRE( + TypeError, "Can't return WebSocket in a Response after calling acceptWebSocket()."); } else { JSG_FAIL_REQUIRE(TypeError, "Can't return WebSocket in a Response after calling accept()."); } @@ -320,8 +310,8 @@ kj::Promise> WebSocket::couple(kj::Own other, // Tear down the IoOwn since we now need to extend the WebSocket to a `DeferredProxy` promise. // This works because the `DeferredProxy` ends on the same event loop, but after the request // context goes away. - kj::Own self = kj::mv(KJ_ASSERT_NONNULL( - native.state.tryGet()).ws); + kj::Own self = + kj::mv(KJ_ASSERT_NONNULL(native.state.tryGet()).ws); native.state.init(); auto& context = IoContext::current(); @@ -355,9 +345,9 @@ kj::Promise> WebSocket::couple(kj::Own other, // We need to use `eagerlyEvaluate()` on both inputs to `joinPromises` to work around the awkward // behavior of `joinPromises` lazily-evaluating tail continuations. - auto promise = kj::joinPromises(kj::arr(upstream.eagerlyEvaluate(nullptr), - downstream.eagerlyEvaluate(nullptr))) - .attach(kj::mv(self), kj::mv(other)); + auto promise = kj::joinPromises( + kj::arr(upstream.eagerlyEvaluate(nullptr), downstream.eagerlyEvaluate(nullptr))) + .attach(kj::mv(self), kj::mv(other)); KJ_IF_SOME(peer, tryGetPeer()) { // Since the WebSocket is terminated locally, we generally want the request and associated @@ -521,15 +511,18 @@ void WebSocket::startReadLoop(jsg::Lock& js, kj::Maybe&& maybeError) mutable { + context.addWaitUntil(context.awaitJs(js, + context.awaitIoLegacy(js, kj::mv(promise)) + .then(js, + [this, thisHandle = JSG_THIS]( + jsg::Lock& js, kj::Maybe&& maybeError) mutable { auto& native = *farNative; KJ_IF_SOME(e, maybeError) { if (!native.closedIncoming && e.getType() == kj::Exception::Type::DISCONNECTED) { // Report premature disconnect or cancel as a close event. - dispatchEventImpl(js, jsg::alloc( - 1006, kj::str("WebSocket disconnected without sending Close frame."), false)); + dispatchEventImpl(js, + jsg::alloc( + 1006, kj::str("WebSocket disconnected without sending Close frame."), false)); native.closedIncoming = true; // If there are no further messages to send, so we can discard the underlying connection. tryReleaseNative(js); @@ -564,7 +557,7 @@ void WebSocket::send(jsg::Lock& js, kj::OneOf, kj::String> messa } JSG_REQUIRE(native.state.is(), TypeError, - "You must call one of accept() or state.acceptWebSocket() on this WebSocket before sending "\ + "You must call one of accept() or state.acceptWebSocket() on this WebSocket before sending " "messages."); auto maybeOutputLock = IoContext::current().waitForOutputLocksIfNecessary(); @@ -583,16 +576,16 @@ void WebSocket::send(jsg::Lock& js, kj::OneOf, kj::String> messa KJ_UNREACHABLE; }(); - auto pendingAutoResponses = autoResponseStatus.pendingAutoResponseDeque.size() - - autoResponseStatus.queuedAutoResponses; + auto pendingAutoResponses = + autoResponseStatus.pendingAutoResponseDeque.size() - autoResponseStatus.queuedAutoResponses; autoResponseStatus.queuedAutoResponses = autoResponseStatus.pendingAutoResponseDeque.size(); - outgoingMessages->insert(GatedMessage{kj::mv(maybeOutputLock), kj::mv(msg), pendingAutoResponses}); + outgoingMessages->insert( + GatedMessage{kj::mv(maybeOutputLock), kj::mv(msg), pendingAutoResponses}); ensurePumping(js); } -void WebSocket::close( - jsg::Lock& js, jsg::Optional code, jsg::Optional reason) { +void WebSocket::close(jsg::Lock& js, jsg::Optional code, jsg::Optional reason) { auto& native = *farNative; // Handle close before connection is established for websockets obtained through `new WebSocket()`. @@ -617,14 +610,14 @@ void WebSocket::close( return; } JSG_REQUIRE(native.state.is(), TypeError, - "You must call one of accept() or state.acceptWebSocket() on this WebSocket before sending "\ + "You must call one of accept() or state.acceptWebSocket() on this WebSocket before sending " "messages."); assertNoError(js); KJ_IF_SOME(c, code) { JSG_REQUIRE(c >= 1000 && c < 5000 && c != 1004 && c != 1005 && c != 1006 && c != 1015, - TypeError, "Invalid WebSocket close code: ", c, "."); + TypeError, "Invalid WebSocket close code: ", c, "."); } if (reason != kj::none) { // The default code of 1005 cannot have a reason, per the standard, so if a reason is specified @@ -638,18 +631,17 @@ void WebSocket::close( // queuedAutoResponses stores the total number of auto-response messages that are already in accounted // for in previous GatedMessages. This is useful to easily calculate the number of pendingAutoResponses // for each new GateMessage. - auto pendingAutoResponses = autoResponseStatus.pendingAutoResponseDeque.size() - - autoResponseStatus.queuedAutoResponses; + auto pendingAutoResponses = + autoResponseStatus.pendingAutoResponseDeque.size() - autoResponseStatus.queuedAutoResponses; autoResponseStatus.queuedAutoResponses = autoResponseStatus.pendingAutoResponseDeque.size(); - outgoingMessages->insert(GatedMessage{ - IoContext::current().waitForOutputLocksIfNecessary(), - kj::WebSocket::Close { - // Code 1005 actually translates to sending a close message with no body on the wire. - static_cast(code.orDefault(1005)), - kj::mv(reason).orDefault(nullptr), - }, pendingAutoResponses - }); + outgoingMessages->insert(GatedMessage{IoContext::current().waitForOutputLocksIfNecessary(), + kj::WebSocket::Close{ + // Code 1005 actually translates to sending a close message with no body on the wire. + static_cast(code.orDefault(1005)), + kj::mv(reason).orDefault(nullptr), + }, + pendingAutoResponses}); native.closedOutgoing = true; closedOutgoingForHib = true; @@ -697,50 +689,51 @@ kj::Maybe WebSocket::getPreferredExtensions(kj::WebSocket::Extension } kj::Maybe WebSocket::getUrl() { - return url.map([](kj::StringPtr value){ return value; }); + return url.map([](kj::StringPtr value) { return value; }); } kj::Maybe WebSocket::getProtocol() { - return protocol.map([](kj::StringPtr value){ return value; }); + return protocol.map([](kj::StringPtr value) { return value; }); } kj::Maybe WebSocket::getExtensions() { - return extensions.map([](kj::StringPtr value){ return value; }); + return extensions.map([](kj::StringPtr value) { return value; }); } kj::Maybe WebSocket::deserializeAttachment(jsg::Lock& js) { - return serializedAttachment.map([&](kj::ArrayPtr attachment) - -> jsg::JsValue { + return serializedAttachment.map([&](kj::ArrayPtr attachment) -> jsg::JsValue { jsg::Deserializer deserializer(js, attachment, kj::none, kj::none, - jsg::Deserializer::Options { - .version = 15, - .readHeader = true, - }); + jsg::Deserializer::Options{ + .version = 15, + .readHeader = true, + }); return deserializer.readValue(js); }); } void WebSocket::serializeAttachment(jsg::Lock& js, jsg::JsValue attachment) { - jsg::Serializer serializer(js, jsg::Serializer::Options { - .version = 15, - .omitHeader = false, - }); + jsg::Serializer serializer(js, + jsg::Serializer::Options{ + .version = 15, + .omitHeader = false, + }); serializer.write(js, attachment); auto released = serializer.release(); JSG_REQUIRE(released.data.size() <= MAX_ATTACHMENT_SIZE, Error, - "A WebSocket 'attachment' cannot be larger than ", MAX_ATTACHMENT_SIZE, " bytes." \ - "'attachment' was ", released.data.size(), " bytes."); + "A WebSocket 'attachment' cannot be larger than ", MAX_ATTACHMENT_SIZE, + " bytes." + "'attachment' was ", + released.data.size(), " bytes."); serializedAttachment = kj::mv(released.data); } -void WebSocket::setAutoResponseStatus(kj::Maybe time, - kj::Promise autoResponsePromise) { +void WebSocket::setAutoResponseStatus( + kj::Maybe time, kj::Promise autoResponsePromise) { autoResponseTimestamp = time; autoResponseStatus.ongoingAutoResponse = kj::mv(autoResponsePromise); } - kj::Maybe WebSocket::getAutoResponseTimestamp() { return autoResponseTimestamp; } @@ -755,8 +748,8 @@ void WebSocket::ensurePumping(jsg::Lock& js) { auto& context = IoContext::current(); auto& accepted = KJ_ASSERT_NONNULL(native.state.tryGet()); auto promise = kj::evalNow([&]() { - return accepted.canceler.wrap(pump(context, *outgoingMessages, - *accepted.ws, native, autoResponseStatus, observer)); + return accepted.canceler.wrap( + pump(context, *outgoingMessages, *accepted.ws, native, autoResponseStatus, observer)); }); // TODO(cleanup): We use awaitIoLegacy() here because we don't want this to count as a pending @@ -814,7 +807,7 @@ void WebSocket::ensurePumping(jsg::Lock& js) { kj::Promise WebSocket::sendAutoResponse(kj::String message, kj::WebSocket& ws) { if (autoResponseStatus.isPumping) { autoResponseStatus.pendingAutoResponseDeque.push_back(kj::mv(message)); - } else if (!autoResponseStatus.isClosed){ + } else if (!autoResponseStatus.isClosed) { auto p = ws.send(message).fork(); autoResponseStatus.ongoingAutoResponse = p.addBranch(); co_await p; @@ -847,11 +840,14 @@ size_t countBytesFromMessage(const kj::WebSocket::Message& message) { KJ_UNREACHABLE; } -} // namespace +} // namespace -kj::Promise WebSocket::pump( - IoContext& context, OutgoingMessagesMap& outgoingMessages, kj::WebSocket& ws, Native& native, - AutoResponse& autoResponse, kj::Maybe>& observer) { +kj::Promise WebSocket::pump(IoContext& context, + OutgoingMessagesMap& outgoingMessages, + kj::WebSocket& ws, + Native& native, + AutoResponse& autoResponse, + kj::Maybe>& observer) { KJ_ASSERT(!native.isPumping); native.isPumping = true; autoResponse.isPumping = true; @@ -947,8 +943,7 @@ kj::Array WebSocket::getHibernatableTags() { } kj::Promise> WebSocket::readLoop( - kj::Maybe> cs, - size_t maxMessageSize) { + kj::Maybe> cs, size_t maxMessageSize) { try { // Note that we'll throw if the websocket has enabled hibernation. auto& ws = *KJ_REQUIRE_NONNULL( @@ -976,17 +971,17 @@ kj::Promise> WebSocket::readLoop( // something like context.run(handleMessage, *this, kj::mv(message)) where the acquired lock, // and the additional arguments are passed into handleMessage, avoiding the need for the // lambda here entirely. - auto result = co_await context.run([this, message=kj::mv(message)](auto& wLock) mutable { + auto result = co_await context.run([this, message = kj::mv(message)](auto& wLock) mutable { auto& native = *farNative; jsg::Lock& js = wLock; KJ_SWITCH_ONEOF(message) { KJ_CASE_ONEOF(text, kj::String) { - dispatchEventImpl(js, - jsg::alloc(js, js.str(text))); + dispatchEventImpl(js, jsg::alloc(js, js.str(text))); } KJ_CASE_ONEOF(data, kj::Array) { - dispatchEventImpl(js, jsg::alloc(js, - jsg::JsValue(js.arrayBuffer(kj::mv(data)).getHandle(js)))); + dispatchEventImpl(js, + jsg::alloc( + js, jsg::JsValue(js.arrayBuffer(kj::mv(data)).getHandle(js)))); } KJ_CASE_ONEOF(close, kj::WebSocket::Close) { native.closedIncoming = true; @@ -1011,8 +1006,7 @@ kj::Promise> WebSocket::readLoop( jsg::Ref WebSocketPair::constructor() { auto pipe = kj::newWebSocketPipe(); auto pair = jsg::alloc( - jsg::alloc(kj::mv(pipe.ends[0])), - jsg::alloc(kj::mv(pipe.ends[1]))); + jsg::alloc(kj::mv(pipe.ends[0])), jsg::alloc(kj::mv(pipe.ends[1]))); auto first = pair->getFirst(); auto second = pair->getSecond(); @@ -1022,10 +1016,10 @@ jsg::Ref WebSocketPair::constructor() { } jsg::Ref WebSocketPair::entries(jsg::Lock&) { - return jsg::alloc(IteratorState { + return jsg::alloc(IteratorState{ .pair = JSG_THIS, .index = 0, - }); + }); } void WebSocket::reportError(jsg::Lock& js, kj::Exception&& e) { @@ -1038,11 +1032,9 @@ void WebSocket::reportError(jsg::Lock& js, jsg::JsRef err) { auto msg = kj::str(v8::Exception::CreateMessage(js.v8Isolate, err.getHandle(js))->Get()); error = err.addRef(js); - dispatchEventImpl(js, jsg::alloc(kj::str("error"), - ErrorEvent::ErrorEventInit { - .message = kj::mv(msg), - .error = kj::mv(err) - })); + dispatchEventImpl(js, + jsg::alloc(kj::str("error"), + ErrorEvent::ErrorEventInit{.message = kj::mv(msg), .error = kj::mv(err)})); // After an error we don't allow further send()s. If the receive loop has also ended then we // can destroy the connection. Note that we don't set closedOutgoing = true because that flag @@ -1080,10 +1072,7 @@ kj::Own WebSocket::acceptAsHibernatable(kj::Array auto ws = kj::mv(hibernatable.ws); // We pass a reference to the kj::WebSocket for the api::WebSocket to refer to when calling // `send()` or `close()`. - farNative->state.init( - Accepted::Hibernatable { - .ws = *ws, - .tagsRef = kj::mv(tags) }, + farNative->state.init(Accepted::Hibernatable{.ws = *ws, .tagsRef = kj::mv(tags)}, *farNative, IoContext::current()); return kj::mv(ws); } @@ -1134,7 +1123,7 @@ bool WebSocket::peerIsAwaitingCoupling() { WebSocket::HibernationPackage WebSocket::buildPackageForHibernation() { // TODO(cleanup): It would be great if we could limit this so only the HibernationManager // (or a derived class) could call it. - return HibernationPackage { + return HibernationPackage{ .url = kj::mv(url), .protocol = kj::mv(protocol), .extensions = kj::mv(extensions), @@ -1183,8 +1172,8 @@ kj::Maybe&> WebSocket::Accepted::WrappedWebSocket::getIfN return inner.tryGet>(); } -kj::Maybe -WebSocket::Accepted::WrappedWebSocket::getIfHibernatable() { +kj::Maybe WebSocket::Accepted::WrappedWebSocket:: + getIfHibernatable() { return inner.tryGet(); } diff --git a/src/workerd/api/web-socket.h b/src/workerd/api/web-socket.h index 5016723cbdd..f28cddbeafa 100644 --- a/src/workerd/api/web-socket.h +++ b/src/workerd/api/web-socket.h @@ -12,23 +12,28 @@ #include namespace workerd { - class ActorObserver; +class ActorObserver; } namespace workerd::api { -template struct DeferredProxy; +template +struct DeferredProxy; class MessageEvent: public Event { public: MessageEvent(jsg::Lock& js, const jsg::JsValue& data) - : Event("message"), data(jsg::JsRef(js, data)) {} + : Event("message"), + data(jsg::JsRef(js, data)) {} MessageEvent(jsg::Lock& js, jsg::JsRef data) - : Event("message"), data(kj::mv(data)) {} + : Event("message"), + data(kj::mv(data)) {} MessageEvent(jsg::Lock& js, kj::String type, const jsg::JsValue& data) - : Event(kj::mv(type)), data(jsg::JsRef(js, kj::mv(data))) {} + : Event(kj::mv(type)), + data(jsg::JsRef(js, kj::mv(data))) {} MessageEvent(jsg::Lock& js, kj::String type, jsg::JsRef data) - : Event(kj::mv(type)), data(kj::mv(data)) {} + : Event(kj::mv(type)), + data(kj::mv(data)) {} struct Initializer { jsg::JsRef data; @@ -38,18 +43,27 @@ class MessageEvent: public Event { data: ArrayBuffer | string; }); }; - static jsg::Ref constructor(jsg::Lock& js, - kj::String type, - Initializer initializer) { + static jsg::Ref constructor( + jsg::Lock& js, kj::String type, Initializer initializer) { return jsg::alloc(js, kj::mv(type), kj::mv(initializer.data)); } - jsg::JsValue getData(jsg::Lock& js) { return data.getHandle(js); } + jsg::JsValue getData(jsg::Lock& js) { + return data.getHandle(js); + } - jsg::Unimplemented getOrigin() { return jsg::Unimplemented(); } - jsg::Unimplemented getLastEventId() { return jsg::Unimplemented(); } - jsg::Unimplemented getSource() { return jsg::Unimplemented(); } - jsg::Unimplemented getPorts() { return jsg::Unimplemented(); } + jsg::Unimplemented getOrigin() { + return jsg::Unimplemented(); + } + jsg::Unimplemented getLastEventId() { + return jsg::Unimplemented(); + } + jsg::Unimplemented getSource() { + return jsg::Unimplemented(); + } + jsg::Unimplemented getPorts() { + return jsg::Unimplemented(); + } JSG_RESOURCE_TYPE(MessageEvent) { JSG_INHERIT(Event); @@ -83,9 +97,15 @@ class MessageEvent: public Event { class CloseEvent: public Event { public: CloseEvent(uint code, kj::String reason, bool clean) - : Event("close"), code(code), reason(kj::mv(reason)), clean(clean) {} + : Event("close"), + code(code), + reason(kj::mv(reason)), + clean(clean) {} CloseEvent(kj::String type, int code, kj::String reason, bool clean) - : Event(kj::mv(type)), code(code), reason(kj::mv(reason)), clean(clean) {} + : Event(kj::mv(type)), + code(code), + reason(kj::mv(reason)), + clean(clean) {} struct Initializer { jsg::Optional code; @@ -95,18 +115,21 @@ class CloseEvent: public Event { JSG_STRUCT(code, reason, wasClean); JSG_STRUCT_TS_OVERRIDE(CloseEventInit); }; - static jsg::Ref constructor(kj::String type, - jsg::Optional initializer) { + static jsg::Ref constructor(kj::String type, jsg::Optional initializer) { Initializer init = kj::mv(initializer).orDefault({}); - return jsg::alloc(kj::mv(type), - init.code.orDefault(0), - kj::mv(init.reason).orDefault(nullptr), - init.wasClean.orDefault(false)); + return jsg::alloc(kj::mv(type), init.code.orDefault(0), + kj::mv(init.reason).orDefault(nullptr), init.wasClean.orDefault(false)); } - int getCode() { return code; } - kj::StringPtr getReason() { return reason; } - bool getWasClean() { return clean; } + int getCode() { + return code; + } + kj::StringPtr getReason() { + return reason; + } + bool getWasClean() { + return clean; + } JSG_RESOURCE_TYPE(CloseEvent) { JSG_INHERIT(Event); @@ -147,14 +170,19 @@ class WebSocketPair: public jsg::Object { tracker.trackField("pair", pair); } }; + public: WebSocketPair(jsg::Ref first, jsg::Ref second) - : sockets { kj::mv(first), kj::mv(second) } {} + : sockets{kj::mv(first), kj::mv(second)} {} static jsg::Ref constructor(); - jsg::Ref getFirst() { return sockets[0].addRef(); } - jsg::Ref getSecond() { return sockets[1].addRef(); } + jsg::Ref getFirst() { + return sockets[0].addRef(); + } + jsg::Ref getSecond() { + return sockets[1].addRef(); + } JSG_ITERATOR(PairIterator, entries, jsg::Ref, IteratorState, iteratorNext); @@ -213,6 +241,7 @@ class WebSocket: public EventTarget { // Forward declarations. struct PackedWebSocket; struct Native; + public: // WebSocket ready states. static constexpr int READY_STATE_CONNECTING = 0; @@ -221,8 +250,7 @@ class WebSocket: public EventTarget { static constexpr int READY_STATE_CLOSED = 3; // Creates the Native object when we recreate the WebSocket when waking from hibernation. - IoOwn initNative( - IoContext& ioContext, + IoOwn initNative(IoContext& ioContext, kj::WebSocket& ws, kj::Array tags, bool closedOutgoingConn); @@ -257,9 +285,7 @@ class WebSocket: public EventTarget { // Similar to how the JS `constructor()` creates a WebSocket, when waking from hibernation // we want to be able to recreate WebSockets from C++ that will be delivered to JS code. static jsg::Ref hibernatableFromNative( - jsg::Lock& js, - kj::WebSocket& ws, - HibernationPackage package); + jsg::Lock& js, kj::WebSocket& ws, HibernationPackage package); // The JS WebSocket constructor needs to initiate a connection, but we need to return the // WebSocket object to the caller in Javascript immediately. We will defer the connection logic @@ -326,7 +352,8 @@ class WebSocket: public EventTarget { // JS API. // Creates a new outbound WebSocket. - static jsg::Ref constructor(jsg::Lock& js, kj::String url, + static jsg::Ref constructor(jsg::Lock& js, + kj::String url, jsg::Optional, kj::String>> protocols); // Begin delivering events locally. @@ -604,7 +631,7 @@ class WebSocket: public EventTarget { JSG_MEMORY_INFO(AutoResponse) { tracker.trackFieldWithSize("ongoingAutoResponse", sizeof(kj::Promise)); - for (const auto& message : pendingAutoResponseDeque) { + for (const auto& message: pendingAutoResponseDeque) { tracker.trackField(nullptr, message); } } @@ -647,11 +674,15 @@ class WebSocket: public EventTarget { // object's members in a thread-unsafe way. `outgoingMessages` and `ws` are both `IoOwn`ed // objects so are safe to access from the thread without the isolate lock. The whole task is // owned by the `IoContext` so it'll be canceled if the `IoContext` is destroyed. - static kj::Promise pump( - IoContext& context, OutgoingMessagesMap& outgoingMessages, kj::WebSocket& ws, Native& native, - AutoResponse& autoResponse, kj::Maybe>& observer); + static kj::Promise pump(IoContext& context, + OutgoingMessagesMap& outgoingMessages, + kj::WebSocket& ws, + Native& native, + AutoResponse& autoResponse, + kj::Maybe>& observer); - kj::Promise> readLoop(kj::Maybe> cs, size_t maxMessageSize); + kj::Promise> readLoop( + kj::Maybe> cs, size_t maxMessageSize); void reportError(jsg::Lock& js, kj::Exception&& e); void reportError(jsg::Lock& js, jsg::JsRef err); @@ -659,15 +690,11 @@ class WebSocket: public EventTarget { void assertNoError(jsg::Lock& js); }; -#define EW_WEBSOCKET_ISOLATE_TYPES \ - api::CloseEvent, \ - api::CloseEvent::Initializer, \ - api::MessageEvent, \ - api::MessageEvent::Initializer, \ - api::WebSocket, \ - api::WebSocketPair, \ - api::WebSocketPair::PairIterator, \ - api::WebSocketPair::PairIterator::Next \ -// The list of websocket.h types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE +#define EW_WEBSOCKET_ISOLATE_TYPES \ + api::CloseEvent, api::CloseEvent::Initializer, api::MessageEvent, \ + api::MessageEvent::Initializer, api::WebSocket, api::WebSocketPair, \ + api::WebSocketPair::PairIterator, \ + api::WebSocketPair::PairIterator:: \ + Next // The list of websocket.h types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE } // namespace workerd::api diff --git a/src/workerd/api/worker-rpc.c++ b/src/workerd/api/worker-rpc.c++ index 16f83736641..69e9163a6e4 100644 --- a/src/workerd/api/worker-rpc.c++ +++ b/src/workerd/api/worker-rpc.c++ @@ -62,10 +62,10 @@ public: if (table[i] == nullptr) { auto paf = kj::newPromiseAndFulfiller(); table[i] = kj::mv(paf.fulfiller); - context.getResults(capnp::MessageSize {4, 1}).setStream(kj::mv(paf.promise)); + context.getResults(capnp::MessageSize{4, 1}).setStream(kj::mv(paf.promise)); } else KJ_SWITCH_ONEOF(table[i]) { KJ_CASE_ONEOF(stream, capnp::Capability::Client) { - context.getResults(capnp::MessageSize {4, 1}).setStream(kj::mv(stream)); + context.getResults(capnp::MessageSize{4, 1}).setStream(kj::mv(stream)); table[i] = Consumed(); } KJ_CASE_ONEOF(fulfiller, StreamFulfiller) { @@ -106,7 +106,7 @@ capnp::Capability::Client RpcSerializerExternalHander::writeStream(BuilderCallba } auto result = ({ - auto req = streamSinkPtr->startStreamRequest(capnp::MessageSize {4, 0}); + auto req = streamSinkPtr->startStreamRequest(capnp::MessageSize{4, 0}); req.setExternalIndex(externals.size()); req.send().getStream(); }); @@ -116,8 +116,8 @@ capnp::Capability::Client RpcSerializerExternalHander::writeStream(BuilderCallba return result; } -capnp::Orphan> - RpcSerializerExternalHander::build(capnp::Orphanage orphanage) { +capnp::Orphan> RpcSerializerExternalHander::build( + capnp::Orphanage orphanage) { auto result = orphanage.newOrphan>(externals.size()); auto builder = result.get(); for (auto i: kj::indices(externals)) { @@ -155,23 +155,27 @@ namespace { // `makeBuilder` is a function which takes a capnp::MessageSize hint and returns the // rpc::JsValue::Builder to fill in. template -void serializeJsValue(jsg::Lock& js, jsg::JsValue value, Func makeBuilder, +void serializeJsValue(jsg::Lock& js, + jsg::JsValue value, + Func makeBuilder, RpcSerializerExternalHander::GetStreamSinkFunc getStreamSinkFunc) { RpcSerializerExternalHander externalHandler(kj::mv(getStreamSinkFunc)); - jsg::Serializer serializer(js, jsg::Serializer::Options { - .version = 15, - .omitHeader = false, - .treatClassInstancesAsPlainObjects = false, - .externalHandler = externalHandler, - }); + jsg::Serializer serializer(js, + jsg::Serializer::Options{ + .version = 15, + .omitHeader = false, + .treatClassInstancesAsPlainObjects = false, + .externalHandler = externalHandler, + }); serializer.write(js, value); kj::Array data = serializer.release().data; JSG_ASSERT(data.size() <= MAX_JS_RPC_MESSAGE_SIZE, Error, "Serialized RPC arguments or return values are limited to 1MiB, but the size of this value " - "was: ", data.size(), " bytes."); + "was: ", + data.size(), " bytes."); - capnp::MessageSize hint {0, 0}; + capnp::MessageSize hint{0, 0}; hint.wordCount += (data.size() + sizeof(capnp::word) - 1) / sizeof(capnp::word); hint.wordCount += capnp::sizeInWords(); hint.wordCount += externalHandler.size() * capnp::sizeInWords(); @@ -185,8 +189,8 @@ void serializeJsValue(jsg::Lock& js, jsg::JsValue value, Func makeBuilder, builder.setV8Serialized(data); if (externalHandler.size() > 0) { - builder.adoptExternals(externalHandler.build( - capnp::Orphanage::getForMessageContaining(builder))); + builder.adoptExternals( + externalHandler.build(capnp::Orphanage::getForMessageContaining(builder))); } } @@ -197,18 +201,18 @@ struct DeserializeResult { }; // Call to construct a JS value from an `rpc::JsValue`. -DeserializeResult deserializeJsValue(jsg::Lock& js, rpc::JsValue::Reader reader, - kj::Maybe streamSink = kj::none) { +DeserializeResult deserializeJsValue( + jsg::Lock& js, rpc::JsValue::Reader reader, kj::Maybe streamSink = kj::none) { auto disposalGroup = kj::heap(); RpcDeserializerExternalHander externalHandler(reader.getExternals(), *disposalGroup, streamSink); jsg::Deserializer deserializer(js, reader.getV8Serialized(), kj::none, kj::none, - jsg::Deserializer::Options { - .version = 15, - .readHeader = true, - .externalHandler = externalHandler, - }); + jsg::Deserializer::Options{ + .version = 15, + .readHeader = true, + .externalHandler = externalHandler, + }); return { .value = deserializer.readValue(js), @@ -219,14 +223,13 @@ DeserializeResult deserializeJsValue(jsg::Lock& js, rpc::JsValue::Reader reader, // Does deserializeJsValue() and then adds a `dispose()` method to the returned object (if it is // an object) which disposes all stubs therein. -jsg::JsValue deserializeRpcReturnValue(jsg::Lock& js, - rpc::JsRpcTarget::CallResults::Reader callResults, - StreamSinkImpl& streamSink) { - auto [ value, disposalGroup, _ ] = deserializeJsValue(js, callResults.getResult(), streamSink); +jsg::JsValue deserializeRpcReturnValue( + jsg::Lock& js, rpc::JsRpcTarget::CallResults::Reader callResults, StreamSinkImpl& streamSink) { + auto [value, disposalGroup, _] = deserializeJsValue(js, callResults.getResult(), streamSink); if (callResults.hasCallPipeline()) { - disposalGroup->setCallPipeline(IoContext::current().addObject( - kj::heap(callResults.getCallPipeline()))); + disposalGroup->setCallPipeline( + IoContext::current().addObject(kj::heap(callResults.getCallPipeline()))); } KJ_IF_SOME(obj, value.tryCast()) { @@ -236,10 +239,8 @@ jsg::JsValue deserializeRpcReturnValue(jsg::Lock& js, } else { // Add a dispose method to the return object that disposes the DisposalGroup. v8::Local func = js.wrapSimpleFunction(js.v8Context(), - [disposalGroup = kj::mv(disposalGroup)] - (jsg::Lock&, const v8::FunctionCallbackInfo&) mutable { - disposalGroup->disposeAll(); - }); + [disposalGroup = kj::mv(disposalGroup)](jsg::Lock&, + const v8::FunctionCallbackInfo&) mutable { disposalGroup->disposeAll(); }); obj.set(js, js.symbolDispose(), jsg::JsValue(func)); } } else { @@ -285,8 +286,7 @@ private: // TODO(cleanup): This is generally useful, should it be part of capnp? class RevokerMembrane final: public capnp::MembranePolicy, public kj::Refcounted { public: - explicit RevokerMembrane(kj::Promise promise) - : promise(promise.fork()) {} + explicit RevokerMembrane(kj::Promise promise): promise(promise.fork()) {} kj::Maybe inboundCall( uint64_t interfaceId, uint16_t methodId, capnp::Capability::Client target) override { @@ -323,11 +323,14 @@ void tryCallDisposeMethod(jsg::Lock& js, jsg::JsValue value) { }); } -} // namespace +} // namespace -JsRpcPromise::JsRpcPromise(jsg::JsRef inner, kj::Own weakRefParam, - IoOwn pipeline) - : inner(kj::mv(inner)), weakRef(kj::mv(weakRefParam)), state(Pending { kj::mv(pipeline) }) { +JsRpcPromise::JsRpcPromise(jsg::JsRef inner, + kj::Own weakRefParam, + IoOwn pipeline) + : inner(kj::mv(inner)), + weakRef(kj::mv(weakRefParam)), + state(Pending{kj::mv(pipeline)}) { KJ_REQUIRE(weakRef->ref == kj::none); weakRef->ref = *this; } @@ -337,7 +340,7 @@ JsRpcPromise::~JsRpcPromise() noexcept(false) { void JsRpcPromise::resolve(jsg::Lock& js, jsg::JsValue result) { if (state.is()) { - state = Resolved { + state = Resolved{ .result = jsg::Value(js.v8Isolate, result), .ctxCheck = IoContext::current().addObject(*this), }; @@ -430,15 +433,13 @@ struct JsRpcPromiseAndPipleine { rpc::JsRpcTarget::CallResults::Pipeline pipeline; jsg::Ref asJsRpcPromise(jsg::Lock& js) && { - return jsg::alloc( - jsg::JsRef(js, promise), kj::mv(weakRef), + return jsg::alloc(jsg::JsRef(js, promise), kj::mv(weakRef), IoContext::current().addObject(kj::heap(kj::mv(pipeline)))); } }; // Core implementation of making an RPC call, reusable for many cases below. -JsRpcPromiseAndPipleine callImpl( - jsg::Lock& js, +JsRpcPromiseAndPipleine callImpl(jsg::Lock& js, JsRpcClientProvider& parent, kj::Maybe name, // If `maybeArgs` is provided, this is a call, otherwise it is a property access. @@ -548,9 +549,9 @@ JsRpcPromiseAndPipleine callImpl( // RemotePromise lets us consume its pipeline and promise portions independently; we consume // the promise here and we consume the pipeline below, both via kj::mv(). auto jsPromise = ioContext.awaitIo(js, kj::mv(callResult), - [weakRef = kj::atomicAddRef(*weakRef), resultStreamSink = kj::mv(resultStreamSink)] - (jsg::Lock& js, capnp::Response response) mutable - -> jsg::Value { + [weakRef = kj::atomicAddRef(*weakRef), resultStreamSink = kj::mv(resultStreamSink)]( + jsg::Lock& js, + capnp::Response response) mutable -> jsg::Value { auto jsResult = deserializeRpcReturnValue(js, response, *resultStreamSink); if (weakRef->disposed) { @@ -576,12 +577,10 @@ JsRpcPromiseAndPipleine callImpl( // synchronously from async functions. auto jsError = jsg::JsValue(error.getHandle(js)); auto pipeline = capnp::newBrokenPipeline(js.exceptionToKj(jsError)); - return { - .promise = js.rejectedJsPromise(jsError), + return {.promise = js.rejectedJsPromise(jsError), .weakRef = kj::atomicRefcounted(), - .pipeline = rpc::JsRpcTarget::CallResults::Pipeline( - capnp::AnyPointer::Pipeline(kj::mv(pipeline))) - }; + .pipeline = + rpc::JsRpcTarget::CallResults::Pipeline(capnp::AnyPointer::Pipeline(kj::mv(pipeline)))}; }); } catch (jsg::JsExceptionThrown&) { // This must be a termination exception, or we would have caught it above. @@ -594,9 +593,8 @@ JsRpcPromiseAndPipleine callImpl( return { .promise = jsg::JsPromise(js.wrapSimplePromise(js.rejectedPromise(kj::mv(e)))), .weakRef = kj::atomicRefcounted(), - .pipeline = rpc::JsRpcTarget::CallResults::Pipeline( - capnp::AnyPointer::Pipeline(kj::mv(pipeline))) - }; + .pipeline = + rpc::JsRpcTarget::CallResults::Pipeline(capnp::AnyPointer::Pipeline(kj::mv(pipeline)))}; } } @@ -622,8 +620,10 @@ jsg::Ref JsRpcPromise::call(const v8::FunctionCallbackInfo promise, - v8::Local handler, jsg::Optional> errorHandler) { +jsg::JsValue thenImpl(jsg::Lock& js, + v8::Local promise, + v8::Local handler, + jsg::Optional> errorHandler) { KJ_IF_SOME(e, errorHandler) { // Note that we intentionally propagate any exception from promise->Then() sychronously since // if V8's native Promise threw synchronously from `then()`, we might as well too. Anyway it's @@ -634,26 +634,27 @@ jsg::JsValue thenImpl(jsg::Lock& js, v8::Local promise, } } -jsg::JsValue catchImpl(jsg::Lock& js, v8::Local promise, - v8::Local errorHandler) { +jsg::JsValue catchImpl( + jsg::Lock& js, v8::Local promise, v8::Local errorHandler) { return jsg::JsPromise(jsg::check(promise->Catch(js.v8Context(), errorHandler))); } -jsg::JsValue finallyImpl(jsg::Lock& js, v8::Local promise, - v8::Local onFinally) { +jsg::JsValue finallyImpl( + jsg::Lock& js, v8::Local promise, v8::Local onFinally) { // HACK: `finally()` is not exposed as a C++ API, so we have to manually read it from JS. jsg::JsObject obj(promise); auto func = obj.get(js, "finally"); KJ_ASSERT(func.isFunction()); v8::Local param = onFinally; - return jsg::JsValue(jsg::check(v8::Local(func).As() - ->Call(js.v8Context(), obj, 1, ¶m))); + return jsg::JsValue(jsg::check( + v8::Local(func).As()->Call(js.v8Context(), obj, 1, ¶m))); } } // namespace -jsg::JsValue JsRpcProperty::then(jsg::Lock& js, v8::Local handler, - jsg::Optional> errorHandler) { +jsg::JsValue JsRpcProperty::then(jsg::Lock& js, + v8::Local handler, + jsg::Optional> errorHandler) { auto promise = callImpl(js, *parent, name, kj::none).promise; return thenImpl(js, promise, handler, errorHandler); @@ -671,8 +672,9 @@ jsg::JsValue JsRpcProperty::finally(jsg::Lock& js, v8::Local onFin return finallyImpl(js, promise, onFinally); } -jsg::JsValue JsRpcPromise::then(jsg::Lock& js, v8::Local handler, - jsg::Optional> errorHandler) { +jsg::JsValue JsRpcPromise::then(jsg::Lock& js, + v8::Local handler, + jsg::Optional> errorHandler) { return thenImpl(js, inner.getHandle(js), handler, errorHandler); } @@ -818,8 +820,7 @@ void RpcStubDisposalGroup::disposeAll() { KJ_ASSERT(list.empty()); } -kj::Maybe> JsRpcStub::getRpcMethod( - jsg::Lock& js, kj::String name) { +kj::Maybe> JsRpcStub::getRpcMethod(jsg::Lock& js, kj::String name) { // Do not return a method for `then`, otherwise JavaScript decides this is a thenable, i.e. a // custom Promise, which will mean a Promise that resolves to this object will attempt to chain // with it, which is not what you want! @@ -846,8 +847,8 @@ void JsRpcStub::serialize(jsg::Lock& js, jsg::Serializer& serializer) { jsg::Ref JsRpcStub::deserialize( jsg::Lock& js, rpc::SerializationTag tag, jsg::Deserializer& deserializer) { - auto& handler = KJ_REQUIRE_NONNULL(deserializer.getExternalHandler(), - "got JsRpcStub on non-RPC serialized object?"); + auto& handler = KJ_REQUIRE_NONNULL( + deserializer.getExternalHandler(), "got JsRpcStub on non-RPC serialized object?"); auto externalHandler = dynamic_cast(&handler); KJ_REQUIRE(externalHandler != nullptr, "got JsRpcStub on non-RPC serialized object?"); @@ -855,8 +856,8 @@ jsg::Ref JsRpcStub::deserialize( KJ_REQUIRE(reader.isRpcTarget(), "external table slot type doesn't match serialization tag"); auto& ioctx = IoContext::current(); - return jsg::alloc(ioctx.addObject(kj::heap(reader.getRpcTarget())), - externalHandler->getDisposalGroup()); + return jsg::alloc( + ioctx.addObject(kj::heap(reader.getRpcTarget())), externalHandler->getDisposalGroup()); } static bool isFunctionForRpc(jsg::Lock& js, v8::Local func) { @@ -884,24 +885,24 @@ static inline bool isFunctionForRpc(jsg::Lock& js, jsg::JsObject val) { // `makeCallPipeline()` has a bit of a complicated result type.. namespace MakeCallPipeline { - // The value is an object, which may have stubs inside it. - struct Object { - rpc::JsRpcTarget::Client cap; +// The value is an object, which may have stubs inside it. +struct Object { + rpc::JsRpcTarget::Client cap; - // Was the value a plain JavaScript object which had a custom dispose() method? - bool hasDispose; - }; + // Was the value a plain JavaScript object which had a custom dispose() method? + bool hasDispose; +}; - // The value was something that should serialize to a single stub (e.g. it was an RpcTarget, a - // plain function, or already a stub). The callPipeline should simply be a copy of that stub. - struct SingleStub {}; +// The value was something that should serialize to a single stub (e.g. it was an RpcTarget, a +// plain function, or already a stub). The callPipeline should simply be a copy of that stub. +struct SingleStub {}; - // The value is not a type that supports pipelining. It may still be serializable, and it could - // even contain stubs (e.g. in a Map). - struct NonPipelinable {}; +// The value is not a type that supports pipelining. It may still be serializable, and it could +// even contain stubs (e.g. in a Map). +struct NonPipelinable {}; - using Result = kj::OneOf; -}; +using Result = kj::OneOf; +}; // namespace MakeCallPipeline // Create the callPipeline for a call result. // @@ -915,8 +916,7 @@ static MakeCallPipeline::Result makeCallPipeline(jsg::Lock& js, jsg::JsValue val // session. class JsRpcTargetBase: public rpc::JsRpcTarget::Server { public: - JsRpcTargetBase(IoContext& ctx) - : weakIoContext(ctx.getWeakRef()) {} + JsRpcTargetBase(IoContext& ctx): weakIoContext(ctx.getWeakRef()) {} struct EnvCtx { v8::Local env; @@ -940,8 +940,8 @@ public: // Handles the delivery of JS RPC method calls. kj::Promise call(CallContext callContext) override { - IoContext& ctx = JSG_REQUIRE_NONNULL(weakIoContext->tryGet(), Error, - "The destination object for this RPC no longer exists."); + IoContext& ctx = JSG_REQUIRE_NONNULL( + weakIoContext->tryGet(), Error, "The destination object for this RPC no longer exists."); // HACK: Cap'n Proto call contexts are documented as being pointer-like types where the backing // object's lifetime is that of the RPC call, but in reality they are refcounted under the @@ -954,10 +954,9 @@ public: auto ownCallContext = capnp::CallContextHook::from(callContext).addRef(); // Try to execute the requested method. - auto promise = ctx.run( - [this, &ctx, callContext, ownCallContext = kj::mv(ownCallContext), ownThis = thisCap()] - (Worker::Lock& lock) mutable -> kj::Promise { - + auto promise = + ctx.run([this, &ctx, callContext, ownCallContext = kj::mv(ownCallContext), + ownThis = thisCap()](Worker::Lock& lock) mutable -> kj::Promise { jsg::Lock& js = lock; auto targetInfo = getTargetInfo(lock, ctx); @@ -965,8 +964,8 @@ public: auto params = callContext.getParams(); // We will try to get the function, if we can't we'll throw an error to the client. - auto [propHandle, thisArg, methodNameForTrace] = tryGetProperty( - lock, targetInfo.target, params, targetInfo.allowInstanceProperties); + auto [propHandle, thisArg, methodNameForTrace] = + tryGetProperty(lock, targetInfo.target, params, targetInfo.allowInstanceProperties); addTrace(js, ctx, methodNameForTrace); @@ -997,14 +996,16 @@ public: callContext.setPipeline(builder.build()); } - auto result = ctx.awaitJs(js, js.toPromise(invocationResult.returnValue) - .then(js, ctx.addFunctor( - [callContext, ownCallContext = kj::mv(ownCallContext), - paramDisposalGroup = kj::mv(invocationResult.paramDisposalGroup), - paramsStreamSink = kj::mv(invocationResult.streamSink), - resultStreamSink = params.getResultsStreamSink(), - callPipelineFulfiller = kj::mv(callPipelineFulfiller)] - (jsg::Lock& js, jsg::Value value) mutable { + auto result = ctx.awaitJs(js, + js.toPromise(invocationResult.returnValue) + .then(js, + ctx.addFunctor( + [callContext, ownCallContext = kj::mv(ownCallContext), + paramDisposalGroup = kj::mv(invocationResult.paramDisposalGroup), + paramsStreamSink = kj::mv(invocationResult.streamSink), + resultStreamSink = params.getResultsStreamSink(), + callPipelineFulfiller = kj::mv(callPipelineFulfiller)]( + jsg::Lock& js, jsg::Value value) mutable { jsg::JsValue resultValue(value.getHandle(js)); // Call makeCallPipeline before serializing becaues it may need to extract the disposer. @@ -1051,7 +1052,8 @@ public: // paramDisposalGroup will be destroyed when we return (or when this lambda is destroyed // as a result of the promise being rejected). This will implicitly dispose the param // stubs. - }), ctx.addFunctor([callPipelineFulfillerRef](jsg::Lock& js, jsg::Value&& error) { + }), + ctx.addFunctor([callPipelineFulfillerRef](jsg::Lock& js, jsg::Value&& error) { // If we set up a `callPipeline` early, we have to make sure it propagates the error. // (Otherwise we get a PromiseFulfiller error instead, which is pretty useless...) KJ_IF_SOME(cpf, callPipelineFulfillerRef) { @@ -1082,8 +1084,8 @@ public: InvocationResult invocationResult; KJ_IF_SOME(envCtx, targetInfo.envCtx) { - invocationResult = invokeFnInsertingEnvCtx(js, methodNameForTrace, fn, thisArg, - args, envCtx.env, envCtx.ctx); + invocationResult = invokeFnInsertingEnvCtx( + js, methodNameForTrace, fn, thisArg, args, envCtx.env, envCtx.ctx); } else { invocationResult = invokeFn(js, fn, thisArg, args); } @@ -1116,11 +1118,8 @@ public: // we add the promise as a task on the context itself, and use a separate promise fulfiller to // wait on the result. auto paf = kj::newPromiseAndFulfiller(); - promise = promise.then([&fulfiller=*paf.fulfiller]() { - fulfiller.fulfill(); - }, [&fulfiller=*paf.fulfiller](kj::Exception&& e) { - fulfiller.reject(kj::mv(e)); - }); + promise = promise.then([&fulfiller = *paf.fulfiller]() { fulfiller.fulfill(); }, + [&fulfiller = *paf.fulfiller](kj::Exception&& e) { fulfiller.reject(kj::mv(e)); }); promise = promise.attach(kj::defer([fulfiller = kj::mv(paf.fulfiller)]() mutable { if (fulfiller->isWaiting()) { fulfiller->reject(JSG_KJ_EXCEPTION(FAILED, Error, @@ -1155,12 +1154,11 @@ private: }; [[noreturn]] static void failLookup(kj::StringPtr kjName) { - JSG_FAIL_REQUIRE(TypeError, - kj::str("The RPC receiver does not implement the method \"", kjName, "\".")); + JSG_FAIL_REQUIRE( + TypeError, kj::str("The RPC receiver does not implement the method \"", kjName, "\".")); } - GetPropResult tryGetProperty( - jsg::Lock& js, + GetPropResult tryGetProperty(jsg::Lock& js, jsg::JsObject object, rpc::JsRpcTarget::CallParams::Reader callParams, bool allowInstanceProperties) { @@ -1245,7 +1243,7 @@ private: } } - result = getProperty(path[n-1]); + result = getProperty(path[n - 1]); methodNameForTrace = kj::ConstString(kj::strArray(path, ".")); } @@ -1267,8 +1265,7 @@ private: }; // Deserializes the arguments and passes them to the given function. - static InvocationResult invokeFn( - jsg::Lock& js, + static InvocationResult invokeFn(jsg::Lock& js, v8::Local fn, v8::Local thisArg, kj::Maybe args) { @@ -1276,17 +1273,16 @@ private: KJ_IF_SOME(a, args) { auto [value, disposalGroup, streamSink] = deserializeJsValue(js, a); auto args = KJ_REQUIRE_NONNULL( - value.tryCast(), - "expected JsArray when deserializing arguments."); + value.tryCast(), "expected JsArray when deserializing arguments."); // Call() expects a `Local []`... so we populate an array. KJ_STACK_ARRAY(v8::Local, arguments, args.size(), 8, 8); for (size_t i = 0; i < args.size(); ++i) { arguments[i] = args.get(js, i); } - InvocationResult result { - .returnValue = jsg::check(fn->Call( - js.v8Context(), thisArg, args.size(), arguments.begin())), + InvocationResult result{ + .returnValue = + jsg::check(fn->Call(js.v8Context(), thisArg, args.size(), arguments.begin())), .streamSink = kj::mv(streamSink), }; if (!disposalGroup->empty()) { @@ -1294,16 +1290,13 @@ private: } return result; } else { - return { - .returnValue = jsg::check(fn->Call(js.v8Context(), thisArg, 0, nullptr)) - }; + return {.returnValue = jsg::check(fn->Call(js.v8Context(), thisArg, 0, nullptr))}; } }; // Like `invokeFn`, but inject the `env` and `ctx` values between the first and second // parameters. Used for service bindings that use functional syntax. - static InvocationResult invokeFnInsertingEnvCtx( - jsg::Lock& js, + static InvocationResult invokeFnInsertingEnvCtx(jsg::Lock& js, kj::StringPtr methodName, v8::Local fn, v8::Local thisArg, @@ -1341,8 +1334,7 @@ private: streamSink = kj::mv(ss); auto array = KJ_REQUIRE_NONNULL( - value.tryCast(), - "expected JsArray when deserializing arguments."); + value.tryCast(), "expected JsArray when deserializing arguments."); argCountFromClient = array.size(); argsArrayFromClient = kj::mv(array); @@ -1356,14 +1348,14 @@ private: // will be replaced with `env` and `ctx`. Probably this would be quickly noticed in testing, // but if you were to accidentally reflect `env` back to the client, it would be a severe // security flaw. - JSG_REQUIRE(arity == 3, TypeError, - "Cannot call handler function \"", methodName, "\" over RPC because it has the wrong " + JSG_REQUIRE(arity == 3, TypeError, "Cannot call handler function \"", methodName, + "\" over RPC because it has the wrong " "number of arguments. A simple function handler can only be called over RPC if it has " "exactly the arguments (arg, env, ctx), where only the first argument comes from the " "client. To support multi-argument RPC functions, use class-based syntax (extending " "WorkerEntrypoint) instead."); - JSG_REQUIRE(argCountFromClient == 1, TypeError, - "Attempted to call RPC function \"", methodName, "\" with the wrong number of arguments. " + JSG_REQUIRE(argCountFromClient == 1, TypeError, "Attempted to call RPC function \"", methodName, + "\" with the wrong number of arguments. " "When calling a top-level handler function that is not declared as part of a class, you " "must always send exactly one argument. In order to support variable numbers of " "arguments, the server must use class-based syntax (extending WorkerEntrypoint) " @@ -1389,8 +1381,8 @@ private: } return { - .returnValue = jsg::check(fn->Call( - js.v8Context(), thisArg, arguments.size(), arguments.begin())), + .returnValue = + jsg::check(fn->Call(js.v8Context(), thisArg, arguments.size(), arguments.begin())), .paramDisposalGroup = kj::mv(paramDisposalGroup), .streamSink = kj::mv(streamSink), }; @@ -1399,8 +1391,8 @@ private: class TransientJsRpcTarget final: public JsRpcTargetBase { public: - TransientJsRpcTarget(jsg::Lock& js, IoContext& ioCtx, jsg::JsObject object, - bool allowInstanceProperties = false) + TransientJsRpcTarget( + jsg::Lock& js, IoContext& ioCtx, jsg::JsObject object, bool allowInstanceProperties = false) : JsRpcTargetBase(ioCtx), handles(ioCtx.addObjectReverse(kj::heap(js, object, kj::none))), allowInstanceProperties(allowInstanceProperties), @@ -1414,9 +1406,11 @@ public: } // Use this version of the constructor to pass the dispose function separately. - TransientJsRpcTarget(jsg::Lock& js, IoContext& ioCtx, jsg::JsObject object, - kj::Maybe> dispose, - bool allowInstanceProperties = false) + TransientJsRpcTarget(jsg::Lock& js, + IoContext& ioCtx, + jsg::JsObject object, + kj::Maybe> dispose, + bool allowInstanceProperties = false) : JsRpcTargetBase(ioCtx), handles(ioCtx.addObjectReverse(kj::heap(js, object, dispose))), allowInstanceProperties(allowInstanceProperties), @@ -1430,8 +1424,7 @@ public: ctx.addTask(ctx.run( [dispose = kj::mv(d), object = kj::mv(handles->object)](Worker::Lock& lock) mutable { jsg::Lock& js = lock; - jsg::check(dispose.getHandle(js)->Call( - js.v8Context(), object.getHandle(js), 0, nullptr)); + jsg::check(dispose.getHandle(js)->Call(js.v8Context(), object.getHandle(js), 0, nullptr)); })); } } @@ -1475,7 +1468,7 @@ private: kj::Own pendingEvent; bool isReservedName(kj::StringPtr name) override { - if (// dup() is reserved to duplicate the stub itself, pointing to the same object. + if ( // dup() is reserved to duplicate the stub itself, pointing to the same object. name == "dup" || // All JS classes define a method `constructor` on the prototype, but we don't actually @@ -1496,15 +1489,14 @@ static rpc::JsRpcTarget::Client makeJsRpcTargetForSingleLoopbackCall( jsg::Lock& js, jsg::JsObject obj) { // We intentionally do not want to hook up the disposer here since we're not taking ownership // of the object. - return rpc::JsRpcTarget::Client(kj::heap( - js, IoContext::current(), obj, kj::none, true)); + return rpc::JsRpcTarget::Client( + kj::heap(js, IoContext::current(), obj, kj::none, true)); } static MakeCallPipeline::Result makeCallPipeline(jsg::Lock& js, jsg::JsValue value) { return js.withinHandleScope([&]() -> MakeCallPipeline::Result { - jsg::JsObject obj = KJ_UNWRAP_OR(value.tryCast(), { - return MakeCallPipeline::NonPipelinable(); - }); + jsg::JsObject obj = KJ_UNWRAP_OR( + value.tryCast(), { return MakeCallPipeline::NonPipelinable(); }); if (obj.getPrototype(js) == js.obj().getPrototype(js)) { // It's a plain object. @@ -1518,11 +1510,10 @@ static MakeCallPipeline::Result makeCallPipeline(jsg::Lock& js, jsg::JsValue val // that a new `dispose()` method will always be added on the client side). obj.delete_(js, js.symbolDispose()); - return MakeCallPipeline::Object { - .cap = rpc::JsRpcTarget::Client(kj::heap( - js, IoContext::current(), obj, maybeDispose, true)), - .hasDispose = maybeDispose != kj::none - }; + return MakeCallPipeline::Object{ + .cap = rpc::JsRpcTarget::Client( + kj::heap(js, IoContext::current(), obj, maybeDispose, true)), + .hasDispose = maybeDispose != kj::none}; } else if (obj.isInstanceOf(js)) { // It's just a stub. It'll serialize as a single stub, obviously. return MakeCallPipeline::SingleStub(); @@ -1580,8 +1571,8 @@ void RpcSerializerExternalHander::serializeFunction( jsg::Lock& js, jsg::Serializer& serializer, v8::Local func) { serializer.writeRawUint32(static_cast(rpc::SerializationTag::JS_RPC_STUB)); - rpc::JsRpcTarget::Client cap = kj::heap( - js, IoContext::current(), jsg::JsObject(func), true); + rpc::JsRpcTarget::Client cap = + kj::heap(js, IoContext::current(), jsg::JsObject(func), true); write([cap = kj::mv(cap)](rpc::JsValue::External::Builder builder) mutable { builder.setRpcTarget(kj::mv(cap)); }); @@ -1591,8 +1582,9 @@ void RpcSerializerExternalHander::serializeFunction( // call of an RPC session. class EntrypointJsRpcTarget final: public JsRpcTargetBase { public: - EntrypointJsRpcTarget(IoContext& ioCtx, kj::Maybe entrypointName, - kj::Maybe> tracer) + EntrypointJsRpcTarget(IoContext& ioCtx, + kj::Maybe entrypointName, + kj::Maybe> tracer) : JsRpcTargetBase(ioCtx), // Most of the time we don't really have to clone this but it's hard to fully prove, so // let's be safe. @@ -1603,7 +1595,7 @@ public: jsg::Lock& js = lock; auto handler = KJ_REQUIRE_NONNULL(lock.getExportedHandler(entrypointName, ioCtx.getActor()), - "Failed to get handler to worker."); + "Failed to get handler to worker."); if (handler->missingSuperclass) { // JS RPC is not enabled on the server side, we cannot call any methods. @@ -1614,16 +1606,13 @@ public: "\"cloudflare:workers\"."); } - TargetInfo targetInfo { - .target = jsg::JsObject(handler->self.getHandle(lock)), + TargetInfo targetInfo{.target = jsg::JsObject(handler->self.getHandle(lock)), .envCtx = handler->ctx.map([&](jsg::Ref& execCtx) -> EnvCtx { - return { - .env = handler->env.getHandle(js), - .ctx = lock.getWorker().getIsolate().getApi() - .wrapExecutionContext(js, execCtx.addRef()), - }; - }) - }; + return { + .env = handler->env.getHandle(js), + .ctx = lock.getWorker().getIsolate().getApi().wrapExecutionContext(js, execCtx.addRef()), + }; + })}; // `targetInfo.envCtx` is present when we're invoking a freestanding function, and therefore // `env` and `ctx` need to be passed as parameters. In that case, we our method lookup @@ -1641,15 +1630,12 @@ private: kj::Maybe> tracer; bool isReservedName(kj::StringPtr name) override { - if (// "fetch" and "connect" are treated specially on entrypoints. - name == "fetch" || - name == "connect" || + if ( // "fetch" and "connect" are treated specially on entrypoints. + name == "fetch" || name == "connect" || // These methods are reserved by the Durable Objects implementation. // TODO(someday): Should they be reserved only for Durable Objects, not WorkerEntrypoint? - name == "alarm" || - name == "webSocketMessage" || - name == "webSocketClose" || + name == "alarm" || name == "webSocketMessage" || name == "webSocketClose" || name == "webSocketError" || // dup() is reserved to duplicate the stub itself, pointing to the same object. @@ -1677,22 +1663,22 @@ private: // completes, since it is actually returned as the result of the top-level RPC call, but that // call doesn't return until the `CompletionMembrane` says all capabilities were dropped, so this // would create a cycle. -class JsRpcSessionCustomEventImpl::ServerTopLevelMembrane final - : public capnp::MembranePolicy, public kj::Refcounted { +class JsRpcSessionCustomEventImpl::ServerTopLevelMembrane final: public capnp::MembranePolicy, + public kj::Refcounted { public: explicit ServerTopLevelMembrane(kj::Own> doneFulfiller) : doneFulfiller(kj::mv(doneFulfiller)) {} ~ServerTopLevelMembrane() noexcept(false) { KJ_IF_SOME(f, doneFulfiller) { - f->reject(KJ_EXCEPTION(DISCONNECTED, - "JS RPC session canceled without calling an RPC method.")); + f->reject( + KJ_EXCEPTION(DISCONNECTED, "JS RPC session canceled without calling an RPC method.")); } } kj::Maybe inboundCall( uint64_t interfaceId, uint16_t methodId, capnp::Capability::Client target) override { - auto f = kj::mv(JSG_REQUIRE_NONNULL(doneFulfiller, - Error, "Only one RPC method call is allowed on this object.")); + auto f = kj::mv(JSG_REQUIRE_NONNULL( + doneFulfiller, Error, "Only one RPC method call is allowed on this object.")); doneFulfiller = kj::none; return capnp::membrane(kj::mv(target), kj::refcounted(kj::mv(f))); } @@ -1719,11 +1705,9 @@ kj::Promise JsRpcSessionCustomEventImpl::r incomingRequest->delivered(); auto [donePromise, doneFulfiller] = kj::newPromiseAndFulfiller(); - capFulfiller->fulfill( - capnp::membrane( - kj::heap(ioctx, entrypointName, - mapAddRef(incomingRequest->getWorkerTracer())), - kj::refcounted(kj::mv(doneFulfiller)))); + capFulfiller->fulfill(capnp::membrane(kj::heap(ioctx, entrypointName, + mapAddRef(incomingRequest->getWorkerTracer())), + kj::refcounted(kj::mv(doneFulfiller)))); KJ_DEFER({ // waitUntil() should allow extending execution on the server side even when the client @@ -1735,13 +1719,10 @@ kj::Promise JsRpcSessionCustomEventImpl::r // and server as part of this session. co_await donePromise.exclusiveJoin(ioctx.onAbort()); - co_return WorkerInterface::CustomEvent::Result { - .outcome = EventOutcome::OK - }; + co_return WorkerInterface::CustomEvent::Result{.outcome = EventOutcome::OK}; } -kj::Promise - JsRpcSessionCustomEventImpl::sendRpc( +kj::Promise JsRpcSessionCustomEventImpl::sendRpc( capnp::HttpOverCapnpFactory& httpOverCapnpFactory, capnp::ByteStreamFactory& byteStreamFactory, kj::TaskSet& waitUntilTasks, @@ -1765,9 +1746,7 @@ kj::Promise rpc::JsRpcTarget::Client cap = sent.getTopLevel(); - cap = capnp::membrane( - kj::mv(cap), - kj::refcounted(kj::mv(revokePaf.promise))); + cap = capnp::membrane(kj::mv(cap), kj::refcounted(kj::mv(revokePaf.promise))); // When no more capabilities exist on the connection, we want to proactively cancel the RPC. // This is needed in particular for the case where the client is dropped without making any calls @@ -1781,8 +1760,7 @@ kj::Promise // less ugly? auto completionPaf = kj::newPromiseAndFulfiller(); cap = capnp::membrane( - kj::mv(cap), - kj::refcounted(kj::mv(completionPaf.fulfiller))); + kj::mv(cap), kj::refcounted(kj::mv(completionPaf.fulfiller))); this->capFulfiller->fulfill(kj::mv(cap)); @@ -1796,16 +1774,15 @@ kj::Promise kj::throwFatalException(kj::mv(e)); } - co_return WorkerInterface::CustomEvent::Result { - .outcome = EventOutcome::OK - }; + co_return WorkerInterface::CustomEvent::Result{.outcome = EventOutcome::OK}; } // ======================================================================================= jsg::Ref WorkerEntrypoint::constructor( const v8::FunctionCallbackInfo& args, - jsg::Ref ctx, jsg::JsObject env) { + jsg::Ref ctx, + jsg::JsObject env) { // HACK: We take `FunctionCallbackInfo` mostly so that we can set properties directly on // `This()`. There ought to be a better way to get access to `this` in a constructor. // We *also* delcare `ctx` and `env` params more explicitly just for the sake of type checking. @@ -1819,7 +1796,8 @@ jsg::Ref WorkerEntrypoint::constructor( jsg::Ref DurableObjectBase::constructor( const v8::FunctionCallbackInfo& args, - jsg::Ref ctx, jsg::JsObject env) { + jsg::Ref ctx, + jsg::JsObject env) { // HACK: We take `FunctionCallbackInfo` mostly so that we can set properties directly on // `This()`. There ought to be a better way to get access to `this` in a constructor. // We *also* delcare `ctx` and `env` params more explicitly just for the sake of type checking. @@ -1831,9 +1809,9 @@ jsg::Ref DurableObjectBase::constructor( return jsg::alloc(); } -jsg::Ref Workflow::constructor( - const v8::FunctionCallbackInfo& args, - jsg::Ref ctx, jsg::JsObject env) { +jsg::Ref Workflow::constructor(const v8::FunctionCallbackInfo& args, + jsg::Ref ctx, + jsg::JsObject env) { // HACK: We take `FunctionCallbackInfo` mostly so that we can set properties directly on // `This()`. There ought to be a better way to get access to `this` in a constructor. // We *also* declare `ctx` and `env` params more explicitly just for the sake of type checking. @@ -1845,4 +1823,4 @@ jsg::Ref Workflow::constructor( return jsg::alloc(); } -}; // namespace workerd::api +}; // namespace workerd::api diff --git a/src/workerd/api/worker-rpc.h b/src/workerd/api/worker-rpc.h index 88c745be1e4..115564b96da 100644 --- a/src/workerd/api/worker-rpc.h +++ b/src/workerd/api/worker-rpc.h @@ -48,7 +48,9 @@ class RpcSerializerExternalHander final: public jsg::Serializer::ExternalHandler // JsValue::External in the Cap'n Proto structure. The external array cannot be allocated until // the number of externals are known, which is only after all calls to `add()` have completed, // hence the need for a callback. - void write(BuilderCallback callback) { externals.add(kj::mv(callback)); } + void write(BuilderCallback callback) { + externals.add(kj::mv(callback)); + } // Like write(), but use this when there is also a stream associated with the external, i.e. // using StreamSink. This returns a capability which will eventually resolve to the stream. @@ -57,7 +59,9 @@ class RpcSerializerExternalHander final: public jsg::Serializer::ExternalHandler // Build the final list. capnp::Orphan> build(capnp::Orphanage orphanage); - size_t size() { return externals.size(); } + size_t size() { + return externals.size(); + } // We serialize functions by turning them into RPC stubs. void serializeFunction( @@ -81,9 +85,11 @@ class RpcDeserializerExternalHander final: public jsg::Deserializer::ExternalHan // The `streamSink` parameter should be provided if a StreamSink already exists, e.g. when // deserializing results. If omitted, it will be constructed on-demand. RpcDeserializerExternalHander(capnp::List::Reader externals, - RpcStubDisposalGroup& disposalGroup, - kj::Maybe streamSink) - : externals(externals), disposalGroup(disposalGroup), streamSink(streamSink) {} + RpcStubDisposalGroup& disposalGroup, + kj::Maybe streamSink) + : externals(externals), + disposalGroup(disposalGroup), + streamSink(streamSink) {} ~RpcDeserializerExternalHander() noexcept(false); // Read and return the next external. @@ -95,12 +101,16 @@ class RpcDeserializerExternalHander final: public jsg::Deserializer::ExternalHan // All stubs deserialized as part of a particular parameter or result set are placed in a // common disposal group so that they can be disposed together. - RpcStubDisposalGroup& getDisposalGroup() { return disposalGroup; } + RpcStubDisposalGroup& getDisposalGroup() { + return disposalGroup; + } // Call after serialization is complete to get the StreamSink that should handle streams found // while deserializing. Returns none if there were no streams. This should only be called if // a `streamSink` was NOT passed to the constructor. - kj::Maybe getStreamSink() { return kj::mv(streamSinkCap); } + kj::Maybe getStreamSink() { + return kj::mv(streamSinkCap); + } private: capnp::List::Reader externals; @@ -117,7 +127,9 @@ class RpcDeserializerExternalHander final: public jsg::Deserializer::ExternalHan // makes RPCs back to the original object. class JsRpcTarget: public jsg::Object { public: - static jsg::Ref constructor() { return jsg::alloc(); } + static jsg::Ref constructor() { + return jsg::alloc(); + } JSG_RESOURCE_TYPE(JsRpcTarget) {} @@ -162,7 +174,8 @@ class JsRpcPromise: public JsRpcClientProvider { bool disposed = false; }; - JsRpcPromise(jsg::JsRef inner, kj::Own weakRef, + JsRpcPromise(jsg::JsRef inner, + kj::Own weakRef, IoOwn pipeline); ~JsRpcPromise() noexcept(false); @@ -184,7 +197,8 @@ class JsRpcPromise: public JsRpcClientProvider { // before the inner promise resolves, becaues it's just a thin wrapper that delegates to the // inner promise. The inner promise will keep running until it completes, and will invoke all // the continuations then. - jsg::JsValue then(jsg::Lock& js, v8::Local handler, + jsg::JsValue then(jsg::Lock& js, + v8::Local handler, jsg::Optional> errorHandler); jsg::JsValue catch_(jsg::Lock& js, v8::Local errorHandler); jsg::JsValue finally(jsg::Lock& js, v8::Local onFinally); @@ -231,11 +245,13 @@ class JsRpcPromise: public JsRpcClientProvider { void visitForGc(jsg::GcVisitor& visitor) { visitor.visit(inner); KJ_SWITCH_ONEOF(state) { - KJ_CASE_ONEOF(pending, Pending) {} + KJ_CASE_ONEOF(pending, Pending) { + } KJ_CASE_ONEOF(resolved, Resolved) { visitor.visit(resolved.result); } - KJ_CASE_ONEOF(disposed, Disposed) {} + KJ_CASE_ONEOF(disposed, Disposed) { + } } } }; @@ -244,7 +260,8 @@ class JsRpcPromise: public JsRpcClientProvider { class JsRpcProperty: public JsRpcClientProvider { public: JsRpcProperty(jsg::Ref parent, kj::String name) - : parent(kj::mv(parent)), name(kj::mv(name)) {} + : parent(kj::mv(parent)), + name(kj::mv(name)) {} rpc::JsRpcTarget::Client getClientForOneCall( jsg::Lock& js, kj::Vector& path) override; @@ -259,7 +276,8 @@ class JsRpcProperty: public JsRpcClientProvider { // the JsRpcProperty in memory until it resolves. It's actually fine if the JsRpcProperty is GC'd // before the promise resolves, since the property is just an API stub. The underlying Cap'n Proto // RPCs it starts will keep running; Cap'n Proto refcounts all the necessary resources internally. - jsg::JsValue then(jsg::Lock& js, v8::Local handler, + jsg::JsValue then(jsg::Lock& js, + v8::Local handler, jsg::Optional> errorHandler); jsg::JsValue catch_(jsg::Lock& js, v8::Local errorHandler); jsg::JsValue finally(jsg::Lock& js, v8::Local onFinally); @@ -312,8 +330,7 @@ class JsRpcProperty: public JsRpcClientProvider { // `JsRpcStub::sendJsRpc()`. class JsRpcStub: public JsRpcClientProvider { public: - JsRpcStub(IoOwn capnpClient) - : capnpClient(kj::mv(capnpClient)) {} + JsRpcStub(IoOwn capnpClient): capnpClient(kj::mv(capnpClient)) {} JsRpcStub(IoOwn capnpClient, RpcStubDisposalGroup& disposalGroup); ~JsRpcStub() noexcept(false); @@ -372,7 +389,9 @@ class RpcStubDisposalGroup { // Call dispose() on every stub in the group. void disposeAll(); - bool empty() { return list.empty(); } + bool empty() { + return list.empty(); + } // When creating a disposal group representing an RPC response, we may also attach the // `callPipeline` from the response, to control when the server-side `dispose()` method is @@ -394,17 +413,15 @@ class JsRpcSessionCustomEventImpl final: public WorkerInterface::CustomEvent { JsRpcSessionCustomEventImpl(uint16_t typeId, kj::PromiseFulfillerPair paf = kj::newPromiseAndFulfiller()) - : capFulfiller(kj::mv(paf.fulfiller)), - clientCap(kj::mv(paf.promise)), - typeId(typeId) {} + : capFulfiller(kj::mv(paf.fulfiller)), + clientCap(kj::mv(paf.promise)), + typeId(typeId) {} - kj::Promise run( - kj::Own incomingRequest, + kj::Promise run(kj::Own incomingRequest, kj::Maybe entrypointName, kj::TaskSet& waitUntilTasks) override; - kj::Promise sendRpc( - capnp::HttpOverCapnpFactory& httpOverCapnpFactory, + kj::Promise sendRpc(capnp::HttpOverCapnpFactory& httpOverCapnpFactory, capnp::ByteStreamFactory& byteStreamFactory, kj::TaskSet& waitUntilTasks, rpc::EventDispatcher::Client dispatcher) override; @@ -452,9 +469,9 @@ class JsRpcSessionCustomEventImpl final: public WorkerInterface::CustomEvent { // define a constructor. class WorkerEntrypoint: public jsg::Object { public: - static jsg::Ref constructor( - const v8::FunctionCallbackInfo& args, - jsg::Ref ctx, jsg::JsObject env); + static jsg::Ref constructor(const v8::FunctionCallbackInfo& args, + jsg::Ref ctx, + jsg::JsObject env); JSG_RESOURCE_TYPE(WorkerEntrypoint) {} }; @@ -471,9 +488,9 @@ class WorkerEntrypoint: public jsg::Object { // everyone to be explicit by inheriting this, and we require it if you want to use RPC. class DurableObjectBase: public jsg::Object { public: - static jsg::Ref constructor( - const v8::FunctionCallbackInfo& args, - jsg::Ref ctx, jsg::JsObject env); + static jsg::Ref constructor(const v8::FunctionCallbackInfo& args, + jsg::Ref ctx, + jsg::JsObject env); JSG_RESOURCE_TYPE(DurableObjectBase) {} }; @@ -492,9 +509,9 @@ class DurableObjectBase: public jsg::Object { // define a constructor. class Workflow: public jsg::Object { public: - static jsg::Ref constructor( - const v8::FunctionCallbackInfo& args, - jsg::Ref ctx, jsg::JsObject env); + static jsg::Ref constructor(const v8::FunctionCallbackInfo& args, + jsg::Ref ctx, + jsg::JsObject env); JSG_RESOURCE_TYPE(Workflow) {} }; @@ -517,15 +534,9 @@ class EntrypointsModule: public jsg::Object { } }; -#define EW_WORKER_RPC_ISOLATE_TYPES \ - api::JsRpcPromise, \ - api::JsRpcProperty, \ - api::JsRpcStub, \ - api::JsRpcTarget, \ - api::WorkerEntrypoint, \ - api::Workflow, \ - api::DurableObjectBase, \ - api::EntrypointsModule +#define EW_WORKER_RPC_ISOLATE_TYPES \ + api::JsRpcPromise, api::JsRpcProperty, api::JsRpcStub, api::JsRpcTarget, api::WorkerEntrypoint, \ + api::Workflow, api::DurableObjectBase, api::EntrypointsModule template void registerRpcModules(Registry& registry, CompatibilityFlags::Reader flags) { @@ -541,4 +552,4 @@ kj::Own getInternalRpcModuleBundle(auto featureFlags builder.addObject(kSpecifier); return builder.finish(); } -}; // namespace workerd::api +}; // namespace workerd::api diff --git a/src/workerd/io/actor-cache-test.c++ b/src/workerd/io/actor-cache-test.c++ index 6a37628833b..267a7ffae97 100644 --- a/src/workerd/io/actor-cache-test.c++ +++ b/src/workerd/io/actor-cache-test.c++ @@ -29,8 +29,8 @@ kj::Promise eagerlyReportExceptions(kj::Promise promise, kj::SourceLocatio } template -kj::Promise expectUncached(kj::OneOf> result, - kj::SourceLocation location = {}) { +kj::Promise expectUncached( + kj::OneOf> result, kj::SourceLocation location = {}) { // Expect that a result returned by get()/list()/delete() was not served entirely from cache, // and return the promise. KJ_SWITCH_ONEOF(result) { @@ -86,7 +86,9 @@ struct KeyValue { } }; -kj::ArrayPtr kvs(kj::ArrayPtr a) { return a; } +kj::ArrayPtr kvs(kj::ArrayPtr a) { + return a; +} // We want to be able to write checks like: // // KJ_ASSERT(results == {{"bar", "456"}, {"foo", "123"}}); @@ -103,7 +105,7 @@ kj::String stringifyValues(ActorCache::ValuePtr value) { return kj::str(value.asChars()); } KeyValue stringifyValues(ActorCache::KeyValuePtrPair kv) { - return { kj::str(kv.key), stringifyValues(kv.value) }; + return {kj::str(kv.key), stringifyValues(kv.value)}; } kj::Array stringifyValues(const ActorCache::GetResultList& list) { return KJ_MAP(e, list) { return stringifyValues(e); }; @@ -116,8 +118,8 @@ auto stringifyValues(const kj::Maybe& values) { template kj::OneOf())), - kj::Promise()))>> - stringifyValues(kj::OneOf> result) { + kj::Promise()))>> +stringifyValues(kj::OneOf> result) { KJ_SWITCH_ONEOF(result) { KJ_CASE_ONEOF(promise, kj::Promise) { return promise.then([](T result) { return stringifyValues(kj::mv(result)); }); @@ -148,21 +150,29 @@ struct ActorCacheConvenienceWrappers { return target.getAlarm(options); } - auto list(kj::StringPtr begin, kj::StringPtr end, - kj::Maybe limit = kj::none, ActorCache::ReadOptions options = {}) { + auto list(kj::StringPtr begin, + kj::StringPtr end, + kj::Maybe limit = kj::none, + ActorCache::ReadOptions options = {}) { return stringifyValues(target.list(kj::str(begin), kj::str(end), limit, options)); } - auto listReverse(kj::StringPtr begin, kj::StringPtr end, - kj::Maybe limit = kj::none, ActorCache::ReadOptions options = {}) { + auto listReverse(kj::StringPtr begin, + kj::StringPtr end, + kj::Maybe limit = kj::none, + ActorCache::ReadOptions options = {}) { return stringifyValues(target.listReverse(kj::str(begin), kj::str(end), limit, options)); } - auto list(kj::StringPtr begin, decltype(nullptr), - kj::Maybe limit = kj::none, ActorCache::ReadOptions options = {}) { + auto list(kj::StringPtr begin, + decltype(nullptr), + kj::Maybe limit = kj::none, + ActorCache::ReadOptions options = {}) { return stringifyValues(target.list(kj::str(begin), kj::none, limit, options)); } - auto listReverse(kj::StringPtr begin, decltype(nullptr), - kj::Maybe limit = kj::none, ActorCache::ReadOptions options = {}) { + auto listReverse(kj::StringPtr begin, + decltype(nullptr), + kj::Maybe limit = kj::none, + ActorCache::ReadOptions options = {}) { return stringifyValues(target.listReverse(kj::str(begin), kj::none, limit, options)); } @@ -171,7 +181,7 @@ struct ActorCacheConvenienceWrappers { } auto put(kj::ArrayPtr kvs, ActorCache::WriteOptions options = {}) { return target.put(KJ_MAP(kv, kvs) { - return ActorCache::KeyValuePair { kj::str(kv.key), kj::heapArray(kv.value.asBytes()) }; + return ActorCache::KeyValuePair{kj::str(kv.key), kj::heapArray(kv.value.asBytes())}; }, options); } auto setAlarm(kj::Maybe newTime, ActorCache::WriteOptions options = {}) { @@ -216,17 +226,16 @@ struct ActorCacheTest: public ActorCacheConvenienceWrappers { kj::UnwindDetector unwindDetector; ActorCacheTest(ActorCacheTestOptions options = {}, - MockServer::Pair mockPair = - MockServer::make()) + MockServer::Pair mockPair = + MockServer::make()) : ActorCacheConvenienceWrappers(cache), - ws(loop), mockStorage(kj::mv(mockPair.mock)), - lru({options.softLimit, options.hardLimit, - options.staleTimeout, options.dirtyListByteLimit, options.maxKeysPerRpc, - options.noCache, options.neverFlush}), + ws(loop), + mockStorage(kj::mv(mockPair.mock)), + lru({options.softLimit, options.hardLimit, options.staleTimeout, options.dirtyListByteLimit, + options.maxKeysPerRpc, options.noCache, options.neverFlush}), cache(kj::mv(mockPair.client), lru, gate), - gateBrokenPromise(options.monitorOutputGate - ? eagerlyReportExceptions(gate.onBroken()) - : kj::Promise(kj::READY_NOW)) {} + gateBrokenPromise(options.monitorOutputGate ? eagerlyReportExceptions(gate.onBroken()) + : kj::Promise(kj::READY_NOW)) {} ~ActorCacheTest() noexcept(false) { // Make sure if the output gate has been broken, the exception was reported. This is important @@ -264,9 +273,7 @@ KJ_TEST("ActorCache single-key basics") { { auto promise = expectUncached(test.get("bar")); - mockStorage->expectCall("get", ws) - .withParams(CAPNP(key = "bar")) - .thenReturn(CAPNP()); + mockStorage->expectCall("get", ws).withParams(CAPNP(key = "bar")).thenReturn(CAPNP()); auto result = promise.wait(ws); KJ_EXPECT(result == kj::none); @@ -322,13 +329,17 @@ KJ_TEST("ActorCache multi-key basics") { auto promise = expectUncached(test.get({"foo"_kj, "bar"_kj, "baz"_kj, "qux"_kj})); mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["bar", "baz", "foo", "qux"]), "stream"_kj) + .withParams(CAPNP(keys = [ "bar", "baz", "foo", "qux" ]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - // baz absent - (key = "foo", value = "123"), - // qux absent - ])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "456"), + // baz absent + (key = "foo", value = "123"), + // qux absent + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -346,8 +357,7 @@ KJ_TEST("ActorCache multi-key basics") { test.put({{"foo", "321"}, {"bar", "654"}}); mockStorage->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "321"), - (key = "bar", value = "654")])) + .withParams(CAPNP(entries = [ (key = "foo", value = "321"), (key = "bar", value = "654") ])) .thenReturn(CAPNP()); } @@ -360,7 +370,7 @@ KJ_TEST("ActorCache multi-key basics") { KJ_ASSERT(expectCached(test.delete_({"foo"_kj, "bar"_kj, "baz"_kj, "qux"_kj})) == 2); mockStorage->expectCall("delete", ws) - .withParams(CAPNP(keys = ["foo", "bar"])) + .withParams(CAPNP(keys = [ "foo", "bar" ])) .thenReturn(CAPNP(numDeleted = 2)); } @@ -383,8 +393,8 @@ KJ_TEST("ActorCache more puts") { // Value is immediately in cache. KJ_ASSERT(KJ_ASSERT_NONNULL(expectCached(test.get("foo"))) == "bar"); - auto inProgressFlush = mockStorage->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "bar")])); + auto inProgressFlush = mockStorage->expectCall("put", ws).withParams( + CAPNP(entries = [(key = "foo", value = "bar")])); // Still in cache during flush. KJ_ASSERT(KJ_ASSERT_NONNULL(expectCached(test.get("foo"))) == "bar"); @@ -424,8 +434,7 @@ KJ_TEST("ActorCache more deletes") { // Value is immediately in cache. KJ_ASSERT(expectCached(test.get("foo")) == kj::none); - auto mockDelete = mockStorage->expectCall("delete", ws) - .withParams(CAPNP(keys = ["foo"])); + auto mockDelete = mockStorage->expectCall("delete", ws).withParams(CAPNP(keys = ["foo"])); // Still in cache during flush. KJ_ASSERT(!promise.poll(ws)); @@ -496,10 +505,11 @@ KJ_TEST("ActorCache more multi-puts") { auto promise = expectUncached(test.get({"foo", "bar", "baz", "qux"})); mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["bar", "baz", "foo", "qux"]), "stream"_kj) + .withParams(CAPNP(keys = [ "bar", "baz", "foo", "qux" ]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = [ (key = "bar", value = "456"), (key = "foo", value = "123") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -519,17 +529,19 @@ KJ_TEST("ActorCache more multi-puts") { KJ_ASSERT(KJ_ASSERT_NONNULL(expectCached(test.get("corge"))) == "987"); mockStorage->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "321"), - // bar omitted because it was redundant - (key = "baz", value = "654"), - (key = "corge", value = "987")])) + .withParams(CAPNP(entries = + [ + (key = "foo", value = "321"), + // bar omitted because it was redundant + (key = "baz", value = "654"), (key = "corge", value = "987") + ])) .thenReturn(CAPNP()); } // Fetch everything again for good measure. { - auto promise = expectUncached(test.get({ - "foo"_kj, "bar"_kj, "baz"_kj, "qux"_kj, "corge"_kj, "grault"_kj})); + auto promise = + expectUncached(test.get({"foo"_kj, "bar"_kj, "baz"_kj, "qux"_kj, "corge"_kj, "grault"_kj})); // Only "grault" is not cached. mockStorage->expectCall("getMultiple", ws) @@ -539,12 +551,13 @@ KJ_TEST("ActorCache more multi-puts") { }).expectCanceled(); auto results = promise.wait(ws); - KJ_ASSERT(results == kvs({ - {"bar", "456"}, - {"baz", "654"}, - {"corge", "987"}, - {"foo", "321"}, - })); + KJ_ASSERT(results == + kvs({ + {"bar", "456"}, + {"baz", "654"}, + {"corge", "987"}, + {"foo", "321"}, + })); } } @@ -561,10 +574,11 @@ KJ_TEST("ActorCache more multi-deletes") { auto promise = expectUncached(test.get({"foo", "bar", "baz", "qux"})); mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["bar", "baz", "foo", "qux"]), "stream"_kj) + .withParams(CAPNP(keys = [ "bar", "baz", "foo", "qux" ]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = [ (key = "bar", value = "456"), (key = "foo", value = "123") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -586,7 +600,7 @@ KJ_TEST("ActorCache more multi-deletes") { auto mockTxn = mockStorage->expectCall("txn", ws).returnMock("transaction"); mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["corge", "grault"])) + .withParams(CAPNP(keys = [ "corge", "grault" ])) .thenReturn(CAPNP(numDeleted = 1)); mockTxn->expectCall("delete", ws) .withParams(CAPNP(keys = ["bar"])) @@ -599,8 +613,8 @@ KJ_TEST("ActorCache more multi-deletes") { // Fetch everything again for good measure. { - auto promise = expectUncached(test.get({ - "foo"_kj, "bar"_kj, "baz"_kj, "qux"_kj, "corge"_kj, "grault"_kj, "garply"_kj})); + auto promise = expectUncached( + test.get({"foo"_kj, "bar"_kj, "baz"_kj, "qux"_kj, "corge"_kj, "grault"_kj, "garply"_kj})); // Only "garply" is not cached. mockStorage->expectCall("getMultiple", ws) @@ -612,10 +626,7 @@ KJ_TEST("ActorCache more multi-deletes") { }).expectCanceled(); auto results = promise.wait(ws); - KJ_ASSERT(results == kvs({ - {"foo", "123"}, - {"garply", "abcd"} - })); + KJ_ASSERT(results == kvs({{"foo", "123"}, {"garply", "abcd"}})); } } @@ -643,30 +654,28 @@ KJ_TEST("ActorCache batching due to maxKeysPerRpc") { auto mockTxn = mockStorage->expectCall("txn", ws).returnMock("transaction"); mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["count1", "count2"])) - .thenReturn(CAPNP(numDeleted = 1)); // Treat one of this batch as present, 2 total. + .withParams(CAPNP(keys = [ "count1", "count2" ])) + .thenReturn(CAPNP(numDeleted = 1)); // Treat one of this batch as present, 2 total. mockTxn->expectCall("delete", ws) .withParams(CAPNP(keys = ["count3"])) - .thenReturn(CAPNP(numDeleted = 1)); // Treat one of this batch as present, 2 total. + .thenReturn(CAPNP(numDeleted = 1)); // Treat one of this batch as present, 2 total. mockTxn->expectCall("delete", ws) .withParams(CAPNP(keys = ["count4"])) - .thenReturn(CAPNP(numDeleted = 0)); // Treat this batch as absent. + .thenReturn(CAPNP(numDeleted = 0)); // Treat this batch as absent. mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["count5", "count6"])) - .thenReturn(CAPNP(numDeleted = 2)); // Treat all of this batch as present. + .withParams(CAPNP(keys = [ "count5", "count6" ])) + .thenReturn(CAPNP(numDeleted = 2)); // Treat all of this batch as present. mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["grault", "garply"])) + .withParams(CAPNP(keys = [ "grault", "garply" ])) .thenReturn(CAPNP(numDeleted = 1)); mockTxn->expectCall("delete", ws) .withParams(CAPNP(keys = ["waldo"])) .thenReturn(CAPNP(numDeleted = 1)); mockTxn->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "123"), - (key = "bar", value = "456")])) + .withParams(CAPNP(entries = [ (key = "foo", value = "123"), (key = "bar", value = "456") ])) .thenReturn(CAPNP()); mockTxn->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "baz", value = "789"), - (key = "qux", value = "555")])) + .withParams(CAPNP(entries = [ (key = "baz", value = "789"), (key = "qux", value = "555") ])) .thenReturn(CAPNP()); mockTxn->expectCall("put", ws) .withParams(CAPNP(entries = [(key = "corge", value = "999")])) @@ -693,10 +702,8 @@ KJ_TEST("ActorCache batching due to max storage RPC words") { } auto mockTxn = mockStorage->expectCall("txn", ws).returnMock("transaction"); - mockTxn->expectCall("put", ws) - .thenReturn(CAPNP()); - mockTxn->expectCall("put", ws) - .thenReturn(CAPNP()); + mockTxn->expectCall("put", ws).thenReturn(CAPNP()); + mockTxn->expectCall("put", ws).thenReturn(CAPNP()); mockTxn->expectCall("commit", ws).thenReturn(CAPNP()); mockTxn->expectDropped(ws); } @@ -711,7 +718,7 @@ KJ_TEST("ActorCache deleteAll()") { auto promise = expectUncached(test.get({"qux"_kj, "corge"_kj})); mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["corge", "qux"]), "stream"_kj) + .withParams(CAPNP(keys = [ "corge", "qux" ]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { stream.call("values", CAPNP(list = [(key = "corge", value = "555")])) .expectReturns(CAPNP(), ws); @@ -751,14 +758,13 @@ KJ_TEST("ActorCache deleteAll()") { { auto mockTxn = mockStorage->expectCall("txn", ws).returnMock("transaction"); mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["bar", "baz", "grault"])) + .withParams(CAPNP(keys = [ "bar", "baz", "grault" ])) .thenReturn(CAPNP(numDeleted = 2)); mockTxn->expectCall("delete", ws) .withParams(CAPNP(keys = ["garply"])) .thenReturn(CAPNP(numDeleted = 2)); mockTxn->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "123"), - (key = "baz", value = "789")])) + .withParams(CAPNP(entries = [ (key = "foo", value = "123"), (key = "baz", value = "789") ])) .thenReturn(CAPNP()); mockTxn->expectCall("setAlarm", ws) .withParams(CAPNP(scheduledTimeMs = 12345)) @@ -767,17 +773,18 @@ KJ_TEST("ActorCache deleteAll()") { mockTxn->expectDropped(ws); } - mockStorage->expectCall("deleteAll", ws) - .thenReturn(CAPNP(numDeleted = 2)); + mockStorage->expectCall("deleteAll", ws).thenReturn(CAPNP(numDeleted = 2)); KJ_ASSERT(deleteAll.count.wait(ws) == 2); // Post-deleteAll writes in a new flush. { mockStorage->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "grault", value = "12345"), - (key = "garply", value = "54321"), - (key = "waldo", value = "99999")])) + .withParams(CAPNP(entries = + [ + (key = "grault", value = "12345"), + (key = "garply", value = "54321"), (key = "waldo", value = "99999") + ])) .thenReturn(CAPNP()); } @@ -805,8 +812,8 @@ KJ_TEST("ActorCache deleteAll() during transaction commit") { test.put("foo", "123"); { - auto inProgressFlush = mockStorage->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "123")])); + auto inProgressFlush = mockStorage->expectCall("put", ws).withParams( + CAPNP(entries = [(key = "foo", value = "123")])); // Issue a put and a deleteAll() here! test.put("bar", "456"); @@ -823,8 +830,7 @@ KJ_TEST("ActorCache deleteAll() during transaction commit") { } // Now the deleteAll() actually happens. - mockStorage->expectCall("deleteAll", ws) - .thenReturn(CAPNP()); + mockStorage->expectCall("deleteAll", ws).thenReturn(CAPNP()); } KJ_TEST("ActorCache deleteAll() again when previous one isn't done yet") { @@ -837,7 +843,7 @@ KJ_TEST("ActorCache deleteAll() again when previous one isn't done yet") { auto promise = expectUncached(test.get({"qux"_kj, "corge"_kj})); mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["corge", "qux"]), "stream"_kj) + .withParams(CAPNP(keys = [ "corge", "qux" ]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { stream.call("values", CAPNP(list = [(key = "corge", value = "555")])) .expectReturns(CAPNP(), ws); @@ -863,14 +869,13 @@ KJ_TEST("ActorCache deleteAll() again when previous one isn't done yet") { { auto mockTxn = mockStorage->expectCall("txn", ws).returnMock("transaction"); mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["bar", "baz", "grault"])) + .withParams(CAPNP(keys = [ "bar", "baz", "grault" ])) .thenReturn(CAPNP(numDeleted = 2)); mockTxn->expectCall("delete", ws) .withParams(CAPNP(keys = ["garply"])) .thenReturn(CAPNP(numDeleted = 2)); mockTxn->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "123"), - (key = "baz", value = "789")])) + .withParams(CAPNP(entries = [ (key = "foo", value = "123"), (key = "baz", value = "789") ])) .thenReturn(CAPNP()); mockTxn->expectCall("commit", ws).thenReturn(CAPNP()); mockTxn->expectDropped(ws); @@ -883,8 +888,7 @@ KJ_TEST("ActorCache deleteAll() again when previous one isn't done yet") { test.put("fred", "2323"); // Now finish it. - mockStorage->expectCall("deleteAll", ws) - .thenReturn(CAPNP(numDeleted = 2)); + mockStorage->expectCall("deleteAll", ws).thenReturn(CAPNP(numDeleted = 2)); KJ_ASSERT(deleteAllA.count.wait(ws) == 2); KJ_ASSERT(deleteAllB.count.wait(ws) == 0); @@ -910,10 +914,11 @@ KJ_TEST("ActorCache coalescing") { auto promise = expectUncached(test.get({"foo", "bar", "baz", "qux"})); mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["bar", "baz", "foo", "qux"]), "stream"_kj) + .withParams(CAPNP(keys = [ "bar", "baz", "foo", "qux" ]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = [ (key = "bar", value = "456"), (key = "foo", value = "123") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -935,29 +940,31 @@ KJ_TEST("ActorCache coalescing") { // still has to be performed in order to produce the deletion count. test.put("waldo", "odlaw"); - auto values = expectCached(test.get({ - "foo"_kj, "bar"_kj, "baz"_kj, "qux"_kj, "corge"_kj, "grault"_kj, - "garply"_kj, "waldo"_kj, "fred"_kj})); - KJ_EXPECT(values == kvs({ - {"corge", "987"}, - {"qux", "555"}, - {"waldo", "odlaw"}, - })); + auto values = expectCached(test.get({"foo"_kj, "bar"_kj, "baz"_kj, "qux"_kj, "corge"_kj, + "grault"_kj, "garply"_kj, "waldo"_kj, "fred"_kj})); + KJ_EXPECT(values == + kvs({ + {"corge", "987"}, + {"qux", "555"}, + {"waldo", "odlaw"}, + })); auto mockTxn = mockStorage->expectCall("txn", ws).returnMock("transaction"); mockTxn->expectCall("delete", ws) .withParams(CAPNP(keys = ["grault"])) .thenReturn(CAPNP(numDeleted = 0)); mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["garply", "waldo", "fred"])) + .withParams(CAPNP(keys = [ "garply", "waldo", "fred" ])) .thenReturn(CAPNP(numDeleted = 2)); mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["bar", "foo"])) + .withParams(CAPNP(keys = [ "bar", "foo" ])) .thenReturn(CAPNP(numDeleted = 65382)); // count is ignored mockTxn->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "qux", value = "555"), - (key = "corge", value = "987"), - (key = "waldo", value = "odlaw")])) + .withParams(CAPNP(entries = + [ + (key = "qux", value = "555"), (key = "corge", value = "987"), + (key = "waldo", value = "odlaw") + ])) .thenReturn(CAPNP()); mockTxn->expectCall("commit", ws).thenReturn(CAPNP()); mockTxn->expectDropped(ws); @@ -991,7 +998,7 @@ KJ_TEST("ActorCache canceled deletes are coalesced") { .withParams(CAPNP(keys = ["corge"])) .thenReturn(CAPNP(numDeleted = 0)); mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["foo", "bar", "baz"])) + .withParams(CAPNP(keys = [ "foo", "bar", "baz" ])) .thenReturn(CAPNP(numDeleted = 1234)); // count ignored mockTxn->expectCall("put", ws) .withParams(CAPNP(entries = [(key = "qux", value = "blah")])) @@ -1031,19 +1038,19 @@ KJ_TEST("ActorCache get-put ordering") { // Expect to receive the storage gets. But, don't return from them yet! KJ_ASSERT(!promise1.poll(ws)); auto mockGet1 = mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["bar", "baz", "foo"]), "stream"_kj); + .withParams(CAPNP(keys = [ "bar", "baz", "foo" ]), "stream"_kj); KJ_ASSERT(!promise2.poll(ws)); - auto mockGet2 = mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["baz"]), "stream"_kj); + auto mockGet2 = + mockStorage->expectCall("getMultiple", ws).withParams(CAPNP(keys = ["baz"]), "stream"_kj); // No writes will be done until our reads finish! mockStorage->expectNoActivity(ws); // Let's have the second read complete first. - kj::mv(mockGet2).useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "baz", value = "987")])) - .expectReturns(CAPNP(), ws); + kj::mv(mockGet2) + .useCallback("stream", [&](MockClient stream) { + stream.call("values", CAPNP(list = [(key = "baz", value = "987")])).expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -1060,10 +1067,15 @@ KJ_TEST("ActorCache get-put ordering") { mockStorage->expectNoActivity(ws); // Finally, have the first read complete. - kj::mv(mockGet1).useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "654"), - (key = "baz", value = "987"), - (key = "foo", value = "321")])) + kj::mv(mockGet1) + .useCallback("stream", [&](MockClient stream) { + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "654"), (key = "baz", value = "987"), + (key = "foo", value = "321") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -1082,8 +1094,7 @@ KJ_TEST("ActorCache get-put ordering") { .withParams(CAPNP(keys = ["bar"])) .thenReturn(CAPNP(numDeleted = 1)); mockTxn->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "123"), - (key = "bar", value = "456")])) + .withParams(CAPNP(entries = [ (key = "foo", value = "123"), (key = "bar", value = "456") ])) .thenReturn(CAPNP()); mockTxn->expectCall("commit", ws).thenReturn(CAPNP()); mockTxn->expectDropped(ws); @@ -1105,9 +1116,8 @@ KJ_TEST("ActorCache put during flush") { test.put({{"foo", "123"}, {"bar", "456"}}); { - auto inProgressFlush = mockStorage->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "123"), - (key = "bar", value = "456")])); + auto inProgressFlush = mockStorage->expectCall("put", ws).withParams( + CAPNP(entries = [ (key = "foo", value = "123"), (key = "bar", value = "456") ])); // We're in the middle of flushing... do a put. Should be fine. test.put("bar", "654"); @@ -1141,14 +1151,16 @@ KJ_TEST("ActorCache flush retry") { auto mockTxn = mockStorage->expectCall("txn", ws).returnMock("transaction"); // One delete succeeds, the other throws (later). mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["qux", "quux"])) + .withParams(CAPNP(keys = [ "qux", "quux" ])) .thenReturn(CAPNP(numDeleted = 1)); - auto mockDelete = mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["corge", "grault"])); + auto mockDelete = + mockTxn->expectCall("delete", ws).withParams(CAPNP(keys = [ "corge", "grault" ])); mockTxn->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "123"), - (key = "bar", value = "456"), - (key = "baz", value = "789")])) + .withParams(CAPNP(entries = + [ + (key = "foo", value = "123"), (key = "bar", value = "456"), + (key = "baz", value = "789") + ])) .thenReturn(CAPNP()); // While the transaction is outstanding, some more puts and deletes mess with things... @@ -1189,16 +1201,17 @@ KJ_TEST("ActorCache flush retry") { .withParams(CAPNP(keys = ["quux"])) .thenReturn(CAPNP()); // count ignored because we got it on the first try! mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["corge", "grault"])) + .withParams(CAPNP(keys = [ "corge", "grault" ])) .thenReturn(CAPNP(numDeleted = 2)); mockTxn->expectCall("delete", ws) .withParams(CAPNP(keys = ["baz"])) - .thenReturn(CAPNP(numDeleted = 1234)); // count ignored + .thenReturn(CAPNP(numDeleted = 1234)); // count ignored mockTxn->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "123"), - (key = "bar", value = "654"), - (key = "qux", value = "987"), - (key = "corge", value = "555")])) + .withParams(CAPNP(entries = + [ + (key = "foo", value = "123"), (key = "bar", value = "654"), + (key = "qux", value = "987"), (key = "corge", value = "555") + ])) .thenReturn(CAPNP()); mockTxn->expectCall("commit", ws).thenReturn(CAPNP()); mockTxn->expectDropped(ws); @@ -1301,8 +1314,8 @@ KJ_TEST("ActorCache output gate bypass on one put but not the next") { // Complete the transaction. { - auto inProgressFlush = mockStorage->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "123"), (key = "bar", value = "456")])); + auto inProgressFlush = mockStorage->expectCall("put", ws).withParams( + CAPNP(entries = [ (key = "foo", value = "123"), (key = "bar", value = "456") ])); // Still blocked until the flush completes. KJ_ASSERT(!gatePromise.poll(ws)); @@ -1331,7 +1344,8 @@ KJ_TEST("ActorCache flush hard failure") { .thenThrow(KJ_EXCEPTION(FAILED, "jsg.Error: flush failed hard")); } - KJ_EXPECT_THROW_MESSAGE("broken.outputGateBroken; jsg.Error: flush failed hard", promise.wait(ws)); + KJ_EXPECT_THROW_MESSAGE( + "broken.outputGateBroken; jsg.Error: flush failed hard", promise.wait(ws)); // Further writes won't even try to start any new transactions because the failure killed them all. test.put("bar", "456"); @@ -1374,8 +1388,7 @@ KJ_TEST("ActorCache read retry") { test.delete_("baz"); // Expect the get, but don't resolve yet. - auto mockGet = mockStorage->expectCall("get", ws) - .withParams(CAPNP(key = "foo")); + auto mockGet = mockStorage->expectCall("get", ws).withParams(CAPNP(key = "foo")); // No activity because reads are outstanding. mockStorage->expectNoActivity(ws); @@ -1384,8 +1397,7 @@ KJ_TEST("ActorCache read retry") { kj::mv(mockGet).thenThrow(KJ_EXCEPTION(DISCONNECTED, "read failed")); // It will be retried. - auto mockGet2 = mockStorage->expectCall("get", ws) - .withParams(CAPNP(key = "foo")); + auto mockGet2 = mockStorage->expectCall("get", ws).withParams(CAPNP(key = "foo")); // Still no activity because of the read. mockStorage->expectNoActivity(ws); @@ -1417,8 +1429,7 @@ KJ_TEST("ActorCache read retry on flush containing only puts") { test.put("bar", "456"); // Expect the get, but don't resolve yet. - auto mockGet = mockStorage->expectCall("get", ws) - .withParams(CAPNP(key = "foo")); + auto mockGet = mockStorage->expectCall("get", ws).withParams(CAPNP(key = "foo")); // No activity on the flush yet (not even starting a txn), because reads are outstanding. mockStorage->expectNoActivity(ws); @@ -1427,8 +1438,7 @@ KJ_TEST("ActorCache read retry on flush containing only puts") { kj::mv(mockGet).thenThrow(KJ_EXCEPTION(DISCONNECTED, "read failed")); // It will be retried. - auto mockGet2 = mockStorage->expectCall("get", ws) - .withParams(CAPNP(key = "foo")); + auto mockGet2 = mockStorage->expectCall("get", ws).withParams(CAPNP(key = "foo")); // Still no transaction activity. mockStorage->expectNoActivity(ws); @@ -1457,8 +1467,7 @@ KJ_TEST("ActorCache read hard fail") { test.delete_("baz"); // Expect the get, but don't resolve yet. - auto mockGet = mockStorage->expectCall("get", ws) - .withParams(CAPNP(key = "foo")); + auto mockGet = mockStorage->expectCall("get", ws).withParams(CAPNP(key = "foo")); // We won't write anything until the read completes. mockStorage->expectNoActivity(ws); @@ -1494,8 +1503,7 @@ KJ_TEST("ActorCache read cancel") { test.delete_("baz"); // Expect the get, but intentionally don't resolve it. - auto mockGet = mockStorage->expectCall("get", ws) - .withParams(CAPNP(key = "foo")); + auto mockGet = mockStorage->expectCall("get", ws).withParams(CAPNP(key = "foo")); // We won't write anything until the read completes. mockStorage->expectNoActivity(ws); @@ -1525,10 +1533,9 @@ KJ_TEST("ActorCache get-multiple multiple blocks") { auto promise = expectUncached(test.get({"foo"_kj, "bar"_kj, "baz"_kj, "qux"_kj, "corge"_kj})); mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["bar", "baz", "corge", "foo", "qux"]), "stream"_kj) + .withParams(CAPNP(keys = [ "bar", "baz", "corge", "foo", "qux" ]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "baz", value = "456")])) - .expectReturns(CAPNP(), ws); + stream.call("values", CAPNP(list = [(key = "baz", value = "456")])).expectReturns(CAPNP(), ws); // At this point, "bar" and "baz" are considered cached. KJ_ASSERT(expectCached(test.get("bar")) == nullptr); @@ -1537,8 +1544,7 @@ KJ_TEST("ActorCache get-multiple multiple blocks") { (void)expectUncached(test.get("foo")); (void)expectUncached(test.get("qux")); - stream.call("values", CAPNP(list = [(key = "foo", value = "789")])) - .expectReturns(CAPNP(), ws); + stream.call("values", CAPNP(list = [(key = "foo", value = "789")])).expectReturns(CAPNP(), ws); // At this point, everything except "qux" is cached. KJ_ASSERT(expectCached(test.get("bar")) == nullptr); @@ -1568,18 +1574,17 @@ KJ_TEST("ActorCache get-multiple partial retry") { auto promise = expectUncached(test.get({"foo"_kj, "bar"_kj, "baz"_kj, "qux"_kj})); mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["bar", "baz", "foo", "qux"]), "stream"_kj) + .withParams(CAPNP(keys = [ "bar", "baz", "foo", "qux" ]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "baz", value = "456")])) - .expectReturns(CAPNP(), ws); + stream.call("values", CAPNP(list = [(key = "baz", value = "456")])).expectReturns(CAPNP(), ws); }).thenThrow(KJ_EXCEPTION(DISCONNECTED, "read failed")); - mockStorage->expectCall("getMultiple", ws) + mockStorage + ->expectCall("getMultiple", ws) // Since "baz" was received, the caller knows that it only has to retry keys after that. - .withParams(CAPNP(keys = ["foo", "qux"]), "stream"_kj) + .withParams(CAPNP(keys = [ "foo", "qux" ]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "qux", value = "789")])) - .expectReturns(CAPNP(), ws); + stream.call("values", CAPNP(list = [(key = "qux", value = "789")])).expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -1600,9 +1605,13 @@ KJ_TEST("ActorCache list()") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "456"), (key = "baz", value = "789"), + (key = "foo", value = "123") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -1625,10 +1634,8 @@ KJ_TEST("ActorCache list()") { // Limits can be applied to the cached results. KJ_ASSERT(expectCached(test.list("bar", "qux", 0u)) == kvs({})); - KJ_ASSERT(expectCached(test.list("bar", "qux", 1)) == - kvs({{"bar", "456"}})); - KJ_ASSERT(expectCached(test.list("bar", "qux", 2)) == - kvs({{"bar", "456"}, {"baz", "789"}})); + KJ_ASSERT(expectCached(test.list("bar", "qux", 1)) == kvs({{"bar", "456"}})); + KJ_ASSERT(expectCached(test.list("bar", "qux", 2)) == kvs({{"bar", "456"}, {"baz", "789"}})); KJ_ASSERT(expectCached(test.list("bar", "qux", 3)) == kvs({{"bar", "456"}, {"baz", "789"}, {"foo", "123"}})); KJ_ASSERT(expectCached(test.list("bar", "qux", 4)) == @@ -1660,9 +1667,13 @@ KJ_TEST("ActorCache list() all") { mockStorage->expectCall("list", ws) .withParams(CAPNP(), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "456"), (key = "baz", value = "789"), + (key = "foo", value = "123") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -1677,10 +1688,8 @@ KJ_TEST("ActorCache list() all") { kvs({{"bar", "456"}, {"baz", "789"}, {"foo", "123"}})); KJ_ASSERT(expectCached(test.list(nullptr, nullptr)) == kvs({{"bar", "456"}, {"baz", "789"}, {"foo", "123"}})); - KJ_ASSERT(expectCached(test.list("baz", nullptr)) == - kvs({{"baz", "789"}, {"foo", "123"}})); - KJ_ASSERT(expectCached(test.list(nullptr, "foo")) == - kvs({{"bar", "456"}, {"baz", "789"}})); + KJ_ASSERT(expectCached(test.list("baz", nullptr)) == kvs({{"baz", "789"}, {"foo", "123"}})); + KJ_ASSERT(expectCached(test.list(nullptr, "foo")) == kvs({{"bar", "456"}, {"baz", "789"}})); } KJ_TEST("ActorCache list() with limit") { @@ -1694,9 +1703,13 @@ KJ_TEST("ActorCache list() with limit") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux", limit = 3), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "456"), (key = "baz", value = "789"), + (key = "foo", value = "123") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -1720,10 +1733,8 @@ KJ_TEST("ActorCache list() with limit") { // Listing the same range again, with the same limit or lower, is fully cached. KJ_ASSERT(expectCached(test.list("bar", "qux", 3)) == kvs({{"bar", "456"}, {"baz", "789"}, {"foo", "123"}})); - KJ_ASSERT(expectCached(test.list("bar", "qux", 2)) == - kvs({{"bar", "456"}, {"baz", "789"}})); - KJ_ASSERT(expectCached(test.list("bar", "qux", 1)) == - kvs({{"bar", "456"}})); + KJ_ASSERT(expectCached(test.list("bar", "qux", 2)) == kvs({{"bar", "456"}, {"baz", "789"}})); + KJ_ASSERT(expectCached(test.list("bar", "qux", 1)) == kvs({{"bar", "456"}})); KJ_ASSERT(expectCached(test.list("bar", "qux", 0u)) == kvs({})); // But a larger limit won't be cached. @@ -1769,10 +1780,13 @@ KJ_TEST("ActorCache list() with limit around negative entries") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux", limit = 7), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "bar1", value = "xxx"), - (key = "bar3", value = "yyy"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "456"), (key = "bar1", value = "xxx"), + (key = "bar3", value = "yyy"), (key = "foo", value = "123") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -1804,8 +1818,9 @@ KJ_TEST("ActorCache list() start point is not present") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "baz", value = "789"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = [ (key = "baz", value = "789"), (key = "foo", value = "123") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -1834,8 +1849,7 @@ KJ_TEST("ActorCache list() multiple ranges") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "a", end = "c"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "a", value = "1"), - (key = "b", value = "2")])) + stream.call("values", CAPNP(list = [ (key = "a", value = "1"), (key = "b", value = "2") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -1851,8 +1865,7 @@ KJ_TEST("ActorCache list() multiple ranges") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "x", end = "z"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "y", value = "9")])) - .expectReturns(CAPNP(), ws); + stream.call("values", CAPNP(list = [(key = "y", value = "9")])).expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -1877,9 +1890,7 @@ KJ_TEST("ActorCache list() with some already-cached keys in range") { auto promise1 = expectUncached(test.get("bbb")); auto promise2 = expectUncached(test.get("ccc")); - mockStorage->expectCall("get", ws) - .withParams(CAPNP(key = "bbb")) - .thenReturn(CAPNP()); + mockStorage->expectCall("get", ws).withParams(CAPNP(key = "bbb")).thenReturn(CAPNP()); mockStorage->expectCall("get", ws) .withParams(CAPNP(key = "ccc")) .thenReturn(CAPNP(value = "cval")); @@ -1899,8 +1910,9 @@ KJ_TEST("ActorCache list() with some already-cached keys in range") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "aaa", end = "fff"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "ccc", value = "cval"), - (key = "eee", value = "eval")])) + stream + .call("values", + CAPNP(list = [ (key = "ccc", value = "cval"), (key = "eee", value = "eval") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -1935,7 +1947,7 @@ KJ_TEST("ActorCache list() with seemingly-redundant dirty entries") { // Initiate a list operation, but don't complete it yet. auto listPromise = expectUncached(test.list("aaa", "fff")); auto listCall = mockStorage->expectCall("list", ws) - .withParams(CAPNP(start = "aaa", end = "fff"), "stream"_kj); + .withParams(CAPNP(start = "aaa", end = "fff"), "stream"_kj); // The delete won't do any work until the list completes. mockStorage->expectNoActivity(ws); @@ -1945,9 +1957,9 @@ KJ_TEST("ActorCache list() with seemingly-redundant dirty entries") { KJ_ASSERT(expectCached(test.delete_("ccc")) == 1); // Now let the list complete in a way that matches what was just written. - kj::mv(listCall).useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bbb", value = "bval")])) - .expectReturns(CAPNP(), ws); + kj::mv(listCall) + .useCallback("stream", [&](MockClient stream) { + stream.call("values", CAPNP(list = [(key = "bbb", value = "bval")])).expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -1998,8 +2010,8 @@ KJ_TEST("ActorCache list() starting from known value") { test.put("bar", "123"); mockStorage->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "bar", value = "123")])) - .thenReturn(CAPNP()); + .withParams(CAPNP(entries = [(key = "bar", value = "123")])) + .thenReturn(CAPNP()); } { @@ -2028,8 +2040,8 @@ KJ_TEST("ActorCache list() starting from unknown value") { test.put("baz", "456"); mockStorage->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "baz", value = "456")])) - .thenReturn(CAPNP()); + .withParams(CAPNP(entries = [(key = "baz", value = "456")])) + .thenReturn(CAPNP()); } { @@ -2038,8 +2050,9 @@ KJ_TEST("ActorCache list() starting from unknown value") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "baz", value = "456"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = [ (key = "baz", value = "456"), (key = "foo", value = "123") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2147,8 +2160,9 @@ KJ_TEST("ActorCache list() consecutively, present midpoint") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "corge", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "corge", value = "789"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = [ (key = "corge", value = "789"), (key = "foo", value = "123") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2171,8 +2185,9 @@ KJ_TEST("ActorCache list() consecutively reverse, present midpoint") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "corge", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "corge", value = "789"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = [ (key = "corge", value = "789"), (key = "foo", value = "123") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2289,9 +2304,13 @@ KJ_TEST("ActorCache list() with limit and dirty puts that end up past the limit" mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux", limit = 3), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "654"), - (key = "foo", value = "789")])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "456"), (key = "baz", value = "654"), + (key = "foo", value = "789") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2319,8 +2338,9 @@ KJ_TEST("ActorCache list() overwrite endpoint") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "corge", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "corge", value = "789"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = [ (key = "corge", value = "789"), (key = "foo", value = "123") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2348,8 +2368,9 @@ KJ_TEST("ActorCache list() delete endpoint") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "corge", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "corge", value = "789"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = [ (key = "corge", value = "789"), (key = "foo", value = "123") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2362,8 +2383,8 @@ KJ_TEST("ActorCache list() delete endpoint") { // Acknowledge the delete transaction. { mockStorage->expectCall("delete", ws) - .withParams(CAPNP(keys = ["qux"])) - .thenReturn(CAPNP(numDeleted = 1)); + .withParams(CAPNP(keys = ["qux"])) + .thenReturn(CAPNP(numDeleted = 1)); } KJ_ASSERT(deletePromise.wait(ws) == 1); @@ -2398,8 +2419,7 @@ KJ_TEST("ActorCache list() delete endpoint empty range") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "corge", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [])) - .expectReturns(CAPNP(), ws); + stream.call("values", CAPNP(list = [])).expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2411,8 +2431,8 @@ KJ_TEST("ActorCache list() delete endpoint empty range") { // Acknowledge the delete transaction. { mockStorage->expectCall("delete", ws) - .withParams(CAPNP(keys = ["qux"])) - .thenReturn(CAPNP(numDeleted = 1)); + .withParams(CAPNP(keys = ["qux"])) + .thenReturn(CAPNP(numDeleted = 1)); } KJ_ASSERT(deletePromise.wait(ws) == 1); @@ -2445,22 +2465,22 @@ KJ_TEST("ActorCache list() interleave streaming with other ops") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "123"), - (key = "corge", value = "456")])) + stream + .call("values", + CAPNP(list = [ (key = "bar", value = "123"), (key = "corge", value = "456") ])) .expectReturns(CAPNP(), ws); KJ_ASSERT(KJ_ASSERT_NONNULL(expectCached(test.get("bar"))) == "123"); KJ_ASSERT(expectCached(test.get("baz")) == nullptr); auto promise2 = expectUncached(test.get("grault")); - mockStorage->expectCall("get", ws) - .withParams(CAPNP(key = "grault")) - .thenReturn(CAPNP()); + mockStorage->expectCall("get", ws).withParams(CAPNP(key = "grault")).thenReturn(CAPNP()); KJ_ASSERT(promise2.wait(ws) == nullptr); test.put("foo", "987"); - stream.call("values", CAPNP(list = [(key = "foo", value = "789"), - (key = "garply", value = "555")])) + stream + .call("values", + CAPNP(list = [ (key = "foo", value = "789"), (key = "garply", value = "555") ])) .expectReturns(CAPNP(), ws); KJ_ASSERT(expectCached(test.delete_("garply")) == 1); @@ -2482,9 +2502,7 @@ KJ_TEST("ActorCache list() interleave streaming with other ops") { .thenReturn(CAPNP()); } { - mockStorage->expectCall("delete", ws) - .withParams(CAPNP(keys = ["garply"])) - .thenReturn(CAPNP()); + mockStorage->expectCall("delete", ws).withParams(CAPNP(keys = ["garply"])).thenReturn(CAPNP()); } } @@ -2496,8 +2514,7 @@ KJ_TEST("ActorCache list() end of first block deleted at inopportune time") { // Do a delete, wait for the commit... and then hold it open. auto deletePromise = expectUncached(test.delete_("corge")); - auto mockDelete = mockStorage->expectCall("delete", ws) - .withParams(CAPNP(keys = ["corge"])); + auto mockDelete = mockStorage->expectCall("delete", ws).withParams(CAPNP(keys = ["corge"])); // Now do a list. auto promise = expectUncached(test.list("bar", "qux")); @@ -2506,8 +2523,9 @@ KJ_TEST("ActorCache list() end of first block deleted at inopportune time") { .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { // First block ends at the deleted entry. - stream.call("values", CAPNP(list = [(key = "bar", value = "123"), - (key = "corge", value = "456")])) + stream + .call("values", + CAPNP(list = [ (key = "bar", value = "123"), (key = "corge", value = "456") ])) .expectReturns(CAPNP(), ws); // Let the delete finish. So now the last key in the first block is cached as a negative @@ -2534,8 +2552,9 @@ KJ_TEST("ActorCache list() retry on failure") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux", limit = 4), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789")])) + stream + .call("values", + CAPNP(list = [ (key = "bar", value = "456"), (key = "baz", value = "789") ])) .expectReturns(CAPNP(), ws); }).thenThrow(KJ_EXCEPTION(DISCONNECTED, "oops")); @@ -2544,9 +2563,13 @@ KJ_TEST("ActorCache list() retry on failure") { .withParams(CAPNP(start = "baz\0", end = "qux", limit = 2), "stream"_kj) .useCallback("stream", [&](MockClient stream) { // Duplicates of earlier keys will be ignored. - stream.call("values", CAPNP(list = [(key = "bar", value = "IGNORE"), - (key = "baz", value = "IGNORE"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "IGNORE"), (key = "baz", value = "IGNORE"), + (key = "foo", value = "123") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2579,9 +2602,7 @@ KJ_TEST("ActorCache get() of endpoint of previous list() returning negative is c { auto promise = expectUncached(test.get("qux")); - mockStorage->expectCall("get", ws) - .withParams(CAPNP(key = "qux")) - .thenReturn(CAPNP()); + mockStorage->expectCall("get", ws).withParams(CAPNP(key = "qux")).thenReturn(CAPNP()); KJ_ASSERT(promise.wait(ws) == nullptr); } @@ -2602,9 +2623,13 @@ KJ_TEST("ActorCache listReverse()") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux", reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "foo", value = "123"), - (key = "baz", value = "789"), - (key = "bar", value = "456")])) + stream + .call("values", + CAPNP(list = + [ + (key = "foo", value = "123"), (key = "baz", value = "789"), + (key = "bar", value = "456") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2627,10 +2652,9 @@ KJ_TEST("ActorCache listReverse()") { // Limits can be applied to the cached results. KJ_ASSERT(expectCached(test.listReverse("bar", "qux", 0u)) == kvs({})); - KJ_ASSERT(expectCached(test.listReverse("bar", "qux", 1)) == - kvs({{"foo", "123"}})); - KJ_ASSERT(expectCached(test.listReverse("bar", "qux", 2)) == - kvs({{"foo", "123"}, {"baz", "789"}})); + KJ_ASSERT(expectCached(test.listReverse("bar", "qux", 1)) == kvs({{"foo", "123"}})); + KJ_ASSERT( + expectCached(test.listReverse("bar", "qux", 2)) == kvs({{"foo", "123"}, {"baz", "789"}})); KJ_ASSERT(expectCached(test.listReverse("bar", "qux", 3)) == kvs({{"foo", "123"}, {"baz", "789"}, {"bar", "456"}})); KJ_ASSERT(expectCached(test.listReverse("bar", "qux", 4)) == @@ -2662,9 +2686,13 @@ KJ_TEST("ActorCache listReverse() all") { mockStorage->expectCall("list", ws) .withParams(CAPNP(reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "foo", value = "123"), - (key = "baz", value = "789"), - (key = "bar", value = "456")])) + stream + .call("values", + CAPNP(list = + [ + (key = "foo", value = "123"), (key = "baz", value = "789"), + (key = "bar", value = "456") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2679,10 +2707,10 @@ KJ_TEST("ActorCache listReverse() all") { kvs({{"foo", "123"}, {"baz", "789"}, {"bar", "456"}})); KJ_ASSERT(expectCached(test.listReverse(nullptr, nullptr)) == kvs({{"foo", "123"}, {"baz", "789"}, {"bar", "456"}})); - KJ_ASSERT(expectCached(test.listReverse("baz", nullptr)) == - kvs({{"foo", "123"}, {"baz", "789"}})); - KJ_ASSERT(expectCached(test.listReverse(nullptr, "foo")) == - kvs({{"baz", "789"}, {"bar", "456"}})); + KJ_ASSERT( + expectCached(test.listReverse("baz", nullptr)) == kvs({{"foo", "123"}, {"baz", "789"}})); + KJ_ASSERT( + expectCached(test.listReverse(nullptr, "foo")) == kvs({{"baz", "789"}, {"bar", "456"}})); } KJ_TEST("ActorCache listReverse() with limit") { @@ -2696,9 +2724,13 @@ KJ_TEST("ActorCache listReverse() with limit") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "abc", end = "qux", limit = 3, reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "foo", value = "123"), - (key = "baz", value = "789"), - (key = "bar", value = "456")])) + stream + .call("values", + CAPNP(list = + [ + (key = "foo", value = "123"), (key = "baz", value = "789"), + (key = "bar", value = "456") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2722,10 +2754,9 @@ KJ_TEST("ActorCache listReverse() with limit") { // Listing the same range again, with the same limit or lower, is fully cached. KJ_ASSERT(expectCached(test.listReverse("bar", "qux", 3)) == kvs({{"foo", "123"}, {"baz", "789"}, {"bar", "456"}})); - KJ_ASSERT(expectCached(test.listReverse("bar", "qux", 2)) == - kvs({{"foo", "123"}, {"baz", "789"}})); - KJ_ASSERT(expectCached(test.listReverse("bar", "qux", 1)) == - kvs({{"foo", "123"}})); + KJ_ASSERT( + expectCached(test.listReverse("bar", "qux", 2)) == kvs({{"foo", "123"}, {"baz", "789"}})); + KJ_ASSERT(expectCached(test.listReverse("bar", "qux", 1)) == kvs({{"foo", "123"}})); KJ_ASSERT(expectCached(test.listReverse("bar", "qux", 0u)) == kvs({})); // But a larger limit won't be cached. @@ -2742,8 +2773,8 @@ KJ_TEST("ActorCache listReverse() with limit") { stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); - KJ_ASSERT(promise.wait(ws) == - kvs({{"foo", "123"}, {"baz", "789"}, {"bar", "456"}, {"baa", "xyz"}})); + KJ_ASSERT( + promise.wait(ws) == kvs({{"foo", "123"}, {"baz", "789"}, {"bar", "456"}, {"baa", "xyz"}})); } // Cached if we try it again though. @@ -2771,10 +2802,13 @@ KJ_TEST("ActorCache listReverse() with limit around negative entries") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux", limit = 7, reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "foo", value = "123"), - (key = "baz", value = "789"), - (key = "bar3", value = "yyy"), - (key = "bar1", value = "xxx")])) + stream + .call("values", + CAPNP(list = + [ + (key = "foo", value = "123"), (key = "baz", value = "789"), + (key = "bar3", value = "yyy"), (key = "bar1", value = "xxx") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2806,8 +2840,9 @@ KJ_TEST("ActorCache listReverse() start point is not present") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux", reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "foo", value = "123"), - (key = "baz", value = "789")])) + stream + .call("values", + CAPNP(list = [ (key = "foo", value = "123"), (key = "baz", value = "789") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2836,8 +2871,7 @@ KJ_TEST("ActorCache listReverse() multiple ranges") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "a", end = "c", reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "b", value = "2"), - (key = "a", value = "1")])) + stream.call("values", CAPNP(list = [ (key = "b", value = "2"), (key = "a", value = "1") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2853,8 +2887,7 @@ KJ_TEST("ActorCache listReverse() multiple ranges") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "x", end = "z", reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "y", value = "9")])) - .expectReturns(CAPNP(), ws); + stream.call("values", CAPNP(list = [(key = "y", value = "9")])).expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2879,9 +2912,7 @@ KJ_TEST("ActorCache listReverse() with some already-cached keys in range") { auto promise1 = expectUncached(test.get("bbb")); auto promise2 = expectUncached(test.get("ccc")); - mockStorage->expectCall("get", ws) - .withParams(CAPNP(key = "bbb")) - .thenReturn(CAPNP()); + mockStorage->expectCall("get", ws).withParams(CAPNP(key = "bbb")).thenReturn(CAPNP()); mockStorage->expectCall("get", ws) .withParams(CAPNP(key = "ccc")) .thenReturn(CAPNP(value = "cval")); @@ -2901,8 +2932,9 @@ KJ_TEST("ActorCache listReverse() with some already-cached keys in range") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "aaa", end = "fff", reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "eee", value = "eval"), - (key = "ccc", value = "cval")])) + stream + .call("values", + CAPNP(list = [ (key = "eee", value = "eval"), (key = "ccc", value = "cval") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -2937,7 +2969,7 @@ KJ_TEST("ActorCache listReverse() with seemingly-redundant dirty entries") { // Initiate a list operation, but don't complete it yet. auto listPromise = expectUncached(test.listReverse("aaa", "fff")); auto listCall = mockStorage->expectCall("list", ws) - .withParams(CAPNP(start = "aaa", end = "fff", reverse = true), "stream"_kj); + .withParams(CAPNP(start = "aaa", end = "fff", reverse = true), "stream"_kj); // We won't do any work while the list is outstanding. mockStorage->expectNoActivity(ws); @@ -2947,9 +2979,9 @@ KJ_TEST("ActorCache listReverse() with seemingly-redundant dirty entries") { KJ_ASSERT(expectCached(test.delete_("ccc")) == 1); // Now let the list complete in a way that matches what was just written. - kj::mv(listCall).useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bbb", value = "bval")])) - .expectReturns(CAPNP(), ws); + kj::mv(listCall) + .useCallback("stream", [&](MockClient stream) { + stream.call("values", CAPNP(list = [(key = "bbb", value = "bval")])).expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -3035,8 +3067,9 @@ KJ_TEST("ActorCache listReverse() starting from unknown value") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux", reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "foo", value = "123"), - (key = "baz", value = "456")])) + stream + .call("values", + CAPNP(list = [ (key = "foo", value = "123"), (key = "baz", value = "456") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -3144,8 +3177,9 @@ KJ_TEST("ActorCache listReverse() consecutively, present midpoint") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "corge", end = "qux", reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "foo", value = "123"), - (key = "corge", value = "789")])) + stream + .call("values", + CAPNP(list = [ (key = "foo", value = "123"), (key = "corge", value = "789") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -3168,8 +3202,9 @@ KJ_TEST("ActorCache listReverse() consecutively reverse, present midpoint") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "corge", end = "qux", reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "foo", value = "123"), - (key = "corge", value = "789")])) + stream + .call("values", + CAPNP(list = [ (key = "foo", value = "123"), (key = "corge", value = "789") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -3281,9 +3316,13 @@ KJ_TEST("ActorCache listReverse() with limit and dirty puts that end up past the mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux", limit = 3, reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "grault", value = "456"), - (key = "foo", value = "654"), - (key = "baz", value = "789")])) + stream + .call("values", + CAPNP(list = + [ + (key = "grault", value = "456"), (key = "foo", value = "654"), + (key = "baz", value = "789") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -3311,8 +3350,9 @@ KJ_TEST("ActorCache listReverse() overwrite endpoint") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "corge", end = "qux", reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "foo", value = "123"), - (key = "corge", value = "789")])) + stream + .call("values", + CAPNP(list = [ (key = "foo", value = "123"), (key = "corge", value = "789") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -3340,8 +3380,9 @@ KJ_TEST("ActorCache listReverse() delete endpoint") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "corge", end = "qux", reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "foo", value = "123"), - (key = "corge", value = "789")])) + stream + .call("values", + CAPNP(list = [ (key = "foo", value = "123"), (key = "corge", value = "789") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -3354,8 +3395,8 @@ KJ_TEST("ActorCache listReverse() delete endpoint") { // Acknowledge the delete transaction. { mockStorage->expectCall("delete", ws) - .withParams(CAPNP(keys = ["corge"])) - .thenReturn(CAPNP(numDeleted = 1)); + .withParams(CAPNP(keys = ["corge"])) + .thenReturn(CAPNP(numDeleted = 1)); } { @@ -3383,23 +3424,23 @@ KJ_TEST("ActorCache listReverse() interleave streaming with other ops") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "baa", end = "qux", reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "garply", value = "555"), - (key = "foo", value = "789")])) + stream + .call("values", + CAPNP(list = [ (key = "garply", value = "555"), (key = "foo", value = "789") ])) .expectReturns(CAPNP(), ws); KJ_ASSERT(KJ_ASSERT_NONNULL(expectCached(test.get("garply"))) == "555"); KJ_ASSERT(expectCached(test.get("grault")) == nullptr); KJ_ASSERT(expectCached(test.get("gah")) == nullptr); auto promise2 = expectUncached(test.get("baz")); - mockStorage->expectCall("get", ws) - .withParams(CAPNP(key = "baz")) - .thenReturn(CAPNP()); + mockStorage->expectCall("get", ws).withParams(CAPNP(key = "baz")).thenReturn(CAPNP()); KJ_ASSERT(promise2.wait(ws) == nullptr); test.put("corge", "987"); - stream.call("values", CAPNP(list = [(key = "corge", value = "456"), - (key = "bar", value = "123")])) + stream + .call("values", + CAPNP(list = [ (key = "corge", value = "456"), (key = "bar", value = "123") ])) .expectReturns(CAPNP(), ws); KJ_ASSERT(expectCached(test.delete_("bar")) == 1); @@ -3420,11 +3461,7 @@ KJ_TEST("ActorCache listReverse() interleave streaming with other ops") { .withParams(CAPNP(entries = [(key = "corge", value = "987")])) .thenReturn(CAPNP()); } - { - mockStorage->expectCall("delete", ws) - .withParams(CAPNP(keys = ["bar"])) - .thenReturn(CAPNP()); - } + { mockStorage->expectCall("delete", ws).withParams(CAPNP(keys = ["bar"])).thenReturn(CAPNP()); } } KJ_TEST("ActorCache listReverse() end of first block deleted at inopportune time") { @@ -3435,8 +3472,7 @@ KJ_TEST("ActorCache listReverse() end of first block deleted at inopportune time // Do a delete, wait for the commit... and then hold it open. auto deletePromise = expectUncached(test.delete_("corge")); - auto mockDelete = mockStorage->expectCall("delete", ws) - .withParams(CAPNP(keys = ["corge"])); + auto mockDelete = mockStorage->expectCall("delete", ws).withParams(CAPNP(keys = ["corge"])); // Now do a list. auto promise = expectUncached(test.listReverse("bar", "qux")); @@ -3445,8 +3481,9 @@ KJ_TEST("ActorCache listReverse() end of first block deleted at inopportune time .withParams(CAPNP(start = "bar", end = "qux", reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { // First block ends at the deleted entry. - stream.call("values", CAPNP(list = [(key = "foo", value = "456"), - (key = "corge", value = "123")])) + stream + .call("values", + CAPNP(list = [ (key = "foo", value = "456"), (key = "corge", value = "123") ])) .expectReturns(CAPNP(), ws); // Let the delete finish. So now the last key in the first block is cached as a negative @@ -3473,8 +3510,9 @@ KJ_TEST("ActorCache listReverse() retry on failure") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux", limit = 4, reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "foo", value = "123"), - (key = "baz", value = "789")])) + stream + .call("values", + CAPNP(list = [ (key = "foo", value = "123"), (key = "baz", value = "789") ])) .expectReturns(CAPNP(), ws); }).thenThrow(KJ_EXCEPTION(DISCONNECTED, "oops")); @@ -3483,9 +3521,13 @@ KJ_TEST("ActorCache listReverse() retry on failure") { .withParams(CAPNP(start = "bar", end = "baz", limit = 2, reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { // Duplicates of earlier keys will be ignored. - stream.call("values", CAPNP(list = [(key = "foo", value = "IGNORE"), - (key = "baz", value = "IGNORE"), - (key = "bar", value = "456")])) + stream + .call("values", + CAPNP(list = + [ + (key = "foo", value = "IGNORE"), (key = "baz", value = "IGNORE"), + (key = "bar", value = "456") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -3633,11 +3675,15 @@ KJ_TEST("ActorCache LRU purge") { auto promise = expectUncached(test.get({"foo"_kj, "bar"_kj, "baz"_kj})); mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["bar", "baz", "foo"]), "stream"_kj) + .withParams(CAPNP(keys = [ "bar", "baz", "foo" ]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "456"), (key = "baz", value = "789"), + (key = "foo", value = "123") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -3768,10 +3814,13 @@ KJ_TEST("ActorCache lru evict entry with known-empty gaps") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789"), - (key = "corge", value = "555"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "456"), (key = "baz", value = "789"), + (key = "corge", value = "555"), (key = "foo", value = "123") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -3821,10 +3870,13 @@ KJ_TEST("ActorCache lru evict gap entry with known-empty gaps") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789"), - (key = "corge", value = "555"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "456"), (key = "baz", value = "789"), + (key = "corge", value = "555"), (key = "foo", value = "123") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -3870,10 +3922,13 @@ KJ_TEST("ActorCache lru evict entry with trailing known-empty gap (followed by E mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789"), - (key = "corge", value = "555"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "456"), (key = "baz", value = "789"), + (key = "corge", value = "555"), (key = "foo", value = "123") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -3925,10 +3980,13 @@ KJ_TEST("ActorCache timeout entry with known-empty gaps") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789"), - (key = "corge", value = "555"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "456"), (key = "baz", value = "789"), + (key = "corge", value = "555"), (key = "foo", value = "123") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -3963,7 +4021,6 @@ KJ_TEST("ActorCache timeout entry with known-empty gaps") { (void)expectUncached(test.get("fo")); } - KJ_TEST("ActorCache evictStale entire list with end marker") { ActorCacheTest test; auto& ws = test.ws; @@ -3979,10 +4036,13 @@ KJ_TEST("ActorCache evictStale entire list with end marker") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789"), - (key = "corge", value = "555"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "456"), (key = "baz", value = "789"), + (key = "corge", value = "555"), (key = "foo", value = "123") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -4015,11 +4075,13 @@ KJ_TEST("ActorCache purge everything while listing") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789")])) + stream + .call("values", + CAPNP(list = [ (key = "bar", value = "456"), (key = "baz", value = "789") ])) .expectReturns(CAPNP(), ws); - stream.call("values", CAPNP(list = [(key = "corge", value = "555"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = [ (key = "corge", value = "555"), (key = "foo", value = "123") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -4049,11 +4111,13 @@ KJ_TEST("ActorCache purge everything while listing; has previous entry") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789")])) + stream + .call("values", + CAPNP(list = [ (key = "bar", value = "456"), (key = "baz", value = "789") ])) .expectReturns(CAPNP(), ws); - stream.call("values", CAPNP(list = [(key = "corge", value = "555"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = [ (key = "corge", value = "555"), (key = "foo", value = "123") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -4067,11 +4131,8 @@ KJ_TEST("ActorCache purge everything while listing; has previous entry") { } KJ_TEST("ActorCache exceed hard limit on read") { - ActorCacheTest test({ - .monitorOutputGate = false, - .softLimit = 2 * ENTRY_SIZE, - .hardLimit = 2 * ENTRY_SIZE - }); + ActorCacheTest test( + {.monitorOutputGate = false, .softLimit = 2 * ENTRY_SIZE, .hardLimit = 2 * ENTRY_SIZE}); auto& ws = test.ws; auto& mockStorage = test.mockStorage; @@ -4084,8 +4145,9 @@ KJ_TEST("ActorCache exceed hard limit on read") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789")])) + stream + .call("values", + CAPNP(list = [ (key = "bar", value = "456"), (key = "baz", value = "789") ])) .expectReturns(CAPNP(), ws); KJ_ASSERT(!brokenPromise.poll(ws)); @@ -4107,32 +4169,29 @@ KJ_TEST("ActorCache exceed hard limit on read") { // The call will actually have been canceled when the first call failed. }).expectCanceled(); - KJ_EXPECT_THROW_MESSAGE("exceeded its memory limit due to overflowing the storage cache", - promise.wait(ws)); + KJ_EXPECT_THROW_MESSAGE( + "exceeded its memory limit due to overflowing the storage cache", promise.wait(ws)); } - KJ_EXPECT_THROW_MESSAGE("exceeded its memory limit due to overflowing the storage cache", - brokenPromise.wait(ws)); + KJ_EXPECT_THROW_MESSAGE( + "exceeded its memory limit due to overflowing the storage cache", brokenPromise.wait(ws)); } KJ_TEST("ActorCache exceed hard limit on write") { - ActorCacheTest test({ - .monitorOutputGate = false, - .softLimit = 2 * ENTRY_SIZE, - .hardLimit = 2 * ENTRY_SIZE - }); + ActorCacheTest test( + {.monitorOutputGate = false, .softLimit = 2 * ENTRY_SIZE, .hardLimit = 2 * ENTRY_SIZE}); auto& ws = test.ws; auto brokenPromise = test.gate.onBroken(); test.put("foo", "123"); test.put("bar", "456"); - KJ_EXPECT_THROW_MESSAGE("exceeded its memory limit due to overflowing the storage cache", - test.put("baz", "789")); + KJ_EXPECT_THROW_MESSAGE( + "exceeded its memory limit due to overflowing the storage cache", test.put("baz", "789")); KJ_ASSERT(brokenPromise.poll(ws)); - KJ_EXPECT_THROW_MESSAGE("exceeded its memory limit due to overflowing the storage cache", - brokenPromise.wait(ws)); + KJ_EXPECT_THROW_MESSAGE( + "exceeded its memory limit due to overflowing the storage cache", brokenPromise.wait(ws)); } // ======================================================================================= @@ -4218,9 +4277,13 @@ KJ_TEST("ActorCache skip cache") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "bar", value = "456"), - (key = "baz", value = "789"), - (key = "foo", value = "123")])) + stream + .call("values", + CAPNP(list = + [ + (key = "bar", value = "456"), (key = "baz", value = "789"), + (key = "foo", value = "123") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -4246,9 +4309,13 @@ KJ_TEST("ActorCache skip cache") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "bar", end = "qux", reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "foo", value = "123"), - (key = "baz", value = "789"), - (key = "bar", value = "456")])) + stream + .call("values", + CAPNP(list = + [ + (key = "foo", value = "123"), (key = "baz", value = "789"), + (key = "bar", value = "456") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -4289,9 +4356,7 @@ KJ_TEST("ActorCache transaction read-through") { { auto promise = expectUncached(eztxn.get("bar")); - mockStorage->expectCall("get", ws) - .withParams(CAPNP(key = "bar")) - .thenReturn(CAPNP()); + mockStorage->expectCall("get", ws).withParams(CAPNP(key = "bar")).thenReturn(CAPNP()); KJ_ASSERT(promise.wait(ws) == nullptr); KJ_ASSERT(expectCached(eztxn.get("bar")) == nullptr); } @@ -4300,10 +4365,11 @@ KJ_TEST("ActorCache transaction read-through") { auto promise = expectUncached(eztxn.get({"baz"_kj, "qux"_kj, "corge"_kj})); mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["baz", "corge", "qux"]), "stream"_kj) + .withParams(CAPNP(keys = [ "baz", "corge", "qux" ]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "baz", value = "456"), - (key = "qux", value = "789")])) + stream + .call("values", + CAPNP(list = [ (key = "baz", value = "456"), (key = "qux", value = "789") ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -4320,10 +4386,13 @@ KJ_TEST("ActorCache transaction read-through") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "a", end = "z", limit = 10), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "baz", value = "456"), - (key = "foo", value = "123"), - (key = "grault", value = "555"), - (key = "qux", value = "789")])) + stream + .call("values", + CAPNP(list = + [ + (key = "baz", value = "456"), (key = "foo", value = "123"), + (key = "grault", value = "555"), (key = "qux", value = "789") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -4362,10 +4431,9 @@ KJ_TEST("ActorCache transaction overlay changes") { .withParams(CAPNP(key = "grault")) .thenReturn(CAPNP(value = "555")); mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["baz", "garply"]), "stream"_kj) + .withParams(CAPNP(keys = [ "baz", "garply" ]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "baz", value = "456")])) - .expectReturns(CAPNP(), ws); + stream.call("values", CAPNP(list = [(key = "baz", value = "456")])).expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -4378,8 +4446,7 @@ KJ_TEST("ActorCache transaction overlay changes") { mockStorage->expectCall("getMultiple", ws) .withParams(CAPNP(keys = ["corge"]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [])) - .expectReturns(CAPNP(), ws); + stream.call("values", CAPNP(list = [])).expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -4392,21 +4459,24 @@ KJ_TEST("ActorCache transaction overlay changes") { { auto promise = expectUncached(eztxn.list("a", "z", 10)); - mockStorage->expectCall("list", ws) + mockStorage + ->expectCall("list", ws) // limit is adjusted by 3 because it could return values that have already been deleted // in the transaction. .withParams(CAPNP(start = "a", end = "z", limit = 13), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "baz", value = "456"), - (key = "foo", value = "123"), - (key = "grault", value = "555"), - (key = "qux", value = "789")])) + stream + .call("values", + CAPNP(list = + [ + (key = "baz", value = "456"), (key = "foo", value = "123"), + (key = "grault", value = "555"), (key = "qux", value = "789") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); - KJ_ASSERT(promise.wait(ws) == - kvs({{"bar", "654"}, {"foo", "321"}, {"qux", "987"}})); + KJ_ASSERT(promise.wait(ws) == kvs({{"bar", "654"}, {"foo", "321"}, {"qux", "987"}})); KJ_ASSERT(expectCached(eztxn.list("a", "z", 10)) == kvs({{"bar", "654"}, {"foo", "321"}, {"qux", "987"}})); @@ -4422,12 +4492,14 @@ KJ_TEST("ActorCache transaction overlay changes") { { auto mockTxn = mockStorage->expectCall("txn", ws).returnMock("transaction"); mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["grault", "baz"])) + .withParams(CAPNP(keys = [ "grault", "baz" ])) .thenReturn(CAPNP(numDeleted = 2)); mockTxn->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "321"), - (key = "bar", value = "654"), - (key = "qux", value = "987")])) + .withParams(CAPNP(entries = + [ + (key = "foo", value = "321"), (key = "bar", value = "654"), + (key = "qux", value = "987") + ])) .thenReturn(CAPNP()); mockTxn->expectCall("commit", ws).thenReturn(CAPNP()); mockTxn->expectDropped(ws); @@ -4448,10 +4520,13 @@ KJ_TEST("ActorCache transaction overlay changes precached") { mockStorage->expectCall("list", ws) .withParams(CAPNP(start = "a", end = "z", limit = 10, reverse = true), "stream"_kj) .useCallback("stream", [&](MockClient stream) { - stream.call("values", CAPNP(list = [(key = "qux", value = "789"), - (key = "grault", value = "555"), - (key = "foo", value = "123"), - (key = "baz", value = "456")])) + stream + .call("values", + CAPNP(list = + [ + (key = "qux", value = "789"), (key = "grault", value = "555"), + (key = "foo", value = "123"), (key = "baz", value = "456") + ])) .expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -4487,12 +4562,14 @@ KJ_TEST("ActorCache transaction overlay changes precached") { { auto mockTxn = mockStorage->expectCall("txn", ws).returnMock("transaction"); mockTxn->expectCall("delete", ws) - .withParams(CAPNP(keys = ["grault", "baz"])) + .withParams(CAPNP(keys = [ "grault", "baz" ])) .thenReturn(CAPNP(numDeleted = 2)); mockTxn->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "321"), - (key = "bar", value = "654"), - (key = "qux", value = "987")])) + .withParams(CAPNP(entries = + [ + (key = "foo", value = "321"), (key = "bar", value = "654"), + (key = "qux", value = "987") + ])) .thenReturn(CAPNP()); mockTxn->expectCall("commit", ws).thenReturn(CAPNP()); mockTxn->expectDropped(ws); @@ -4519,8 +4596,8 @@ KJ_TEST("ActorCache transaction output gate blocked during flush") { // Complete the transaction. { - auto inProgressFlush = mockStorage->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "123")])); + auto inProgressFlush = mockStorage->expectCall("put", ws).withParams( + CAPNP(entries = [(key = "foo", value = "123")])); // Still blocked until the flush completes. KJ_ASSERT(!gatePromise.poll(ws)); @@ -4579,8 +4656,8 @@ KJ_TEST("ActorCache transaction output gate bypass on one put but not the next") // Complete the transaction. { - auto inProgressFlush = mockStorage->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "123"), (key = "bar", value = "456")])); + auto inProgressFlush = mockStorage->expectCall("put", ws).withParams( + CAPNP(entries = [ (key = "foo", value = "123"), (key = "bar", value = "456") ])); // Still blocked until the flush completes. KJ_ASSERT(!gatePromise.poll(ws)); @@ -4610,12 +4687,10 @@ KJ_TEST("ActorCache transaction multiple put batches") { auto mockTxn = mockStorage->expectCall("txn", ws).returnMock("transaction"); mockTxn->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "123"), - (key = "bar", value = "456")])) + .withParams(CAPNP(entries = [ (key = "foo", value = "123"), (key = "bar", value = "456") ])) .thenReturn(CAPNP()); mockTxn->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "baz", value = "789"), - (key = "qux", value = "555")])) + .withParams(CAPNP(entries = [ (key = "baz", value = "789"), (key = "qux", value = "555") ])) .thenReturn(CAPNP()); mockTxn->expectCall("put", ws) .withParams(CAPNP(entries = [(key = "corge", value = "999")])) @@ -4624,7 +4699,6 @@ KJ_TEST("ActorCache transaction multiple put batches") { mockTxn->expectDropped(ws); } - KJ_TEST("ActorCache transaction multiple counted delete batches") { // Do a transaction with a big counted delete. The rpc getMultiple and delete should batch // according to maxKeysPerRpc. @@ -4651,20 +4725,21 @@ KJ_TEST("ActorCache transaction multiple counted delete batches") { eztxn.put("count3", "3"); } - auto deletePromise = eztxn.delete_( - {"count1"_kj, "count2"_kj, "count3"_kj, "count4"_kj, "count5"_kj}).get>(); + auto deletePromise = + eztxn.delete_({"count1"_kj, "count2"_kj, "count3"_kj, "count4"_kj, "count5"_kj}) + .get>(); - mockStorage->expectCall("getMultiple", ws) + mockStorage + ->expectCall("getMultiple", ws) // Note that this batch is smaller because "count2" was known to the actor cache. .withParams(CAPNP(keys = ["count1"]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { // Pretend that "count1" already exists but was not in the cache. - stream.call("values", CAPNP(list = [(key = "count1", value = "1")])) - .expectReturns(CAPNP(), ws); + stream.call("values", CAPNP(list = [(key = "count1", value = "1")])).expectReturns(CAPNP(), ws); stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["count4", "count5"]), "stream"_kj) + .withParams(CAPNP(keys = [ "count4", "count5" ]), "stream"_kj) .useCallback("stream", [&](MockClient stream) { stream.call("end", CAPNP()).expectReturns(CAPNP(), ws); }).expectCanceled(); @@ -4676,11 +4751,13 @@ KJ_TEST("ActorCache transaction multiple counted delete batches") { txn.commit(); auto mockTxn = mockStorage->expectCall("txn", ws).returnMock("transaction"); - mockTxn->expectCall("delete", ws) + mockTxn + ->expectCall("delete", ws) // "count3" comes first because it entered the transaction first. - .withParams(CAPNP(keys = ["count3", "count1"])) + .withParams(CAPNP(keys = [ "count3", "count1" ])) .thenReturn(CAPNP(numDeleted = 1)); - mockTxn->expectCall("delete", ws) + mockTxn + ->expectCall("delete", ws) // Neither "count4" or "count5" are deleted because we observed them in the get. .withParams(CAPNP(keys = ["count2"])) .thenReturn(CAPNP(numDeleted = 1)); @@ -4725,9 +4802,8 @@ KJ_TEST("ActorCache list stream cancellation") { { // We allocate `lru` on the heap to assist valgrind in being able to detect when it is used // after free. - auto lru = kj::heap(ActorCache::SharedLru::Options { - options.softLimit, options.hardLimit, options.staleTimeout, options.dirtyListByteLimit, - options.maxKeysPerRpc}); + auto lru = kj::heap(ActorCache::SharedLru::Options{options.softLimit, + options.hardLimit, options.staleTimeout, options.dirtyListByteLimit, options.maxKeysPerRpc}); OutputGate gate; ActorCache cache(mockClient, *lru, gate); @@ -4736,8 +4812,8 @@ KJ_TEST("ActorCache list stream cancellation") { auto promise = expectUncached(ezCache.get({"foo"_kj, "bar"_kj})); call = mockStorage->expectCall("getMultiple", ws) - .withParams(CAPNP(keys = ["bar", "foo"]), "stream"_kj) - .useCallback("stream", [&](MockClient stream) { + .withParams(CAPNP(keys = [ "bar", "foo" ]), "stream"_kj) + .useCallback("stream", [&](MockClient stream) { stream.call("values", CAPNP(list = [(key = "bar", value = "123")])) .expectReturns(CAPNP(), ws); listClient = kj::mv(stream); @@ -4747,7 +4823,8 @@ KJ_TEST("ActorCache list stream cancellation") { // outstanding, with unreported entries in it! } - KJ_ASSERT_NONNULL(listClient).call("values", CAPNP(list = [(key = "foo", value = "456")])) + KJ_ASSERT_NONNULL(listClient) + .call("values", CAPNP(list = [(key = "foo", value = "456")])) .expectThrows(kj::Exception::Type::DISCONNECTED, "canceled", ws); KJ_ASSERT_NONNULL(kj::mv(call)).expectCanceled(); @@ -4755,9 +4832,8 @@ KJ_TEST("ActorCache list stream cancellation") { { // We allocate `lru` on the heap to assist valgrind in being able to detect when it is used // after free. - auto lru = kj::heap(ActorCache::SharedLru::Options { - options.softLimit, options.hardLimit, options.staleTimeout, options.dirtyListByteLimit, - options.maxKeysPerRpc}); + auto lru = kj::heap(ActorCache::SharedLru::Options{options.softLimit, + options.hardLimit, options.staleTimeout, options.dirtyListByteLimit, options.maxKeysPerRpc}); OutputGate gate; ActorCache cache(mockClient, *lru, gate); @@ -4766,8 +4842,8 @@ KJ_TEST("ActorCache list stream cancellation") { auto promise = expectUncached(ezCache.list("bar", "qux")); call = mockStorage->expectCall("list", ws) - .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) - .useCallback("stream", [&](MockClient stream) { + .withParams(CAPNP(start = "bar", end = "qux"), "stream"_kj) + .useCallback("stream", [&](MockClient stream) { stream.call("values", CAPNP(list = [(key = "bar", value = "123")])) .expectReturns(CAPNP(), ws); listClient = kj::mv(stream); @@ -4777,7 +4853,8 @@ KJ_TEST("ActorCache list stream cancellation") { // outstanding, with unreported entries in it! } - KJ_ASSERT_NONNULL(listClient).call("values", CAPNP(list = [(key = "foo", value = "456")])) + KJ_ASSERT_NONNULL(listClient) + .call("values", CAPNP(list = [(key = "foo", value = "456")])) .expectThrows(kj::Exception::Type::DISCONNECTED, "canceled", ws); KJ_ASSERT_NONNULL(kj::mv(call)).expectCanceled(); @@ -4785,9 +4862,8 @@ KJ_TEST("ActorCache list stream cancellation") { { // We allocate `lru` on the heap to assist valgrind in being able to detect when it is used // after free. - auto lru = kj::heap(ActorCache::SharedLru::Options { - options.softLimit, options.hardLimit, options.staleTimeout, options.dirtyListByteLimit, - options.maxKeysPerRpc}); + auto lru = kj::heap(ActorCache::SharedLru::Options{options.softLimit, + options.hardLimit, options.staleTimeout, options.dirtyListByteLimit, options.maxKeysPerRpc}); OutputGate gate; ActorCache cache(mockClient, *lru, gate); @@ -4796,8 +4872,8 @@ KJ_TEST("ActorCache list stream cancellation") { auto promise = expectUncached(ezCache.listReverse("bar", "qux")); call = mockStorage->expectCall("list", ws) - .withParams(CAPNP(start = "bar", end = "qux", reverse = true), "stream"_kj) - .useCallback("stream", [&](MockClient stream) { + .withParams(CAPNP(start = "bar", end = "qux", reverse = true), "stream"_kj) + .useCallback("stream", [&](MockClient stream) { stream.call("values", CAPNP(list = [(key = "foo", value = "123")])) .expectReturns(CAPNP(), ws); listClient = kj::mv(stream); @@ -4807,7 +4883,8 @@ KJ_TEST("ActorCache list stream cancellation") { // outstanding, with unreported entries in it! } - KJ_ASSERT_NONNULL(listClient).call("values", CAPNP(list = [(key = "bar", value = "456")])) + KJ_ASSERT_NONNULL(listClient) + .call("values", CAPNP(list = [(key = "bar", value = "456")])) .expectThrows(kj::Exception::Type::DISCONNECTED, "canceled", ws); KJ_ASSERT_NONNULL(kj::mv(call)).expectCanceled(); } @@ -4846,8 +4923,7 @@ KJ_TEST("ActorCache alarm get/put") { { auto time = expectUncached(test.getAlarm()); - mockStorage->expectCall("getAlarm", ws) - .thenReturn(CAPNP(scheduledTimeMs = 0)); + mockStorage->expectCall("getAlarm", ws).thenReturn(CAPNP(scheduledTimeMs = 0)); KJ_ASSERT(time.wait(ws) == kj::none); } @@ -4869,9 +4945,7 @@ KJ_TEST("ActorCache alarm get/put") { mockTxn->expectCall("put", ws) .withParams(CAPNP(entries = [(key = "foo", value = "bar")])) .thenReturn(CAPNP()); - mockTxn->expectCall("setAlarm", ws) - .withParams(CAPNP(scheduledTimeMs = 1)) - .thenReturn(CAPNP()); + mockTxn->expectCall("setAlarm", ws).withParams(CAPNP(scheduledTimeMs = 1)).thenReturn(CAPNP()); mockTxn->expectCall("commit", ws).thenReturn(CAPNP()); mockTxn->expectDropped(ws); } @@ -4914,9 +4988,7 @@ KJ_TEST("ActorCache alarm get/put") { { // Test that alarm handler handle clears alarm when dropped with no writes - { - auto maybeWrite = KJ_ASSERT_NONNULL(test.cache.armAlarmHandler(oneMs, false)); - } + { auto maybeWrite = KJ_ASSERT_NONNULL(test.cache.armAlarmHandler(oneMs, false)); } mockStorage->expectCall("deleteAlarm", ws) .withParams(CAPNP(timeToDeleteMs = 1)) .thenReturn(CAPNP(deleted = true)); @@ -4939,9 +5011,7 @@ KJ_TEST("ActorCache alarm get/put") { test.setAlarm(oneMs); // Test that alarm handler handle does not cache delete when it fails - { - auto maybeWrite = KJ_ASSERT_NONNULL(test.cache.armAlarmHandler(oneMs, false)); - } + { auto maybeWrite = KJ_ASSERT_NONNULL(test.cache.armAlarmHandler(oneMs, false)); } mockStorage->expectCall("deleteAlarm", ws) .withParams(CAPNP(timeToDeleteMs = 1)) .thenReturn(CAPNP(deleted = false)); @@ -4950,9 +5020,7 @@ KJ_TEST("ActorCache alarm get/put") { { // Test that alarm handler handle does not cache alarm delete when noCache == true - { - auto maybeWrite = KJ_ASSERT_NONNULL(test.cache.armAlarmHandler(twoMs, true)); - } + { auto maybeWrite = KJ_ASSERT_NONNULL(test.cache.armAlarmHandler(twoMs, true)); } mockStorage->expectCall("deleteAlarm", ws) .withParams(CAPNP(timeToDeleteMs = 2)) .thenReturn(CAPNP(deleted = true)); @@ -4962,8 +5030,7 @@ KJ_TEST("ActorCache alarm get/put") { { auto time = expectUncached(test.getAlarm()); - mockStorage->expectCall("getAlarm", ws) - .thenReturn(CAPNP(scheduledTimeMs = 0)); + mockStorage->expectCall("getAlarm", ws).thenReturn(CAPNP(scheduledTimeMs = 0)); KJ_ASSERT(time.wait(ws) == kj::none); } @@ -4977,8 +5044,7 @@ KJ_TEST("ActorCache uncached nonnull alarm get") { auto time = expectUncached(test.getAlarm()); auto oneMs = 1 * kj::MILLISECONDS + kj::UNIX_EPOCH; - mockStorage->expectCall("getAlarm", ws) - .thenReturn(CAPNP(scheduledTimeMs = 1)); + mockStorage->expectCall("getAlarm", ws).thenReturn(CAPNP(scheduledTimeMs = 1)); KJ_ASSERT(time.wait(ws) == oneMs); } @@ -4993,8 +5059,7 @@ KJ_TEST("ActorCache alarm delete when flush fails") { { auto time = expectUncached(test.getAlarm()); - mockStorage->expectCall("getAlarm", ws) - .thenReturn(CAPNP(scheduledTimeMs = 1)); + mockStorage->expectCall("getAlarm", ws).thenReturn(CAPNP(scheduledTimeMs = 1)); KJ_ASSERT(time.wait(ws) == oneMs); } @@ -5013,7 +5078,7 @@ KJ_TEST("ActorCache alarm delete when flush fails") { KJ_ASSERT(time == kj::none); } - for(auto i = 0; i < 2; i++) { + for (auto i = 0; i < 2; i++) { mockStorage->expectCall("deleteAlarm", ws) .withParams(CAPNP(timeToDeleteMs = 1)) .thenThrow(KJ_EXCEPTION(DISCONNECTED, "foo")); @@ -5030,8 +5095,7 @@ KJ_TEST("ActorCache alarm delete when flush fails") { { auto time = expectUncached(test.getAlarm()); - mockStorage->expectCall("getAlarm", ws) - .thenReturn(CAPNP(scheduledTimeMs = 10)); + mockStorage->expectCall("getAlarm", ws).thenReturn(CAPNP(scheduledTimeMs = 10)); KJ_ASSERT(time.wait(ws) == 10 * kj::MILLISECONDS + kj::UNIX_EPOCH); } @@ -5110,77 +5174,77 @@ KJ_TEST("ActorCache can wait for flush") { // Join in on a simple put. test.put("foo", "bar"); - verify([&](){ - return InFlightRequest { - .op = mockStorage->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "bar")])), + verify( + [&]() { + return InFlightRequest{ + .op = mockStorage->expectCall("put", ws).withParams( + CAPNP(entries = [(key = "foo", value = "bar")])), }; - }, [&](auto req) { - kj::mv(req.op).thenReturn(CAPNP()); - }, { - .skipSecondOperation = false, - }); + }, [&](auto req) { kj::mv(req.op).thenReturn(CAPNP()); }, + { + .skipSecondOperation = false, + }); } { // Join in on a delete. test.delete_("foo"); - verify([&](){ - return InFlightRequest { + verify( + [&]() { + return InFlightRequest{ .op = mockStorage->expectCall("delete", ws).withParams(CAPNP(keys = ["foo"])), }; - }, [&](auto req) { - kj::mv(req.op).thenReturn(CAPNP(numDeleted = 1)); - }, { - .skipSecondOperation = false, - }); + }, [&](auto req) { kj::mv(req.op).thenReturn(CAPNP(numDeleted = 1)); }, + { + .skipSecondOperation = false, + }); } { // Join in on a simple put with allowUnconfirmed. test.put("foo", "baz", ActorCacheWriteOptions{.allowUnconfirmed = true}); - verify([&](){ - return InFlightRequest { - .op = mockStorage->expectCall("put", ws) - .withParams(CAPNP(entries = [(key = "foo", value = "baz")])), + verify( + [&]() { + return InFlightRequest{ + .op = mockStorage->expectCall("put", ws).withParams( + CAPNP(entries = [(key = "foo", value = "baz")])), }; - }, [&](auto req) { - kj::mv(req.op).thenReturn(CAPNP()); - }, { - .skipSecondOperation = false, - }); + }, [&](auto req) { kj::mv(req.op).thenReturn(CAPNP()); }, + { + .skipSecondOperation = false, + }); } { // Join in on a delete with allowUnconfirmed. test.delete_("foo", ActorCacheWriteOptions{.allowUnconfirmed = true}); - verify([&](){ - return InFlightRequest { + verify( + [&]() { + return InFlightRequest{ .op = mockStorage->expectCall("delete", ws).withParams(CAPNP(keys = ["foo"])), }; - }, [&](auto req) { - kj::mv(req.op).thenReturn(CAPNP(numDeleted = 1)); - }, { - .skipSecondOperation = false, - }); + }, [&](auto req) { kj::mv(req.op).thenReturn(CAPNP(numDeleted = 1)); }, + { + .skipSecondOperation = false, + }); } { // Join in on a scheduled setAlarm. test.setAlarm(1 * kj::MILLISECONDS + kj::UNIX_EPOCH); - verify([&](){ - return InFlightRequest { + verify( + [&]() { + return InFlightRequest{ .op = mockStorage->expectCall("setAlarm", ws).withParams(CAPNP(scheduledTimeMs = 1)), }; - }, [&](auto req) { - kj::mv(req.op).thenReturn(CAPNP()); - }, { - .skipSecondOperation = false, - }); + }, [&](auto req) { kj::mv(req.op).thenReturn(CAPNP()); }, + { + .skipSecondOperation = false, + }); } { @@ -5188,52 +5252,51 @@ KJ_TEST("ActorCache can wait for flush") { test.setAlarm( 2 * kj::MILLISECONDS + kj::UNIX_EPOCH, ActorCacheWriteOptions{.allowUnconfirmed = true}); - verify([&](){ - return InFlightRequest { + verify( + [&]() { + return InFlightRequest{ .op = mockStorage->expectCall("setAlarm", ws).withParams(CAPNP(scheduledTimeMs = 2)), }; - }, [&](auto req) { - kj::mv(req.op).thenReturn(CAPNP()); - }, { - .skipSecondOperation = false, - }); + }, [&](auto req) { kj::mv(req.op).thenReturn(CAPNP()); }, + { + .skipSecondOperation = false, + }); } { // Join in on a scheduled deleteAll. test.cache.deleteAll(ActorCacheWriteOptions{.allowUnconfirmed = false}); - verify([&](){ - return InFlightRequest { + verify( + [&]() { + return InFlightRequest{ .op = mockStorage->expectCall("deleteAll", ws).withParams(CAPNP()), }; - }, [&](auto req) { - kj::mv(req.op).thenReturn(CAPNP()); - }, { - // We can't test the second operation because deleteAll immediately follows up with any puts - // that happened while it was in flight. This means that we invoke the mock twice in the same - // promise chain without being able to set up exceptions in time. - .skipSecondOperation = true, - }); + }, [&](auto req) { kj::mv(req.op).thenReturn(CAPNP()); }, + { + // We can't test the second operation because deleteAll immediately follows up with any puts + // that happened while it was in flight. This means that we invoke the mock twice in the same + // promise chain without being able to set up exceptions in time. + .skipSecondOperation = true, + }); } { // Join in on a scheduled deleteAll with allowUnconfirmed. test.cache.deleteAll(ActorCacheWriteOptions{.allowUnconfirmed = true}); - verify([&](){ - return InFlightRequest { + verify( + [&]() { + return InFlightRequest{ .op = mockStorage->expectCall("deleteAll", ws).withParams(CAPNP()), }; - }, [&](auto req) { - kj::mv(req.op).thenReturn(CAPNP()); - }, { - .skipSecondOperation = true, - }); + }, [&](auto req) { kj::mv(req.op).thenReturn(CAPNP()); }, + { + .skipSecondOperation = true, + }); } } - KJ_TEST("ActorCache can shutdown") { // This test confirms that `shutdown()` stops scheduled flushes but does not stop in-flight // flushes. It also confirms that `shutdown()` prevents future operations. @@ -5301,18 +5364,18 @@ KJ_TEST("ActorCache can shutdown") { verifyWithOptions(beforeShutdown, afterShutdown, {.maybeError = KJ_EXCEPTION(FAILED, "Nope.")}); }; - verify([](ActorCacheTest& test){ + verify([](ActorCacheTest& test) { // Do nothing and expect nothing! return BeforeShutdownResult{ .maybeReq = kj::none, .shouldBreakOutputGate = false, }; - }, [](ActorCacheTest& test, kj::Maybe){ + }, [](ActorCacheTest& test, kj::Maybe) { // Nothing should have made it to storage. test.mockStorage->expectNoActivity(test.ws); }); - verify([](ActorCacheTest& test){ + verify([](ActorCacheTest& test) { // Do a confirmed put (which schedules a flush). test.put("foo", "bar", {.allowUnconfirmed = false}); @@ -5321,12 +5384,12 @@ KJ_TEST("ActorCache can shutdown") { .maybeReq = kj::none, .shouldBreakOutputGate = true, }; - }, [](ActorCacheTest& test, kj::Maybe){ + }, [](ActorCacheTest& test, kj::Maybe) { // Nothing should have made it to storage. test.mockStorage->expectNoActivity(test.ws); }); - verify([](ActorCacheTest& test){ + verify([](ActorCacheTest& test) { // Do an unconfirmed put (which schedules a flush). test.put("foo", "bar", {.allowUnconfirmed = true}); @@ -5335,7 +5398,7 @@ KJ_TEST("ActorCache can shutdown") { .maybeReq = kj::none, .shouldBreakOutputGate = true, }; - }, [](ActorCacheTest& test, kj::Maybe){ + }, [](ActorCacheTest& test, kj::Maybe) { // Nothing should have made it to storage. test.mockStorage->expectNoActivity(test.ws); }); @@ -5345,18 +5408,19 @@ KJ_TEST("ActorCache can shutdown") { test.put("foo", "bar", {.allowUnconfirmed = false}); auto op = test.mockStorage->expectCall("put", test.ws) - .withParams(CAPNP(entries = [(key = "foo", value = "bar")])); + .withParams(CAPNP(entries = [(key = "foo", value = "bar")])); auto promise = KJ_REQUIRE_NONNULL(test.cache.onNoPendingFlush()); KJ_EXPECT(!promise.poll(test.ws)); return BeforeShutdownResult{ - .maybeReq = InFlightRequest{ - .op = kj::mv(op), - .promise = kj::mv(promise), - }, + .maybeReq = + InFlightRequest{ + .op = kj::mv(op), + .promise = kj::mv(promise), + }, .shouldBreakOutputGate = false, }; - }, [](ActorCacheTest& test, kj::Maybe maybeReq){ + }, [](ActorCacheTest& test, kj::Maybe maybeReq) { // Finish the storage response and wait to see our pre-shutdown in-flight flush finish. auto req = KJ_ASSERT_NONNULL(kj::mv(maybeReq)); kj::mv(req.op).thenReturn(CAPNP()); @@ -5366,24 +5430,24 @@ KJ_TEST("ActorCache can shutdown") { test.mockStorage->expectNoActivity(test.ws); }); - verify([](ActorCacheTest& test) { // Do an unconfirmed put and wait for it to be in-flight. test.put("foo", "bar", {.allowUnconfirmed = true}); auto op = test.mockStorage->expectCall("put", test.ws) - .withParams(CAPNP(entries = [(key = "foo", value = "bar")])); + .withParams(CAPNP(entries = [(key = "foo", value = "bar")])); auto promise = KJ_REQUIRE_NONNULL(test.cache.onNoPendingFlush()); KJ_EXPECT(!promise.poll(test.ws)); return BeforeShutdownResult{ - .maybeReq = InFlightRequest{ - .op = kj::mv(op), - .promise = kj::mv(promise), - }, + .maybeReq = + InFlightRequest{ + .op = kj::mv(op), + .promise = kj::mv(promise), + }, .shouldBreakOutputGate = false, }; - }, [](ActorCacheTest& test, kj::Maybe maybeReq){ + }, [](ActorCacheTest& test, kj::Maybe maybeReq) { // Finish the storage response and wait to see our pre-shutdown in-flight flush finish. auto req = KJ_ASSERT_NONNULL(kj::mv(maybeReq)); kj::mv(req.op).thenReturn(CAPNP()); diff --git a/src/workerd/io/actor-cache.c++ b/src/workerd/io/actor-cache.c++ index 9f8507147c6..e2023a10f83 100644 --- a/src/workerd/io/actor-cache.c++ +++ b/src/workerd/io/actor-cache.c++ @@ -39,10 +39,13 @@ auto recordStorageWrite(ActorCache::Hooks& hooks, const kj::MonotonicClock& cloc } // namespace - -ActorCache::ActorCache(rpc::ActorStorage::Stage::Client storage, const SharedLru& lru, - OutputGate& gate, Hooks& hooks) - : storage(kj::mv(storage)), lru(lru), gate(gate), hooks(hooks), clock(kj::systemPreciseMonotonicClock()), +ActorCache::ActorCache( + rpc::ActorStorage::Stage::Client storage, const SharedLru& lru, OutputGate& gate, Hooks& hooks) + : storage(kj::mv(storage)), + lru(lru), + gate(gate), + hooks(hooks), + clock(kj::systemPreciseMonotonicClock()), currentValues(lru.cleanList.lockExclusive()) {} ActorCache::~ActorCache() noexcept(false) { @@ -59,7 +62,9 @@ void ActorCache::clear(Lock& lock) { } ActorCache::Entry::Entry(ActorCache& cache, Key key, Value value) - : maybeCache(cache), key(kj::mv(key)), value(kj::mv(value)), + : maybeCache(cache), + key(kj::mv(key)), + value(kj::mv(value)), valueStatus(EntryValueStatus::PRESENT) { KJ_IF_SOME(c, maybeCache) { c.lru.size.fetch_add(size(), std::memory_order_relaxed); @@ -67,19 +72,23 @@ ActorCache::Entry::Entry(ActorCache& cache, Key key, Value value) } ActorCache::Entry::Entry(ActorCache& cache, Key key, EntryValueStatus valueStatus) - : maybeCache(cache), key(kj::mv(key)), valueStatus(valueStatus) { - KJ_IASSERT( - valueStatus != EntryValueStatus::PRESENT, - "Pass a serialized empty v8 value if you want a present but empty entry!"); + : maybeCache(cache), + key(kj::mv(key)), + valueStatus(valueStatus) { + KJ_IASSERT(valueStatus != EntryValueStatus::PRESENT, + "Pass a serialized empty v8 value if you want a present but empty entry!"); KJ_IF_SOME(c, maybeCache) { c.lru.size.fetch_add(size(), std::memory_order_relaxed); } } ActorCache::Entry::Entry(Key key, Value value) - : key(kj::mv(key)), value(kj::mv(value)), valueStatus(EntryValueStatus::PRESENT) {} + : key(kj::mv(key)), + value(kj::mv(value)), + valueStatus(EntryValueStatus::PRESENT) {} ActorCache::Entry::Entry(Key key, EntryValueStatus valueStatus) - : key(kj::mv(key)), valueStatus(valueStatus) {} + : key(kj::mv(key)), + valueStatus(valueStatus) {} ActorCache::Entry::~Entry() noexcept(false) { KJ_IF_SOME(c, maybeCache) { @@ -89,13 +98,13 @@ ActorCache::Entry::~Entry() noexcept(false) { if (KJ_UNLIKELY(before < size)) { // underflow -- shouldn't happen, but just in case, let's fix - KJ_LOG(ERROR, "SharedLru size tracking inconsistency detected", - before, size, kj::getStackTrace()); + KJ_LOG(ERROR, "SharedLru size tracking inconsistency detected", before, size, + kj::getStackTrace()); c.lru.size.store(0, std::memory_order_relaxed); } if (link.isLinked()) { - switch(getSyncStatus()) { + switch (getSyncStatus()) { case EntrySyncStatus::CLEAN: { KJ_LOG(WARNING, "Entry destructed while still in the clean list"); break; @@ -122,7 +131,8 @@ ActorCache::SharedLru::~SharedLru() noexcept(false) { KJ_REQUIRE(cleanList.getWithoutLock().empty(), "ActorCache::SharedLru destroyed while an ActorCache still exists?"); if (size.load(std::memory_order_relaxed) != 0) { - KJ_LOG(ERROR, "SharedLru destroyed while cache entries still exist, " + KJ_LOG(ERROR, + "SharedLru destroyed while cache entries still exist, " "this will lead to use-after-free"); } } @@ -172,11 +182,11 @@ kj::Maybe> ActorCache::armAlarmHandler(kj::Date scheduledTime, boo } if (alarmDeleteNeeded) { - currentAlarmTime = DeferredAlarmDelete { + currentAlarmTime = DeferredAlarmDelete{ .status = DeferredAlarmDelete::Status::WAITING, .timeToDelete = scheduledTime, .noCache = noCache, - }; + }; } static const DeferredAlarmDeleter disposer; return kj::Own(this, disposer); @@ -184,11 +194,9 @@ kj::Maybe> ActorCache::armAlarmHandler(kj::Date scheduledTime, boo void ActorCache::cancelDeferredAlarmDeletion() { KJ_IF_SOME(deferredDelete, currentAlarmTime.tryGet()) { - currentAlarmTime = KnownAlarmTime { - .status = KnownAlarmTime::Status::CLEAN, + currentAlarmTime = KnownAlarmTime{.status = KnownAlarmTime::Status::CLEAN, .time = deferredDelete.timeToDelete, - .noCache = deferredDelete.noCache - }; + .noCache = deferredDelete.noCache}; } } @@ -361,7 +369,7 @@ void ActorCache::verifyConsistencyForTest() { } prevKey = entry->key; auto& key = entry->key; - switch(entry->getValueStatus()) { + switch (entry->getValueStatus()) { case EntryValueStatus::ABSENT: { KJ_ASSERT(!prevGapIsKnownEmpty || !entry->gapIsKnownEmpty, "clean negative entry in the middle of a known-empty gap is redundant", key); @@ -372,8 +380,7 @@ void ActorCache::verifyConsistencyForTest() { break; } case EntryValueStatus::UNKNOWN: { - KJ_ASSERT(!entry->gapIsKnownEmpty, - "entry can't be followed by known-empty gap", key); + KJ_ASSERT(!entry->gapIsKnownEmpty, "entry can't be followed by known-empty gap", key); break; } } @@ -389,8 +396,8 @@ void ActorCache::verifyConsistencyForTest() { // ======================================================================================= // read operations -kj::OneOf, kj::Promise>> - ActorCache::get(Key key, ReadOptions options) { +kj::OneOf, kj::Promise>> ActorCache::get( + Key key, ReadOptions options) { options.noCache = options.noCache || lru.options.noCache; requireNotTerminal(); @@ -407,12 +414,11 @@ kj::OneOf, kj::Promise } } -auto ActorCache::getImpl(kj::Own entry, ReadOptions options) - -> kj::Promise> { +auto ActorCache::getImpl( + kj::Own entry, ReadOptions options) -> kj::Promise> { auto response = co_await scheduleStorageRead( [key = entry->key.asBytes()](rpc::ActorStorage::Operations::Client client) { - auto req = client.getRequest( - capnp::MessageSize { 4 + key.size() / sizeof(capnp::word), 0 }); + auto req = client.getRequest(capnp::MessageSize{4 + key.size() / sizeof(capnp::word), 0}); req.setKey(key); return req.send().dropPipeline(); }); @@ -429,12 +435,15 @@ auto ActorCache::getImpl(kj::Own entry, ReadOptions options) class ActorCache::GetMultiStreamImpl final: public rpc::ActorStorage::ListStream::Server { public: - GetMultiStreamImpl(ActorCache& cache, kj::Vector> cachedEntries, - kj::Vector keysToFetchParam, - kj::Own> fulfiller, - const ReadOptions& options) - : cache(cache), cachedEntries(kj::mv(cachedEntries)), - keysToFetch(kj::mv(keysToFetchParam)), fulfiller(kj::mv(fulfiller)), + GetMultiStreamImpl(ActorCache& cache, + kj::Vector> cachedEntries, + kj::Vector keysToFetchParam, + kj::Own> fulfiller, + const ReadOptions& options) + : cache(cache), + cachedEntries(kj::mv(cachedEntries)), + keysToFetch(kj::mv(keysToFetchParam)), + fulfiller(kj::mv(fulfiller)), options(options) { nextExpectedKey = keysToFetch.begin(); } @@ -465,8 +474,8 @@ public: // This may be a duplicate due to a retry. Ignore it. break; } else if (key == *nextExpectedKey) { - fetchedEntries.add(cache.addReadResultToCache( - lock, kj::mv(*nextExpectedKey), kv.getValue(), options)); + fetchedEntries.add( + cache.addReadResultToCache(lock, kj::mv(*nextExpectedKey), kv.getValue(), options)); ++nextExpectedKey; break; } @@ -527,8 +536,8 @@ public: // in the foot. We do, however, want to produce a consistent ordering for reproducibility's // sake, but any consistent ordering will due. Sorted order is as good as anything else, and // happens to be nice and easy for us. - fulfiller->fulfill(GetResultList( - kj::mv(cachedEntries), kj::mv(fetchedEntries), GetResultList::FORWARD)); + fulfiller->fulfill( + GetResultList(kj::mv(cachedEntries), kj::mv(fetchedEntries), GetResultList::FORWARD)); } // Indicates that the operation is being canceled. Proactively drops all entries. This @@ -550,8 +559,8 @@ public: ReadOptions options; }; -kj::OneOf> - ActorCache::get(kj::Array keys, ReadOptions options) { +kj::OneOf> ActorCache::get( + kj::Array keys, ReadOptions options) { options.noCache = options.noCache || lru.options.noCache; requireNotTerminal(); @@ -563,13 +572,13 @@ kj::OneOf> kj::Vector keysToFetch(keys.size()); // Keys that were not satisfied from cache. - capnp::MessageSize sizeHint { 4, 1 }; + capnp::MessageSize sizeHint{4, 1}; { auto lock = lru.cleanList.lockExclusive(); for (auto& key: keys) { auto entry = findInCache(lock, key, options); - switch(entry->getValueStatus()) { + switch (entry->getValueStatus()) { case EntryValueStatus::PRESENT: case EntryValueStatus::ABSENT: { cachedEntries.add(kj::mv(entry)); @@ -591,22 +600,21 @@ kj::OneOf> auto paf = kj::newPromiseAndFulfiller(); auto streamServer = kj::heap( - *this, kj::mv(cachedEntries), kj::mv(keysToFetch), kj::mv(paf.fulfiller), - options); + *this, kj::mv(cachedEntries), kj::mv(keysToFetch), kj::mv(paf.fulfiller), options); auto& streamServerRef = *streamServer; rpc::ActorStorage::ListStream::Client streamClient = kj::mv(streamServer); auto sendPromise = scheduleStorageRead( - [sizeHint,streamClient,&streamServerRef] - (rpc::ActorStorage::Operations::Client client) mutable -> kj::Promise { + [sizeHint, streamClient, &streamServerRef]( + rpc::ActorStorage::Operations::Client client) mutable -> kj::Promise { if (streamServerRef.nextExpectedKey == streamServerRef.keysToFetch.end()) { // No more keys expected, must have finished listing on a previous try. return kj::READY_NOW; } auto req = client.getMultipleRequest(sizeHint); - auto keysToFetch = kj::arrayPtr(streamServerRef.nextExpectedKey, - streamServerRef.keysToFetch.end()); + auto keysToFetch = + kj::arrayPtr(streamServerRef.nextExpectedKey, streamServerRef.keysToFetch.end()); auto list = req.initKeys(keysToFetch.size()); for (auto i: kj::indices(keysToFetch)) { list.set(i, keysToFetch[i].asBytes()); @@ -618,8 +626,7 @@ kj::OneOf> // Wait on the RPC only until stream.end() is called, then report the results. We prevent // `stream` from being destroyed until we have a result so that if the RPC throws an exception, // we don't accidentally report "PromiseFulfiller not fulfilled" instead of the exception. - auto promise = sendPromise - .then([&streamServerRef]() -> kj::Promise { + auto promise = sendPromise.then([&streamServerRef]() -> kj::Promise { if (streamServerRef.fulfiller->isWaiting()) { return KJ_EXCEPTION(FAILED, "getMultiple() never called stream.end()"); } else { @@ -628,9 +635,8 @@ kj::OneOf> } }); return paf.promise.exclusiveJoin(kj::mv(promise)) - .attach(kj::defer([client = kj::mv(streamClient), &streamServerRef]() { - streamServerRef.cancel(); - })); + .attach(kj::defer( + [client = kj::mv(streamClient), &streamServerRef]() { streamServerRef.cancel(); })); } kj::OneOf, kj::Promise>> ActorCache::getAlarm( @@ -641,9 +647,9 @@ kj::OneOf, kj::Promise>> ActorCache::get // Else schedule alarm read KJ_SWITCH_ONEOF(currentAlarmTime) { KJ_CASE_ONEOF(entry, ActorCache::DeferredAlarmDelete) { - // An alarm handler is currently running, and a new alarm time has not been set yet. - // We need to return that there is no alarm. - return kj::Maybe(kj::none); + // An alarm handler is currently running, and a new alarm time has not been set yet. + // We need to return that there is no alarm. + return kj::Maybe(kj::none); } KJ_CASE_ONEOF(entry, ActorCache::KnownAlarmTime) { return entry.time; @@ -652,9 +658,9 @@ kj::OneOf, kj::Promise>> ActorCache::get return scheduleStorageRead([](rpc::ActorStorage::Operations::Client client) { auto req = client.getAlarmRequest(); return req.send().dropPipeline(); - }).then([this, options] - (capnp::Response response) mutable - -> kj::Maybe { + }) + .then([this, options](capnp::Response + response) mutable -> kj::Maybe { auto scheduledTimeMs = response.getScheduledTimeMs(); auto result = [&]() -> kj::Maybe { if (scheduledTimeMs == 0) { @@ -671,10 +677,8 @@ kj::OneOf, kj::Promise>> ActorCache::get // If it was created by a setAlarm(), then it is actually fresher. If it was created // by a concurrent getAlarm(), then it should be exactly the same time. - currentAlarmTime = ActorCache::KnownAlarmTime { - ActorCache::KnownAlarmTime::Status::CLEAN, - result - }; + currentAlarmTime = + ActorCache::KnownAlarmTime{ActorCache::KnownAlarmTime::Status::CLEAN, result}; } return result; @@ -733,15 +737,24 @@ inline auto seekOrEnd(auto& map, kj::Maybe key) { class ActorCache::ForwardListStreamImpl final: public rpc::ActorStorage::ListStream::Server { public: - ForwardListStreamImpl(ActorCache& cache, Key beginKey, kj::Maybe endKey, - kj::Vector> cachedEntries, - kj::Own> fulfiller, - kj::Maybe originalLimit, kj::Maybe adjustedLimit, - bool beginKeyIsKnown, const ReadOptions& options) - : cache(cache), beginKey(kj::mv(beginKey)), endKey(kj::mv(endKey)), - cachedEntries(kj::mv(cachedEntries)), fulfiller(kj::mv(fulfiller)), - originalLimit(originalLimit), adjustedLimit(adjustedLimit), - beginKeyIsKnown(beginKeyIsKnown), options(options) {} + ForwardListStreamImpl(ActorCache& cache, + Key beginKey, + kj::Maybe endKey, + kj::Vector> cachedEntries, + kj::Own> fulfiller, + kj::Maybe originalLimit, + kj::Maybe adjustedLimit, + bool beginKeyIsKnown, + const ReadOptions& options) + : cache(cache), + beginKey(kj::mv(beginKey)), + endKey(kj::mv(endKey)), + cachedEntries(kj::mv(cachedEntries)), + fulfiller(kj::mv(fulfiller)), + originalLimit(originalLimit), + adjustedLimit(adjustedLimit), + beginKeyIsKnown(beginKeyIsKnown), + options(options) {} kj::Promise values(ValuesContext context) override { if (!fulfiller->isWaiting()) { @@ -829,8 +842,8 @@ public: } void fulfill() { - fulfiller->fulfill(GetResultList(kj::mv(cachedEntries), kj::mv(fetchedEntries), - GetResultList::FORWARD, originalLimit)); + fulfiller->fulfill(GetResultList( + kj::mv(cachedEntries), kj::mv(fetchedEntries), GetResultList::FORWARD, originalLimit)); }; // Mark the start of the list operation will a null entry, because we did not see it listed. @@ -891,9 +904,8 @@ public: ReadOptions options; }; -kj::OneOf> - ActorCache::list(Key beginKey, kj::Maybe endKey, - kj::Maybe limit, ReadOptions options) { +kj::OneOf> ActorCache::list( + Key beginKey, kj::Maybe endKey, kj::Maybe limit, ReadOptions options) { options.noCache = options.noCache || lru.options.noCache; requireNotTerminal(); @@ -977,14 +989,15 @@ kj::OneOf> // may still be DIRTY so won't be returned when we list the database. Later on we'll merge the // entries we find in cache with those we get from disk. for (; iter != ordered.end() && iter->get()->key < endKey && - positiveCount < limit.orDefault(kj::maxValue); ++iter) { + positiveCount < limit.orDefault(kj::maxValue); + ++iter) { Entry& entry = **iter; if (!options.noCache) { touchEntry(lock, entry); } - switch(entry.getValueStatus()) { + switch (entry.getValueStatus()) { case EntryValueStatus::ABSENT: { cachedEntries.add(kj::atomicAddRef(entry)); if (storageListStart != kj::none && entry.isDirty()) { @@ -1028,27 +1041,26 @@ kj::OneOf> return GetResultList(kj::mv(cachedEntries), {}, GetResultList::FORWARD, limit); } - auto adjustedLimit = limit.map([&](uint orig) { - return orig + limitAdjustment - knownPrefixSize; - }); + auto adjustedLimit = + limit.map([&](uint orig) { return orig + limitAdjustment - knownPrefixSize; }); auto paf = kj::newPromiseAndFulfiller(); - auto streamServer = kj::heap( - *this, cloneKey(KJ_ASSERT_NONNULL(storageListStart)), kj::mv(endKey), - kj::mv(cachedEntries), kj::mv(paf.fulfiller), limit, adjustedLimit, - storageListStartIsKnown, options); + auto streamServer = kj::heap(*this, + cloneKey(KJ_ASSERT_NONNULL(storageListStart)), kj::mv(endKey), kj::mv(cachedEntries), + kj::mv(paf.fulfiller), limit, adjustedLimit, storageListStartIsKnown, options); auto& streamServerRef = *streamServer; rpc::ActorStorage::ListStream::Client streamClient = kj::mv(streamServer); auto sendPromise = scheduleStorageRead( - [&streamServerRef,streamClient] - (rpc::ActorStorage::Operations::Client client) mutable -> kj::Promise { - auto req = client.listRequest(capnp::MessageSize { - 8 + streamServerRef.beginKey.size() / sizeof(capnp::word) + - streamServerRef.endKey - .map([](KeyPtr k) { return k.size() / sizeof(capnp::word); }) - .orDefault(0), 1 }); + [&streamServerRef, streamClient]( + rpc::ActorStorage::Operations::Client client) mutable -> kj::Promise { + auto req = client.listRequest( + capnp::MessageSize{8 + streamServerRef.beginKey.size() / sizeof(capnp::word) + + streamServerRef.endKey.map([](KeyPtr k) { + return k.size() / sizeof(capnp::word); + }).orDefault(0), + 1}); if (streamServerRef.beginKeyIsKnown) { // `streamServerRef.beginKey` points to a key for which we already know the value, either @@ -1087,8 +1099,7 @@ kj::OneOf> // Wait on the RPC only until stream.end() is called, then report the results. We prevent // `stream` from being destroyed until we have a result so that if the RPC throws an exception, // we don't accidentally report "PromiseFulfiller not fulfilled" instead of the exception. - auto promise = sendPromise - .then([&streamServerRef]() -> kj::Promise { + auto promise = sendPromise.then([&streamServerRef]() -> kj::Promise { if (streamServerRef.fulfiller->isWaiting()) { return KJ_EXCEPTION(FAILED, "list() never called stream.end()"); } else { @@ -1098,23 +1109,30 @@ kj::OneOf> }); return paf.promise.exclusiveJoin(kj::mv(promise)) - .attach(kj::defer([client = kj::mv(streamClient), &streamServerRef]() { - streamServerRef.cancel(); - })); + .attach(kj::defer( + [client = kj::mv(streamClient), &streamServerRef]() { streamServerRef.cancel(); })); } // ----------------------------------------------------------------------------- class ActorCache::ReverseListStreamImpl final: public rpc::ActorStorage::ListStream::Server { public: - ReverseListStreamImpl(ActorCache& cache, Key beginKey, kj::Maybe endKey, - kj::Vector> cachedEntries, - kj::Own> fulfiller, - kj::Maybe originalLimit, kj::Maybe adjustedLimit, - ReadOptions options) - : cache(cache), beginKey(kj::mv(beginKey)), endKey(kj::mv(endKey)), - cachedEntries(kj::mv(cachedEntries)), fulfiller(kj::mv(fulfiller)), - originalLimit(originalLimit), adjustedLimit(adjustedLimit), options(options) {} + ReverseListStreamImpl(ActorCache& cache, + Key beginKey, + kj::Maybe endKey, + kj::Vector> cachedEntries, + kj::Own> fulfiller, + kj::Maybe originalLimit, + kj::Maybe adjustedLimit, + ReadOptions options) + : cache(cache), + beginKey(kj::mv(beginKey)), + endKey(kj::mv(endKey)), + cachedEntries(kj::mv(cachedEntries)), + fulfiller(kj::mv(fulfiller)), + originalLimit(originalLimit), + adjustedLimit(adjustedLimit), + options(options) {} kj::Promise values(ValuesContext context) override { if (!fulfiller->isWaiting()) { @@ -1238,9 +1256,8 @@ public: ReadOptions options; }; -kj::OneOf> - ActorCache::listReverse(Key beginKey, kj::Maybe endKey, - kj::Maybe limit, ReadOptions options) { +kj::OneOf> ActorCache:: + listReverse(Key beginKey, kj::Maybe endKey, kj::Maybe limit, ReadOptions options) { options.noCache = options.noCache || lru.options.noCache; requireNotTerminal(); @@ -1290,7 +1307,7 @@ kj::OneOf> touchEntry(lock, **iter); } } - for (; positiveCount < limit.orDefault(kj::maxValue); ) { + for (; positiveCount < limit.orDefault(kj::maxValue);) { if (iter == ordered.begin()) { // No earlier entries, treat same as if previous entry were before beginKey and had // gapIsKnownEmpty = false. @@ -1319,7 +1336,7 @@ kj::OneOf> // Note that we need to add even negative entries to `cachedEntries` so that they override // whatever we read from storage later. However, they should not count against the limit. - switch(entry.getValueStatus()) { + switch (entry.getValueStatus()) { case EntryValueStatus::ABSENT: { cachedEntries.add(kj::atomicAddRef(entry)); if (storageListEnd != kj::none && entry.isDirty()) { @@ -1369,26 +1386,25 @@ kj::OneOf> } } - auto adjustedLimit = limit.map([&](uint orig) { - return orig + limitAdjustment - knownSuffixSize; - }); + auto adjustedLimit = + limit.map([&](uint orig) { return orig + limitAdjustment - knownSuffixSize; }); auto paf = kj::newPromiseAndFulfiller(); - auto streamServer = kj::heap( - *this, kj::mv(beginKey), kj::mv(endKey), + auto streamServer = kj::heap(*this, kj::mv(beginKey), kj::mv(endKey), kj::mv(cachedEntries), kj::mv(paf.fulfiller), limit, adjustedLimit, options); auto& streamServerRef = *streamServer; rpc::ActorStorage::ListStream::Client streamClient = kj::mv(streamServer); auto sendPromise = scheduleStorageRead( - [&streamServerRef,streamClient] - (rpc::ActorStorage::Operations::Client client) mutable -> kj::Promise { - auto req = client.listRequest(capnp::MessageSize { - 8 + streamServerRef.beginKey.size() / sizeof(capnp::word) + - streamServerRef.endKey - .map([](KeyPtr k) { return k.size() / sizeof(capnp::word); }) - .orDefault(0), 1 }); + [&streamServerRef, streamClient]( + rpc::ActorStorage::Operations::Client client) mutable -> kj::Promise { + auto req = client.listRequest( + capnp::MessageSize{8 + streamServerRef.beginKey.size() / sizeof(capnp::word) + + streamServerRef.endKey.map([](KeyPtr k) { + return k.size() / sizeof(capnp::word); + }).orDefault(0), + 1}); if (streamServerRef.beginKey.size() > 0) { req.setStart(streamServerRef.beginKey.asBytes()); } @@ -1411,8 +1427,7 @@ kj::OneOf> // Wait on the RPC only until stream.end() is called, then report the results. We prevent // `stream` from being destroyed until we have a result so that if the RPC throws an exception, // we don't accidentally report "PromiseFulfiller not fulfilled" instead of the exception. - auto promise = sendPromise - .then([&streamServerRef]() -> kj::Promise { + auto promise = sendPromise.then([&streamServerRef]() -> kj::Promise { if (streamServerRef.fulfiller->isWaiting()) { return KJ_EXCEPTION(FAILED, "list() never called stream.end()"); } else { @@ -1422,9 +1437,8 @@ kj::OneOf> }); return paf.promise.exclusiveJoin(kj::mv(promise)) - .attach(kj::defer([client = kj::mv(streamClient), &streamServerRef]() { - streamServerRef.cancel(); - })); + .attach(kj::defer( + [client = kj::mv(streamClient), &streamServerRef]() { streamServerRef.cancel(); })); } // ----------------------------------------------------------------------------- @@ -1490,7 +1504,8 @@ kj::Own ActorCache::addReadResultToCache( if (iter->get()->gapIsKnownEmpty) { // This entry is redundant, so we won't insert it. - return kj::atomicRefcounted(kj::mv(key), EntryValueStatus::ABSENT);; + return kj::atomicRefcounted(kj::mv(key), EntryValueStatus::ABSENT); + ; } } @@ -1576,8 +1591,8 @@ kj::Own ActorCache::addReadResultToCache( // entries could not possibly be marked clean until after the list operation completes. // And, they cannot be evicted until they are marked clean. So these entries could not // have been evicted yet. -void ActorCache::markGapsEmpty(Lock& lock, KeyPtr beginKey, kj::Maybe endKey, - const ReadOptions& options) { +void ActorCache::markGapsEmpty( + Lock& lock, KeyPtr beginKey, kj::Maybe endKey, const ReadOptions& options) { if (options.noCache) { // Oops, never mind. We're not caching the list() results, so we can't mark anything // known-empty. @@ -1703,7 +1718,8 @@ void ActorCache::markGapsEmpty(Lock& lock, KeyPtr beginKey, kj::Maybe en } ActorCache::GetResultList::GetResultList(kj::Vector contents) - : entries(contents.size()), cacheStatuses(contents.size()) { + : entries(contents.size()), + cacheStatuses(contents.size()) { // TODO(perf): Allocating an `Entry` object for every key/value pair is lame but to avoid it // we'd have to make the common case worse... for (auto& kv: contents) { @@ -1721,9 +1737,10 @@ ActorCache::GetResultList::GetResultList(kj::Vector contents) // // The idea is that `cachedEntries` is the set of entries that were loaded from cache while // `fetchedEntries` is the set read from storage. -ActorCache::GetResultList::GetResultList( - kj::Vector> cachedEntries, kj::Vector> fetchedEntries, - Order order, kj::Maybe maybeLimit) { +ActorCache::GetResultList::GetResultList(kj::Vector> cachedEntries, + kj::Vector> fetchedEntries, + Order order, + kj::Maybe maybeLimit) { uint limit = maybeLimit.orDefault(kj::maxValue); entries.reserve(kj::min(cachedEntries.size() + fetchedEntries.size(), limit)); @@ -1739,14 +1756,13 @@ ActorCache::GetResultList::GetResultList( }; while ((cachedIter != cachedEntries.end() || fetchedIter != fetchedEntries.end()) && - entries.size() < limit) { + entries.size() < limit) { if (cachedIter == cachedEntries.end()) { add(kj::mv(*fetchedIter++), CacheStatus::UNCACHED); } else if (fetchedIter == fetchedEntries.end()) { add(kj::mv(*cachedIter++), CacheStatus::CACHED); - } else if (order == REVERSE - ? cachedIter->get()->key > fetchedIter->get()->key - : cachedIter->get()->key < fetchedIter->get()->key) { + } else if (order == REVERSE ? cachedIter->get()->key > fetchedIter->get()->key + : cachedIter->get()->key < fetchedIter->get()->key) { add(kj::mv(*cachedIter++), CacheStatus::CACHED); } else if (cachedIter->get()->key == fetchedIter->get()->key) { // Same key in both. Prefer the cached entry because it will reflect the state as of when the @@ -1781,12 +1797,12 @@ kj::PromiseForResult ActorCache::sc // This is basically kj::retryOnDisconnect() except that we make the first call synchronously. // For our use case, this is safe, and I wanted to make sure reads get sent concurrently with // further JavaScript execution if possible. - auto promise = kj::evalNow([&]() mutable { - return function(storage).attach(recordStorageRead(hooks, clock)); - }); - return oomCanceler.wrap(promise.catch_( - [this, function = kj::mv(function)](kj::Exception&& e) mutable - -> kj::PromiseForResult { + auto promise = kj::evalNow( + [&]() mutable { return function(storage).attach(recordStorageRead(hooks, clock)); }); + return oomCanceler.wrap( + promise + .catch_([this, function = kj::mv(function)](kj::Exception&& e) mutable + -> kj::PromiseForResult { if (e.getType() == kj::Exception::Type::DISCONNECTED) { return function(storage).attach(recordStorageRead(hooks, clock)); } else { @@ -1853,7 +1869,8 @@ kj::Maybe> ActorCache::put(kj::Array pairs, Writ return getBackpressure(); } -kj::Maybe> ActorCache::setAlarm(kj::Maybe newAlarmTime, WriteOptions options) { +kj::Maybe> ActorCache::setAlarm( + kj::Maybe newAlarmTime, WriteOptions options) { options.noCache = options.noCache || lru.options.noCache; KJ_IF_SOME(time, currentAlarmTime.tryGet()) { // If we're in the alarm handler and haven't set the time yet, @@ -1873,11 +1890,8 @@ kj::Maybe> ActorCache::setAlarm(kj::Maybe newAlarmTi } } - currentAlarmTime = ActorCache::KnownAlarmTime { - ActorCache::KnownAlarmTime::Status::DIRTY, - newAlarmTime, - options.noCache - }; + currentAlarmTime = ActorCache::KnownAlarmTime{ + ActorCache::KnownAlarmTime::Status::DIRTY, newAlarmTime, options.noCache}; ensureFlushScheduled(options); @@ -1885,7 +1899,7 @@ kj::Maybe> ActorCache::setAlarm(kj::Maybe newAlarmTi } namespace { -template +template kj::OneOf, kj::PromiseForResult> mapPromise( kj::Maybe> maybePromise, F&& f) { KJ_IF_SOME(promise, maybePromise) { @@ -1894,7 +1908,7 @@ kj::OneOf, kj::PromiseForResult> mapPromise( return kj::fwd(f)(); } } -} // namespace +} // namespace kj::OneOf> ActorCache::delete_(Key key, WriteOptions options) { options.noCache = options.noCache || lru.options.noCache; @@ -1916,9 +1930,8 @@ kj::OneOf> ActorCache::delete_(Key key, WriteOptions opt } else if (countedDelete->entries.size()) { maybePromise = countedDelete->forgiveIfFinished(lastFlush.addBranch()); } - return mapPromise(kj::mv(maybePromise), [waiter = kj::mv(waiter)]() { - return waiter->getCountedDelete().countDeleted > 0; - }); + return mapPromise(kj::mv(maybePromise), + [waiter = kj::mv(waiter)]() { return waiter->getCountedDelete().countDeleted > 0; }); } kj::OneOf> ActorCache::delete_(kj::Array keys, WriteOptions options) { @@ -1943,9 +1956,8 @@ kj::OneOf> ActorCache::delete_(kj::Array keys, Writ } else if (countedDelete->entries.size()) { maybePromise = countedDelete->forgiveIfFinished(lastFlush.addBranch()); } - return mapPromise(kj::mv(maybePromise), [waiter = kj::mv(waiter)]() { - return waiter->getCountedDelete().countDeleted; - }); + return mapPromise(kj::mv(maybePromise), + [waiter = kj::mv(waiter)]() { return waiter->getCountedDelete().countDeleted; }); } kj::Own ActorCache::startTransaction() { @@ -1964,7 +1976,7 @@ ActorCache::DeleteAllResults ActorCache::deleteAll(WriteOptions options) { options.noCache = options.noCache || lru.options.noCache; requireNotTerminal(); - kj::Promise result { (uint)0 }; + kj::Promise result{(uint)0}; { auto lock = lru.cleanList.lockExclusive(); @@ -1996,10 +2008,8 @@ ActorCache::DeleteAllResults ActorCache::deleteAll(WriteOptions options) { if (requestedDeleteAll == kj::none) { auto paf = kj::newPromiseAndFulfiller(); result = kj::mv(paf.promise); - requestedDeleteAll = DeleteAllState { - .deletedDirty = kj::mv(deletedDirty), - .countFulfiller = kj::mv(paf.fulfiller) - }; + requestedDeleteAll = DeleteAllState{ + .deletedDirty = kj::mv(deletedDirty), .countFulfiller = kj::mv(paf.fulfiller)}; ensureFlushScheduled(options); } else { // A previous deleteAll() was scheduled and hasn't been committed yet. This means that we @@ -2014,14 +2024,12 @@ ActorCache::DeleteAllResults ActorCache::deleteAll(WriteOptions options) { evictOrOomIfNeeded(lock); } - return DeleteAllResults { - .backpressure = getBackpressure(), - .count = kj::mv(result) - }; + return DeleteAllResults{.backpressure = getBackpressure(), .count = kj::mv(result)}; } -void ActorCache::putImpl( - Lock& lock, kj::Own newEntry, const WriteOptions& options, +void ActorCache::putImpl(Lock& lock, + kj::Own newEntry, + const WriteOptions& options, kj::Maybe maybeCountedDelete) { auto& map = currentValues.get(lock); auto ordered = map.ordered(); @@ -2143,14 +2151,15 @@ void ActorCache::ensureFlushScheduled(const WriteOptions& options) { } KJ_CASE_ONEOF(deferredDelete, ActorCache::DeferredAlarmDelete) { if (deferredDelete.status == DeferredAlarmDelete::Status::READY) { - currentAlarmTime = KnownAlarmTime { + currentAlarmTime = KnownAlarmTime{ .status = KnownAlarmTime::Status::CLEAN, .time = kj::none, }; hooks.updateAlarmInMemory(kj::none); } } - KJ_CASE_ONEOF(_, UnknownAlarmTime){} + KJ_CASE_ONEOF(_, UnknownAlarmTime) { + } } return; @@ -2158,25 +2167,23 @@ void ActorCache::ensureFlushScheduled(const WriteOptions& options) { if (!flushScheduled) { flushScheduled = true; - auto flushPromise = lastFlush.addBranch().attach(kj::defer([this]() { + auto flushPromise = lastFlush.addBranch() + .attach(kj::defer([this]() { flushScheduled = false; flushScheduledWithOutputGate = false; })).then([this]() { ++flushesEnqueued; - return kj::evalNow([this](){ + return kj::evalNow([this]() { // `flushImpl()` can throw, so we need to wrap it in `evalNow()` to observe all pathways. return flushImpl(); - }).attach(kj::defer([this](){ - --flushesEnqueued; - })); + }).attach(kj::defer([this]() { --flushesEnqueued; })); }); if (options.allowUnconfirmed) { // Don't apply output gate. But, if an exception is thrown, we still want to break the gate, // so arrange for that. - flushPromise = flushPromise.catch_([this](kj::Exception&& e) { - return gate.lockWhile(kj::Promise(kj::mv(e))); - }); + flushPromise = flushPromise.catch_( + [this](kj::Exception&& e) { return gate.lockWhile(kj::Promise(kj::mv(e))); }); } else { flushPromise = gate.lockWhile(kj::mv(flushPromise)); flushScheduledWithOutputGate = true; @@ -2261,7 +2268,7 @@ using RpcPutRequest = capnp::Request; -} +} // namespace kj::Promise ActorCache::startFlushTransaction() { // Whenever we flush, we MUST write ALL dirty entries in a single transaction. This is necessary @@ -2311,9 +2318,8 @@ kj::Promise ActorCache::startFlushTransaction() { if (batches.empty()) { // This is the first one, let's just set up a current batch. batches.add(FlushBatch{}); - } else if (auto& tailBatch = batches.back(); - tailBatch.pairCount >= lru.options.maxKeysPerRpc - || ((tailBatch.wordCount + words) > MAX_ACTOR_STORAGE_RPC_WORDS)) { + } else if (auto& tailBatch = batches.back(); tailBatch.pairCount >= lru.options.maxKeysPerRpc || + ((tailBatch.wordCount + words) > MAX_ACTOR_STORAGE_RPC_WORDS)) { // We've filled this batch, add a new one. batches.add(FlushBatch{}); } @@ -2324,7 +2330,7 @@ kj::Promise ActorCache::startFlushTransaction() { }; kj::Vector countedDeleteFlushes(countedDeletes.size()); - for (auto countedDelete : countedDeletes) { + for (auto countedDelete: countedDeletes) { if (countedDelete->isFinished) { // This countedDelete has already be executed, but we haven't delivered the final count to // the waiter yet. We'll skip it here since the destructor of CountedDeleteWaiter should @@ -2336,7 +2342,7 @@ kj::Promise ActorCache::startFlushTransaction() { // In that case, we might have entries that have since been overwritten, and which no longer // need to be scheduled for deletion. kj::Vector> entriesToDelete(countedDelete->entries.size()); - for (auto& entry : countedDelete->entries) { + for (auto& entry: countedDelete->entries) { if (entry->overwritingCountedDelete && countedDelete->completedInTransaction) { // Not only is this a retry, but we have since modified the entry with a put(). // Since we already have the delete count, we don't need to delete this entry again. @@ -2357,7 +2363,7 @@ kj::Promise ActorCache::startFlushTransaction() { // Now that we've filtered our entries down to only those that need to be deleted, // we need to overwrite the CountedDelete's `entries`. countedDelete->entries = kj::mv(entriesToDelete); - for (auto& entry : countedDelete->entries) { + for (auto& entry: countedDelete->entries) { // A delete() call on this key is waiting to find out if the key existed in storage. Since // each delete() call needs to return the count of keys deleted, we must issue // corresponding delete calls to storage with the same batching, so that storage returns @@ -2413,17 +2419,18 @@ kj::Promise ActorCache::startFlushTransaction() { if (knownAlarmTime.status == KnownAlarmTime::Status::DIRTY || knownAlarmTime.status == KnownAlarmTime::Status::FLUSHING) { knownAlarmTime.status = KnownAlarmTime::Status::FLUSHING; - maybeAlarmChange = DirtyAlarm { knownAlarmTime.time }; + maybeAlarmChange = DirtyAlarm{knownAlarmTime.time}; } } KJ_CASE_ONEOF(deferredDelete, ActorCache::DeferredAlarmDelete) { if (deferredDelete.status == DeferredAlarmDelete::Status::READY || deferredDelete.status == DeferredAlarmDelete::Status::FLUSHING) { deferredDelete.status = DeferredAlarmDelete::Status::FLUSHING; - maybeAlarmChange = DirtyAlarm { kj::none }; + maybeAlarmChange = DirtyAlarm{kj::none}; } } - KJ_CASE_ONEOF(_, UnknownAlarmTime){} + KJ_CASE_ONEOF(_, UnknownAlarmTime) { + } } // We have to remember _before_ waiting for the flush whether or not it was a pre-deleteAll() @@ -2463,10 +2470,18 @@ kj::Promise ActorCache::startFlushTransaction() { }; uint typesOfDataToFlush = 0; - if (putFlush.batches.size() > 0) { ++typesOfDataToFlush; } - if (mutedDeleteFlush.batches.size() > 0) { ++typesOfDataToFlush; } - if (countedDeleteFlushes.size() > 0) { ++typesOfDataToFlush; } - if (maybeAlarmChange.is()) { ++typesOfDataToFlush; } + if (putFlush.batches.size() > 0) { + ++typesOfDataToFlush; + } + if (mutedDeleteFlush.batches.size() > 0) { + ++typesOfDataToFlush; + } + if (countedDeleteFlushes.size() > 0) { + ++typesOfDataToFlush; + } + if (maybeAlarmChange.is()) { + ++typesOfDataToFlush; + } if (typesOfDataToFlush == 0) { // Oh, nothing to do. @@ -2504,8 +2519,8 @@ kj::Promise ActorCache::flushImpl(uint retryCount) { auto flushProm = startFlushTransaction(); bool flushingBeforeDeleteAll = requestedDeleteAll != kj::none; - return oomCanceler.wrap(kj::mv(flushProm)).then( - [this, flushingBeforeDeleteAll]() -> kj::Promise { + return oomCanceler.wrap(kj::mv(flushProm)) + .then([this, flushingBeforeDeleteAll]() -> kj::Promise { // We need to process the alarm result before we (potentially) start the delete all because if // we did not our alarm state can't know if it need to flush a new time or not after the delete // all. This might be another reason why delete all should not be considered truly deleting the @@ -2526,15 +2541,14 @@ kj::Promise ActorCache::flushImpl(uint retryCount) { if (deferredDelete.noCache || !wasDeleted) { currentAlarmTime = UnknownAlarmTime{}; } else { - currentAlarmTime = KnownAlarmTime { - .status = KnownAlarmTime::Status::CLEAN, + currentAlarmTime = KnownAlarmTime{.status = KnownAlarmTime::Status::CLEAN, .time = kj::none, - .noCache = deferredDelete.noCache - }; + .noCache = deferredDelete.noCache}; } } } - KJ_CASE_ONEOF(_, ActorCache::UnknownAlarmTime) {} + KJ_CASE_ONEOF(_, ActorCache::UnknownAlarmTime) { + } } if (flushingBeforeDeleteAll) { // The writes we flushed were writes that had occurred before a deleteAll. Now that they are @@ -2608,12 +2622,12 @@ kj::Promise ActorCache::flushImpl(uint retryCount) { evictOrOomIfNeeded(lock); return kj::READY_NOW; - }, [this,retryCount](kj::Exception&& e) -> kj::Promise { + }, [this, retryCount](kj::Exception&& e) -> kj::Promise { static const size_t MAX_RETRIES = 4; if (e.getType() == kj::Exception::Type::DISCONNECTED && retryCount < MAX_RETRIES) { return flushImpl(retryCount + 1); } else if (jsg::isTunneledException(e.getDescription()) || - jsg::isDoNotLogException(e.getDescription())) { + jsg::isDoNotLogException(e.getDescription())) { // Before passing along the exception, give it the proper brokenness reason. // We were overriding any exception that came through here by ioGateBroken (now outputGateBroken). // without checking for previous brokenness reasons we would be unable to throw @@ -2632,7 +2646,7 @@ kj::Promise ActorCache::flushImpl(uint retryCount) { // Pass through exception type to convey appropriate retry behavior. return kj::Exception(e.getType(), __FILE__, __LINE__, kj::str("broken.outputGateBroken; jsg.Error: Internal error in Durable " - "Object storage write caused object to be reset.")); + "Object storage write caused object to be reset.")); } }); } @@ -2644,10 +2658,10 @@ kj::Promise ActorCache::flushImplUsingSinglePut(PutFlush putFlush) { KJ_ASSERT(batch.wordCount < MAX_ACTOR_STORAGE_RPC_WORDS); KJ_ASSERT(batch.pairCount == putFlush.entries.size()); - auto request = storage.putRequest(capnp::MessageSize { 4 + batch.wordCount, 0 }); + auto request = storage.putRequest(capnp::MessageSize{4 + batch.wordCount, 0}); auto list = request.initEntries(batch.pairCount); auto entryIt = putFlush.entries.begin(); - for (auto kv : list) { + for (auto kv: list) { auto& entry = **(entryIt++); auto v = KJ_ASSERT_NONNULL(entry.getValuePtr()); kv.setKey(entry.key.asBytes()); @@ -2659,7 +2673,8 @@ kj::Promise ActorCache::flushImplUsingSinglePut(PutFlush putFlush) { putFlush.batches.clear(); { auto writeObserver = recordStorageWrite(hooks, clock); - util::DurationExceededLogger logger(clock, 1*kj::SECONDS, "storage operation took longer than expected: single put"); + util::DurationExceededLogger logger( + clock, 1 * kj::SECONDS, "storage operation took longer than expected: single put"); co_await request.send().ignoreResult(); } } @@ -2671,7 +2686,7 @@ kj::Promise ActorCache::flushImplUsingSingleMutedDelete(MutedDeleteFlush m KJ_ASSERT(batch.wordCount < MAX_ACTOR_STORAGE_RPC_WORDS); KJ_ASSERT(batch.pairCount == mutedFlush.entries.size()); - auto request = storage.deleteRequest(capnp::MessageSize { 4 + batch.wordCount, 0 }); + auto request = storage.deleteRequest(capnp::MessageSize{4 + batch.wordCount, 0}); auto listBuilder = request.initKeys(batch.pairCount); auto entryIt = mutedFlush.entries.begin(); for (size_t i = 0; i < batch.pairCount; ++i) { @@ -2685,7 +2700,8 @@ kj::Promise ActorCache::flushImplUsingSingleMutedDelete(MutedDeleteFlush m { auto writeObserver = recordStorageWrite(hooks, clock); - util::DurationExceededLogger logger(clock, 1*kj::SECONDS, "storage operation took longer than expected: muted delete"); + util::DurationExceededLogger logger( + clock, 1 * kj::SECONDS, "storage operation took longer than expected: muted delete"); co_await request.send().ignoreResult(); } } @@ -2698,7 +2714,7 @@ kj::Promise ActorCache::flushImplUsingSingleCountedDelete(CountedDeleteFlu KJ_ASSERT(batch.wordCount < MAX_ACTOR_STORAGE_RPC_WORDS); KJ_ASSERT(batch.pairCount == countedDelete->entries.size()); - auto request = storage.deleteRequest(capnp::MessageSize { 4 + batch.wordCount, 0 }); + auto request = storage.deleteRequest(capnp::MessageSize{4 + batch.wordCount, 0}); auto listBuilder = request.initKeys(batch.pairCount); auto entryIt = countedDelete->entries.begin(); for (size_t i = 0; i < batch.pairCount; ++i) { @@ -2710,7 +2726,8 @@ kj::Promise ActorCache::flushImplUsingSingleCountedDelete(CountedDeleteFlu countedFlush.batches.clear(); auto writeObserver = recordStorageWrite(hooks, clock); - util::DurationExceededLogger logger(clock, 1*kj::SECONDS, "storage operation took longer than expected: counted delete"); + util::DurationExceededLogger logger( + clock, 1 * kj::SECONDS, "storage operation took longer than expected: counted delete"); auto response = co_await request.send(); countedDelete->countDeleted += response.getNumDeleted(); countedDelete->isFinished = true; @@ -2718,7 +2735,8 @@ kj::Promise ActorCache::flushImplUsingSingleCountedDelete(CountedDeleteFlu kj::Promise ActorCache::flushImplAlarmOnly(DirtyAlarm dirty) { auto writeObserver = recordStorageWrite(hooks, clock); - util::DurationExceededLogger logger(clock, 1*kj::SECONDS, "storage operation took longer than expected: set/delete alarm"); + util::DurationExceededLogger logger( + clock, 1 * kj::SECONDS, "storage operation took longer than expected: set/delete alarm"); // TODO(someday) This could be templated to reuse the same code for this and the transaction case. // Handle alarm writes first, since they're simplest. @@ -2757,10 +2775,11 @@ kj::Promise ActorCache::flushImplAlarmOnly(DirtyAlarm dirty) { } } -kj::Promise ActorCache::flushImplUsingTxn( - PutFlush putFlush, MutedDeleteFlush mutedDeleteFlush, - CountedDeleteFlushes countedDeleteFlushes, MaybeAlarmChange maybeAlarmChange) { - auto txnProm = storage.txnRequest(capnp::MessageSize { 4, 0 }).send(); +kj::Promise ActorCache::flushImplUsingTxn(PutFlush putFlush, + MutedDeleteFlush mutedDeleteFlush, + CountedDeleteFlushes countedDeleteFlushes, + MaybeAlarmChange maybeAlarmChange) { + auto txnProm = storage.txnRequest(capnp::MessageSize{4, 0}).send(); auto txn = txnProm.getTransaction(); struct RpcCountedDelete { @@ -2778,7 +2797,7 @@ kj::Promise ActorCache::flushImplUsingTxn( for (auto& batch: flush.batches) { KJ_ASSERT(batch.wordCount < MAX_ACTOR_STORAGE_RPC_WORDS); - auto request = txn.deleteRequest(capnp::MessageSize { 4 + batch.wordCount, 0 }); + auto request = txn.deleteRequest(capnp::MessageSize{4 + batch.wordCount, 0}); auto listBuilder = request.initKeys(batch.pairCount); for (size_t i = 0; i < batch.pairCount; ++i) { KJ_ASSERT(entryIt != countedDelete->entries.end()); @@ -2801,7 +2820,7 @@ kj::Promise ActorCache::flushImplUsingTxn( for (auto& batch: mutedDeleteFlush.batches) { KJ_ASSERT(batch.wordCount < MAX_ACTOR_STORAGE_RPC_WORDS); - auto request = txn.deleteRequest(capnp::MessageSize { 4 + batch.wordCount, 0 }); + auto request = txn.deleteRequest(capnp::MessageSize{4 + batch.wordCount, 0}); auto listBuilder = request.initKeys(batch.pairCount); for (size_t i = 0; i < batch.pairCount; ++i) { KJ_ASSERT(entryIt != mutedDeleteFlush.entries.end()); @@ -2820,9 +2839,9 @@ kj::Promise ActorCache::flushImplUsingTxn( for (auto& batch: putFlush.batches) { KJ_ASSERT(batch.wordCount < MAX_ACTOR_STORAGE_RPC_WORDS); - auto request = txn.putRequest(capnp::MessageSize { 4 + batch.wordCount, 0 }); + auto request = txn.putRequest(capnp::MessageSize{4 + batch.wordCount, 0}); auto listBuilder = request.initEntries(batch.pairCount); - for (auto kv : listBuilder) { + for (auto kv: listBuilder) { KJ_ASSERT(entryIt != putFlush.entries.end()); auto& entry = **(entryIt++); auto v = KJ_ASSERT_NONNULL(entry.getValuePtr()); @@ -2844,21 +2863,18 @@ kj::Promise ActorCache::flushImplUsingTxn( // The constant extra 2 promises are those added outside of the rpc batches, currently one // to work around a bug in capnp::autoreconnect, and one to actually commit the flush txn // A 3rd promise may be added to write the alarm time if necessary. - auto promises = kj::heapArrayBuilder>( - rpcPuts.size() + rpcMutedDeletes.size() + rpcCountedDeletes.size() - + 2 + !maybeAlarmChange.is()); + auto promises = kj::heapArrayBuilder>(rpcPuts.size() + rpcMutedDeletes.size() + + rpcCountedDeletes.size() + 2 + !maybeAlarmChange.is()); auto joinCountedDelete = [](RpcCountedDelete& rpcCountedDelete) -> kj::Promise { auto promises = KJ_MAP(request, rpcCountedDelete.rpcDeletes) { return request.send().then( [](capnp::Response&& response) mutable - -> uint { - return response.getNumDeleted(); - }); + -> uint { return response.getNumDeleted(); }); }; size_t recordsDeleted = 0; - for (auto& promise : promises) { + for (auto& promise: promises) { recordsDeleted += co_await promise; } @@ -2897,7 +2913,8 @@ kj::Promise ActorCache::flushImplUsingTxn( auto req = txn.deleteAlarmRequest(); KJ_IF_SOME(deferredDelete, currentAlarmTime.tryGet()) { if (deferredDelete.status == DeferredAlarmDelete::Status::FLUSHING) { - req.setTimeToDeleteMs((deferredDelete.timeToDelete - kj::UNIX_EPOCH) / kj::MILLISECONDS); + req.setTimeToDeleteMs( + (deferredDelete.timeToDelete - kj::UNIX_EPOCH) / kj::MILLISECONDS); auto prom = req.send().then([this](auto response) { KJ_IF_SOME(deferredDelete, currentAlarmTime.tryGet()) { if (deferredDelete.status == DeferredAlarmDelete::Status::FLUSHING) { @@ -2922,7 +2939,8 @@ kj::Promise ActorCache::flushImplUsingTxn( } } } - KJ_CASE_ONEOF(_, CleanAlarm) {} + KJ_CASE_ONEOF(_, CleanAlarm) { + } } // We have to wait on the transaction promise so we don't cancel the catch_ branch that triggers @@ -2933,8 +2951,9 @@ kj::Promise ActorCache::flushImplUsingTxn( { auto writeObserver = recordStorageWrite(hooks, clock); - util::DurationExceededLogger logger(clock, 1*kj::SECONDS, "storage operation took longer than expected: commit flush transaction"); - promises.add(txn.commitRequest(capnp::MessageSize { 4, 0 }).send().ignoreResult()); + util::DurationExceededLogger logger(clock, 1 * kj::SECONDS, + "storage operation took longer than expected: commit flush transaction"); + promises.add(txn.commitRequest(capnp::MessageSize{4, 0}).send().ignoreResult()); co_await kj::joinPromises(promises.finish()); for (auto& rpcCountedDelete: rpcCountedDeletes) { @@ -2955,9 +2974,11 @@ kj::Promise ActorCache::flushImplDeleteAll(uint retryCount) { KJ_ASSERT(requestedDeleteAll != kj::none); - return storage.deleteAllRequest(capnp::MessageSize {2, 0}).send() - .then([this](capnp::Response results) - -> kj::Promise { + return storage.deleteAllRequest(capnp::MessageSize{2, 0}) + .send() + .then( + [this](capnp::Response results) + -> kj::Promise { KJ_ASSERT_NONNULL(requestedDeleteAll).countFulfiller->fulfill(results.getNumDeleted()); // Success! We can now null out `requestedDeleteAll`. Note that we don't have to worry about @@ -2979,12 +3000,13 @@ kj::Promise ActorCache::flushImplDeleteAll(uint retryCount) { // operations differ. This can mean that we will not wait for the output gate when we were asked // to do so. We should fix this. return flushImpl(); - }, [this, retryCount](kj::Exception&& e) -> kj::Promise { + }, + [this, retryCount](kj::Exception&& e) -> kj::Promise { static const size_t MAX_RETRIES = 4; if (e.getType() == kj::Exception::Type::DISCONNECTED && retryCount < MAX_RETRIES) { return flushImplDeleteAll(retryCount + 1); } else if (jsg::isTunneledException(e.getDescription()) || - jsg::isDoNotLogException(e.getDescription())) { + jsg::isDoNotLogException(e.getDescription())) { // Before passing along the exception, give it the proper brokenness reason. auto msg = jsg::stripRemoteExceptionPrefix(e.getDescription()); e.setDescription(kj::str("broken.outputGateBroken; ", msg)); @@ -2993,7 +3015,8 @@ kj::Promise ActorCache::flushImplDeleteAll(uint retryCount) { LOG_EXCEPTION("actorCacheDeleteAll", e); // Pass through exception type to convey appropriate retry behavior. return kj::Exception(e.getType(), __FILE__, __LINE__, - kj::str("broken.outputGateBroken; jsg.Error: Internal error in Durable Object storage deleteAll() caused object to be reset.")); + kj::str( + "broken.outputGateBroken; jsg.Error: Internal error in Durable Object storage deleteAll() caused object to be reset.")); } }); } @@ -3001,8 +3024,7 @@ kj::Promise ActorCache::flushImplDeleteAll(uint retryCount) { // ======================================================================================= // ActorCache::Transaction -ActorCache::Transaction::Transaction(ActorCache& cache) - : cache(cache) {} +ActorCache::Transaction::Transaction(ActorCache& cache): cache(cache) {} ActorCache::Transaction::~Transaction() noexcept(false) { // If not commit()ed... we don't have to do anything in particular here, just drop the changes. } @@ -3034,8 +3056,8 @@ kj::Promise ActorCache::Transaction::rollback() { // ----------------------------------------------------------------------------- // transaction reads -kj::OneOf, kj::Promise>> - ActorCache::Transaction::get(Key key, ReadOptions options) { +kj::OneOf, kj::Promise>> ActorCache:: + Transaction::get(Key key, ReadOptions options) { options.noCache = options.noCache || cache.lru.options.noCache; KJ_IF_SOME(change, entriesToWrite.find(key)) { return change.entry->getValue(); @@ -3044,8 +3066,8 @@ kj::OneOf, kj::Promise } } -kj::OneOf> - ActorCache::Transaction::get(kj::Array keys, ReadOptions options) { +kj::OneOf> ActorCache:: + Transaction::get(kj::Array keys, ReadOptions options) { options.noCache = options.noCache || cache.lru.options.noCache; kj::Vector> changedEntries; @@ -3063,7 +3085,7 @@ kj::OneOf> [](auto& a, auto& b) { return a.get()->key < b.get()->key; }); return merge(kj::mv(changedEntries), cache.get(keysToFetch.releaseAsArray(), options), - GetResultList::FORWARD); + GetResultList::FORWARD); } kj::OneOf, kj::Promise>> ActorCache::Transaction::getAlarm( @@ -3076,9 +3098,8 @@ kj::OneOf, kj::Promise>> ActorCache::Tra } } -kj::OneOf> - ActorCache::Transaction::list(Key begin, kj::Maybe end, - kj::Maybe limit, ReadOptions options) { +kj::OneOf> ActorCache:: + Transaction::list(Key begin, kj::Maybe end, kj::Maybe limit, ReadOptions options) { options.noCache = options.noCache || cache.lru.options.noCache; kj::Vector> changedEntries; if (limit.orDefault(kj::maxValue) == 0 || begin >= end) { @@ -3100,14 +3121,13 @@ kj::OneOf> // Increase limit to make sure it can't be underrun by negative entries negating it. limit = limit.map([&](uint n) { return n + (changedEntries.size() - positiveCount); }); - return merge(kj::mv(changedEntries), - cache.list(kj::mv(begin), kj::mv(end), limit, options), + return merge(kj::mv(changedEntries), cache.list(kj::mv(begin), kj::mv(end), limit, options), GetResultList::FORWARD); } -kj::OneOf> - ActorCache::Transaction::listReverse(Key begin, kj::Maybe end, - kj::Maybe limit, ReadOptions options) { +kj::OneOf> ActorCache:: + Transaction::listReverse( + Key begin, kj::Maybe end, kj::Maybe limit, ReadOptions options) { options.noCache = options.noCache || cache.lru.options.noCache; kj::Vector> changedEntries; if (limit.orDefault(kj::maxValue) == 0 || begin >= end) { @@ -3130,13 +3150,11 @@ kj::OneOf> limit = limit.map([&](uint n) { return n + (changedEntries.size() - positiveCount); }); return merge(kj::mv(changedEntries), - cache.listReverse(kj::mv(begin), kj::mv(end), limit, options), - GetResultList::REVERSE); + cache.listReverse(kj::mv(begin), kj::mv(end), limit, options), GetResultList::REVERSE); } -kj::OneOf> - ActorCache::Transaction::merge( - kj::Vector> changedEntries, +kj::OneOf> ActorCache:: + Transaction::merge(kj::Vector> changedEntries, kj::OneOf> cacheRead, GetResultList::Order order) { KJ_SWITCH_ONEOF(cacheRead) { @@ -3144,10 +3162,9 @@ kj::OneOf> return GetResultList(kj::mv(changedEntries), kj::mv(results.entries), order); } KJ_CASE_ONEOF(promise, kj::Promise) { - return promise.then([changedEntries = kj::mv(changedEntries), order] - (GetResultList results) mutable { - return GetResultList(kj::mv(changedEntries), kj::mv(results.entries), - order); + return promise.then( + [changedEntries = kj::mv(changedEntries), order](GetResultList results) mutable { + return GetResultList(kj::mv(changedEntries), kj::mv(results.entries), order); }); } } @@ -3185,13 +3202,12 @@ kj::Maybe> ActorCache::Transaction::put( kj::Maybe> ActorCache::Transaction::setAlarm( kj::Maybe newTime, WriteOptions options) { options.noCache = options.noCache || cache.lru.options.noCache; - alarmChange = DirtyAlarmWithOptions { DirtyAlarm { newTime }, options }; + alarmChange = DirtyAlarmWithOptions{DirtyAlarm{newTime}, options}; return kj::none; } -kj::OneOf> ActorCache::Transaction::delete_( - Key key, WriteOptions options) { +kj::OneOf> ActorCache::Transaction::delete_(Key key, WriteOptions options) { options.noCache = options.noCache || cache.lru.options.noCache; uint count = 0; @@ -3210,9 +3226,7 @@ kj::OneOf> ActorCache::Transaction::delete_( return value != kj::none; } KJ_CASE_ONEOF(promise, kj::Promise>) { - return promise.then([](kj::Maybe value) { - return value != kj::none; - }); + return promise.then([](kj::Maybe value) { return value != kj::none; }); } } KJ_UNREACHABLE; @@ -3231,9 +3245,7 @@ kj::OneOf> ActorCache::Transaction::delete_( uint count = 0; kj::Vector> keysToCount; - auto startNewBatch = [&]() { - return &keysToCount.add(); - }; + auto startNewBatch = [&]() { return &keysToCount.add(); }; auto currentBatch = startNewBatch(); { @@ -3256,7 +3268,7 @@ kj::OneOf> ActorCache::Transaction::delete_( // gets, we need to batch said gets. This all would be much simpler if our default get behavior // did batching/sync. kj::Maybe> maybeTotalPromise; - for(auto& batch : keysToCount) { + for (auto& batch: keysToCount) { // Unfortunately, to find out the count, we have to do a read. Note that even returning this // value separate from a committed transaction means that non-transaction storage ops can make // the value incorrect. @@ -3269,8 +3281,9 @@ kj::OneOf> ActorCache::Transaction::delete_( // We had to do a remote get, start a promise maybeTotalPromise.emplace(0); } - maybeTotalPromise = KJ_ASSERT_NONNULL(maybeTotalPromise).then( - [promise = kj::mv(promise)](uint previousResult) mutable -> kj::Promise { + maybeTotalPromise = KJ_ASSERT_NONNULL(maybeTotalPromise) + .then([promise = kj::mv(promise)]( + uint previousResult) mutable -> kj::Promise { return promise.then([previousResult](GetResultList results) mutable -> uint { return previousResult + kj::implicitCast(results.size()); }); @@ -3280,9 +3293,7 @@ kj::OneOf> ActorCache::Transaction::delete_( } KJ_IF_SOME(totalPromise, maybeTotalPromise) { - return totalPromise.then([count](uint result){ - return count + result; - }); + return totalPromise.then([count](uint result) { return count + result; }); } else { return count; } @@ -3290,9 +3301,8 @@ kj::OneOf> ActorCache::Transaction::delete_( } kj::Maybe ActorCache::Transaction::putImpl( - Lock& lock, kj::Own entry, const WriteOptions& options, - kj::Maybe count) { - Change change { + Lock& lock, kj::Own entry, const WriteOptions& options, kj::Maybe count) { + Change change{ .entry = kj::mv(entry), .options = options, }; @@ -3315,18 +3325,18 @@ kj::Maybe ActorCache::Transaction::putImpl( // ======================================================================================= kj::Promise ActorCacheInterface::getCurrentBookmark() { - JSG_FAIL_REQUIRE(Error, - "This Durable Object's storage back-end does not implement point-in-time recovery."); + JSG_FAIL_REQUIRE( + Error, "This Durable Object's storage back-end does not implement point-in-time recovery."); } kj::Promise ActorCacheInterface::getBookmarkForTime(kj::Date timestamp) { - JSG_FAIL_REQUIRE(Error, - "This Durable Object's storage back-end does not implement point-in-time recovery."); + JSG_FAIL_REQUIRE( + Error, "This Durable Object's storage back-end does not implement point-in-time recovery."); } kj::Promise ActorCacheInterface::onNextSessionRestoreBookmark(kj::StringPtr bookmark) { - JSG_FAIL_REQUIRE(Error, - "This Durable Object's storage back-end does not implement point-in-time recovery."); + JSG_FAIL_REQUIRE( + Error, "This Durable Object's storage back-end does not implement point-in-time recovery."); } } // namespace workerd diff --git a/src/workerd/io/actor-cache.h b/src/workerd/io/actor-cache.h index 19b1f0e6f45..c27a70b6e62 100644 --- a/src/workerd/io/actor-cache.h +++ b/src/workerd/io/actor-cache.h @@ -49,7 +49,9 @@ class ActorCacheOps { typedef kj::String Key; typedef kj::StringPtr KeyPtr; // Keys are text for now, but we could also change this to `Array`. - static inline Key cloneKey(KeyPtr ptr) { return kj::str(ptr); } + static inline Key cloneKey(KeyPtr ptr) { + return kj::str(ptr); + } // Values are raw bytes. typedef kj::Array Value; @@ -72,26 +74,26 @@ class ActorCacheOps { Key newKey; }; - enum class CacheStatus { - CACHED, - UNCACHED - }; + enum class CacheStatus { CACHED, UNCACHED }; struct KeyValuePtrPairWithCache: public KeyValuePtrPair { CacheStatus status; KeyValuePtrPairWithCache(const KeyValuePtrPair& other, CacheStatus status) - : KeyValuePtrPair(other), status(status) {} + : KeyValuePtrPair(other), + status(status) {} KeyValuePtrPairWithCache(const KeyValuePtrPairWithCache& other) - : KeyValuePtrPair(other.key, other.value), status(other.status) {} + : KeyValuePtrPair(other.key, other.value), + status(other.status) {} KeyValuePtrPairWithCache(KeyPtr key, ValuePtr value, CacheStatus status) - : KeyValuePtrPair(key, value), status(status) {} + : KeyValuePtrPair(key, value), + status(status) {} }; // An iterable type where each element is a KeyValuePtrPair. class GetResultList; - struct CleanAlarm{}; + struct CleanAlarm {}; struct DirtyAlarm { kj::Maybe newTime; @@ -99,7 +101,7 @@ class ActorCacheOps { using MaybeAlarmChange = kj::OneOf; - struct DirtyAlarmWithOptions : public DirtyAlarm { + struct DirtyAlarmWithOptions: public DirtyAlarm { ActorCacheWriteOptions options; }; @@ -138,23 +140,20 @@ class ActorCacheOps { // delay further puts until the promise resolves. This happens when too much data is pinned in // cache because writes haven't been flushed to disk yet. Dropping this promise will not cancel // the put. - virtual kj::Maybe> put( - Key key, Value value, WriteOptions options) = 0; - virtual kj::Maybe> put( - kj::Array pairs, WriteOptions options) = 0; + virtual kj::Maybe> put(Key key, Value value, WriteOptions options) = 0; + virtual kj::Maybe> put(kj::Array pairs, WriteOptions options) = 0; // Writes a new alarm time into cache and schedules it to be flushed to disk later, same as put(). - virtual kj::Maybe> setAlarm(kj::Maybe newTime, WriteOptions options) = 0; + virtual kj::Maybe> setAlarm( + kj::Maybe newTime, WriteOptions options) = 0; // Delete the gives keys. // // Returns a `bool` or `uint` if it can be immediately determined from cache how many keys were // present before the call. Otherwise, returns a promise which resolves after getting a response // from underlying storage. The promise also applies backpressure if needed, as with put(). - virtual kj::OneOf> delete_( - Key key, WriteOptions options) = 0; - virtual kj::OneOf> delete_( - kj::Array keys, WriteOptions options) = 0; + virtual kj::OneOf> delete_(Key key, WriteOptions options) = 0; + virtual kj::OneOf> delete_(kj::Array keys, WriteOptions options) = 0; }; // Abstract interface that is implemented by ActorCache as well as ActorSqlite. @@ -265,11 +264,15 @@ class ActorCache final: public ActorCacheInterface { "broken.ignored; jsg.Error: " "Durable Object storage is no longer accessible."_kj; - ActorCache(rpc::ActorStorage::Stage::Client storage, const SharedLru& lru, OutputGate& gate, + ActorCache(rpc::ActorStorage::Stage::Client storage, + const SharedLru& lru, + OutputGate& gate, Hooks& hooks = const_cast(Hooks::DEFAULT)); ~ActorCache() noexcept(false); - kj::Maybe getSqliteDatabase() override { return kj::none; } + kj::Maybe getSqliteDatabase() override { + return kj::none; + } kj::OneOf, kj::Promise>> get( Key key, ReadOptions options) override; kj::OneOf> get( @@ -284,7 +287,8 @@ class ActorCache final: public ActorCacheInterface { kj::Maybe> put(kj::Array pairs, WriteOptions options) override; kj::OneOf> delete_(Key key, WriteOptions options) override; kj::OneOf> delete_(kj::Array keys, WriteOptions options) override; - kj::Maybe> setAlarm(kj::Maybe newAlarmTime, WriteOptions options) override; + kj::Maybe> setAlarm( + kj::Maybe newAlarmTime, WriteOptions options) override; // See ActorCacheOps. kj::Own startTransaction() override; @@ -311,7 +315,7 @@ class ActorCache final: public ActorCacheInterface { auto p = reinterpret_cast(pointer); KJ_IF_SOME(d, p->currentAlarmTime.tryGet()) { d.status = DeferredAlarmDelete::Status::READY; - p->ensureFlushScheduled(WriteOptions { .noCache = d.noCache }); + p->ensureFlushScheduled(WriteOptions{.noCache = d.noCache}); } } }; @@ -398,6 +402,7 @@ class ActorCache final: public ActorCacheInterface { // This enum indicates how synchronized this entry is with storage. EntrySyncStatus syncStatus = EntrySyncStatus::NOT_IN_CACHE; + public: EntryValueStatus getValueStatus() const { return valueStatus; @@ -438,7 +443,7 @@ class ActorCache final: public ActorCacheInterface { } bool isDirty() const { - switch(getSyncStatus()) { + switch (getSyncStatus()) { case EntrySyncStatus::DIRTY: { return true; } @@ -489,14 +494,20 @@ class ActorCache final: public ActorCacheInterface { // Callbacks for a kj::TreeIndex for a kj::Table>. class EntryTableCallbacks { public: - inline KeyPtr keyForRow(const kj::Own& row) const { return row->key; } + inline KeyPtr keyForRow(const kj::Own& row) const { + return row->key; + } - inline bool isBefore(const kj::Own& row, KeyPtr key) const { return row->key < key; } + inline bool isBefore(const kj::Own& row, KeyPtr key) const { + return row->key < key; + } inline bool isBefore(const kj::Own& a, const kj::Own& b) const { return a->key < b->key; } - inline bool matches(const kj::Own& row, KeyPtr key) const { return row->key == key; } + inline bool matches(const kj::Own& row, KeyPtr key) const { + return row->key == key; + } }; // When delete() is called with one or more keys that aren't in cache, we will need to get @@ -543,13 +554,14 @@ class ActorCache final: public ActorCacheInterface { class CountedDeleteWaiter { public: explicit CountedDeleteWaiter(ActorCache& cache, kj::Own state) - : cache(cache), state(kj::mv(state)) { + : cache(cache), + state(kj::mv(state)) { // Register this operation so that we can batch it properly during flush. cache.countedDeletes.insert(this->state.get()); } KJ_DISALLOW_COPY_AND_MOVE(CountedDeleteWaiter); ~CountedDeleteWaiter() noexcept(false) { - for (auto& entry : state->entries) { + for (auto& entry: state->entries) { // Let each entry associated with this counted delete know that we aren't waiting anymore. entry->isCountedDelete = false; } @@ -593,8 +605,12 @@ class ActorCache final: public ActorCacheInterface { return innerSize; } - auto begin() { return inner.begin(); } - auto end() { return inner.end(); } + auto begin() { + return inner.begin(); + } + auto end() { + return inner.end(); + } private: kj::List inner; @@ -612,8 +628,8 @@ class ActorCache final: public ActorCacheInterface { kj::ExternalMutexGuarded, kj::TreeIndex>> currentValues; - struct UnknownAlarmTime{}; - struct KnownAlarmTime{ + struct UnknownAlarmTime {}; + struct KnownAlarmTime { enum class Status { CLEAN, DIRTY, FLUSHING } status; kj::Maybe time; bool noCache = false; @@ -633,7 +649,8 @@ class ActorCache final: public ActorCacheInterface { bool noCache = false; }; - kj::OneOf currentAlarmTime = UnknownAlarmTime{}; + kj::OneOf currentAlarmTime = + UnknownAlarmTime{}; struct ReadCompletionChain: public kj::Refcounted { kj::Maybe> next; @@ -720,16 +737,17 @@ class ActorCache final: public ActorCacheInterface { // inserted and will instead immediately have state NOT_IN_CACHE. // // Either way, a strong reference to the entry is returned. - kj::Own addReadResultToCache(Lock& lock, Key key, kj::Maybe value, - const ReadOptions& readOptions); - + kj::Own addReadResultToCache( + Lock& lock, Key key, kj::Maybe value, const ReadOptions& readOptions); // Mark all gaps empty between the begin and end key. void markGapsEmpty(Lock& lock, KeyPtr begin, kj::Maybe end, const ReadOptions& options); // Implements put() or delete(). Multi-key variants call this for each key. - void putImpl(Lock& lock, kj::Own newEntry, - const WriteOptions& options, kj::Maybe counted); + void putImpl(Lock& lock, + kj::Own newEntry, + const WriteOptions& options, + kj::Maybe counted); kj::Promise> getImpl(kj::Own entry, ReadOptions options); @@ -782,9 +800,10 @@ class ActorCache final: public ActorCacheInterface { kj::Promise flushImplUsingSingleMutedDelete(MutedDeleteFlush mutedFlush); kj::Promise flushImplUsingSingleCountedDelete(CountedDeleteFlush countedFlush); kj::Promise flushImplAlarmOnly(DirtyAlarm dirty); - kj::Promise flushImplUsingTxn( - PutFlush putFlush, MutedDeleteFlush mutedDeleteFlush, - CountedDeleteFlushes countedDeleteFlushes, MaybeAlarmChange maybeAlarmChange); + kj::Promise flushImplUsingTxn(PutFlush putFlush, + MutedDeleteFlush mutedDeleteFlush, + CountedDeleteFlushes countedDeleteFlushes, + MaybeAlarmChange maybeAlarmChange); // Carefully remove a clean entry from `currentValues`, making sure to update gaps. void evictEntry(Lock& lock, Entry& entry); @@ -811,12 +830,13 @@ class ActorCache final: public ActorCacheInterface { class ActorCacheOps::GetResultList { using Entry = ActorCache::Entry; + public: class Iterator { public: KeyValuePtrPairWithCache operator*() { KJ_IREQUIRE(ptr->get()->getValueStatus() == ActorCache::EntryValueStatus::PRESENT); - return { ptr->get()->key, ptr->get()->getValuePtr().orDefault({}), *statusPtr }; + return {ptr->get()->key, ptr->get()->getValuePtr().orDefault({}), *statusPtr}; } Iterator& operator++() { ++ptr; @@ -838,13 +858,20 @@ class ActorCacheOps::GetResultList { const CacheStatus* statusPtr; explicit Iterator(const kj::Own* ptr, const CacheStatus* statusPtr) - : ptr(ptr), statusPtr(statusPtr) {} + : ptr(ptr), + statusPtr(statusPtr) {} friend class GetResultList; }; - Iterator begin() const { return Iterator(entries.begin(), cacheStatuses.begin()); } - Iterator end() const { return Iterator(entries.end(), cacheStatuses.end()); } - size_t size() const { return entries.size(); } + Iterator begin() const { + return Iterator(entries.begin(), cacheStatuses.begin()); + } + Iterator end() const { + return Iterator(entries.end(), cacheStatuses.end()); + } + size_t size() const { + return entries.size(); + } // Construct a simple GetResultList from key-value pairs. explicit GetResultList(kj::Vector contents); @@ -853,10 +880,7 @@ class ActorCacheOps::GetResultList { kj::Vector> entries; kj::Vector cacheStatuses; - enum Order { - FORWARD, - REVERSE - }; + enum Order { FORWARD, REVERSE }; // Merges `cachedEntries` and `fetchedEntries`, which should each already be sorted in the // given order. If a key exists in both, `cachedEntries` is preferred. @@ -868,8 +892,9 @@ class ActorCacheOps::GetResultList { // The idea is that `cachedEntries` is the set of entries that were loaded from cache while // `fetchedEntries` is the set read from storage. explicit GetResultList(kj::Vector> cachedEntries, - kj::Vector> fetchedEntries, - Order order, kj::Maybe limit = kj::none); + kj::Vector> fetchedEntries, + Order order, + kj::Maybe limit = kj::none); friend class ActorCache; }; @@ -917,7 +942,9 @@ class ActorCache::SharedLru { KJ_DISALLOW_COPY_AND_MOVE(SharedLru); // Mostly for testing. - size_t currentSize() const { return size.load(std::memory_order_relaxed); } + size_t currentSize() const { + return size.load(std::memory_order_relaxed); + } private: const Options options; @@ -966,7 +993,8 @@ class ActorCache::Transaction final: public ActorCacheInterface::Transaction { kj::Maybe> put(kj::Array pairs, WriteOptions options) override; kj::OneOf> delete_(Key key, WriteOptions options) override; kj::OneOf> delete_(kj::Array keys, WriteOptions options) override; - kj::Maybe> setAlarm(kj::Maybe newAlarmTime, WriteOptions options) override; + kj::Maybe> setAlarm( + kj::Maybe newAlarmTime, WriteOptions options) override; // Same interface as ActorCache. // // Read ops will reflect the previous writes made to the transaction even though they aren't @@ -987,10 +1015,16 @@ class ActorCache::Transaction final: public ActorCacheInterface::Transaction { // Callbacks for a kj::TreeIndex for a kj::Table. class ChangeTableCallbacks { public: - inline KeyPtr keyForRow(const Change& row) const { return row.entry->key; } + inline KeyPtr keyForRow(const Change& row) const { + return row.entry->key; + } - inline bool isBefore(const Change& row, KeyPtr key) const { return row.entry->key < key; } - inline bool matches(const Change& row, KeyPtr key) const { return row.entry->key == key; } + inline bool isBefore(const Change& row, KeyPtr key) const { + return row.entry->key < key; + } + inline bool matches(const Change& row, KeyPtr key) const { + return row.entry->key == key; + } }; kj::Table> entriesToWrite; @@ -1007,8 +1041,10 @@ class ActorCache::Transaction final: public ActorCacheInterface::Transaction { // Adds the given key/value pair to `changes`. If an existing entry is replaced, *count is // incremented if it was a positive entry. If no existing entry is replaced, then the key // is returned, indicating that if a count is needed, we'll need to inspect cache/disk. - kj::Maybe putImpl(Lock& lock, kj::Own entry, - const WriteOptions& options, kj::Maybe count = kj::none); + kj::Maybe putImpl(Lock& lock, + kj::Own entry, + const WriteOptions& options, + kj::Maybe count = kj::none); }; } // namespace workerd diff --git a/src/workerd/io/actor-sqlite.c++ b/src/workerd/io/actor-sqlite.c++ index b6ab1265b40..e1781c3da13 100644 --- a/src/workerd/io/actor-sqlite.c++ +++ b/src/workerd/io/actor-sqlite.c++ @@ -9,16 +9,20 @@ namespace workerd { -ActorSqlite::ActorSqlite(kj::Own dbParam, OutputGate& outputGate, - kj::Function()> commitCallback, - Hooks& hooks) - : db(kj::mv(dbParam)), outputGate(outputGate), commitCallback(kj::mv(commitCallback)), - hooks(hooks), kv(*db), commitTasks(*this) { +ActorSqlite::ActorSqlite(kj::Own dbParam, + OutputGate& outputGate, + kj::Function()> commitCallback, + Hooks& hooks) + : db(kj::mv(dbParam)), + outputGate(outputGate), + commitCallback(kj::mv(commitCallback)), + hooks(hooks), + kv(*db), + commitTasks(*this) { db->onWrite(KJ_BIND_METHOD(*this, onWrite)); } -ActorSqlite::ImplicitTxn::ImplicitTxn(ActorSqlite& parent) - : parent(parent) { +ActorSqlite::ImplicitTxn::ImplicitTxn(ActorSqlite& parent): parent(parent) { KJ_REQUIRE(parent.currentTxn.is()); parent.beginTxn.run(); parent.currentTxn = this; @@ -46,10 +50,10 @@ void ActorSqlite::ImplicitTxn::commit() { } } -ActorSqlite::ExplicitTxn::ExplicitTxn(ActorSqlite& actorSqlite) - : actorSqlite(actorSqlite) { +ActorSqlite::ExplicitTxn::ExplicitTxn(ActorSqlite& actorSqlite): actorSqlite(actorSqlite) { KJ_SWITCH_ONEOF(actorSqlite.currentTxn) { - KJ_CASE_ONEOF(_, NoTxn) {} + KJ_CASE_ONEOF(_, NoTxn) { + } KJ_CASE_ONEOF(implicit, ImplicitTxn*) { // An implicit transaction is open, commit it now because it would be weird if writes // performed before the explicit transaction started were postponed until the transaction @@ -71,8 +75,7 @@ ActorSqlite::ExplicitTxn::ExplicitTxn(ActorSqlite& actorSqlite) // Unfortunately this means we cannot prepare the statement, unless we prepare a series of // statements for each depth. (Actually, it could be reasonable to prepare statements for // depth 0 specifically, but I'm not going to try it for now.) - actorSqlite.db->run(SqliteDatabase::TRUSTED, - kj::str("SAVEPOINT _cf_savepoint_", depth)); + actorSqlite.db->run(SqliteDatabase::TRUSTED, kj::str("SAVEPOINT _cf_savepoint_", depth)); } ActorSqlite::ExplicitTxn::~ExplicitTxn() noexcept(false) { [&]() noexcept { @@ -96,18 +99,17 @@ ActorSqlite::ExplicitTxn::~ExplicitTxn() noexcept(false) { } kj::Maybe> ActorSqlite::ExplicitTxn::commit() { - KJ_REQUIRE(!hasChild, "critical sections should have prevented committing transaction while " + KJ_REQUIRE(!hasChild, + "critical sections should have prevented committing transaction while " "nested txn is outstanding"); - actorSqlite.db->run(SqliteDatabase::TRUSTED, - kj::str("RELEASE _cf_savepoint_", depth)); + actorSqlite.db->run(SqliteDatabase::TRUSTED, kj::str("RELEASE _cf_savepoint_", depth)); committed = true; if (parent == kj::none) { // We committed the root transaction, so it's time to signal any replication layer and lock // the output gate in the meantime. - actorSqlite.commitTasks.add( - actorSqlite.outputGate.lockWhile(actorSqlite.commitCallback())); + actorSqlite.commitTasks.add(actorSqlite.outputGate.lockWhile(actorSqlite.commitCallback())); } // No backpressure for SQLite. @@ -125,18 +127,16 @@ kj::Promise ActorSqlite::ExplicitTxn::rollback() { } void ActorSqlite::ExplicitTxn::rollbackImpl() noexcept(false) { - actorSqlite.db->run(SqliteDatabase::TRUSTED, - kj::str("ROLLBACK TO _cf_savepoint_", depth)); - actorSqlite.db->run(SqliteDatabase::TRUSTED, - kj::str("RELEASE _cf_savepoint_", depth)); + actorSqlite.db->run(SqliteDatabase::TRUSTED, kj::str("ROLLBACK TO _cf_savepoint_", depth)); + actorSqlite.db->run(SqliteDatabase::TRUSTED, kj::str("RELEASE _cf_savepoint_", depth)); } void ActorSqlite::onWrite() { if (currentTxn.is()) { auto txn = kj::heap(*this); - commitTasks.add(outputGate.lockWhile(kj::evalLater( - [this, txn = kj::mv(txn)]() mutable -> kj::Promise { + commitTasks.add(outputGate.lockWhile( + kj::evalLater([this, txn = kj::mv(txn)]() mutable -> kj::Promise { // Don't commit if shutdown() has been called. requireNotBroken(); @@ -180,30 +180,25 @@ void ActorSqlite::requireNotBroken() { // ======================================================================================= // ActorCacheInterface implementation -kj::OneOf, - kj::Promise>> - ActorSqlite::get(Key key, ReadOptions options) { +kj::OneOf, kj::Promise>> +ActorSqlite::get(Key key, ReadOptions options) { requireNotBroken(); kj::Maybe result; - kv.get(key, [&](ValuePtr value) { - result = kj::heapArray(value); - }); + kv.get(key, [&](ValuePtr value) { result = kj::heapArray(value); }); return result; } -kj::OneOf> - ActorSqlite::get(kj::Array keys, ReadOptions options) { +kj::OneOf> ActorSqlite::get( + kj::Array keys, ReadOptions options) { requireNotBroken(); kj::Vector results; for (auto& key: keys) { - kv.get(key, [&](ValuePtr value) { - results.add(KeyValuePair { kj::mv(key), kj::heapArray(value) }); - }); + kv.get( + key, [&](ValuePtr value) { results.add(KeyValuePair{kj::mv(key), kj::heapArray(value)}); }); } - std::sort(results.begin(), results.end(), - [](auto& a, auto& b) { return a.key < b.key; }); + std::sort(results.begin(), results.end(), [](auto& a, auto& b) { return a.key < b.key; }); return GetResultList(kj::mv(results)); } @@ -214,27 +209,26 @@ kj::OneOf, kj::Promise>> ActorSqlite::ge return hooks.getAlarm(); } -kj::OneOf> - ActorSqlite::list(Key begin, kj::Maybe end, kj::Maybe limit, ReadOptions options) { +kj::OneOf> ActorSqlite:: + list(Key begin, kj::Maybe end, kj::Maybe limit, ReadOptions options) { requireNotBroken(); kj::Vector results; kv.list(begin, end, limit, SqliteKv::FORWARD, [&](KeyPtr key, ValuePtr value) { - results.add(KeyValuePair { kj::str(key), kj::heapArray(value) }); + results.add(KeyValuePair{kj::str(key), kj::heapArray(value)}); }); // Already guaranteed sorted. return GetResultList(kj::mv(results)); } -kj::OneOf> - ActorSqlite::listReverse(Key begin, kj::Maybe end, kj::Maybe limit, - ReadOptions options) { +kj::OneOf> ActorSqlite:: + listReverse(Key begin, kj::Maybe end, kj::Maybe limit, ReadOptions options) { requireNotBroken(); kj::Vector results; kv.list(begin, end, limit, SqliteKv::REVERSE, [&](KeyPtr key, ValuePtr value) { - results.add(KeyValuePair { kj::str(key), kj::heapArray(value) }); + results.add(KeyValuePair{kj::str(key), kj::heapArray(value)}); }); // Already guaranteed sorted (reversed). @@ -248,8 +242,7 @@ kj::Maybe> ActorSqlite::put(Key key, Value value, WriteOptions return kj::none; } -kj::Maybe> ActorSqlite::put( - kj::Array pairs, WriteOptions options) { +kj::Maybe> ActorSqlite::put(kj::Array pairs, WriteOptions options) { requireNotBroken(); for (auto& pair: pairs) { @@ -264,8 +257,7 @@ kj::OneOf> ActorSqlite::delete_(Key key, WriteOptions op return kv.delete_(key); } -kj::OneOf> ActorSqlite::delete_( - kj::Array keys, WriteOptions options) { +kj::OneOf> ActorSqlite::delete_(kj::Array keys, WriteOptions options) { requireNotBroken(); uint count = 0; @@ -375,24 +367,23 @@ kj::Promise ActorSqlite::Hooks::setAlarm(kj::Maybe) { } kj::OneOf, kj::Promise>> - ActorSqlite::ExplicitTxn::get(Key key, ReadOptions options) { +ActorSqlite::ExplicitTxn::get(Key key, ReadOptions options) { return actorSqlite.get(kj::mv(key), options); } -kj::OneOf> - ActorSqlite::ExplicitTxn::get(kj::Array keys, ReadOptions options) { +kj::OneOf> ActorSqlite:: + ExplicitTxn::get(kj::Array keys, ReadOptions options) { return actorSqlite.get(kj::mv(keys), options); } kj::OneOf, kj::Promise>> ActorSqlite::ExplicitTxn::getAlarm( ReadOptions options) { return actorSqlite.getAlarm(options); } -kj::OneOf> - ActorSqlite::ExplicitTxn::list( - Key begin, kj::Maybe end, kj::Maybe limit, ReadOptions options) { +kj::OneOf> ActorSqlite:: + ExplicitTxn::list(Key begin, kj::Maybe end, kj::Maybe limit, ReadOptions options) { return actorSqlite.list(kj::mv(begin), kj::mv(end), limit, options); } -kj::OneOf> - ActorSqlite::ExplicitTxn::listReverse( +kj::OneOf> ActorSqlite:: + ExplicitTxn::listReverse( Key begin, kj::Maybe end, kj::Maybe limit, ReadOptions options) { return actorSqlite.listReverse(kj::mv(begin), kj::mv(end), limit, options); } diff --git a/src/workerd/io/actor-sqlite.h b/src/workerd/io/actor-sqlite.h index 98bb253d68a..3e29769c049 100644 --- a/src/workerd/io/actor-sqlite.h +++ b/src/workerd/io/actor-sqlite.h @@ -39,13 +39,18 @@ class ActorSqlite final: public ActorCacheInterface, private kj::TaskSet::ErrorH // `commitCallback` will be invoked after committing a transaction. The output gate will block on // the returned promise. This can be used e.g. when the database needs to be replicated to other // machines before being considered durable. - explicit ActorSqlite(kj::Own dbParam, OutputGate& outputGate, - kj::Function()> commitCallback, - Hooks& hooks = const_cast(Hooks::DEFAULT)); + explicit ActorSqlite(kj::Own dbParam, + OutputGate& outputGate, + kj::Function()> commitCallback, + Hooks& hooks = const_cast(Hooks::DEFAULT)); - bool isCommitScheduled() { return !currentTxn.is(); } + bool isCommitScheduled() { + return !currentTxn.is(); + } - kj::Maybe getSqliteDatabase() override { return *db; } + kj::Maybe getSqliteDatabase() override { + return *db; + } kj::OneOf, kj::Promise>> get( Key key, ReadOptions options) override; @@ -61,7 +66,8 @@ class ActorSqlite final: public ActorCacheInterface, private kj::TaskSet::ErrorH kj::Maybe> put(kj::Array pairs, WriteOptions options) override; kj::OneOf> delete_(Key key, WriteOptions options) override; kj::OneOf> delete_(kj::Array keys, WriteOptions options) override; - kj::Maybe> setAlarm(kj::Maybe newAlarmTime, WriteOptions options) override; + kj::Maybe> setAlarm( + kj::Maybe newAlarmTime, WriteOptions options) override; // See ActorCacheOps. kj::Own startTransaction() override; diff --git a/src/workerd/io/actor-storage.c++ b/src/workerd/io/actor-storage.c++ index 26d1de35894..81feb6b3d68 100644 --- a/src/workerd/io/actor-storage.c++ +++ b/src/workerd/io/actor-storage.c++ @@ -10,23 +10,23 @@ namespace workerd { void ActorStorageLimits::checkMaxKeySize(kj::StringPtr key) { // It's tempting to put the key in this message, but that key could be surprisingly large so let's // return a simple message. - JSG_REQUIRE(key.size() <= MAX_KEY_SIZE, RangeError, kj::str( - "Keys cannot be larger than ", MAX_KEY_SIZE, " bytes. ", - "A key of size ", key.size(), " was provided.")); + JSG_REQUIRE(key.size() <= MAX_KEY_SIZE, RangeError, + kj::str("Keys cannot be larger than ", MAX_KEY_SIZE, " bytes. ", "A key of size ", key.size(), + " was provided.")); } void ActorStorageLimits::checkMaxValueSize(kj::StringPtr, kj::ArrayPtr value) { // It's tempting to put the key in this message, but that key could be surprisingly large so let's // return a simple message. - JSG_REQUIRE(value.size() <= ENFORCED_MAX_VALUE_SIZE, RangeError, kj::str( - "Values cannot be larger than ", ADVERTISED_MAX_VALUE_SIZE, " bytes. ", - "A value of size ", value.size(), " was provided.")); + JSG_REQUIRE(value.size() <= ENFORCED_MAX_VALUE_SIZE, RangeError, + kj::str("Values cannot be larger than ", ADVERTISED_MAX_VALUE_SIZE, " bytes. ", + "A value of size ", value.size(), " was provided.")); } void ActorStorageLimits::checkMaxPairsCount(size_t count) { - JSG_REQUIRE(count <= rpc::ActorStorage::MAX_KEYS, RangeError, kj::str( - "Maximum number of key value pairs is ", rpc::ActorStorage::MAX_KEYS, ". ", - count, " pairs were provided.")); + JSG_REQUIRE(count <= rpc::ActorStorage::MAX_KEYS, RangeError, + kj::str("Maximum number of key value pairs is ", rpc::ActorStorage::MAX_KEYS, ". ", count, + " pairs were provided.")); } -} // namespace workerd +} // namespace workerd diff --git a/src/workerd/io/actor-storage.h b/src/workerd/io/actor-storage.h index 9fafae88de2..9764eca2245 100644 --- a/src/workerd/io/actor-storage.h +++ b/src/workerd/io/actor-storage.h @@ -36,4 +36,4 @@ class ActorStorageLimits { static void checkMaxPairsCount(size_t count); }; -} // namespace workerd +} // namespace workerd diff --git a/src/workerd/io/compatibility-date-test.c++ b/src/workerd/io/compatibility-date-test.c++ index b2a8477181b..6f2c9d5ef34 100644 --- a/src/workerd/io/compatibility-date-test.c++ +++ b/src/workerd/io/compatibility-date-test.c++ @@ -61,12 +61,11 @@ KJ_TEST("compatibility date parsing") { } KJ_TEST("compatibility flag parsing") { - auto expectCompileCompatibilityFlags = [](kj::StringPtr compatDate, - kj::ArrayPtr featureFlags, - kj::StringPtr expectedOutput, - kj::ArrayPtr expectedErrors = nullptr, - CompatibilityDateValidation dateValidation = CompatibilityDateValidation::FUTURE_FOR_TEST, - bool r2InternalBetaApiSet = false, bool experimental = false) { + auto expectCompileCompatibilityFlags = + [](kj::StringPtr compatDate, kj::ArrayPtr featureFlags, + kj::StringPtr expectedOutput, kj::ArrayPtr expectedErrors = nullptr, + CompatibilityDateValidation dateValidation = CompatibilityDateValidation::FUTURE_FOR_TEST, + bool r2InternalBetaApiSet = false, bool experimental = false) { capnp::MallocMessageBuilder message; auto orphanage = message.getOrphanage(); @@ -80,8 +79,8 @@ KJ_TEST("compatibility flag parsing") { auto output = outputOrphan.get(); SimpleWorkerErrorReporter errorReporter; - compileCompatibilityFlags(compatDate, flagList.asReader(), output, errorReporter, experimental, - dateValidation); + compileCompatibilityFlags( + compatDate, flagList.asReader(), output, errorReporter, experimental, dateValidation); capnp::TextCodec codec; auto parsedExpectedOutput = codec.decode(expectedOutput, orphanage); @@ -108,20 +107,18 @@ KJ_TEST("compatibility flag parsing") { "(formDataParserSupportsFiles = false)"); // Test compatibility flag overrides. - expectCompileCompatibilityFlags("2021-05-17", {"formdata_parser_supports_files"_kj}, - "(formDataParserSupportsFiles = true)"); + expectCompileCompatibilityFlags( + "2021-05-17", {"formdata_parser_supports_files"_kj}, "(formDataParserSupportsFiles = true)"); expectCompileCompatibilityFlags("2021-05-17", {"fetch_refuses_unknown_protocols"_kj}, "(fetchRefusesUnknownProtocols = true)"); expectCompileCompatibilityFlags("2021-05-17", {"formdata_parser_supports_files"_kj, "fetch_refuses_unknown_protocols"_kj}, "(formDataParserSupportsFiles = true, fetchRefusesUnknownProtocols = true)"); - expectCompileCompatibilityFlags("2021-11-04", - {"fetch_refuses_unknown_protocols"_kj}, + expectCompileCompatibilityFlags("2021-11-04", {"fetch_refuses_unknown_protocols"_kj}, "(formDataParserSupportsFiles = true, fetchRefusesUnknownProtocols = true)"); // Test errors. - expectCompileCompatibilityFlags("abcd", {}, "()", - {"Invalid compatibility date: abcd"}); + expectCompileCompatibilityFlags("abcd", {}, "()", {"Invalid compatibility date: abcd"}); expectCompileCompatibilityFlags("2021-05-17", {"formdata_parser_supports_files"_kj, "formdata_parser_supports_files"_kj}, "(formDataParserSupportsFiles = true)", @@ -131,13 +128,12 @@ KJ_TEST("compatibility flag parsing") { "(formDataParserSupportsFiles = true)", {"Compatibility flags are mutually contradictory: " "formdata_parser_supports_files vs formdata_parser_converts_files_to_strings"}); - expectCompileCompatibilityFlags("2021-11-04", - {"formdata_parser_supports_files"_kj}, + expectCompileCompatibilityFlags("2021-11-04", {"formdata_parser_supports_files"_kj}, "(formDataParserSupportsFiles = true)", {"The compatibility flag formdata_parser_supports_files became the default as of " "2021-11-03 so does not need to be specified anymore."}); - expectCompileCompatibilityFlags("2021-05-17", {"unknown_feature"_kj}, "()", - {"No such compatibility flag: unknown_feature"}); + expectCompileCompatibilityFlags( + "2021-05-17", {"unknown_feature"_kj}, "()", {"No such compatibility flag: unknown_feature"}); expectCompileCompatibilityFlags("2252-04-01", {}, "()", {"Can't set compatibility date in the future: 2252-04-01"}, @@ -145,7 +141,8 @@ KJ_TEST("compatibility flag parsing") { expectCompileCompatibilityFlags("2252-04-01", {}, "()", {kj::str("This Worker requires compatibility date \"2252-04-01\", but the newest date " - "supported by this server binary is \"", SUPPORTED_COMPATIBILITY_DATE, "\".")}, + "supported by this server binary is \"", + SUPPORTED_COMPATIBILITY_DATE, "\".")}, CompatibilityDateValidation::CODE_VERSION); // Test experimental requirement using durable_object_rename as it is obsolete @@ -168,14 +165,14 @@ KJ_TEST("compatibility flag parsing") { // Multiple errors. expectCompileCompatibilityFlags("abcd", {"formdata_parser_supports_files"_kj, "fetch_refuses_unknown_protocols"_kj, - "unknown_feature"_kj, "fetch_refuses_unknown_protocols"_kj, - "another_feature"_kj, "formdata_parser_supports_files"_kj}, + "unknown_feature"_kj, "fetch_refuses_unknown_protocols"_kj, "another_feature"_kj, + "formdata_parser_supports_files"_kj}, "(formDataParserSupportsFiles = true, fetchRefusesUnknownProtocols = true)", {"Invalid compatibility date: abcd", - "Compatibility flag specified multiple times: fetch_refuses_unknown_protocols", - "Compatibility flag specified multiple times: formdata_parser_supports_files", - "No such compatibility flag: another_feature", - "No such compatibility flag: unknown_feature"}); + "Compatibility flag specified multiple times: fetch_refuses_unknown_protocols", + "Compatibility flag specified multiple times: formdata_parser_supports_files", + "No such compatibility flag: another_feature", + "No such compatibility flag: unknown_feature"}); // Can explicitly disable flag that's enabled for all dates.s expectCompileCompatibilityFlags("2021-05-17", {"r2_internal_beta_bindings"}, "()", {}, @@ -237,8 +234,8 @@ KJ_TEST("compatibility flag parsing") { " globalFetchStrictlyPublic = false," " newModuleRegistry = false," " allowCustomPorts = true," - " internalWritableStreamAbortClearsQueue = true)", {}, - CompatibilityDateValidation::FUTURE_FOR_TEST, false, false); + " internalWritableStreamAbortClearsQueue = true)", + {}, CompatibilityDateValidation::FUTURE_FOR_TEST, false, false); expectCompileCompatibilityFlags("2024-09-01", {"nodejs_compat"}, "(formDataParserSupportsFiles = true," " fetchRefusesUnknownProtocols = true," @@ -292,19 +289,18 @@ KJ_TEST("compatibility flag parsing") { " fetchStandardUrl = true," " nodeJsCompatV2 = false," " globalFetchStrictlyPublic = false," - " newModuleRegistry = false)", {}, - CompatibilityDateValidation::FUTURE_FOR_TEST, false, false); + " newModuleRegistry = false)", + {}, CompatibilityDateValidation::FUTURE_FOR_TEST, false, false); } KJ_TEST("encode to flag list for FL") { capnp::MallocMessageBuilder message; auto orphanage = message.getOrphanage(); - auto compileOwnFeatureFlags = [&](kj::StringPtr compatDate, - kj::ArrayPtr featureFlags, - CompatibilityDateValidation dateValidation = CompatibilityDateValidation::FUTURE_FOR_TEST, - bool experimental = false) { - + auto compileOwnFeatureFlags = + [&](kj::StringPtr compatDate, kj::ArrayPtr featureFlags, + CompatibilityDateValidation dateValidation = CompatibilityDateValidation::FUTURE_FOR_TEST, + bool experimental = false) { auto flagListOrphan = orphanage.newOrphan>(featureFlags.size()); auto flagList = flagListOrphan.get(); for (auto i: kj::indices(featureFlags)) { @@ -316,8 +312,8 @@ KJ_TEST("encode to flag list for FL") { SimpleWorkerErrorReporter errorReporter; - compileCompatibilityFlags(compatDate, flagList.asReader(), output, errorReporter, experimental, - dateValidation); + compileCompatibilityFlags( + compatDate, flagList.asReader(), output, errorReporter, experimental, dateValidation); KJ_ASSERT(errorReporter.errors.empty()); return kj::mv(outputOrphan); @@ -325,7 +321,7 @@ KJ_TEST("encode to flag list for FL") { { // Disabled by date. - auto featureFlagsOrphan = compileOwnFeatureFlags("2021-05-17",{}); + auto featureFlagsOrphan = compileOwnFeatureFlags("2021-05-17", {}); auto featureFlags = featureFlagsOrphan.get(); auto strings = decompileCompatibilityFlagsForFl(featureFlags); KJ_EXPECT(strings.size() == 0); @@ -333,7 +329,7 @@ KJ_TEST("encode to flag list for FL") { { // Disabled by date, enabled by flag. - auto featureFlagsOrphan = compileOwnFeatureFlags("2021-05-17",{"minimal_subrequests"_kj}); + auto featureFlagsOrphan = compileOwnFeatureFlags("2021-05-17", {"minimal_subrequests"_kj}); auto featureFlags = featureFlagsOrphan.get(); auto strings = decompileCompatibilityFlagsForFl(featureFlags); KJ_EXPECT(strings.size() == 1); @@ -342,7 +338,7 @@ KJ_TEST("encode to flag list for FL") { { // Enabled by date. - auto featureFlagsOrphan = compileOwnFeatureFlags("2022-07-01",{}); + auto featureFlagsOrphan = compileOwnFeatureFlags("2022-07-01", {}); auto featureFlags = featureFlagsOrphan.get(); auto strings = decompileCompatibilityFlagsForFl(featureFlags); KJ_EXPECT(strings.size() == 2); @@ -352,7 +348,7 @@ KJ_TEST("encode to flag list for FL") { { // Enabled by date, disabled by flag. - auto featureFlagsOrphan = compileOwnFeatureFlags("2022-07-01",{"cots_on_external_fetch"}); + auto featureFlagsOrphan = compileOwnFeatureFlags("2022-07-01", {"cots_on_external_fetch"}); auto featureFlags = featureFlagsOrphan.get(); auto strings = decompileCompatibilityFlagsForFl(featureFlags); KJ_EXPECT(strings.size() == 1); diff --git a/src/workerd/io/compatibility-date.c++ b/src/workerd/io/compatibility-date.c++ index 06fbc565e83..793bbcbf7c6 100644 --- a/src/workerd/io/compatibility-date.c++ +++ b/src/workerd/io/compatibility-date.c++ @@ -57,11 +57,11 @@ struct CompatDate { if (year < 2000 || year >= 3000) return kj::none; if (month < 1 || month > 12) return kj::none; if (day < 1 || day > 31) return kj::none; - return CompatDate { year, month, day }; + return CompatDate{year, month, day}; } static CompatDate parse(kj::StringPtr text, Worker::ValidationErrorReporter& errorReporter) { - static constexpr CompatDate DEFAULT_DATE { 2021, 5, 1 }; + static constexpr CompatDate DEFAULT_DATE{2021, 5, 1}; KJ_IF_SOME(v, parse(text)) { return v; } else { @@ -79,11 +79,11 @@ struct CompatDate { struct tm t; KJ_ASSERT(gmtime_r(&now, &t) == &t); #endif - return { (uint)(t.tm_year + 1900), (uint)(t.tm_mon + 1), (uint)t.tm_mday }; + return {(uint)(t.tm_year + 1900), (uint)(t.tm_mon + 1), (uint)t.tm_mday}; } kj::String toString() { - return kj::str(year, '-', month < 10 ? "0" : "", month, '-', day < 10 ? "0" : "", day); + return kj::str(year, '-', month < 10 ? "0" : "", month, '-', day < 10 ? "0" : "", day); } }; } // namespace @@ -92,26 +92,29 @@ kj::String currentDateStr() { return CompatDate::today().toString(); } -void compileCompatibilityFlags(kj::StringPtr compatDate, capnp::List::Reader compatFlags, - CompatibilityFlags::Builder output, - Worker::ValidationErrorReporter& errorReporter, - bool allowExperimentalFeatures, - CompatibilityDateValidation dateValidation) { +void compileCompatibilityFlags(kj::StringPtr compatDate, + capnp::List::Reader compatFlags, + CompatibilityFlags::Builder output, + Worker::ValidationErrorReporter& errorReporter, + bool allowExperimentalFeatures, + CompatibilityDateValidation dateValidation) { auto parsedCompatDate = CompatDate::parse(compatDate, errorReporter); switch (dateValidation) { case CompatibilityDateValidation::CODE_VERSION: if (KJ_ASSERT_NONNULL(CompatDate::parse(SUPPORTED_COMPATIBILITY_DATE)) < parsedCompatDate) { - errorReporter.addError(kj::str( - "This Worker requires compatibility date \"", parsedCompatDate, "\", but the newest " - "date supported by this server binary is \"", SUPPORTED_COMPATIBILITY_DATE, "\".")); + errorReporter.addError( + kj::str("This Worker requires compatibility date \"", parsedCompatDate, + "\", but the newest " + "date supported by this server binary is \"", + SUPPORTED_COMPATIBILITY_DATE, "\".")); } break; case CompatibilityDateValidation::CURRENT_DATE_FOR_CLOUDFLARE: if (CompatDate::today() < parsedCompatDate) { - errorReporter.addError(kj::str( - "Can't set compatibility date in the future: ", parsedCompatDate)); + errorReporter.addError( + kj::str("Can't set compatibility date in the future: ", parsedCompatDate)); } break; @@ -178,7 +181,7 @@ void compileCompatibilityFlags(kj::StringPtr compatDate, capnp::List= parsedDate && !disableByFlag) { - maybeImpliedBy.emplace(ImpliedBy { + maybeImpliedBy.emplace(ImpliedBy{ .field = field, .other = schema.getFieldByName(s.getName()), }); @@ -195,18 +198,15 @@ void compileCompatibilityFlags(kj::StringPtr compatDate, capnp::List()) { dynamicOutput.set(implied.field, true); } @@ -248,8 +248,7 @@ struct ParsedField { capnp::StructSchema::Field field; }; -kj::Array makeFieldTable( - capnp::StructSchema::FieldList fields) { +kj::Array makeFieldTable(capnp::StructSchema::FieldList fields) { kj::Vector table(fields.size()); for (auto field: fields) { @@ -265,7 +264,7 @@ kj::Array makeFieldTable( } if (neededByFl) { - table.add(ParsedField { + table.add(ParsedField{ .enableFlag = KJ_REQUIRE_NONNULL(enableFlag), .field = field, }); @@ -278,8 +277,8 @@ kj::Array makeFieldTable( } // namespace kj::Array decompileCompatibilityFlagsForFl(CompatibilityFlags::Reader input) { - static const auto fieldTable = makeFieldTable( - capnp::Schema::from().getFields()); + static const auto fieldTable = + makeFieldTable(capnp::Schema::from().getFields()); kj::Vector enableFlags; diff --git a/src/workerd/io/compatibility-date.h b/src/workerd/io/compatibility-date.h index c182edf76a0..8633b49fb2b 100644 --- a/src/workerd/io/compatibility-date.h +++ b/src/workerd/io/compatibility-date.h @@ -32,11 +32,12 @@ enum class CompatibilityDateValidation { FUTURE_FOR_TEST }; -void compileCompatibilityFlags(kj::StringPtr compatDate, capnp::List::Reader compatFlags, - CompatibilityFlags::Builder output, - Worker::ValidationErrorReporter& errorReporter, - bool allowExperimentalFeatures, - CompatibilityDateValidation dateValidation); +void compileCompatibilityFlags(kj::StringPtr compatDate, + capnp::List::Reader compatFlags, + CompatibilityFlags::Builder output, + Worker::ValidationErrorReporter& errorReporter, + bool allowExperimentalFeatures, + CompatibilityDateValidation dateValidation); // Return an array of compatibility enable-flags which express the given FeatureFlags. The returned // StringPtrs point to FeatureFlags annotation parameters, which live in static storage. diff --git a/src/workerd/io/hibernation-manager.c++ b/src/workerd/io/hibernation-manager.c++ index 08a48abb4d9..0f11d7d83eb 100644 --- a/src/workerd/io/hibernation-manager.c++ +++ b/src/workerd/io/hibernation-manager.c++ @@ -66,17 +66,17 @@ jsg::Ref HibernationManagerImpl::HibernatableWebSocket::getActiv // Now that we unhibernated the WebSocket, we can set the last received autoResponse timestamp // that was stored in the corresponding HibernatableWebSocket. We also move autoResponsePromise // from the hibernation manager to api::websocket to prevent possible ws.send races. - activeOrPackage.init>( - api::WebSocket::hibernatableFromNative(js, *KJ_REQUIRE_NONNULL(ws), kj::mv(package)) - )->setAutoResponseStatus(autoResponseTimestamp, kj::mv(autoResponsePromise)); + activeOrPackage + .init>( + api::WebSocket::hibernatableFromNative(js, *KJ_REQUIRE_NONNULL(ws), kj::mv(package))) + ->setAutoResponseStatus(autoResponseTimestamp, kj::mv(autoResponsePromise)); autoResponsePromise = kj::READY_NOW; } return activeOrPackage.get>().addRef(); } HibernationManagerImpl::HibernationManagerImpl( - kj::Own loopback, - uint16_t hibernationEventType) + kj::Own loopback, uint16_t hibernationEventType) : loopback(kj::mv(loopback)), hibernationEventType(hibernationEventType), onDisconnect(DisconnectHandler{}), @@ -94,8 +94,7 @@ kj::Own HibernationManagerImpl::addRef() { } void HibernationManagerImpl::acceptWebSocket( - jsg::Ref ws, - kj::ArrayPtr tags) { + jsg::Ref ws, kj::ArrayPtr tags) { // First, we create the HibernatableWebSocket and add it to the collection where it'll stay // until it's destroyed. @@ -122,10 +121,7 @@ void HibernationManagerImpl::acceptWebSocket( auto& tagCollection = tagToWs.findOrCreate(*tag, [&tag]() { auto item = kj::heap( kj::mv(*tag), kj::heap>()); - return decltype(tagToWs)::Entry { - item->tag, - kj::mv(item) - }; + return decltype(tagToWs)::Entry{item->tag, kj::mv(item)}; }); // This TagListItem sits in the HibernatableWebSocket's tagItems array. auto& tagListItem = refToHibernatable.tagItems[position]; @@ -142,8 +138,9 @@ void HibernationManagerImpl::acceptWebSocket( // Before starting the readLoop, we need to move the kj::Own from the // api::WebSocket into the HibernatableWebSocket and accept the api::WebSocket as "hibernatable". - refToHibernatable.ws = refToHibernatable.activeOrPackage.get>() - ->acceptAsHibernatable(refToHibernatable.getTags()); + refToHibernatable.ws = + refToHibernatable.activeOrPackage.get>()->acceptAsHibernatable( + refToHibernatable.getTags()); // Finally, we initiate the readloop for this HibernatableWebSocket and // give the task to the HibernationManager so it lives long. @@ -161,8 +158,7 @@ kj::Promise HibernationManagerImpl::handleReadLoop(HibernatableWebSocket& } kj::Vector> HibernationManagerImpl::getWebSockets( - jsg::Lock& js, - kj::Maybe maybeTag) { + jsg::Lock& js, kj::Maybe maybeTag) { kj::Vector> matches; KJ_IF_SOME(tag, maybeTag) { KJ_IF_SOME(item, tagToWs.find(tag)) { @@ -174,7 +170,7 @@ kj::Vector> HibernationManagerImpl::getWebSockets( } } else { // Add all websockets! - for (auto& hibWS : allWs) { + for (auto& hibWS: allWs) { matches.add(hibWS->getActiveOrUnhibernate(js)); } } @@ -194,12 +190,13 @@ void HibernationManagerImpl::setWebSocketAutoResponse( autoResponsePair->response = kj::none; } -kj::Maybe> HibernationManagerImpl::getWebSocketAutoResponse() { +kj::Maybe> HibernationManagerImpl:: + getWebSocketAutoResponse() { KJ_IF_SOME(req, autoResponsePair->request) { // When getting the currently set auto-response pair, if we have a request we must have a response // set. If not, we'll throw. - return api::WebSocketRequestResponsePair::constructor(kj::str(req), - kj::str(KJ_REQUIRE_NONNULL(autoResponsePair->response))); + return api::WebSocketRequestResponsePair::constructor( + kj::str(req), kj::str(KJ_REQUIRE_NONNULL(autoResponsePair->response))); } return kj::none; } @@ -210,13 +207,14 @@ void HibernationManagerImpl::setTimerChannel(TimerChannel& timerChannel) { void HibernationManagerImpl::hibernateWebSockets(Worker::Lock& lock) { JSG_WITHIN_CONTEXT_SCOPE(lock, lock.getContext(), [&](jsg::Lock& js) { - for (auto& ws : allWs) { + for (auto& ws: allWs) { KJ_IF_SOME(active, ws->activeOrPackage.tryGet>()) { // Transfers ownership of properties from api::WebSocket to HibernatableWebSocket via the // HibernationPackage. ws->activeOrPackage.init( active.get()->buildPackageForHibernation()); - } else {} // Here to quash compiler warning + } else { + } // Here to quash compiler warning } }); } @@ -248,10 +246,8 @@ kj::Promise HibernationManagerImpl::handleSocketTermination( if (!hib.hasDispatchedClose && (error.getType() == kj::Exception::Type::DISCONNECTED)) { // If premature disconnect/cancel, dispatch a close event if we haven't already. hib.hasDispatchedClose = true; - params = api::HibernatableSocketParams( - 1006, - kj::str("WebSocket disconnected without sending Close frame."), - false, + params = api::HibernatableSocketParams(1006, + kj::str("WebSocket disconnected without sending Close frame."), false, kj::mv(websocketId)); } else { // Otherwise, we need to dispatch an error event! @@ -261,9 +257,11 @@ kj::Promise HibernationManagerImpl::handleSocketTermination( KJ_REQUIRE_NONNULL(params).setTimeout(eventTimeoutMs); // Dispatch the event. auto workerInterface = loopback->getWorker(IoChannelFactory::SubrequestMetadata{}); - event = workerInterface->customEvent(kj::heap( - hibernationEventType, readLoopTasks, kj::mv(KJ_REQUIRE_NONNULL(params)), *this)) - .ignoreResult().attach(kj::mv(workerInterface)); + event = workerInterface + ->customEvent(kj::heap( + hibernationEventType, readLoopTasks, kj::mv(KJ_REQUIRE_NONNULL(params)), *this)) + .ignoreResult() + .attach(kj::mv(workerInterface)); } // Returning the event promise will store it in readLoopTasks. @@ -286,7 +284,7 @@ kj::Promise HibernationManagerImpl::readLoop(HibernatableWebSocket& hib) { // If we have a request != kj::none, we can compare it the received message. This also implies // that we have a response set in autoResponsePair. - KJ_IF_SOME (req, autoResponsePair->request) { + KJ_IF_SOME(req, autoResponsePair->request) { KJ_SWITCH_ONEOF(message) { KJ_CASE_ONEOF(text, kj::String) { if (text == req) { @@ -303,7 +301,7 @@ kj::Promise HibernationManagerImpl::readLoop(HibernatableWebSocket& hib) { // We'll store the current timestamp in the HibernatableWebSocket to assure it gets // stored even if the WebSocket is currently hibernating. In that scenario, the timestamp // value will be loaded into the WebSocket during unhibernation. - KJ_SWITCH_ONEOF(hib.activeOrPackage){ + KJ_SWITCH_ONEOF(hib.activeOrPackage) { KJ_CASE_ONEOF(apiWs, jsg::Ref) { // If the actor is not hibernated/If the WebSocket is active, we need to update // autoResponseTimestamp on the active websocket. @@ -320,8 +318,7 @@ kj::Promise HibernationManagerImpl::readLoop(HibernatableWebSocket& hib) { // If we do that, we have to provide it with the promise to avoid races. This can // happen if we have a websocket hibernating, that unhibernates and sends a // message while ws.send() for auto-response is also sending. - auto p = ws.send( - KJ_REQUIRE_NONNULL(autoResponsePair->response).asArray()).fork(); + auto p = ws.send(KJ_REQUIRE_NONNULL(autoResponsePair->response).asArray()).fork(); hib.autoResponsePromise = p.addBranch(); co_await p; hib.autoResponsePromise = kj::READY_NOW; @@ -366,13 +363,12 @@ kj::Promise HibernationManagerImpl::readLoop(HibernatableWebSocket& hib) { auto isClose = params.isCloseEvent(); // Dispatch the event. auto workerInterface = loopback->getWorker(IoChannelFactory::SubrequestMetadata{}); - co_await workerInterface->customEvent( - kj::heap( - hibernationEventType, readLoopTasks, kj::mv(params), *this)); + co_await workerInterface->customEvent(kj::heap( + hibernationEventType, readLoopTasks, kj::mv(params), *this)); if (isClose) { co_return; } } } -}; // namespace workerd +}; // namespace workerd diff --git a/src/workerd/io/hibernation-manager.h b/src/workerd/io/hibernation-manager.h index ae482f4a721..90d9c0d50a0 100644 --- a/src/workerd/io/hibernation-manager.h +++ b/src/workerd/io/hibernation-manager.h @@ -15,7 +15,7 @@ namespace workerd { // Implements the HibernationManager class. -class HibernationManagerImpl final : public Worker::Actor::HibernationManager { +class HibernationManagerImpl final: public Worker::Actor::HibernationManager { public: HibernationManagerImpl(kj::Own loopback, uint16_t hibernationEventType); ~HibernationManagerImpl() noexcept(false); @@ -28,15 +28,14 @@ class HibernationManagerImpl final : public Worker::Actor::HibernationManager { // Gets a collection of websockets associated with the given tag. Any hibernating websockets will // be woken up. If no tag is provided, we return all accepted websockets. kj::Vector> getWebSockets( - jsg::Lock& js, - kj::Maybe tag) override; + jsg::Lock& js, kj::Maybe tag) override; // Hibernates all the websockets held by the HibernationManager. // This converts our activeOrPackage from an api::WebSocket to a HibernationPackage. void hibernateWebSockets(Worker::Lock& lock) override; - void setWebSocketAutoResponse(kj::Maybe request, - kj::Maybe response) override; + void setWebSocketAutoResponse( + kj::Maybe request, kj::Maybe response) override; kj::Maybe> getWebSocketAutoResponse() override; void setTimerChannel(TimerChannel& timerChannel) override; @@ -77,8 +76,8 @@ class HibernationManagerImpl final : public Worker::Actor::HibernationManager { class HibernatableWebSocket { public: HibernatableWebSocket(jsg::Ref websocket, - kj::ArrayPtr tags, - HibernationManagerImpl& manager); + kj::ArrayPtr tags, + HibernationManagerImpl& manager); ~HibernatableWebSocket() noexcept(false); KJ_DISALLOW_COPY_AND_MOVE(HibernatableWebSocket); @@ -150,8 +149,7 @@ class HibernationManagerImpl final : public Worker::Actor::HibernationManager { // dispatch a close event (if we haven't already), or an error event. // We will also remove the HibernatableWebSocket from the HibernationManager's collections. kj::Promise handleSocketTermination( - HibernatableWebSocket& hib, kj::Maybe& maybeError) - KJ_WARN_UNUSED_RESULT; + HibernatableWebSocket& hib, kj::Maybe& maybeError) KJ_WARN_UNUSED_RESULT; // Like the api::WebSocket readLoop(), but we dispatch different types of events. kj::Promise readLoop(HibernatableWebSocket& hib); @@ -214,4 +212,4 @@ class HibernationManagerImpl final : public Worker::Actor::HibernationManager { kj::Maybe timer; kj::Maybe eventTimeoutMs; }; -}; // namespace workerd +}; // namespace workerd diff --git a/src/workerd/io/io-channels.h b/src/workerd/io/io-channels.h index 90b43188334..a9cd9267712 100644 --- a/src/workerd/io/io-channels.h +++ b/src/workerd/io/io-channels.h @@ -10,7 +10,9 @@ #include #include -namespace kj { class HttpClient; } +namespace kj { +class HttpClient; +} namespace workerd { @@ -32,8 +34,7 @@ class CacheClient { // The returned client is intended to be used for one request. `parentSpan` has the same meaning // as in `IoContext::SubrequestMetadata`. virtual kj::Own getNamespace( - kj::StringPtr name, kj::Maybe cfBlobJson, - SpanParent parentSpan) = 0; + kj::StringPtr name, kj::Maybe cfBlobJson, SpanParent parentSpan) = 0; }; // A timer instance, used to back Date.now(), setTimeout(), etc. This object may implement @@ -146,12 +147,15 @@ class IoChannelFactory { // one of the worker's bindings, however it doesn't necessarily have to be from the the correct // `ActorIdFactory` -- if it's from some other factory, the method will throw an appropriate // exception. - virtual kj::Own getGlobalActor(uint channel, const ActorIdFactory::ActorId& id, - kj::Maybe locationHint, ActorGetMode mode, SpanParent parentSpan) = 0; + virtual kj::Own getGlobalActor(uint channel, + const ActorIdFactory::ActorId& id, + kj::Maybe locationHint, + ActorGetMode mode, + SpanParent parentSpan) = 0; // Get an actor stub from the given namespace for the actor with the given name. - virtual kj::Own getColoLocalActor(uint channel, kj::StringPtr id, - SpanParent parentSpan) = 0; + virtual kj::Own getColoLocalActor( + uint channel, kj::StringPtr id, SpanParent parentSpan) = 0; // Aborts all actors except those in namespaces marked with `preventEviction`. virtual void abortAllActors() { @@ -159,4 +163,4 @@ class IoChannelFactory { } }; -} // namespace workerd +} // namespace workerd diff --git a/src/workerd/io/io-context.c++ b/src/workerd/io/io-context.c++ index 05a0ea1e758..109bf7048b1 100644 --- a/src/workerd/io/io-context.c++ +++ b/src/workerd/io/io-context.c++ @@ -113,9 +113,9 @@ public: }; IoContext::IoContext(ThreadContext& thread, - kj::Own workerParam, - kj::Maybe actorParam, - kj::Own limitEnforcerParam) + kj::Own workerParam, + kj::Maybe actorParam, + kj::Own limitEnforcerParam) : thread(thread), worker(kj::mv(workerParam)), actor(actorParam), @@ -130,11 +130,11 @@ IoContext::IoContext(ThreadContext& thread, auto localAbortPromise = kj::mv(paf.promise); // Arrange to complain if execution resource limits (CPU/memory) are exceeded. - auto makeLimitsPromise = [this](){ + auto makeLimitsPromise = [this]() { auto promise = limitEnforcer->onLimitsExceeded(); if (isInspectorEnabled()) { // Arrange to report the problem to the inspector in addition to aborting. - promise = (kj::coCapture([this, promise=kj::mv(promise)]() mutable -> kj::Promise { + promise = (kj::coCapture([this, promise = kj::mv(promise)]() mutable -> kj::Promise { kj::Maybe maybeException; try { co_await promise; @@ -167,8 +167,8 @@ IoContext::IoContext(ThreadContext& thread, // Stop the ActorCache from flushing any scheduled write operations to prevent any unnecessary // or unintentional async work - localAbortPromise = (kj::coCapture([this, promise = kj::mv(localAbortPromise)]() mutable - -> kj::Promise { + localAbortPromise = + (kj::coCapture([this, promise = kj::mv(localAbortPromise)]() mutable -> kj::Promise { try { co_await promise; } catch (...) { @@ -193,8 +193,7 @@ IoContext::IoContext(ThreadContext& thread, } } -IoContext::IncomingRequest::IoContext_IncomingRequest( - kj::Own contextParam, +IoContext::IncomingRequest::IoContext_IncomingRequest(kj::Own contextParam, kj::Own ioChannelFactoryParam, kj::Own metricsParam, kj::Maybe> workerTracer) @@ -264,14 +263,13 @@ IoContext::IncomingRequest::~IoContext_IncomingRequest() noexcept(false) { } InputGate::Lock IoContext::getInputLock() { - return KJ_ASSERT_NONNULL(currentInputLock, - "no input lock available in this context").addRef(); + return KJ_ASSERT_NONNULL(currentInputLock, "no input lock available in this context").addRef(); } kj::Maybe> IoContext::getCriticalSection() { KJ_IF_SOME(l, currentInputLock) { - return l.getCriticalSection() - .map([](InputGate::CriticalSection& cs) { return kj::addRef(cs); }); + return l.getCriticalSection().map( + [](InputGate::CriticalSection& cs) { return kj::addRef(cs); }); } else { return kj::none; } @@ -290,15 +288,12 @@ bool IoContext::hasOutputGate() { } kj::Maybe> IoContext::waitForOutputLocksIfNecessary() { - return actor.map([](Worker::Actor& actor) { - return actor.getOutputGate().wait(); - }); + return actor.map([](Worker::Actor& actor) { return actor.getOutputGate().wait(); }); } kj::Maybe>> IoContext::waitForOutputLocksIfNecessaryIoOwn() { - return waitForOutputLocksIfNecessary().map([this](kj::Promise promise) { - return addObject(kj::heap(kj::mv(promise))); - }); + return waitForOutputLocksIfNecessary().map( + [this](kj::Promise promise) { return addObject(kj::heap(kj::mv(promise))); }); } bool IoContext::isOutputGateBroken() { @@ -333,16 +328,14 @@ void IoContext::logUncaughtException(kj::StringPtr description) { KJ_REQUIRE_NONNULL(currentLock).logUncaughtException(description); } -void IoContext::logUncaughtException(UncaughtExceptionSource source, - const jsg::JsValue& exception, - const jsg::JsMessage& message) { +void IoContext::logUncaughtException( + UncaughtExceptionSource source, const jsg::JsValue& exception, const jsg::JsMessage& message) { KJ_REQUIRE_NONNULL(currentLock).logUncaughtException(source, exception, message); } -void IoContext::logUncaughtExceptionAsync(UncaughtExceptionSource source, - kj::Exception&& exception) { - if (getWorkerTracer() == kj::none && - !worker->getIsolate().isInspectorEnabled()) { +void IoContext::logUncaughtExceptionAsync( + UncaughtExceptionSource source, kj::Exception&& exception) { + if (getWorkerTracer() == kj::none && !worker->getIsolate().isInspectorEnabled()) { // We don't need to take the isolate lock as neither inspecting nor tracing is enabled. We // do still want to syslog if relevant, but we can do that without a lock. if (!jsg::isTunneledException(exception.getDescription()) && @@ -362,7 +355,8 @@ void IoContext::logUncaughtExceptionAsync(UncaughtExceptionSource source, kj::Exception exception; RunnableImpl(UncaughtExceptionSource source, kj::Exception&& exception) - : source(source), exception(kj::mv(exception)) {} + : source(source), + exception(kj::mv(exception)) {} void run(Worker::Lock& lock) override { // TODO(soon): Add logUncaughtException to jsg::Lock. lock.logUncaughtException(source, kj::mv(exception)); @@ -372,9 +366,7 @@ void IoContext::logUncaughtExceptionAsync(UncaughtExceptionSource source, // Make sure this is logged even if another exception occurs trying to log it to the devtools inspector, // e.g. if `runImpl` throws before calling logUncaughtException. // This is useful for tests (and in fact only affects tests, since it's logged at an INFO level). - KJ_ON_SCOPE_FAILURE({ - KJ_LOG(INFO, "uncaught exception", source, exception); - }); + KJ_ON_SCOPE_FAILURE({ KJ_LOG(INFO, "uncaught exception", source, exception); }); RunnableImpl runnable(source, kj::mv(exception)); // TODO(perf): Is it worth using an async lock here? The only case where it really matters is // when a trace worker is active, but maybe they'll be more common in the future. To take an @@ -408,9 +400,8 @@ void IoContext::addTask(kj::Promise promise) { auto& metrics = getMetrics(); if (metrics.getSpan().isObserved()) { metrics.addedContextTask(); - promise = promise.attach(kj::defer([metrics = kj::addRef(metrics)]() mutable { - metrics->finishedContextTask(); - })); + promise = promise.attach( + kj::defer([metrics = kj::addRef(metrics)]() mutable { metrics->finishedContextTask(); })); } } @@ -424,9 +415,8 @@ void IoContext::addWaitUntil(kj::Promise promise) { auto& metrics = getMetrics(); if (metrics.getSpan().isObserved()) { metrics.addedWaitUntilTask(); - promise = promise.attach(kj::defer([metrics = kj::addRef(metrics)]() mutable { - metrics->finishedWaitUntilTask(); - })); + promise = promise.attach(kj::defer( + [metrics = kj::addRef(metrics)]() mutable { metrics->finishedWaitUntilTask(); })); } } @@ -458,11 +448,13 @@ kj::Promise IoContext::IncomingRequest::drain() { // For non-actor requests, apply the configured soft timeout, typically 30 seconds. timeoutPromise = context->limitEnforcer->limitDrain(); } - return context->waitUntilTasks.onEmpty().exclusiveJoin(kj::mv(timeoutPromise)) - .exclusiveJoin(context->abortPromise.addBranch().then([]{}, [](kj::Exception&&){})); + return context->waitUntilTasks.onEmpty() + .exclusiveJoin(kj::mv(timeoutPromise)) + .exclusiveJoin(context->abortPromise.addBranch().then([] {}, [](kj::Exception&&) {})); } -kj::Promise IoContext::IncomingRequest::finishScheduled() { +kj::Promise IoContext::IncomingRequest:: + finishScheduled() { // TODO(someday): In principle we should be able to support delivering the "scheduled" event type // to an actor, and this may be important if we open up the whole of WorkerInterface to be // callable from any stub. However, the logic around async tasks would have to be different. We @@ -476,17 +468,14 @@ kj::Promise IoContext::Incomin KJ_ASSERT(context->incomingRequests.size() == 1); context->incomingRequests.front().waitedForWaitUntil = true; - auto timeoutPromise = context->limitEnforcer->limitScheduled().then([] { - return IoContext_IncomingRequest::FinishScheduledResult::TIMEOUT; - }); + auto timeoutPromise = context->limitEnforcer->limitScheduled().then( + [] { return IoContext_IncomingRequest::FinishScheduledResult::TIMEOUT; }); return context->waitUntilTasks.onEmpty() .then([]() { return IoContext_IncomingRequest::FinishScheduledResult::COMPLETED; }) .exclusiveJoin(kj::mv(timeoutPromise)) .exclusiveJoin(context->abortPromise.addBranch().then([] { - return IoContext_IncomingRequest::FinishScheduledResult::ABORTED; - }, [](kj::Exception&&) { - return IoContext_IncomingRequest::FinishScheduledResult::ABORTED; - })); + return IoContext_IncomingRequest::FinishScheduledResult::ABORTED; + }, [](kj::Exception&&) { return IoContext_IncomingRequest::FinishScheduledResult::ABORTED; })); } class IoContext::PendingEvent: public kj::Refcounted { @@ -520,12 +509,10 @@ IoContext::PendingEvent::~PendingEvent() noexcept(false) { // events come back into JavaScript. If registerPendingEvent() is called in the meantime, this // will be canceled. context.runFinalizersTask = Worker::AsyncLock::whenThreadIdle() - .then([&context = context]() noexcept { + .then([&context = context]() noexcept { // We have nothing left to do and no PendingEvent has been registered. Run finalizers now. - return context.worker->takeAsyncLock(context.getMetrics()).then( - [&context](Worker::AsyncLock asyncLock) { - context.runFinalizers(asyncLock); - }); + return context.worker->takeAsyncLock(context.getMetrics()) + .then([&context](Worker::AsyncLock asyncLock) { context.runFinalizers(asyncLock); }); }).eagerlyEvaluate(nullptr); } @@ -552,7 +539,8 @@ kj::Own IoContext::registerPendingEvent() { IoContext::TimeoutManagerImpl::TimeoutState::TimeoutState( TimeoutManagerImpl& manager, TimeoutParameters params) - : manager(manager), params(kj::mv(params)) { + : manager(manager), + params(kj::mv(params)) { ++manager.timeoutsStarted; } @@ -565,9 +553,7 @@ IoContext::TimeoutManagerImpl::TimeoutState::~TimeoutState() { void IoContext::TimeoutManagerImpl::TimeoutState::trigger(Worker::Lock& lock) { isRunning = true; - auto cleanupGuard = kj::defer([&]{ - isRunning = false; - }); + auto cleanupGuard = kj::defer([&] { isRunning = false; }); // Now it's safe to call the user's callback. KJ_IF_SOME(function, params.function) { @@ -594,10 +580,9 @@ void IoContext::TimeoutManagerImpl::TimeoutState::cancel() { auto IoContext::TimeoutManagerImpl::addState( TimeoutId::Generator& generator, TimeoutParameters params) -> IdAndIterator { JSG_REQUIRE(getTimeoutCount() < MAX_TIMEOUTS, DOMQuotaExceededError, - "You have exceeded the number of active timeouts you may set.", - " max active timeouts: ", MAX_TIMEOUTS, - ", current active timeouts: ", getTimeoutCount(), - ", finished timeouts: ", timeoutsFinished); + "You have exceeded the number of active timeouts you may set.", + " max active timeouts: ", MAX_TIMEOUTS, ", current active timeouts: ", getTimeoutCount(), + ", finished timeouts: ", timeoutsFinished); auto id = generator.getNext(); auto [it, wasEmplaced] = timeouts.try_emplace(id, *this, kj::mv(params)); @@ -612,7 +597,7 @@ auto IoContext::TimeoutManagerImpl::addState( delay, repeat); } - return { id, it }; + return {id, it}; } void IoContext::TimeoutManagerImpl::setTimeoutImpl(IoContext& context, Iterator it) { @@ -633,9 +618,9 @@ void IoContext::TimeoutManagerImpl::setTimeoutImpl(IoContext& context, Iterator // TODO(cleanup): The manual use of run() here (including carrying over the critical section) is // kind of ugly, but using awaitIo() doesn't work here because we need the ability to cancel // the timer, so we don't want to addTask() it, which awaitIo() does implicitly. - auto promise = paf.promise - .then([this, &context, it, cs = context.getCriticalSection()]() mutable { - return context.run([this, &context, it] (Worker::Lock& lock) mutable { + auto promise = + paf.promise.then([this, &context, it, cs = context.getCriticalSection()]() mutable { + return context.run([this, &context, it](Worker::Lock& lock) mutable { auto& state = it->second; auto stateGuard = kj::defer([&] { @@ -675,21 +660,19 @@ void IoContext::TimeoutManagerImpl::setTimeoutImpl(IoContext& context, Iterator // TODO(perf): If we can guarantee that `timeout->second = nullptr` will never throw, it // might be worthwhile having an early-out path for non-interval timeouts. kj::UnwindDetector unwindDetector; - KJ_DEFER( - unwindDetector.catchExceptionsIfUnwinding([&] { - if (state.isCanceled) { - // The user's callback has called clearInterval(), nothing more to do. - KJ_ASSERT(state.maybePromise == kj::none); - return; - } - - // If this is an interval task and the script has CPU time left, reschedule the task; - // otherwise leave the dead map entry in place. - if (state.params.repeat && context.limitEnforcer->getLimitsExceeded() == kj::none) { - setTimeoutImpl(context, it); - } - }); - ); + KJ_DEFER(unwindDetector.catchExceptionsIfUnwinding([&] { + if (state.isCanceled) { + // The user's callback has called clearInterval(), nothing more to do. + KJ_ASSERT(state.maybePromise == kj::none); + return; + } + + // If this is an interval task and the script has CPU time left, reschedule the task; + // otherwise leave the dead map entry in place. + if (state.params.repeat && context.limitEnforcer->getLimitsExceeded() == kj::none) { + setTimeoutImpl(context, it); + } + });); state.trigger(lock); } @@ -700,10 +683,9 @@ void IoContext::TimeoutManagerImpl::setTimeoutImpl(IoContext& context, Iterator // Add an entry to the timeoutTimes map, to track when the nearest timeout is. Arrange for it // to be removed when the promise completes. - TimeoutTime timeoutTimesKey { when, timeoutTimesTiebreakerCounter++ }; + TimeoutTime timeoutTimesKey{when, timeoutTimesTiebreakerCounter++}; timeoutTimes.insert(timeoutTimesKey, kj::mv(paf.fulfiller)); - auto deferredTimeoutTimeRemoval = kj::defer( - [this, &context, timeoutTimesKey]() { + auto deferredTimeoutTimeRemoval = kj::defer([this, &context, timeoutTimesKey]() { // If the promise is being destroyed due to IoContext teardown then IoChannelFactory may // no longer be available, but we can just skip starting a new timer in that case as it'd be // canceled anyway. @@ -723,9 +705,8 @@ void IoContext::TimeoutManagerImpl::setTimeoutImpl(IoContext& context, Iterator // Add a wait-until task which resolves when this timer completes. This ensures that // `IncomingRequest::drain()` waits until all timers finish. auto paf = kj::newPromiseAndFulfiller(); - promise = promise.attach(kj::defer([fulfiller = kj::mv(paf.fulfiller)]() mutable { - fulfiller->fulfill(); - })); + promise = promise.attach( + kj::defer([fulfiller = kj::mv(paf.fulfiller)]() mutable { fulfiller->fulfill(); })); context.addWaitUntil(kj::mv(paf.promise)); } @@ -740,22 +721,19 @@ void IoContext::TimeoutManagerImpl::resetTimerTask(TimerChannel& timerChannel) { // Wait for the first timer. auto& entry = *timeoutTimes.begin(); timerTask = timerChannel.atTime(entry.key.when) - .then([this, key = entry.key]() { + .then([this, key = entry.key]() { auto& newEntry = *timeoutTimes.begin(); KJ_ASSERT(newEntry.key == key, "front of timeoutTimes changed without calling resetTimerTask(), we probably missed " "a timeout!"); newEntry.value->fulfill(); - }).eagerlyEvaluate([](kj::Exception&& e) { - KJ_LOG(ERROR, e); - }); + }).eagerlyEvaluate([](kj::Exception&& e) { KJ_LOG(ERROR, e); }); } } -void IoContext::TimeoutManagerImpl::clearTimeout( - IoContext& context, TimeoutId timeoutId) { +void IoContext::TimeoutManagerImpl::clearTimeout(IoContext& context, TimeoutId timeoutId) { auto timeout = timeouts.find(timeoutId); - if(timeout == timeouts.end()) { + if (timeout == timeouts.end()) { // We can't find this timeout, thus we act as if it was already canceled. return; } @@ -765,17 +743,14 @@ void IoContext::TimeoutManagerImpl::clearTimeout( } TimeoutId IoContext::setTimeoutImpl( - TimeoutId::Generator& generator, - bool repeat, - jsg::Function function, - double msDelay) { + TimeoutId::Generator& generator, bool repeat, jsg::Function function, double msDelay) { static constexpr int64_t max = 3153600000000; // Milliseconds in 100 years // Clamp the range on timers to [0, 3153600000000] (inclusive). The specs // do not indicate a clear maximum range for setTimeout/setInterval so the // limit here is fairly arbitrary. 100 years max should be plenty safe. - int64_t delay = - msDelay <= 0 || std::isnan(msDelay) ? 0 : - msDelay >= static_cast(max) ? max : static_cast(msDelay); + int64_t delay = msDelay <= 0 || std::isnan(msDelay) ? 0 + : msDelay >= static_cast(max) ? max + : static_cast(msDelay); auto params = TimeoutManager::TimeoutParameters(repeat, delay, kj::mv(function)); return timeoutManager->setTimeout(*this, generator, kj::mv(params)); } @@ -792,7 +767,7 @@ kj::Date IoContext::now(IncomingRequest& incomingRequest) { kj::Date adjustedTime = incomingRequest.ioChannelFactory->getTimer().now(); incomingRequest.metrics->clockRead(); - KJ_IF_SOME (maybeNextTimeout, timeoutManager->getNextTimeout()) { + KJ_IF_SOME(maybeNextTimeout, timeoutManager->getNextTimeout()) { // Don't return a time beyond when the next setTimeout() callback is intended to run. This // ensures that Date.now() inside the callback itself always returns exactly the time at which // the callback was scheduled (hiding non-determinism which could contain side channels), and @@ -840,34 +815,38 @@ kj::Own IoContext::getSubrequest( kj::Own IoContext::getSubrequestChannel( uint channel, bool isInHouse, kj::Maybe cfBlobJson, kj::ConstString operationName) { - return getSubrequest([&](SpanBuilder& span, IoChannelFactory& channelFactory) { - return getSubrequestChannelImpl( - channel, isInHouse, kj::mv(cfBlobJson), span, channelFactory); - }, SubrequestOptions { - .inHouse = isInHouse, - .wrapMetrics = !isInHouse, - .operationName = kj::mv(operationName), - }); + return getSubrequest( + [&](SpanBuilder& span, IoChannelFactory& channelFactory) { + return getSubrequestChannelImpl(channel, isInHouse, kj::mv(cfBlobJson), span, channelFactory); + }, + SubrequestOptions{ + .inHouse = isInHouse, + .wrapMetrics = !isInHouse, + .operationName = kj::mv(operationName), + }); } -kj::Own IoContext::getSubrequestChannelNoChecks( - uint channel, bool isInHouse, kj::Maybe cfBlobJson, +kj::Own IoContext::getSubrequestChannelNoChecks(uint channel, + bool isInHouse, + kj::Maybe cfBlobJson, kj::Maybe operationName) { - return getSubrequestNoChecks([&](SpanBuilder& span, - IoChannelFactory& channelFactory) { - return getSubrequestChannelImpl( - channel, isInHouse, kj::mv(cfBlobJson), span, channelFactory); - }, SubrequestOptions { - .inHouse = isInHouse, - .wrapMetrics = !isInHouse, - .operationName = kj::mv(operationName), - }); + return getSubrequestNoChecks( + [&](SpanBuilder& span, IoChannelFactory& channelFactory) { + return getSubrequestChannelImpl(channel, isInHouse, kj::mv(cfBlobJson), span, channelFactory); + }, + SubrequestOptions{ + .inHouse = isInHouse, + .wrapMetrics = !isInHouse, + .operationName = kj::mv(operationName), + }); } -kj::Own IoContext::getSubrequestChannelImpl( - uint channel, bool isInHouse, kj::Maybe cfBlobJson, - SpanBuilder& span, IoChannelFactory& channelFactory) { - IoChannelFactory::SubrequestMetadata metadata { +kj::Own IoContext::getSubrequestChannelImpl(uint channel, + bool isInHouse, + kj::Maybe cfBlobJson, + SpanBuilder& span, + IoChannelFactory& channelFactory) { + IoChannelFactory::SubrequestMetadata metadata{ .cfBlobJson = kj::mv(cfBlobJson), .parentSpan = span, .featureFlagsForFl = worker->getIsolate().getFeatureFlagsForFl(), @@ -880,15 +859,16 @@ kj::Own IoContext::getSubrequestChannelImpl( kj::Own IoContext::getHttpClient( uint channel, bool isInHouse, kj::Maybe cfBlobJson, kj::ConstString operationName) { - return asHttpClient(getSubrequestChannel( - channel, isInHouse, kj::mv(cfBlobJson), kj::mv(operationName))); + return asHttpClient( + getSubrequestChannel(channel, isInHouse, kj::mv(cfBlobJson), kj::mv(operationName))); } -kj::Own IoContext::getHttpClientNoChecks( - uint channel, bool isInHouse, kj::Maybe cfBlobJson, +kj::Own IoContext::getHttpClientNoChecks(uint channel, + bool isInHouse, + kj::Maybe cfBlobJson, kj::Maybe operationName) { - return asHttpClient(getSubrequestChannelNoChecks(channel, isInHouse, kj::mv(cfBlobJson), - kj::mv(operationName))); + return asHttpClient( + getSubrequestChannelNoChecks(channel, isInHouse, kj::mv(cfBlobJson), kj::mv(operationName))); } kj::Own IoContext::getCacheClient() { @@ -904,7 +884,7 @@ jsg::AsyncContextFrame::StorageScope IoContext::makeAsyncTraceScope( Worker::Lock& lock, kj::Maybe spanParentOverride) { jsg::Lock& js = lock; kj::Own spanParent; - KJ_IF_SOME (spo, kj::mv(spanParentOverride)) { + KJ_IF_SOME(spo, kj::mv(spanParentOverride)) { spanParent = kj::heap(kj::mv(spo)); } else { spanParent = kj::heap(getMetrics().getSpan()); @@ -917,9 +897,9 @@ jsg::AsyncContextFrame::StorageScope IoContext::makeAsyncTraceScope( SpanParent IoContext::getCurrentTraceSpan() { // If called while lock is held, try to use the trace info stored in the async context. - KJ_IF_SOME (lock, currentLock) { - KJ_IF_SOME (frame, jsg::AsyncContextFrame::current(lock)) { - KJ_IF_SOME (value, frame.get(lock.getTraceAsyncContextKey())) { + KJ_IF_SOME(lock, currentLock) { + KJ_IF_SOME(frame, jsg::AsyncContextFrame::current(lock)) { + KJ_IF_SOME(value, frame.get(lock.getTraceAsyncContextKey())) { auto handle = value.getHandle(lock); jsg::Lock& js = lock; auto& spanParent = jsg::unwrapOpaqueRef>(js.v8Isolate, handle); @@ -974,8 +954,7 @@ Worker::Actor& IoContext::getActorOrThrow() { return KJ_ASSERT_NONNULL(actor, "not an actor request"); } -void IoContext::runInContextScope( - Worker::LockType lockType, +void IoContext::runInContextScope(Worker::LockType lockType, kj::Maybe inputLock, kj::Function func) { // The previously-current context, before we entered this scope. We have to allow opening @@ -1016,10 +995,11 @@ void IoContext::runInContextScope( }); } -void IoContext::runImpl(Runnable& runnable, bool takePendingEvent, - Worker::LockType lockType, - kj::Maybe inputLock, - bool allowPermanentException) { +void IoContext::runImpl(Runnable& runnable, + bool takePendingEvent, + Worker::LockType lockType, + kj::Maybe inputLock, + bool allowPermanentException) { KJ_IF_SOME(l, inputLock) { KJ_REQUIRE(l.isFor(KJ_ASSERT_NONNULL(actor).getInputGate())); } @@ -1107,8 +1087,7 @@ void IoContext::runImpl(Runnable& runnable, bool takePendingEvent, // useful. We should improve the tunneling to include stack traces and ensure that all // consumers do in fact log exceptions, then we can remove this. workerLock.logUncaughtException(UncaughtExceptionSource::INTERNAL, - jsg::JsValue(jsException), - jsg::JsMessage(tryCatch.Message())); + jsg::JsValue(jsException), jsg::JsMessage(tryCatch.Message())); jsg::throwTunneledException(workerLock.getIsolate(), jsException); } @@ -1165,8 +1144,8 @@ void IoContext::runFinalizers(Worker::AsyncLock& asyncLock) { // Don't bother fulfilling `abortFulfiller` if limits were exceeded because in that case the // abort promise will be fulfilled shortly anyway. if (limitEnforcer->getLimitsExceeded() == kj::none) { - abortFulfiller->reject(JSG_KJ_EXCEPTION(FAILED, Error, - "The script will never generate a response.")); + abortFulfiller->reject( + JSG_KJ_EXCEPTION(FAILED, Error, "The script will never generate a response.")); } } @@ -1182,7 +1161,8 @@ void IoContext::runFinalizers(Worker::AsyncLock& asyncLock) { kj::Vector warnings; RunnableImpl(IoContext& context, kj::Vector warnings) - : context(context), warnings(kj::mv(warnings)) {} + : context(context), + warnings(kj::mv(warnings)) {} void run(Worker::Lock& lock) override { for (auto warning: warnings) { context.logWarning(warning); @@ -1202,9 +1182,9 @@ namespace { class CacheSerializedInputStream final: public kj::AsyncInputStream { public: CacheSerializedInputStream( - kj::Own inner, - kj::Own> fulfiller) - : inner(kj::mv(inner)), fulfiller(kj::mv(fulfiller)) {} + kj::Own inner, kj::Own> fulfiller) + : inner(kj::mv(inner)), + fulfiller(kj::mv(fulfiller)) {} ~CacheSerializedInputStream() noexcept(false) { fulfiller->fulfill(); @@ -1218,8 +1198,7 @@ public: return inner->tryGetLength(); } - kj::Promise pumpTo( - kj::AsyncOutputStream& output, uint64_t amount) override { + kj::Promise pumpTo(kj::AsyncOutputStream& output, uint64_t amount) override { return inner->pumpTo(output, amount); } @@ -1236,9 +1215,10 @@ jsg::Promise> IoContext::makeCachePutStream( KJ_DEFER(cachePutSerializer = kj::mv(paf.promise)); - return awaitIo(js, cachePutSerializer.then( - [fulfiller = kj::mv(paf.fulfiller), stream = kj::mv(stream)]() mutable - -> kj::Own { + return awaitIo(js, + cachePutSerializer.then( + [fulfiller = kj::mv(paf.fulfiller), + stream = kj::mv(stream)]() mutable -> kj::Own { if (stream->tryGetLength() != kj::none) { // PUT with Content-Length. We can just return immediately, allowing the next PUT to start. KJ_DEFER(fulfiller->fulfill()); @@ -1250,15 +1230,16 @@ jsg::Promise> IoContext::makeCachePutStream( // be, so wrap the stream that only unblocks the next PUT after this one is complete. return kj::heap(kj::mv(stream), kj::mv(fulfiller)); } - }), [this](jsg::Lock&, kj::Own result) { - return addObject(kj::mv(result)); - }); + }), + [this]( + jsg::Lock&, kj::Own result) { return addObject(kj::mv(result)); }); } -void IoContext::writeLogfwdr(uint channel, - kj::FunctionParam buildMessage) { - addWaitUntil(getIoChannelFactory().writeLogfwdr(channel, kj::mv(buildMessage)) - .attach(registerPendingEvent())); +void IoContext::writeLogfwdr( + uint channel, kj::FunctionParam buildMessage) { + addWaitUntil(getIoChannelFactory() + .writeLogfwdr(channel, kj::mv(buildMessage)) + .attach(registerPendingEvent())); } void IoContext::requireCurrentOrThrowJs() { @@ -1277,23 +1258,28 @@ void IoContext::requireCurrentOrThrowJs(WeakRef& weak) { } void IoContext::throwNotCurrentJsError(kj::Maybe maybeType) { - auto type = maybeType.map([](const std::type_info& type) { + auto type = maybeType + .map([](const std::type_info& type) { return kj::str(" (I/O type: ", jsg::typeName(type), ")"); }).orDefault(kj::String()); if (threadLocalRequest != nullptr && threadLocalRequest->actor != kj::none) { JSG_FAIL_REQUIRE(Error, - kj::str("Cannot perform I/O on behalf of a different Durable Object. I/O objects " - "(such as streams, request/response bodies, and others) created in the context of one " - "Durable Object cannot be accessed from a different Durable Object in the same isolate. " - "This is a limitation of Cloudflare Workers which allows us to improve overall " - "performance.", type)); + kj::str( + "Cannot perform I/O on behalf of a different Durable Object. I/O objects " + "(such as streams, request/response bodies, and others) created in the context of one " + "Durable Object cannot be accessed from a different Durable Object in the same isolate. " + "This is a limitation of Cloudflare Workers which allows us to improve overall " + "performance.", + type)); } else { JSG_FAIL_REQUIRE(Error, - kj::str("Cannot perform I/O on behalf of a different request. I/O objects (such as " - "streams, request/response bodies, and others) created in the context of one request " - "handler cannot be accessed from a different request's handler. This is a limitation " - "of Cloudflare Workers which allows us to improve overall performance.", type)); + kj::str( + "Cannot perform I/O on behalf of a different request. I/O objects (such as " + "streams, request/response bodies, and others) created in the context of one request " + "handler cannot be accessed from a different request's handler. This is a limitation " + "of Cloudflare Workers which allows us to improve overall performance.", + type)); } } @@ -1321,19 +1307,17 @@ WarningAggregator::~WarningAggregator() noexcept(false) { // destroyed during garbage collection. V8 does not like having most of its API // invoked in the middle of GC. So we'll delay our warning until GC finished. auto& context = IoContext::current(); - context.addTask(context.run( - [emitter=kj::mv(emitter), warnings=kj::mv(warnings)](Worker::Lock& lock) mutable { - emitter(lock, kj::mv(warnings)); - })); + context.addTask( + context.run([emitter = kj::mv(emitter), warnings = kj::mv(warnings)]( + Worker::Lock& lock) mutable { emitter(lock, kj::mv(warnings)); })); } else { // We aren't in any JavaScript context. The object might be being destroyed during // IoContext shutdown or maybe even during deferred proxying. So, avoid touching // the IoContext. Instead, we'll lock the worker directly. worker->runInLockScope(Worker::Lock::TakeSynchronously(*requestMetrics), - [emitter=kj::mv(emitter), warnings=kj::mv(warnings)](Worker::Lock& lock) mutable { - JSG_WITHIN_CONTEXT_SCOPE(lock, lock.getContext(), [&](jsg::Lock& js) { - emitter(lock, kj::mv(warnings)); - }); + [emitter = kj::mv(emitter), warnings = kj::mv(warnings)](Worker::Lock& lock) mutable { + JSG_WITHIN_CONTEXT_SCOPE( + lock, lock.getContext(), [&](jsg::Lock& js) { emitter(lock, kj::mv(warnings)); }); }); } } @@ -1344,10 +1328,9 @@ void WarningAggregator::add(kj::Own warning) const { } kj::Own IoContext::getWarningAggregator( - const WarningAggregator::Key& key, - kj::Function(IoContext&)> load) { - auto& instance = warningAggregatorMap.findOrCreate(key, - [this, load=kj::mv(load), &key]() mutable -> WarningAggregator::Map::Entry { + const WarningAggregator::Key& key, kj::Function(IoContext&)> load) { + auto& instance = warningAggregatorMap.findOrCreate( + key, [this, load = kj::mv(load), &key]() mutable -> WarningAggregator::Map::Entry { return {key, load(*this)}; }); return kj::atomicAddRef(*instance); diff --git a/src/workerd/io/io-context.h b/src/workerd/io/io-context.h index 73d5245af47..d3cd57c94ba 100644 --- a/src/workerd/io/io-context.h +++ b/src/workerd/io/io-context.h @@ -26,7 +26,9 @@ #include #include -namespace capnp { class HttpOverCapnpFactory; } +namespace capnp { +class HttpOverCapnpFactory; +} namespace workerd { @@ -41,14 +43,18 @@ class IoContext; // information for each individual collected instance. class WarningAggregator final: public kj::AtomicRefcounted { public: - // The IoContext will maintain a map of WarningAggregators based on an opaque key. class Key final { public: - Key() : hash(kj::hashCode(this)) {} + Key(): hash(kj::hashCode(this)) {} KJ_DISALLOW_COPY_AND_MOVE(Key); - inline uint hashCode() const { return hash; } - inline bool operator==(const Key& other) const { return this == &other; } + inline uint hashCode() const { + return hash; + } + inline bool operator==(const Key& other) const { + return this == &other; + } + private: uint hash; }; @@ -63,9 +69,8 @@ class WarningAggregator final: public kj::AtomicRefcounted { // The EmitCallback is called when the WarningAggregator is destroyed. It is // responsible for actually emitting the warnings that are collected. It will // only be called once and only if there are any collected warnings. - using EmitCallback = kj::Function> warnings)>; + using EmitCallback = + kj::Function> warnings)>; WarningAggregator(IoContext& context, EmitCallback emitter); ~WarningAggregator() noexcept(false); @@ -98,13 +103,15 @@ class WarningAggregator final: public kj::AtomicRefcounted { class IoContext_IncomingRequest final { public: IoContext_IncomingRequest(kj::Own context, - kj::Own ioChannelFactory, - kj::Own metrics, - kj::Maybe> workerTracer); + kj::Own ioChannelFactory, + kj::Own metrics, + kj::Maybe> workerTracer); KJ_DISALLOW_COPY_AND_MOVE(IoContext_IncomingRequest); ~IoContext_IncomingRequest() noexcept(false); - IoContext& getContext() { return *context; } + IoContext& getContext() { + return *context; + } // Invoked when the request is actually delivered. // @@ -140,9 +147,13 @@ class IoContext_IncomingRequest final { enum class FinishScheduledResult { COMPLETED, ABORTED, TIMEOUT }; kj::Promise finishScheduled(); - RequestObserver& getMetrics() { return *metrics; } + RequestObserver& getMetrics() { + return *metrics; + } - kj::Maybe getWorkerTracer() { return workerTracer; } + kj::Maybe getWorkerTracer() { + return workerTracer; + } private: kj::Own context; @@ -194,16 +205,21 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler // Construct a new IoContext. Before using it, you must also create an IncomingRequest. IoContext(ThreadContext& thread, - kj::Own worker, kj::Maybe actor, - kj::Own limitEnforcer); + kj::Own worker, + kj::Maybe actor, + kj::Own limitEnforcer); // On destruction, all outstanding tasks associated with this request are canceled. ~IoContext() noexcept(false); using IncomingRequest = IoContext_IncomingRequest; - const Worker& getWorker() { return *worker; } - Worker::Lock& getCurrentLock() { return KJ_REQUIRE_NONNULL(currentLock); } + const Worker& getWorker() { + return *worker; + } + Worker::Lock& getCurrentLock() { + return KJ_REQUIRE_NONNULL(currentLock); + } kj::Maybe getActor() { return actor; @@ -221,7 +237,9 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler return getCurrentIncomingRequest().getWorkerTracer(); } - LimitEnforcer& getLimitEnforcer() { return *limitEnforcer; } + LimitEnforcer& getLimitEnforcer() { + return *limitEnforcer; + } // Get the current input lock. Throws an exception if no input lock is held (e.g. because this is // not an actor request). @@ -284,8 +302,8 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler void logUncaughtException(kj::StringPtr description); void logUncaughtException(UncaughtExceptionSource source, - const jsg::JsValue& exception, - const jsg::JsMessage& message = jsg::JsMessage()); + const jsg::JsValue& exception, + const jsg::JsMessage& message = jsg::JsMessage()); // Log an uncaught exception from an asynchronous context, i.e. when the IoContext is not // "current". @@ -296,16 +314,24 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler // Returns a promise that will reject with an exception if and when the request should be // aborted, e.g. because its CPU time expired. This should be joined with any promises for // incoming tasks. - kj::Promise onAbort() { return abortPromise.addBranch(); } + kj::Promise onAbort() { + return abortPromise.addBranch(); + } // Force context abort now. - void abort(kj::Exception&& e) { abortFulfiller->reject(kj::mv(e)); } + void abort(kj::Exception&& e) { + abortFulfiller->reject(kj::mv(e)); + } // Has event.passThroughOnException() been called? - bool isFailOpen() { return failOpen; } + bool isFailOpen() { + return failOpen; + } // Called by event.passThroughOnException(). - void setFailOpen() { failOpen = true; } + void setFailOpen() { + failOpen = true; + } // ----------------------------------------------------------------- // Tracking thread-local request @@ -319,15 +345,13 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler // before executing the callback. template kj::PromiseForResult run( - Func&& func, kj::Maybe inputLock = kj::none) - KJ_WARN_UNUSED_RESULT; + Func&& func, kj::Maybe inputLock = kj::none) KJ_WARN_UNUSED_RESULT; // Like run() but executes within the given critical section, if it is non-null. If // `criticalSection` is null, then this just forwards to the other run() (with null inputLock). template - kj::PromiseForResult run( - Func&& func, kj::Maybe> criticalSection) - KJ_WARN_UNUSED_RESULT; + kj::PromiseForResult run(Func&& func, + kj::Maybe> criticalSection) KJ_WARN_UNUSED_RESULT; // Returns the current IoContext for the thread. // Throws an exception if there is no current context (see hasCurrent() below). @@ -380,8 +404,7 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler void addTask(kj::Promise promise); template - jsg::PromiseForResult awaitIo( - jsg::Lock& js, kj::Promise promise, Func&& func); + jsg::PromiseForResult awaitIo(jsg::Lock& js, kj::Promise promise, Func&& func); // Waits for some background I/O to complete, then executes `func` on the result, returning a // JavaScript promise for the result of that. If no `func` is provided, no transformation is @@ -423,9 +446,8 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler jsg::Promise awaitIoWithInputLock(jsg::Lock& js, kj::Promise promise); template - jsg::PromiseForResult awaitIoWithInputLock(jsg::Lock& js, - kj::Promise promise, - Func&& func); + jsg::PromiseForResult awaitIoWithInputLock( + jsg::Lock& js, kj::Promise promise, Func&& func); // DEPRECATED: Like awaitIo() but: // - Does not have a continuation function, so suffers from the problems described in @@ -465,7 +487,9 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler kj::_::ReducePromises> awaitJs(jsg::Lock& js, jsg::Promise promise); // Returns the number of times addTask() has been called (even if the tasks have completed). - uint taskCount() { return addTaskCounter; } + uint taskCount() { + return addTaskCounter; + } // Indicates that the script has requested that it stay active until the given promise resolves. // drain() waits until all such promises have completed. @@ -473,7 +497,9 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler // Returns the status of waitUntil promises. If a promise fails, this sets the status to the // one corresponding to the exception type. - EventOutcome waitUntilStatus() const { return waitUntilStatusValue; } + EventOutcome waitUntilStatus() const { + return waitUntilStatusValue; + } // DO NOT USE, use `addWaitUntil()` instead. kj::TaskSet& getWaitUntilTasks() { @@ -488,14 +514,16 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler // thread. // 2. Can be safely destroyed from any thread. // 3. Invalidates itself when the request ends (such that dereferencing throws). - template IoOwn addObject(kj::Own obj); + template + IoOwn addObject(kj::Own obj); // Wraps a reference in a wrapper which: // 1. Will throw an exception if dereferenced while the IoContext is not current for the // thread. // 2. Can be safely destroyed from any thread. // 3. Invalidates itself when the request ends (such that dereferencing throws). - template IoPtr addObject(T& obj); + template + IoPtr addObject(T& obj); // Like addObject() but takes a functor, returning a functor with the same signature but which // holds the original functor under a `IoOwn`, and so will stop working if the IoContext @@ -508,7 +536,8 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler // reference is dropped OR the IoContext itself is destroyed. In the latter case, further // attempts to access the returned reference will throw. The reference can only be used and // destroyed within the same thread as the IoContext lives. - template ReverseIoOwn addObjectReverse(kj::Own obj); + template + ReverseIoOwn addObjectReverse(kj::Own obj); // Call this to indicate that the caller expects to call into JavaScript in this IoContext // at some point in the future, in response to some *external* event that the caller is waiting @@ -533,8 +562,8 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler // resolves, the inner promise (the DeferredProxy) is treated as external I/O. template jsg::Promise awaitDeferredProxy(jsg::Lock& js, kj::Promise>&& promise) { - return awaitIoImpl(js, waitForDeferredProxy(kj::mv(promise)), getCriticalSection(), - IdentityFunc()); + return awaitIoImpl( + js, waitForDeferredProxy(kj::mv(promise)), getCriticalSection(), IdentityFunc()); } bool isFinalized() { @@ -542,10 +571,14 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler } // Called by ScheduledEvent - void setNoRetryScheduled() { retryScheduled = false; } + void setNoRetryScheduled() { + retryScheduled = false; + } // Called by ServiceWorkerGlobalScope::runScheduled - bool shouldRetryScheduled() { return retryScheduled; } + bool shouldRetryScheduled() { + return retryScheduled; + } // ----------------------------------------------------------------- // Access to I/O @@ -553,10 +586,7 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler // Used to implement setTimeout(). We don't expose the timer directly because the // promises it returns need to live in this I/O context, anyway. TimeoutId setTimeoutImpl( - TimeoutId::Generator& generator, - bool repeat, - jsg::Function function, - double msDelay); + TimeoutId::Generator& generator, bool repeat, jsg::Function function, double msDelay); // Used to implement clearTimeout(). We don't expose the timer directly because the // promises it returns need to live in this I/O context, anyway. @@ -571,7 +601,9 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler kj::Date now(); // Returns a promise that resolves once `now() >= when`. - kj::Promise atTime(kj::Date when) { return getIoChannelFactory().getTimer().atTime(when); } + kj::Promise atTime(kj::Date when) { + return getIoChannelFactory().getTimer().atTime(when); + } // Returns a promise that resolves after some time. This is intended to be used for implementing // time limits on some sort of operation, not for implementing application-driven timing, as it @@ -582,7 +614,9 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler } // Provide access to the system CSPRNG. - kj::EntropySource& getEntropySource() { return thread.getEntropySource(); } + kj::EntropySource& getEntropySource() { + return thread.getEntropySource(); + } capnp::HttpOverCapnpFactory& getHttpOverCapnpFactory() { return thread.getHttpOverCapnpFactory(); @@ -592,8 +626,12 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler return thread.getByteStreamFactory(); } - const kj::HttpHeaderTable& getHeaderTable() { return thread.getHeaderTable(); } - const ThreadContext::HeaderIdBundle& getHeaderIds() { return thread.getHeaderIds(); } + const kj::HttpHeaderTable& getHeaderTable() { + return thread.getHeaderTable(); + } + const ThreadContext::HeaderIdBundle& getHeaderIds() { + return thread.getHeaderIds(); + } // Subrequest channel numbers for the two special channels. // NULL = The channel used by global fetch() when the Request has no fetcher attached. @@ -648,23 +686,29 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler // - In preview, in-house requests do not show up in the network tab. // // `operationName` is the name to use for the request's span, if tracing is turned on. - kj::Own getSubrequestChannel( - uint channel, bool isInHouse, kj::Maybe cfBlobJson, kj::ConstString operationName); + kj::Own getSubrequestChannel(uint channel, + bool isInHouse, + kj::Maybe cfBlobJson, + kj::ConstString operationName); // Like getSubrequestChannel() but doesn't enforce limits. Use for trusted paths only. - kj::Own getSubrequestChannelNoChecks( - uint channel, bool isInHouse, kj::Maybe cfBlobJson, + kj::Own getSubrequestChannelNoChecks(uint channel, + bool isInHouse, + kj::Maybe cfBlobJson, kj::Maybe operationName = kj::none); // Convenience methods that call getSubrequest*() and adapt the returned WorkerInterface objects // to HttpClient. - kj::Own getHttpClient( - uint channel, bool isInHouse, kj::Maybe cfBlobJson, kj::ConstString operationName); + kj::Own getHttpClient(uint channel, + bool isInHouse, + kj::Maybe cfBlobJson, + kj::ConstString operationName); // Convenience methods that call getSubrequest*() and adapt the returned WorkerInterface objects // to HttpClient. - kj::Own getHttpClientNoChecks( - uint channel, bool isInHouse, kj::Maybe cfBlobJson, + kj::Own getHttpClientNoChecks(uint channel, + bool isInHouse, + kj::Maybe cfBlobJson, kj::Maybe operationName = kj::none); // TODO(cleanup): Make it the caller's job to call asHttpClient() on the result of // getSubrequest*(). @@ -673,14 +717,16 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler return getIoChannelFactory().getCapability(channel); } - kj::Own getGlobalActorChannel( - uint channel, const ActorIdFactory::ActorId& id, kj::Maybe locationHint, - ActorGetMode mode, SpanParent parentSpan) { - return getIoChannelFactory().getGlobalActor(channel, id, kj::mv(locationHint), mode, - kj::mv(parentSpan)); - } - kj::Own getColoLocalActorChannel(uint channel, kj::StringPtr id, + kj::Own getGlobalActorChannel(uint channel, + const ActorIdFactory::ActorId& id, + kj::Maybe locationHint, + ActorGetMode mode, SpanParent parentSpan) { + return getIoChannelFactory().getGlobalActor( + channel, id, kj::mv(locationHint), mode, kj::mv(parentSpan)); + } + kj::Own getColoLocalActorChannel( + uint channel, kj::StringPtr id, SpanParent parentSpan) { return getIoChannelFactory().getColoLocalActor(channel, id, kj::mv(parentSpan)); } @@ -728,8 +774,7 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler // Returns the existing WarningAggregator for the specified key, or calls load to create one. kj::Own getWarningAggregator( - const WarningAggregator::Key& key, - kj::Function(IoContext&)> load); + const WarningAggregator::Key& key, kj::Function(IoContext&)> load); // The IoChannelFactory must be accessed through the // currentIncomingRequest because it has some tracing context built in. @@ -790,8 +835,11 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler kj::TaskSet waitUntilTasks; EventOutcome waitUntilStatusValue = EventOutcome::OK; - void setTimeoutImpl(TimeoutId timeoutId, bool repeat, jsg::V8Ref function, - double msDelay, kj::Array args); + void setTimeoutImpl(TimeoutId timeoutId, + bool repeat, + jsg::V8Ref function, + double msDelay, + kj::Array args); uint addTaskCounter = 0; kj::Maybe tasks; @@ -807,13 +855,17 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler // destructed. kj::Own timeoutManager; - kj::Own getSubrequestChannelImpl( - uint channel, bool isInHouse, kj::Maybe cfBlobJson, - SpanBuilder& span, IoChannelFactory& channelFactory); + kj::Own getSubrequestChannelImpl(uint channel, + bool isInHouse, + kj::Maybe cfBlobJson, + SpanBuilder& span, + IoChannelFactory& channelFactory); friend class IoContext_IncomingRequest; - template friend class IoOwn; - template friend class IoPtr; + template + friend class IoOwn; + template + friend class IoPtr; void taskFailed(kj::Exception&& exception) override; void requireCurrent(); @@ -825,8 +877,11 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler public: virtual void run(Worker::Lock& lock) = 0; }; - void runImpl(Runnable& runnable, bool takePendingEvent, Worker::LockType lockType, - kj::Maybe inputLock, bool allowPermanentException); + void runImpl(Runnable& runnable, + bool takePendingEvent, + Worker::LockType lockType, + kj::Maybe inputLock, + bool allowPermanentException); void runFinalizers(Worker::AsyncLock& asyncLock); @@ -879,15 +934,16 @@ class IoContext final: public kj::Refcounted, private kj::TaskSet::ErrorHandler // setup of a number of scopes that must be entered prior to running within the // context, including entering the V8StackScope and acquiring the Worker::Lock. void runInContextScope(Worker::LockType lockType, - kj::Maybe inputLock, - kj::Function func); + kj::Maybe inputLock, + kj::Function func); friend class Finalizeable; friend class DeleteQueue; template friend kj::Promise> promiseForExceptionOrT(kj::Promise promise); - template - friend Result throwOrReturnResult(jsg::Lock& js, IoContext::ExceptionOr&& exceptionOrResult); + template + friend Result throwOrReturnResult( + jsg::Lock& js, IoContext::ExceptionOr&& exceptionOrResult); }; // ======================================================================================= @@ -902,8 +958,8 @@ template kj::PromiseForResult IoContext::run( Func&& func, kj::Maybe> criticalSection) { KJ_IF_SOME(cs, criticalSection) { - return cs.get()->wait() - .then([this,func=kj::fwd(func)](InputGate::Lock&& inputLock) mutable { + return cs.get()->wait().then( + [this, func = kj::fwd(func)](InputGate::Lock&& inputLock) mutable { return run(kj::fwd(func), kj::mv(inputLock)); }); } else { @@ -917,8 +973,8 @@ kj::PromiseForResult IoContext::run( kj::Promise asyncLockPromise = nullptr; KJ_IF_SOME(a, actor) { if (inputLock == kj::none) { - return a.getInputGate().wait() - .then([this,func=kj::fwd(func)](InputGate::Lock&& inputLock) mutable { + return a.getInputGate().wait().then( + [this, func = kj::fwd(func)](InputGate::Lock&& inputLock) mutable { return run(kj::fwd(func), kj::mv(inputLock)); }); } @@ -928,9 +984,8 @@ kj::PromiseForResult IoContext::run( asyncLockPromise = worker->takeAsyncLock(getMetrics()); } - return asyncLockPromise - .then([this,inputLock=kj::mv(inputLock),func=kj::fwd(func)] - (Worker::AsyncLock lock) mutable { + return asyncLockPromise.then([this, inputLock = kj::mv(inputLock), func = kj::fwd(func)]( + Worker::AsyncLock lock) mutable { typedef decltype(func(kj::instance())) Result; if constexpr (kj::isSameType()) { struct RunnableImpl: public Runnable { @@ -955,7 +1010,7 @@ kj::PromiseForResult IoContext::run( } }; - RunnableImpl runnable { kj::fwd(func) }; + RunnableImpl runnable{kj::fwd(func)}; runImpl(runnable, true, lock, kj::mv(inputLock), false); KJ_IF_SOME(r, runnable.result) { return kj::mv(r); @@ -969,27 +1024,26 @@ kj::PromiseForResult IoContext::run( template jsg::PromiseForResult IoContext::awaitIo( jsg::Lock& js, kj::Promise promise, Func&& func) { - return awaitIoImpl(js, promise.attach(registerPendingEvent()), getCriticalSection(), - kj::fwd(func)); + return awaitIoImpl( + js, promise.attach(registerPendingEvent()), getCriticalSection(), kj::fwd(func)); } template jsg::Promise IoContext::awaitIo(jsg::Lock& js, kj::Promise promise) { - return awaitIoImpl(js, promise.attach(registerPendingEvent()), getCriticalSection(), - IdentityFunc()); + return awaitIoImpl( + js, promise.attach(registerPendingEvent()), getCriticalSection(), IdentityFunc()); } template jsg::PromiseForResult IoContext::awaitIoWithInputLock( jsg::Lock& js, kj::Promise promise, Func&& func) { - return awaitIoImpl(js, promise.attach(registerPendingEvent()), getInputLock(), - kj::fwd(func)); + return awaitIoImpl( + js, promise.attach(registerPendingEvent()), getInputLock(), kj::fwd(func)); } template jsg::Promise IoContext::awaitIoWithInputLock(jsg::Lock& js, kj::Promise promise) { - return awaitIoImpl(js, promise.attach(registerPendingEvent()), getInputLock(), - IdentityFunc()); + return awaitIoImpl(js, promise.attach(registerPendingEvent()), getInputLock(), IdentityFunc()); } template @@ -1005,24 +1059,18 @@ jsg::Promise IoContext::awaitIoLegacyWithInputLock(jsg::Lock& js, kj::Promise // To reduce the code size impact of awaitIoImpl, move promise continuation code out of // awaitIoImpl() where possible. This way, the then() parameters are only templated based on one // type each. -template +template kj::Promise> promiseForExceptionOrT(kj::Promise promise) { if constexpr (jsg::isVoid()) { - return promise.then([]() -> IoContext::ExceptionOr { - return kj::none; - }, [](kj::Exception&& exception) -> IoContext::ExceptionOr { - return kj::mv(exception); - }); + return promise.then([]() -> IoContext::ExceptionOr { return kj::none; }, + [](kj::Exception&& exception) -> IoContext::ExceptionOr { return kj::mv(exception); }); } else { - return promise.then([](T&& result) -> IoContext::ExceptionOr { - return kj::mv(result); - }, [](kj::Exception&& exception) -> IoContext::ExceptionOr { - return kj::mv(exception); - }); + return promise.then([](T&& result) -> IoContext::ExceptionOr { return kj::mv(result); }, + [](kj::Exception&& exception) -> IoContext::ExceptionOr { return kj::mv(exception); }); } }; -template +template Result throwOrReturnResult(jsg::Lock& js, IoContext::ExceptionOr&& exceptionOrResult) { if constexpr (jsg::isVoid()) { KJ_IF_SOME(e, exceptionOrResult) { @@ -1070,16 +1118,15 @@ jsg::PromiseForResult IoContext::awaitIoImpl( // Reminder: This can throw JsExceptionThrown if the execution context has been terminated. // it's important in that case that `promiseExceptionOrT` will be destroyed before `func`. - auto [ jsPromise, resolver ] = js.newPromiseAndResolver>(); - - addTask(promiseExceptionOrT - .then([this, resolver = kj::mv(resolver), ilOrCs = kj::mv(ilOrCs), - maybeAsyncContext = jsg::AsyncContextFrame::currentRef(js), - // Reminder: It's important that `func` gets attached to the promise before the whole - // thing is passed to `addTask()`, so that it's impossible for `func` to be destroyed - // before the inner promise. - func = kj::fwd(func)] - (ExceptionOr&& exceptionOrT) mutable { + auto [jsPromise, resolver] = js.newPromiseAndResolver>(); + + addTask(promiseExceptionOrT.then( + [this, resolver = kj::mv(resolver), ilOrCs = kj::mv(ilOrCs), + maybeAsyncContext = jsg::AsyncContextFrame::currentRef(js), + // Reminder: It's important that `func` gets attached to the promise before the whole + // thing is passed to `addTask()`, so that it's impossible for `func` to be destroyed + // before the inner promise. + func = kj::fwd(func)](ExceptionOr&& exceptionOrT) mutable { struct FuncResultPair { // It's important that `exceptionOrT` is destroyed before `Func`. Lambda captures are // destroyed in unspecified order, so we wrap them in a struct to make it explicit. @@ -1087,10 +1134,10 @@ jsg::PromiseForResult IoContext::awaitIoImpl( ExceptionOr exceptionOrT; }; - return run([resolver = kj::mv(resolver), - funcResultPair = FuncResultPair { kj::fwd(func), kj::mv(exceptionOrT) }, - maybeAsyncContext = kj::mv(maybeAsyncContext)] - (Worker::Lock& lock) mutable { + return run( + [resolver = kj::mv(resolver), + funcResultPair = FuncResultPair{kj::fwd(func), kj::mv(exceptionOrT)}, + maybeAsyncContext = kj::mv(maybeAsyncContext)](Worker::Lock& lock) mutable { jsg::AsyncContextFrame::Scope asyncScope(lock, maybeAsyncContext); jsg::Lock& js = lock; @@ -1141,9 +1188,7 @@ jsg::PromiseForResult IoContext::awaitIoImpl( // Here we can just `resolver.reject` because we already have a JS exception. resolver.resolve(js, funcResultPair.func(js, kj::mv(result))); } - }, [&](jsg::Value error) { - resolver.reject(js, error.getHandle(js)); - }); + }, [&](jsg::Value error) { resolver.reject(js, error.getHandle(js)); }); } catch (jsg::JsExceptionThrown&) { // An uncatchable JS exception -- presumably, the isolate has been terminated. We // can't convert this into a promise rejection, we need to just propagate it up. @@ -1155,7 +1200,8 @@ jsg::PromiseForResult IoContext::awaitIoImpl( } } } - }, kj::mv(ilOrCs)); + }, + kj::mv(ilOrCs)); })); // Reminder: This can throw JsExceptionThrown if the execution context has been terminated. We @@ -1178,21 +1224,19 @@ kj::_::ReducePromises> IoContext::awaitJs(jsg::Lock& js, jsg::Pro if (!isDone) { // The JavaScript resolver was garbage collected, i.e. JavaScript will never resolve // this promise. - fulfiller->reject( - JSG_KJ_EXCEPTION(FAILED, Error, "Promise will never complete.")); + fulfiller->reject(JSG_KJ_EXCEPTION(FAILED, Error, "Promise will never complete.")); } } private: kj::Maybe finalize() override { if (!isDone) { - fulfiller->reject(JSG_KJ_EXCEPTION(FAILED, - Error, "Promise will never complete.")); + fulfiller->reject(JSG_KJ_EXCEPTION(FAILED, Error, "Promise will never complete.")); isDone = true; return "A hanging Promise was canceled. This happens when the worker runtime is waiting " - "for a Promise from JavaScript to resolve, but has detected that the Promise " - "cannot possibly ever resolve because all code and events related to the " - "Promise's I/O context have already finished."_kj; + "for a Promise from JavaScript to resolve, but has detected that the Promise " + "cannot possibly ever resolve because all code and events related to the " + "Promise's I/O context have already finished."_kj; } else { return kj::none; } @@ -1200,9 +1244,8 @@ kj::_::ReducePromises> IoContext::awaitJs(jsg::Lock& js, jsg::Pro }; auto fulfiller = kj::refcounted(kj::mv(paf.fulfiller)); - auto errorHandler = - [fulfiller = addObject(kj::addRef(*fulfiller))] - (jsg::Lock& js, jsg::Value jsExceptionRef) mutable { + auto errorHandler = [fulfiller = addObject(kj::addRef(*fulfiller))]( + jsg::Lock& js, jsg::Value jsExceptionRef) mutable { // Note: `context` can possibly be different than the one that started the wait, if the // promise resolved from a different context. In that case the use of `fulfiller` will // throw later on. But it's OK to use the wrong context up until that point. @@ -1218,8 +1261,8 @@ kj::_::ReducePromises> IoContext::awaitJs(jsg::Lock& js, jsg::Pro // once the exception has been tunneled into a KJ exception, so the later logging won't be // as useful. We should improve the tunneling to include stack traces and ensure that all // consumers do in fact log exceptions, then we can remove this. - context.logUncaughtException(UncaughtExceptionSource::INTERNAL_ASYNC, - jsg::JsValue(jsException)); + context.logUncaughtException( + UncaughtExceptionSource::INTERNAL_ASYNC, jsg::JsValue(jsException)); fulfiller->fulfiller->reject(jsg::createTunneledException(isolate, jsException)); fulfiller->isDone = true; @@ -1231,8 +1274,7 @@ kj::_::ReducePromises> IoContext::awaitJs(jsg::Lock& js, jsg::Pro fulfiller->isDone = true; }, kj::mv(errorHandler)); } else { - jsPromise.then(js, [fulfiller = addObject(kj::mv(fulfiller))] - (jsg::Lock&, T&& result) mutable { + jsPromise.then(js, [fulfiller = addObject(kj::mv(fulfiller))](jsg::Lock&, T&& result) mutable { if constexpr (isIoOwn()) { fulfiller->fulfiller->fulfill(kj::mv(*result)); } else { @@ -1260,13 +1302,11 @@ inline IoPtr IoContext::addObject(T& obj) { template auto IoContext::addFunctor(Func&& func) { if constexpr (kj::isReference()) { - return [func = addObject(func)](auto&&... params) mutable { - return (*func)(kj::fwd(params)...); - }; + return [func = addObject(func)]( + auto&&... params) mutable { return (*func)(kj::fwd(params)...); }; } else { - return [func = addObject(kj::heap(kj::mv(func)))](auto&&... params) mutable { - return (*func)(kj::fwd(params)...); - }; + return [func = addObject(kj::heap(kj::mv(func)))]( + auto&&... params) mutable { return (*func)(kj::fwd(params)...); }; } } @@ -1287,11 +1327,14 @@ jsg::PromiseForResult IoContext::blockConcurrencyWhile( typedef jsg::RemovePromise> T; auto [result, resolver] = js.newPromiseAndResolver(); - addTask(cs->wait().then([this, callback = kj::mv(callback), - maybeAsyncContext = jsg::AsyncContextFrame::currentRef(js)] - (InputGate::Lock inputLock) mutable { - return run([this, callback = kj::mv(callback), - maybeAsyncContext = kj::mv(maybeAsyncContext)](Worker::Lock& lock) mutable { + addTask( + cs->wait() + .then([this, callback = kj::mv(callback), + maybeAsyncContext = jsg::AsyncContextFrame::currentRef(js)]( + InputGate::Lock inputLock) mutable { + return run( + [this, callback = kj::mv(callback), maybeAsyncContext = kj::mv(maybeAsyncContext)]( + Worker::Lock& lock) mutable { jsg::AsyncContextFrame::Scope scope(lock, maybeAsyncContext); auto cb = kj::mv(callback); @@ -1301,26 +1344,29 @@ jsg::PromiseForResult IoContext::blockConcurrencyWhile( // Arrange to time out if the critical section runs more than 30 seconds, so that objects // won't be hung forever if they have a critical section that deadlocks. - auto timeout = afterLimitTimeout(30 * kj::SECONDS) - .then([]() -> T { - kj::throwFatalException(JSG_KJ_EXCEPTION( - OVERLOADED, Error, - "A call to blockConcurrencyWhile() in a Durable Object waited for " - "too long. The call was canceled and the Durable Object was reset.")); + auto timeout = afterLimitTimeout(30 * kj::SECONDS).then([]() -> T { + kj::throwFatalException(JSG_KJ_EXCEPTION(OVERLOADED, Error, + "A call to blockConcurrencyWhile() in a Durable Object waited for " + "too long. The call was canceled and the Durable Object was reset.")); }); return awaitJs(lock, kj::mv(promise)).exclusiveJoin(kj::mv(timeout)); - }, kj::mv(inputLock)); - }).then([this, cs = kj::mv(cs), resolver = kj::mv(resolver), - maybeAsyncContext = jsg::AsyncContextFrame::currentRef(js)](T&& value) mutable { + }, + kj::mv(inputLock)); + }) + .then( + [this, cs = kj::mv(cs), resolver = kj::mv(resolver), + maybeAsyncContext = jsg::AsyncContextFrame::currentRef(js)](T&& value) mutable { auto inputLock = cs->succeeded(); - return run([value = kj::mv(value),resolver = kj::mv(resolver), - maybeAsyncContext = kj::mv(maybeAsyncContext)](Worker::Lock& lock) mutable { + return run( + [value = kj::mv(value), resolver = kj::mv(resolver), + maybeAsyncContext = kj::mv(maybeAsyncContext)](Worker::Lock& lock) mutable { jsg::AsyncContextFrame::Scope scope(lock, maybeAsyncContext); resolver.resolve(lock, kj::mv(value)); - }, kj::mv(inputLock)); - }, [cs = kj::mv(cs2)] - (kj::Exception&& e) mutable { + }, + kj::mv(inputLock)); + }, + [cs = kj::mv(cs2)](kj::Exception&& e) mutable { // Annotate as broken for periodic metrics. auto msg = e.getDescription(); if (!msg.startsWith("broken."_kj) && !msg.startsWith("remote.broken."_kj)) { diff --git a/src/workerd/io/io-gate.c++ b/src/workerd/io/io-gate.c++ index 52b4cae8e99..6125ddeb6cf 100644 --- a/src/workerd/io/io-gate.c++ +++ b/src/workerd/io/io-gate.c++ @@ -25,7 +25,9 @@ InputGate::~InputGate() noexcept { InputGate::Waiter::Waiter( kj::PromiseFulfiller& fulfiller, InputGate& gate, bool isChildWaiter) - : fulfiller(fulfiller), gate(&gate), isChildWaiter(isChildWaiter) { + : fulfiller(fulfiller), + gate(&gate), + isChildWaiter(isChildWaiter) { gate.hooks.inputGateWaiterAdded(); if (isChildWaiter) { gate.waitingChildren.add(*this); @@ -64,9 +66,8 @@ kj::Promise InputGate::onBroken() { InputGate::Lock::Lock(InputGate& gate) : gate(&gate), - cs(gate.isCriticalSection - ? kj::Maybe(kj::addRef(static_cast(gate))) - : kj::none) { + cs(gate.isCriticalSection ? kj::Maybe(kj::addRef(static_cast(gate))) + : kj::none) { InputGate* gateToLock = &gate; KJ_IF_SOME(c, cs) { @@ -283,7 +284,7 @@ void InputGate::setBroken(const kj::Exception& e) { InputGate& InputGate::CriticalSection::parentAsInputGate() { CriticalSection* ptr = this; - for(;;) { + for (;;) { KJ_SWITCH_ONEOF(ptr->parent) { KJ_CASE_ONEOF(p, InputGate*) { return *p; @@ -303,7 +304,8 @@ InputGate& InputGate::CriticalSection::parentAsInputGate() { // ======================================================================================= OutputGate::OutputGate(Hooks& hooks) - : hooks(hooks), pastLocksPromise(kj::Promise(kj::READY_NOW).fork()) {} + : hooks(hooks), + pastLocksPromise(kj::Promise(kj::READY_NOW).fork()) {} OutputGate::~OutputGate() noexcept(false) {} const OutputGate::Hooks OutputGate::Hooks::DEFAULT; @@ -317,14 +319,13 @@ kj::Own> OutputGate::lock() { kj::Promise OutputGate::wait() { hooks.outputGateWaiterAdded(); - return pastLocksPromise.addBranch().attach(kj::defer([this]() { - hooks.outputGateWaiterRemoved(); - })); + return pastLocksPromise.addBranch().attach( + kj::defer([this]() { hooks.outputGateWaiterRemoved(); })); } kj::Promise OutputGate::onBroken() { - KJ_REQUIRE(!brokenState.is>>(), - "onBroken() can only be called once"); + KJ_REQUIRE( + !brokenState.is>>(), "onBroken() can only be called once"); KJ_IF_SOME(e, brokenState.tryGet()) { return kj::cp(e); @@ -343,7 +344,7 @@ namespace { void END_OUTPUT_LOCK_CANCELATION_STACK_START_WAITER_STACK() {} -} // namespace +} // namespace kj::Exception OutputGate::makeUnfulfilledException() { return kj::getDestructionReason( diff --git a/src/workerd/io/io-gate.h b/src/workerd/io/io-gate.h index e3cb51195e8..8b418fb420c 100644 --- a/src/workerd/io/io-gate.h +++ b/src/workerd/io/io-gate.h @@ -63,12 +63,18 @@ class InputGate { class Lock { public: KJ_DISALLOW_COPY(Lock); - Lock(Lock&& other): gate(other.gate), cs(kj::mv(other.cs)) { other.gate = nullptr; } - ~Lock() noexcept(false) { if (gate != nullptr) gate->releaseLock(); } + Lock(Lock&& other): gate(other.gate), cs(kj::mv(other.cs)) { + other.gate = nullptr; + } + ~Lock() noexcept(false) { + if (gate != nullptr) gate->releaseLock(); + } // Increments the lock's refcount, returning a duplicate `Lock`. All `Lock`s must be dropped // before the gate is unlocked. - Lock addRef() { return Lock(*gate); } + Lock addRef() { + return Lock(*gate); + } // Start a new critical section from this lock. After `wait()` has been called on the returned // critical section for the first time, no further Locks will be handed out by @@ -84,7 +90,9 @@ class InputGate { bool isFor(const InputGate& gate) const; - inline bool operator==(const Lock& other) const { return gate == other.gate; } + inline bool operator==(const Lock& other) const { + return gate == other.gate; + } private: // Becomes null on move. @@ -225,7 +233,9 @@ class OutputGate { // Optionally make a promise which should be exclusiveJoin()ed with the lock promise to // implement a timeout. The returned promise should be something that throws an exception // after some timeout has expired. - virtual kj::Promise makeTimeoutPromise() { return kj::NEVER_DONE; } + virtual kj::Promise makeTimeoutPromise() { + return kj::NEVER_DONE; + } // Optionally track metrics. In practice these are implemented by MetricsCollector::Actor, but // we don't want to depend on that class from here. @@ -283,12 +293,11 @@ kj::Promise OutputGate::lockWhile(kj::Promise promise) { if constexpr (std::is_void_v) { promise = promise.exclusiveJoin(hooks.makeTimeoutPromise()); } else { - promise = promise.exclusiveJoin(hooks.makeTimeoutPromise() - .then([]() -> T { KJ_UNREACHABLE; })); + promise = promise.exclusiveJoin(hooks.makeTimeoutPromise().then([]() -> T { KJ_UNREACHABLE; })); } hooks.outputGateLocked(); - auto rejectIfCanceled = kj::defer([this, &fulfiller](){ + auto rejectIfCanceled = kj::defer([this, &fulfiller]() { hooks.outputGateReleased(); if (fulfiller->isWaiting()) { auto e = makeUnfulfilledException(); diff --git a/src/workerd/io/io-own.c++ b/src/workerd/io/io-own.c++ index 68ca0cedda1..6eb8a5c44d3 100644 --- a/src/workerd/io/io-own.c++ +++ b/src/workerd/io/io-own.c++ @@ -38,8 +38,8 @@ void DeleteQueue::checkFarGet(const DeleteQueue* deleteQueue, const std::type_in void DeleteQueue::checkWeakGet(workerd::WeakRef& weak) { if (!weak.isValid()) { - JSG_FAIL_REQUIRE(Error, - kj::str("Couldn't complete operation because the execution context has ended.")); + JSG_FAIL_REQUIRE( + Error, kj::str("Couldn't complete operation because the execution context has ended.")); } } @@ -66,7 +66,7 @@ void OwnedObjectList::link(kj::Own object) { KJ_IF_SOME(f, object->finalizer) { if (finalizersRan) { KJ_LOG(ERROR, "somehow new objects are being added after finalizers already ran", - kj::getStackTrace()); + kj::getStackTrace()); f.finalize(); } } diff --git a/src/workerd/io/io-own.h b/src/workerd/io/io-own.h index 70876a4611f..e81c6c6838d 100644 --- a/src/workerd/io/io-own.h +++ b/src/workerd/io/io-own.h @@ -13,17 +13,28 @@ namespace workerd { class IoContext; -template class IoOwn; -template class IoPtr; -template class ReverseIoOwn; +template +class IoOwn; +template +class IoPtr; +template +class ReverseIoOwn; template -struct RemoveIoOwn_ { typedef T Type; static constexpr bool is = false; }; +struct RemoveIoOwn_ { + typedef T Type; + static constexpr bool is = false; +}; template -struct RemoveIoOwn_> { typedef T Type; static constexpr bool is = true; }; +struct RemoveIoOwn_> { + typedef T Type; + static constexpr bool is = true; +}; template -constexpr bool isIoOwn() { return RemoveIoOwn_::is; } +constexpr bool isIoOwn() { + return RemoveIoOwn_::is; +} template using RemoveIoOwn = typename RemoveIoOwn_::Type; @@ -104,8 +115,7 @@ class OwnedObjectList { // Object which receives possibly-cross-thread deletions of owned objects. class DeleteQueue: public kj::AtomicRefcounted { public: - DeleteQueue() - : crossThreadDeleteQueue(State { kj::Vector() }) {} + DeleteQueue(): crossThreadDeleteQueue(State{kj::Vector()}) {} void scheduleDeletion(OwnedObject* object) const; @@ -120,7 +130,8 @@ class DeleteQueue: public kj::AtomicRefcounted { kj::MutexGuarded> crossThreadDeleteQueue; // Implements the corresponding methods of IoContext and ActorContext. - template IoOwn addObject(kj::Own obj, OwnedObjectList& ownedObjects); + template + IoOwn addObject(kj::Own obj, OwnedObjectList& ownedObjects); template ReverseIoOwn addObjectReverse( @@ -148,8 +159,7 @@ inline SpecificOwnedObject* DeleteQueue::addObjectImpl( // (which would have forced a bunch of useless vtables and vtable pointers)... I'm manually // constructing the kj::Own<> using a disposer that I know is compatible. // TODO(cleanup): Can KJ be made to support this use case? - kj::Own ownedObject( - new SpecificOwnedObject(kj::mv(obj)), + kj::Own ownedObject(new SpecificOwnedObject(kj::mv(obj)), kj::_::HeapDisposer>::instance); if constexpr (kj::canConvert()) { @@ -162,8 +172,7 @@ inline SpecificOwnedObject* DeleteQueue::addObjectImpl( } template -inline IoOwn DeleteQueue::addObject( - kj::Own obj, OwnedObjectList& ownedObjects) { +inline IoOwn DeleteQueue::addObject(kj::Own obj, OwnedObjectList& ownedObjects) { return IoOwn(kj::atomicAddRef(*this), addObjectImpl(kj::mv(obj), ownedObjects)); } @@ -179,8 +188,7 @@ inline ReverseIoOwn DeleteQueue::addObjectReverse( // to the delete queue to get the tear-down order right. class DeleteQueuePtr: public kj::Own { public: - DeleteQueuePtr(kj::Own value) - : kj::Own(kj::mv(value)) {} + DeleteQueuePtr(kj::Own value): kj::Own(kj::mv(value)) {} KJ_DISALLOW_COPY_AND_MOVE(DeleteQueuePtr); ~DeleteQueuePtr() noexcept(false) { auto ptr = get(); @@ -202,7 +210,9 @@ class IoOwn { KJ_DISALLOW_COPY(IoOwn); T* operator->(); - T& operator*() { return *operator->(); } + T& operator*() { + return *operator->(); + } operator kj::Own() &&; IoOwn& operator=(IoOwn&& other); IoOwn& operator=(decltype(nullptr)); @@ -228,9 +238,9 @@ class IoOwn { kj::Own deleteQueue; SpecificOwnedObject* item; - IoOwn(kj::Own deleteQueue, - SpecificOwnedObject* item) - : deleteQueue(kj::mv(deleteQueue)), item(item) {} + IoOwn(kj::Own deleteQueue, SpecificOwnedObject* item) + : deleteQueue(kj::mv(deleteQueue)), + item(item) {} }; // Reference held by a V8 heap object, pointing to a KJ event loop object. Cannot be @@ -238,12 +248,13 @@ class IoOwn { template class IoPtr { public: - IoPtr(const IoPtr& other) - : deleteQueue(kj::atomicAddRef(*other.deleteQueue)), ptr(other.ptr) {} + IoPtr(const IoPtr& other): deleteQueue(kj::atomicAddRef(*other.deleteQueue)), ptr(other.ptr) {} IoPtr(IoPtr&& other) = default; T* operator->(); - T& operator*() { return *operator->(); } + T& operator*() { + return *operator->(); + } IoPtr& operator=(decltype(nullptr)); private: @@ -253,9 +264,9 @@ class IoPtr { kj::Own deleteQueue; T* ptr; - IoPtr(kj::Own deleteQueue, - T* ptr) - : deleteQueue(kj::mv(deleteQueue)), ptr(ptr) {} + IoPtr(kj::Own deleteQueue, T* ptr) + : deleteQueue(kj::mv(deleteQueue)), + ptr(ptr) {} }; // Owned pointer held by a KJ I/O object living in the same thread as an IoContext. The underlying @@ -277,7 +288,9 @@ class ReverseIoOwn { KJ_DISALLOW_COPY(ReverseIoOwn); T* operator->(); - T& operator*() { return *operator->(); } + T& operator*() { + return *operator->(); + } operator kj::Own() &&; ReverseIoOwn& operator=(ReverseIoOwn&& other); ReverseIoOwn& operator=(decltype(nullptr)); @@ -289,15 +302,14 @@ class ReverseIoOwn { kj::Own> weakRef; SpecificOwnedObject* item; - ReverseIoOwn(kj::Own> weakRef, - SpecificOwnedObject* item) - : weakRef(kj::mv(weakRef)), item(item) {} + ReverseIoOwn(kj::Own> weakRef, SpecificOwnedObject* item) + : weakRef(kj::mv(weakRef)), + item(item) {} }; template -IoOwn::IoOwn(IoOwn&& other) - : deleteQueue(kj::mv(other.deleteQueue)), - item(other.item) { +IoOwn::IoOwn(IoOwn&& other): deleteQueue(kj::mv(other.deleteQueue)), + item(other.item) { other.item = nullptr; } diff --git a/src/workerd/io/io-thread-context.c++ b/src/workerd/io/io-thread-context.c++ index fa065da5916..1c20b01dd9c 100644 --- a/src/workerd/io/io-thread-context.c++ +++ b/src/workerd/io/io-thread-context.c++ @@ -15,9 +15,12 @@ ThreadContext::HeaderIdBundle::HeaderIdBundle(kj::HttpHeaderTable::Builder& buil authorization(builder.add("Authorization")), secWebSocketProtocol(builder.add("Sec-WebSocket-Protocol")) {} -ThreadContext::ThreadContext( - kj::Timer& timer, kj::EntropySource& entropySource, - HeaderIdBundle headerIds, capnp::HttpOverCapnpFactory& httpOverCapnpFactory, capnp::ByteStreamFactory& byteStreamFactory, bool fiddle) +ThreadContext::ThreadContext(kj::Timer& timer, + kj::EntropySource& entropySource, + HeaderIdBundle headerIds, + capnp::HttpOverCapnpFactory& httpOverCapnpFactory, + capnp::ByteStreamFactory& byteStreamFactory, + bool fiddle) : timer(timer), entropySource(entropySource), headerIds(headerIds), diff --git a/src/workerd/io/io-thread-context.h b/src/workerd/io/io-thread-context.h index 21ccd516be2..6285f8dc8e6 100644 --- a/src/workerd/io/io-thread-context.h +++ b/src/workerd/io/io-thread-context.h @@ -15,34 +15,46 @@ class ThreadContext { const kj::HttpHeaderTable& table; const kj::HttpHeaderId contentEncoding; - const kj::HttpHeaderId cfCacheStatus; // used by cache API implementation + const kj::HttpHeaderId cfCacheStatus; // used by cache API implementation const kj::HttpHeaderId cacheControl; - const kj::HttpHeaderId cfCacheNamespace; // used by Cache binding implementation - const kj::HttpHeaderId cfKvMetadata; // used by KV binding implementation - const kj::HttpHeaderId cfR2ErrorHeader; // used by R2 binding implementation - const kj::HttpHeaderId cfBlobMetadataSize; // used by R2 binding implementation - const kj::HttpHeaderId cfBlobRequest; // used by R2 binding implementation - const kj::HttpHeaderId authorization; // used by R2 binding implementation + const kj::HttpHeaderId cfCacheNamespace; // used by Cache binding implementation + const kj::HttpHeaderId cfKvMetadata; // used by KV binding implementation + const kj::HttpHeaderId cfR2ErrorHeader; // used by R2 binding implementation + const kj::HttpHeaderId cfBlobMetadataSize; // used by R2 binding implementation + const kj::HttpHeaderId cfBlobRequest; // used by R2 binding implementation + const kj::HttpHeaderId authorization; // used by R2 binding implementation const kj::HttpHeaderId secWebSocketProtocol; }; - ThreadContext( - kj::Timer& timer, kj::EntropySource& entropySource, - HeaderIdBundle headerIds, capnp::HttpOverCapnpFactory& httpOverCapnpFactory, - capnp::ByteStreamFactory& byteStreamFactory, bool isFiddle); + ThreadContext(kj::Timer& timer, + kj::EntropySource& entropySource, + HeaderIdBundle headerIds, + capnp::HttpOverCapnpFactory& httpOverCapnpFactory, + capnp::ByteStreamFactory& byteStreamFactory, + bool isFiddle); // This should only be used to construct TimerChannel. Everything else should use TimerChannel. - inline kj::Timer& getUnsafeTimer() const { return timer; } - inline kj::EntropySource& getEntropySource() const { return entropySource; } - inline const kj::HttpHeaderTable& getHeaderTable() const { return headerIds.table; } - inline const HeaderIdBundle& getHeaderIds() const { return headerIds; } + inline kj::Timer& getUnsafeTimer() const { + return timer; + } + inline kj::EntropySource& getEntropySource() const { + return entropySource; + } + inline const kj::HttpHeaderTable& getHeaderTable() const { + return headerIds.table; + } + inline const HeaderIdBundle& getHeaderIds() const { + return headerIds; + } inline capnp::HttpOverCapnpFactory& getHttpOverCapnpFactory() const { return httpOverCapnpFactory; } inline capnp::ByteStreamFactory& getByteStreamFactory() const { return byteStreamFactory; } - inline bool isFiddle() const { return fiddle; } + inline bool isFiddle() const { + return fiddle; + } private: // NOTE: This timer only updates when entering the event loop! diff --git a/src/workerd/io/io-timers.c++ b/src/workerd/io/io-timers.c++ index 9bfd591e92d..ee6ccdfb5ef 100644 --- a/src/workerd/io/io-timers.c++ +++ b/src/workerd/io/io-timers.c++ @@ -9,7 +9,8 @@ TimeoutId TimeoutId::Generator::getNext() { auto id = nextId++; if (nextId > MAX_SAFE_INTEGER) { KJ_LOG(WARNING, "Unable to set timeout because there are no more unique ids"); - JSG_FAIL_REQUIRE(Error, "Unable to set timeout because there are no more unique ids " + JSG_FAIL_REQUIRE(Error, + "Unable to set timeout because there are no more unique ids " "less than Number.MAX_SAFE_INTEGER."); } return TimeoutId(id); @@ -17,7 +18,9 @@ TimeoutId TimeoutId::Generator::getNext() { TimeoutManager::TimeoutParameters::TimeoutParameters( bool repeat, int64_t msDelay, jsg::Function function) - : repeat(repeat), msDelay(msDelay), function(kj::mv(function)) { + : repeat(repeat), + msDelay(msDelay), + function(kj::mv(function)) { // Don't allow pushing Date.now() backwards! This should be checked before TimeoutParameters // is created but just in case... if (msDelay < 0) { diff --git a/src/workerd/io/limit-enforcer.h b/src/workerd/io/limit-enforcer.h index 0052b035c27..b92b1a0a7b4 100644 --- a/src/workerd/io/limit-enforcer.h +++ b/src/workerd/io/limit-enforcer.h @@ -86,7 +86,7 @@ class IsolateLimitEnforcer { }; // Abstract interface that enforces resource limits on a IoContext. -class LimitEnforcer { +class LimitEnforcer { public: // Called just after taking the isolate lock, before executing JavaScript code, to enforce // limits on that code execution, particularly the CPU limit. The returned `Own` should diff --git a/src/workerd/io/observer.c++ b/src/workerd/io/observer.c++ index 50999c62a84..144abf0279b 100644 --- a/src/workerd/io/observer.c++ +++ b/src/workerd/io/observer.c++ @@ -13,9 +13,7 @@ class FeatureObserverImpl final: public FeatureObserver { public: void use(Feature feature) const override { auto lock = counts.lockExclusive(); - lock->upsert(feature, 1, [](uint64_t& count, uint64_t value) { - count += value; - }); + lock->upsert(feature, 1, [](uint64_t& count, uint64_t value) { count += value; }); } void collect(CollectCallback&& callback) const override { @@ -46,4 +44,4 @@ kj::Maybe FeatureObserver::get() { } return kj::none; } -}; +}; // namespace workerd diff --git a/src/workerd/io/observer.h b/src/workerd/io/observer.h index ff65c87a1e9..a4052d88cdf 100644 --- a/src/workerd/io/observer.h +++ b/src/workerd/io/observer.h @@ -23,9 +23,9 @@ class TimerChannel; class WebSocketObserver: public kj::Refcounted { public: // Called when a worker sends a message on this WebSocket (includes close messages). - virtual void sentMessage(size_t bytes) { }; + virtual void sentMessage(size_t bytes) {}; // Called when a worker receives a message on this WebSocket (includes close messages). - virtual void receivedMessage(size_t bytes) { }; + virtual void receivedMessage(size_t bytes) {}; }; // Observes a specific request to a specific worker. Also observes outgoing subrequests. @@ -39,7 +39,9 @@ class RequestObserver: public kj::Refcounted { // // This means that, when the returned observer observes a message being sent, the message is being // sent from the worker to the client making the request. - virtual kj::Maybe> tryCreateWebSocketObserver() { return kj::none; }; + virtual kj::Maybe> tryCreateWebSocketObserver() { + return kj::none; + }; // Invoked when the request is actually delivered. // @@ -57,7 +59,7 @@ class RequestObserver: public kj::Refcounted { virtual void setIsPrewarm() {} // Describes the source of a failure - enum class FailureSource: uint8_t { + enum class FailureSource : uint8_t { // Failure occurred during deferred proxying DEFERRED_PROXY, @@ -75,7 +77,9 @@ class RequestObserver: public kj::Refcounted { // called once, and only one method call may be made to the returned interface. // // The returned reference remains valid as long as the observer and `worker` both remain live. - virtual WorkerInterface& wrapWorkerInterface(WorkerInterface& worker) { return worker; } + virtual WorkerInterface& wrapWorkerInterface(WorkerInterface& worker) { + return worker; + } // Wrap an HttpClient so that its usage is counted in the request's subrequest stats. virtual kj::Own wrapSubrequestClient(kj::Own client) { @@ -90,7 +94,9 @@ class RequestObserver: public kj::Refcounted { // Used to record when a worker has used a dynamic dispatch binding. virtual void setHasDispatched() {}; - virtual SpanParent getSpan() { return nullptr; } + virtual SpanParent getSpan() { + return nullptr; + } virtual void addedContextTask() {} virtual void finishedContextTask() {} @@ -99,12 +105,14 @@ class RequestObserver: public kj::Refcounted { virtual void setFailedOpen(bool value) {} - virtual uint64_t clockRead() { return 0; } + virtual uint64_t clockRead() { + return 0; + } }; class IsolateObserver: public kj::AtomicRefcounted, public jsg::IsolateObserver { public: - virtual ~IsolateObserver() noexcept(false) { } + virtual ~IsolateObserver() noexcept(false) {} // Called when Worker::Isolate is created. virtual void created() {}; @@ -118,7 +126,7 @@ class IsolateObserver: public kj::AtomicRefcounted, public jsg::IsolateObserver virtual void teardownFinished() {} // Describes why a worker was started. - enum class StartType: uint8_t { + enum class StartType : uint8_t { // Cold start with active request waiting. COLD, @@ -148,8 +156,8 @@ class IsolateObserver: public kj::AtomicRefcounted, public jsg::IsolateObserver virtual void waitingForOtherIsolate(kj::StringPtr id) {} // Call if this is an async lock attempt, before constructing LockRecord. - virtual void reportAsyncInfo(uint currentLoad, bool threadWaitingSameLock, - uint threadWaitingDifferentLockCount) {} + virtual void reportAsyncInfo( + uint currentLoad, bool threadWaitingSameLock, uint threadWaitingDifferentLockCount) {} // TODO(cleanup): Should be able to get this data at `tryCreateLockTiming()` time. It'd be // easier if IsolateObserver were an AOP class, and thus had access to the real isolate. @@ -164,7 +172,9 @@ class IsolateObserver: public kj::AtomicRefcounted, public jsg::IsolateObserver // Construct a LockTiming if config.reportScriptLockTiming is true, or if the // request (if any) is being traced. virtual kj::Maybe> tryCreateLockTiming( - kj::OneOf> parentOrRequest) const { return kj::none; } + kj::OneOf> parentOrRequest) const { + return kj::none; + } // Use like so: // @@ -192,9 +202,15 @@ class IsolateObserver: public kj::AtomicRefcounted, public jsg::IsolateObserver } KJ_DISALLOW_COPY_AND_MOVE(LockRecord); - void locked() { KJ_IF_SOME(l, lockTiming) l.get()->locked(); } - void gcPrologue() { KJ_IF_SOME(l, lockTiming) l.get()->gcPrologue(); } - void gcEpilogue() { KJ_IF_SOME(l, lockTiming) l.get()->gcEpilogue(); } + void locked() { + KJ_IF_SOME(l, lockTiming) l.get()->locked(); + } + void gcPrologue() { + KJ_IF_SOME(l, lockTiming) l.get()->gcPrologue(); + } + void gcEpilogue() { + KJ_IF_SOME(l, lockTiming) l.get()->gcEpilogue(); + } private: // The presence of `lockTiming` determines whether or not we need to record timing data. If diff --git a/src/workerd/io/promise-wrapper-test.c++ b/src/workerd/io/promise-wrapper-test.c++ index adafffb944e..8b379b3a42c 100644 --- a/src/workerd/io/promise-wrapper-test.c++ +++ b/src/workerd/io/promise-wrapper-test.c++ @@ -45,9 +45,7 @@ struct CaptureThrowContext: public jsg::Object, public ContextGlobal { template v8::Local testT(jsg::Lock& js, const jsg::TypeHandler>& handler) { - return handler.wrap(js, [](Lock&) -> T { - JSG_FAIL_REQUIRE(TypeError, "boom"); - }); + return handler.wrap(js, [](Lock&) -> T { JSG_FAIL_REQUIRE(TypeError, "boom"); }); } static kj::Promise staticTest1() { @@ -83,9 +81,7 @@ struct CaptureThrowContext: public jsg::Object, public ContextGlobal { } }; JSG_DECLARE_ISOLATE_TYPE( - CaptureThrowIsolate, - CaptureThrowContext, - jsg::TypeWrapperExtension); + CaptureThrowIsolate, CaptureThrowContext, jsg::TypeWrapperExtension); KJ_TEST("Async functions capture sync errors with flag") { Evaluator e(v8System); diff --git a/src/workerd/io/promise-wrapper.h b/src/workerd/io/promise-wrapper.h index 35a0cb6f529..4d0fd901f93 100644 --- a/src/workerd/io/promise-wrapper.h +++ b/src/workerd/io/promise-wrapper.h @@ -13,7 +13,9 @@ template class PromiseWrapper { public: template - static constexpr const char* getName(kj::Promise*) { return "Promise"; } + static constexpr const char* getName(kj::Promise*) { + return "Promise"; + } // Explicitly disallow V8 handles, which are not safe for the KJ event loop to own directly. template @@ -22,12 +24,14 @@ class PromiseWrapper { static constexpr const char* getName(kj::Promise>*) = delete; template - static constexpr const char* getName(kj::Promise>*) { return "Promise"; } + static constexpr const char* getName(kj::Promise>*) { + return "Promise"; + } // For some reason, this wasn't needed for jsg::V8Ref... template - v8::Local wrap( - v8::Local context, kj::Maybe> creator, + v8::Local wrap(v8::Local context, + kj::Maybe> creator, kj::Promise promise) { auto& js = jsg::Lock::from(context->GetIsolate()); auto jsPromise = IoContext::current().awaitIoLegacy(js, kj::mv(promise)); @@ -35,12 +39,13 @@ class PromiseWrapper { } template - kj::Maybe> tryUnwrap( - v8::Local context, v8::Local handle, kj::Promise*, - kj::Maybe> parentObject) { + kj::Maybe> tryUnwrap(v8::Local context, + v8::Local handle, + kj::Promise*, + kj::Maybe> parentObject) { auto& wrapper = static_cast(*this); - auto jsPromise = KJ_UNWRAP_OR_RETURN(wrapper.tryUnwrap( - context, handle, (jsg::Promise*)nullptr, parentObject), kj::none); + auto jsPromise = KJ_UNWRAP_OR_RETURN( + wrapper.tryUnwrap(context, handle, (jsg::Promise*)nullptr, parentObject), kj::none); auto& js = jsg::Lock::from(context->GetIsolate()); return IoContext::current().awaitJs(js, kj::mv(jsPromise)); } @@ -51,4 +56,4 @@ class PromiseWrapper { v8::Local getTemplate(v8::Isolate* isolate, kj::Promise*) = delete; }; -} // namespace workerd +} // namespace workerd diff --git a/src/workerd/io/request-tracker.c++ b/src/workerd/io/request-tracker.c++ index cc4df524d89..c9eb03351c9 100644 --- a/src/workerd/io/request-tracker.c++ +++ b/src/workerd/io/request-tracker.c++ @@ -6,12 +6,12 @@ namespace workerd { -RequestTracker::RequestTracker(Hooks& hooksImpl) : hooks(hooksImpl) {}; +RequestTracker::RequestTracker(Hooks& hooksImpl): hooks(hooksImpl) {}; RequestTracker::~RequestTracker() noexcept(false) {} RequestTracker::ActiveRequest::ActiveRequest(kj::Badge, RequestTracker& parent) - : maybeParent(kj::addRef(parent)) { + : maybeParent(kj::addRef(parent)) { parent.requestActive(); } RequestTracker::ActiveRequest::~ActiveRequest() noexcept(false) { @@ -40,4 +40,4 @@ RequestTracker::ActiveRequest RequestTracker::startRequest() { return ActiveRequest({}, *this); } -} // namespace workerd +} // namespace workerd diff --git a/src/workerd/io/request-tracker.h b/src/workerd/io/request-tracker.h index 1aeb299d2a0..da32a29de24 100644 --- a/src/workerd/io/request-tracker.h +++ b/src/workerd/io/request-tracker.h @@ -50,7 +50,7 @@ class RequestTracker final: public kj::Refcounted { hooks = kj::none; } - kj::Own addRef() { + kj::Own addRef() { return kj::addRef(*this); } @@ -62,4 +62,4 @@ class RequestTracker final: public kj::Refcounted { kj::Maybe hooks; }; -} // namespace workerd +} // namespace workerd diff --git a/src/workerd/io/trace.c++ b/src/workerd/io/trace.c++ index 85c40cf7882..d81292f7fd2 100644 --- a/src/workerd/io/trace.c++ +++ b/src/workerd/io/trace.c++ @@ -22,17 +22,19 @@ static kj::HttpMethod validateMethod(capnp::HttpMethod method) { return static_cast(method); } -} // namespace +} // namespace -Trace::FetchEventInfo::FetchEventInfo(kj::HttpMethod method, kj::String url, kj::String cfJson, - kj::Array
headers) - : method(method), url(kj::mv(url)), cfJson(kj::mv(cfJson)), headers(kj::mv(headers)) {} +Trace::FetchEventInfo::FetchEventInfo( + kj::HttpMethod method, kj::String url, kj::String cfJson, kj::Array
headers) + : method(method), + url(kj::mv(url)), + cfJson(kj::mv(cfJson)), + headers(kj::mv(headers)) {} Trace::FetchEventInfo::FetchEventInfo(rpc::Trace::FetchEventInfo::Reader reader) : method(validateMethod(reader.getMethod())), url(kj::str(reader.getUrl())), - cfJson(kj::str(reader.getCfJson())) -{ + cfJson(kj::str(reader.getCfJson())) { kj::Vector
v; v.addAll(reader.getHeaders()); headers = v.releaseAsArray(); @@ -50,18 +52,19 @@ void Trace::FetchEventInfo::copyTo(rpc::Trace::FetchEventInfo::Builder builder) } Trace::FetchEventInfo::Header::Header(kj::String name, kj::String value) - : name(kj::mv(name)), value(kj::mv(value)) {} + : name(kj::mv(name)), + value(kj::mv(value)) {} Trace::FetchEventInfo::Header::Header(rpc::Trace::FetchEventInfo::Header::Reader reader) - : name(kj::str(reader.getName())), value(kj::str(reader.getValue())) {} + : name(kj::str(reader.getName())), + value(kj::str(reader.getValue())) {} void Trace::FetchEventInfo::Header::copyTo(rpc::Trace::FetchEventInfo::Header::Builder builder) { builder.setName(name); builder.setValue(value); } -Trace::JsRpcEventInfo::JsRpcEventInfo(kj::String methodName) - : methodName(kj::mv(methodName)) {} +Trace::JsRpcEventInfo::JsRpcEventInfo(kj::String methodName): methodName(kj::mv(methodName)) {} Trace::JsRpcEventInfo::JsRpcEventInfo(rpc::Trace::JsRpcEventInfo::Reader reader) : methodName(kj::str(reader.getMethodName())) {} @@ -71,18 +74,19 @@ void Trace::JsRpcEventInfo::copyTo(rpc::Trace::JsRpcEventInfo::Builder builder) } Trace::ScheduledEventInfo::ScheduledEventInfo(double scheduledTime, kj::String cron) - : scheduledTime(scheduledTime), cron(kj::mv(cron)) {} + : scheduledTime(scheduledTime), + cron(kj::mv(cron)) {} Trace::ScheduledEventInfo::ScheduledEventInfo(rpc::Trace::ScheduledEventInfo::Reader reader) - : scheduledTime(reader.getScheduledTime()), cron(kj::str(reader.getCron())) {} + : scheduledTime(reader.getScheduledTime()), + cron(kj::str(reader.getCron())) {} void Trace::ScheduledEventInfo::copyTo(rpc::Trace::ScheduledEventInfo::Builder builder) { builder.setScheduledTime(scheduledTime); builder.setCron(cron); } -Trace::AlarmEventInfo::AlarmEventInfo(kj::Date scheduledTime) - : scheduledTime(scheduledTime) {} +Trace::AlarmEventInfo::AlarmEventInfo(kj::Date scheduledTime): scheduledTime(scheduledTime) {} Trace::AlarmEventInfo::AlarmEventInfo(rpc::Trace::AlarmEventInfo::Reader reader) : scheduledTime(reader.getScheduledTimeMs() * kj::MILLISECONDS + kj::UNIX_EPOCH) {} @@ -92,10 +96,12 @@ void Trace::AlarmEventInfo::copyTo(rpc::Trace::AlarmEventInfo::Builder builder) } Trace::QueueEventInfo::QueueEventInfo(kj::String queueName, uint32_t batchSize) - : queueName(kj::mv(queueName)), batchSize(batchSize) {} + : queueName(kj::mv(queueName)), + batchSize(batchSize) {} Trace::QueueEventInfo::QueueEventInfo(rpc::Trace::QueueEventInfo::Reader reader) - : queueName(kj::heapString(reader.getQueueName())), batchSize(reader.getBatchSize()) {} + : queueName(kj::heapString(reader.getQueueName())), + batchSize(reader.getBatchSize()) {} void Trace::QueueEventInfo::copyTo(rpc::Trace::QueueEventInfo::Builder builder) { builder.setQueueName(queueName); @@ -103,7 +109,9 @@ void Trace::QueueEventInfo::copyTo(rpc::Trace::QueueEventInfo::Builder builder) } Trace::EmailEventInfo::EmailEventInfo(kj::String mailFrom, kj::String rcptTo, uint32_t rawSize) - : mailFrom(kj::mv(mailFrom)), rcptTo(kj::mv(rcptTo)), rawSize(rawSize) {} + : mailFrom(kj::mv(mailFrom)), + rcptTo(kj::mv(rcptTo)), + rawSize(rawSize) {} Trace::EmailEventInfo::EmailEventInfo(rpc::Trace::EmailEventInfo::Reader reader) : mailFrom(kj::heapString(reader.getMailFrom())), @@ -116,11 +124,11 @@ void Trace::EmailEventInfo::copyTo(rpc::Trace::EmailEventInfo::Builder builder) builder.setRawSize(rawSize); } -kj::Vector getTraceItemsFromTraces(kj::ArrayPtr> traces) { +kj::Vector getTraceItemsFromTraces( + kj::ArrayPtr> traces) { return KJ_MAP(t, traces) -> Trace::TraceEventInfo::TraceItem { - return Trace::TraceEventInfo::TraceItem(t->scriptName.map([](auto& scriptName) { - return kj::str(scriptName); - })); + return Trace::TraceEventInfo::TraceItem( + t->scriptName.map([](auto& scriptName) { return kj::str(scriptName); })); }; } @@ -150,15 +158,15 @@ Trace::TraceEventInfo::TraceItem::TraceItem(kj::Maybe scriptName) Trace::TraceEventInfo::TraceItem::TraceItem(rpc::Trace::TraceEventInfo::TraceItem::Reader reader) : scriptName(kj::str(reader.getScriptName())) {} -void Trace::TraceEventInfo::TraceItem::copyTo(rpc::Trace::TraceEventInfo::TraceItem::Builder builder) { +void Trace::TraceEventInfo::TraceItem::copyTo( + rpc::Trace::TraceEventInfo::TraceItem::Builder builder) { KJ_IF_SOME(name, scriptName) { builder.setScriptName(name); } } -Trace::DiagnosticChannelEvent::DiagnosticChannelEvent(kj::Date timestamp, - kj::String channel, - kj::Array message) +Trace::DiagnosticChannelEvent::DiagnosticChannelEvent( + kj::Date timestamp, kj::String channel, kj::Array message) : timestamp(timestamp), channel(kj::mv(channel)), message(kj::mv(message)) {} @@ -169,15 +177,13 @@ Trace::DiagnosticChannelEvent::DiagnosticChannelEvent( channel(kj::heapString(reader.getChannel())), message(kj::heapArray(reader.getMessage())) {} -void Trace::DiagnosticChannelEvent::copyTo( - rpc::Trace::DiagnosticChannelEvent::Builder builder) { +void Trace::DiagnosticChannelEvent::copyTo(rpc::Trace::DiagnosticChannelEvent::Builder builder) { builder.setTimestampNs((timestamp - kj::UNIX_EPOCH) / kj::NANOSECONDS); builder.setChannel(channel); builder.setMessage(message); } -Trace::HibernatableWebSocketEventInfo::HibernatableWebSocketEventInfo(Type type) - : type(type) {} +Trace::HibernatableWebSocketEventInfo::HibernatableWebSocketEventInfo(Type type): type(type) {} Trace::HibernatableWebSocketEventInfo::HibernatableWebSocketEventInfo( rpc::Trace::HibernatableWebSocketEventInfo::Reader reader) @@ -204,13 +210,13 @@ void Trace::HibernatableWebSocketEventInfo::copyTo( Trace::HibernatableWebSocketEventInfo::Type Trace::HibernatableWebSocketEventInfo::readFrom( rpc::Trace::HibernatableWebSocketEventInfo::Reader reader) { auto type = reader.getType(); - switch(type.which()) { + switch (type.which()) { case rpc::Trace::HibernatableWebSocketEventInfo::Type::MESSAGE: { return Message{}; } case rpc::Trace::HibernatableWebSocketEventInfo::Type::CLOSE: { auto close = type.getClose(); - return Close { + return Close{ .code = close.getCode(), .wasClean = close.getWasClean(), }; @@ -221,8 +227,7 @@ Trace::HibernatableWebSocketEventInfo::Type Trace::HibernatableWebSocketEventInf } } -Trace::FetchResponseInfo::FetchResponseInfo(uint16_t statusCode) - : statusCode(statusCode) {} +Trace::FetchResponseInfo::FetchResponseInfo(uint16_t statusCode): statusCode(statusCode) {} Trace::FetchResponseInfo::FetchResponseInfo(rpc::Trace::FetchResponseInfo::Reader reader) : statusCode(reader.getStatusCode()) {} @@ -236,14 +241,20 @@ Trace::Log::Log(kj::Date timestamp, LogLevel logLevel, kj::String message) logLevel(logLevel), message(kj::mv(message)) {} -Trace::Exception::Exception(kj::Date timestamp, kj::String name, kj::String message, - kj::Maybe stack) - : timestamp(timestamp), name(kj::mv(name)), message(kj::mv(message)), stack(kj::mv(stack)) {} +Trace::Exception::Exception( + kj::Date timestamp, kj::String name, kj::String message, kj::Maybe stack) + : timestamp(timestamp), + name(kj::mv(name)), + message(kj::mv(message)), + stack(kj::mv(stack)) {} -Trace::Trace(kj::Maybe stableId, kj::Maybe scriptName, +Trace::Trace(kj::Maybe stableId, + kj::Maybe scriptName, kj::Maybe> scriptVersion, - kj::Maybe dispatchNamespace, kj::Maybe scriptId, - kj::Array scriptTags, kj::Maybe entrypoint) + kj::Maybe dispatchNamespace, + kj::Maybe scriptId, + kj::Array scriptTags, + kj::Maybe entrypoint) : stableId(kj::mv(stableId)), scriptName(kj::mv(scriptName)), scriptVersion(kj::mv(scriptVersion)), @@ -467,7 +478,7 @@ Trace::Exception::Exception(rpc::Trace::Exception::Reader reader) } } -SpanBuilder& SpanBuilder::operator=(SpanBuilder &&other) { +SpanBuilder& SpanBuilder::operator=(SpanBuilder&& other) { end(); observer = kj::mv(other.observer); span = kj::mv(other.span); @@ -497,7 +508,8 @@ void SpanBuilder::setOperationName(kj::ConstString operationName) { void SpanBuilder::setTag(kj::ConstString key, TagValue value) { KJ_IF_SOME(s, span) { auto keyPtr = key.asPtr(); - s.tags.upsert(kj::mv(key), kj::mv(value), [keyPtr](TagValue& existingValue, TagValue&& newValue) { + s.tags.upsert( + kj::mv(key), kj::mv(value), [keyPtr](TagValue& existingValue, TagValue&& newValue) { // This is a programming error, but not a serious one. We could alternatively just emit // duplicate tags and leave the Jaeger UI in charge of warning about them. [[maybe_unused]] static auto logged = [keyPtr]() { @@ -514,13 +526,11 @@ void SpanBuilder::addLog(kj::Date timestamp, kj::ConstString key, TagValue value if (s.logs.size() >= Span::MAX_LOGS) { ++s.droppedLogs; } else { - s.logs.add(Span::Log { - .timestamp = timestamp, + s.logs.add(Span::Log{.timestamp = timestamp, .tag = { .key = kj::mv(key), .value = kj::mv(value), - } - }); + }}); } } } @@ -544,10 +554,13 @@ kj::Promise>> PipelineTracer::onComplete() { return kj::mv(paf.promise); } -kj::Own PipelineTracer::makeWorkerTracer( - PipelineLogLevel pipelineLogLevel, kj::Maybe scriptId, kj::Maybe stableId, - kj::Maybe scriptName, kj::Maybe> scriptVersion, - kj::Maybe dispatchNamespace, kj::Array scriptTags, +kj::Own PipelineTracer::makeWorkerTracer(PipelineLogLevel pipelineLogLevel, + kj::Maybe scriptId, + kj::Maybe stableId, + kj::Maybe scriptName, + kj::Maybe> scriptVersion, + kj::Maybe dispatchNamespace, + kj::Array scriptTags, kj::Maybe entrypoint) { auto trace = kj::refcounted(kj::mv(stableId), kj::mv(scriptName), kj::mv(scriptVersion), kj::mv(dispatchNamespace), kj::mv(scriptId), kj::mv(scriptTags), kj::mv(entrypoint)); @@ -555,13 +568,15 @@ kj::Own PipelineTracer::makeWorkerTracer( return kj::refcounted(kj::addRef(*this), kj::mv(trace), pipelineLogLevel); } -WorkerTracer::WorkerTracer(kj::Own parentPipeline, - kj::Own trace, PipelineLogLevel pipelineLogLevel) - : pipelineLogLevel(pipelineLogLevel), trace(kj::mv(trace)), +WorkerTracer::WorkerTracer( + kj::Own parentPipeline, kj::Own trace, PipelineLogLevel pipelineLogLevel) + : pipelineLogLevel(pipelineLogLevel), + trace(kj::mv(trace)), parentPipeline(kj::mv(parentPipeline)) {} WorkerTracer::WorkerTracer(PipelineLogLevel pipelineLogLevel) : pipelineLogLevel(pipelineLogLevel), - trace(kj::refcounted(kj::none, kj::none, kj::none, kj::none, kj::none, nullptr, kj::none)) {} + trace(kj::refcounted( + kj::none, kj::none, kj::none, kj::none, kj::none, nullptr, kj::none)) {} void WorkerTracer::log(kj::Date timestamp, LogLevel logLevel, kj::String message) { if (trace->exceededLogLimit) { @@ -575,17 +590,17 @@ void WorkerTracer::log(kj::Date timestamp, LogLevel logLevel, kj::String message trace->exceededLogLimit = true; trace->truncated = true; // We use a JSON encoded array/string to match other console.log() recordings: - trace->logs.add( - timestamp, LogLevel::WARN, - kj::str("[\"Log size limit exceeded: More than 128KB of data (across console.log statements, exception, request metadata and headers) was logged during a single request. Subsequent data for this request will not be recorded in logs, appear when tailing this Worker's logs, or in Tail Workers.\"]")); + trace->logs.add(timestamp, LogLevel::WARN, + kj::str( + "[\"Log size limit exceeded: More than 128KB of data (across console.log statements, exception, request metadata and headers) was logged during a single request. Subsequent data for this request will not be recorded in logs, appear when tailing this Worker's logs, or in Tail Workers.\"]")); return; } trace->bytesUsed = newSize; trace->logs.add(timestamp, logLevel, kj::mv(message)); } -void WorkerTracer::addException(kj::Date timestamp, kj::String name, kj::String message, - kj::Maybe stack) { +void WorkerTracer::addException( + kj::Date timestamp, kj::String name, kj::String message, kj::Maybe stack) { if (trace->exceededExceptionLimit) { return; } @@ -602,32 +617,29 @@ void WorkerTracer::addException(kj::Date timestamp, kj::String name, kj::String if (newSize > MAX_TRACE_BYTES) { trace->exceededExceptionLimit = true; trace->truncated = true; - trace->exceptions.add( - timestamp, kj::str("Error"), - kj::str("Trace resource limit exceeded; subsequent exceptions not recorded."), - kj::none); + trace->exceptions.add(timestamp, kj::str("Error"), + kj::str("Trace resource limit exceeded; subsequent exceptions not recorded."), kj::none); return; } trace->bytesUsed = newSize; trace->exceptions.add(timestamp, kj::mv(name), kj::mv(message), kj::mv(stack)); } -void WorkerTracer::addDiagnosticChannelEvent(kj::Date timestamp, - kj::String channel, - kj::Array message) { +void WorkerTracer::addDiagnosticChannelEvent( + kj::Date timestamp, kj::String channel, kj::Array message) { if (trace->exceededDiagnosticChannelEventLimit) { return; } if (pipelineLogLevel == PipelineLogLevel::NONE) { return; } - size_t newSize = trace->bytesUsed + sizeof(Trace::DiagnosticChannelEvent) + channel.size() + - message.size(); + size_t newSize = + trace->bytesUsed + sizeof(Trace::DiagnosticChannelEvent) + channel.size() + message.size(); if (newSize > MAX_TRACE_BYTES) { trace->exceededDiagnosticChannelEventLimit = true; trace->truncated = true; - trace->diagnosticChannelEvents.add(timestamp, kj::str("workerd.LimitExceeded"), - kj::Array()); + trace->diagnosticChannelEvents.add( + timestamp, kj::str("workerd.LimitExceeded"), kj::Array()); return; } trace->bytesUsed = newSize; @@ -658,21 +670,28 @@ void WorkerTracer::setEventInfo(kj::Date timestamp, Trace::EventInfo&& info) { newSize += fetch.cfJson.size(); if (newSize > MAX_TRACE_BYTES) { trace->truncated = true; - trace->logs.add( - timestamp, LogLevel::WARN, + trace->logs.add(timestamp, LogLevel::WARN, kj::str("[\"Trace resource limit exceeded; could not capture event info.\"]")); trace->eventInfo = Trace::FetchEventInfo(fetch.method, {}, {}, {}); return; } } - KJ_CASE_ONEOF(_, Trace::JsRpcEventInfo) {} - KJ_CASE_ONEOF(_, Trace::ScheduledEventInfo) {} - KJ_CASE_ONEOF(_, Trace::AlarmEventInfo) {} - KJ_CASE_ONEOF(_, Trace::QueueEventInfo) {} - KJ_CASE_ONEOF(_, Trace::EmailEventInfo) {} - KJ_CASE_ONEOF(_, Trace::TraceEventInfo) {} - KJ_CASE_ONEOF(_, Trace::HibernatableWebSocketEventInfo) {} - KJ_CASE_ONEOF(_, Trace::CustomEventInfo) {} + KJ_CASE_ONEOF(_, Trace::JsRpcEventInfo) { + } + KJ_CASE_ONEOF(_, Trace::ScheduledEventInfo) { + } + KJ_CASE_ONEOF(_, Trace::AlarmEventInfo) { + } + KJ_CASE_ONEOF(_, Trace::QueueEventInfo) { + } + KJ_CASE_ONEOF(_, Trace::EmailEventInfo) { + } + KJ_CASE_ONEOF(_, Trace::TraceEventInfo) { + } + KJ_CASE_ONEOF(_, Trace::HibernatableWebSocketEventInfo) { + } + KJ_CASE_ONEOF(_, Trace::CustomEventInfo) { + } } trace->bytesUsed = newSize; trace->eventInfo = kj::mv(info); @@ -699,8 +718,7 @@ void WorkerTracer::setFetchResponseInfo(Trace::FetchResponseInfo&& info) { } KJ_REQUIRE(KJ_REQUIRE_NONNULL(trace->eventInfo).is()); - KJ_ASSERT(trace->fetchResponseInfo == kj::none, - "setFetchResponseInfo can only be called once"); + KJ_ASSERT(trace->fetchResponseInfo == kj::none, "setFetchResponseInfo can only be called once"); trace->fetchResponseInfo = kj::mv(info); } @@ -712,4 +730,4 @@ void WorkerTracer::setTrace(rpc::Trace::Reader reader) { trace->mergeFrom(reader, pipelineLogLevel); } -} // namespace workerd +} // namespace workerd diff --git a/src/workerd/io/trace.h b/src/workerd/io/trace.h index 2aea551836d..ee9bb1a71a9 100644 --- a/src/workerd/io/trace.h +++ b/src/workerd/io/trace.h @@ -17,9 +17,9 @@ #include namespace kj { - enum class HttpMethod; - class EntropySource; -} +enum class HttpMethod; +class EntropySource; +} // namespace kj namespace workerd { @@ -31,7 +31,8 @@ typedef rpc::Trace::Log::Level LogLevel; enum class PipelineLogLevel { // WARNING: This must be kept in sync with PipelineDef::LogLevel (which is not in the OSS // release). - NONE, FULL + NONE, + FULL }; // TODO(someday): See if we can merge similar code concepts... Trace fills a role similar to @@ -48,12 +49,15 @@ enum class PipelineLogLevel { // TODO(cleanup) - worth separating into immutable Trace vs. mutable TraceBuilder? // Collects trace information about the handling of a worker/pipeline fetch event. -class Trace final : public kj::Refcounted { +class Trace final: public kj::Refcounted { public: - explicit Trace(kj::Maybe stableId, kj::Maybe scriptName, + explicit Trace(kj::Maybe stableId, + kj::Maybe scriptName, kj::Maybe> scriptVersion, - kj::Maybe dispatchNamespace, kj::Maybe scriptId, - kj::Array scriptTags, kj::Maybe entrypoint); + kj::Maybe dispatchNamespace, + kj::Maybe scriptId, + kj::Array scriptTags, + kj::Maybe entrypoint); Trace(rpc::Trace::Reader reader); ~Trace() noexcept(false); KJ_DISALLOW_COPY_AND_MOVE(Trace); @@ -62,8 +66,8 @@ class Trace final : public kj::Refcounted { public: class Header; - explicit FetchEventInfo(kj::HttpMethod method, kj::String url, kj::String cfJson, - kj::Array
headers); + explicit FetchEventInfo( + kj::HttpMethod method, kj::String url, kj::String cfJson, kj::Array
headers); FetchEventInfo(rpc::Trace::FetchEventInfo::Reader reader); class Header { @@ -84,7 +88,7 @@ class Trace final : public kj::Refcounted { kj::HttpMethod method; kj::String url; - // TODO(perf): It might be more efficient to store some sort of parsed JSON result instead? + // TODO(perf): It might be more efficient to store some sort of parsed JSON result instead? kj::String cfJson; kj::Array
headers; @@ -169,12 +173,12 @@ class Trace final : public kj::Refcounted { class HibernatableWebSocketEventInfo { public: - struct Message{}; + struct Message {}; struct Close { uint16_t code; bool wasClean; }; - struct Error{}; + struct Error {}; using Type = kj::OneOf; @@ -191,7 +195,6 @@ class Trace final : public kj::Refcounted { public: explicit CustomEventInfo() {}; CustomEventInfo(rpc::Trace::CustomEventInfo::Reader reader) {}; - }; class FetchResponseInfo { @@ -206,9 +209,8 @@ class Trace final : public kj::Refcounted { class DiagnosticChannelEvent { public: - explicit DiagnosticChannelEvent(kj::Date timestamp, - kj::String channel, - kj::Array message); + explicit DiagnosticChannelEvent( + kj::Date timestamp, kj::String channel, kj::Array message); DiagnosticChannelEvent(rpc::Trace::DiagnosticChannelEvent::Reader reader); DiagnosticChannelEvent(DiagnosticChannelEvent&&) = default; KJ_DISALLOW_COPY(DiagnosticChannelEvent); @@ -240,8 +242,8 @@ class Trace final : public kj::Refcounted { class Exception { public: - explicit Exception(kj::Date timestamp, kj::String name, kj::String message, - kj::Maybe stack); + explicit Exception( + kj::Date timestamp, kj::String name, kj::String message, kj::Maybe stack); Exception(rpc::Trace::Exception::Reader reader); Exception(Exception&&) = default; KJ_DISALLOW_COPY(Exception); @@ -264,9 +266,16 @@ class Trace final : public kj::Refcounted { // We treat the origin value as "unset". kj::Date eventTimestamp = kj::UNIX_EPOCH; - typedef kj::OneOf EventInfo; + typedef kj::OneOf + EventInfo; kj::Maybe eventInfo; // TODO(someday): Support more event types. // TODO(someday): Work out what sort of information we may want to convey about the parent @@ -317,7 +326,7 @@ class WorkerTracer; // A tracer which records traces for a set of stages. All traces for a pipeline's stages and // possible subpipeline stages are recorded here, where they can be used to call a pipeline's // trace worker. -class PipelineTracer final : public kj::Refcounted { +class PipelineTracer final: public kj::Refcounted { public: // Creates a pipeline tracer (with a possible parent). explicit PipelineTracer(kj::Maybe> parentPipeline = kj::none) @@ -336,13 +345,13 @@ class PipelineTracer final : public kj::Refcounted { } kj::Own makeWorkerTracer(PipelineLogLevel pipelineLogLevel, - kj::Maybe scriptId, - kj::Maybe stableId, - kj::Maybe scriptName, - kj::Maybe> scriptVersion, - kj::Maybe dispatchNamespace, - kj::Array scriptTags, - kj::Maybe entrypoint); + kj::Maybe scriptId, + kj::Maybe stableId, + kj::Maybe scriptName, + kj::Maybe> scriptVersion, + kj::Maybe dispatchNamespace, + kj::Array scriptTags, + kj::Maybe entrypoint); // Makes a tracer for a worker stage. private: @@ -358,10 +367,11 @@ class PipelineTracer final : public kj::Refcounted { // Tracer are released, its Trace is considered complete and ready for submission. If the Trace to // write to isn't provided (that already exists in a PipelineTracer), the trace must by extracted // via extractTrace. -class WorkerTracer final : public kj::Refcounted { +class WorkerTracer final: public kj::Refcounted { public: explicit WorkerTracer(kj::Own parentPipeline, - kj::Own trace, PipelineLogLevel pipelineLogLevel); + kj::Own trace, + PipelineLogLevel pipelineLogLevel); explicit WorkerTracer(PipelineLogLevel pipelineLogLevel); KJ_DISALLOW_COPY_AND_MOVE(WorkerTracer); @@ -371,11 +381,11 @@ class WorkerTracer final : public kj::Refcounted { // TODO(soon): Eventually: //void setMetrics(...) // Or get from MetricsCollector::Request directly? - void addException(kj::Date timestamp, kj::String name, kj::String message, - kj::Maybe stack); + void addException( + kj::Date timestamp, kj::String name, kj::String message, kj::Maybe stack); - void addDiagnosticChannelEvent(kj::Date timestamp, kj::String channel, - kj::Array message); + void addDiagnosticChannelEvent( + kj::Date timestamp, kj::String channel, kj::Array message); // Adds info about the event that triggered the trace. Must not be called more than once. void setEventInfo(kj::Date timestamp, Trace::EventInfo&&); @@ -463,7 +473,9 @@ struct Span { uint droppedLogs = 0; explicit Span(kj::ConstString operationName, kj::Date startTime) - : operationName(kj::mv(operationName)), startTime(startTime), endTime(startTime) {} + : operationName(kj::mv(operationName)), + startTime(startTime), + endTime(startTime) {} }; // An opaque token which can be used to create child spans of some parent. This is typically @@ -488,18 +500,22 @@ class SpanParent { // Create a new child span. // // `operationName` should be a string literal with infinite lifetime. - SpanBuilder newChild(kj::ConstString operationName, - kj::Date startTime = kj::systemPreciseCalendarClock().now()); + SpanBuilder newChild( + kj::ConstString operationName, kj::Date startTime = kj::systemPreciseCalendarClock().now()); // Useful to skip unnecessary code when not observed. - bool isObserved() { return observer != kj::none; } + bool isObserved() { + return observer != kj::none; + } // Get the underlying SpanObserver representing the parent span. // // This is needed in particular when making outbound network requests that must be annotated with // trace IDs in a way that is specific to the trace back-end being used. The caller must downcast // the `SpanObserver` to the expected observer type in order to extract the trace ID. - kj::Maybe getObserver() { return observer; } + kj::Maybe getObserver() { + return observer; + } private: kj::Maybe> observer; @@ -522,8 +538,9 @@ class SpanBuilder { // // `operationName` should be a string literal with infinite lifetime, or somehow otherwise be // attached to the observer observing this span. - explicit SpanBuilder(kj::Maybe> observer, kj::ConstString operationName, - kj::Date startTime = kj::systemPreciseCalendarClock().now()) { + explicit SpanBuilder(kj::Maybe> observer, + kj::ConstString operationName, + kj::Date startTime = kj::systemPreciseCalendarClock().now()) { if (observer != kj::none) { this->observer = kj::mv(observer); span.emplace(kj::mv(operationName), startTime); @@ -545,20 +562,24 @@ class SpanBuilder { void end(); // Useful to skip unnecessary code when not observed. - bool isObserved() { return observer != kj::none; } + bool isObserved() { + return observer != kj::none; + } // Get the underlying SpanObserver representing the span. // // This is needed in particular when making outbound network requests that must be annotated with // trace IDs in a way that is specific to the trace back-end being used. The caller must downcast // the `SpanObserver` to the expected observer type in order to extract the trace ID. - kj::Maybe getObserver() { return observer; } + kj::Maybe getObserver() { + return observer; + } // Create a new child span. // // `operationName` should be a string literal with infinite lifetime. - SpanBuilder newChild(kj::ConstString operationName, - kj::Date startTime = kj::systemPreciseCalendarClock().now()); + SpanBuilder newChild( + kj::ConstString operationName, kj::Date startTime = kj::systemPreciseCalendarClock().now()); // Change the operation name from what was specified at span creation. // @@ -604,8 +625,7 @@ class SpanObserver: public kj::Refcounted { virtual void report(const Span& span) = 0; }; -inline SpanParent::SpanParent(SpanBuilder& builder) - : observer(mapAddRef(builder.observer)) {} +inline SpanParent::SpanParent(SpanBuilder& builder): observer(mapAddRef(builder.observer)) {} inline SpanParent SpanParent::addRef() { return SpanParent(mapAddRef(observer)); @@ -613,12 +633,12 @@ inline SpanParent SpanParent::addRef() { inline SpanBuilder SpanParent::newChild(kj::ConstString operationName, kj::Date startTime) { return SpanBuilder(observer.map([](kj::Own& obs) { return obs->newChild(); }), - kj::mv(operationName), startTime); + kj::mv(operationName), startTime); } inline SpanBuilder SpanBuilder::newChild(kj::ConstString operationName, kj::Date startTime) { return SpanBuilder(observer.map([](kj::Own& obs) { return obs->newChild(); }), - kj::mv(operationName), startTime); + kj::mv(operationName), startTime); } -} // namespace workerd +} // namespace workerd diff --git a/src/workerd/io/worker-entrypoint.c++ b/src/workerd/io/worker-entrypoint.c++ index c61de1cf016..23d432e912e 100644 --- a/src/workerd/io/worker-entrypoint.c++ +++ b/src/workerd/io/worker-entrypoint.c++ @@ -39,25 +39,28 @@ public: // WorkerLimits::Reader. Hence this is not necessarily the same as // topLevelRequest.getZoneDefaultWorkerLimits(), since the top level request may be shared between // zone and non-zone workers. - static kj::Own construct( - ThreadContext& threadContext, - kj::Own worker, - kj::Maybe entrypointName, - kj::Maybe> actor, - kj::Own limitEnforcer, - kj::Own ioContextDependency, - kj::Own ioChannelFactory, - kj::Own metrics, - kj::TaskSet& waitUntilTasks, - bool tunnelExceptions, - kj::Maybe> workerTracer, - kj::Maybe cfBlobJson); - - kj::Promise request( - kj::HttpMethod method, kj::StringPtr url, const kj::HttpHeaders& headers, - kj::AsyncInputStream& requestBody, Response& response) override; - kj::Promise connect(kj::StringPtr host, const kj::HttpHeaders& headers, - kj::AsyncIoStream& connection, ConnectResponse& response, + static kj::Own construct(ThreadContext& threadContext, + kj::Own worker, + kj::Maybe entrypointName, + kj::Maybe> actor, + kj::Own limitEnforcer, + kj::Own ioContextDependency, + kj::Own ioChannelFactory, + kj::Own metrics, + kj::TaskSet& waitUntilTasks, + bool tunnelExceptions, + kj::Maybe> workerTracer, + kj::Maybe cfBlobJson); + + kj::Promise request(kj::HttpMethod method, + kj::StringPtr url, + const kj::HttpHeaders& headers, + kj::AsyncInputStream& requestBody, + Response& response) override; + kj::Promise connect(kj::StringPtr host, + const kj::HttpHeaders& headers, + kj::AsyncIoStream& connection, + ConnectResponse& response, kj::HttpConnectSettings settings) override; void prewarm(kj::StringPtr url) override; kj::Promise runScheduled(kj::Date scheduledTime, kj::StringPtr cron) override; @@ -84,8 +87,7 @@ private: kj::Maybe> failOpenService; bool loggedExceptionEarlier = false; - void init( - kj::Own worker, + void init(kj::Own worker, kj::Maybe> actor, kj::Own limitEnforcer, kj::Own ioContextDependency, @@ -97,32 +99,36 @@ private: kj::Promise maybeAddGcPassForTest(IoContext& context, kj::Promise promise); kj::Promise runAlarmImpl( - kj::Own incomingRequest, kj::Date scheduledTime, uint32_t retryCount); + kj::Own incomingRequest, + kj::Date scheduledTime, + uint32_t retryCount); public: // For kj::heap() only; pretend this is private. WorkerEntrypoint(kj::Badge badge, - ThreadContext& threadContext, - kj::TaskSet& waitUntilTasks, - bool tunnelExceptions, - kj::Maybe entrypointName, - kj::Maybe cfBlobJson); + ThreadContext& threadContext, + kj::TaskSet& waitUntilTasks, + bool tunnelExceptions, + kj::Maybe entrypointName, + kj::Maybe cfBlobJson); }; // Simple wrapper around `HttpService::Response` to let us know if the response was sent // already. class WorkerEntrypoint::ResponseSentTracker final: public kj::HttpService::Response { public: - ResponseSentTracker(kj::HttpService::Response& inner) - : inner(inner) {} + ResponseSentTracker(kj::HttpService::Response& inner): inner(inner) {} KJ_DISALLOW_COPY_AND_MOVE(ResponseSentTracker); - bool isSent() const { return sent; } + bool isSent() const { + return sent; + } - kj::Own send( - uint statusCode, kj::StringPtr statusText, const kj::HttpHeaders& headers, + kj::Own send(uint statusCode, + kj::StringPtr statusText, + const kj::HttpHeaders& headers, kj::Maybe expectedBodySize = kj::none) override { - TRACE_EVENT("workerd", "WorkerEntrypoint::ResponseSentTracker::send()", - "statusCode", statusCode); + TRACE_EVENT( + "workerd", "WorkerEntrypoint::ResponseSentTracker::send()", "statusCode", statusCode); sent = true; return inner.send(statusCode, statusText, headers, expectedBodySize); } @@ -138,43 +144,40 @@ private: bool sent = false; }; -kj::Own WorkerEntrypoint::construct( - ThreadContext& threadContext, - kj::Own worker, - kj::Maybe entrypointName, - kj::Maybe> actor, - kj::Own limitEnforcer, - kj::Own ioContextDependency, - kj::Own ioChannelFactory, - kj::Own metrics, - kj::TaskSet& waitUntilTasks, - bool tunnelExceptions, - kj::Maybe> workerTracer, - kj::Maybe cfBlobJson) { +kj::Own WorkerEntrypoint::construct(ThreadContext& threadContext, + kj::Own worker, + kj::Maybe entrypointName, + kj::Maybe> actor, + kj::Own limitEnforcer, + kj::Own ioContextDependency, + kj::Own ioChannelFactory, + kj::Own metrics, + kj::TaskSet& waitUntilTasks, + bool tunnelExceptions, + kj::Maybe> workerTracer, + kj::Maybe cfBlobJson) { TRACE_EVENT("workerd", "WorkerEntrypoint::construct()"); auto obj = kj::heap(kj::Badge(), threadContext, waitUntilTasks, tunnelExceptions, entrypointName, kj::mv(cfBlobJson)); - obj->init(kj::mv(worker), kj::mv(actor), kj::mv(limitEnforcer), - kj::mv(ioContextDependency), kj::mv(ioChannelFactory), kj::addRef(*metrics), - kj::mv(workerTracer)); + obj->init(kj::mv(worker), kj::mv(actor), kj::mv(limitEnforcer), kj::mv(ioContextDependency), + kj::mv(ioChannelFactory), kj::addRef(*metrics), kj::mv(workerTracer)); auto& wrapper = metrics->wrapWorkerInterface(*obj); return kj::attachRef(wrapper, kj::mv(obj), kj::mv(metrics)); } WorkerEntrypoint::WorkerEntrypoint(kj::Badge badge, - ThreadContext& threadContext, - kj::TaskSet& waitUntilTasks, - bool tunnelExceptions, - kj::Maybe entrypointName, - kj::Maybe cfBlobJson) + ThreadContext& threadContext, + kj::TaskSet& waitUntilTasks, + bool tunnelExceptions, + kj::Maybe entrypointName, + kj::Maybe cfBlobJson) : threadContext(threadContext), waitUntilTasks(waitUntilTasks), tunnelExceptions(tunnelExceptions), entrypointName(entrypointName), cfBlobJson(kj::mv(cfBlobJson)) {} -void WorkerEntrypoint::init( - kj::Own worker, +void WorkerEntrypoint::init(kj::Own worker, kj::Maybe> actor, kj::Own limitEnforcer, kj::Own ioContextDependency, @@ -187,13 +190,10 @@ void WorkerEntrypoint::init( auto newContext = [&]() { TRACE_EVENT("workerd", "WorkerEntrypoint::init() create new IoContext"); - auto actorRef = actor.map([](kj::Own& ptr) -> Worker::Actor& { - return *ptr; - }); + auto actorRef = actor.map([](kj::Own& ptr) -> Worker::Actor& { return *ptr; }); - return kj::refcounted( - threadContext, kj::mv(worker), actorRef, kj::mv(limitEnforcer)) - .attach(kj::mv(ioContextDependency)); + return kj::refcounted(threadContext, kj::mv(worker), actorRef, kj::mv(limitEnforcer)) + .attach(kj::mv(ioContextDependency)); }; kj::Own context; @@ -209,18 +209,19 @@ void WorkerEntrypoint::init( } incomingRequest = kj::heap( - kj::mv(context), kj::mv(ioChannelFactory), kj::mv(metrics), - kj::mv(workerTracer)) - .attach(kj::mv(actor)); + kj::mv(context), kj::mv(ioChannelFactory), kj::mv(metrics), kj::mv(workerTracer)) + .attach(kj::mv(actor)); } -kj::Promise WorkerEntrypoint::request( - kj::HttpMethod method, kj::StringPtr url, const kj::HttpHeaders& headers, - kj::AsyncInputStream& requestBody, Response& response) { +kj::Promise WorkerEntrypoint::request(kj::HttpMethod method, + kj::StringPtr url, + const kj::HttpHeaders& headers, + kj::AsyncInputStream& requestBody, + Response& response) { TRACE_EVENT("workerd", "WorkerEntrypoint::request()", "url", url.cStr(), - PERFETTO_FLOW_FROM_POINTER(this)); - auto incomingRequest = kj::mv(KJ_REQUIRE_NONNULL(this->incomingRequest, - "request() can only be called once")); + PERFETTO_FLOW_FROM_POINTER(this)); + auto incomingRequest = + kj::mv(KJ_REQUIRE_NONNULL(this->incomingRequest, "request() can only be called once")); this->incomingRequest = kj::none; incomingRequest->delivered(); auto& context = incomingRequest->getContext(); @@ -245,80 +246,77 @@ kj::Promise WorkerEntrypoint::request( kj::TreeMap> traceHeaders; headers.forEach([&](kj::StringPtr name, kj::StringPtr value) { kj::String lower = api::toLower(name); - auto& slot = traceHeaders.findOrCreate(lower, - [&]() { return decltype(traceHeaders)::Entry {kj::mv(lower), {}}; }); + auto& slot = traceHeaders.findOrCreate( + lower, [&]() { return decltype(traceHeaders)::Entry{kj::mv(lower), {}}; }); slot.add(value); }); auto traceHeadersArray = KJ_MAP(entry, traceHeaders) { - return Trace::FetchEventInfo::Header(kj::mv(entry.key), - kj::strArray(entry.value, ", ")); + return Trace::FetchEventInfo::Header(kj::mv(entry.key), kj::strArray(entry.value, ", ")); }; - t.setEventInfo(timestamp, Trace::FetchEventInfo(method, kj::str(url), - kj::mv(cfJson), kj::mv(traceHeadersArray))); + t.setEventInfo(timestamp, + Trace::FetchEventInfo(method, kj::str(url), kj::mv(cfJson), kj::mv(traceHeadersArray))); } auto metricsForCatch = kj::addRef(incomingRequest->getMetrics()); auto metricsForProxyTask = kj::addRef(incomingRequest->getMetrics()); TRACE_EVENT_BEGIN("workerd", "WorkerEntrypoint::request() waiting on context", - PERFETTO_TRACK_FROM_POINTER(&context), - PERFETTO_FLOW_FROM_POINTER(this)); + PERFETTO_TRACK_FROM_POINTER(&context), PERFETTO_FLOW_FROM_POINTER(this)); - return context.run( - [this, &context, method, url, &headers, &requestBody, - &metrics = incomingRequest->getMetrics(), - &wrappedResponse = *wrappedResponse, entrypointName = entrypointName] - (Worker::Lock& lock) mutable { + return context + .run([this, &context, method, url, &headers, &requestBody, + &metrics = incomingRequest->getMetrics(), &wrappedResponse = *wrappedResponse, + entrypointName = entrypointName](Worker::Lock& lock) mutable { TRACE_EVENT_END("workerd", PERFETTO_TRACK_FROM_POINTER(&context)); - TRACE_EVENT("workerd", "WorkerEntrypoint::request() run", - PERFETTO_FLOW_FROM_POINTER(this)); + TRACE_EVENT("workerd", "WorkerEntrypoint::request() run", PERFETTO_FLOW_FROM_POINTER(this)); jsg::AsyncContextFrame::StorageScope traceScope = context.makeAsyncTraceScope(lock); - return lock.getGlobalScope().request( - method, url, headers, requestBody, wrappedResponse, + return lock.getGlobalScope().request(method, url, headers, requestBody, wrappedResponse, cfBlobJson, lock, lock.getExportedHandler(entrypointName, context.getActor())); - }).then([this](api::DeferredProxy deferredProxy) { + }) + .then([this](api::DeferredProxy deferredProxy) { TRACE_EVENT("workerd", "WorkerEntrypoint::request() deferred proxy step", - PERFETTO_FLOW_FROM_POINTER(this)); + PERFETTO_FLOW_FROM_POINTER(this)); proxyTask = kj::mv(deferredProxy.proxyTask); - }).exclusiveJoin(context.onAbort()) - .catch_([this,&context](kj::Exception&& exception) mutable -> kj::Promise { - TRACE_EVENT("workerd", "WorkerEntrypoint::request() catch", - PERFETTO_FLOW_FROM_POINTER(this)); + }) + .exclusiveJoin(context.onAbort()) + .catch_([this, &context](kj::Exception&& exception) mutable -> kj::Promise { + TRACE_EVENT("workerd", "WorkerEntrypoint::request() catch", PERFETTO_FLOW_FROM_POINTER(this)); // Log JS exceptions to the JS console, if fiddle is attached. This also has the effect of // logging internal errors to syslog. loggedExceptionEarlier = true; - context.logUncaughtExceptionAsync(UncaughtExceptionSource::REQUEST_HANDLER, - kj::cp(exception)); + context.logUncaughtExceptionAsync(UncaughtExceptionSource::REQUEST_HANDLER, kj::cp(exception)); // Do not allow the exception to escape the isolate without waiting for the output gate to // open. Note that in the success path, this is taken care of in `FetchEvent::respondWith()`. - return context.waitForOutputLocks() - .then([exception = kj::mv(exception), - flow=PERFETTO_TERMINATING_FLOW_FROM_POINTER(this)]() mutable - -> kj::Promise { + return context.waitForOutputLocks().then( + [exception = kj::mv(exception), + flow = PERFETTO_TERMINATING_FLOW_FROM_POINTER(this)]() mutable -> kj::Promise { TRACE_EVENT("workerd", "WorkerEntrypoint::request() after output lock wait", flow); return kj::mv(exception); }); - }).attach(kj::defer([this,incomingRequest = kj::mv(incomingRequest),&context]() mutable { + }) + .attach(kj::defer([this, incomingRequest = kj::mv(incomingRequest), &context]() mutable { // The request has been canceled, but allow it to continue executing in the background. if (context.isFailOpen()) { // Fail-open behavior has been chosen, we'd better save an interface that we can use for // that purpose later. - failOpenService = context.getSubrequestChannelNoChecks(IoContext::NEXT_CLIENT_CHANNEL, false, - kj::mv(cfBlobJson)); + failOpenService = context.getSubrequestChannelNoChecks( + IoContext::NEXT_CLIENT_CHANNEL, false, kj::mv(cfBlobJson)); } auto promise = incomingRequest->drain().attach(kj::mv(incomingRequest)); waitUntilTasks.add(maybeAddGcPassForTest(context, kj::mv(promise))); - })).then([this, metrics = kj::mv(metricsForProxyTask)]() mutable -> kj::Promise { + })) + .then([this, metrics = kj::mv(metricsForProxyTask)]() mutable -> kj::Promise { TRACE_EVENT("workerd", "WorkerEntrypoint::request() finish proxying", - PERFETTO_TERMINATING_FLOW_FROM_POINTER(this)); + PERFETTO_TERMINATING_FLOW_FROM_POINTER(this)); // Now that the IoContext is dropped (unless it had waitUntil()s), we can finish proxying // without pinning it or the isolate into memory. KJ_IF_SOME(p, proxyTask) { if (util::Autogate::isEnabled(util::AutogateKey::RESPONSE_STREAM_DISCONNECTED_STATUS)) { - return p.catch_([metrics = kj::mv(metrics)](kj::Exception&& e) mutable -> kj::Promise { + return p.catch_( + [metrics = kj::mv(metrics)](kj::Exception&& e) mutable -> kj::Promise { metrics->reportFailure(e, RequestObserver::FailureSource::DEFERRED_PROXY); return kj::mv(e); }); @@ -328,18 +326,20 @@ kj::Promise WorkerEntrypoint::request( } else { return kj::READY_NOW; } - }).attach(kj::defer([this]() mutable { + }) + .attach(kj::defer([this]() mutable { // If we're being cancelled, we need to make sure `proxyTask` gets canceled. proxyTask = kj::none; - })).catch_([this,wrappedResponse = kj::mv(wrappedResponse),isActor, - method, url, &headers, &requestBody, metrics = kj::mv(metricsForCatch)] - (kj::Exception&& exception) mutable -> kj::Promise { + })) + .catch_([this, wrappedResponse = kj::mv(wrappedResponse), isActor, method, url, &headers, + &requestBody, metrics = kj::mv(metricsForCatch)]( + kj::Exception&& exception) mutable -> kj::Promise { // Don't return errors to end user. TRACE_EVENT("workerd", "WorkerEntrypoint::request() exception", - PERFETTO_TERMINATING_FLOW_FROM_POINTER(this)); + PERFETTO_TERMINATING_FLOW_FROM_POINTER(this)); - auto isInternalException = !jsg::isTunneledException(exception.getDescription()) - && !jsg::isDoNotLogException(exception.getDescription()); + auto isInternalException = !jsg::isTunneledException(exception.getDescription()) && + !jsg::isDoNotLogException(exception.getDescription()); if (!loggedExceptionEarlier) { // This exception seems to have originated during the deferred proxy task, so it was not // logged to the IoContext earlier. @@ -356,8 +356,8 @@ kj::Promise WorkerEntrypoint::request( // due to an internal error. Note that this does not need to be labeled "remote." since jsg // will sanitize it as an internal error. Note that we use `setDescription()` to preserve // the exception type for `cjfs::makeInternalError(...)` downstream. - exception.setDescription(kj::str( - "worker_do_not_log; Request failed due to internal error")); + exception.setDescription( + kj::str("worker_do_not_log; Request failed due to internal error")); return kj::mv(exception); } else { // We do not care how many remote capnp servers this went through since we are returning @@ -373,7 +373,6 @@ kj::Promise WorkerEntrypoint::request( } return kj::mv(exception); } - }; if (wrappedResponse->isSent()) { @@ -395,14 +394,12 @@ kj::Promise WorkerEntrypoint::request( metrics->reportFailure(exception); auto promise = kj::evalNow([&] { - auto promise = service.get()->request( - method, url, headers, requestBody, *wrappedResponse); + auto promise = service.get()->request(method, url, headers, requestBody, *wrappedResponse); metrics->setFailedOpen(true); return promise.attach(kj::mv(service)); }); - return promise.catch_([this,wrappedResponse = kj::mv(wrappedResponse), - metrics = kj::mv(metrics)] - (kj::Exception&& e) mutable { + return promise.catch_([this, wrappedResponse = kj::mv(wrappedResponse), + metrics = kj::mv(metrics)](kj::Exception&& e) mutable { metrics->setFailedOpen(false); if (e.getType() != kj::Exception::Type::DISCONNECTED && // Avoid logging recognized external errors here, such as invalid headers returned from @@ -444,8 +441,10 @@ kj::Promise WorkerEntrypoint::request( }); } -kj::Promise WorkerEntrypoint::connect(kj::StringPtr host, const kj::HttpHeaders& headers, - kj::AsyncIoStream& connection, ConnectResponse& response, +kj::Promise WorkerEntrypoint::connect(kj::StringPtr host, + const kj::HttpHeaders& headers, + kj::AsyncIoStream& connection, + ConnectResponse& response, kj::HttpConnectSettings settings) { JSG_FAIL_REQUIRE(TypeError, "Incoming CONNECT on a worker not supported"); } @@ -453,8 +452,8 @@ kj::Promise WorkerEntrypoint::connect(kj::StringPtr host, const kj::HttpHe void WorkerEntrypoint::prewarm(kj::StringPtr url) { // Nothing to do, the worker is already loaded. TRACE_EVENT("workerd", "WorkerEntrypoint::prewarm()", "url", url.cStr()); - auto incomingRequest = kj::mv(KJ_REQUIRE_NONNULL(this->incomingRequest, - "prewarm() can only be called once")); + auto incomingRequest = + kj::mv(KJ_REQUIRE_NONNULL(this->incomingRequest, "prewarm() can only be called once")); incomingRequest->getMetrics().setIsPrewarm(); // Intentionally don't call incomingRequest->delivered() for prewarm requests. @@ -465,11 +464,10 @@ void WorkerEntrypoint::prewarm(kj::StringPtr url) { } kj::Promise WorkerEntrypoint::runScheduled( - kj::Date scheduledTime, - kj::StringPtr cron) { + kj::Date scheduledTime, kj::StringPtr cron) { TRACE_EVENT("workerd", "WorkerEntrypoint::runScheduled()"); - auto incomingRequest = kj::mv(KJ_REQUIRE_NONNULL(this->incomingRequest, - "runScheduled() can only be called once")); + auto incomingRequest = + kj::mv(KJ_REQUIRE_NONNULL(this->incomingRequest, "runScheduled() can only be called once")); this->incomingRequest = kj::none; incomingRequest->delivered(); auto& context = incomingRequest->getContext(); @@ -485,34 +483,33 @@ kj::Promise WorkerEntrypoint::runScheduled( } // Scheduled handlers run entirely in waitUntil() tasks. - context.addWaitUntil(context.run( - [scheduledTime, cron, entrypointName=entrypointName, &context, - &metrics = incomingRequest->getMetrics()] - (Worker::Lock& lock) mutable { + context.addWaitUntil( + context.run([scheduledTime, cron, entrypointName = entrypointName, &context, + &metrics = incomingRequest->getMetrics()](Worker::Lock& lock) mutable { TRACE_EVENT("workerd", "WorkerEntrypoint::runScheduled() run"); jsg::AsyncContextFrame::StorageScope traceScope = context.makeAsyncTraceScope(lock); - lock.getGlobalScope().startScheduled(scheduledTime, cron, lock, - lock.getExportedHandler(entrypointName, context.getActor())); + lock.getGlobalScope().startScheduled( + scheduledTime, cron, lock, lock.getExportedHandler(entrypointName, context.getActor())); })); static auto constexpr waitForFinished = [](IoContext& context, - kj::Own request) + kj::Own request) -> kj::Promise { TRACE_EVENT("workerd", "WorkerEntrypoint::runScheduled() waitForFinished()"); auto result = co_await request->finishScheduled(); bool completed = result == IoContext_IncomingRequest::FinishScheduledResult::COMPLETED; - co_return WorkerInterface::ScheduledResult { - .retry = context.shouldRetryScheduled(), - .outcome = completed ? context.waitUntilStatus() : EventOutcome::EXCEEDED_CPU - }; + co_return WorkerInterface::ScheduledResult{.retry = context.shouldRetryScheduled(), + .outcome = completed ? context.waitUntilStatus() : EventOutcome::EXCEEDED_CPU}; }; return maybeAddGcPassForTest(context, waitForFinished(context, kj::mv(incomingRequest))); } kj::Promise WorkerEntrypoint::runAlarmImpl( - kj::Own incomingRequest, kj::Date scheduledTime, uint32_t retryCount) { + kj::Own incomingRequest, + kj::Date scheduledTime, + uint32_t retryCount) { // We want to de-duplicate alarm requests as follows: // - An alarm must not be canceled once it is running, UNLESS the whole actor is shut down. // - If multiple alarm invocations arrive with the same scheduled time, we only run one. @@ -558,10 +555,10 @@ kj::Promise WorkerEntrypoint::runAlarmImpl( waitUntilTasks.add(incomingRequest->drain().attach(kj::mv(incomingRequest))); }); - try { - auto result = co_await context.run( - [scheduledTime, retryCount, entrypointName=entrypointName, &context](Worker::Lock& lock){ + auto result = + co_await context.run([scheduledTime, retryCount, entrypointName = entrypointName, + &context](Worker::Lock& lock) { jsg::AsyncContextFrame::StorageScope traceScope = context.makeAsyncTraceScope(lock); // If we have an invalid timeout, set it to the default value of 15 minutes. @@ -577,7 +574,7 @@ kj::Promise WorkerEntrypoint::runAlarmImpl( // The alarm handler was successfully complete. We must guarantee this same alarm does not // run again. - if (result.outcome == EventOutcome::OK){ + if (result.outcome == EventOutcome::OK) { // When an alarm handler completes its execution, the alarm is marked ready for deletion in // actor-cache. This alarm change will only be reflected in the alarmsXX table, once cache // flushes and changes are written to CRDB. @@ -612,8 +609,8 @@ kj::Promise WorkerEntrypoint::runAlarmImpl( kj::Promise WorkerEntrypoint::runAlarm( kj::Date scheduledTime, uint32_t retryCount) { TRACE_EVENT("workerd", "WorkerEntrypoint::runAlarm()"); - auto incomingRequest = kj::mv(KJ_REQUIRE_NONNULL(this->incomingRequest, - "runAlarm() can only be called once")); + auto incomingRequest = + kj::mv(KJ_REQUIRE_NONNULL(this->incomingRequest, "runAlarm() can only be called once")); this->incomingRequest = kj::none; auto& context = incomingRequest->getContext(); @@ -623,26 +620,26 @@ kj::Promise WorkerEntrypoint::runAlarm( kj::Promise WorkerEntrypoint::test() { TRACE_EVENT("workerd", "WorkerEntrypoint::test()"); - auto incomingRequest = kj::mv(KJ_REQUIRE_NONNULL(this->incomingRequest, - "test() can only be called once")); + auto incomingRequest = + kj::mv(KJ_REQUIRE_NONNULL(this->incomingRequest, "test() can only be called once")); this->incomingRequest = kj::none; incomingRequest->delivered(); auto& context = incomingRequest->getContext(); context.addWaitUntil(context.run( - [entrypointName=entrypointName, &context, &metrics = incomingRequest->getMetrics()] - (Worker::Lock& lock) mutable -> kj::Promise { + [entrypointName = entrypointName, &context, &metrics = incomingRequest->getMetrics()]( + Worker::Lock& lock) mutable -> kj::Promise { TRACE_EVENT("workerd", "WorkerEntrypoint::test() run"); jsg::AsyncContextFrame::StorageScope traceScope = context.makeAsyncTraceScope(lock); - return context.awaitJs(lock, lock.getGlobalScope() - .test(lock, lock.getExportedHandler(entrypointName, context.getActor()))); + return context.awaitJs(lock, + lock.getGlobalScope().test( + lock, lock.getExportedHandler(entrypointName, context.getActor()))); })); - static auto constexpr waitForFinished = [](IoContext& context, - kj::Own request) - -> kj::Promise { + static auto constexpr waitForFinished = + [](IoContext& context, kj::Own request) -> kj::Promise { TRACE_EVENT("workerd", "WorkerEntrypoint::test() waitForFinished()"); auto result = co_await request->finishScheduled(); bool completed = result == IoContext_IncomingRequest::FinishScheduledResult::COMPLETED; @@ -653,16 +650,16 @@ kj::Promise WorkerEntrypoint::test() { return maybeAddGcPassForTest(context, waitForFinished(context, kj::mv(incomingRequest))); } -kj::Promise - WorkerEntrypoint::customEvent(kj::Own event) { +kj::Promise WorkerEntrypoint::customEvent( + kj::Own event) { TRACE_EVENT("workerd", "WorkerEntrypoint::customEvent()", "type", event->getType()); - auto incomingRequest = kj::mv(KJ_REQUIRE_NONNULL(this->incomingRequest, - "customEvent() can only be called once")); + auto incomingRequest = + kj::mv(KJ_REQUIRE_NONNULL(this->incomingRequest, "customEvent() can only be called once")); this->incomingRequest = kj::none; auto& context = incomingRequest->getContext(); - auto promise = event->run(kj::mv(incomingRequest), entrypointName, waitUntilTasks) - .attach(kj::mv(event)); + auto promise = + event->run(kj::mv(incomingRequest), entrypointName, waitUntilTasks).attach(kj::mv(event)); // TODO(cleanup): In theory `context` may have been destroyed by now if `event->run()` dropped // the `incomingRequest` synchronously. No current implementation does that, and @@ -698,8 +695,7 @@ kj::Promise addGcPassForTest(IoContext& context, kj::Promise promise) { #endif template -kj::Promise WorkerEntrypoint::maybeAddGcPassForTest( - IoContext& context, kj::Promise promise) { +kj::Promise WorkerEntrypoint::maybeAddGcPassForTest(IoContext& context, kj::Promise promise) { #ifdef KJ_DEBUG if (isPredictableModeForTest()) { return addGcPassForTest(context, kj::mv(promise)); @@ -710,8 +706,7 @@ kj::Promise WorkerEntrypoint::maybeAddGcPassForTest( } // namespace -kj::Own newWorkerEntrypoint( - ThreadContext& threadContext, +kj::Own newWorkerEntrypoint(ThreadContext& threadContext, kj::Own worker, kj::Maybe entrypointName, kj::Maybe> actor, @@ -723,19 +718,9 @@ kj::Own newWorkerEntrypoint( bool tunnelExceptions, kj::Maybe> workerTracer, kj::Maybe cfBlobJson) { - return WorkerEntrypoint::construct( - threadContext, - kj::mv(worker), - kj::mv(entrypointName), - kj::mv(actor), - kj::mv(limitEnforcer), - kj::mv(ioContextDependency), - kj::mv(ioChannelFactory), - kj::mv(metrics), - waitUntilTasks, - tunnelExceptions, - kj::mv(workerTracer), - kj::mv(cfBlobJson)); + return WorkerEntrypoint::construct(threadContext, kj::mv(worker), kj::mv(entrypointName), + kj::mv(actor), kj::mv(limitEnforcer), kj::mv(ioContextDependency), kj::mv(ioChannelFactory), + kj::mv(metrics), waitUntilTasks, tunnelExceptions, kj::mv(workerTracer), kj::mv(cfBlobJson)); } -} // namespace workerd +} // namespace workerd diff --git a/src/workerd/io/worker-entrypoint.h b/src/workerd/io/worker-entrypoint.h index ef96d55e351..e5213e8d6e5 100644 --- a/src/workerd/io/worker-entrypoint.h +++ b/src/workerd/io/worker-entrypoint.h @@ -23,8 +23,7 @@ class WorkerTracer; // - Catching exceptions and converting them to HTTP error responses. // - Or, falling back to proxying if passThroughOnException() was used. // - Finish waitUntil() tasks. -kj::Own newWorkerEntrypoint( - ThreadContext& threadContext, +kj::Own newWorkerEntrypoint(ThreadContext& threadContext, kj::Own worker, kj::Maybe entrypointName, kj::Maybe> actor, @@ -37,4 +36,4 @@ kj::Own newWorkerEntrypoint( kj::Maybe> workerTracer, kj::Maybe cfBlobJson); -} // namespace workerd +} // namespace workerd diff --git a/src/workerd/io/worker-interface.c++ b/src/workerd/io/worker-interface.c++ index 4a487d5d5e6..dca82833254 100644 --- a/src/workerd/io/worker-interface.c++ +++ b/src/workerd/io/worker-interface.c++ @@ -15,16 +15,17 @@ namespace { // interface the promise resolved to. class PromisedWorkerInterface final: public kj::Refcounted, public WorkerInterface { public: - PromisedWorkerInterface(kj::TaskSet& waitUntilTasks, - kj::Promise> promise) + PromisedWorkerInterface( + kj::TaskSet& waitUntilTasks, kj::Promise> promise) : waitUntilTasks(waitUntilTasks), - promise(promise.then([this](kj::Own result) { - worker = kj::mv(result); - }).fork()) {} - - kj::Promise request( - kj::HttpMethod method, kj::StringPtr url, const kj::HttpHeaders& headers, - kj::AsyncInputStream& requestBody, Response& response) override { + promise(promise.then([this](kj::Own result) { worker = kj::mv(result); }) + .fork()) {} + + kj::Promise request(kj::HttpMethod method, + kj::StringPtr url, + const kj::HttpHeaders& headers, + kj::AsyncInputStream& requestBody, + Response& response) override { KJ_IF_SOME(w, worker) { co_await w.get()->request(method, url, headers, requestBody, response); } else { @@ -33,8 +34,10 @@ public: } } - kj::Promise connect(kj::StringPtr host, const kj::HttpHeaders& headers, - kj::AsyncIoStream& connection, ConnectResponse& response, + kj::Promise connect(kj::StringPtr host, + const kj::HttpHeaders& headers, + kj::AsyncIoStream& connection, + ConnectResponse& response, kj::HttpConnectSettings settings) override { KJ_IF_SOME(w, worker) { co_await w.get()->connect(host, headers, connection, response, kj::mv(settings)); @@ -50,10 +53,8 @@ public: w.get()->prewarm(url); } else { static auto constexpr handlePrewarm = - [](kj::Promise promise, - kj::String url, - kj::Own self) - -> kj::Promise { + [](kj::Promise promise, kj::String url, + kj::Own self) -> kj::Promise { co_await promise; KJ_ASSERT_NONNULL(self->worker)->prewarm(url); }; @@ -94,7 +95,7 @@ private: kj::ForkedPromise promise; kj::Maybe> worker; }; -} +} // namespace kj::Own newPromisedWorkerInterface( kj::TaskSet& waitUntilTasks, kj::Promise> promise) { @@ -111,14 +112,17 @@ namespace { class RevocableWebSocket final: public kj::WebSocket { public: RevocableWebSocket(kj::Own ws, kj::Promise revokeProm) - : ws(kj::mv(ws)), revokeProm(revokeProm.catch_([this](kj::Exception&& e) -> kj::Promise { - canceler.cancel(kj::cp(e)); - KJ_IF_SOME(ws, this->ws.tryGet>()) { - (ws)->abort(); - } - this->ws = kj::mv(e); - return kj::READY_NOW; - }).eagerlyEvaluate(nullptr)) {} + : ws(kj::mv(ws)), + revokeProm(revokeProm + .catch_([this](kj::Exception&& e) -> kj::Promise { + canceler.cancel(kj::cp(e)); + KJ_IF_SOME(ws, this->ws.tryGet>()) { + (ws)->abort(); + } + this->ws = kj::mv(e); + return kj::READY_NOW; + }) + .eagerlyEvaluate(nullptr)) {} kj::Promise send(kj::ArrayPtr message) override { return wrap(getInner().send(message)); @@ -163,11 +167,15 @@ public: return getInner().getPreferredExtensions(ctx); }; - uint64_t sentByteCount() override { return 0; } - uint64_t receivedByteCount() override { return 0; } + uint64_t sentByteCount() override { + return 0; + } + uint64_t receivedByteCount() override { + return 0; + } private: - template + template kj::Promise wrap(kj::Promise prom) { // just to fix the revocation promise return type, serves no purpose otherwise return canceler.wrap(kj::mv(prom)); @@ -192,13 +200,15 @@ private: // A HttpResponse that can revoke long-running websocket connections started as part of the // response. Ordinary HTTP requests are not revoked. -class RevocableWebSocketHttpResponse final : public kj::HttpService::Response { +class RevocableWebSocketHttpResponse final: public kj::HttpService::Response { public: RevocableWebSocketHttpResponse(kj::HttpService::Response& inner, kj::Promise revokeProm) - : inner(inner), revokeProm(revokeProm.fork()) {} + : inner(inner), + revokeProm(revokeProm.fork()) {} - kj::Own send( - uint statusCode, kj::StringPtr statusText, const kj::HttpHeaders& headers, + kj::Own send(uint statusCode, + kj::StringPtr statusText, + const kj::HttpHeaders& headers, kj::Maybe expectedBodySize = kj::none) override { return inner.send(statusCode, statusText, headers, expectedBodySize); } @@ -217,11 +227,15 @@ private: class RevocableWebSocketWorkerInterface final: public WorkerInterface { public: RevocableWebSocketWorkerInterface(WorkerInterface& worker, kj::Promise revokeProm); - kj::Promise request( - kj::HttpMethod method, kj::StringPtr url, const kj::HttpHeaders& headers, - kj::AsyncInputStream& requestBody, Response& response) override; - kj::Promise connect(kj::StringPtr host, const kj::HttpHeaders& headers, - kj::AsyncIoStream& connection, ConnectResponse& response, + kj::Promise request(kj::HttpMethod method, + kj::StringPtr url, + const kj::HttpHeaders& headers, + kj::AsyncInputStream& requestBody, + Response& response) override; + kj::Promise connect(kj::StringPtr host, + const kj::HttpHeaders& headers, + kj::AsyncIoStream& connection, + ConnectResponse& response, kj::HttpConnectSettings settings) override; void prewarm(kj::StringPtr url) override; kj::Promise runScheduled(kj::Date scheduledTime, kj::StringPtr cron) override; @@ -233,49 +247,54 @@ private: kj::ForkedPromise revokeProm; }; -kj::Promise RevocableWebSocketWorkerInterface::request( - kj::HttpMethod method, kj::StringPtr url, const kj::HttpHeaders& headers, - kj::AsyncInputStream& requestBody, kj::HttpService::Response& response) { +kj::Promise RevocableWebSocketWorkerInterface::request(kj::HttpMethod method, + kj::StringPtr url, + const kj::HttpHeaders& headers, + kj::AsyncInputStream& requestBody, + kj::HttpService::Response& response) { auto wrappedResponse = kj::heap(response, revokeProm.addBranch()); return worker.request(method, url, headers, requestBody, *wrappedResponse) .attach(kj::mv(wrappedResponse)); } -kj::Promise RevocableWebSocketWorkerInterface::connect(kj::StringPtr host, const kj::HttpHeaders& headers, - kj::AsyncIoStream& connection, ConnectResponse& response, +kj::Promise RevocableWebSocketWorkerInterface::connect(kj::StringPtr host, + const kj::HttpHeaders& headers, + kj::AsyncIoStream& connection, + ConnectResponse& response, kj::HttpConnectSettings settings) { - KJ_UNIMPLEMENTED("TODO(someday): RevocableWebSocketWorkerInterface::connect() should be implemented to " + KJ_UNIMPLEMENTED( + "TODO(someday): RevocableWebSocketWorkerInterface::connect() should be implemented to " "disconnect long-lived connections similar to how it treats WebSockets"); } -RevocableWebSocketWorkerInterface::RevocableWebSocketWorkerInterface(WorkerInterface& worker, - kj::Promise revokeProm) - : worker(worker), revokeProm(revokeProm.fork()) {} +RevocableWebSocketWorkerInterface::RevocableWebSocketWorkerInterface( + WorkerInterface& worker, kj::Promise revokeProm) + : worker(worker), + revokeProm(revokeProm.fork()) {} void RevocableWebSocketWorkerInterface::prewarm(kj::StringPtr url) { worker.prewarm(url); } kj::Promise RevocableWebSocketWorkerInterface::runScheduled( - kj::Date scheduledTime, - kj::StringPtr cron) { + kj::Date scheduledTime, kj::StringPtr cron) { return worker.runScheduled(scheduledTime, cron); } -kj::Promise RevocableWebSocketWorkerInterface::runAlarm(kj::Date scheduledTime, uint32_t retryCount) { +kj::Promise RevocableWebSocketWorkerInterface::runAlarm( + kj::Date scheduledTime, uint32_t retryCount) { return worker.runAlarm(scheduledTime, retryCount); } -kj::Promise - RevocableWebSocketWorkerInterface::customEvent(kj::Own event) { +kj::Promise RevocableWebSocketWorkerInterface::customEvent( + kj::Own event) { return worker.customEvent(kj::mv(event)); } } // namespace kj::Own newRevocableWebSocketWorkerInterface( - kj::Own worker, - kj::Promise revokeProm) { + kj::Own worker, kj::Promise revokeProm) { return kj::heap(*worker, kj::mv(revokeProm)) .attach(kj::mv(worker)); } @@ -288,14 +307,18 @@ class ErrorWorkerInterface final: public WorkerInterface { public: ErrorWorkerInterface(kj::Exception&& exception): exception(exception) {} - kj::Promise request( - kj::HttpMethod method, kj::StringPtr url, const kj::HttpHeaders& headers, - kj::AsyncInputStream& requestBody, Response& response) override { + kj::Promise request(kj::HttpMethod method, + kj::StringPtr url, + const kj::HttpHeaders& headers, + kj::AsyncInputStream& requestBody, + Response& response) override { kj::throwFatalException(kj::mv(exception)); } - kj::Promise connect(kj::StringPtr host, const kj::HttpHeaders& headers, - kj::AsyncIoStream& connection, ConnectResponse& response, + kj::Promise connect(kj::StringPtr host, + const kj::HttpHeaders& headers, + kj::AsyncIoStream& connection, + ConnectResponse& response, kj::HttpConnectSettings settings) override { kj::throwFatalException(kj::mv(exception)); } @@ -329,76 +352,74 @@ kj::Own WorkerInterface::fromException(kj::Exception&& e) { // ======================================================================================= RpcWorkerInterface::RpcWorkerInterface(capnp::HttpOverCapnpFactory& httpOverCapnpFactory, - capnp::ByteStreamFactory& byteStreamFactory, - kj::TaskSet& waitUntilTasks, - rpc::EventDispatcher::Client dispatcher) + capnp::ByteStreamFactory& byteStreamFactory, + kj::TaskSet& waitUntilTasks, + rpc::EventDispatcher::Client dispatcher) : httpOverCapnpFactory(httpOverCapnpFactory), byteStreamFactory(byteStreamFactory), waitUntilTasks(waitUntilTasks), dispatcher(kj::mv(dispatcher)) {} -kj::Promise RpcWorkerInterface::request( - kj::HttpMethod method, kj::StringPtr url, const kj::HttpHeaders& headers, - kj::AsyncInputStream& requestBody, Response& response) { +kj::Promise RpcWorkerInterface::request(kj::HttpMethod method, + kj::StringPtr url, + const kj::HttpHeaders& headers, + kj::AsyncInputStream& requestBody, + Response& response) { auto inner = httpOverCapnpFactory.capnpToKj(dispatcher.getHttpServiceRequest().send().getHttp()); auto promise = inner->request(method, url, headers, requestBody, response); return promise.attach(kj::mv(inner)); } -kj::Promise RpcWorkerInterface::connect( - kj::StringPtr host, const kj::HttpHeaders& headers, kj::AsyncIoStream& connection, - ConnectResponse& tunnel, kj::HttpConnectSettings settings) { +kj::Promise RpcWorkerInterface::connect(kj::StringPtr host, + const kj::HttpHeaders& headers, + kj::AsyncIoStream& connection, + ConnectResponse& tunnel, + kj::HttpConnectSettings settings) { auto inner = httpOverCapnpFactory.capnpToKj(dispatcher.getHttpServiceRequest().send().getHttp()); auto promise = inner->connect(host, headers, connection, tunnel, kj::mv(settings)); return promise.attach(kj::mv(inner)); } - void RpcWorkerInterface::prewarm(kj::StringPtr url) { - auto req = dispatcher.prewarmRequest( - capnp::MessageSize { url.size() / sizeof(capnp::word) + 4, 0 }); + auto req = dispatcher.prewarmRequest(capnp::MessageSize{url.size() / sizeof(capnp::word) + 4, 0}); req.setUrl(url); waitUntilTasks.add(req.send().ignoreResult()); } kj::Promise RpcWorkerInterface::runScheduled( - kj::Date scheduledTime, - kj::StringPtr cron) { + kj::Date scheduledTime, kj::StringPtr cron) { auto req = dispatcher.runScheduledRequest(); req.setScheduledTime((scheduledTime - kj::UNIX_EPOCH) / kj::SECONDS); req.setCron(cron); return req.send().then([](auto resp) { auto respResult = resp.getResult(); - return WorkerInterface::ScheduledResult { - .retry = respResult.getRetry(), - .outcome = respResult.getOutcome() - }; + return WorkerInterface::ScheduledResult{ + .retry = respResult.getRetry(), .outcome = respResult.getOutcome()}; }); } -kj::Promise RpcWorkerInterface::runAlarm(kj::Date scheduledTime, uint32_t retryCount) { +kj::Promise RpcWorkerInterface::runAlarm( + kj::Date scheduledTime, uint32_t retryCount) { auto req = dispatcher.runAlarmRequest(); req.setScheduledTime((scheduledTime - kj::UNIX_EPOCH) / kj::MILLISECONDS); req.setRetryCount(retryCount); return req.send().then([](auto resp) { auto respResult = resp.getResult(); - return WorkerInterface::AlarmResult { - .retry = respResult.getRetry(), + return WorkerInterface::AlarmResult{.retry = respResult.getRetry(), .retryCountsAgainstLimit = respResult.getRetryCountsAgainstLimit(), - .outcome = respResult.getOutcome() - }; + .outcome = respResult.getOutcome()}; }); } -kj::Promise - RpcWorkerInterface::customEvent(kj::Own event) { +kj::Promise RpcWorkerInterface::customEvent( + kj::Own event) { return event->sendRpc(httpOverCapnpFactory, byteStreamFactory, waitUntilTasks, dispatcher); } // ====================================================================================== WorkerInterface::AlarmFulfiller::AlarmFulfiller( kj::Own> fulfiller) - : maybeFulfiller(kj::mv(fulfiller)) {} + : maybeFulfiller(kj::mv(fulfiller)) {} WorkerInterface::AlarmFulfiller::~AlarmFulfiller() noexcept(false) { KJ_IF_SOME(fulfiller, getFulfiller()) { @@ -427,8 +448,8 @@ void WorkerInterface::AlarmFulfiller::cancel() { } } -kj::Maybe&> -WorkerInterface::AlarmFulfiller::getFulfiller() { +kj::Maybe&> WorkerInterface::AlarmFulfiller:: + getFulfiller() { KJ_IF_SOME(fulfiller, maybeFulfiller) { if (fulfiller.get()->isWaiting()) { return *fulfiller; @@ -438,5 +459,4 @@ WorkerInterface::AlarmFulfiller::getFulfiller() { return kj::none; } -} // namespace workerd - +} // namespace workerd diff --git a/src/workerd/io/worker-interface.h b/src/workerd/io/worker-interface.h index 03e10c5055c..d07a5c8cd92 100644 --- a/src/workerd/io/worker-interface.h +++ b/src/workerd/io/worker-interface.h @@ -22,9 +22,11 @@ class WorkerInterface: public kj::HttpService { // Make an HTTP request. (This method is inherited from HttpService, but re-declared here for // visibility.) - virtual kj::Promise request( - kj::HttpMethod method, kj::StringPtr url, const kj::HttpHeaders& headers, - kj::AsyncInputStream& requestBody, kj::HttpService::Response& response) = 0; + virtual kj::Promise request(kj::HttpMethod method, + kj::StringPtr url, + const kj::HttpHeaders& headers, + kj::AsyncInputStream& requestBody, + kj::HttpService::Response& response) = 0; // TODO(perf): Consider changing this to return Promise. This would allow // more resources to be dropped when merely proxying a request. However, it means we would no // longer be immplementing kj::HttpService. But maybe that doesn't matter too much in practice. @@ -33,10 +35,10 @@ class WorkerInterface: public kj::HttpService { // pure-virtual to force all subclasses of WorkerInterface to implement it explicitly rather // than get the default implementation which throws an unimplemented exception. virtual kj::Promise connect(kj::StringPtr host, - const kj::HttpHeaders& headers, - kj::AsyncIoStream& connection, - ConnectResponse& response, - kj::HttpConnectSettings settings) = 0; + const kj::HttpHeaders& headers, + kj::AsyncIoStream& connection, + ConnectResponse& response, + kj::HttpConnectSettings settings) = 0; // Hints that this worker will likely be invoked in the near future, so should be warmed up now. // This method should also call `prewarm()` on any subsequent pipeline stages that are expected @@ -86,13 +88,15 @@ class WorkerInterface: public kj::HttpService { // passed or failed. In the case of a failure, information should have already been written to // stderr and to the devtools; there is no need for the caller to write anything further. (If the // promise rejects, this indicates a bug in the test harness itself.) - virtual kj::Promise test() { return nullptr; } + virtual kj::Promise test() { + return nullptr; + } // TODO(someday): Produce a structured test report? // These two constants are shared by multiple systems that invoke alarms (the production // implementation, and the preview implementation), whose code live in completely different // places. We end up defining them here mostly for lack of a better option. - static constexpr auto ALARM_RETRY_START_SECONDS = 2; // not a duration so we can left shift it + static constexpr auto ALARM_RETRY_START_SECONDS = 2; // not a duration so we can left shift it static constexpr auto ALARM_RETRY_MAX_TRIES = 6; class CustomEvent { @@ -104,14 +108,12 @@ class WorkerInterface: public kj::HttpService { // Deliver the event to an isolate in this process. `incomingRequest` has been newly-allocated // for this event. - virtual kj::Promise run( - kj::Own incomingRequest, + virtual kj::Promise run(kj::Own incomingRequest, kj::Maybe entrypointName, kj::TaskSet& waitUntilTasks) = 0; // Forward the event over RPC. - virtual kj::Promise sendRpc( - capnp::HttpOverCapnpFactory& httpOverCapnpFactory, + virtual kj::Promise sendRpc(capnp::HttpOverCapnpFactory& httpOverCapnpFactory, capnp::ByteStreamFactory& byteStreamFactory, kj::TaskSet& waitUntilTasks, rpc::EventDispatcher::Client dispatcher) = 0; @@ -135,7 +137,8 @@ class WorkerInterface: public kj::HttpService { // immediately; if its callbacks have not run yet, they will not run at all. So, a CustomEvent // implementation can hold references to objects it doesn't own as long as the returned promise // will be canceled before those objects go away. - [[nodiscard]] virtual kj::Promise customEvent(kj::Own event) = 0; + [[nodiscard]] virtual kj::Promise customEvent( + kj::Own event) = 0; private: kj::Maybe> adapterService; @@ -156,8 +159,7 @@ kj::Own asHttpClient(kj::Own workerInterface); // A WorkerInterface that cancels WebSockets when revokeProm is rejected. // Currently only supports cancelling for upgrades. kj::Own newRevocableWebSocketWorkerInterface( - kj::Own worker, - kj::Promise revokeProm); + kj::Own worker, kj::Promise revokeProm); // Implementation of WorkerInterface on top of rpc::EventDispatcher. Since an EventDispatcher // is intended to be single-use, this class is also inherently single-use (i.e. only one event @@ -165,17 +167,21 @@ kj::Own newRevocableWebSocketWorkerInterface( class RpcWorkerInterface: public WorkerInterface { public: RpcWorkerInterface(capnp::HttpOverCapnpFactory& httpOverCapnpFactory, - capnp::ByteStreamFactory& byteStreamFactory, - kj::TaskSet& waitUntilTasks, - rpc::EventDispatcher::Client dispatcher); - - kj::Promise request( - kj::HttpMethod method, kj::StringPtr url, const kj::HttpHeaders& headers, - kj::AsyncInputStream& requestBody, Response& response) override; - - kj::Promise connect( - kj::StringPtr host, const kj::HttpHeaders& headers, kj::AsyncIoStream& connection, - ConnectResponse& tunnel, kj::HttpConnectSettings settings) override; + capnp::ByteStreamFactory& byteStreamFactory, + kj::TaskSet& waitUntilTasks, + rpc::EventDispatcher::Client dispatcher); + + kj::Promise request(kj::HttpMethod method, + kj::StringPtr url, + const kj::HttpHeaders& headers, + kj::AsyncInputStream& requestBody, + Response& response) override; + + kj::Promise connect(kj::StringPtr host, + const kj::HttpHeaders& headers, + kj::AsyncIoStream& connection, + ConnectResponse& tunnel, + kj::HttpConnectSettings settings) override; void prewarm(kj::StringPtr url) override; kj::Promise runScheduled(kj::Date scheduledTime, kj::StringPtr cron) override; @@ -189,4 +195,4 @@ class RpcWorkerInterface: public WorkerInterface { rpc::EventDispatcher::Client dispatcher; }; -} // namespace workerd +} // namespace workerd diff --git a/src/workerd/io/worker.c++ b/src/workerd/io/worker.c++ index 8779699daa4..9dac1999315 100644 --- a/src/workerd/io/worker.c++ +++ b/src/workerd/io/worker.c++ @@ -125,20 +125,19 @@ using ExceptionOrDuration = kj::OneOf; // Passes `source` as the exception's short message. Reconstructs `message` from `exception` if // `message` is empty. void sendExceptionToInspector(jsg::Lock& js, - v8_inspector::V8Inspector& inspector, - UncaughtExceptionSource source, - const jsg::JsValue& exception, - jsg::JsMessage message) { + v8_inspector::V8Inspector& inspector, + UncaughtExceptionSource source, + const jsg::JsValue& exception, + jsg::JsMessage message) { jsg::sendExceptionToInspector(js, inspector, kj::str(source), exception, message); } void addExceptionToTrace(jsg::Lock& js, - IoContext &ioContext, - WorkerTracer& tracer, - UncaughtExceptionSource source, - const jsg::JsValue& exception, - const jsg::TypeHandler& - errorTypeHandler) { + IoContext& ioContext, + WorkerTracer& tracer, + UncaughtExceptionSource source, + const jsg::JsValue& exception, + const jsg::TypeHandler& errorTypeHandler) { if (source == UncaughtExceptionSource::INTERNAL || source == UncaughtExceptionSource::INTERNAL_ASYNC) { // Skip redundant intermediate JS->C++ exception reporting. See: IoContext::runImpl(), @@ -213,8 +212,7 @@ void addExceptionToTrace(jsg::Lock& js, tracer.addException(timestamp, kj::mv(name), kj::mv(message), kj::mv(stack)); } -void reportStartupError( - kj::StringPtr id, +void reportStartupError(kj::StringPtr id, jsg::Lock& js, const kj::Maybe>& inspector, const IsolateLimitEnforcer& limitEnforcer, @@ -256,18 +254,17 @@ void reportStartupError( auto limitScope = limitEnforcer.enterLoggingJs(js, limitErrorOrTime2); kj::Vector lines; - lines.add(kj::str("Uncaught ", jsg::extractTunneledExceptionDescription( - KJ_ASSERT_NONNULL(permanentException).getDescription()))); + lines.add(kj::str("Uncaught ", + jsg::extractTunneledExceptionDescription( + KJ_ASSERT_NONNULL(permanentException).getDescription()))); jsg::JsMessage message(catcher.Message()); message.addJsStackTrace(js, lines); e.addError(kj::strArray(lines, "\n")); } else KJ_IF_SOME(i, inspector) { auto limitScope = limitEnforcer.enterLoggingJs(js, limitErrorOrTime2); - sendExceptionToInspector(js, *i.get(), - UncaughtExceptionSource::INTERNAL, - jsg::JsValue(exception), - jsg::JsMessage(catcher.Message())); + sendExceptionToInspector(js, *i.get(), UncaughtExceptionSource::INTERNAL, + jsg::JsValue(exception), jsg::JsMessage(catcher.Message())); // When the inspector is active, we don't want to throw here because then the inspector // won't be able to connect and the developer will never know what happened. } else { @@ -288,11 +285,11 @@ void reportStartupError( } } } catch (const jsg::JsExceptionThrown&) { -#define LOG_AND_SET_PERM_EXCEPTION(...) \ - KJ_LOG(ERROR, __VA_ARGS__); \ - if (permanentException == kj::none) { \ - permanentException = KJ_EXCEPTION(FAILED, __VA_ARGS__); \ - } +#define LOG_AND_SET_PERM_EXCEPTION(...) \ + KJ_LOG(ERROR, __VA_ARGS__); \ + if (permanentException == kj::none) { \ + permanentException = KJ_EXCEPTION(FAILED, __VA_ARGS__); \ + } KJ_SWITCH_ONEOF(limitErrorOrTime2) { KJ_CASE_ONEOF(limitError2, kj::Exception) { @@ -307,11 +304,13 @@ void reportStartupError( if (catcher2.HasTerminated()) { LOG_AND_SET_PERM_EXCEPTION( "script startup threw exception; during our attempt to stringify the exception, " - "the script apparently was terminated for non-resource-limit reasons.", id); + "the script apparently was terminated for non-resource-limit reasons.", + id); } else { LOG_AND_SET_PERM_EXCEPTION( "script startup threw exception; furthermore, an attempt to stringify the exception " - "threw another exception, which shouldn't be possible?", id); + "threw another exception, which shouldn't be possible?", + id); } } } @@ -389,8 +388,8 @@ public: KJ_IF_SOME(info, lockedState->inspectorTimerInfo) { if (info.threadId == getCurrentThreadId()) { // We're on an inspector-serving thread. - timePoint = info.timer.now() + info.timerOffset - - kj::origin() + kj::UNIX_EPOCH; + timePoint = + info.timer.now() + info.timerOffset - kj::origin() + kj::UNIX_EPOCH; } } // We're at script startup time -- just return the Epoch. @@ -400,7 +399,7 @@ public: void setInspectorTimerInfo(kj::Timer& timer, kj::Duration timerOffset) { auto lockedState = state.lockExclusive(); - lockedState->inspectorTimerInfo = InspectorTimerInfo { timer, timerOffset, getCurrentThreadId() }; + lockedState->inspectorTimerInfo = InspectorTimerInfo{timer, timerOffset, getCurrentThreadId()}; } void setChannel(Worker::Isolate::InspectorChannelImpl& channel) { @@ -531,11 +530,10 @@ struct Worker::Isolate::Impl { class Lock { public: - explicit Lock(const Worker::Isolate& isolate, Worker::LockType lockType, - jsg::V8StackScope& stackScope) + explicit Lock( + const Worker::Isolate& isolate, Worker::LockType lockType, jsg::V8StackScope& stackScope) : impl(*isolate.impl), - metrics([&isolate, &lockType]() - -> kj::Maybe> { + metrics([&isolate, &lockType]() -> kj::Maybe> { KJ_SWITCH_ONEOF(lockType.origin) { KJ_CASE_ONEOF(sync, Worker::Lock::TakeSynchronously) { // TODO(perf): We could do some tracking here to discover overly harmful synchronous @@ -601,8 +599,8 @@ struct Worker::Isolate::Impl { // The V8Inspector implements the `console` object. KJ_IF_SOME(i, impl.inspector) { - i.get()->contextCreated(v8_inspector::V8ContextInfo(context, 1, - jsg::toInspectorStringView("Worker"))); + i.get()->contextCreated( + v8_inspector::V8ContextInfo(context, 1, jsg::toInspectorStringView("Worker"))); } // We replace the default V8 console.log(), etc. methods, to give the worker access to @@ -615,11 +613,11 @@ struct Worker::Isolate::Impl { auto setHandler = [&](const char* method, LogLevel level) { auto methodStr = jsg::v8StrIntern(lock->v8Isolate, method); v8::Global original( - lock->v8Isolate, jsg::check(console->Get(context, methodStr)).As()); + lock->v8Isolate, jsg::check(console->Get(context, methodStr)).As()); auto f = lock->wrapSimpleFunction(context, - [mode, level, original = kj::mv(original)](jsg::Lock& js, - const v8::FunctionCallbackInfo& info) { + [mode, level, original = kj::mv(original)]( + jsg::Lock& js, const v8::FunctionCallbackInfo& info) { handleLog(js, mode, level, original, info); }); jsg::check(console->Set(context, methodStr, f)); @@ -684,17 +682,17 @@ struct Worker::Isolate::Impl { // destructor if it owns the last `kj::Own` reference. // // Fairly obviously, this member is protected by its own mutex, not the isolate lock. - const kj::MutexGuarded>> workerDestructionQueue { - WORKER_DESTRUCTION_QUEUE_INITIAL_SIZE, - WORKER_DESTRUCTION_QUEUE_MAX_CAPACITY - }; + const kj::MutexGuarded>> workerDestructionQueue{ + WORKER_DESTRUCTION_QUEUE_INITIAL_SIZE, WORKER_DESTRUCTION_QUEUE_MAX_CAPACITY}; // TODO(cleanup): The only reason this exists and we can't just rely on the isolate's regular // deferred destruction queue to lazily destroy the various V8 objects in Worker::Impl is // because our GlobalScope object needs to have a function called on it, and any attached // inspector needs to be notified. JSG doesn't know about these things. - Impl(const Api& api, IsolateObserver& metrics, - IsolateLimitEnforcer& limitEnforcer, InspectorPolicy inspectorPolicy) + Impl(const Api& api, + IsolateObserver& metrics, + IsolateLimitEnforcer& limitEnforcer, + InspectorPolicy inspectorPolicy) : metrics(metrics), inspectorPolicy(inspectorPolicy), actorCacheLru(limitEnforcer.getActorCacheLruOptions()) { @@ -722,7 +720,7 @@ public: static const CpuProfilerDisposer instance; }; -const CpuProfilerDisposer CpuProfilerDisposer::instance {}; +const CpuProfilerDisposer CpuProfilerDisposer::instance{}; static constexpr kj::StringPtr PROFILE_NAME = "Default Profile"_kj; @@ -733,19 +731,15 @@ static void setSamplingInterval(v8::CpuProfiler& profiler, int interval) { static void startProfiling(jsg::Lock& js, v8::CpuProfiler& profiler) { js.withinHandleScope([&] { v8::CpuProfilingOptions options( - v8::kLeafNodeLineNumbers, - v8::CpuProfilingOptions::kNoSampleLimit - ); + v8::kLeafNodeLineNumbers, v8::CpuProfilingOptions::kNoSampleLimit); profiler.StartProfiling(jsg::v8StrIntern(js.v8Isolate, PROFILE_NAME), kj::mv(options)); }); } -static void stopProfiling(jsg::Lock& js, - v8::CpuProfiler& profiler, - cdp::Command::Builder& cmd) { +static void stopProfiling(jsg::Lock& js, v8::CpuProfiler& profiler, cdp::Command::Builder& cmd) { js.withinHandleScope([&] { auto cpuProfile = profiler.StopProfiling(jsg::v8StrIntern(js.v8Isolate, PROFILE_NAME)); - if (cpuProfile == nullptr) return; // profiling never started + if (cpuProfile == nullptr) return; // profiling never started kj::Vector allNodes; kj::Vector unvisited; @@ -755,7 +749,7 @@ static void stopProfiling(jsg::Lock& js, auto next = unvisited.back(); allNodes.add(next); unvisited.removeLast(); - for (int i=0; i < next->GetChildrenCount(); i++) { + for (int i = 0; i < next->GetChildrenCount(); i++) { unvisited.add(next->GetChild(i)); } } @@ -766,7 +760,7 @@ static void stopProfiling(jsg::Lock& js, profile.setEndTime(cpuProfile->GetEndTime()); auto nodes = profile.initNodes(allNodes.size()); - for (auto i : kj::indices(allNodes)) { + for (auto i: kj::indices(allNodes)) { auto nodeBuilder = nodes[i]; nodeBuilder.setId(allNodes[i]->GetNodeId()); @@ -781,7 +775,7 @@ static void stopProfiling(jsg::Lock& js, nodeBuilder.setHitCount(allNodes[i]->GetHitCount()); auto children = nodeBuilder.initChildren(allNodes[i]->GetChildrenCount()); - for (int j=0; j < allNodes[i]->GetChildrenCount(); j++) { + for (int j = 0; j < allNodes[i]->GetChildrenCount(); j++) { children.set(j, allNodes[i]->GetChild(j)->GetNodeId()); } @@ -790,7 +784,7 @@ static void stopProfiling(jsg::Lock& js, allNodes[i]->GetLineTicks(lineBuffer.begin(), lineBuffer.size()); auto positionTicks = nodeBuilder.initPositionTicks(hitLineCount); - for (uint j=0; j < hitLineCount; j++) { + for (uint j = 0; j < hitLineCount; j++) { auto positionTick = positionTicks[j]; positionTick.setLine(lineBuffer[j].line); positionTick.setTicks(lineBuffer[j].hit_count); @@ -801,7 +795,7 @@ static void stopProfiling(jsg::Lock& js, auto samples = profile.initSamples(sampleCount); auto timeDeltas = profile.initTimeDeltas(sampleCount); auto lastTimestamp = cpuProfile->GetStartTime(); - for (int i=0; i < sampleCount; i++) { + for (int i = 0; i < sampleCount; i++) { samples.set(i, cpuProfile->GetSample(i)->GetNodeId()); auto sampleTime = cpuProfile->GetSampleTimestamp(i); timeDeltas.set(i, sampleTime - lastTimestamp); @@ -810,7 +804,7 @@ static void stopProfiling(jsg::Lock& js, }); } -} // anonymous namespace +} // anonymous namespace struct Worker::Script::Impl { kj::OneOf unboundScriptOrMainModule; @@ -826,22 +820,21 @@ struct Worker::Script::Impl { jsg::Value value; bool isException = false; DynamicImportResult(jsg::Value value, bool isException = false) - : value(kj::mv(value)), isException(isException) {} + : value(kj::mv(value)), + isException(isException) {} }; using DynamicImportHandler = kj::Function; void configureDynamicImports(jsg::Lock& js, jsg::ModuleRegistry& modules) { static auto constexpr handleDynamicImport = - [](kj::Own worker, - DynamicImportHandler handler, - kj::Maybe> asyncContext) -> - kj::Promise { + [](kj::Own worker, DynamicImportHandler handler, + kj::Maybe> asyncContext) + -> kj::Promise { co_await kj::yield(); auto asyncLock = co_await worker->takeAsyncLockWithoutRequest(nullptr); co_return worker->runInLockScope(asyncLock, [&](Worker::Lock& lock) { - return JSG_WITHIN_CONTEXT_SCOPE(lock, lock.getContext(), - [&](jsg::Lock& js) { + return JSG_WITHIN_CONTEXT_SCOPE(lock, lock.getContext(), [&](jsg::Lock& js) { jsg::AsyncContextFrame::Scope asyncContextScope(js, asyncContext); // We have to wrap the call to handler in a try catch here because @@ -849,8 +842,8 @@ struct Worker::Script::Impl { v8::TryCatch tryCatch(js.v8Isolate); ExceptionOrDuration limitErrorOrTime = 0 * kj::NANOSECONDS; try { - auto limitScope = worker->getIsolate().getLimitEnforcer() - .enterDynamicImportJs(lock, limitErrorOrTime); + auto limitScope = worker->getIsolate().getLimitEnforcer().enterDynamicImportJs( + lock, limitErrorOrTime); return DynamicImportResult(handler()); } catch (jsg::JsExceptionThrown&) { // Handled below... @@ -866,8 +859,8 @@ struct Worker::Script::Impl { kj::throwFatalException(kj::mv(limitError)); } KJ_CASE_ONEOF_DEFAULT { - kj::throwFatalException(JSG_KJ_EXCEPTION(FAILED, Error, - "Failed to load dynamic module.")); + kj::throwFatalException( + JSG_KJ_EXCEPTION(FAILED, Error, "Failed to load dynamic module.")); } } } @@ -884,9 +877,8 @@ struct Worker::Script::Impl { auto& context = IoContext::current(); return context.awaitIo(js, - handleDynamicImport(kj::atomicAddRef(context.getWorker()), - kj::mv(handler), - jsg::AsyncContextFrame::currentRef(js)), + handleDynamicImport(kj::atomicAddRef(context.getWorker()), kj::mv(handler), + jsg::AsyncContextFrame::currentRef(js)), [](jsg::Lock& js, DynamicImportResult result) { if (result.isException) { return js.rejectedPromise(kj::mv(result.value)); @@ -963,8 +955,7 @@ kj::Maybe makeCompatJson(kj::ArrayPtr enableFlags) { // be held on the Promise itself, and will be fulfilled/rejected when the // promise is resolved or rejected. This will signal all of the waiters // from other IoContexts. -jsg::Promise addCrossThreadPromiseWaiter(jsg::Lock& js, - v8::Local& promise) { +jsg::Promise addCrossThreadPromiseWaiter(jsg::Lock& js, v8::Local& promise) { auto waiter = kj::newPromiseAndCrossThreadFulfiller(); struct Waiter: public kj::Refcounted { @@ -983,13 +974,11 @@ jsg::Promise addCrossThreadPromiseWaiter(jsg::Lock& js, auto fulfiller = kj::refcounted(kj::mv(waiter.fulfiller)); - auto onSuccess = [waiter=kj::addRef(*fulfiller)](jsg::Lock& js, jsg::Value value) mutable { - waiter->done(); - }; + auto onSuccess = [waiter = kj::addRef(*fulfiller)]( + jsg::Lock& js, jsg::Value value) mutable { waiter->done(); }; - auto onFailure = [waiter=kj::mv(fulfiller)](jsg::Lock& js, jsg::Value exception) mutable { - waiter->done(); - }; + auto onFailure = [waiter = kj::mv(fulfiller)]( + jsg::Lock& js, jsg::Value exception) mutable { waiter->done(); }; js.toPromise(promise).then(js, kj::mv(onSuccess), kj::mv(onFailure)); @@ -1008,11 +997,11 @@ const HeapSnapshotDeleter HeapSnapshotDeleter::INSTANCE; } // namespace Worker::Isolate::Isolate(kj::Own apiParam, - kj::Own&& metricsParam, - kj::StringPtr id, - kj::Own limitEnforcerParam, - InspectorPolicy inspectorPolicy, - ConsoleMode consoleMode) + kj::Own&& metricsParam, + kj::StringPtr id, + kj::Own limitEnforcerParam, + InspectorPolicy inspectorPolicy, + ConsoleMode consoleMode) : id(kj::str(id)), limitEnforcer(kj::mv(limitEnforcerParam)), api(kj::mv(apiParam)), @@ -1046,15 +1035,13 @@ Worker::Isolate::Isolate(kj::Own apiParam, KJ_LOG(INFO, "console warning", message); }); lock->setErrorReporterCallback([this](jsg::Lock& js, kj::String desc, - const jsg::JsValue& error, - const jsg::JsMessage& message) { + const jsg::JsValue& error, const jsg::JsMessage& message) { // Only add exception to trace when running within an I/O context with a tracer. if (IoContext::hasCurrent()) { auto& ioContext = IoContext::current(); KJ_IF_SOME(tracer, ioContext.getWorkerTracer()) { - addExceptionToTrace(js, ioContext, tracer, - UncaughtExceptionSource::REQUEST_HANDLER, error, - api->getErrorInterfaceTypeHandler(js)); + addExceptionToTrace(js, ioContext, tracer, UncaughtExceptionSource::REQUEST_HANDLER, + error, api->getErrorInterfaceTypeHandler(js)); } } @@ -1120,10 +1107,9 @@ Worker::Isolate::Isolate(kj::Own apiParam, // our patched v8 logic will check to see if the followed promise's tag matches the // current Isolate tag. If they do not, then v8 will invoke this callback. The promise // here is the promise that belongs to a different IoContext. - lock->v8Isolate->SetPromiseCrossContextCallback([](v8::Local context, - v8::Local promise, - v8::Local tag) -> - v8::MaybeLocal { + lock->v8Isolate->SetPromiseCrossContextCallback( + [](v8::Local context, v8::Local promise, + v8::Local tag) -> v8::MaybeLocal { try { auto& js = jsg::Lock::from(context->GetIsolate()); @@ -1133,8 +1119,9 @@ Worker::Isolate::Isolate(kj::Own apiParam, "Unable to wait on a promise created within a request when not running within a " "request."); - return js.wrapSimplePromise(addCrossThreadPromiseWaiter(js, promise).then(js, - [promise=js.v8Ref(promise.As())](auto& js) mutable { + return js.wrapSimplePromise( + addCrossThreadPromiseWaiter(js, promise) + .then(js, [promise = js.v8Ref(promise.As())](auto& js) mutable { // Once the waiter has been resolved, return the now settled promise. // Since the promise has been settled, it is now safe to access from // other requests. Note that the resolved value of the promise still @@ -1157,9 +1144,12 @@ Worker::Isolate::Isolate(kj::Own apiParam, }); } -Worker::Script::Script(kj::Own isolateParam, kj::StringPtr id, - Script::Source source, IsolateObserver::StartType startType, - bool logNewScript, kj::Maybe errorReporter) +Worker::Script::Script(kj::Own isolateParam, + kj::StringPtr id, + Script::Source source, + IsolateObserver::StartType startType, + bool logNewScript, + kj::Maybe errorReporter) : isolate(kj::mv(isolateParam)), id(kj::str(id)), modular(source.is()), @@ -1172,8 +1162,8 @@ Worker::Script::Script(kj::Own isolateParam, kj::StringPtr id, // isolate, we may wish to make the RequestObserver object available here, in order to // attribute lock timing to that request. jsg::runInV8Stack([&](jsg::V8StackScope& stackScope) { - Isolate::Impl::Lock recordedLock(*isolate, - Worker::Lock::TakeSynchronously(kj::none), stackScope); + Isolate::Impl::Lock recordedLock( + *isolate, Worker::Lock::TakeSynchronously(kj::none), stackScope); auto& lock = *recordedLock.lock; // If we throw an exception, it's important that `impl` is destroyed under lock. @@ -1202,8 +1192,8 @@ Worker::Script::Script(kj::Own isolateParam, kj::StringPtr id, // Although we're going to compile a script independent of context, V8 requires that there be // an active context, otherwise it will segfault, I guess. So we create a dummy context. // (Undocumented, as usual.) - context = v8::Context::New( - lock.v8Isolate, nullptr, v8::ObjectTemplate::New(lock.v8Isolate)); + context = + v8::Context::New(lock.v8Isolate, nullptr, v8::ObjectTemplate::New(lock.v8Isolate)); } JSG_WITHIN_CONTEXT_SCOPE(lock, context, [&](jsg::Lock& js) { @@ -1215,8 +1205,8 @@ Worker::Script::Script(kj::Own isolateParam, kj::StringPtr id, // inspector is enabled. We want to do this immediately after the context is created, // before the user gets a chance to modify the behavior of the console, which if they did, // we'd then need to be more careful to apply time limits and such. - lockedWorkerIsolate.logMessage(lock, - static_cast(cdp::LogType::WARNING), "Script modified; context reset."); + lockedWorkerIsolate.logMessage(lock, static_cast(cdp::LogType::WARNING), + "Script modified; context reset."); } // We need to register this context with the inspector, otherwise errors won't be reported. But @@ -1227,10 +1217,11 @@ Worker::Script::Script(kj::Own isolateParam, kj::StringPtr id, // (For modules, the context was already registered by `setupContext()`, above. KJ_IF_SOME(i, isolate->impl->inspector) { if (!source.is()) { - i.get()->contextCreated(v8_inspector::V8ContextInfo(context, - 1, jsg::toInspectorStringView("Compiler"))); + i.get()->contextCreated( + v8_inspector::V8ContextInfo(context, 1, jsg::toInspectorStringView("Compiler"))); } - } else {} // Here to squash a compiler warning + } else { + } // Here to squash a compiler warning KJ_DEFER({ if (!source.is()) { KJ_IF_SOME(i, isolate->impl->inspector) { @@ -1248,13 +1239,15 @@ Worker::Script::Script(kj::Own isolateParam, kj::StringPtr id, try { KJ_SWITCH_ONEOF(source) { KJ_CASE_ONEOF(script, ScriptSource) { - impl->globals = script.compileGlobals(lock, isolate->getApi(), isolate->impl->metrics); + impl->globals = + script.compileGlobals(lock, isolate->getApi(), isolate->impl->metrics); { // It's unclear to me if CompileUnboundScript() can get trapped in any infinite loops or // excessively-expensive computation requiring a time limit. We'll go ahead and apply a time // limit just to be safe. Don't add it to the rollover bank, though. - auto limitScope = isolate->getLimitEnforcer().enterStartupJs(lock, limitErrorOrTime); + auto limitScope = + isolate->getLimitEnforcer().enterStartupJs(lock, limitErrorOrTime); impl->unboundScriptOrMainModule = jsg::NonModuleScript::compile(script.mainScript, lock, script.mainScriptName); } @@ -1265,7 +1258,8 @@ Worker::Script::Script(kj::Own isolateParam, kj::StringPtr id, KJ_CASE_ONEOF(modulesSource, ModulesSource) { this->isPython = modulesSource.isPython; if (!isolate->getApi().getFeatureFlags().getNewModuleRegistry()) { - auto limitScope = isolate->getLimitEnforcer().enterStartupJs(lock, limitErrorOrTime); + auto limitScope = + isolate->getLimitEnforcer().enterStartupJs(lock, limitErrorOrTime); auto& modules = KJ_ASSERT_NONNULL(impl->moduleContext)->getModuleRegistry(); impl->configureDynamicImports(lock, modules); modulesSource.compileModules(lock, isolate->getApi()); @@ -1282,14 +1276,8 @@ Worker::Script::Script(kj::Own isolateParam, kj::StringPtr id, // in the outer try/catch. } } catch (const jsg::JsExceptionThrown&) { - reportStartupError(id, - lock, - isolate->impl->inspector, - isolate->getLimitEnforcer(), - kj::mv(limitErrorOrTime), - catcher, - errorReporter, - impl->permanentException); + reportStartupError(id, lock, isolate->impl->inspector, isolate->getLimitEnforcer(), + kj::mv(limitErrorOrTime), catcher, errorReporter, impl->permanentException); } }); }); @@ -1329,8 +1317,8 @@ Worker::Script::~Script() noexcept(false) { // except in preview. In any case, Scripts are destroyed in the GC thread, where we don't care // too much about lock latency. jsg::runInV8Stack([&](jsg::V8StackScope& stackScope) { - Isolate::Impl::Lock recordedLock(*isolate, - Worker::Lock::TakeSynchronously(kj::none), stackScope); + Isolate::Impl::Lock recordedLock( + *isolate, Worker::Lock::TakeSynchronously(kj::none), stackScope); KJ_IF_SOME(c, impl->moduleContext) { recordedLock.disposeContext(kj::mv(c)); } @@ -1363,29 +1351,26 @@ void setWebAssemblyModuleHasInstance(jsg::Lock& lock, v8::Local con v8::Object* webAssembly = v8::Object::Cast(*jsg::check( context->Global()->Get(context, jsg::v8StrIntern(lock.v8Isolate, "WebAssembly")))); - v8::Object* module = v8::Object::Cast(*jsg::check( - webAssembly->Get(context, jsg::v8StrIntern(lock.v8Isolate, "Module")))); + v8::Object* module = v8::Object::Cast( + *jsg::check(webAssembly->Get(context, jsg::v8StrIntern(lock.v8Isolate, "Module")))); - jsg::check(module->DefineOwnProperty( - context, v8::Symbol::GetHasInstance(lock.v8Isolate), function)); + jsg::check( + module->DefineOwnProperty(context, v8::Symbol::GetHasInstance(lock.v8Isolate), function)); } // ======================================================================================= namespace { -kj::Maybe tryResolveMainModule( - jsg::Lock& js, +kj::Maybe tryResolveMainModule(jsg::Lock& js, const kj::Path& mainModule, jsg::JsContext& jsContext, const Worker::Script& script, ExceptionOrDuration& limitErrorOrTime) { kj::Own limitScope; if (script.isPython) { - limitScope = script.getIsolate().getLimitEnforcer().enterStartupPython( - js, limitErrorOrTime); + limitScope = script.getIsolate().getLimitEnforcer().enterStartupPython(js, limitErrorOrTime); } else { - limitScope = - script.getIsolate().getLimitEnforcer().enterStartupJs(js, limitErrorOrTime); + limitScope = script.getIsolate().getLimitEnforcer().enterStartupJs(js, limitErrorOrTime); } if (script.getIsolate().getApi().getFeatureFlags().getNewModuleRegistry()) { KJ_DEFER({ @@ -1398,15 +1383,14 @@ kj::Maybe tryResolveMainModule( // This intentionally does not return the kj::Maybe directly from the // call to tryResolveModuleNamespace because I intend to add some additional // logging/metrics logic around this call. - KJ_IF_SOME(ns, jsg::modules::ModuleRegistry::tryResolveModuleNamespace( - js, mainModule.toString(true))) { + KJ_IF_SOME(ns, + jsg::modules::ModuleRegistry::tryResolveModuleNamespace(js, mainModule.toString(true))) { return ns; } } else { auto& registry = jsContext->getModuleRegistry(); KJ_IF_SOME(entry, registry.resolve(js, mainModule, kj::none)) { - JSG_REQUIRE(entry.maybeSynthetic == kj::none, TypeError, - "Main module must be an ES module."); + JSG_REQUIRE(entry.maybeSynthetic == kj::none, TypeError, "Main module must be an ES module."); auto module = entry.module.getHandle(js); jsg::instantiateModule(js, module); @@ -1431,17 +1415,17 @@ kj::Maybe tryResolveMainModule( } // anonymous namespace Worker::Worker(kj::Own scriptParam, - kj::Own metricsParam, - kj::FunctionParam target)> compileBindings, - IsolateObserver::StartType startType, - SpanParent parentSpan, LockType lockType, - kj::Maybe errorReporter, - kj::Maybe startupTime) + kj::Own metricsParam, + kj::FunctionParam target)> + compileBindings, + IsolateObserver::StartType startType, + SpanParent parentSpan, + LockType lockType, + kj::Maybe errorReporter, + kj::Maybe startupTime) : script(kj::mv(scriptParam)), metrics(kj::mv(metricsParam)), - impl(kj::heap()){ + impl(kj::heap()) { // Enter/lock isolate. jsg::runInV8Stack([&](jsg::V8StackScope& stackScope) { Isolate::Impl::Lock recordedLock(*script->isolate, lockType, stackScope); @@ -1528,13 +1512,13 @@ Worker::Worker(kj::Own scriptParam, KJ_SWITCH_ONEOF(script->impl->unboundScriptOrMainModule) { KJ_CASE_ONEOF(unboundScript, jsg::NonModuleScript) { - auto limitScope = script->isolate->getLimitEnforcer().enterStartupJs(lock, - limitErrorOrTime); + auto limitScope = + script->isolate->getLimitEnforcer().enterStartupJs(lock, limitErrorOrTime); unboundScript.run(lock.v8Context()); } KJ_CASE_ONEOF(mainModule, kj::Path) { - KJ_IF_SOME(ns, tryResolveMainModule(lock, mainModule, *jsContext, *script, - limitErrorOrTime)) { + KJ_IF_SOME(ns, + tryResolveMainModule(lock, mainModule, *jsContext, *script, limitErrorOrTime)) { impl->env = lock.v8Ref(bindingsScope.As()); auto& api = script->isolate->getApi(); @@ -1556,10 +1540,11 @@ Worker::Worker(kj::Own scriptParam, for (;;) { if (handle == entrypointClasses.durableObject) { - impl->actorClasses.insert(kj::mv(handler.name), Impl::ActorClassInfo { - .cls = kj::mv(cls), - .missingSuperclass = false, - }); + impl->actorClasses.insert(kj::mv(handler.name), + Impl::ActorClassInfo{ + .cls = kj::mv(cls), + .missingSuperclass = false, + }); return; } else if (handle == entrypointClasses.workerEntrypoint) { impl->statelessClasses.insert(kj::mv(handler.name), kj::mv(cls)); @@ -1578,10 +1563,11 @@ Worker::Worker(kj::Own scriptParam, // class if it doesn't inherit anything. // TODO(someday): Log a warning suggesting extending DurableObject. // TODO(someday): Introduce a compat flag that makes this required. - impl->actorClasses.insert(kj::mv(handler.name), Impl::ActorClassInfo { - .cls = kj::mv(cls), - .missingSuperclass = true, - }); + impl->actorClasses.insert(kj::mv(handler.name), + Impl::ActorClassInfo{ + .cls = kj::mv(cls), + .missingSuperclass = true, + }); return; }); } @@ -1600,9 +1586,11 @@ Worker::Worker(kj::Own scriptParam, KJ_CASE_ONEOF(startupTimeElapsed, kj::Duration) { s = startupTimeElapsed; } - KJ_CASE_ONEOF(limitError, kj::Exception) { } + KJ_CASE_ONEOF(limitError, kj::Exception) { + } } - } else {} // Added to suppress a compiler warning + } else { + } // Added to suppress a compiler warning startupMetrics->done(); } catch (const kj::Exception& e) { @@ -1611,14 +1599,9 @@ Worker::Worker(kj::Own scriptParam, // in the outer try/catch. } } catch (const jsg::JsExceptionThrown&) { - reportStartupError(script->id, - lock, - script->isolate->impl->inspector, - script->isolate->getLimitEnforcer(), - kj::mv(limitErrorOrTime), - catcher, - errorReporter, - impl->permanentException); + reportStartupError(script->id, lock, script->isolate->impl->inspector, + script->isolate->getLimitEnforcer(), kj::mv(limitErrorOrTime), catcher, errorReporter, + impl->permanentException); } }); }); @@ -1640,13 +1623,15 @@ Worker::~Worker() noexcept(false) { lock->push(kj::mv(impl)); } -void Worker::handleLog(jsg::Lock& js, ConsoleMode consoleMode, LogLevel level, - const v8::Global& original, - const v8::FunctionCallbackInfo& info) { +void Worker::handleLog(jsg::Lock& js, + ConsoleMode consoleMode, + LogLevel level, + const v8::Global& original, + const v8::FunctionCallbackInfo& info) { // Call original V8 implementation so messages sent to connected inspector if any auto context = js.v8Context(); int length = info.Length(); - KJ_STACK_ARRAY(v8::Local, args, length + 1, 64, 64); // + 1 used for `colors` later + KJ_STACK_ARRAY(v8::Local, args, length + 1, 64, 64); // + 1 used for `colors` later for (auto i: kj::zeroTo(length)) args[i] = info[i]; jsg::check(original.Get(js.v8Isolate)->Call(context, info.This(), length, args.begin())); @@ -1676,12 +1661,9 @@ void Worker::handleLog(jsg::Lock& js, ConsoleMode consoleMode, LogLevel level, js.withinHandleScope([&] { auto context = js.v8Context(); bool shouldSerialiseToJson = false; - if (arg->IsNull() || - arg->IsNumber() || - arg->IsArray() || - arg->IsBoolean() || + if (arg->IsNull() || arg->IsNumber() || arg->IsArray() || arg->IsBoolean() || arg->IsString() || - arg->IsUndefined()) { // This is special cased for backwards compatibility. + arg->IsUndefined()) { // This is special cased for backwards compatibility. shouldSerialiseToJson = true; } if (arg->IsObject()) { @@ -1705,7 +1687,7 @@ void Worker::handleLog(jsg::Lock& js, ConsoleMode consoleMode, LogLevel level, } } - if (kj::runCatchingExceptions([&]() { + if (kj::runCatchingExceptions([&]() { // On the off chance the the arg is the request.cf object, let's make // sure we do not log proxied fields here. if (shouldSerialiseToJson) { @@ -1755,10 +1737,10 @@ void Worker::handleLog(jsg::Lock& js, ConsoleMode consoleMode, LogLevel level, // Log warnings and errors to stderr auto useStderr = level >= LogLevel::WARN; - auto fd = useStderr ? stderr : stdout; + auto fd = useStderr ? stderr : stdout; auto tty = useStderr ? STDERR_TTY : STDOUT_TTY; - auto colors = COLOR_MODE == ColorMode::ENABLED || - (COLOR_MODE == ColorMode::ENABLED_IF_TTY && tty); + auto colors = + COLOR_MODE == ColorMode::ENABLED || (COLOR_MODE == ColorMode::ENABLED_IF_TTY && tty); auto registry = jsg::ModuleRegistry::from(js); auto inspectModule = registry->resolveInternalImport(js, "node-internal:internal_inspect"_kj); @@ -1767,14 +1749,14 @@ void Worker::handleLog(jsg::Lock& js, ConsoleMode consoleMode, LogLevel level, auto recv = js.v8Undefined(); args[length] = v8::Boolean::New(js.v8Isolate, colors); - auto formatted = js.toString(jsg::check(formatLog->Call(context, recv, length + 1, args.begin()))); + auto formatted = + js.toString(jsg::check(formatLog->Call(context, recv, length + 1, args.begin()))); fprintf(fd, "%s\n", formatted.cStr()); fflush(fd); } } -Worker::Lock::TakeSynchronously::TakeSynchronously( - kj::Maybe requestParam) { +Worker::Lock::TakeSynchronously::TakeSynchronously(kj::Maybe requestParam) { KJ_IF_SOME(r, requestParam) { request = &r; } @@ -1797,7 +1779,7 @@ struct Worker::Lock::Impl { }; Worker::Lock::Lock(const Worker& constWorker, LockType lockType, jsg::V8StackScope& stackScope) - : // const_cast OK because we took out a lock. + : // const_cast OK because we took out a lock. worker(const_cast(constWorker)), impl(kj::heap(worker, lockType, stackScope)) { kj::requireOnStack(this, "Worker::Lock MUST be allocated on the stack."); @@ -1850,12 +1832,12 @@ kj::Maybe> Worker::Lock::getExportedHandler( } kj::StringPtr n = name.orDefault("default"_kj); - KJ_IF_SOME(h, worker.impl->namedHandlers.find(n)){ + KJ_IF_SOME(h, worker.impl->namedHandlers.find(n)) { return fakeOwn(h); } else KJ_IF_SOME(cls, worker.impl->statelessClasses.find(n)) { jsg::Lock& js = *this; - auto handler = kj::heap(cls(js, jsg::alloc(), - KJ_ASSERT_NONNULL(worker.impl->env).addRef(js))); + auto handler = kj::heap(cls( + js, jsg::alloc(), KJ_ASSERT_NONNULL(worker.impl->env).addRef(js))); // HACK: We set handler.env and handler.ctx to undefined because we already passed the real // env and ctx into the constructor, and we want the handler methods to act like they take @@ -1918,18 +1900,16 @@ void Worker::Lock::logUncaughtException(kj::StringPtr description) { // We don't add the exception to traces here, since it turns out that this path only gets hit by // intermediate exception handling. KJ_IF_SOME(i, worker.script->isolate->impl->inspector) { - JSG_WITHIN_CONTEXT_SCOPE(*this, getContext(), [&](jsg::Lock& js) { - jsg::sendExceptionToInspector(js, *i.get(), description); - }); + JSG_WITHIN_CONTEXT_SCOPE(*this, getContext(), + [&](jsg::Lock& js) { jsg::sendExceptionToInspector(js, *i.get(), description); }); } // Run with --verbose to log JS exceptions to stderr. Useful when running tests. KJ_LOG(INFO, "uncaught exception", description); } -void Worker::Lock::logUncaughtException(UncaughtExceptionSource source, - const jsg::JsValue& exception, - const jsg::JsMessage& message) { +void Worker::Lock::logUncaughtException( + UncaughtExceptionSource source, const jsg::JsValue& exception, const jsg::JsMessage& message) { // Only add exception to trace when running within an I/O context with a tracer. if (IoContext::hasCurrent()) { auto& ioContext = IoContext::current(); @@ -1942,9 +1922,8 @@ void Worker::Lock::logUncaughtException(UncaughtExceptionSource source, } KJ_IF_SOME(i, worker.script->isolate->impl->inspector) { - JSG_WITHIN_CONTEXT_SCOPE(*this, getContext(), [&](jsg::Lock& js) { - sendExceptionToInspector(js, *i.get(), source, exception, message); - }); + JSG_WITHIN_CONTEXT_SCOPE(*this, getContext(), + [&](jsg::Lock& js) { sendExceptionToInspector(js, *i.get(), source, exception, message); }); } // Run with --verbose to log JS exceptions to stderr. Useful when running tests. @@ -1966,8 +1945,7 @@ void Worker::Lock::logUncaughtException(UncaughtExceptionSource source, } } -void Worker::Lock::logUncaughtException(UncaughtExceptionSource source, - kj::Exception&& exception) { +void Worker::Lock::logUncaughtException(UncaughtExceptionSource source, kj::Exception&& exception) { jsg::Lock& js = *this; // If we have an attached serialized exception, deserialize it and log that instead, rather @@ -2003,8 +1981,7 @@ void Worker::Lock::logUncaughtException(UncaughtExceptionSource source, } void Worker::Lock::reportPromiseRejectEvent(v8::PromiseRejectMessage& message) { - getGlobalScope().emitPromiseRejection( - *this, message.GetEvent(), + getGlobalScope().emitPromiseRejection(*this, message.GetEvent(), jsg::V8Ref(getIsolate(), message.GetPromise()), jsg::V8Ref(getIsolate(), message.GetValue())); } @@ -2026,8 +2003,8 @@ void Worker::Lock::validateHandlers(ValidationErrorReporter& errorReporter) { } } if (!foundAny) { - errorReporter.addError(kj::str( - "No event handlers were registered. This script does nothing.")); + errorReporter.addError( + kj::str("No event handlers were registered. This script does nothing.")); } } else { auto report = [&](kj::Maybe name, api::ExportedHandler& exported) { @@ -2086,8 +2063,8 @@ void Worker::Lock::validateHandlers(ValidationErrorReporter& errorReporter) { jsg::JsValue proto = ctor.get(js, "prototype"); kj::HashSet seenNames; for (;;) { - auto protoObj = JSG_REQUIRE_NONNULL(proto.tryCast(), - TypeError, "Exported entrypoint class's prototype chain does not end in Object."); + auto protoObj = JSG_REQUIRE_NONNULL(proto.tryCast(), TypeError, + "Exported entrypoint class's prototype chain does not end in Object."); if (protoObj == prototypeOfObject) { // Reached the prototype for `Object`. Stop here. break; @@ -2095,10 +2072,9 @@ void Worker::Lock::validateHandlers(ValidationErrorReporter& errorReporter) { // Awkwardly, the prototype's members are not typically enumerable, so we have to // enumerate them rather directly. - jsg::JsArray properties = protoObj.getPropertyNames( - js, jsg::KeyCollectionFilter::OWN_ONLY, - jsg::PropertyFilter::SKIP_SYMBOLS, - jsg::IndexFilter::SKIP_INDICES); + jsg::JsArray properties = + protoObj.getPropertyNames(js, jsg::KeyCollectionFilter::OWN_ONLY, + jsg::PropertyFilter::SKIP_SYMBOLS, jsg::IndexFilter::SKIP_INDICES); for (auto i: kj::zeroTo(properties.size())) { auto name = properties.get(js, i).toString(js); if (name == "constructor"_kj) { @@ -2108,9 +2084,8 @@ void Worker::Lock::validateHandlers(ValidationErrorReporter& errorReporter) { // Only report each method name once, even if it overrides a method in a superclass. bool isNew = true; - kj::StringPtr namePtr = seenNames.upsert(kj::mv(name), [&](auto&, auto&&) { - isNew = false; - }); + kj::StringPtr namePtr = + seenNames.upsert(kj::mv(name), [&](auto&, auto&&) { isNew = false; }); if (isNew) { errorReporter.addHandler(entrypointName, namePtr); } @@ -2143,8 +2118,7 @@ kj::Promise Worker::Isolate::takeAsyncLockWithoutRequest( return takeAsyncLockImpl(kj::mv(lockTiming)); } -kj::Promise Worker::Isolate::takeAsyncLock( - RequestObserver& request) const { +kj::Promise Worker::Isolate::takeAsyncLock(RequestObserver& request) const { auto lockTiming = getMetrics().tryCreateLockTiming(kj::Maybe(request)); return takeAsyncLockImpl(kj::mv(lockTiming)); } @@ -2156,14 +2130,13 @@ kj::Promise Worker::Isolate::takeAsyncLockImpl( currentLoad = getCurrentLoad(); } - for (uint threadWaitingDifferentLockCount = 0; ; ++threadWaitingDifferentLockCount) { + for (uint threadWaitingDifferentLockCount = 0;; ++threadWaitingDifferentLockCount) { AsyncWaiter* waiter = AsyncWaiter::threadCurrentWaiter; if (waiter == nullptr) { // Thread is not currently waiting on a lock. KJ_IF_SOME(lt, lockTiming) { - lt.get()->reportAsyncInfo( - KJ_ASSERT_NONNULL(currentLoad), false /* threadWaitingSameLock */, + lt.get()->reportAsyncInfo(KJ_ASSERT_NONNULL(currentLoad), false /* threadWaitingSameLock */, threadWaitingDifferentLockCount); } auto newWaiter = kj::refcounted(kj::atomicAddRef(*this)); @@ -2173,8 +2146,7 @@ kj::Promise Worker::Isolate::takeAsyncLockImpl( // Thread is waiting on a lock already, and it's for the same isolate. We can coalesce the // locks. KJ_IF_SOME(lt, lockTiming) { - lt.get()->reportAsyncInfo( - KJ_ASSERT_NONNULL(currentLoad), true /* threadWaitingSameLock */, + lt.get()->reportAsyncInfo(KJ_ASSERT_NONNULL(currentLoad), true /* threadWaitingSameLock */, threadWaitingDifferentLockCount); } auto newWaiterRef = kj::addRef(*waiter); @@ -2340,7 +2312,8 @@ struct MessageQueue { class Worker::Isolate::InspectorChannelImpl final: public v8_inspector::V8Inspector::Channel { public: InspectorChannelImpl(kj::Own isolateParam, kj::WebSocket& webSocket) - : ioHandler(webSocket), state(kj::heap(this, kj::mv(isolateParam))) { + : ioHandler(webSocket), + state(kj::heap(this, kj::mv(isolateParam))) { ioHandler.connect(*this); } @@ -2374,9 +2347,7 @@ public: // // TODO(cleanup): Maybe we could add a kj::stringifyCurrentException() or // kj::logUncaughtException() or something? - KJ_IF_SOME(exception, kj::runCatchingExceptions([&]() { - throw; - })) { + KJ_IF_SOME(exception, kj::runCatchingExceptions([&]() { throw; })) { KJ_LOG(ERROR, "uncaught exception in ~Script() and the C++ standard is broken", exception); } } @@ -2388,10 +2359,10 @@ public: } void dispatchProtocolMessage(kj::String message, - v8_inspector::V8InspectorSession& session, - Isolate& isolate, - jsg::V8StackScope& stackScope, - Isolate::Impl::Lock& recordedLock) { + v8_inspector::V8InspectorSession& session, + Isolate& isolate, + jsg::V8StackScope& stackScope, + Isolate::Impl::Lock& recordedLock) { capnp::MallocMessageBuilder messageBuilder; auto cmd = messageBuilder.initRoot(); getCdpJsonCodec().decode(message, cmd); @@ -2447,9 +2418,7 @@ public: case cdp::Command::TAKE_HEAP_SNAPSHOT: { auto& lock = recordedLock.lock; auto params = cmd.getTakeHeapSnapshot().getParams(); - takeHeapSnapshot(*lock, - params.getExposeInternals(), - params.getCaptureNumericValue()); + takeHeapSnapshot(*lock, params.getExposeInternals(), params.getCaptureNumericValue()); break; } } @@ -2491,9 +2460,8 @@ public: // create one. Ugh. auto dummyContext = v8::Context::New(lock->v8Isolate); auto& inspector = *KJ_ASSERT_NONNULL(isolate.impl->inspector); - inspector.contextCreated( - v8_inspector::V8ContextInfo(dummyContext, 1, v8_inspector::StringView( - reinterpret_cast("Worker"), 6))); + inspector.contextCreated(v8_inspector::V8ContextInfo(dummyContext, 1, + v8_inspector::StringView(reinterpret_cast("Worker"), 6))); JSG_WITHIN_CONTEXT_SCOPE(*lock, dummyContext, [&](jsg::Lock& js) { jsg::sendExceptionToInspector(js, inspector, jsg::extractTunneledExceptionDescription(limitError.getDescription())); @@ -2501,7 +2469,8 @@ public: inspector.contextDestroyed(dummyContext); }); } - KJ_CASE_ONEOF(startupTimeElapsed, kj::Duration) {} + KJ_CASE_ONEOF(startupTimeElapsed, kj::Duration) { + } } if (recordedLock.checkInWithLimitEnforcer(isolate)) { @@ -2514,8 +2483,7 @@ public: } void handleDispatchProtocolMessage( - Worker::AsyncLock& asyncLock, - kj::MutexGuarded& incomingQueue) { + Worker::AsyncLock& asyncLock, kj::MutexGuarded& incomingQueue) { auto lockedState = state.lockExclusive(); v8_inspector::V8InspectorSession& session = *lockedState->get()->session; Isolate& isolate = const_cast(*lockedState->get()->isolate); @@ -2528,7 +2496,7 @@ public: } auto messages = lockedQueue->messages.slice(lockedQueue->head, lockedQueue->messages.size()); - for (auto& message : messages) { + for (auto& message: messages) { dispatchProtocolMessage(kj::mv(message), session, isolate, stackScope, recordedLock); } lockedQueue->messages.clear(); @@ -2593,8 +2561,7 @@ private: // the InspectorChannelImpl and the InspectorClient. class WebSocketIoHandler final { public: - WebSocketIoHandler(kj::WebSocket& webSocket) - : webSocket(webSocket) { + WebSocketIoHandler(kj::WebSocket& webSocket): webSocket(webSocket) { // Assume we are being instantiated on the InspectorService thread, the thread that will do // I/O for CDP messages. Messages are delivered to the InspectorChannelImpl on the Isolate thread. incomingQueueNotifier = XThreadNotifier::create(); @@ -2616,15 +2583,13 @@ private: // has to remain in runMessageLoopOnPause() but still receive CDP messages // (e.g. resume). kj::Maybe waitForMessage() { - return incomingQueue.when( - [](const MessageQueue& incomingQueue) { - return (incomingQueue.head < incomingQueue.messages.size() || - incomingQueue.status == MessageQueue::Status::CLOSED); - }, - [](MessageQueue& incomingQueue) -> kj::Maybe { - if (incomingQueue.status == MessageQueue::Status::CLOSED) return {}; - return pollMessage(incomingQueue); - }); + return incomingQueue.when([](const MessageQueue& incomingQueue) { + return (incomingQueue.head < incomingQueue.messages.size() || + incomingQueue.status == MessageQueue::Status::CLOSED); + }, [](MessageQueue& incomingQueue) -> kj::Maybe { + if (incomingQueue.status == MessageQueue::Status::CLOSED) return {}; + return pollMessage(incomingQueue); + }); } // Message pumping promise that should be evaluated on the InspectorService @@ -2654,9 +2619,9 @@ private: } void shutdown() { - // Drain incoming queue, the isolate thread may be waiting on it - // on will notice it is closed if woken without any messages to - // deliver in WebSocketIoWorker::waitForMessage(). + // Drain incoming queue, the isolate thread may be waiting on it + // on will notice it is closed if woken without any messages to + // deliver in WebSocketIoWorker::waitForMessage(). { auto lockedIncomingQueue = incomingQueue.lockExclusive(); lockedIncomingQueue->head = 0; @@ -2672,14 +2637,14 @@ private: } kj::Promise receiveLoop() { - for (;;) { + for (;;) { auto message = co_await webSocket.receive(MAX_MESSAGE_SIZE); KJ_SWITCH_ONEOF(message) { KJ_CASE_ONEOF(text, kj::String) { incomingQueue.lockExclusive()->messages.add(kj::mv(text)); incomingQueueNotifier->notify(); } - KJ_CASE_ONEOF(blob, kj::Array){ + KJ_CASE_ONEOF(blob, kj::Array) { // Ignore. } KJ_CASE_ONEOF(close, kj::WebSocket::Close) { @@ -2716,14 +2681,14 @@ private: co_return; } } catch (kj::Exception& e) { - shutdown(); - throw; + shutdown(); + throw; } } } kj::Promise sendToWebSocket(kj::Vector messages) { - for (auto& message : messages) { + for (auto& message: messages) { co_await webSocket.send(message); } } @@ -2734,9 +2699,9 @@ private: kj::MutexGuarded outgoingQueue; kj::Own outgoingQueueNotifier; - kj::WebSocket& webSocket; // only accessed on the InspectorService thread. - std::atomic_bool receivedClose; // accessed on any thread (only transitions false -> true). - kj::Maybe channel; // only accessed on the isolate thread. + kj::WebSocket& webSocket; // only accessed on the InspectorService thread. + std::atomic_bool receivedClose; // accessed on any thread (only transitions false -> true). + kj::Maybe channel; // only accessed on the isolate thread. // Sometimes the inspector protocol sends large messages. KJ defaults to a 1MB size limit // for WebSocket messages, which makes sense for production use cases, but for debug we should @@ -2749,7 +2714,7 @@ private: void takeHeapSnapshot(jsg::Lock& js, bool exposeInternals, bool captureNumericValue) { struct Activity: public v8::ActivityControl { InspectorChannelImpl& channel; - Activity(InspectorChannelImpl& channel) : channel(channel) {} + Activity(InspectorChannelImpl& channel): channel(channel) {} ControlOption ReportProgressValue(uint32_t done, uint32_t total) { capnp::MallocMessageBuilder message; @@ -2769,7 +2734,7 @@ private: struct Writer: public v8::OutputStream { InspectorChannelImpl& channel; - Writer(InspectorChannelImpl& channel) : channel(channel) {} + Writer(InspectorChannelImpl& channel): channel(channel) {} void EndOfStream() override {} int GetChunkSize() override { @@ -2811,14 +2776,18 @@ private: State(InspectorChannelImpl* self, kj::Own isolateParam) : isolate(kj::mv(isolateParam)), session(KJ_ASSERT_NONNULL(isolate->impl->inspector) - ->connect(1, self, v8_inspector::StringView(), - isolate->impl->inspectorPolicy == InspectorPolicy::ALLOW_UNTRUSTED ? - v8_inspector::V8Inspector::kUntrusted : - v8_inspector::V8Inspector::kFullyTrusted)) {} + ->connect(1, + self, + v8_inspector::StringView(), + isolate->impl->inspectorPolicy == InspectorPolicy::ALLOW_UNTRUSTED + ? v8_inspector::V8Inspector::kUntrusted + : v8_inspector::V8Inspector::kFullyTrusted)) {} ~State() noexcept(false) { if (session != nullptr) { - KJ_LOG(ERROR, "Deleting InspectorChannelImpl::State without having called " - "teardownUnderLock()", kj::getStackTrace()); + KJ_LOG(ERROR, + "Deleting InspectorChannelImpl::State without having called " + "teardownUnderLock()", + kj::getStackTrace()); // Isolate locks are recursive so it should be safe to lock here. jsg::runInV8Stack([&](jsg::V8StackScope& stackScope) { @@ -2865,12 +2834,12 @@ bool Worker::Isolate::InspectorChannelImpl::dispatchOneMessageDuringPause() { } } -bool Worker::InspectorClient::dispatchOneMessageDuringPause(Worker::Isolate::InspectorChannelImpl& channel) { +bool Worker::InspectorClient::dispatchOneMessageDuringPause( + Worker::Isolate::InspectorChannelImpl& channel) { return channel.dispatchOneMessageDuringPause(); } -kj::Promise Worker::Isolate::attachInspector( - kj::Timer& timer, +kj::Promise Worker::Isolate::attachInspector(kj::Timer& timer, kj::Duration timerOffset, kj::HttpService::Response& response, const kj::HttpHeaderTable& headerTable, @@ -2881,19 +2850,16 @@ kj::Promise Worker::Isolate::attachInspector( headers.set(controlHeaderId, "{\"ewLog\":{\"status\":\"ok\"}}"); auto webSocket = response.acceptWebSocket(headers); - return attachInspector(timer, timerOffset, *webSocket) - .attach(kj::mv(webSocket)); + return attachInspector(timer, timerOffset, *webSocket).attach(kj::mv(webSocket)); } kj::Promise Worker::Isolate::attachInspector( - kj::Timer& timer, - kj::Duration timerOffset, - kj::WebSocket& webSocket) const { + kj::Timer& timer, kj::Duration timerOffset, kj::WebSocket& webSocket) const { KJ_REQUIRE(impl->inspector != kj::none); return jsg::runInV8Stack([&](jsg::V8StackScope& stackScope) { - Isolate::Impl::Lock recordedLock(*this, - InspectorChannelImpl::InspectorLock(kj::none), stackScope); + Isolate::Impl::Lock recordedLock( + *this, InspectorChannelImpl::InspectorLock(kj::none), stackScope); auto& lock = *recordedLock.lock; auto& lockedSelf = const_cast(*this); @@ -2906,7 +2872,8 @@ kj::Promise Worker::Isolate::attachInspector( lockedSelf.impl->inspectorClient.setInspectorTimerInfo(timer, timerOffset); - auto channel = kj::heap(kj::atomicAddRef(*this), webSocket); + auto channel = + kj::heap(kj::atomicAddRef(*this), webSocket); lockedSelf.currentInspectorSession = *channel; lockedSelf.impl->inspectorClient.setChannel(*channel); @@ -2962,8 +2929,7 @@ void Worker::Isolate::logErrorOnce(kj::StringPtr description) { }); } -void Worker::Isolate::logMessage(jsg::Lock& js, - uint16_t type, kj::StringPtr description) { +void Worker::Isolate::logMessage(jsg::Lock& js, uint16_t type, kj::StringPtr description) { if (impl->inspector != kj::none) { // We want to log a warning to the devtools console, as if `console.warn()` were called. // However, the only public interface to call the real `console.warn()` is via JavaScript, @@ -3022,23 +2988,33 @@ struct Worker::Actor::Impl { // If the actor is backed by a class, this field tracks the instance through its stages. The // instance is constructed as part of the first request to be delivered. - kj::OneOf< - NoClass, // not class-based - Worker::Impl::ActorClassInfo*, // constructor not run yet - Initializing, // constructor currently running - api::ExportedHandler, // fully constructed - kj::Exception // constructor threw - > classInstance; + kj::OneOf + classInstance; class HooksImpl: public InputGate::Hooks, public OutputGate::Hooks, public ActorCache::Hooks { public: HooksImpl(kj::Own loopback, TimerChannel& timerChannel, ActorObserver& metrics) - : loopback(kj::mv(loopback)), timerChannel(timerChannel), metrics(metrics) {} + : loopback(kj::mv(loopback)), + timerChannel(timerChannel), + metrics(metrics) {} - void inputGateLocked() override { metrics.inputGateLocked(); } - void inputGateReleased() override { metrics.inputGateReleased(); } - void inputGateWaiterAdded() override { metrics.inputGateWaiterAdded(); } - void inputGateWaiterRemoved() override { metrics.inputGateWaiterRemoved(); } + void inputGateLocked() override { + metrics.inputGateLocked(); + } + void inputGateReleased() override { + metrics.inputGateReleased(); + } + void inputGateWaiterAdded() override { + metrics.inputGateWaiterAdded(); + } + void inputGateWaiterRemoved() override { + metrics.inputGateWaiterRemoved(); + } // Implements InputGate::Hooks. kj::Promise makeTimeoutPromise() override { @@ -3049,16 +3025,24 @@ struct Worker::Actor::Impl { co_await timerChannel.afterLimitTimeout(timeout); kj::throwFatalException(KJ_EXCEPTION(OVERLOADED, - "broken.outputGateBroken; jsg.Error: Durable Object storage operation exceeded " - "timeout which caused object to be reset.")); + "broken.outputGateBroken; jsg.Error: Durable Object storage operation exceeded " + "timeout which caused object to be reset.")); } // Implements OutputGate::Hooks. - void outputGateLocked() override { metrics.outputGateLocked(); } - void outputGateReleased() override { metrics.outputGateReleased(); } - void outputGateWaiterAdded() override { metrics.outputGateWaiterAdded(); } - void outputGateWaiterRemoved() override { metrics.outputGateWaiterRemoved(); } + void outputGateLocked() override { + metrics.outputGateLocked(); + } + void outputGateReleased() override { + metrics.outputGateReleased(); + } + void outputGateWaiterAdded() override { + metrics.outputGateWaiterAdded(); + } + void outputGateWaiterRemoved() override { + metrics.outputGateWaiterRemoved(); + } // Implements ActorCache::Hooks @@ -3071,8 +3055,8 @@ struct Worker::Actor::Impl { } private: - kj::Own loopback; // only for updateAlarmInMemory() - TimerChannel& timerChannel; // only for afterLimitTimeout() and updateAlarmInMemory() + kj::Own loopback; // only for updateAlarmInMemory() + TimerChannel& timerChannel; // only for afterLimitTimeout() and updateAlarmInMemory() ActorObserver& metrics; kj::Maybe> maybeAlarmPreviewTask; @@ -3114,10 +3098,11 @@ struct Worker::Actor::Impl { kj::PromiseFulfillerPair constructorFailedPaf = kj::newPromiseAndFulfiller(); struct ScheduledAlarm { - ScheduledAlarm(kj::Date scheduledTime, - kj::PromiseFulfillerPair pf) - : scheduledTime(scheduledTime), resultFulfiller(kj::mv(pf.fulfiller)), - resultPromise(pf.promise.fork()) {} + ScheduledAlarm( + kj::Date scheduledTime, kj::PromiseFulfillerPair pf) + : scheduledTime(scheduledTime), + resultFulfiller(kj::mv(pf.fulfiller)), + resultPromise(pf.promise.fork()) {} KJ_DISALLOW_COPY(ScheduledAlarm); ScheduledAlarm(ScheduledAlarm&&) = default; ~ScheduledAlarm() noexcept(false) {} @@ -3125,8 +3110,8 @@ struct Worker::Actor::Impl { kj::Date scheduledTime; WorkerInterface::AlarmFulfiller resultFulfiller; kj::ForkedPromise resultPromise; - kj::Promise cleanupPromise = - resultPromise.addBranch().then([](WorkerInterface::AlarmResult&&){}, [](kj::Exception&&){}); + kj::Promise cleanupPromise = resultPromise.addBranch().then( + [](WorkerInterface::AlarmResult&&) {}, [](kj::Exception&&) {}); // The first thing we do after we get a result should be to remove the running alarm (if we got // that far). So we grab the first branch now and ignore any results, before anyone else has a // chance to do so. @@ -3147,16 +3132,24 @@ struct Worker::Actor::Impl { // is running. kj::ForkedPromise runningAlarmTask = kj::Promise(kj::READY_NOW).fork(); - Impl(Worker::Actor& self, Worker::Lock& lock, Actor::Id actorId, - bool hasTransient, MakeActorCacheFunc makeActorCache, - MakeStorageFunc makeStorage, kj::Own loopback, - TimerChannel& timerChannel, kj::Own metricsParam, - kj::Maybe> manager, kj::Maybe& hibernationEventType, - kj::PromiseFulfillerPair paf = kj::newPromiseAndFulfiller()) - : actorId(kj::mv(actorId)), makeStorage(kj::mv(makeStorage)), + Impl(Worker::Actor& self, + Worker::Lock& lock, + Actor::Id actorId, + bool hasTransient, + MakeActorCacheFunc makeActorCache, + MakeStorageFunc makeStorage, + kj::Own loopback, + TimerChannel& timerChannel, + kj::Own metricsParam, + kj::Maybe> manager, + kj::Maybe& hibernationEventType, + kj::PromiseFulfillerPair paf = kj::newPromiseAndFulfiller()) + : actorId(kj::mv(actorId)), + makeStorage(kj::mv(makeStorage)), metrics(kj::mv(metricsParam)), hooks(loopback->addRef(), timerChannel, *metrics), - inputGate(hooks), outputGate(hooks), + inputGate(hooks), + outputGate(hooks), loopback(kj::mv(loopback)), timerChannel(timerChannel), shutdownPromise(paf.promise.fork()), @@ -3168,16 +3161,15 @@ struct Worker::Actor::Impl { transient.emplace(js, js.obj()); } - actorCache = makeActorCache(self.worker->getIsolate().impl->actorCacheLru, - outputGate, hooks); + actorCache = makeActorCache(self.worker->getIsolate().impl->actorCacheLru, outputGate, hooks); }); } }; kj::Promise Worker::takeAsyncLockWhenActorCacheReady( kj::Date now, Actor& actor, RequestObserver& request) const { - auto lockTiming = getIsolate().getMetrics() - .tryCreateLockTiming(kj::Maybe(request)); + auto lockTiming = + getIsolate().getMetrics().tryCreateLockTiming(kj::Maybe(request)); KJ_IF_SOME(c, actor.impl->actorCache) { KJ_IF_SOME(p, c.get()->evictStale(now)) { @@ -3198,17 +3190,24 @@ kj::Maybe Worker::getConnectOverride(kj::StringPtr networkAd return connectOverrides.find(networkAddress); } -Worker::Actor::Actor(const Worker& worker, kj::Maybe tracker, Actor::Id actorId, - bool hasTransient, MakeActorCacheFunc makeActorCache, - kj::Maybe className, MakeStorageFunc makeStorage, Worker::Lock& lock, - kj::Own loopback, TimerChannel& timerChannel, kj::Own metrics, - kj::Maybe> manager, kj::Maybe hibernationEventType) - : worker(kj::atomicAddRef(worker)), tracker(tracker.map([](RequestTracker& tracker){ - return tracker.addRef(); - })) { +Worker::Actor::Actor(const Worker& worker, + kj::Maybe tracker, + Actor::Id actorId, + bool hasTransient, + MakeActorCacheFunc makeActorCache, + kj::Maybe className, + MakeStorageFunc makeStorage, + Worker::Lock& lock, + kj::Own loopback, + TimerChannel& timerChannel, + kj::Own metrics, + kj::Maybe> manager, + kj::Maybe hibernationEventType) + : worker(kj::atomicAddRef(worker)), + tracker(tracker.map([](RequestTracker& tracker) { return tracker.addRef(); })) { impl = kj::heap(*this, lock, kj::mv(actorId), hasTransient, kj::mv(makeActorCache), - kj::mv(makeStorage), kj::mv(loopback), timerChannel, kj::mv(metrics), - kj::mv(manager), hibernationEventType); + kj::mv(makeStorage), kj::mv(loopback), timerChannel, kj::mv(metrics), kj::mv(manager), + hibernationEventType); KJ_IF_SOME(c, className) { KJ_IF_SOME(cls, lock.getWorker().impl->actorClasses.find(c)) { @@ -3223,15 +3222,15 @@ Worker::Actor::Actor(const Worker& worker, kj::Maybe tracker, A void Worker::Actor::ensureConstructed(IoContext& context) { KJ_IF_SOME(info, impl->classInstance.tryGet()) { - context.addWaitUntil(context.run([this, &info = *info](Worker::Lock& lock) { + context.addWaitUntil(context + .run([this, &info = *info](Worker::Lock& lock) { jsg::Lock& js = lock; kj::Maybe> storage; KJ_IF_SOME(c, impl->actorCache) { storage = impl->makeStorage(lock, worker->getIsolate().getApi(), *c); } - auto handler = info.cls(lock, - jsg::alloc(cloneId(), kj::mv(storage)), + auto handler = info.cls(lock, jsg::alloc(cloneId(), kj::mv(storage)), KJ_ASSERT_NONNULL(lock.getWorker().impl->env).addRef(js)); // HACK: We set handler.env to undefined because we already passed the real env into the @@ -3278,9 +3277,8 @@ Worker::Actor::~Actor() noexcept(false) { // potentially colocate multiple actors on the same thread, but they are always from the same // namespace and hence would be locking the same isolate anyway -- it's not like one of the // other actors could be running while we wait for this lock. - worker->runInLockScope(Worker::Lock::TakeSynchronously(kj::none), [&](Worker::Lock& lock) { - impl = nullptr; - }); + worker->runInLockScope( + Worker::Lock::TakeSynchronously(kj::none), [&](Worker::Lock& lock) { impl = nullptr; }); } void Worker::Actor::shutdown(uint16_t reasonCode, kj::Maybe error) { @@ -3327,10 +3325,10 @@ kj::Promise Worker::Actor::onBroken() { } return abortPromise - // inputGate.onBroken() is covered by IoContext::onAbort(), but outputGate.onBroken() is - // not. - .exclusiveJoin(impl->outputGate.onBroken()) - .exclusiveJoin(kj::mv(impl->constructorFailedPaf.promise)); + // inputGate.onBroken() is covered by IoContext::onAbort(), but outputGate.onBroken() is + // not. + .exclusiveJoin(impl->outputGate.onBroken()) + .exclusiveJoin(kj::mv(impl->constructorFailedPaf.promise)); } const Worker::Actor::Id& Worker::Actor::getId() { @@ -3355,9 +3353,7 @@ Worker::Actor::Id Worker::Actor::cloneId() { kj::Maybe> Worker::Actor::getTransient(Worker::Lock& lock) { KJ_REQUIRE(&lock.getWorker() == worker.get()); - return impl->transient.map([&](jsg::JsRef& val) { - return val.addRef(lock); - }); + return impl->transient.map([&](jsg::JsRef& val) { return val.addRef(lock); }); } kj::Maybe Worker::Actor::getPersistent() { @@ -3368,8 +3364,8 @@ kj::Own Worker::Actor::getLoopback() { return impl->loopback->addRef(); } -kj::Maybe> - Worker::Actor::makeStorageForSwSyntax(Worker::Lock& lock) { +kj::Maybe> Worker::Actor::makeStorageForSwSyntax( + Worker::Lock& lock) { return impl->actorCache.map([&](kj::Own& cache) { return impl->makeStorage(lock, worker->getIsolate().getApi(), *cache); }); @@ -3380,8 +3376,8 @@ void Worker::Actor::assertCanSetAlarm() { KJ_CASE_ONEOF(_, Impl::NoClass) { // Once upon a time, we allowed actors without classes. Let's make a nicer message if we // we somehow see a classless actor attempt to run an alarm in the wild. - JSG_FAIL_REQUIRE(TypeError, - "Your Durable Object must be class-based in order to call setAlarm()"); + JSG_FAIL_REQUIRE( + TypeError, "Your Durable Object must be class-based in order to call setAlarm()"); } KJ_CASE_ONEOF(_, Worker::Impl::ActorClassInfo*) { KJ_FAIL_ASSERT("setAlarm() invoked before Durable Object ctor"); @@ -3415,10 +3411,10 @@ void Worker::Actor::Impl::HooksImpl::updateAlarmInMemory(kj::Maybe new auto retry = kj::coCapture([this, originalTime = scheduledTime]() -> kj::Promise { kj::Date scheduledTime = originalTime; - for (auto i : kj::zeroTo(WorkerInterface::ALARM_RETRY_MAX_TRIES)) { + for (auto i: kj::zeroTo(WorkerInterface::ALARM_RETRY_MAX_TRIES)) { co_await timerChannel.atTime(scheduledTime); auto result = co_await loopback->getWorker(IoChannelFactory::SubrequestMetadata{}) - ->runAlarm(originalTime, i); + ->runAlarm(originalTime, i); if (result.outcome == EventOutcome::OK || !result.retry) { break; @@ -3462,9 +3458,9 @@ kj::Promise Worker::Actor::scheduleAlarm( } KJ_IF_SOME(scheduledAlarm, impl->maybeScheduledAlarm) { - // We had a previously scheduled alarm, let's cancel it. - scheduledAlarm.resultFulfiller.cancel(); - impl->maybeScheduledAlarm = kj::none; + // We had a previously scheduled alarm, let's cancel it. + scheduledAlarm.resultFulfiller.cancel(); + impl->maybeScheduledAlarm = kj::none; } KJ_IASSERT(impl->maybeScheduledAlarm == kj::none); @@ -3473,8 +3469,8 @@ kj::Promise Worker::Actor::scheduleAlarm( // Probably don't need to use kj::coCapture for this but doing so just to be on the // safe side... - auto whenCanceled = (kj::coCapture([&scheduledAlarm]() - -> kj::Promise { + auto whenCanceled = + (kj::coCapture([&scheduledAlarm]() -> kj::Promise { // We've been cancelled, so return that result. Note that we cannot be resolved any other // way until we return an AlarmFulfiller below. co_return co_await scheduledAlarm.resultPromise; @@ -3507,7 +3503,8 @@ kj::Promise Worker::Actor::handleAlarm( .scheduledTime = scheduledAlarm.scheduledTime, .resultPromise = kj::mv(scheduledAlarm.resultPromise), }); - impl->runningAlarmTask = scheduledAlarm.cleanupPromise.attach(kj::defer([&impl=*impl](){ + impl->runningAlarmTask = scheduledAlarm.cleanupPromise + .attach(kj::defer([&impl = *impl]() { // As soon as we get fulfilled or rejected, let's unset this alarm as the running alarm. // // NOTE: We could get here during `Actor`'s destructor, which in turn calls `Actor::Impl`'s @@ -3515,7 +3512,7 @@ kj::Promise Worker::Actor::handleAlarm( // is already nulled out (the pointer gets nulled before the destructor runs). This is why we // captured `impl` by reference above, rather than capturing `this`. impl.maybeRunningAlarm = kj::none; - })).eagerlyEvaluate([](kj::Exception&& e){ + })).eagerlyEvaluate([](kj::Exception&& e) { LOG_EXCEPTION("actorAlarmCleanup", e); }).fork(); co_return kj::mv(scheduledAlarm.resultFulfiller); @@ -3559,9 +3556,7 @@ OutputGate& Worker::Actor::getOutputGate() { } kj::Maybe Worker::Actor::getIoContext() { - return impl->ioContext.map([](kj::Own& rc) -> IoContext& { - return *rc; - }); + return impl->ioContext.map([](kj::Own& rc) -> IoContext& { return *rc; }); } void Worker::Actor::setIoContext(kj::Own context) { @@ -3572,16 +3567,14 @@ void Worker::Actor::setIoContext(kj::Own context) { } auto& limitEnforcer = context->getLimitEnforcer(); impl->ioContext = kj::mv(context); - impl->metricsFlushLoopTask = impl->metrics->flushLoop(impl->timerChannel, limitEnforcer) - .eagerlyEvaluate([](kj::Exception&& e) { - LOG_EXCEPTION("actorMetricsFlushLoop", e); - }); + impl->metricsFlushLoopTask = + impl->metrics->flushLoop(impl->timerChannel, limitEnforcer) + .eagerlyEvaluate([](kj::Exception&& e) { LOG_EXCEPTION("actorMetricsFlushLoop", e); }); } kj::Maybe Worker::Actor::getHibernationManager() { - return impl->hibernationManager.map([](kj::Own& hib) -> HibernationManager& { - return *hib; - }); + return impl->hibernationManager.map( + [](kj::Own& hib) -> HibernationManager& { return *hib; }); } void Worker::Actor::setHibernationManager(kj::Own hib) { @@ -3614,13 +3607,14 @@ uint Worker::Isolate::getLockSuccessCount() const { return __atomic_load_n(&impl->lockSuccessCount, __ATOMIC_RELAXED); } -kj::Own Worker::Isolate::newScript( - kj::StringPtr scriptId, Script::Source source, - IsolateObserver::StartType startType, bool logNewScript, +kj::Own Worker::Isolate::newScript(kj::StringPtr scriptId, + Script::Source source, + IsolateObserver::StartType startType, + bool logNewScript, kj::Maybe errorReporter) const { // Script doesn't already exist, so compile it. - return kj::atomicRefcounted"_kj)); + auto url = KJ_ASSERT_NONNULL(Url::tryParse("data:text/html,"_kj)); KJ_ASSERT(url.getProtocol() == "data:"_kj); KJ_ASSERT(url.getPathname() == "text/html,"_kj); } @@ -3124,9 +2972,8 @@ KJ_TEST("Relative URLs") { } { - auto url = - KJ_ASSERT_NONNULL(Url::tryParse("../../../../../././../../././../.././abc"_kj, - "https://abc:def@example.org:81/a/b/c?query#fragment"_kj)); + auto url = KJ_ASSERT_NONNULL(Url::tryParse("../../../../../././../../././../.././abc"_kj, + "https://abc:def@example.org:81/a/b/c?query#fragment"_kj)); KJ_ASSERT(url.getPathname() == "/abc"_kj); } @@ -3188,4 +3035,3 @@ KJ_TEST("Normalize path for comparison and cloning") { } // namespace } // namespace workerd::jsg::test - diff --git a/src/workerd/jsg/url.c++ b/src/workerd/jsg/url.c++ index 1cf223ad007..13e861c2e72 100644 --- a/src/workerd/jsg/url.c++ +++ b/src/workerd/jsg/url.c++ @@ -2,7 +2,7 @@ #include extern "C" { - #include "ada_c.h" +#include "ada_c.h" } #include "ada.h" #include @@ -20,16 +20,17 @@ extern "C" { namespace workerd::jsg { namespace { -class AdaOwnedStringDisposer : public kj::ArrayDisposer { +class AdaOwnedStringDisposer: public kj::ArrayDisposer { public: static const AdaOwnedStringDisposer INSTANCE; protected: - void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount, - size_t capacity, void (*destroyElement)(void*)) const { - ada_owned_string data = { - static_cast(firstElement), - elementCount }; + void disposeImpl(void* firstElement, + size_t elementSize, + size_t elementCount, + size_t capacity, + void (*destroyElement)(void*)) const { + ada_owned_string data = {static_cast(firstElement), elementCount}; ada_free_owned_string(data); } }; @@ -53,11 +54,10 @@ kj::Array normalizePathEncoding(kj::ArrayPtr pathname) { // through ourselves. This is simple enough, tho. We'll percent decode as we go, // re-encode the pieces and then join them back together with %2F. - static constexpr auto findNext = [](std::string_view input) - -> kj::Maybe { + static constexpr auto findNext = [](std::string_view input) -> kj::Maybe { size_t pos = input.find("%2", 0); if (pos != std::string_view::npos) { - if (input[pos+2] == 'f' || input[pos+2] == 'F') { + if (input[pos + 2] == 'f' || input[pos + 2] == 'F') { return pos; } } @@ -85,10 +85,12 @@ kj::Array normalizePathEncoding(kj::ArrayPtr pathname) { std::string res; bool first = true; - for (auto& part : parts) { + for (auto& part: parts) { auto encoded = ada::unicode::percent_encode(part, ada::character_sets::PATH_PERCENT_ENCODE); - if (!first) res += "%2F"; - else first = false; + if (!first) + res += "%2F"; + else + first = false; res += encoded; } @@ -99,7 +101,7 @@ kj::Array normalizePathEncoding(kj::ArrayPtr pathname) { } // namespace -Url::Url(kj::Own inner) : inner(kj::mv(inner)) {} +Url::Url(kj::Own inner): inner(kj::mv(inner)) {} bool Url::operator==(const Url& other) const { return getHref() == other.getHref(); @@ -123,41 +125,37 @@ bool Url::equal(const Url& other, EquivalenceOption option) const { } // If we are ignoring fragments, we'll compare each component separately: - return (other.getProtocol() == getProtocol()) && - (other.getHost() == getHost()) && - (other.getUsername() == getUsername()) && - (other.getPassword() == getPassword()) && - (otherPathname == thisPathname) && - (((option & EquivalenceOption::IGNORE_SEARCH) == EquivalenceOption::IGNORE_SEARCH) ? - true : other.getSearch() == getSearch()) && - (((option & EquivalenceOption::IGNORE_FRAGMENTS) == EquivalenceOption::IGNORE_FRAGMENTS) ? - true : other.getHash() == getHash()); - } + return (other.getProtocol() == getProtocol()) && (other.getHost() == getHost()) && + (other.getUsername() == getUsername()) && (other.getPassword() == getPassword()) && + (otherPathname == thisPathname) && + (((option & EquivalenceOption::IGNORE_SEARCH) == EquivalenceOption::IGNORE_SEARCH) + ? true + : other.getSearch() == getSearch()) && + (((option & EquivalenceOption::IGNORE_FRAGMENTS) == EquivalenceOption::IGNORE_FRAGMENTS) + ? true + : other.getHash() == getHash()); +} bool Url::canParse(kj::StringPtr input, kj::Maybe base) { return canParse(kj::ArrayPtr(input), base); } -bool Url::canParse(kj::ArrayPtr input, - kj::Maybe> base) { +bool Url::canParse(kj::ArrayPtr input, kj::Maybe> base) { KJ_IF_SOME(b, base) { - return ada_can_parse_with_base(input.begin(), input.size(), - b.begin(), b.size()); + return ada_can_parse_with_base(input.begin(), input.size(), b.begin(), b.size()); } return ada_can_parse(input.begin(), input.size()); } -kj::Maybe Url::tryParse(kj::StringPtr input, - kj::Maybe base) { +kj::Maybe Url::tryParse(kj::StringPtr input, kj::Maybe base) { return tryParse(kj::ArrayPtr(input), base); } -kj::Maybe Url::tryParse(kj::ArrayPtr input, - kj::Maybe> base) { +kj::Maybe Url::tryParse( + kj::ArrayPtr input, kj::Maybe> base) { ada_url result = nullptr; KJ_IF_SOME(b, base) { - result = ada_parse_with_base(input.begin(), input.size(), - b.begin(), b.size()); + result = ada_parse_with_base(input.begin(), input.size(), b.begin(), b.size()); } else { result = ada_parse(input.begin(), input.size()); } @@ -225,9 +223,7 @@ kj::ArrayPtr Url::getProtocol() const { kj::Array Url::getOrigin() const { ada_owned_string result = ada_get_origin(getInner(inner)); return kj::Array( - const_cast(result.data), - result.length, - AdaOwnedStringDisposer::INSTANCE); + const_cast(result.data), result.length, AdaOwnedStringDisposer::INSTANCE); } bool Url::setHref(kj::ArrayPtr value) { @@ -309,18 +305,12 @@ Url Url::clone(EquivalenceOption option) const { kj::Array Url::idnToUnicode(kj::ArrayPtr value) { ada_owned_string result = ada_idna_to_unicode(value.begin(), value.size()); - return kj::Array( - result.data, - result.length, - AdaOwnedStringDisposer::INSTANCE); + return kj::Array(result.data, result.length, AdaOwnedStringDisposer::INSTANCE); } kj::Array Url::idnToAscii(kj::ArrayPtr value) { ada_owned_string result = ada_idna_to_ascii(value.begin(), value.size()); - return kj::Array( - result.data, - result.length, - AdaOwnedStringDisposer::INSTANCE); + return kj::Array(result.data, result.length, AdaOwnedStringDisposer::INSTANCE); } kj::Maybe Url::tryResolve(kj::ArrayPtr input) const { @@ -349,9 +339,9 @@ kj::Own emptySearchParams() { } } // namespace -UrlSearchParams::UrlSearchParams() : inner(emptySearchParams()) {} +UrlSearchParams::UrlSearchParams(): inner(emptySearchParams()) {} -UrlSearchParams::UrlSearchParams(kj::Own inner) : inner(kj::mv(inner)) {} +UrlSearchParams::UrlSearchParams(kj::Own inner): inner(kj::mv(inner)) {} bool UrlSearchParams::operator==(const UrlSearchParams& other) const { return toStr() == other.toStr(); @@ -368,55 +358,52 @@ size_t UrlSearchParams::size() const { } void UrlSearchParams::append(kj::ArrayPtr key, kj::ArrayPtr value) { - ada_search_params_append(getInner(inner), - key.begin(), key.size(), - value.begin(), value.size()); + ada_search_params_append( + getInner(inner), key.begin(), key.size(), value.begin(), value.size()); } void UrlSearchParams::set(kj::ArrayPtr key, kj::ArrayPtr value) { - ada_search_params_set(getInner(inner), - key.begin(), key.size(), - value.begin(), value.size()); + ada_search_params_set( + getInner(inner), key.begin(), key.size(), value.begin(), value.size()); } -void UrlSearchParams::delete_(kj::ArrayPtr key, - kj::Maybe> maybeValue) { +void UrlSearchParams::delete_( + kj::ArrayPtr key, kj::Maybe> maybeValue) { KJ_IF_SOME(value, maybeValue) { - ada_search_params_remove_value(getInner(inner), - key.begin(), key.size(), - value.begin(), value.size()); + ada_search_params_remove_value(getInner(inner), key.begin(), key.size(), + value.begin(), value.size()); } else { ada_search_params_remove(getInner(inner), key.begin(), key.size()); } } -bool UrlSearchParams::has(kj::ArrayPtr key, - kj::Maybe> maybeValue) const { +bool UrlSearchParams::has( + kj::ArrayPtr key, kj::Maybe> maybeValue) const { KJ_IF_SOME(value, maybeValue) { - return ada_search_params_has_value(getInner(inner), - key.begin(), key.size(), - value.begin(), value.size()); + return ada_search_params_has_value(getInner(inner), key.begin(), + key.size(), value.begin(), value.size()); } else { return ada_search_params_has(getInner(inner), key.begin(), key.size()); } } kj::Maybe> UrlSearchParams::get(kj::ArrayPtr key) const { - auto result = ada_search_params_get(getInner(inner), key.begin(), key.size()); + auto result = + ada_search_params_get(getInner(inner), key.begin(), key.size()); if (result.data == nullptr) return kj::none; return kj::ArrayPtr(result.data, result.length); } kj::Array> UrlSearchParams::getAll(kj::ArrayPtr key) const { - ada_strings results = ada_search_params_get_all(getInner(inner), - key.begin(), key.size()); + ada_strings results = + ada_search_params_get_all(getInner(inner), key.begin(), key.size()); size_t size = ada_strings_size(results); kj::Vector> items(size); for (size_t n = 0; n < size; n++) { auto item = ada_strings_get(results, n); items.add(kj::ArrayPtr(item.data, item.length)); } - return items.releaseAsArray().attach(kj::defer([results](){ada_free_strings(results);})); + return items.releaseAsArray().attach(kj::defer([results]() { ada_free_strings(results); })); } void UrlSearchParams::sort() { @@ -425,56 +412,50 @@ void UrlSearchParams::sort() { UrlSearchParams::KeyIterator UrlSearchParams::getKeys() const { return KeyIterator(kj::disposeWith( - ada_search_params_get_keys(getInner(inner)))); + ada_search_params_get_keys(getInner(inner)))); } UrlSearchParams::ValueIterator UrlSearchParams::getValues() const { return ValueIterator(kj::disposeWith( - ada_search_params_get_values(getInner(inner)))); + ada_search_params_get_values(getInner(inner)))); } UrlSearchParams::EntryIterator UrlSearchParams::getEntries() const { return EntryIterator(kj::disposeWith( - ada_search_params_get_entries(getInner(inner)))); + ada_search_params_get_entries(getInner(inner)))); } kj::Array UrlSearchParams::toStr() const { ada_owned_string result = ada_search_params_to_string(getInner(inner)); - return kj::Array( - result.data, - result.length, - AdaOwnedStringDisposer::INSTANCE); + return kj::Array(result.data, result.length, AdaOwnedStringDisposer::INSTANCE); } -UrlSearchParams::KeyIterator::KeyIterator(kj::Own inner) : inner(kj::mv(inner)) {} +UrlSearchParams::KeyIterator::KeyIterator(kj::Own inner): inner(kj::mv(inner)) {} bool UrlSearchParams::KeyIterator::hasNext() const { - return ada_search_params_keys_iter_has_next( - getInner(inner)); + return ada_search_params_keys_iter_has_next(getInner(inner)); } kj::Maybe> UrlSearchParams::KeyIterator::next() const { if (!hasNext()) return kj::none; - auto next = ada_search_params_keys_iter_next( - getInner(inner)); + auto next = ada_search_params_keys_iter_next(getInner(inner)); return kj::ArrayPtr(next.data, next.length); } -UrlSearchParams::ValueIterator::ValueIterator(kj::Own inner) : inner(kj::mv(inner)) {} +UrlSearchParams::ValueIterator::ValueIterator(kj::Own inner): inner(kj::mv(inner)) {} bool UrlSearchParams::ValueIterator::hasNext() const { - return ada_search_params_values_iter_has_next( - getInner(inner)); + return ada_search_params_values_iter_has_next(getInner(inner)); } kj::Maybe> UrlSearchParams::ValueIterator::next() const { if (!hasNext()) return kj::none; - auto next = ada_search_params_values_iter_next( - getInner(inner)); + auto next = + ada_search_params_values_iter_next(getInner(inner)); return kj::ArrayPtr(next.data, next.length); } -UrlSearchParams::EntryIterator::EntryIterator(kj::Own inner) : inner(kj::mv(inner)) {} +UrlSearchParams::EntryIterator::EntryIterator(kj::Own inner): inner(kj::mv(inner)) {} bool UrlSearchParams::EntryIterator::hasNext() const { return ada_search_params_entries_iter_has_next( @@ -483,9 +464,9 @@ bool UrlSearchParams::EntryIterator::hasNext() const { kj::Maybe UrlSearchParams::EntryIterator::next() const { if (!hasNext()) return kj::none; - auto next = ada_search_params_entries_iter_next( - getInner(inner)); - return Entry { + auto next = + ada_search_params_entries_iter_next(getInner(inner)); + return Entry{ .key = kj::ArrayPtr(next.key.data, next.key.length), .value = kj::ArrayPtr(next.value.data, next.value.length), }; @@ -500,20 +481,23 @@ constexpr auto MODIFIER_OPTIONAL = "?"_kjc; constexpr auto MODIFIER_ZERO_OR_MORE = "*"_kjc; constexpr auto MODIFIER_ONE_OR_MORE = "+"_kjc; -inline bool isAsciiDigit(char c) { return c >= '0' && c <= '9'; }; +inline bool isAsciiDigit(char c) { + return c >= '0' && c <= '9'; +}; inline bool isHexDigit(char c) { // Check if `c` is the ASCII code of a hexadecimal digit. return isAsciiDigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'); } -inline bool isAscii(char codepoint) { return codepoint >= 0x00 && codepoint <= 0x7f; }; +inline bool isAscii(char codepoint) { + return codepoint >= 0x00 && codepoint <= 0x7f; +}; inline bool isForbiddenHostCodepoint(char c) { - return c == 0x00 || c == 0x09 /* Tab */ || c == 0x0a /* LF */ || c == 0x0d /* CR */ || - c == ' ' || c == '#' || c == '%' || c == '/' || c == ':' || - c == '<' || c == '>' || c == '?' || c == '@' || c == '[' || c == '\\' || c == ']' || - c == '^' || c == '|'; + return c == 0x00 || c == 0x09 /* Tab */ || c == 0x0a /* LF */ || c == 0x0d /* CR */ || c == ' ' || + c == '#' || c == '%' || c == '/' || c == ':' || c == '<' || c == '>' || c == '?' || + c == '@' || c == '[' || c == '\\' || c == ']' || c == '^' || c == '|'; }; // This is not meant to be a comprehensive validation that the hostname is @@ -535,14 +519,11 @@ inline bool isValidHostnameInput(kj::StringPtr input) { inline bool isValidCodepoint(uint32_t codepoint, bool first) { // https://tc39.es/ecma262/#prod-IdentifierStart if (first) { - return codepoint == '$' || - codepoint == '_' || - u_hasBinaryProperty(codepoint, UCHAR_ID_START); - } - return codepoint == '$' || - codepoint == 0x200C || // Zero-width non-joiner - codepoint == 0x200D || // Zero-width joiner - u_hasBinaryProperty(codepoint, UCHAR_ID_CONTINUE); + return codepoint == '$' || codepoint == '_' || u_hasBinaryProperty(codepoint, UCHAR_ID_START); + } + return codepoint == '$' || codepoint == 0x200C || // Zero-width non-joiner + codepoint == 0x200D || // Zero-width joiner + u_hasBinaryProperty(codepoint, UCHAR_ID_CONTINUE); }; inline kj::Maybe strFromMaybePtr(const kj::Maybe& ptr) { @@ -551,8 +532,8 @@ inline kj::Maybe strFromMaybePtr(const kj::Maybe& ptr using Canonicalizer = kj::Maybe(kj::StringPtr, kj::Maybe); -kj::Maybe canonicalizeProtocol(kj::StringPtr protocol, - kj::Maybe = kj::none) { +kj::Maybe canonicalizeProtocol( + kj::StringPtr protocol, kj::Maybe = kj::none) { // @see https://wicg.github.io/urlpattern/#canonicalize-a-protocol if (protocol.size() == 0) return kj::str(); auto input = kj::str(protocol, "://dummy.test"); @@ -563,8 +544,8 @@ kj::Maybe canonicalizeProtocol(kj::StringPtr protocol, return kj::none; } -kj::Maybe canonicalizeUsername(kj::StringPtr username, - kj::Maybe = kj::none) { +kj::Maybe canonicalizeUsername( + kj::StringPtr username, kj::Maybe = kj::none) { // @see https://wicg.github.io/urlpattern/#canonicalize-a-username if (username.size() == 0) return kj::str(); auto url = KJ_ASSERT_NONNULL(Url::tryParse("fake://dummy.test"_kj)); @@ -572,8 +553,8 @@ kj::Maybe canonicalizeUsername(kj::StringPtr username, return kj::str(url.getUsername()); } -kj::Maybe canonicalizePassword(kj::StringPtr password, - kj::Maybe = kj::none) { +kj::Maybe canonicalizePassword( + kj::StringPtr password, kj::Maybe = kj::none) { // @see https://wicg.github.io/urlpattern/#canonicalize-a-password if (password.size() == 0) return kj::str(); auto url = KJ_ASSERT_NONNULL(Url::tryParse("fake://dummy.test"_kj)); @@ -581,8 +562,8 @@ kj::Maybe canonicalizePassword(kj::StringPtr password, return kj::str(url.getPassword()); } -kj::Maybe canonicalizeHostname(kj::StringPtr hostname, - kj::Maybe = kj::none) { +kj::Maybe canonicalizeHostname( + kj::StringPtr hostname, kj::Maybe = kj::none) { // @see https://wicg.github.io/urlpattern/#canonicalize-a-hostname if (hostname.size() == 0) return kj::str(); auto url = KJ_ASSERT_NONNULL(Url::tryParse("fake://dummy.test"_kj)); @@ -591,12 +572,11 @@ kj::Maybe canonicalizeHostname(kj::StringPtr hostname, return kj::str(url.getHostname()); } -kj::Maybe canonicalizeIpv6Hostname(kj::StringPtr hostname, - kj::Maybe = kj::none) { +kj::Maybe canonicalizeIpv6Hostname( + kj::StringPtr hostname, kj::Maybe = kj::none) { // @see https://wicg.github.io/urlpattern/#canonicalize-an-ipv6-hostname - if (!std::all_of(hostname.begin(), hostname.end(), [](char c) { - return isHexDigit(c) || c == '[' || c == ']' || c == ':'; - })) { + if (!std::all_of(hostname.begin(), hostname.end(), + [](char c) { return isHexDigit(c) || c == '[' || c == ']' || c == ':'; })) { return kj::none; } return kj::str(hostname); @@ -613,8 +593,8 @@ kj::Maybe canonicalizePort(kj::StringPtr port, kj::Maybe canonicalizePathname(kj::StringPtr pathname, - kj::Maybe = kj::none) { +kj::Maybe canonicalizePathname( + kj::StringPtr pathname, kj::Maybe = kj::none) { // @see https://wicg.github.io/urlpattern/#canonicalize-a-pathname if (pathname.size() == 0) return kj::str(); bool leadingSlash = pathname[0] == '/'; @@ -626,8 +606,8 @@ kj::Maybe canonicalizePathname(kj::StringPtr pathname, return kj::none; } -kj::Maybe canonicalizeOpaquePathname(kj::StringPtr pathname, - kj::Maybe = kj::none) { +kj::Maybe canonicalizeOpaquePathname( + kj::StringPtr pathname, kj::Maybe = kj::none) { // @see https://wicg.github.io/urlpattern/#canonicalize-an-opaque-pathname if (pathname.size() == 0) return kj::str(); auto str = kj::str("fake:", pathname); @@ -635,8 +615,8 @@ kj::Maybe canonicalizeOpaquePathname(kj::StringPtr pathname, return kj::str(url.getPathname()); } -kj::Maybe canonicalizeSearch(kj::StringPtr search, - kj::Maybe = kj::none) { +kj::Maybe canonicalizeSearch( + kj::StringPtr search, kj::Maybe = kj::none) { // @see https://wicg.github.io/urlpattern/#canonicalize-a-search if (search.size() == 0) return kj::str(); auto url = KJ_ASSERT_NONNULL(Url::tryParse("fake://dummy.test"_kj)); @@ -644,8 +624,7 @@ kj::Maybe canonicalizeSearch(kj::StringPtr search, return url.getSearch().size() > 0 ? kj::str(url.getSearch().slice(1)) : kj::str(); } -kj::Maybe canonicalizeHash(kj::StringPtr hash, - kj::Maybe = kj::none) { +kj::Maybe canonicalizeHash(kj::StringPtr hash, kj::Maybe = kj::none) { // @see https://wicg.github.io/urlpattern/#canonicalize-a-hash if (hash.size() == 0) return kj::str(); auto url = KJ_ASSERT_NONNULL(Url::tryParse("fake://dummy.test"_kj)); @@ -685,17 +664,16 @@ kj::String escape(kj::ArrayPtr str, auto predicate) { kj::String escapeRegexString(kj::ArrayPtr str) { return escape(str, [](auto c) { - return c == '.' || c == '+' || c == '*' || c == '?' || c == '^' || - c == '$' || c == '{' || c == '}' || c == '(' || c == ')' || - c == '[' || c == ']' || c == '|' || c == '/' || c == '\\'; + return c == '.' || c == '+' || c == '*' || c == '?' || c == '^' || c == '$' || c == '{' || + c == '}' || c == '(' || c == ')' || c == '[' || c == ']' || c == '|' || c == '/' || + c == '\\'; }); } kj::String escapePatternString(kj::ArrayPtr str) { return escape(str, [](auto c) { - return c == '+' || c == '*' || c == '?' || c == ':' || - c == '{' || c == '}' || c == '(' || c == ')' || - c == '\\'; + return c == '+' || c == '*' || c == '?' || c == ':' || c == '{' || c == '}' || c == '(' || + c == ')' || c == '\\'; }); } @@ -752,10 +730,14 @@ struct Part { kj::Maybe modifierToString(const Part::Modifier& modifier) { switch (modifier) { - case Part::Modifier::NONE: return kj::none; - case Part::Modifier::OPTIONAL: return MODIFIER_OPTIONAL; - case Part::Modifier::ZERO_OR_MORE: return MODIFIER_ZERO_OR_MORE; - case Part::Modifier::ONE_OR_MORE: return MODIFIER_ONE_OR_MORE; + case Part::Modifier::NONE: + return kj::none; + case Part::Modifier::OPTIONAL: + return MODIFIER_OPTIONAL; + case Part::Modifier::ZERO_OR_MORE: + return MODIFIER_ZERO_OR_MORE; + case Part::Modifier::ONE_OR_MORE: + return MODIFIER_ONE_OR_MORE; } KJ_UNREACHABLE; } @@ -795,7 +777,7 @@ struct Token { Type type = Type::INVALID_CHAR; size_t index = 0; - kj::OneOf> value = (char) 0; + kj::OneOf> value = (char)0; Part::Modifier modifier = Part::Modifier::NONE; operator kj::String() const { @@ -1136,9 +1118,7 @@ UrlPattern::Result> tokenize(kj::StringPtr input, Token::Policy } UrlPattern::Result> parsePattern( - kj::StringPtr input, - Canonicalizer canonicalizer, - const CompileComponentOptions& options) { + kj::StringPtr input, Canonicalizer canonicalizer, const CompileComponentOptions& options) { kj::Array tokens = nullptr; KJ_SWITCH_ONEOF(tokenize(input, Token::Policy::STRICT)) { KJ_CASE_ONEOF(err, kj::String) { @@ -1171,7 +1151,7 @@ UrlPattern::Result> parsePattern( pendingFixedValue = kj::none; if (value.size() == 0) return true; KJ_IF_SOME(canonical, canonicalizer(value, kj::none)) { - partList.add(Part { + partList.add(Part{ .type = Part::Type::FIXED_TEXT, .modifier = Part::Modifier::NONE, .value = kj::mv(canonical), @@ -1223,28 +1203,23 @@ UrlPattern::Result> parsePattern( }; auto isDuplicateName = [&](kj::StringPtr name) -> bool { - return std::any_of(partList.begin(), partList.end(), - [&name](Part& part) { return part.name == name; }); + return std::any_of( + partList.begin(), partList.end(), [&name](Part& part) { return part.name == name; }); }; auto maybeTokenToModifier = [](kj::Maybe modifierToken) -> Part::Modifier { KJ_IF_SOME(token, modifierToken) { - KJ_DASSERT(token.type == Token::Type::OTHER_MODIFIER || - token.type == Token::Type::ASTERISK); + KJ_DASSERT(token.type == Token::Type::OTHER_MODIFIER || token.type == Token::Type::ASTERISK); return token.modifier; } return Part::Modifier::NONE; }; - auto addPart = [&] - (kj::Maybe maybePrefix, - kj::Maybe nameToken, - kj::Maybe regexOrWildcardToken, - kj::Maybe suffix, - kj::Maybe modifierToken) mutable -> kj::Maybe { + auto addPart = [&](kj::Maybe maybePrefix, kj::Maybe nameToken, + kj::Maybe regexOrWildcardToken, kj::Maybe suffix, + kj::Maybe modifierToken) mutable -> kj::Maybe { auto modifier = maybeTokenToModifier(modifierToken); - if (nameToken == kj::none && - regexOrWildcardToken == kj::none && + if (nameToken == kj::none && regexOrWildcardToken == kj::none && modifier == Part::Modifier::NONE) { KJ_IF_SOME(prefix, maybePrefix) { appendToPendingFixedValue(prefix); @@ -1259,7 +1234,7 @@ UrlPattern::Result> parsePattern( KJ_IF_SOME(prefix, maybePrefix) { if (prefix.size() > 0) { KJ_IF_SOME(canonical, canonicalizer(prefix, kj::none)) { - partList.add(Part { + partList.add(Part{ .type = Part::Type::FIXED_TEXT, .modifier = modifier, .value = kj::mv(canonical), @@ -1317,7 +1292,7 @@ UrlPattern::Result> parsePattern( } } - partList.add(Part { + partList.add(Part{ .type = type, .modifier = modifier, .value = kj::mv(regexValue), @@ -1335,9 +1310,7 @@ UrlPattern::Result> parsePattern( auto regexOrWildcardToken = tryConsumeRegexOrWildcardToken(nameToken); if (nameToken != kj::none || regexOrWildcardToken != kj::none) { - auto maybePrefix = charToken.map([](Token& token) { - return kj::String(token); - }); + auto maybePrefix = charToken.map([](Token& token) { return kj::String(token); }); KJ_IF_SOME(prefix, maybePrefix) { if (prefix.size() > 0) { @@ -1361,8 +1334,8 @@ UrlPattern::Result> parsePattern( return kj::str("Syntax error in URL Pattern"); } auto modifierToken = tryConsumeModifierToken(); - KJ_IF_SOME(err, addPart(kj::mv(maybePrefix), nameToken, regexOrWildcardToken, - kj::none, modifierToken)) { + KJ_IF_SOME(err, + addPart(kj::mv(maybePrefix), nameToken, regexOrWildcardToken, kj::none, modifierToken)) { return kj::mv(err); } continue; @@ -1385,8 +1358,9 @@ UrlPattern::Result> parsePattern( return kj::str("Syntax error in URL Pattern: Missing required close token"); } auto modifierToken = tryConsumeModifierToken(); - KJ_IF_SOME(err, addPart(kj::mv(maybePrefix), nameToken, regexOrWildcardToken, - kj::mv(suffix), modifierToken)) { + KJ_IF_SOME(err, + addPart(kj::mv(maybePrefix), nameToken, regexOrWildcardToken, kj::mv(suffix), + modifierToken)) { return kj::mv(err); } continue; @@ -1404,14 +1378,13 @@ UrlPattern::Result> parsePattern( } RegexAndNameList generateRegexAndNameList( - kj::ArrayPtr partList, - const CompileComponentOptions& options) { + kj::ArrayPtr partList, const CompileComponentOptions& options) { // Worst case is that the nameList is equal to partList, although that will almost never // be the case, so let's be more conservative in what we reserve. kj::Vector nameList(partList.size() / 2); auto regex = kj::strTree("^"); - for (auto& part : partList) { + for (auto& part: partList) { if (part.type == Part::Type::FIXED_TEXT) { auto escaped = escapeRegexString(part.value); if (part.modifier == Part::Modifier::NONE) { @@ -1427,10 +1400,9 @@ RegexAndNameList generateRegexAndNameList( KJ_DASSERT(part.name.size() > 0); nameList.add(kj::mv(part.name)); - auto value = part.type == Part::Type::SEGMENT_WILDCARD ? - kj::str(options.segmentWildcardRegexp) : - part.type == Part::Type::FULL_WILDCARD ? - kj::str(".*") : kj::mv(part.value); + auto value = part.type == Part::Type::SEGMENT_WILDCARD ? kj::str(options.segmentWildcardRegexp) + : part.type == Part::Type::FULL_WILDCARD ? kj::str(".*") + : kj::mv(part.value); if (part.prefix == kj::none && part.suffix == kj::none) { if (part.modifier == Part::Modifier::NONE || part.modifier == Part::Modifier::OPTIONAL) { @@ -1465,7 +1437,7 @@ RegexAndNameList generateRegexAndNameList( } regex = kj::strTree(kj::mv(regex), "(?:", escapedPrefix, "((?:", value, ")(?:", escapedSuffix, - escapedPrefix, "(?:", value, "))*)", escapedSuffix, ")"); + escapedPrefix, "(?:", value, "))*)", escapedSuffix, ")"); if (part.modifier == Part::Modifier::ZERO_OR_MORE) { regex = kj::strTree(kj::mv(regex), MODIFIER_ZERO_OR_MORE); } @@ -1473,14 +1445,14 @@ RegexAndNameList generateRegexAndNameList( regex = kj::strTree(kj::mv(regex), "$"); - return RegexAndNameList { + return RegexAndNameList{ .regex = regex.flatten(), .names = nameList.releaseAsArray(), }; } -kj::String generatePatternString(kj::ArrayPtr partList, - const CompileComponentOptions& options) { +kj::String generatePatternString( + kj::ArrayPtr partList, const CompileComponentOptions& options) { auto pattern = kj::strTree(); Part* previousPart = nullptr; Part* nextPart = nullptr; @@ -1521,14 +1493,9 @@ kj::String generatePatternString(kj::ArrayPtr partList, } } } - if (!needsGrouping && - prefixIsEmpty && - customName && - part.type == Part::Type::SEGMENT_WILDCARD && - part.modifier == Part::Modifier::NONE && - nextPart != nullptr && - partPrefixEmpty(nextPart) && - partSuffixEmpty(nextPart)) { + if (!needsGrouping && prefixIsEmpty && customName && + part.type == Part::Type::SEGMENT_WILDCARD && part.modifier == Part::Modifier::NONE && + nextPart != nullptr && partPrefixEmpty(nextPart) && partSuffixEmpty(nextPart)) { if (nextPart->type == Part::Type::FIXED_TEXT) { return nextPart->name.size() > 0 && isValidCodepoint(nextPart->name[0], false); } else { @@ -1567,8 +1534,8 @@ kj::String generatePatternString(kj::ArrayPtr partList, // if because in some cases, they may be evaluated before the previousPart != nullptr // check. if (previousPart->type == Part::Type::FIXED_TEXT && - (previousPart->value.size() >0 && - previousPart->value[previousPart->value.size() - 1] == options.prefix.orDefault(0))) { + (previousPart->value.size() > 0 && + previousPart->value[previousPart->value.size() - 1] == options.prefix.orDefault(0))) { needsGrouping = true; } } @@ -1587,20 +1554,14 @@ kj::String generatePatternString(kj::ArrayPtr partList, subPattern = kj::strTree(kj::mv(subPattern), "(", options.segmentWildcardRegexp, ")"); } else if (part.type == Part::Type::FULL_WILDCARD) { if (!customName && - ( - previousPart == nullptr || - previousPart->type == Part::Type::FIXED_TEXT || - previousPart->modifier != Part::Modifier::NONE || - needsGrouping || - !prefixIsEmpty)) { + (previousPart == nullptr || previousPart->type == Part::Type::FIXED_TEXT || + previousPart->modifier != Part::Modifier::NONE || needsGrouping || !prefixIsEmpty)) { subPattern = kj::strTree(kj::mv(subPattern), MODIFIER_ZERO_OR_MORE); } else { subPattern = kj::strTree(kj::mv(subPattern), "(.*)"); } } - if (part.type == Part::Type::SEGMENT_WILDCARD && - customName && - partSuffixIsValid(&part)) { + if (part.type == Part::Type::SEGMENT_WILDCARD && customName && partSuffixIsValid(&part)) { subPattern = kj::strTree(kj::mv(subPattern), "\\"); } @@ -1621,8 +1582,7 @@ kj::String generatePatternString(kj::ArrayPtr partList, return pattern.flatten(); } -UrlPattern::Result tryCompileComponent( - kj::Maybe& input, +UrlPattern::Result tryCompileComponent(kj::Maybe& input, Canonicalizer canonicalizer, const CompileComponentOptions& options) { auto pattern = kj::mv(input).orDefault([] { return kj::str(MODIFIER_ZERO_OR_MORE); }); @@ -1633,28 +1593,24 @@ UrlPattern::Result tryCompileComponent( KJ_CASE_ONEOF(partList, kj::Array) { auto pattern = generatePatternString(partList, options); auto regexAndNameList = generateRegexAndNameList(partList, options); - return UrlPattern::Component(kj::mv(pattern), - kj::mv(regexAndNameList.regex), - kj::mv(regexAndNameList.names)); + return UrlPattern::Component( + kj::mv(pattern), kj::mv(regexAndNameList.regex), kj::mv(regexAndNameList.names)); } } KJ_UNREACHABLE; } -bool protocolComponentMatchesSpecialScheme(kj::StringPtr regex, - const UrlPattern::CompileOptions& options) { +bool protocolComponentMatchesSpecialScheme( + kj::StringPtr regex, const UrlPattern::CompileOptions& options) { std::regex rx(regex.begin(), regex.size()); std::cmatch cmatch; - return std::regex_match("http", cmatch, rx) || - std::regex_match("https", cmatch, rx) || - std::regex_match("ws", cmatch, rx) || - std::regex_match("wss", cmatch, rx) || - std::regex_match("ftp", cmatch, rx); + return std::regex_match("http", cmatch, rx) || std::regex_match("https", cmatch, rx) || + std::regex_match("ws", cmatch, rx) || std::regex_match("wss", cmatch, rx) || + std::regex_match("ftp", cmatch, rx); } UrlPattern::Result tryParseConstructorString( - kj::StringPtr input, - const UrlPattern::CompileOptions& options) { + kj::StringPtr input, const UrlPattern::CompileOptions& options) { enum class State { INIT, PROTOCOL, @@ -1675,7 +1631,7 @@ UrlPattern::Result tryParseConstructorString( size_t ipv6Depth = 0; bool protocolMatchesSpecialScheme = false; - UrlPattern::Init result { + UrlPattern::Init result{ .baseUrl = strFromMaybePtr(options.baseUrl), }; @@ -1769,35 +1725,24 @@ UrlPattern::Result tryParseConstructorString( const auto isNonSpecialPatternChar = [&](auto iter, char c) { KJ_DASSERT(tokens.begin() <= iter && iter < tokens.end()); Token& token = *iter; - return (token.type == Token::Type::CHAR || - token.type == Token::Type::ESCAPED_CHAR || - token.type == Token::Type::INVALID_CHAR) && - token == c; + return (token.type == Token::Type::CHAR || token.type == Token::Type::ESCAPED_CHAR || + token.type == Token::Type::INVALID_CHAR) && + token == c; }; - const auto isProtocolSuffix = [&]() { - return isNonSpecialPatternChar(it, ':'); - }; + const auto isProtocolSuffix = [&]() { return isNonSpecialPatternChar(it, ':'); }; const auto nextIsAuthoritySlashes = [&]() { return isNonSpecialPatternChar(it + 1, '/') && isNonSpecialPatternChar(it + 2, '/'); }; - const auto isIdentityTerminator = [&]() { - return isNonSpecialPatternChar(it, '@'); - }; + const auto isIdentityTerminator = [&]() { return isNonSpecialPatternChar(it, '@'); }; - const auto isPasswordPrefix = [&]() { - return isNonSpecialPatternChar(it, ':'); - }; + const auto isPasswordPrefix = [&]() { return isNonSpecialPatternChar(it, ':'); }; - const auto isPortPrefix = [&]() { - return isNonSpecialPatternChar(it, ':'); - }; + const auto isPortPrefix = [&]() { return isNonSpecialPatternChar(it, ':'); }; - const auto isPathnameStart = [&]() { - return isNonSpecialPatternChar(it, '/'); - }; + const auto isPathnameStart = [&]() { return isNonSpecialPatternChar(it, '/'); }; const auto isSearchPrefix = [&]() { if (isNonSpecialPatternChar(it, '?')) { @@ -1809,36 +1754,24 @@ UrlPattern::Result tryParseConstructorString( if (it == tokens.begin()) return true; auto& previousToken = *(it - 1); - return previousToken.type != Token::Type::NAME && - previousToken.type != Token::Type::REGEXP && - previousToken.type != Token::Type::CLOSE && - previousToken.type != Token::Type::ASTERISK; + return previousToken.type != Token::Type::NAME && previousToken.type != Token::Type::REGEXP && + previousToken.type != Token::Type::CLOSE && previousToken.type != Token::Type::ASTERISK; }; - const auto isHashPrefix = [&]() { - return isNonSpecialPatternChar(it, '#'); - }; + const auto isHashPrefix = [&]() { return isNonSpecialPatternChar(it, '#'); }; - const auto isGroupOpen = [&]() { - return it->type == Token::Type::OPEN; - }; + const auto isGroupOpen = [&]() { return it->type == Token::Type::OPEN; }; - const auto isGroupClose = [&]() { - return it->type == Token::Type::CLOSE; - }; + const auto isGroupClose = [&]() { return it->type == Token::Type::CLOSE; }; - const auto isIPv6Open = [&]() { - return isNonSpecialPatternChar(it, '['); - }; + const auto isIPv6Open = [&]() { return isNonSpecialPatternChar(it, '['); }; - const auto isIPv6Close = [&]() { - return isNonSpecialPatternChar(it, ']'); - }; + const auto isIPv6Close = [&]() { return isNonSpecialPatternChar(it, ']'); }; const auto computeMatchesSpecialScheme = [&] { kj::Maybe input = makeComponentString(); - KJ_SWITCH_ONEOF(tryCompileComponent(input, &canonicalizeProtocol, - CompileComponentOptions::DEFAULT)) { + KJ_SWITCH_ONEOF(tryCompileComponent( + input, &canonicalizeProtocol, CompileComponentOptions::DEFAULT)) { KJ_CASE_ONEOF(err, kj::String) { // Ignore any errors at this point. If the component is invalid we'll // catch it later. @@ -1915,20 +1848,27 @@ UrlPattern::Result tryParseConstructorString( if (isProtocolSuffix()) { computeMatchesSpecialScheme(); if (protocolMatchesSpecialScheme) result.pathname = kj::str("/"); - if (nextIsAuthoritySlashes()) changeState(State::AUTHORITY, 3); - else if (protocolMatchesSpecialScheme) changeState(State::AUTHORITY, 1); - else changeState(State::PATHNAME, 1); + if (nextIsAuthoritySlashes()) + changeState(State::AUTHORITY, 3); + else if (protocolMatchesSpecialScheme) + changeState(State::AUTHORITY, 1); + else + changeState(State::PATHNAME, 1); } break; } case State::AUTHORITY: { - if (isIdentityTerminator()) rewind(State::USERNAME); - else if (isPathnameStart() || isSearchPrefix() || isHashPrefix()) rewind(State::HOSTNAME); + if (isIdentityTerminator()) + rewind(State::USERNAME); + else if (isPathnameStart() || isSearchPrefix() || isHashPrefix()) + rewind(State::HOSTNAME); break; } case State::USERNAME: { - if (isPasswordPrefix()) changeState(State::PASSWORD, 1); - else if (isIdentityTerminator()) changeState(State::HOSTNAME, 1); + if (isPasswordPrefix()) + changeState(State::PASSWORD, 1); + else if (isIdentityTerminator()) + changeState(State::HOSTNAME, 1); break; } case State::PASSWORD: { @@ -1936,23 +1876,34 @@ UrlPattern::Result tryParseConstructorString( break; } case State::HOSTNAME: { - if (isIPv6Open()) ipv6Depth++; - else if (isIPv6Close()) ipv6Depth--; - else if (isPortPrefix() && ipv6Depth == 0) changeState(State::PORT, 1); - else if (isPathnameStart()) changeState(State::PATHNAME, 0); - else if (isSearchPrefix()) changeState(State::SEARCH, 1); - else if (isHashPrefix()) changeState(State::HASH, 1); + if (isIPv6Open()) + ipv6Depth++; + else if (isIPv6Close()) + ipv6Depth--; + else if (isPortPrefix() && ipv6Depth == 0) + changeState(State::PORT, 1); + else if (isPathnameStart()) + changeState(State::PATHNAME, 0); + else if (isSearchPrefix()) + changeState(State::SEARCH, 1); + else if (isHashPrefix()) + changeState(State::HASH, 1); break; } case State::PORT: { - if (isPathnameStart()) changeState(State::PATHNAME, 0); - else if (isSearchPrefix()) changeState(State::SEARCH, 1); - else if (isHashPrefix()) changeState(State::HASH, 1); + if (isPathnameStart()) + changeState(State::PATHNAME, 0); + else if (isSearchPrefix()) + changeState(State::SEARCH, 1); + else if (isHashPrefix()) + changeState(State::HASH, 1); break; } case State::PATHNAME: { - if (isSearchPrefix()) changeState(State::SEARCH, 1); - else if (isHashPrefix()) changeState(State::HASH, 1); + if (isSearchPrefix()) + changeState(State::SEARCH, 1); + else if (isHashPrefix()) + changeState(State::HASH, 1); break; } case State::SEARCH: { @@ -1979,22 +1930,19 @@ UrlPattern::Result tryParseConstructorString( } } // namespace -UrlPattern::Component::Component(kj::String pattern, - kj::String regex, - kj::Array names) +UrlPattern::Component::Component(kj::String pattern, kj::String regex, kj::Array names) : pattern(kj::mv(pattern)), regex(kj::mv(regex)), names(kj::mv(names)) {} UrlPattern::Result UrlPattern::tryCompileInit( - UrlPattern::Init init, - const UrlPattern::CompileOptions& options) { + UrlPattern::Init init, const UrlPattern::CompileOptions& options) { kj::Vector components(7); bool matchesSpecialScheme = false; - KJ_SWITCH_ONEOF(tryCompileComponent(init.protocol, &canonicalizeProtocol, - CompileComponentOptions::DEFAULT)) { + KJ_SWITCH_ONEOF(tryCompileComponent( + init.protocol, &canonicalizeProtocol, CompileComponentOptions::DEFAULT)) { KJ_CASE_ONEOF(err, kj::String) { return kj::mv(err); } @@ -2004,9 +1952,9 @@ UrlPattern::Result UrlPattern::tryCompileInit( } } - const auto handleComponent = [&](auto& input, Canonicalizer canonicalizer, - const CompileComponentOptions& options) - -> kj::Maybe { + const auto handleComponent = + [&](auto& input, Canonicalizer canonicalizer, + const CompileComponentOptions& options) -> kj::Maybe { KJ_SWITCH_ONEOF(tryCompileComponent(input, canonicalizer, options)) { KJ_CASE_ONEOF(err, kj::String) { return kj::mv(err); @@ -2019,13 +1967,12 @@ UrlPattern::Result UrlPattern::tryCompileInit( KJ_UNREACHABLE; }; - KJ_IF_SOME(err, handleComponent(init.username, &canonicalizeUsername, - CompileComponentOptions::DEFAULT)) { + KJ_IF_SOME(err, + handleComponent(init.username, &canonicalizeUsername, CompileComponentOptions::DEFAULT)) { return kj::mv(err); } - KJ_IF_SOME(err, handleComponent(init.password, - &canonicalizePassword, - CompileComponentOptions::DEFAULT)) { + KJ_IF_SOME(err, + handleComponent(init.password, &canonicalizePassword, CompileComponentOptions::DEFAULT)) { return kj::mv(err); } @@ -2035,8 +1982,8 @@ UrlPattern::Result UrlPattern::tryCompileInit( hostnameCanonicalizer = &canonicalizeIpv6Hostname; } } - KJ_IF_SOME(err, handleComponent(init.hostname, hostnameCanonicalizer, - CompileComponentOptions::HOSTNAME)) { + KJ_IF_SOME(err, + handleComponent(init.hostname, hostnameCanonicalizer, CompileComponentOptions::HOSTNAME)) { return kj::mv(err); } @@ -2044,26 +1991,25 @@ UrlPattern::Result UrlPattern::tryCompileInit( return kj::mv(err); } - KJ_IF_SOME(err, handleComponent(init.pathname, - matchesSpecialScheme ? &canonicalizePathname : &canonicalizeOpaquePathname, - matchesSpecialScheme ? CompileComponentOptions::PATHNAME : - CompileComponentOptions::DEFAULT)) { + KJ_IF_SOME(err, + handleComponent(init.pathname, + matchesSpecialScheme ? &canonicalizePathname : &canonicalizeOpaquePathname, + matchesSpecialScheme ? CompileComponentOptions::PATHNAME + : CompileComponentOptions::DEFAULT)) { return kj::mv(err); } - KJ_IF_SOME(err, handleComponent(init.search, &canonicalizeSearch, - CompileComponentOptions::DEFAULT)) { + KJ_IF_SOME(err, + handleComponent(init.search, &canonicalizeSearch, CompileComponentOptions::DEFAULT)) { return kj::mv(err); } - KJ_IF_SOME(err, handleComponent(init.hash, &canonicalizeHash, - CompileComponentOptions::DEFAULT)) { + KJ_IF_SOME(err, handleComponent(init.hash, &canonicalizeHash, CompileComponentOptions::DEFAULT)) { return kj::mv(err); } return UrlPattern(components.releaseAsArray(), options.ignoreCase); } UrlPattern::Result UrlPattern::processInit( - UrlPattern::Init init, - kj::Maybe maybeOptions) { + UrlPattern::Init init, kj::Maybe maybeOptions) { auto options = maybeOptions.orDefault({}); Init result; @@ -2103,8 +2049,8 @@ UrlPattern::Result UrlPattern::processInit( } if (options.mode == ProcessInitOptions::Mode::PATTERN) { - KJ_IF_SOME(protocol, chooseStr(kj::mv(init.protocol), options.protocol) - .map([](kj::String&& str) mutable { + KJ_IF_SOME(protocol, + chooseStr(kj::mv(init.protocol), options.protocol).map([](kj::String&& str) mutable { // It's silly but the URL spec always includes the : suffix in the value, // while the URLPattern spec always omits it. Silly specs. return stripSuffixFromProtocol(str.asPtr()); @@ -2173,8 +2119,7 @@ UrlPattern::Result UrlPattern::processInit( // attempting to use it to parse a URL. bool emptyProtocol = protocol == ""; auto str = kj::str((emptyProtocol ? "fake:"_kj : protocol.asPtr()), - (emptyProtocol || protocol.asArray().back() == ':') ? "" : ":", - "//a:b@fake-url"); + (emptyProtocol || protocol.asArray().back() == ':') ? "" : ":", "//a:b@fake-url"); KJ_IF_SOME(parsed, Url::tryParse(str.asPtr())) { // Nice. We have a good protocol component. Let's set the normalized version // on the result and return the parsed URL to use as our temporary. @@ -2225,8 +2170,7 @@ UrlPattern::Result UrlPattern::processInit( result.password = kj::str(url.getPassword()); } KJ_IF_SOME(hostname, chooseStr(kj::mv(init.hostname), options.hostname)) { - if (!isValidHostnameInput(hostname) || - !url.setHostname(hostname.asPtr())) { + if (!isValidHostnameInput(hostname) || !url.setHostname(hostname.asPtr())) { return kj::str("Invalid URL hostname component"); } result.hostname = kj::str(url.getHostname()); @@ -2237,7 +2181,7 @@ UrlPattern::Result UrlPattern::processInit( } if (port.size() == 0) { url.setPort(kj::none); - } else if(!url.setPort(kj::Maybe(port.asPtr()))) { + } else if (!url.setPort(kj::Maybe(port.asPtr()))) { return kj::str("Invalid URL port component"); } result.port = kj::str(url.getPort()); @@ -2297,8 +2241,8 @@ UrlPattern::Result UrlPattern::processInit( KJ_UNREACHABLE; } -UrlPattern::Result UrlPattern::tryCompile(Init init, - kj::Maybe maybeOptions) { +UrlPattern::Result UrlPattern::tryCompile( + Init init, kj::Maybe maybeOptions) { auto options = maybeOptions.orDefault({}); KJ_SWITCH_ONEOF(processInit(kj::mv(init))) { KJ_CASE_ONEOF(err, kj::String) { @@ -2311,8 +2255,8 @@ UrlPattern::Result UrlPattern::tryCompile(Init init, KJ_UNREACHABLE; } -UrlPattern::Result UrlPattern::tryCompile(kj::StringPtr input, - kj::Maybe maybeOptions) { +UrlPattern::Result UrlPattern::tryCompile( + kj::StringPtr input, kj::Maybe maybeOptions) { auto options = maybeOptions.orDefault({}); KJ_SWITCH_ONEOF(tryParseConstructorString(input, options)) { KJ_CASE_ONEOF(err, kj::String) { @@ -2345,6 +2289,6 @@ UrlPattern::UrlPattern(kj::Array components, bool ignoreCase) } // namespace workerd::jsg -const workerd::jsg::Url operator "" _url(const char* str, size_t size) { +const workerd::jsg::Url operator"" _url(const char* str, size_t size) { return KJ_ASSERT_NONNULL(workerd::jsg::Url::tryParse(kj::ArrayPtr(str, size))); } diff --git a/src/workerd/jsg/url.h b/src/workerd/jsg/url.h index 1253e8965d4..224108e776c 100644 --- a/src/workerd/jsg/url.h +++ b/src/workerd/jsg/url.h @@ -47,26 +47,22 @@ class Url final { NORMALIZE_PATH = 1 << 2, }; - bool equal(const Url& other, EquivalenceOption option = EquivalenceOption::DEFAULT) const - KJ_WARN_UNUSED_RESULT; + bool equal(const Url& other, + EquivalenceOption option = EquivalenceOption::DEFAULT) const KJ_WARN_UNUSED_RESULT; // Returns true if the given input can be successfully parsed as a URL. This is generally // more performant than using tryParse and checking for a kj::none result if all you want // to do is verify that the input is parseable. If you actually want to parse and use the // result, use tryParse instead. static bool canParse(kj::ArrayPtr input, - kj::Maybe> base = kj::none) - KJ_WARN_UNUSED_RESULT; - static bool canParse(kj::StringPtr input, - kj::Maybe base = kj::none) - KJ_WARN_UNUSED_RESULT; + kj::Maybe> base = kj::none) KJ_WARN_UNUSED_RESULT; + static bool canParse( + kj::StringPtr input, kj::Maybe base = kj::none) KJ_WARN_UNUSED_RESULT; static kj::Maybe tryParse(kj::ArrayPtr input, - kj::Maybe> base = kj::none) - KJ_WARN_UNUSED_RESULT; - static kj::Maybe tryParse(kj::StringPtr input, - kj::Maybe base = kj::none) - KJ_WARN_UNUSED_RESULT; + kj::Maybe> base = kj::none) KJ_WARN_UNUSED_RESULT; + static kj::Maybe tryParse( + kj::StringPtr input, kj::Maybe base = kj::none) KJ_WARN_UNUSED_RESULT; kj::Array getOrigin() const KJ_WARN_UNUSED_RESULT; kj::ArrayPtr getProtocol() const KJ_LIFETIMEBOUND KJ_WARN_UNUSED_RESULT; @@ -115,13 +111,9 @@ class Url final { static bool isSpecialSchemeDefaultPort(kj::StringPtr protocol, kj::StringPtr port); JSG_MEMORY_INFO(Url) { - tracker.trackFieldWithSize("inner", getProtocol().size() + - getUsername().size() + - getPassword().size() + - getHost().size() + - getPathname().size() + - getHash().size() + - getSearch().size()); + tracker.trackFieldWithSize("inner", + getProtocol().size() + getUsername().size() + getPassword().size() + getHost().size() + + getPathname().size() + getHash().size() + getSearch().size()); } static kj::Array percentDecode(kj::ArrayPtr input); @@ -144,6 +136,7 @@ class UrlSearchParams final { public: bool hasNext() const; kj::Maybe> next() const; + private: KeyIterator(kj::Own inner); kj::Own inner; @@ -153,6 +146,7 @@ class UrlSearchParams final { public: bool hasNext() const; kj::Maybe> next() const; + private: ValueIterator(kj::Own inner); kj::Own inner; @@ -166,6 +160,7 @@ class UrlSearchParams final { }; bool hasNext() const; kj::Maybe next() const; + private: EntryIterator(kj::Own inner); kj::Own inner; @@ -184,15 +179,14 @@ class UrlSearchParams final { size_t size() const; void append(kj::ArrayPtr key, kj::ArrayPtr value); void set(kj::ArrayPtr key, kj::ArrayPtr value); - void delete_(kj::ArrayPtr key, - kj::Maybe> maybeValue = kj::none); + void delete_( + kj::ArrayPtr key, kj::Maybe> maybeValue = kj::none); bool has(kj::ArrayPtr key, - kj::Maybe> maybeValue = kj::none) const - KJ_WARN_UNUSED_RESULT; - kj::Maybe> get(kj::ArrayPtr key) const - KJ_LIFETIMEBOUND KJ_WARN_UNUSED_RESULT; - kj::Array> getAll(kj::ArrayPtr key) const - KJ_LIFETIMEBOUND KJ_WARN_UNUSED_RESULT; + kj::Maybe> maybeValue = kj::none) const KJ_WARN_UNUSED_RESULT; + kj::Maybe> get( + kj::ArrayPtr key) const KJ_LIFETIMEBOUND KJ_WARN_UNUSED_RESULT; + kj::Array> getAll( + kj::ArrayPtr key) const KJ_LIFETIMEBOUND KJ_WARN_UNUSED_RESULT; void sort(); KeyIterator getKeys() const KJ_LIFETIMEBOUND KJ_WARN_UNUSED_RESULT; ValueIterator getValues() const KJ_LIFETIMEBOUND KJ_WARN_UNUSED_RESULT; @@ -237,8 +231,12 @@ class UrlPattern final { Component& operator=(Component&&) = default; KJ_DISALLOW_COPY(Component); - inline kj::StringPtr getPattern() const KJ_LIFETIMEBOUND { return pattern; } - inline kj::StringPtr getRegex() const KJ_LIFETIMEBOUND { return regex; } + inline kj::StringPtr getPattern() const KJ_LIFETIMEBOUND { + return pattern; + } + inline kj::StringPtr getRegex() const KJ_LIFETIMEBOUND { + return regex; + } inline kj::ArrayPtr getNames() const KJ_LIFETIMEBOUND { return names.asPtr(); } @@ -246,7 +244,7 @@ class UrlPattern final { JSG_MEMORY_INFO(Component) { tracker.trackField("pattern", pattern); tracker.trackField("regex", regex); - for (const auto& name : names) { + for (const auto& name: names) { tracker.trackField("name", name); } } @@ -294,9 +292,8 @@ class UrlPattern final { // Processes the given init according to the specified mode and options. // If a kj::String is returned, then processing failed and the string // is the description to include in the error message (if any). - static Result processInit(Init init, - kj::Maybe options = kj::none) - KJ_WARN_UNUSED_RESULT; + static Result processInit( + Init init, kj::Maybe options = kj::none) KJ_WARN_UNUSED_RESULT; struct CompileOptions { // The base URL to use. Only used in the compile(kj::StringPtr, ...) variant. @@ -304,27 +301,45 @@ class UrlPattern final { bool ignoreCase = false; }; - static Result tryCompile(kj::StringPtr, kj::Maybe = kj::none) - KJ_WARN_UNUSED_RESULT; - static Result tryCompile(Init init, kj::Maybe = kj::none) - KJ_WARN_UNUSED_RESULT; + static Result tryCompile( + kj::StringPtr, kj::Maybe = kj::none) KJ_WARN_UNUSED_RESULT; + static Result tryCompile( + Init init, kj::Maybe = kj::none) KJ_WARN_UNUSED_RESULT; UrlPattern(UrlPattern&&) = default; UrlPattern& operator=(UrlPattern&&) = default; KJ_DISALLOW_COPY(UrlPattern); - inline const Component& getProtocol() const KJ_LIFETIMEBOUND { return protocol; } - inline const Component& getUsername() const KJ_LIFETIMEBOUND { return username; } - inline const Component& getPassword() const KJ_LIFETIMEBOUND { return password; } - inline const Component& getHostname() const KJ_LIFETIMEBOUND { return hostname; } - inline const Component& getPort() const KJ_LIFETIMEBOUND { return port; } - inline const Component& getPathname() const KJ_LIFETIMEBOUND { return pathname; } - inline const Component& getSearch() const KJ_LIFETIMEBOUND { return search; } - inline const Component& getHash() const KJ_LIFETIMEBOUND { return hash; } + inline const Component& getProtocol() const KJ_LIFETIMEBOUND { + return protocol; + } + inline const Component& getUsername() const KJ_LIFETIMEBOUND { + return username; + } + inline const Component& getPassword() const KJ_LIFETIMEBOUND { + return password; + } + inline const Component& getHostname() const KJ_LIFETIMEBOUND { + return hostname; + } + inline const Component& getPort() const KJ_LIFETIMEBOUND { + return port; + } + inline const Component& getPathname() const KJ_LIFETIMEBOUND { + return pathname; + } + inline const Component& getSearch() const KJ_LIFETIMEBOUND { + return search; + } + inline const Component& getHash() const KJ_LIFETIMEBOUND { + return hash; + } // If ignoreCase is true, the JavaScript regular expression created for each pattern // must use the `vi` flag. Otherwise, they must use the `v` flag. - inline bool getIgnoreCase() const { return ignoreCase; } + inline bool getIgnoreCase() const { + return ignoreCase; + } JSG_MEMORY_INFO(UrlPattern) { tracker.trackField("protocol", protocol); @@ -356,4 +371,4 @@ class UrlPattern final { // Append _url to a string literal to create a parsed URL. An assert will be triggered // if the value cannot be parsed successfully. -const workerd::jsg::Url operator "" _url(const char* str, size_t size) KJ_WARN_UNUSED_RESULT; +const workerd::jsg::Url operator"" _url(const char* str, size_t size) KJ_WARN_UNUSED_RESULT; diff --git a/src/workerd/jsg/util-test.c++ b/src/workerd/jsg/util-test.c++ index aa2acacd93c..4debd4325f3 100644 --- a/src/workerd/jsg/util-test.c++ +++ b/src/workerd/jsg/util-test.c++ @@ -25,15 +25,14 @@ JSG_DECLARE_ISOLATE_TYPE(FreezeIsolate, FreezeContext); KJ_TEST("recursive freezing") { Evaluator e(v8System); - e.expectEval( - "let obj = { foo: [ { bar: 1 } ] };\n" - "recursivelyFreeze(obj);\n" - // We rely on non-strict mode here to silently discard our mutations. - "obj.foo[0].bar = 2;\n" - "obj.foo[0].baz = 3;\n" - "obj.foo[1] = { qux: 4 };\n" - "obj.bar = {};\n" - "JSON.stringify(obj);\n", + e.expectEval("let obj = { foo: [ { bar: 1 } ] };\n" + "recursivelyFreeze(obj);\n" + // We rely on non-strict mode here to silently discard our mutations. + "obj.foo[0].bar = 2;\n" + "obj.foo[0].baz = 3;\n" + "obj.foo[1] = { qux: 4 };\n" + "obj.bar = {};\n" + "JSON.stringify(obj);\n", "string", "{\"foo\":[{\"bar\":1}]}"); } @@ -66,9 +65,7 @@ KJ_TEST("deep clone") { struct TypeErrorContext: public ContextGlobalObject { auto returnFunctionTakingBox(double value) { - return [value](Lock&, Ref value2) mutable { - return value + value2->value; - }; + return [value](Lock&, Ref value2) mutable { return value + value2->value; }; } JSG_RESOURCE_TYPE(TypeErrorContext) { @@ -80,30 +77,24 @@ JSG_DECLARE_ISOLATE_TYPE(TypeErrorIsolate, TypeErrorContext, NumberBox); KJ_TEST("throw TypeError") { Evaluator e(v8System); - e.expectEval( - "new NumberBox(123).addBox(321)", - "throws", "TypeError: Failed to execute 'addBox' on 'NumberBox': parameter 1 is not of " - "type 'NumberBox'."); - e.expectEval( - "new NumberBox(123).boxed = 321", - "throws", "TypeError: Failed to set the 'boxed' property on 'NumberBox': the provided " - "value is not of type 'NumberBox'."); - e.expectEval( - "NumberBox(123)", - "throws", "TypeError: Failed to construct 'NumberBox': Please use the 'new' operator, " - "this object constructor cannot be called as a function."); - e.expectEval( - "returnFunctionTakingBox(123)(321)", - "throws", "TypeError: Failed to execute function: parameter 1 is not of type 'NumberBox'."); + e.expectEval("new NumberBox(123).addBox(321)", "throws", + "TypeError: Failed to execute 'addBox' on 'NumberBox': parameter 1 is not of " + "type 'NumberBox'."); + e.expectEval("new NumberBox(123).boxed = 321", "throws", + "TypeError: Failed to set the 'boxed' property on 'NumberBox': the provided " + "value is not of type 'NumberBox'."); + e.expectEval("NumberBox(123)", "throws", + "TypeError: Failed to construct 'NumberBox': Please use the 'new' operator, " + "this object constructor cannot be called as a function."); + e.expectEval("returnFunctionTakingBox(123)(321)", "throws", + "TypeError: Failed to execute function: parameter 1 is not of type 'NumberBox'."); } // ======================================================================================== struct ThrowContext: public ContextGlobalObject { auto returnFunctionThatThrows(double value) { - return [](Lock&, double) -> double { - KJ_FAIL_ASSERT("thrown from returnFunctionThatThrows"); - }; + return [](Lock&, double) -> double { KJ_FAIL_ASSERT("thrown from returnFunctionThatThrows"); }; } void throwException() { KJ_FAIL_REQUIRE("thrown from throwException"); @@ -161,8 +152,7 @@ struct TunneledContext: public ContextGlobalObject { } void throwTunneledTypeErrorWithExpectation() { auto s = kj::str("Hello, world!"); - JSG_REQUIRE(s.startsWith(";"), TypeError, - "thrown from throwTunneledTypeErrorWithExpectation"); + JSG_REQUIRE(s.startsWith(";"), TypeError, "thrown from throwTunneledTypeErrorWithExpectation"); } void throwTunneledOperationError() { JSG_FAIL_REQUIRE(DOMOperationError, "thrown from throwTunneledOperationError"); @@ -177,16 +167,17 @@ struct TunneledContext: public ContextGlobalObject { } void throwTunneledOperationErrorWithExpectation() { auto s = kj::str("Hello, world!"); - JSG_REQUIRE(s.startsWith(";"), DOMOperationError, "thrown from " - "throwTunneledOperationErrorWithExpectation"); + JSG_REQUIRE(s.startsWith(";"), DOMOperationError, + "thrown from " + "throwTunneledOperationErrorWithExpectation"); } void throwTunneledInternalOperationError() { - JSG_FAIL_REQUIRE(InternalDOMOperationError, - "thrown from throwTunneledInternalOperationError"); + JSG_FAIL_REQUIRE(InternalDOMOperationError, "thrown from throwTunneledInternalOperationError"); } void throwRemoteCpuExceededError() { - kj::throwFatalException(KJ_EXCEPTION( - OVERLOADED, "remote exception: remote exception: worker_do_not_log; script exceeded time limit", "script exceeded time limit")); + kj::throwFatalException(KJ_EXCEPTION(OVERLOADED, + "remote exception: remote exception: worker_do_not_log; script exceeded time limit", + "script exceeded time limit")); } void throwBadTunneledError() { KJ_FAIL_REQUIRE(" jsg.TypeError"); @@ -210,16 +201,16 @@ struct TunneledContext: public ContextGlobalObject { } void throwTunneledMacroTypeErrorWithExpectation() { auto s = kj::str("Hello, world!"); - JSG_REQUIRE(s.startsWith(";"), TypeError, - "thrown from throwTunneledMacroTypeErrorWithExpectation"); + JSG_REQUIRE( + s.startsWith(";"), TypeError, "thrown from throwTunneledMacroTypeErrorWithExpectation"); } void throwTunneledMacroOperationError() { JSG_FAIL_REQUIRE(DOMOperationError, "thrown ", "from throwTunneledMacroOperationError"); } void throwTunneledMacroOperationErrorWithExpectation() { auto s = kj::str("Hello, world!"); - JSG_REQUIRE(s.startsWith(";"), DOMOperationError, - "thrown from ", kj::str("throwTunneledMacroOperationErrorWithExpectation")); + JSG_REQUIRE(s.startsWith(";"), DOMOperationError, "thrown from ", + kj::str("throwTunneledMacroOperationErrorWithExpectation")); } // Test that the error types mapped to WasmCompileError are handled correctly void throwTunneledCompileError() { @@ -274,142 +265,122 @@ JSG_DECLARE_ISOLATE_TYPE(TunneledIsolate, TunneledContext); KJ_TEST("throw tunneled exception") { Evaluator e(v8System); e.expectEval( - "throwTunneledTypeError()", - "throws", "TypeError: thrown from throwTunneledTypeError" - ); - e.expectEval( - "throwTunneledTypeErrorLateColon()", - "throws", "TypeError" - ); - e.expectEval( - "throwTunneledTypeErrorWithExpectation()", - "throws", "TypeError: thrown from throwTunneledTypeErrorWithExpectation" - ); - e.expectEval( - "throwTunneledOperationError()", - "throws", "OperationError: thrown from throwTunneledOperationError" - ); - e.expectEval( - "throwTunneledOperationErrorWithoutMessage()", - "throws", "OperationError" - ); - e.expectEval( - "throwTunneledOperationErrorLateColon()", - "throws", "OperationError" - ); - e.expectEval( - "throwTunneledOperationErrorWithExpectation()", - "throws", "OperationError: thrown from throwTunneledOperationErrorWithExpectation" - ); + "throwTunneledTypeError()", "throws", "TypeError: thrown from throwTunneledTypeError"); + e.expectEval("throwTunneledTypeErrorLateColon()", "throws", "TypeError"); + e.expectEval("throwTunneledTypeErrorWithExpectation()", "throws", + "TypeError: thrown from throwTunneledTypeErrorWithExpectation"); + e.expectEval("throwTunneledOperationError()", "throws", + "OperationError: thrown from throwTunneledOperationError"); + e.expectEval("throwTunneledOperationErrorWithoutMessage()", "throws", "OperationError"); + e.expectEval("throwTunneledOperationErrorLateColon()", "throws", "OperationError"); + e.expectEval("throwTunneledOperationErrorWithExpectation()", "throws", + "OperationError: thrown from throwTunneledOperationErrorWithExpectation"); { KJ_EXPECT_LOG(ERROR, "thrown from throwTunneledInternalOperationError"); e.expectEval( - "throwTunneledInternalOperationError()", - "throws", "OperationError: internal error" - ); + "throwTunneledInternalOperationError()", "throws", "OperationError: internal error"); } { KJ_EXPECT_LOG(ERROR, " jsg.TypeError"); - e.expectEval( - "throwBadTunneledError()", - "throws", "Error: internal error" - ); + e.expectEval("throwBadTunneledError()", "throws", "Error: internal error"); } { KJ_EXPECT_LOG(ERROR, "expected s.startsWith(\";\"); jsg.TypeError"); - e.expectEval( - "throwBadTunneledErrorWithExpectation()", - "throws", "Error: internal error" - ); - } - e.expectEval( - "throwTunneledMacroTypeError()", - "throws", "TypeError: thrown from throwTunneledMacroTypeError" - ); - e.expectEval( - "throwTunneledMacroTypeErrorWithExpectation()", - "throws", "TypeError: thrown from throwTunneledMacroTypeErrorWithExpectation" - ); - e.expectEval( - "throwTunneledMacroOperationError()", - "throws", "OperationError: thrown from throwTunneledMacroOperationError" - ); - e.expectEval( - "throwTunneledMacroOperationErrorWithExpectation()", - "throws", "OperationError: thrown from throwTunneledMacroOperationErrorWithExpectation" - ); + e.expectEval("throwBadTunneledErrorWithExpectation()", "throws", "Error: internal error"); + } + e.expectEval("throwTunneledMacroTypeError()", "throws", + "TypeError: thrown from throwTunneledMacroTypeError"); + e.expectEval("throwTunneledMacroTypeErrorWithExpectation()", "throws", + "TypeError: thrown from throwTunneledMacroTypeErrorWithExpectation"); + e.expectEval("throwTunneledMacroOperationError()", "throws", + "OperationError: thrown from throwTunneledMacroOperationError"); + e.expectEval("throwTunneledMacroOperationErrorWithExpectation()", "throws", + "OperationError: thrown from throwTunneledMacroOperationErrorWithExpectation"); + e.expectEval("throwTunneledCompileError()", "throws", + "CompileError: thrown from throwTunneledCompileError"); e.expectEval( - "throwTunneledCompileError()", - "throws", "CompileError: thrown from throwTunneledCompileError" - ); + "throwTunneledLinkError()", "throws", "CompileError: thrown from throwTunneledLinkError"); + e.expectEval("throwTunneledRuntimeError()", "throws", + "CompileError: thrown from throwTunneledRuntimeError"); e.expectEval( - "throwTunneledLinkError()", - "throws", "CompileError: thrown from throwTunneledLinkError" - ); - e.expectEval( - "throwTunneledRuntimeError()", - "throws", "CompileError: thrown from throwTunneledRuntimeError" - ); - e.expectEval( - "throwTunneledDOMException()", - "throws", "Some error: thrown from throwTunneledDOMException" - ); + "throwTunneledDOMException()", "throws", "Some error: thrown from throwTunneledDOMException"); { KJ_EXPECT_LOG(ERROR, " thrown from throwTunneledInvalidDOMException"); - e.expectEval( - "throwTunneledInvalidDOMException()", - "throws", "Error: internal error" - ); + e.expectEval("throwTunneledInvalidDOMException()", "throws", "Error: internal error"); } { KJ_EXPECT_LOG(ERROR, " thrown from throwTunneledGarbledDOMException"); - e.expectEval( - "throwTunneledGarbledDOMException()", - "throws", "Error: internal error" - ); + e.expectEval("throwTunneledGarbledDOMException()", "throws", "Error: internal error"); } } KJ_TEST("runTunnelingExceptions") { Evaluator e(v8System); - e.expectEval( - "throwRetunneledTypeError()", - "throws", "TypeError: Dummy error message." - ); + e.expectEval("throwRetunneledTypeError()", "throws", "TypeError: Dummy error message."); } KJ_TEST("isTunneledException") { TunneledContext context; - try { context.throwTunneledTypeError(); KJ_UNREACHABLE; } catch (kj::Exception e) { + try { + context.throwTunneledTypeError(); + KJ_UNREACHABLE; + } catch (kj::Exception e) { KJ_EXPECT(isTunneledException(e.getDescription()), e.getDescription()); } - try { context.throwTunneledTypeErrorWithoutMessage(); KJ_UNREACHABLE; } catch (kj::Exception e) { + try { + context.throwTunneledTypeErrorWithoutMessage(); + KJ_UNREACHABLE; + } catch (kj::Exception e) { KJ_EXPECT(isTunneledException(e.getDescription()), e.getDescription()); } - try { context.throwTunneledTypeErrorLateColon(); KJ_UNREACHABLE; } catch (kj::Exception e) { + try { + context.throwTunneledTypeErrorLateColon(); + KJ_UNREACHABLE; + } catch (kj::Exception e) { KJ_EXPECT(isTunneledException(e.getDescription()), e.getDescription()); } - try { context.throwTunneledTypeErrorWithExpectation(); KJ_UNREACHABLE; } catch (kj::Exception e) { + try { + context.throwTunneledTypeErrorWithExpectation(); + KJ_UNREACHABLE; + } catch (kj::Exception e) { KJ_EXPECT(isTunneledException(e.getDescription()), e.getDescription()); } - try { context.throwTunneledOperationError(); KJ_UNREACHABLE; } catch (kj::Exception e) { + try { + context.throwTunneledOperationError(); + KJ_UNREACHABLE; + } catch (kj::Exception e) { KJ_EXPECT(isTunneledException(e.getDescription()), e.getDescription()); } - try { context.throwTunneledOperationErrorLateColon(); KJ_UNREACHABLE; } catch (kj::Exception e) { + try { + context.throwTunneledOperationErrorLateColon(); + KJ_UNREACHABLE; + } catch (kj::Exception e) { KJ_EXPECT(isTunneledException(e.getDescription()), e.getDescription()); } - try { context.throwTunneledOperationErrorWithExpectation(); KJ_UNREACHABLE; } catch (kj::Exception e) { + try { + context.throwTunneledOperationErrorWithExpectation(); + KJ_UNREACHABLE; + } catch (kj::Exception e) { KJ_EXPECT(isTunneledException(e.getDescription()), e.getDescription()); } - try { context.throwBadTunneledError(); KJ_UNREACHABLE; } catch (kj::Exception e) { + try { + context.throwBadTunneledError(); + KJ_UNREACHABLE; + } catch (kj::Exception e) { KJ_EXPECT(!isTunneledException(e.getDescription()), e.getDescription()); } - try { context.throwBadTunneledErrorWithExpectation(); KJ_UNREACHABLE; } catch (kj::Exception e) { + try { + context.throwBadTunneledErrorWithExpectation(); + KJ_UNREACHABLE; + } catch (kj::Exception e) { KJ_EXPECT(!isTunneledException(e.getDescription()), e.getDescription()); } - try { context.throwRemoteCpuExceededError(); KJ_UNREACHABLE; } catch (kj::Exception e) { + try { + context.throwRemoteCpuExceededError(); + KJ_UNREACHABLE; + } catch (kj::Exception e) { KJ_EXPECT(!isTunneledException(e.getDescription()), e.getDescription()); KJ_EXPECT(isDoNotLogException(e.getDescription()), e.getDescription()); } diff --git a/src/workerd/jsg/util.c++ b/src/workerd/jsg/util.c++ index c16a958f941..7210e42c72f 100644 --- a/src/workerd/jsg/util.c++ +++ b/src/workerd/jsg/util.c++ @@ -45,8 +45,10 @@ kj::String fullyQualifiedTypeName(const std::type_info& type) { // Replace instances of `anonymous namespace' with (anonymous namespace) for (auto& c: result.asArray()) { - if (c == '`') c = '('; - else if (c == '\'') c = ')'; + if (c == '`') + c = '('; + else if (c == '\'') + c = ')'; } return kj::mv(result); @@ -104,41 +106,29 @@ bool setRemoteError(v8::Isolate* isolate, v8::Local& exception) { // If an exception was tunneled, we add a property `.remote` to the Javascript error. KJ_ASSERT(exception->IsObject()); auto obj = exception.As(); - return jsg::check( - obj->Set( - isolate->GetCurrentContext(), - jsg::v8StrIntern(isolate, "remote"_kj), - v8::True(isolate))); + return jsg::check(obj->Set( + isolate->GetCurrentContext(), jsg::v8StrIntern(isolate, "remote"_kj), v8::True(isolate))); } bool setRetryableError(v8::Isolate* isolate, v8::Local& exception) { KJ_ASSERT(exception->IsObject()); auto obj = exception.As(); - return jsg::check( - obj->Set( - isolate->GetCurrentContext(), - jsg::v8StrIntern(isolate, "retryable"_kj), - v8::True(isolate))); + return jsg::check(obj->Set( + isolate->GetCurrentContext(), jsg::v8StrIntern(isolate, "retryable"_kj), v8::True(isolate))); } bool setOverloadedError(v8::Isolate* isolate, v8::Local& exception) { KJ_ASSERT(exception->IsObject()); auto obj = exception.As(); - return jsg::check( - obj->Set( - isolate->GetCurrentContext(), - jsg::v8StrIntern(isolate, "overloaded"_kj), - v8::True(isolate))); + return jsg::check(obj->Set( + isolate->GetCurrentContext(), jsg::v8StrIntern(isolate, "overloaded"_kj), v8::True(isolate))); } bool setDurableObjectResetError(v8::Isolate* isolate, v8::Local& exception) { KJ_ASSERT(exception->IsObject()); auto obj = exception.As(); - return jsg::check( - obj->Set( - isolate->GetCurrentContext(), - jsg::v8StrIntern(isolate, "durableObjectReset"_kj), - v8::True(isolate))); + return jsg::check(obj->Set(isolate->GetCurrentContext(), + jsg::v8StrIntern(isolate, "durableObjectReset"_kj), v8::True(isolate))); } struct DecodedException { v8::Local handle; @@ -147,9 +137,8 @@ struct DecodedException { bool isDurableObjectReset; }; -DecodedException decodeTunneledException(v8::Isolate* isolate, - kj::StringPtr internalMessage, - kj::Exception::Type excType) { +DecodedException decodeTunneledException( + v8::Isolate* isolate, kj::StringPtr internalMessage, kj::Exception::Type excType) { // We currently support tunneling the following error types: // // - Error: While the Web IDL spec claims this is reserved for use by program authors, this @@ -183,11 +172,11 @@ DecodedException decodeTunneledException(v8::Isolate* isolate, result.isFromRemote = tunneledInfo.isFromRemote; result.isDurableObjectReset = tunneledInfo.isDurableObjectReset; -#define HANDLE_V8_ERROR(error_name, error_type) \ - if (errorType.startsWith(error_name)) { \ - auto message = appMessage(errorType.slice(strlen(error_name))); \ - result.handle = v8::Exception::error_type(v8Str(isolate, message)); \ - break; \ +#define HANDLE_V8_ERROR(error_name, error_type) \ + if (errorType.startsWith(error_name)) { \ + auto message = appMessage(errorType.slice(strlen(error_name))); \ + result.handle = v8::Exception::error_type(v8Str(isolate, message)); \ + break; \ } do { @@ -264,11 +253,12 @@ v8::Local makeInternalError(v8::Isolate* isolate, kj::Exception&& exc if (tunneledException.isInternal) { auto& observer = IsolateBase::from(isolate).getObserver(); - observer.reportInternalException(exception, { - .isInternal = tunneledException.isInternal, - .isFromRemote = tunneledException.isFromRemote, - .isDurableObjectReset = tunneledException.isDurableObjectReset, - }); + observer.reportInternalException(exception, + { + .isInternal = tunneledException.isInternal, + .isFromRemote = tunneledException.isFromRemote, + .isDurableObjectReset = tunneledException.isDurableObjectReset, + }); // Don't log exceptions that have been explicitly marked with worker_do_not_log or are // DISCONNECTED exceptions as these are unlikely to represent bugs worth tracking. if (exception.getType() != kj::Exception::Type::DISCONNECTED && @@ -299,9 +289,8 @@ v8::Local makeInternalError(v8::Isolate* isolate, kj::Exception&& exc } Value Lock::exceptionToJs(kj::Exception&& exception) { - return withinHandleScope([&] { - return Value(v8Isolate, makeInternalError(v8Isolate, kj::mv(exception))); - }); + return withinHandleScope( + [&] { return Value(v8Isolate, makeInternalError(v8Isolate, kj::mv(exception))); }); } JsRef Lock::exceptionToJsValue(kj::Exception&& exception) { @@ -312,16 +301,12 @@ JsRef Lock::exceptionToJsValue(kj::Exception&& exception) { } void Lock::throwException(Value&& exception) { - withinHandleScope([&] { - v8Isolate->ThrowException(exception.getHandle(*this)); - }); + withinHandleScope([&] { v8Isolate->ThrowException(exception.getHandle(*this)); }); throw JsExceptionThrown(); } void Lock::throwException(const JsValue& exception) { - withinHandleScope([&] { - v8Isolate->ThrowException(exception); - }); + withinHandleScope([&] { v8Isolate->ThrowException(exception); }); throw JsExceptionThrown(); } @@ -342,11 +327,12 @@ void throwInternalError(v8::Isolate* isolate, kj::Exception&& exception) { void addExceptionDetail(Lock& js, kj::Exception& exception, v8::Local handle) { v8::TryCatch tryCatch(js.v8Isolate); try { - Serializer ser(js, { - // Make sure we don't break compatibility if V8 introduces a new version. This value can - // be bumped to match the new version once all of production is updated to understand it. - .version = 15, - }); + Serializer ser(js, + { + // Make sure we don't break compatibility if V8 introduces a new version. This value can + // be bumped to match the new version once all of production is updated to understand it. + .version = 15, + }); ser.write(js, JsValue(handle)); exception.setDetail(TUNNELED_EXCEPTION_DETAIL_ID, ser.release().data); } catch (JsExceptionThrown&) { @@ -367,46 +353,37 @@ static kj::String typeErrorMessage(TypeErrorContext c, const char* expectedType) } switch (c.kind) { - case TypeErrorContext::METHOD_ARGUMENT: - return kj::str( - "Failed to execute '", c.memberName, "' on '", type, "': parameter ", c.argumentIndex + 1, - " is not of type '", expectedType, "'."); - case TypeErrorContext::CONSTRUCTOR_ARGUMENT: - return kj::str( - "Failed to construct '", type, "': constructor parameter ", c.argumentIndex + 1, - " is not of type '", expectedType, "'."); - case TypeErrorContext::SETTER_ARGUMENT: - return kj::str( - "Failed to set the '", c.memberName, "' property on '", type, - "': the provided value is not of type '", expectedType, "'."); - case TypeErrorContext::STRUCT_FIELD: - return kj::str( - "Incorrect type for the '", c.memberName, "' field on '", type, - "': the provided value is not of type '", expectedType, "'."); - case TypeErrorContext::ARRAY_ELEMENT: - return kj::str( - "Incorrect type for array element ", c.argumentIndex, - ": the provided value is not of type '", expectedType, "'."); - case TypeErrorContext::CALLBACK_ARGUMENT: - return kj::str( - "Failed to execute function: parameter ", c.argumentIndex + 1, " is not of type '", - expectedType, "'."); - case TypeErrorContext::CALLBACK_RETURN: - return kj::str("Callback returned incorrect type; expected '", expectedType, "'"); - case TypeErrorContext::DICT_KEY: - return kj::str( - "Incorrect type for map entry '", c.memberName, - "': the provided key is not of type '", expectedType, "'."); - case TypeErrorContext::DICT_FIELD: - return kj::str( - "Incorrect type for map entry '", c.memberName, - "': the provided value is not of type '", expectedType, "'."); - case TypeErrorContext::PROMISE_RESOLUTION: - return kj::str( - "Incorrect type for Promise: the Promise did not resolve to '", expectedType, "'."); - case TypeErrorContext::OTHER: - return kj::str( - "Incorrect type: the provided value is not of type '", expectedType, "'."); + case TypeErrorContext::METHOD_ARGUMENT: + return kj::str("Failed to execute '", c.memberName, "' on '", type, "': parameter ", + c.argumentIndex + 1, " is not of type '", expectedType, "'."); + case TypeErrorContext::CONSTRUCTOR_ARGUMENT: + return kj::str("Failed to construct '", type, "': constructor parameter ", + c.argumentIndex + 1, " is not of type '", expectedType, "'."); + case TypeErrorContext::SETTER_ARGUMENT: + return kj::str("Failed to set the '", c.memberName, "' property on '", type, + "': the provided value is not of type '", expectedType, "'."); + case TypeErrorContext::STRUCT_FIELD: + return kj::str("Incorrect type for the '", c.memberName, "' field on '", type, + "': the provided value is not of type '", expectedType, "'."); + case TypeErrorContext::ARRAY_ELEMENT: + return kj::str("Incorrect type for array element ", c.argumentIndex, + ": the provided value is not of type '", expectedType, "'."); + case TypeErrorContext::CALLBACK_ARGUMENT: + return kj::str("Failed to execute function: parameter ", c.argumentIndex + 1, + " is not of type '", expectedType, "'."); + case TypeErrorContext::CALLBACK_RETURN: + return kj::str("Callback returned incorrect type; expected '", expectedType, "'"); + case TypeErrorContext::DICT_KEY: + return kj::str("Incorrect type for map entry '", c.memberName, + "': the provided key is not of type '", expectedType, "'."); + case TypeErrorContext::DICT_FIELD: + return kj::str("Incorrect type for map entry '", c.memberName, + "': the provided value is not of type '", expectedType, "'."); + case TypeErrorContext::PROMISE_RESOLUTION: + return kj::str( + "Incorrect type for Promise: the Promise did not resolve to '", expectedType, "'."); + case TypeErrorContext::OTHER: + return kj::str("Incorrect type: the provided value is not of type '", expectedType, "'."); }; KJ_UNREACHABLE; @@ -420,36 +397,32 @@ static kj::String unimplementedErrorMessage(TypeErrorContext c) { } switch (c.kind) { - case TypeErrorContext::METHOD_ARGUMENT: - return kj::str( - "Failed to execute '", c.memberName, "' on '", type, "': parameter ", c.argumentIndex + 1, - " is not implemented."); - case TypeErrorContext::CONSTRUCTOR_ARGUMENT: - return kj::str( - "Failed to construct '", type, "': constructor parameter ", c.argumentIndex + 1, - " is not implemented."); - case TypeErrorContext::SETTER_ARGUMENT: - return kj::str( - "Failed to set the '", c.memberName, "' property on '", type, - "': the ability to set this property is not implemented."); - case TypeErrorContext::STRUCT_FIELD: - return kj::str( - "The '", c.memberName, "' field on '", type, "' is not implemented."); - case TypeErrorContext::ARRAY_ELEMENT: - KJ_UNREACHABLE; - case TypeErrorContext::CALLBACK_ARGUMENT: - return kj::str( - "Failed to execute function: parameter ", c.argumentIndex + 1, " is not implemented."); - case TypeErrorContext::CALLBACK_RETURN: - KJ_UNREACHABLE; - case TypeErrorContext::DICT_KEY: - KJ_UNREACHABLE; - case TypeErrorContext::DICT_FIELD: - KJ_UNREACHABLE; - case TypeErrorContext::PROMISE_RESOLUTION: - KJ_UNREACHABLE; - case TypeErrorContext::OTHER: - KJ_UNREACHABLE; + case TypeErrorContext::METHOD_ARGUMENT: + return kj::str("Failed to execute '", c.memberName, "' on '", type, "': parameter ", + c.argumentIndex + 1, " is not implemented."); + case TypeErrorContext::CONSTRUCTOR_ARGUMENT: + return kj::str("Failed to construct '", type, "': constructor parameter ", + c.argumentIndex + 1, " is not implemented."); + case TypeErrorContext::SETTER_ARGUMENT: + return kj::str("Failed to set the '", c.memberName, "' property on '", type, + "': the ability to set this property is not implemented."); + case TypeErrorContext::STRUCT_FIELD: + return kj::str("The '", c.memberName, "' field on '", type, "' is not implemented."); + case TypeErrorContext::ARRAY_ELEMENT: + KJ_UNREACHABLE; + case TypeErrorContext::CALLBACK_ARGUMENT: + return kj::str( + "Failed to execute function: parameter ", c.argumentIndex + 1, " is not implemented."); + case TypeErrorContext::CALLBACK_RETURN: + KJ_UNREACHABLE; + case TypeErrorContext::DICT_KEY: + KJ_UNREACHABLE; + case TypeErrorContext::DICT_FIELD: + KJ_UNREACHABLE; + case TypeErrorContext::PROMISE_RESOLUTION: + KJ_UNREACHABLE; + case TypeErrorContext::OTHER: + KJ_UNREACHABLE; }; KJ_UNREACHABLE; @@ -460,20 +433,18 @@ void throwTypeError(v8::Isolate* isolate, kj::StringPtr message) { throw JsExceptionThrown(); } -void throwTypeError(v8::Isolate* isolate, - TypeErrorContext errorContext, kj::String expectedType) { +void throwTypeError(v8::Isolate* isolate, TypeErrorContext errorContext, kj::String expectedType) { kj::String message = typeErrorMessage(errorContext, expectedType.cStr()); throwTypeError(isolate, message); } -void throwTypeError(v8::Isolate* isolate, - TypeErrorContext errorContext, const char* expectedType) { +void throwTypeError(v8::Isolate* isolate, TypeErrorContext errorContext, const char* expectedType) { kj::String message = typeErrorMessage(errorContext, expectedType); throwTypeError(isolate, message); } -void throwTypeError(v8::Isolate* isolate, - TypeErrorContext errorContext, const std::type_info& expectedType) { +void throwTypeError( + v8::Isolate* isolate, TypeErrorContext errorContext, const std::type_info& expectedType) { if (expectedType == typeid(Unimplemented)) { isolate->ThrowError(v8StrIntern(isolate, unimplementedErrorMessage(errorContext))); throw JsExceptionThrown(); @@ -500,15 +471,12 @@ kj::Exception createTunneledException(v8::Isolate* isolate, v8::Local } kj::Exception Lock::exceptionToKj(Value&& exception) { - return withinHandleScope([&] { - return createTunneledException(v8Isolate, exception.getHandle(*this)); - }); + return withinHandleScope( + [&] { return createTunneledException(v8Isolate, exception.getHandle(*this)); }); } kj::Exception Lock::exceptionToKj(const JsValue& exception) { - return withinHandleScope([&] { - return createTunneledException(v8Isolate, exception); - }); + return withinHandleScope([&] { return createTunneledException(v8Isolate, exception); }); } static kj::byte DUMMY = 0; @@ -560,14 +528,11 @@ void recursivelyFreeze(v8::Local context, v8::Local valu } else if (value->IsObject()) { v8::HandleScope scope(context->GetIsolate()); auto obj = value.As(); - auto names = check(obj->GetPropertyNames(context, - v8::KeyCollectionMode::kOwnOnly, - v8::ALL_PROPERTIES, - v8::IndexFilter::kIncludeIndices)); + auto names = check(obj->GetPropertyNames(context, v8::KeyCollectionMode::kOwnOnly, + v8::ALL_PROPERTIES, v8::IndexFilter::kIncludeIndices)); for (auto i: kj::zeroTo(names->Length())) { - recursivelyFreeze(context, - check(obj->Get(context, check(names->Get(context, i))))); + recursivelyFreeze(context, check(obj->Get(context, check(names->Get(context, i))))); } check(obj->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen)); @@ -584,8 +549,7 @@ v8::Local deepClone(v8::Local context, v8::Local makeRejectedPromise( - v8::Isolate* isolate, - v8::Local exception) { + v8::Isolate* isolate, v8::Local exception) { v8::Local resolver; auto context = isolate->GetCurrentContext(); if (!v8::Promise::Resolver::New(context).ToLocal(&resolver) || @@ -596,10 +560,7 @@ v8::MaybeLocal makeRejectedPromise( return resolver->GetPromise(); }; -void returnRejectedPromiseImpl( - auto info, - v8::Local exception, - v8::TryCatch& tryCatch) { +void returnRejectedPromiseImpl(auto info, v8::Local exception, v8::TryCatch& tryCatch) { v8::Local promise; if (!makeRejectedPromise(info.GetIsolate(), exception).ToLocal(&promise)) { // If makeRejectedPromise fails, the tryCatch should have caught the error. @@ -610,18 +571,18 @@ void returnRejectedPromiseImpl( } } // namespace -void returnRejectedPromise( - const v8::FunctionCallbackInfo& info, +void returnRejectedPromise(const v8::FunctionCallbackInfo& info, v8::Local exception, v8::TryCatch& tryCatch) { - return returnRejectedPromiseImpl&>(info, exception, tryCatch); + return returnRejectedPromiseImpl&>( + info, exception, tryCatch); } -void returnRejectedPromise( - const v8::PropertyCallbackInfo& info, +void returnRejectedPromise(const v8::PropertyCallbackInfo& info, v8::Local exception, v8::TryCatch& tryCatch) { - return returnRejectedPromiseImpl&>(info, exception, tryCatch); + return returnRejectedPromiseImpl&>( + info, exception, tryCatch); } // ====================================================================================== @@ -653,14 +614,20 @@ class ExternString: public Type { // IN THE SOFTWARE. public: - inline const Data* data() const override { return buf.begin(); } + inline const Data* data() const override { + return buf.begin(); + } - inline size_t length() const override { return buf.size(); } + inline size_t length() const override { + return buf.size(); + } - inline uint64_t byteLength() const { return length() * sizeof(Data); } + inline uint64_t byteLength() const { + return length() * sizeof(Data); + } - static v8::MaybeLocal createExtern(v8::Isolate* isolate, - kj::ArrayPtr& buf) { + static v8::MaybeLocal createExtern( + v8::Isolate* isolate, kj::ArrayPtr& buf) { if (buf.size() == 0) { return v8::String::Empty(isolate); } @@ -695,7 +662,8 @@ private: kj::ArrayPtr buf; inline ExternString(v8::Isolate* isolate, kj::ArrayPtr& buf) - : isolate(isolate), buf(buf) {} + : isolate(isolate), + buf(buf) {} }; using ExternOneByteString = ExternString; diff --git a/src/workerd/jsg/util.h b/src/workerd/jsg/util.h index 1caa95a471e..9c1f5596d2d 100644 --- a/src/workerd/jsg/util.h +++ b/src/workerd/jsg/util.h @@ -69,22 +69,22 @@ constexpr kj::Exception::DetailTypeId TUNNELED_EXCEPTION_DETAIL_ID = 0xe80272921 void addExceptionDetail(Lock& js, kj::Exception& exception, v8::Local handle); struct TypeErrorContext { - enum Kind: uint8_t { - METHOD_ARGUMENT, // has type name, member (method) name, and argument index - CONSTRUCTOR_ARGUMENT, // has type name, argument index - SETTER_ARGUMENT, // has type name and member (property) name - STRUCT_FIELD, // has type name and member (field) name - ARRAY_ELEMENT, // has argument (element) index - // TODO(someday): Capture where the array itself was declared? - CALLBACK_ARGUMENT, // has argument index - // TODO(someday): Track where callback was introduced for better errors. - CALLBACK_RETURN, // has nothing - // TODO(someday): Track where callback was introduced for better errors. - DICT_KEY, // has member (key) name - DICT_FIELD, // has member (field) name - PROMISE_RESOLUTION, // has nothing - // TODO(someday): Track where the promise was introduced. - OTHER, // has nothing + enum Kind : uint8_t { + METHOD_ARGUMENT, // has type name, member (method) name, and argument index + CONSTRUCTOR_ARGUMENT, // has type name, argument index + SETTER_ARGUMENT, // has type name and member (property) name + STRUCT_FIELD, // has type name and member (field) name + ARRAY_ELEMENT, // has argument (element) index + // TODO(someday): Capture where the array itself was declared? + CALLBACK_ARGUMENT, // has argument index + // TODO(someday): Track where callback was introduced for better errors. + CALLBACK_RETURN, // has nothing + // TODO(someday): Track where callback was introduced for better errors. + DICT_KEY, // has member (key) name + DICT_FIELD, // has member (field) name + PROMISE_RESOLUTION, // has nothing + // TODO(someday): Track where the promise was introduced. + OTHER, // has nothing }; Kind kind; @@ -94,57 +94,56 @@ struct TypeErrorContext { static inline TypeErrorContext methodArgument( const std::type_info& type, const char* methodName, uint argumentIndex) { - return { METHOD_ARGUMENT, argumentIndex, type, methodName }; + return {METHOD_ARGUMENT, argumentIndex, type, methodName}; } static inline TypeErrorContext constructorArgument( const std::type_info& type, uint argumentIndex) { - return { CONSTRUCTOR_ARGUMENT, argumentIndex, type, nullptr }; + return {CONSTRUCTOR_ARGUMENT, argumentIndex, type, nullptr}; } static inline TypeErrorContext setterArgument( const std::type_info& type, const char* propertyName) { - return { SETTER_ARGUMENT, 0, type, propertyName }; + return {SETTER_ARGUMENT, 0, type, propertyName}; } static inline TypeErrorContext structField(const std::type_info& type, const char* fieldName) { - return { STRUCT_FIELD, 0, type, fieldName }; + return {STRUCT_FIELD, 0, type, fieldName}; } static inline TypeErrorContext arrayElement(uint index) { - return { ARRAY_ELEMENT, index, kj::none, nullptr }; + return {ARRAY_ELEMENT, index, kj::none, nullptr}; } static inline TypeErrorContext callbackArgument(uint argumentIndex) { - return { CALLBACK_ARGUMENT, argumentIndex, kj::none, nullptr }; + return {CALLBACK_ARGUMENT, argumentIndex, kj::none, nullptr}; } static inline TypeErrorContext callbackReturn() { - return { CALLBACK_RETURN, 0, kj::none, nullptr }; + return {CALLBACK_RETURN, 0, kj::none, nullptr}; } static inline TypeErrorContext dictKey(const char* keyName) { - return { DICT_KEY, 0, kj::none, keyName }; + return {DICT_KEY, 0, kj::none, keyName}; } static inline TypeErrorContext dictField(const char* fieldName) { - return { DICT_FIELD, 0, kj::none, fieldName }; + return {DICT_FIELD, 0, kj::none, fieldName}; } static inline TypeErrorContext promiseResolution() { - return { PROMISE_RESOLUTION, 0, kj::none, nullptr }; + return {PROMISE_RESOLUTION, 0, kj::none, nullptr}; } static inline TypeErrorContext other() { - return { OTHER, 0, kj::none, nullptr }; + return {OTHER, 0, kj::none, nullptr}; } }; // Throw a JavaScript exception indicating an argument type error, and then throw a C++ exception // of type JsExceptionThrown, which will be caught by liftKj(). -[[noreturn]] void throwTypeError(v8::Isolate* isolate, - TypeErrorContext errorContext, const char* expectedType); +[[noreturn]] void throwTypeError( + v8::Isolate* isolate, TypeErrorContext errorContext, const char* expectedType); // Throw a JavaScript exception indicating an argument type error, and then throw a C++ exception // of type JsExceptionThrown, which will be caught by liftKj(). -[[noreturn]] void throwTypeError(v8::Isolate* isolate, - TypeErrorContext errorContext, const std::type_info& expectedType); +[[noreturn]] void throwTypeError( + v8::Isolate* isolate, TypeErrorContext errorContext, const std::type_info& expectedType); // Throw a JavaScript exception indicating an argument type error, and then throw a C++ exception // of type JsExceptionThrown, which will be caught by liftKj(). -[[noreturn]] void throwTypeError(v8::Isolate* isolate, - TypeErrorContext errorContext, - kj::String expectedType); +[[noreturn]] void throwTypeError( + v8::Isolate* isolate, TypeErrorContext errorContext, kj::String expectedType); // Throw a JavaScript TypeError with a free-form message. [[noreturn]] void throwTypeError(v8::Isolate* isolate, kj::StringPtr message); @@ -213,20 +212,15 @@ v8::Local deepClone(v8::Local context, v8::Local -v8::Local v8Str(v8::Isolate* isolate, kj::ArrayPtr ptr, - v8::NewStringType newType = v8::NewStringType::kNormal) { +v8::Local v8Str(v8::Isolate* isolate, + kj::ArrayPtr ptr, + v8::NewStringType newType = v8::NewStringType::kNormal) { if constexpr (kj::isSameType()) { return check(v8::String::NewFromTwoByte( - isolate, - reinterpret_cast(ptr.begin()), - newType, - ptr.size())); + isolate, reinterpret_cast(ptr.begin()), newType, ptr.size())); } else if constexpr (kj::isSameType()) { return check(v8::String::NewFromTwoByte( - isolate, - reinterpret_cast(ptr.begin()), - newType, - ptr.size())); + isolate, reinterpret_cast(ptr.begin()), newType, ptr.size())); } else if constexpr (kj::isSameType()) { return check(v8::String::NewFromTwoByte(isolate, ptr.begin(), newType, ptr.size())); } else if constexpr (kj::isSameType()) { @@ -239,14 +233,14 @@ v8::Local v8Str(v8::Isolate* isolate, kj::ArrayPtr ptr, } // Make a JavaScript String in v8's Heap with the kj::StringPtr interpreted as UTF-8. -inline v8::Local v8Str(v8::Isolate* isolate, kj::StringPtr str, - v8::NewStringType newType = v8::NewStringType::kNormal) { +inline v8::Local v8Str(v8::Isolate* isolate, + kj::StringPtr str, + v8::NewStringType newType = v8::NewStringType::kNormal) { return v8Str(isolate, str.asArray(), newType); } // Make a JavaScript String in v8's Heap with the kj::ArrayPtr interpreted as Latin1. -inline v8::Local v8StrFromLatin1( - v8::Isolate* isolate, +inline v8::Local v8StrFromLatin1(v8::Isolate* isolate, kj::ArrayPtr ptr, v8::NewStringType newType = v8::NewStringType::kNormal) { return check(v8::String::NewFromOneByte(isolate, ptr.begin(), newType, ptr.size())); @@ -256,22 +250,36 @@ inline v8::Local v8StrIntern(v8::Isolate* isolate, kj::StringPtr str return v8Str(isolate, str, v8::NewStringType::kInternalized); } -template constexpr bool isVoid() { return false; } -template <> constexpr bool isVoid() { return true; } - -template struct RemoveMaybe_; -template struct RemoveMaybe_> { typedef T Type; }; -template using RemoveMaybe = typename RemoveMaybe_::Type; +template +constexpr bool isVoid() { + return false; +} +template <> +constexpr bool isVoid() { + return true; +} -template struct RemoveRvalueRef_ { typedef T Type; }; -template struct RemoveRvalueRef_ { typedef T Type; }; -template using RemoveRvalueRef = typename RemoveRvalueRef_::Type; +template +struct RemoveMaybe_; +template +struct RemoveMaybe_> { + typedef T Type; +}; +template +using RemoveMaybe = typename RemoveMaybe_::Type; -enum class JsgKind { - RESOURCE, - STRUCT, - EXTENSION +template +struct RemoveRvalueRef_ { + typedef T Type; +}; +template +struct RemoveRvalueRef_ { + typedef T Type; }; +template +using RemoveRvalueRef = typename RemoveRvalueRef_::Type; + +enum class JsgKind { RESOURCE, STRUCT, EXTENSION }; template struct LiftKj_ { @@ -281,7 +289,7 @@ struct LiftKj_ { try { try { v8::HandleScope scope(isolate); - if constexpr(isVoid()) { + if constexpr (isVoid()) { func(); if constexpr (!kj::canConvert&>()) { info.GetReturnValue().SetUndefined(); @@ -301,19 +309,17 @@ struct LiftKj_ { } catch (std::exception& exception) { throwInternalError(isolate, exception.what()); } catch (...) { - throwInternalError(isolate, kj::str("caught unknown exception of type: ", - kj::getCaughtExceptionType())); + throwInternalError( + isolate, kj::str("caught unknown exception of type: ", kj::getCaughtExceptionType())); } } }; -void returnRejectedPromise( - const v8::FunctionCallbackInfo& info, +void returnRejectedPromise(const v8::FunctionCallbackInfo& info, v8::Local exception, v8::TryCatch& tryCatch); -void returnRejectedPromise( - const v8::PropertyCallbackInfo& info, +void returnRejectedPromise(const v8::PropertyCallbackInfo& info, v8::Local exception, v8::TryCatch& tryCatch); @@ -349,8 +355,8 @@ struct LiftKj_> { } catch (std::exception& exception) { throwInternalError(isolate, exception.what()); } catch (...) { - throwInternalError(isolate, kj::str("caught unknown exception of type: ", - kj::getCaughtExceptionType())); + throwInternalError( + isolate, kj::str("caught unknown exception of type: ", kj::getCaughtExceptionType())); } } }; @@ -391,7 +397,7 @@ struct Detector>, Op, Args...> { static constexpr bool value = true; }; -} // namespace _ (private) +} // namespace _ // A typedef for `Op` if that template is instantiable, otherwise `Default`. template class Op, typename... Args> @@ -402,14 +408,18 @@ using DetectedOr = typename _::Detector::Type; // http://en.cppreference.com/w/cpp/experimental/is_detected // template