DevTools: add support for system-unique execution context ids
This adds ExecutionContextDescription.uniqueId for a system-unique way to identify an execution context and supports it in Runtime.evaluate. This allows a client to avoid accidentally executing an expression in a context different from that originally intended if a navigation occurs while Runtime.evaluate is in flight. Design doc: https://docs.google.com/document/d/1vGVWvKP9FTTX6kimcUJR_PAfVgDeIzXXITFpl0SyghQ Bug: v8:11268, chromium:1101897 Change-Id: I4c6bec562ffc85312559316f639d641780144039 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2594538 Commit-Queue: Andrey Kosyakov <caseq@chromium.org> Reviewed-by: Dmitry Gozman <dgozman@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#71869}
This commit is contained in:
parent
e51dcc5225
commit
f656eab592
@ -1226,6 +1226,10 @@ domain Runtime
|
||||
string origin
|
||||
# Human readable name describing given context.
|
||||
string name
|
||||
# A system-unique execution context identifier. Unlike the id, this is unique accross
|
||||
# multiple processes, so can be reliably used to identify specific context while backend
|
||||
# performs a cross-process navigation.
|
||||
experimental string uniqueId
|
||||
# Embedder-specific auxiliary data.
|
||||
optional object auxData
|
||||
|
||||
@ -1389,6 +1393,9 @@ domain Runtime
|
||||
optional boolean silent
|
||||
# Specifies in which execution context to perform evaluation. If the parameter is omitted the
|
||||
# evaluation will be performed in the context of the inspected page.
|
||||
# This is mutually exclusive with `uniqueContextId`, which offers an
|
||||
# alternative way to identify the execution context that is more reliable
|
||||
# in a multi-process environment.
|
||||
optional ExecutionContextId contextId
|
||||
# Whether the result is expected to be a JSON object that should be sent by value.
|
||||
optional boolean returnByValue
|
||||
@ -1415,6 +1422,13 @@ domain Runtime
|
||||
# when called with non-callable arguments. This flag bypasses CSP for this
|
||||
# evaluation and allows unsafe-eval. Defaults to true.
|
||||
experimental optional boolean allowUnsafeEvalBlockedByCSP
|
||||
# An alternative way to specify the execution context to evaluate in.
|
||||
# Compared to contextId that may be reused accross processes, this is guaranteed to be
|
||||
# system-unique, so it can be used to prevent accidental evaluation of the expression
|
||||
# in context different than intended (e.g. as a result of navigation accross process
|
||||
# boundaries).
|
||||
# This is mutually exclusive with `contextId`.
|
||||
experimental optional string uniqueContextId
|
||||
returns
|
||||
# Evaluation result.
|
||||
RemoteObject result
|
||||
|
@ -124,6 +124,8 @@ v8_source_set("inspector") {
|
||||
"v8-console.h",
|
||||
"v8-debugger-agent-impl.cc",
|
||||
"v8-debugger-agent-impl.h",
|
||||
"v8-debugger-id.cc",
|
||||
"v8-debugger-id.h",
|
||||
"v8-debugger-script.cc",
|
||||
"v8-debugger-script.h",
|
||||
"v8-debugger.cc",
|
||||
|
@ -55,7 +55,8 @@ InspectedContext::InspectedContext(V8InspectorImpl* inspector,
|
||||
m_contextGroupId(info.contextGroupId),
|
||||
m_origin(toString16(info.origin)),
|
||||
m_humanReadableName(toString16(info.humanReadableName)),
|
||||
m_auxData(toString16(info.auxData)) {
|
||||
m_auxData(toString16(info.auxData)),
|
||||
m_uniqueId(V8DebuggerId::generate(inspector)) {
|
||||
v8::debug::SetContextId(info.context, contextId);
|
||||
m_weakCallbackData =
|
||||
new WeakCallbackData(this, m_inspector, m_contextGroupId, m_contextId);
|
||||
|
@ -9,11 +9,11 @@
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "include/v8.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "src/debug/debug-interface.h"
|
||||
#include "src/inspector/string-16.h"
|
||||
|
||||
#include "include/v8.h"
|
||||
#include "src/inspector/v8-debugger-id.h"
|
||||
|
||||
namespace v8_inspector {
|
||||
|
||||
@ -37,6 +37,7 @@ class InspectedContext {
|
||||
int contextGroupId() const { return m_contextGroupId; }
|
||||
String16 origin() const { return m_origin; }
|
||||
String16 humanReadableName() const { return m_humanReadableName; }
|
||||
V8DebuggerId uniqueId() const { return m_uniqueId; }
|
||||
String16 auxData() const { return m_auxData; }
|
||||
|
||||
bool isReported(int sessionId) const;
|
||||
@ -66,6 +67,7 @@ class InspectedContext {
|
||||
const String16 m_origin;
|
||||
const String16 m_humanReadableName;
|
||||
const String16 m_auxData;
|
||||
const V8DebuggerId m_uniqueId;
|
||||
std::unordered_set<int> m_reportedSessionIds;
|
||||
std::unordered_map<int, std::unique_ptr<InjectedScript>> m_injectedScripts;
|
||||
WeakCallbackData* m_weakCallbackData;
|
||||
|
45
src/inspector/v8-debugger-id.cc
Normal file
45
src/inspector/v8-debugger-id.cc
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/inspector/v8-debugger-id.h"
|
||||
|
||||
#include "src/debug/debug-interface.h"
|
||||
#include "src/inspector/v8-inspector-impl.h"
|
||||
|
||||
namespace v8_inspector {
|
||||
|
||||
V8DebuggerId::V8DebuggerId(std::pair<int64_t, int64_t> pair)
|
||||
: m_first(pair.first), m_second(pair.second) {}
|
||||
|
||||
// static
|
||||
V8DebuggerId V8DebuggerId::generate(V8InspectorImpl* inspector) {
|
||||
return V8DebuggerId(std::make_pair(inspector->generateUniqueId(),
|
||||
inspector->generateUniqueId()));
|
||||
}
|
||||
|
||||
V8DebuggerId::V8DebuggerId(const String16& debuggerId) {
|
||||
const UChar dot = '.';
|
||||
size_t pos = debuggerId.find(dot);
|
||||
if (pos == String16::kNotFound) return;
|
||||
bool ok = false;
|
||||
int64_t first = debuggerId.substring(0, pos).toInteger64(&ok);
|
||||
if (!ok) return;
|
||||
int64_t second = debuggerId.substring(pos + 1).toInteger64(&ok);
|
||||
if (!ok) return;
|
||||
m_first = first;
|
||||
m_second = second;
|
||||
}
|
||||
|
||||
String16 V8DebuggerId::toString() const {
|
||||
return String16::fromInteger64(m_first) + "." +
|
||||
String16::fromInteger64(m_second);
|
||||
}
|
||||
|
||||
bool V8DebuggerId::isValid() const { return m_first || m_second; }
|
||||
|
||||
std::pair<int64_t, int64_t> V8DebuggerId::pair() const {
|
||||
return std::make_pair(m_first, m_second);
|
||||
}
|
||||
|
||||
} // namespace v8_inspector
|
44
src/inspector/v8-debugger-id.h
Normal file
44
src/inspector/v8-debugger-id.h
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_INSPECTOR_V8_DEBUGGER_ID_H_
|
||||
#define V8_INSPECTOR_V8_DEBUGGER_ID_H_
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "src/base/macros.h"
|
||||
#include "src/inspector/protocol/Forward.h"
|
||||
|
||||
namespace v8_inspector {
|
||||
|
||||
class V8InspectorImpl;
|
||||
|
||||
// This debugger id tries to be unique by generating two random
|
||||
// numbers, which should most likely avoid collisions.
|
||||
// Debugger id has a 1:1 mapping to context group. It is used to
|
||||
// attribute stack traces to a particular debugging, when doing any
|
||||
// cross-debugger operations (e.g. async step in).
|
||||
// See also Runtime.UniqueDebuggerId in the protocol.
|
||||
class V8DebuggerId {
|
||||
public:
|
||||
V8DebuggerId() = default;
|
||||
explicit V8DebuggerId(std::pair<int64_t, int64_t>);
|
||||
explicit V8DebuggerId(const String16&);
|
||||
V8DebuggerId(const V8DebuggerId&) V8_NOEXCEPT = default;
|
||||
~V8DebuggerId() = default;
|
||||
|
||||
static V8DebuggerId generate(V8InspectorImpl*);
|
||||
|
||||
String16 toString() const;
|
||||
bool isValid() const;
|
||||
std::pair<int64_t, int64_t> pair() const;
|
||||
|
||||
private:
|
||||
int64_t m_first = 0;
|
||||
int64_t m_second = 0;
|
||||
};
|
||||
|
||||
} // namespace v8_inspector
|
||||
|
||||
#endif // V8_INSPECTOR_V8_DEBUGGER_ID_H_
|
@ -64,39 +64,6 @@ class MatchPrototypePredicate : public v8::debug::QueryObjectPredicate {
|
||||
|
||||
} // namespace
|
||||
|
||||
V8DebuggerId::V8DebuggerId(std::pair<int64_t, int64_t> pair)
|
||||
: m_first(pair.first), m_second(pair.second) {}
|
||||
|
||||
// static
|
||||
V8DebuggerId V8DebuggerId::generate(V8InspectorImpl* inspector) {
|
||||
return V8DebuggerId(std::make_pair(inspector->generateUniqueId(),
|
||||
inspector->generateUniqueId()));
|
||||
}
|
||||
|
||||
V8DebuggerId::V8DebuggerId(const String16& debuggerId) {
|
||||
const UChar dot = '.';
|
||||
size_t pos = debuggerId.find(dot);
|
||||
if (pos == String16::kNotFound) return;
|
||||
bool ok = false;
|
||||
int64_t first = debuggerId.substring(0, pos).toInteger64(&ok);
|
||||
if (!ok) return;
|
||||
int64_t second = debuggerId.substring(pos + 1).toInteger64(&ok);
|
||||
if (!ok) return;
|
||||
m_first = first;
|
||||
m_second = second;
|
||||
}
|
||||
|
||||
String16 V8DebuggerId::toString() const {
|
||||
return String16::fromInteger64(m_first) + "." +
|
||||
String16::fromInteger64(m_second);
|
||||
}
|
||||
|
||||
bool V8DebuggerId::isValid() const { return m_first || m_second; }
|
||||
|
||||
std::pair<int64_t, int64_t> V8DebuggerId::pair() const {
|
||||
return std::make_pair(m_first, m_second);
|
||||
}
|
||||
|
||||
V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector)
|
||||
: m_isolate(isolate),
|
||||
m_inspector(inspector),
|
||||
|
@ -11,15 +11,15 @@
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "include/v8-inspector.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "src/inspector/inspected-context.h"
|
||||
#include "src/inspector/protocol/Debugger.h"
|
||||
#include "src/inspector/protocol/Forward.h"
|
||||
#include "src/inspector/protocol/Runtime.h"
|
||||
#include "src/inspector/v8-debugger-id.h"
|
||||
#include "src/inspector/v8-debugger-script.h"
|
||||
|
||||
#include "include/v8-inspector.h"
|
||||
|
||||
namespace v8_inspector {
|
||||
|
||||
class AsyncStackTrace;
|
||||
@ -36,31 +36,6 @@ using protocol::Response;
|
||||
using TerminateExecutionCallback =
|
||||
protocol::Runtime::Backend::TerminateExecutionCallback;
|
||||
|
||||
// This debugger id tries to be unique by generating two random
|
||||
// numbers, which should most likely avoid collisions.
|
||||
// Debugger id has a 1:1 mapping to context group. It is used to
|
||||
// attribute stack traces to a particular debugging, when doing any
|
||||
// cross-debugger operations (e.g. async step in).
|
||||
// See also Runtime.UniqueDebuggerId in the protocol.
|
||||
class V8DebuggerId {
|
||||
public:
|
||||
V8DebuggerId() = default;
|
||||
explicit V8DebuggerId(std::pair<int64_t, int64_t>);
|
||||
explicit V8DebuggerId(const String16&);
|
||||
V8DebuggerId(const V8DebuggerId&) V8_NOEXCEPT = default;
|
||||
~V8DebuggerId() = default;
|
||||
|
||||
static V8DebuggerId generate(V8InspectorImpl*);
|
||||
|
||||
String16 toString() const;
|
||||
bool isValid() const;
|
||||
std::pair<int64_t, int64_t> pair() const;
|
||||
|
||||
private:
|
||||
int64_t m_first = 0;
|
||||
int64_t m_second = 0;
|
||||
};
|
||||
|
||||
class V8Debugger : public v8::debug::DebugDelegate,
|
||||
public v8::debug::AsyncEventDelegate {
|
||||
public:
|
||||
|
@ -81,6 +81,11 @@ int V8InspectorImpl::contextGroupId(int contextId) const {
|
||||
return it != m_contextIdToGroupIdMap.end() ? it->second : 0;
|
||||
}
|
||||
|
||||
int V8InspectorImpl::resolveUniqueContextId(V8DebuggerId uniqueId) const {
|
||||
auto it = m_uniqueIdToContextId.find(uniqueId.pair());
|
||||
return it == m_uniqueIdToContextId.end() ? 0 : it->second;
|
||||
}
|
||||
|
||||
v8::MaybeLocal<v8::Value> V8InspectorImpl::compileAndRunInternalScript(
|
||||
v8::Local<v8::Context> context, v8::Local<v8::String> source) {
|
||||
v8::Local<v8::UnboundScript> unboundScript;
|
||||
@ -190,6 +195,11 @@ void V8InspectorImpl::contextCreated(const V8ContextInfo& info) {
|
||||
auto* context = new InspectedContext(this, info, contextId);
|
||||
m_contextIdToGroupIdMap[contextId] = info.contextGroupId;
|
||||
|
||||
DCHECK(m_uniqueIdToContextId.find(context->uniqueId().pair()) ==
|
||||
m_uniqueIdToContextId.end());
|
||||
m_uniqueIdToContextId.insert(
|
||||
std::make_pair(context->uniqueId().pair(), contextId));
|
||||
|
||||
auto contextIt = m_contexts.find(info.contextGroupId);
|
||||
if (contextIt == m_contexts.end())
|
||||
contextIt = m_contexts
|
||||
@ -233,14 +243,15 @@ void V8InspectorImpl::contextCollected(int groupId, int contextId) {
|
||||
void V8InspectorImpl::resetContextGroup(int contextGroupId) {
|
||||
m_consoleStorageMap.erase(contextGroupId);
|
||||
m_muteExceptionsMap.erase(contextGroupId);
|
||||
std::vector<int> contextIdsToClear;
|
||||
forEachContext(contextGroupId,
|
||||
[&contextIdsToClear](InspectedContext* context) {
|
||||
contextIdsToClear.push_back(context->contextId());
|
||||
});
|
||||
auto contextsIt = m_contexts.find(contextGroupId);
|
||||
// Context might have been removed already by discardContextScript()
|
||||
if (contextsIt != m_contexts.end()) {
|
||||
for (const auto& map_entry : *contextsIt->second)
|
||||
m_uniqueIdToContextId.erase(map_entry.second->uniqueId().pair());
|
||||
m_contexts.erase(contextsIt);
|
||||
}
|
||||
forEachSession(contextGroupId,
|
||||
[](V8InspectorSessionImpl* session) { session->reset(); });
|
||||
m_contexts.erase(contextGroupId);
|
||||
}
|
||||
|
||||
void V8InspectorImpl::idleStarted() { m_isolate->SetIdle(true); }
|
||||
@ -362,7 +373,9 @@ v8::Local<v8::Context> V8InspectorImpl::regexContext() {
|
||||
|
||||
void V8InspectorImpl::discardInspectedContext(int contextGroupId,
|
||||
int contextId) {
|
||||
if (!getContext(contextGroupId, contextId)) return;
|
||||
auto* context = getContext(contextGroupId, contextId);
|
||||
if (!context) return;
|
||||
m_uniqueIdToContextId.erase(context->uniqueId().pair());
|
||||
m_contexts[contextGroupId]->erase(contextId);
|
||||
if (m_contexts[contextGroupId]->empty()) m_contexts.erase(contextGroupId);
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ class V8InspectorImpl : public V8Inspector {
|
||||
int contextGroupId(v8::Local<v8::Context>) const;
|
||||
int contextGroupId(int contextId) const;
|
||||
uint64_t isolateId() const { return m_isolateId; }
|
||||
int resolveUniqueContextId(V8DebuggerId uniqueId) const;
|
||||
|
||||
v8::MaybeLocal<v8::Value> compileAndRunInternalScript(v8::Local<v8::Context>,
|
||||
v8::Local<v8::String>);
|
||||
@ -178,6 +179,7 @@ class V8InspectorImpl : public V8Inspector {
|
||||
ConsoleStorageMap m_consoleStorageMap;
|
||||
|
||||
std::unordered_map<int, int> m_contextIdToGroupIdMap;
|
||||
std::map<std::pair<int64_t, int64_t>, int> m_uniqueIdToContextId;
|
||||
|
||||
std::unique_ptr<V8Console> m_console;
|
||||
|
||||
|
@ -204,9 +204,21 @@ void innerCallFunctionOn(
|
||||
}
|
||||
|
||||
Response ensureContext(V8InspectorImpl* inspector, int contextGroupId,
|
||||
Maybe<int> executionContextId, int* contextId) {
|
||||
Maybe<int> executionContextId,
|
||||
Maybe<String16> uniqueContextId, int* contextId) {
|
||||
if (executionContextId.isJust()) {
|
||||
if (uniqueContextId.isJust()) {
|
||||
return Response::InvalidParams(
|
||||
"contextId and uniqueContextId are mutually exclusive");
|
||||
}
|
||||
*contextId = executionContextId.fromJust();
|
||||
} else if (uniqueContextId.isJust()) {
|
||||
V8DebuggerId uniqueId(uniqueContextId.fromJust());
|
||||
if (!uniqueId.isValid())
|
||||
return Response::InvalidParams("invalid uniqueContextId");
|
||||
int id = inspector->resolveUniqueContextId(uniqueId);
|
||||
if (!id) return Response::InvalidParams("uniqueContextId not found");
|
||||
*contextId = id;
|
||||
} else {
|
||||
v8::HandleScope handles(inspector->isolate());
|
||||
v8::Local<v8::Context> defaultContext =
|
||||
@ -215,6 +227,7 @@ Response ensureContext(V8InspectorImpl* inspector, int contextGroupId,
|
||||
return Response::ServerError("Cannot find default execution context");
|
||||
*contextId = InspectedContext::contextId(defaultContext);
|
||||
}
|
||||
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
@ -238,13 +251,14 @@ void V8RuntimeAgentImpl::evaluate(
|
||||
Maybe<bool> generatePreview, Maybe<bool> userGesture,
|
||||
Maybe<bool> maybeAwaitPromise, Maybe<bool> throwOnSideEffect,
|
||||
Maybe<double> timeout, Maybe<bool> disableBreaks, Maybe<bool> maybeReplMode,
|
||||
Maybe<bool> allowUnsafeEvalBlockedByCSP,
|
||||
Maybe<bool> allowUnsafeEvalBlockedByCSP, Maybe<String16> uniqueContextId,
|
||||
std::unique_ptr<EvaluateCallback> callback) {
|
||||
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
|
||||
"EvaluateScript");
|
||||
int contextId = 0;
|
||||
Response response = ensureContext(m_inspector, m_session->contextGroupId(),
|
||||
std::move(executionContextId), &contextId);
|
||||
std::move(executionContextId),
|
||||
std::move(uniqueContextId), &contextId);
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
@ -378,9 +392,9 @@ void V8RuntimeAgentImpl::callFunctionOn(
|
||||
std::move(callback));
|
||||
} else {
|
||||
int contextId = 0;
|
||||
Response response =
|
||||
ensureContext(m_inspector, m_session->contextGroupId(),
|
||||
std::move(executionContextId.fromJust()), &contextId);
|
||||
Response response = ensureContext(m_inspector, m_session->contextGroupId(),
|
||||
std::move(executionContextId.fromJust()),
|
||||
/* uniqueContextId */ {}, &contextId);
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
@ -497,7 +511,8 @@ Response V8RuntimeAgentImpl::compileScript(
|
||||
|
||||
int contextId = 0;
|
||||
Response response = ensureContext(m_inspector, m_session->contextGroupId(),
|
||||
std::move(executionContextId), &contextId);
|
||||
std::move(executionContextId),
|
||||
/*uniqueContextId*/ {}, &contextId);
|
||||
if (!response.IsSuccess()) return response;
|
||||
InjectedScript::ContextScope scope(m_session, contextId);
|
||||
response = scope.initialize();
|
||||
@ -550,7 +565,8 @@ void V8RuntimeAgentImpl::runScript(
|
||||
|
||||
int contextId = 0;
|
||||
Response response = ensureContext(m_inspector, m_session->contextGroupId(),
|
||||
std::move(executionContextId), &contextId);
|
||||
std::move(executionContextId),
|
||||
/*uniqueContextId*/ {}, &contextId);
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
@ -626,7 +642,8 @@ Response V8RuntimeAgentImpl::globalLexicalScopeNames(
|
||||
std::unique_ptr<protocol::Array<String16>>* outNames) {
|
||||
int contextId = 0;
|
||||
Response response = ensureContext(m_inspector, m_session->contextGroupId(),
|
||||
std::move(executionContextId), &contextId);
|
||||
std::move(executionContextId),
|
||||
/*uniqueContextId*/ {}, &contextId);
|
||||
if (!response.IsSuccess()) return response;
|
||||
|
||||
InjectedScript::ContextScope scope(m_session, contextId);
|
||||
@ -864,6 +881,7 @@ void V8RuntimeAgentImpl::reportExecutionContextCreated(
|
||||
.setId(context->contextId())
|
||||
.setName(context->humanReadableName())
|
||||
.setOrigin(context->origin())
|
||||
.setUniqueId(context->uniqueId().toString())
|
||||
.build();
|
||||
const String16& aux = context->auxData();
|
||||
if (!aux.isEmpty()) {
|
||||
|
@ -71,6 +71,7 @@ class V8RuntimeAgentImpl : public protocol::Runtime::Backend {
|
||||
Maybe<bool> awaitPromise, Maybe<bool> throwOnSideEffect,
|
||||
Maybe<double> timeout, Maybe<bool> disableBreaks,
|
||||
Maybe<bool> replMode, Maybe<bool> allowUnsafeEvalBlockedByCSP,
|
||||
Maybe<String16> uniqueContextId,
|
||||
std::unique_ptr<EvaluateCallback>) override;
|
||||
void awaitPromise(const String16& promiseObjectId, Maybe<bool> returnByValue,
|
||||
Maybe<bool> generatePreview,
|
||||
|
@ -36,7 +36,7 @@ InspectorTest.logMessage = function(originalMessage) {
|
||||
const nonStableFields = new Set([
|
||||
'objectId', 'scriptId', 'exceptionId', 'timestamp', 'executionContextId',
|
||||
'callFrameId', 'breakpointId', 'bindRemoteObjectFunctionId',
|
||||
'formatterObjectId', 'debuggerId', 'bodyGetterId'
|
||||
'formatterObjectId', 'debuggerId', 'bodyGetterId', 'uniqueId'
|
||||
]);
|
||||
const message = JSON.parse(JSON.stringify(originalMessage, replacer.bind(null, Symbol(), nonStableFields)));
|
||||
if (message.id)
|
||||
|
@ -6,6 +6,7 @@ Checks createContext().
|
||||
id : 1
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -16,6 +17,7 @@ Checks createContext().
|
||||
id : 2
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -37,6 +39,7 @@ Reported script's execution id: 2
|
||||
id : 1
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -47,6 +50,7 @@ Reported script's execution id: 2
|
||||
id : 2
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
Tests how Runtime.evaluate handles uniqueContextId argument
|
||||
token in context 1: context 1
|
||||
token in context 2: context 2
|
||||
{
|
||||
error : {
|
||||
code : -32602
|
||||
message : contextId and uniqueContextId are mutually exclusive
|
||||
}
|
||||
id : <messageId>
|
||||
}
|
||||
{
|
||||
error : {
|
||||
code : -32602
|
||||
message : invalid uniqueContextId
|
||||
}
|
||||
id : <messageId>
|
||||
}
|
||||
{
|
||||
error : {
|
||||
code : -32602
|
||||
message : uniqueContextId not found
|
||||
}
|
||||
id : <messageId>
|
||||
}
|
66
test/inspector/runtime/evaluate-unique-context-id.js
Normal file
66
test/inspector/runtime/evaluate-unique-context-id.js
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
const {Protocol, contextGroup} = InspectorTest.start(
|
||||
`Tests how Runtime.evaluate handles uniqueContextId argument`);
|
||||
|
||||
(async function test(){
|
||||
Protocol.Runtime.enable();
|
||||
const context1 = (await Protocol.Runtime.onceExecutionContextCreated()).params.context;
|
||||
|
||||
contextGroup.createContext();
|
||||
const context2 = (await Protocol.Runtime.onceExecutionContextCreated()).params.context;
|
||||
|
||||
Protocol.Runtime.evaluate({
|
||||
expression: 'token = "context 1";',
|
||||
contextId: context1.id
|
||||
});
|
||||
Protocol.Runtime.evaluate({
|
||||
expression: 'token = "context 2";',
|
||||
contextId: context2.id
|
||||
});
|
||||
|
||||
{
|
||||
const response = (await Protocol.Runtime.evaluate({
|
||||
expression: 'token',
|
||||
uniqueContextId: context1.uniqueId,
|
||||
returnByValue: true
|
||||
})).result.result.value;
|
||||
InspectorTest.logMessage(`token in context 1: ${response}`);
|
||||
}
|
||||
{
|
||||
const response = (await Protocol.Runtime.evaluate({
|
||||
expression: 'token',
|
||||
uniqueContextId: context2.uniqueId,
|
||||
returnByValue: true
|
||||
})).result.result.value;
|
||||
InspectorTest.logMessage(`token in context 2: ${response}`);
|
||||
}
|
||||
|
||||
// The following tests are for error handling.
|
||||
{
|
||||
const response = (await Protocol.Runtime.evaluate({
|
||||
expression: 'token',
|
||||
uniqueContextId: context1.uniqueId,
|
||||
contextId: context1.id
|
||||
}));
|
||||
InspectorTest.logMessage(response);
|
||||
}
|
||||
{
|
||||
const response = (await Protocol.Runtime.evaluate({
|
||||
expression: 'token',
|
||||
uniqueContextId: 'fubar',
|
||||
}));
|
||||
InspectorTest.logMessage(response);
|
||||
}
|
||||
{
|
||||
const response = (await Protocol.Runtime.evaluate({
|
||||
expression: 'token',
|
||||
uniqueContextId: context1.uniqueId + 1,
|
||||
}));
|
||||
InspectorTest.logMessage(response);
|
||||
}
|
||||
|
||||
InspectorTest.completeTest();
|
||||
})();
|
@ -8,6 +8,7 @@ Running test: testExecutionContextsNotificationsOnRestore
|
||||
id : 1
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -24,6 +25,7 @@ will reconnect..
|
||||
id : 1
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ From session 1
|
||||
id : 1
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -20,6 +21,7 @@ From session 2
|
||||
id : 1
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -32,6 +34,7 @@ From session 2
|
||||
id : 1
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -44,6 +47,7 @@ From session 1
|
||||
id : 1
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -56,6 +60,7 @@ From session 3
|
||||
id : 1
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,6 +97,7 @@ From session 2
|
||||
id : 2
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,6 +109,7 @@ From session 1
|
||||
id : 2
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,6 +121,7 @@ From session 3
|
||||
id : 2
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,6 +135,7 @@ From session 4
|
||||
id : 2
|
||||
name :
|
||||
origin :
|
||||
uniqueId : <uniqueId>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user