From 28cb67cdec1777bebf44e4b921d81a3ff31cd78c Mon Sep 17 00:00:00 2001 From: Vladimir Nechaev Date: Wed, 28 Dec 2022 10:03:56 +0000 Subject: [PATCH] Runtime.callFunctionOn supports uniqueContextId Bug: v8:13620 Change-Id: I802deb3325a5c8ac9e7e378d60be591af66e6fee Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4126215 Reviewed-by: Benedikt Meurer Commit-Queue: Vladimir Nechaev Cr-Commit-Position: refs/heads/main@{#85027} --- include/js_protocol.pdl | 7 +++ src/inspector/v8-runtime-agent-impl.cc | 24 ++++++---- src/inspector/v8-runtime-agent-impl.h | 2 +- .../call-function-on-async-expected.txt | 43 +++++++++++++++++- .../runtime/call-function-on-async.js | 45 +++++++++++++++++-- 5 files changed, 106 insertions(+), 15 deletions(-) diff --git a/include/js_protocol.pdl b/include/js_protocol.pdl index 6efcf78785..7960a56f54 100644 --- a/include/js_protocol.pdl +++ b/include/js_protocol.pdl @@ -1402,6 +1402,13 @@ domain Runtime optional string objectGroup # Whether to throw an exception if side effect cannot be ruled out during evaluation. experimental optional boolean throwOnSideEffect + # An alternative way to specify the execution context to call function on. + # Compared to contextId that may be reused across processes, this is guaranteed to be + # system-unique, so it can be used to prevent accidental function call + # in context different than intended (e.g. as a result of navigation across process + # boundaries). + # This is mutually exclusive with `executionContextId`. + experimental optional string uniqueContextId # Whether the result should contain `webDriverValue`, serialized according to # https://w3c.github.io/webdriver-bidi. This is mutually exclusive with `returnByValue`, but # resulting `objectId` is still provided. diff --git a/src/inspector/v8-runtime-agent-impl.cc b/src/inspector/v8-runtime-agent-impl.cc index 9d7f4b0b70..5cb582c0bf 100644 --- a/src/inspector/v8-runtime-agent-impl.cc +++ b/src/inspector/v8-runtime-agent-impl.cc @@ -375,16 +375,22 @@ void V8RuntimeAgentImpl::callFunctionOn( Maybe silent, Maybe returnByValue, Maybe generatePreview, Maybe userGesture, Maybe awaitPromise, Maybe executionContextId, Maybe objectGroup, - Maybe throwOnSideEffect, Maybe generateWebDriverValue, + Maybe throwOnSideEffect, Maybe uniqueContextId, + Maybe generateWebDriverValue, std::unique_ptr callback) { - if (objectId.isJust() && executionContextId.isJust()) { - callback->sendFailure(Response::ServerError( - "ObjectId must not be specified together with executionContextId")); + int justCount = (objectId.isJust() ? 1 : 0) + + (executionContextId.isJust() ? 1 : 0) + + (uniqueContextId.isJust() ? 1 : 0); + if (justCount > 1) { + callback->sendFailure(Response::InvalidParams( + "ObjectId, executionContextId and uniqueContextId must mutually " + "exclude each other")); return; } - if (!objectId.isJust() && !executionContextId.isJust()) { - callback->sendFailure(Response::ServerError( - "Either ObjectId or executionContextId must be specified")); + if (justCount < 1) { + callback->sendFailure( + Response::InvalidParams("Either objectId or executionContextId or " + "uniqueContextId must be specified")); return; } WrapMode wrap_mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview @@ -409,8 +415,8 @@ void V8RuntimeAgentImpl::callFunctionOn( } else { int contextId = 0; Response response = ensureContext(m_inspector, m_session->contextGroupId(), - std::move(executionContextId.fromJust()), - /* uniqueContextId */ {}, &contextId); + std::move(executionContextId), + std::move(uniqueContextId), &contextId); if (!response.IsSuccess()) { callback->sendFailure(response); return; diff --git a/src/inspector/v8-runtime-agent-impl.h b/src/inspector/v8-runtime-agent-impl.h index 9e2ad27e56..4bb0e87114 100644 --- a/src/inspector/v8-runtime-agent-impl.h +++ b/src/inspector/v8-runtime-agent-impl.h @@ -89,7 +89,7 @@ class V8RuntimeAgentImpl : public protocol::Runtime::Backend { Maybe generatePreview, Maybe userGesture, Maybe awaitPromise, Maybe executionContextId, Maybe objectGroup, Maybe throwOnSideEffect, - Maybe generateWebDriverValue, + Maybe uniqueContextId, Maybe generateWebDriverValue, std::unique_ptr) override; Response releaseObject(const String16& objectId) override; Response getProperties( diff --git a/test/inspector/runtime/call-function-on-async-expected.txt b/test/inspector/runtime/call-function-on-async-expected.txt index f98fc43bf9..e05a203c7d 100644 --- a/test/inspector/runtime/call-function-on-async-expected.txt +++ b/test/inspector/runtime/call-function-on-async-expected.txt @@ -208,11 +208,50 @@ Running test: testEvaluateOnExecutionContext } } +Running test: testEvaluateOnUniqueExecutionContext +{ + id : + result : { + result : { + description : 70 + type : number + value : 70 + } + } +} + Running test: testPassingBothObjectIdAndExecutionContextId { error : { - code : -32000 - message : ObjectId must not be specified together with executionContextId + code : -32602 + message : ObjectId, executionContextId and uniqueContextId must mutually exclude each other + } + id : +} + +Running test: testPassingBothObjectIdAndExecutionContextUniqueId +{ + error : { + code : -32602 + message : ObjectId, executionContextId and uniqueContextId must mutually exclude each other + } + id : +} + +Running test: testPassingTwoExecutionContextIds +{ + error : { + code : -32602 + message : ObjectId, executionContextId and uniqueContextId must mutually exclude each other + } + id : +} + +Running test: testPassingNeitherContextIdNorObjectId +{ + error : { + code : -32602 + message : Either objectId or executionContextId or uniqueContextId must be specified } id : } diff --git a/test/inspector/runtime/call-function-on-async.js b/test/inspector/runtime/call-function-on-async.js index 70f823c52c..18c60a288c 100644 --- a/test/inspector/runtime/call-function-on-async.js +++ b/test/inspector/runtime/call-function-on-async.js @@ -8,10 +8,12 @@ let callFunctionOn = Protocol.Runtime.callFunctionOn.bind(Protocol.Runtime); let remoteObject1; let remoteObject2; let executionContextId; +let executionContextUniqueId; Protocol.Runtime.enable(); Protocol.Runtime.onExecutionContextCreated(messageObject => { executionContextId = messageObject.params.context.id; + executionContextUniqueId = messageObject.params.context.uniqueId; InspectorTest.runAsyncTestSuite(testSuite); }); @@ -135,15 +137,52 @@ let testSuite = [ })); }, + async function testEvaluateOnUniqueExecutionContext() { + InspectorTest.logMessage(await callFunctionOn({ + uniqueContextId: executionContextUniqueId, + functionDeclaration: '(function(arg) { return this.globalObjectProperty + arg; })', + arguments: prepareArguments([ 28 ]), + returnByValue: true, + generatePreview: false, + awaitPromise: false + })); + }, + async function testPassingBothObjectIdAndExecutionContextId() { InspectorTest.logMessage(await callFunctionOn({ executionContextId, objectId: remoteObject1.objectId, functionDeclaration: '(function() { return 42; })', arguments: prepareArguments([]), - returnByValue: true, - generatePreview: false, - awaitPromise: false + returnByValue: true + })); + }, + + async function testPassingBothObjectIdAndExecutionContextUniqueId() { + InspectorTest.logMessage(await callFunctionOn({ + uniqueContextId: executionContextUniqueId, + objectId: remoteObject1.objectId, + functionDeclaration: '(function() { return 42; })', + arguments: prepareArguments([]), + returnByValue: true + })); + }, + + async function testPassingTwoExecutionContextIds() { + InspectorTest.logMessage(await callFunctionOn({ + executionContextId, + uniqueContextId: executionContextUniqueId, + functionDeclaration: '(function() { return 42; })', + arguments: prepareArguments([]), + returnByValue: true + })); + }, + + async function testPassingNeitherContextIdNorObjectId() { + InspectorTest.logMessage(await callFunctionOn({ + functionDeclaration: '(function() { return 42; })', + arguments: prepareArguments([]), + returnByValue: true })); },