[DevTools] Roll inspector_protocol (V8)
Upstream PR: "Introduce a crdtp/dispatch.{h,cc} library." https://chromium-review.googlesource.com/c/deps/inspector_protocol/+/1974680 "For the shallow parse of a DevTools message, allow "params": null." https://chromium-review.googlesource.com/c/deps/inspector_protocol/+/2109466 New Revision: c69cdc36200992d21a17bf4e5c2f3a95b8860ddf Change-Id: Icc447ff9ce408b24f5245c643dd2f1843da9255f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2076215 Commit-Queue: Johannes Henkel <johannes@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Cr-Commit-Position: refs/heads/master@{#66813}
This commit is contained in:
parent
1e40c682e9
commit
fa3aada528
@ -116,7 +116,7 @@ bool substituteObjectTags(int sessionId, const String16& groupName,
|
||||
protocol::Response response =
|
||||
injectedScript->wrapObject(originValue, groupName, WrapMode::kNoPreview,
|
||||
configValue, maxDepth - 1, &wrapper);
|
||||
if (!response.isSuccess() || !wrapper) {
|
||||
if (!response.IsSuccess() || !wrapper) {
|
||||
reportError(context, tryCatch, "cannot wrap value");
|
||||
return false;
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ class InjectedScript::ProtocolPromiseHandler {
|
||||
if (!session) return;
|
||||
InjectedScript::ContextScope scope(session, m_executionContextId);
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) return;
|
||||
if (!response.IsSuccess()) return;
|
||||
|
||||
std::unique_ptr<EvaluateCallback> callback =
|
||||
scope.injectedScript()->takeEvaluateCallback(m_callback);
|
||||
@ -210,7 +210,7 @@ class InjectedScript::ProtocolPromiseHandler {
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
|
||||
response = scope.injectedScript()->wrapObject(result, m_objectGroup,
|
||||
m_wrapMode, &wrappedValue);
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -224,14 +224,14 @@ class InjectedScript::ProtocolPromiseHandler {
|
||||
if (!session) return;
|
||||
InjectedScript::ContextScope scope(session, m_executionContextId);
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) return;
|
||||
if (!response.IsSuccess()) return;
|
||||
std::unique_ptr<EvaluateCallback> callback =
|
||||
scope.injectedScript()->takeEvaluateCallback(m_callback);
|
||||
if (!callback) return;
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> wrappedValue;
|
||||
response = scope.injectedScript()->wrapObject(result, m_objectGroup,
|
||||
m_wrapMode, &wrappedValue);
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -251,7 +251,7 @@ class InjectedScript::ProtocolPromiseHandler {
|
||||
exceptionDetails;
|
||||
response = scope.injectedScript()->createExceptionDetails(
|
||||
message, exception, m_objectGroup, &exceptionDetails);
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -297,7 +297,7 @@ class InjectedScript::ProtocolPromiseHandler {
|
||||
.build();
|
||||
response = scope.injectedScript()->addExceptionToDetails(
|
||||
result, exceptionDetails.get(), m_objectGroup);
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -315,11 +315,11 @@ class InjectedScript::ProtocolPromiseHandler {
|
||||
if (!session) return;
|
||||
InjectedScript::ContextScope scope(session, m_executionContextId);
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) return;
|
||||
if (!response.IsSuccess()) return;
|
||||
std::unique_ptr<EvaluateCallback> callback =
|
||||
scope.injectedScript()->takeEvaluateCallback(m_callback);
|
||||
if (!callback) return;
|
||||
callback->sendFailure(Response::Error("Promise was collected"));
|
||||
callback->sendFailure(Response::ServerError("Promise was collected"));
|
||||
}
|
||||
|
||||
V8InspectorImpl* m_inspector;
|
||||
@ -380,60 +380,59 @@ Response InjectedScript::getProperties(
|
||||
.setEnumerable(mirror.enumerable)
|
||||
.setIsOwn(mirror.isOwn)
|
||||
.build();
|
||||
Response response;
|
||||
std::unique_ptr<RemoteObject> remoteObject;
|
||||
if (mirror.value) {
|
||||
response = wrapObjectMirror(*mirror.value, groupName, wrapMode,
|
||||
v8::MaybeLocal<v8::Value>(),
|
||||
kMaxCustomPreviewDepth, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
Response response = wrapObjectMirror(
|
||||
*mirror.value, groupName, wrapMode, v8::MaybeLocal<v8::Value>(),
|
||||
kMaxCustomPreviewDepth, &remoteObject);
|
||||
if (!response.IsSuccess()) return response;
|
||||
descriptor->setValue(std::move(remoteObject));
|
||||
descriptor->setWritable(mirror.writable);
|
||||
}
|
||||
if (mirror.getter) {
|
||||
response =
|
||||
Response response =
|
||||
mirror.getter->buildRemoteObject(context, wrapMode, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
response =
|
||||
bindRemoteObjectIfNeeded(sessionId, context, mirror.getter->v8Value(),
|
||||
groupName, remoteObject.get());
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
descriptor->setGet(std::move(remoteObject));
|
||||
}
|
||||
if (mirror.setter) {
|
||||
response =
|
||||
Response response =
|
||||
mirror.setter->buildRemoteObject(context, wrapMode, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
response =
|
||||
bindRemoteObjectIfNeeded(sessionId, context, mirror.setter->v8Value(),
|
||||
groupName, remoteObject.get());
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
descriptor->setSet(std::move(remoteObject));
|
||||
}
|
||||
if (mirror.symbol) {
|
||||
response =
|
||||
Response response =
|
||||
mirror.symbol->buildRemoteObject(context, wrapMode, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
response =
|
||||
bindRemoteObjectIfNeeded(sessionId, context, mirror.symbol->v8Value(),
|
||||
groupName, remoteObject.get());
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
descriptor->setSymbol(std::move(remoteObject));
|
||||
}
|
||||
if (mirror.exception) {
|
||||
response =
|
||||
Response response =
|
||||
mirror.exception->buildRemoteObject(context, wrapMode, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
response = bindRemoteObjectIfNeeded(sessionId, context,
|
||||
mirror.exception->v8Value(),
|
||||
groupName, remoteObject.get());
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
descriptor->setValue(std::move(remoteObject));
|
||||
descriptor->setWasThrown(true);
|
||||
}
|
||||
(*properties)->emplace_back(std::move(descriptor));
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response InjectedScript::getInternalAndPrivateProperties(
|
||||
@ -445,7 +444,7 @@ Response InjectedScript::getInternalAndPrivateProperties(
|
||||
*internalProperties = std::make_unique<Array<InternalPropertyDescriptor>>();
|
||||
*privateProperties = std::make_unique<Array<PrivatePropertyDescriptor>>();
|
||||
|
||||
if (!value->IsObject()) return Response::OK();
|
||||
if (!value->IsObject()) return Response::Success();
|
||||
|
||||
v8::Local<v8::Object> value_obj = value.As<v8::Object>();
|
||||
|
||||
@ -458,11 +457,11 @@ Response InjectedScript::getInternalAndPrivateProperties(
|
||||
std::unique_ptr<RemoteObject> remoteObject;
|
||||
Response response = internalProperty.value->buildRemoteObject(
|
||||
m_context->context(), WrapMode::kNoPreview, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
response = bindRemoteObjectIfNeeded(sessionId, context,
|
||||
internalProperty.value->v8Value(),
|
||||
groupName, remoteObject.get());
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
(*internalProperties)
|
||||
->emplace_back(InternalPropertyDescriptor::create()
|
||||
.setName(internalProperty.name)
|
||||
@ -479,45 +478,44 @@ Response InjectedScript::getInternalAndPrivateProperties(
|
||||
.build();
|
||||
|
||||
std::unique_ptr<RemoteObject> remoteObject;
|
||||
Response response;
|
||||
DCHECK((privateProperty.getter || privateProperty.setter) ^
|
||||
(!!privateProperty.value));
|
||||
if (privateProperty.value) {
|
||||
response = privateProperty.value->buildRemoteObject(
|
||||
Response response = privateProperty.value->buildRemoteObject(
|
||||
context, WrapMode::kNoPreview, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
response = bindRemoteObjectIfNeeded(sessionId, context,
|
||||
privateProperty.value->v8Value(),
|
||||
groupName, remoteObject.get());
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
descriptor->setValue(std::move(remoteObject));
|
||||
}
|
||||
|
||||
if (privateProperty.getter) {
|
||||
response = privateProperty.getter->buildRemoteObject(
|
||||
Response response = privateProperty.getter->buildRemoteObject(
|
||||
context, WrapMode::kNoPreview, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
response = bindRemoteObjectIfNeeded(sessionId, context,
|
||||
privateProperty.getter->v8Value(),
|
||||
groupName, remoteObject.get());
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
descriptor->setGet(std::move(remoteObject));
|
||||
}
|
||||
|
||||
if (privateProperty.setter) {
|
||||
response = privateProperty.setter->buildRemoteObject(
|
||||
Response response = privateProperty.setter->buildRemoteObject(
|
||||
context, WrapMode::kNoPreview, &remoteObject);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
response = bindRemoteObjectIfNeeded(sessionId, context,
|
||||
privateProperty.setter->v8Value(),
|
||||
groupName, remoteObject.get());
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
descriptor->setSet(std::move(remoteObject));
|
||||
}
|
||||
|
||||
(*privateProperties)->emplace_back(std::move(descriptor));
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void InjectedScript::releaseObject(const String16& objectId) {
|
||||
@ -564,11 +562,11 @@ Response InjectedScript::wrapObjectMirror(
|
||||
v8::Local<v8::Context> context = m_context->context();
|
||||
v8::Context::Scope contextScope(context);
|
||||
Response response = mirror.buildRemoteObject(context, wrapMode, result);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
v8::Local<v8::Value> value = mirror.v8Value();
|
||||
response = bindRemoteObjectIfNeeded(sessionId, context, value, groupName,
|
||||
result->get());
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
if (customPreviewEnabled && value->IsObject()) {
|
||||
std::unique_ptr<protocol::Runtime::CustomPreview> customPreview;
|
||||
generateCustomPreview(sessionId, groupName, value.As<v8::Object>(),
|
||||
@ -576,7 +574,7 @@ Response InjectedScript::wrapObjectMirror(
|
||||
&customPreview);
|
||||
if (customPreview) (*result)->setCustomPreview(std::move(customPreview));
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable(
|
||||
@ -593,7 +591,7 @@ std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable(
|
||||
std::unique_ptr<RemoteObject> remoteObject;
|
||||
Response response =
|
||||
wrapObject(table, "console", WrapMode::kNoPreview, &remoteObject);
|
||||
if (!remoteObject || !response.isSuccess()) return nullptr;
|
||||
if (!remoteObject || !response.IsSuccess()) return nullptr;
|
||||
|
||||
auto mirror = ValueMirror::create(context, table);
|
||||
std::unique_ptr<ObjectPreview> preview;
|
||||
@ -662,7 +660,8 @@ void InjectedScript::addPromiseCallback(
|
||||
|
||||
void InjectedScript::discardEvaluateCallbacks() {
|
||||
for (auto& callback : m_evaluateCallbacks) {
|
||||
callback->sendFailure(Response::Error("Execution context was destroyed."));
|
||||
callback->sendFailure(
|
||||
Response::ServerError("Execution context was destroyed."));
|
||||
delete callback;
|
||||
}
|
||||
m_evaluateCallbacks.clear();
|
||||
@ -681,9 +680,9 @@ Response InjectedScript::findObject(const RemoteObjectId& objectId,
|
||||
v8::Local<v8::Value>* outObject) const {
|
||||
auto it = m_idToWrappedObject.find(objectId.id());
|
||||
if (it == m_idToWrappedObject.end())
|
||||
return Response::Error("Could not find object with given id");
|
||||
return Response::ServerError("Could not find object with given id");
|
||||
*outObject = it->second.Get(m_context->isolate());
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
String16 InjectedScript::objectGroupName(const RemoteObjectId& objectId) const {
|
||||
@ -723,9 +722,9 @@ Response InjectedScript::resolveCallArgument(
|
||||
std::unique_ptr<RemoteObjectId> remoteObjectId;
|
||||
Response response =
|
||||
RemoteObjectId::parse(callArgument->getObjectId(""), &remoteObjectId);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
if (remoteObjectId->contextId() != m_context->contextId())
|
||||
return Response::Error(
|
||||
return Response::ServerError(
|
||||
"Argument should belong to the same JavaScript world as target "
|
||||
"object");
|
||||
return findObject(*remoteObjectId, result);
|
||||
@ -753,28 +752,29 @@ Response InjectedScript::resolveCallArgument(
|
||||
->compileAndRunInternalScript(
|
||||
m_context->context(), toV8String(m_context->isolate(), value))
|
||||
.ToLocal(result)) {
|
||||
return Response::Error("Couldn't parse value object in call argument");
|
||||
return Response::ServerError(
|
||||
"Couldn't parse value object in call argument");
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
*result = v8::Undefined(m_context->isolate());
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response InjectedScript::addExceptionToDetails(
|
||||
v8::Local<v8::Value> exception,
|
||||
protocol::Runtime::ExceptionDetails* exceptionDetails,
|
||||
const String16& objectGroup) {
|
||||
if (exception.IsEmpty()) return Response::OK();
|
||||
if (exception.IsEmpty()) return Response::Success();
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> wrapped;
|
||||
Response response =
|
||||
wrapObject(exception, objectGroup,
|
||||
exception->IsNativeError() ? WrapMode::kNoPreview
|
||||
: WrapMode::kWithPreview,
|
||||
&wrapped);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
exceptionDetails->setException(std::move(wrapped));
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response InjectedScript::createExceptionDetails(
|
||||
@ -821,9 +821,9 @@ Response InjectedScript::createExceptionDetails(
|
||||
}
|
||||
Response response =
|
||||
addExceptionToDetails(exception, exceptionDetails.get(), objectGroup);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
*result = std::move(exceptionDetails);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response InjectedScript::wrapEvaluateResult(
|
||||
@ -836,14 +836,14 @@ Response InjectedScript::wrapEvaluateResult(
|
||||
if (!maybeResultValue.ToLocal(&resultValue))
|
||||
return Response::InternalError();
|
||||
Response response = wrapObject(resultValue, objectGroup, wrapMode, result);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
if (objectGroup == "console") {
|
||||
m_lastEvaluationResult.Reset(m_context->isolate(), resultValue);
|
||||
m_lastEvaluationResult.AnnotateStrongRetainer(kGlobalHandleLabel);
|
||||
}
|
||||
} else {
|
||||
if (tryCatch.HasTerminated() || !tryCatch.CanContinue()) {
|
||||
return Response::Error("Execution was terminated");
|
||||
return Response::ServerError("Execution was terminated");
|
||||
}
|
||||
v8::Local<v8::Value> exception = tryCatch.Exception();
|
||||
Response response =
|
||||
@ -851,13 +851,13 @@ Response InjectedScript::wrapEvaluateResult(
|
||||
exception->IsNativeError() ? WrapMode::kNoPreview
|
||||
: WrapMode::kWithPreview,
|
||||
result);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
// We send exception in result for compatibility reasons, even though it's
|
||||
// accessible through exceptionDetails.exception.
|
||||
response = createExceptionDetails(tryCatch, objectGroup, exceptionDetails);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> InjectedScript::commandLineAPI() {
|
||||
@ -889,11 +889,11 @@ Response InjectedScript::Scope::initialize() {
|
||||
m_inspector->sessionById(m_contextGroupId, m_sessionId);
|
||||
if (!session) return Response::InternalError();
|
||||
Response response = findInjectedScript(session);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
m_context = m_injectedScript->context()->context();
|
||||
m_context->Enter();
|
||||
if (m_allowEval) m_context->AllowCodeGenerationFromStrings(true);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void InjectedScript::Scope::installCommandLineAPI() {
|
||||
@ -976,15 +976,15 @@ Response InjectedScript::ObjectScope::findInjectedScript(
|
||||
V8InspectorSessionImpl* session) {
|
||||
std::unique_ptr<RemoteObjectId> remoteId;
|
||||
Response response = RemoteObjectId::parse(m_remoteObjectId, &remoteId);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
InjectedScript* injectedScript = nullptr;
|
||||
response = session->findInjectedScript(remoteId.get(), injectedScript);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
m_objectGroupName = injectedScript->objectGroupName(*remoteId);
|
||||
response = injectedScript->findObject(*remoteId, &m_object);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
m_injectedScript = injectedScript;
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
InjectedScript::CallFrameScope::CallFrameScope(V8InspectorSessionImpl* session,
|
||||
@ -997,7 +997,7 @@ Response InjectedScript::CallFrameScope::findInjectedScript(
|
||||
V8InspectorSessionImpl* session) {
|
||||
std::unique_ptr<RemoteCallFrameId> remoteId;
|
||||
Response response = RemoteCallFrameId::parse(m_remoteCallFrameId, &remoteId);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
m_frameOrdinal = static_cast<size_t>(remoteId->frameOrdinal());
|
||||
return session->findInjectedScript(remoteId.get(), m_injectedScript);
|
||||
}
|
||||
@ -1022,9 +1022,9 @@ String16 InjectedScript::bindObject(v8::Local<v8::Value> value,
|
||||
Response InjectedScript::bindRemoteObjectIfNeeded(
|
||||
int sessionId, v8::Local<v8::Context> context, v8::Local<v8::Value> value,
|
||||
const String16& groupName, protocol::Runtime::RemoteObject* remoteObject) {
|
||||
if (!remoteObject) return Response::OK();
|
||||
if (remoteObject->hasValue()) return Response::OK();
|
||||
if (remoteObject->hasUnserializableValue()) return Response::OK();
|
||||
if (!remoteObject) return Response::Success();
|
||||
if (remoteObject->hasValue()) return Response::Success();
|
||||
if (remoteObject->hasUnserializableValue()) return Response::Success();
|
||||
if (remoteObject->getType() != RemoteObject::TypeEnum::Undefined) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
V8InspectorImpl* inspector =
|
||||
@ -1035,11 +1035,11 @@ Response InjectedScript::bindRemoteObjectIfNeeded(
|
||||
inspectedContext ? inspectedContext->getInjectedScript(sessionId)
|
||||
: nullptr;
|
||||
if (!injectedScript) {
|
||||
return Response::Error("Cannot find context with specified id");
|
||||
return Response::ServerError("Cannot find context with specified id");
|
||||
}
|
||||
remoteObject->setObjectId(injectedScript->bindObject(value, groupName));
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void InjectedScript::unbindObject(int id) {
|
||||
|
@ -38,12 +38,12 @@ Response RemoteObjectId::parse(const String16& objectId,
|
||||
std::unique_ptr<RemoteObjectId> remoteObjectId(new RemoteObjectId());
|
||||
std::unique_ptr<protocol::DictionaryValue> parsedObjectId =
|
||||
remoteObjectId->parseInjectedScriptId(objectId);
|
||||
if (!parsedObjectId) return Response::Error("Invalid remote object id");
|
||||
if (!parsedObjectId) return Response::ServerError("Invalid remote object id");
|
||||
|
||||
bool success = parsedObjectId->getInteger("id", &remoteObjectId->m_id);
|
||||
if (!success) return Response::Error("Invalid remote object id");
|
||||
if (!success) return Response::ServerError("Invalid remote object id");
|
||||
*result = std::move(remoteObjectId);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
RemoteCallFrameId::RemoteCallFrameId()
|
||||
@ -54,13 +54,13 @@ Response RemoteCallFrameId::parse(const String16& objectId,
|
||||
std::unique_ptr<RemoteCallFrameId> remoteCallFrameId(new RemoteCallFrameId());
|
||||
std::unique_ptr<protocol::DictionaryValue> parsedObjectId =
|
||||
remoteCallFrameId->parseInjectedScriptId(objectId);
|
||||
if (!parsedObjectId) return Response::Error("Invalid call frame id");
|
||||
if (!parsedObjectId) return Response::ServerError("Invalid call frame id");
|
||||
|
||||
bool success =
|
||||
parsedObjectId->getInteger("ordinal", &remoteCallFrameId->m_frameOrdinal);
|
||||
if (!success) return Response::Error("Invalid call frame id");
|
||||
if (!success) return Response::ServerError("Invalid call frame id");
|
||||
*result = std::move(remoteCallFrameId);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
String16 RemoteCallFrameId::serialize(int injectedScriptId, int frameOrdinal) {
|
||||
|
@ -161,3 +161,10 @@ String16 stackTraceIdToString(uintptr_t id) {
|
||||
}
|
||||
|
||||
} // namespace v8_inspector
|
||||
|
||||
namespace v8_crdtp {
|
||||
void SerializerTraits<v8_inspector::protocol::Binary>::Serialize(
|
||||
const v8_inspector::protocol::Binary& binary, std::vector<uint8_t>* out) {
|
||||
cbor::EncodeBinary(span<uint8_t>(binary.data(), binary.size()), out);
|
||||
}
|
||||
} // namespace v8_crdtp
|
||||
|
@ -24,17 +24,6 @@ using String = v8_inspector::String16;
|
||||
|
||||
class StringUtil {
|
||||
public:
|
||||
static String substring(const String& s, size_t pos, size_t len) {
|
||||
return s.substring(pos, len);
|
||||
}
|
||||
static size_t find(const String& s, const char* needle) {
|
||||
return s.find(needle);
|
||||
}
|
||||
static size_t find(const String& s, const String& needle) {
|
||||
return s.find(needle);
|
||||
}
|
||||
static const size_t kNotFound = String::kNotFound;
|
||||
|
||||
static String fromUTF8(const uint8_t* data, size_t length) {
|
||||
return String16::fromUTF8(reinterpret_cast<const char*>(data), length);
|
||||
}
|
||||
@ -100,4 +89,13 @@ String16 stackTraceIdToString(uintptr_t id);
|
||||
|
||||
} // namespace v8_inspector
|
||||
|
||||
// See third_party/inspector_protocol/crdtp/serializer_traits.h.
|
||||
namespace v8_crdtp {
|
||||
template <>
|
||||
struct SerializerTraits<v8_inspector::protocol::Binary> {
|
||||
static void Serialize(const v8_inspector::protocol::Binary& binary,
|
||||
std::vector<uint8_t>* out);
|
||||
};
|
||||
} // namespace v8_crdtp
|
||||
|
||||
#endif // V8_INSPECTOR_STRING_UTIL_H_
|
||||
|
@ -27,23 +27,23 @@ V8ConsoleAgentImpl::V8ConsoleAgentImpl(
|
||||
V8ConsoleAgentImpl::~V8ConsoleAgentImpl() = default;
|
||||
|
||||
Response V8ConsoleAgentImpl::enable() {
|
||||
if (m_enabled) return Response::OK();
|
||||
if (m_enabled) return Response::Success();
|
||||
m_state->setBoolean(ConsoleAgentState::consoleEnabled, true);
|
||||
m_enabled = true;
|
||||
m_session->inspector()->enableStackCapturingIfNeeded();
|
||||
reportAllMessages();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8ConsoleAgentImpl::disable() {
|
||||
if (!m_enabled) return Response::OK();
|
||||
if (!m_enabled) return Response::Success();
|
||||
m_session->inspector()->disableStackCapturingIfNeeded();
|
||||
m_state->setBoolean(ConsoleAgentState::consoleEnabled, false);
|
||||
m_enabled = false;
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8ConsoleAgentImpl::clearMessages() { return Response::OK(); }
|
||||
Response V8ConsoleAgentImpl::clearMessages() { return Response::Success(); }
|
||||
|
||||
void V8ConsoleAgentImpl::restore() {
|
||||
if (!m_state->booleanProperty(ConsoleAgentState::consoleEnabled, false))
|
||||
|
@ -595,7 +595,7 @@ static void inspectImpl(const v8::FunctionCallbackInfo<v8::Value>& info,
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject> wrappedObject;
|
||||
protocol::Response response = injectedScript->wrapObject(
|
||||
value, "", WrapMode::kNoPreview, &wrappedObject);
|
||||
if (!response.isSuccess()) return;
|
||||
if (!response.IsSuccess()) return;
|
||||
|
||||
std::unique_ptr<protocol::DictionaryValue> hints =
|
||||
protocol::DictionaryValue::create();
|
||||
|
@ -252,8 +252,8 @@ Response buildScopes(v8::Isolate* isolate, v8::debug::ScopeIterator* iterator,
|
||||
InjectedScript* injectedScript,
|
||||
std::unique_ptr<Array<Scope>>* scopes) {
|
||||
*scopes = std::make_unique<Array<Scope>>();
|
||||
if (!injectedScript) return Response::OK();
|
||||
if (iterator->Done()) return Response::OK();
|
||||
if (!injectedScript) return Response::Success();
|
||||
if (iterator->Done()) return Response::Success();
|
||||
|
||||
String16 scriptId = String16::fromInteger(iterator->GetScriptId());
|
||||
|
||||
@ -262,7 +262,7 @@ Response buildScopes(v8::Isolate* isolate, v8::debug::ScopeIterator* iterator,
|
||||
Response result =
|
||||
injectedScript->wrapObject(iterator->GetObject(), kBacktraceObjectGroup,
|
||||
WrapMode::kNoPreview, &object);
|
||||
if (!result.isSuccess()) return result;
|
||||
if (!result.IsSuccess()) return result;
|
||||
|
||||
auto scope = Scope::create()
|
||||
.setType(scopeType(iterator->GetType()))
|
||||
@ -290,7 +290,7 @@ Response buildScopes(v8::Isolate* isolate, v8::debug::ScopeIterator* iterator,
|
||||
}
|
||||
(*scopes)->emplace_back(std::move(scope));
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
protocol::DictionaryValue* getOrCreateObject(protocol::DictionaryValue* object,
|
||||
@ -344,17 +344,17 @@ Response V8DebuggerAgentImpl::enable(Maybe<double> maxScriptsCacheSize,
|
||||
maxScriptsCacheSize.fromMaybe(std::numeric_limits<double>::max()));
|
||||
*outDebuggerId =
|
||||
m_debugger->debuggerIdFor(m_session->contextGroupId()).toString();
|
||||
if (enabled()) return Response::OK();
|
||||
if (enabled()) return Response::Success();
|
||||
|
||||
if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId()))
|
||||
return Response::Error("Script execution is prohibited");
|
||||
return Response::ServerError("Script execution is prohibited");
|
||||
|
||||
enableImpl();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::disable() {
|
||||
if (!enabled()) return Response::OK();
|
||||
if (!enabled()) return Response::Success();
|
||||
|
||||
m_state->remove(DebuggerAgentState::breakpointsByRegex);
|
||||
m_state->remove(DebuggerAgentState::breakpointsByUrl);
|
||||
@ -389,7 +389,7 @@ Response V8DebuggerAgentImpl::disable() {
|
||||
m_enabled = false;
|
||||
m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
|
||||
m_debugger->disable();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void V8DebuggerAgentImpl::restore() {
|
||||
@ -421,21 +421,21 @@ void V8DebuggerAgentImpl::restore() {
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::setBreakpointsActive(bool active) {
|
||||
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
|
||||
if (m_breakpointsActive == active) return Response::OK();
|
||||
if (!enabled()) return Response::ServerError(kDebuggerNotEnabled);
|
||||
if (m_breakpointsActive == active) return Response::Success();
|
||||
m_breakpointsActive = active;
|
||||
m_debugger->setBreakpointsActive(active);
|
||||
if (!active && !m_breakReason.empty()) {
|
||||
clearBreakDetails();
|
||||
m_debugger->setPauseOnNextCall(false, m_session->contextGroupId());
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::setSkipAllPauses(bool skip) {
|
||||
m_state->setBoolean(DebuggerAgentState::skipAllPauses, skip);
|
||||
m_skipAllPauses = skip;
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
static bool matches(V8InspectorImpl* inspector, const V8DebuggerScript& script,
|
||||
@ -469,13 +469,14 @@ Response V8DebuggerAgentImpl::setBreakpointByUrl(
|
||||
(optionalURLRegex.isJust() ? 1 : 0) +
|
||||
(optionalScriptHash.isJust() ? 1 : 0);
|
||||
if (specified != 1) {
|
||||
return Response::Error(
|
||||
return Response::ServerError(
|
||||
"Either url or urlRegex or scriptHash must be specified.");
|
||||
}
|
||||
int columnNumber = 0;
|
||||
if (optionalColumnNumber.isJust()) {
|
||||
columnNumber = optionalColumnNumber.fromJust();
|
||||
if (columnNumber < 0) return Response::Error("Incorrect column number");
|
||||
if (columnNumber < 0)
|
||||
return Response::ServerError("Incorrect column number");
|
||||
}
|
||||
|
||||
BreakpointType type = BreakpointType::kByUrl;
|
||||
@ -515,7 +516,8 @@ Response V8DebuggerAgentImpl::setBreakpointByUrl(
|
||||
UNREACHABLE();
|
||||
}
|
||||
if (breakpoints->get(breakpointId)) {
|
||||
return Response::Error("Breakpoint at specified location already exists.");
|
||||
return Response::ServerError(
|
||||
"Breakpoint at specified location already exists.");
|
||||
}
|
||||
|
||||
String16 hint;
|
||||
@ -539,7 +541,7 @@ Response V8DebuggerAgentImpl::setBreakpointByUrl(
|
||||
breakpointHints->setString(breakpointId, hint);
|
||||
}
|
||||
*outBreakpointId = breakpointId;
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::setBreakpoint(
|
||||
@ -551,15 +553,17 @@ Response V8DebuggerAgentImpl::setBreakpoint(
|
||||
location->getLineNumber(), location->getColumnNumber(0));
|
||||
if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
|
||||
m_breakpointIdToDebuggerBreakpointIds.end()) {
|
||||
return Response::Error("Breakpoint at specified location already exists.");
|
||||
return Response::ServerError(
|
||||
"Breakpoint at specified location already exists.");
|
||||
}
|
||||
*actualLocation = setBreakpointImpl(breakpointId, location->getScriptId(),
|
||||
optionalCondition.fromMaybe(String16()),
|
||||
location->getLineNumber(),
|
||||
location->getColumnNumber(0));
|
||||
if (!*actualLocation) return Response::Error("Could not resolve breakpoint");
|
||||
if (!*actualLocation)
|
||||
return Response::ServerError("Could not resolve breakpoint");
|
||||
*outBreakpointId = breakpointId;
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::setBreakpointOnFunctionCall(
|
||||
@ -567,9 +571,9 @@ Response V8DebuggerAgentImpl::setBreakpointOnFunctionCall(
|
||||
String16* outBreakpointId) {
|
||||
InjectedScript::ObjectScope scope(m_session, functionObjectId);
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
if (!scope.object()->IsFunction()) {
|
||||
return Response::Error("Could not find function with given id");
|
||||
return Response::ServerError("Could not find function with given id");
|
||||
}
|
||||
v8::Local<v8::Function> function =
|
||||
v8::Local<v8::Function>::Cast(scope.object());
|
||||
@ -577,35 +581,37 @@ Response V8DebuggerAgentImpl::setBreakpointOnFunctionCall(
|
||||
generateBreakpointId(BreakpointType::kBreakpointAtEntry, function);
|
||||
if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
|
||||
m_breakpointIdToDebuggerBreakpointIds.end()) {
|
||||
return Response::Error("Breakpoint at specified location already exists.");
|
||||
return Response::ServerError(
|
||||
"Breakpoint at specified location already exists.");
|
||||
}
|
||||
v8::Local<v8::String> condition =
|
||||
toV8String(m_isolate, optionalCondition.fromMaybe(String16()));
|
||||
setBreakpointImpl(breakpointId, function, condition);
|
||||
*outBreakpointId = breakpointId;
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::setInstrumentationBreakpoint(
|
||||
const String16& instrumentation, String16* outBreakpointId) {
|
||||
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
|
||||
if (!enabled()) return Response::ServerError(kDebuggerNotEnabled);
|
||||
String16 breakpointId = generateInstrumentationBreakpointId(instrumentation);
|
||||
protocol::DictionaryValue* breakpoints = getOrCreateObject(
|
||||
m_state, DebuggerAgentState::instrumentationBreakpoints);
|
||||
if (breakpoints->get(breakpointId)) {
|
||||
return Response::Error("Instrumentation breakpoint is already enabled.");
|
||||
return Response::ServerError(
|
||||
"Instrumentation breakpoint is already enabled.");
|
||||
}
|
||||
breakpoints->setBoolean(breakpointId, true);
|
||||
*outBreakpointId = breakpointId;
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::removeBreakpoint(const String16& breakpointId) {
|
||||
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
|
||||
if (!enabled()) return Response::ServerError(kDebuggerNotEnabled);
|
||||
BreakpointType type;
|
||||
String16 selector;
|
||||
if (!parseBreakpointId(breakpointId, &type, &selector)) {
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
protocol::DictionaryValue* breakpoints = nullptr;
|
||||
switch (type) {
|
||||
@ -649,7 +655,7 @@ Response V8DebuggerAgentImpl::removeBreakpoint(const String16& breakpointId) {
|
||||
}
|
||||
removeBreakpointImpl(breakpointId, scripts);
|
||||
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void V8DebuggerAgentImpl::removeBreakpointImpl(
|
||||
@ -681,7 +687,7 @@ Response V8DebuggerAgentImpl::getPossibleBreakpoints(
|
||||
String16 scriptId = start->getScriptId();
|
||||
|
||||
if (start->getLineNumber() < 0 || start->getColumnNumber(0) < 0)
|
||||
return Response::Error(
|
||||
return Response::ServerError(
|
||||
"start.lineNumber and start.columnNumber should be >= 0");
|
||||
|
||||
v8::debug::Location v8Start(start->getLineNumber(),
|
||||
@ -689,23 +695,24 @@ Response V8DebuggerAgentImpl::getPossibleBreakpoints(
|
||||
v8::debug::Location v8End;
|
||||
if (end.isJust()) {
|
||||
if (end.fromJust()->getScriptId() != scriptId)
|
||||
return Response::Error("Locations should contain the same scriptId");
|
||||
return Response::ServerError(
|
||||
"Locations should contain the same scriptId");
|
||||
int line = end.fromJust()->getLineNumber();
|
||||
int column = end.fromJust()->getColumnNumber(0);
|
||||
if (line < 0 || column < 0)
|
||||
return Response::Error(
|
||||
return Response::ServerError(
|
||||
"end.lineNumber and end.columnNumber should be >= 0");
|
||||
v8End = v8::debug::Location(line, column);
|
||||
}
|
||||
auto it = m_scripts.find(scriptId);
|
||||
if (it == m_scripts.end()) return Response::Error("Script not found");
|
||||
if (it == m_scripts.end()) return Response::ServerError("Script not found");
|
||||
std::vector<v8::debug::BreakLocation> v8Locations;
|
||||
{
|
||||
v8::HandleScope handleScope(m_isolate);
|
||||
int contextId = it->second->executionContextId();
|
||||
InspectedContext* inspected = m_inspector->getContext(contextId);
|
||||
if (!inspected) {
|
||||
return Response::Error("Cannot retrive script context");
|
||||
return Response::ServerError("Cannot retrive script context");
|
||||
}
|
||||
v8::Context::Scope contextScope(inspected->context());
|
||||
v8::MicrotasksScope microtasks(m_isolate,
|
||||
@ -729,23 +736,23 @@ Response V8DebuggerAgentImpl::getPossibleBreakpoints(
|
||||
}
|
||||
(*locations)->emplace_back(std::move(breakLocation));
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::continueToLocation(
|
||||
std::unique_ptr<protocol::Debugger::Location> location,
|
||||
Maybe<String16> targetCallFrames) {
|
||||
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
|
||||
if (!isPaused()) return Response::Error(kDebuggerNotPaused);
|
||||
if (!enabled()) return Response::ServerError(kDebuggerNotEnabled);
|
||||
if (!isPaused()) return Response::ServerError(kDebuggerNotPaused);
|
||||
ScriptsMap::iterator it = m_scripts.find(location->getScriptId());
|
||||
if (it == m_scripts.end()) {
|
||||
return Response::Error("Cannot continue to specified location");
|
||||
return Response::ServerError("Cannot continue to specified location");
|
||||
}
|
||||
V8DebuggerScript* script = it->second.get();
|
||||
int contextId = script->executionContextId();
|
||||
InspectedContext* inspected = m_inspector->getContext(contextId);
|
||||
if (!inspected)
|
||||
return Response::Error("Cannot continue to specified location");
|
||||
return Response::ServerError("Cannot continue to specified location");
|
||||
v8::HandleScope handleScope(m_isolate);
|
||||
v8::Context::Scope contextScope(inspected->context());
|
||||
return m_debugger->continueToLocation(
|
||||
@ -759,7 +766,7 @@ Response V8DebuggerAgentImpl::getStackTrace(
|
||||
std::unique_ptr<protocol::Runtime::StackTrace>* outStackTrace) {
|
||||
bool isOk = false;
|
||||
int64_t id = inStackTraceId->getId().toInteger64(&isOk);
|
||||
if (!isOk) return Response::Error("Invalid stack trace id");
|
||||
if (!isOk) return Response::ServerError("Invalid stack trace id");
|
||||
|
||||
V8DebuggerId debuggerId;
|
||||
if (inStackTraceId->hasDebuggerId()) {
|
||||
@ -767,19 +774,20 @@ Response V8DebuggerAgentImpl::getStackTrace(
|
||||
} else {
|
||||
debuggerId = m_debugger->debuggerIdFor(m_session->contextGroupId());
|
||||
}
|
||||
if (!debuggerId.isValid()) return Response::Error("Invalid stack trace id");
|
||||
if (!debuggerId.isValid())
|
||||
return Response::ServerError("Invalid stack trace id");
|
||||
|
||||
V8StackTraceId v8StackTraceId(id, debuggerId.pair());
|
||||
if (v8StackTraceId.IsInvalid())
|
||||
return Response::Error("Invalid stack trace id");
|
||||
return Response::ServerError("Invalid stack trace id");
|
||||
auto stack =
|
||||
m_debugger->stackTraceFor(m_session->contextGroupId(), v8StackTraceId);
|
||||
if (!stack) {
|
||||
return Response::Error("Stack trace with given id is not found");
|
||||
return Response::ServerError("Stack trace with given id is not found");
|
||||
}
|
||||
*outStackTrace = stack->buildInspectorObject(
|
||||
m_debugger, m_debugger->maxAsyncCallChainDepth());
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
bool V8DebuggerAgentImpl::isFunctionBlackboxed(const String16& scriptId,
|
||||
@ -879,13 +887,13 @@ Response V8DebuggerAgentImpl::searchInContent(
|
||||
v8::HandleScope handles(m_isolate);
|
||||
ScriptsMap::iterator it = m_scripts.find(scriptId);
|
||||
if (it == m_scripts.end())
|
||||
return Response::Error("No script for id: " + scriptId);
|
||||
return Response::ServerError("No script for id: " + scriptId.utf8());
|
||||
|
||||
*results = std::make_unique<protocol::Array<protocol::Debugger::SearchMatch>>(
|
||||
searchInTextByLinesImpl(m_session, it->second->source(0), query,
|
||||
optionalCaseSensitive.fromMaybe(false),
|
||||
optionalIsRegex.fromMaybe(false)));
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::setScriptSource(
|
||||
@ -895,11 +903,11 @@ Response V8DebuggerAgentImpl::setScriptSource(
|
||||
Maybe<protocol::Runtime::StackTrace>* asyncStackTrace,
|
||||
Maybe<protocol::Runtime::StackTraceId>* asyncStackTraceId,
|
||||
Maybe<protocol::Runtime::ExceptionDetails>* optOutCompileError) {
|
||||
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
|
||||
if (!enabled()) return Response::ServerError(kDebuggerNotEnabled);
|
||||
|
||||
ScriptsMap::iterator it = m_scripts.find(scriptId);
|
||||
if (it == m_scripts.end()) {
|
||||
return Response::Error("No script with given id found");
|
||||
return Response::ServerError("No script with given id found");
|
||||
}
|
||||
int contextId = it->second->executionContextId();
|
||||
InspectedContext* inspected = m_inspector->getContext(contextId);
|
||||
@ -922,17 +930,17 @@ Response V8DebuggerAgentImpl::setScriptSource(
|
||||
.setColumnNumber(result.column_number != -1 ? result.column_number
|
||||
: 0)
|
||||
.build();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
} else {
|
||||
*stackChanged = result.stack_changed;
|
||||
}
|
||||
std::unique_ptr<Array<CallFrame>> callFrames;
|
||||
Response response = currentCallFrames(&callFrames);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
*newCallFrames = std::move(callFrames);
|
||||
*asyncStackTrace = currentAsyncStackTrace();
|
||||
*asyncStackTraceId = currentExternalStackTrace();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::restartFrame(
|
||||
@ -940,52 +948,52 @@ Response V8DebuggerAgentImpl::restartFrame(
|
||||
std::unique_ptr<Array<CallFrame>>* newCallFrames,
|
||||
Maybe<protocol::Runtime::StackTrace>* asyncStackTrace,
|
||||
Maybe<protocol::Runtime::StackTraceId>* asyncStackTraceId) {
|
||||
if (!isPaused()) return Response::Error(kDebuggerNotPaused);
|
||||
if (!isPaused()) return Response::ServerError(kDebuggerNotPaused);
|
||||
InjectedScript::CallFrameScope scope(m_session, callFrameId);
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
int frameOrdinal = static_cast<int>(scope.frameOrdinal());
|
||||
auto it = v8::debug::StackTraceIterator::Create(m_isolate, frameOrdinal);
|
||||
if (it->Done()) {
|
||||
return Response::Error("Could not find call frame with given id");
|
||||
return Response::ServerError("Could not find call frame with given id");
|
||||
}
|
||||
if (!it->Restart()) {
|
||||
return Response::InternalError();
|
||||
}
|
||||
response = currentCallFrames(newCallFrames);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
*asyncStackTrace = currentAsyncStackTrace();
|
||||
*asyncStackTraceId = currentExternalStackTrace();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::getScriptSource(
|
||||
const String16& scriptId, String16* scriptSource,
|
||||
Maybe<protocol::Binary>* bytecode) {
|
||||
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
|
||||
if (!enabled()) return Response::ServerError(kDebuggerNotEnabled);
|
||||
ScriptsMap::iterator it = m_scripts.find(scriptId);
|
||||
if (it == m_scripts.end())
|
||||
return Response::Error("No script for id: " + scriptId);
|
||||
return Response::ServerError("No script for id: " + scriptId.utf8());
|
||||
*scriptSource = it->second->source(0);
|
||||
v8::MemorySpan<const uint8_t> span;
|
||||
if (it->second->wasmBytecode().To(&span)) {
|
||||
*bytecode = protocol::Binary::fromSpan(span.data(), span.size());
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::getWasmBytecode(const String16& scriptId,
|
||||
protocol::Binary* bytecode) {
|
||||
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
|
||||
if (!enabled()) return Response::ServerError(kDebuggerNotEnabled);
|
||||
ScriptsMap::iterator it = m_scripts.find(scriptId);
|
||||
if (it == m_scripts.end())
|
||||
return Response::Error("No script for id: " + scriptId);
|
||||
return Response::ServerError("No script for id: " + scriptId.utf8());
|
||||
v8::MemorySpan<const uint8_t> span;
|
||||
if (!it->second->wasmBytecode().To(&span))
|
||||
return Response::Error("Script with id " + scriptId +
|
||||
" is not WebAssembly");
|
||||
return Response::ServerError("Script with id " + scriptId.utf8() +
|
||||
" is not WebAssembly");
|
||||
*bytecode = protocol::Binary::fromSpan(span.data(), span.size());
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void V8DebuggerAgentImpl::pushBreakDetails(
|
||||
@ -1023,8 +1031,8 @@ void V8DebuggerAgentImpl::cancelPauseOnNextStatement() {
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::pause() {
|
||||
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
|
||||
if (isPaused()) return Response::OK();
|
||||
if (!enabled()) return Response::ServerError(kDebuggerNotEnabled);
|
||||
if (isPaused()) return Response::Success();
|
||||
if (m_debugger->canBreakProgram()) {
|
||||
m_debugger->interruptAndBreak(m_session->contextGroupId());
|
||||
} else {
|
||||
@ -1033,48 +1041,48 @@ Response V8DebuggerAgentImpl::pause() {
|
||||
}
|
||||
pushBreakDetails(protocol::Debugger::Paused::ReasonEnum::Other, nullptr);
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::resume(Maybe<bool> terminateOnResume) {
|
||||
if (!isPaused()) return Response::Error(kDebuggerNotPaused);
|
||||
if (!isPaused()) return Response::ServerError(kDebuggerNotPaused);
|
||||
m_session->releaseObjectGroup(kBacktraceObjectGroup);
|
||||
m_debugger->continueProgram(m_session->contextGroupId(),
|
||||
terminateOnResume.fromMaybe(false));
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::stepOver() {
|
||||
if (!isPaused()) return Response::Error(kDebuggerNotPaused);
|
||||
if (!isPaused()) return Response::ServerError(kDebuggerNotPaused);
|
||||
m_session->releaseObjectGroup(kBacktraceObjectGroup);
|
||||
m_debugger->stepOverStatement(m_session->contextGroupId());
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::stepInto(Maybe<bool> inBreakOnAsyncCall) {
|
||||
if (!isPaused()) return Response::Error(kDebuggerNotPaused);
|
||||
if (!isPaused()) return Response::ServerError(kDebuggerNotPaused);
|
||||
m_session->releaseObjectGroup(kBacktraceObjectGroup);
|
||||
m_debugger->stepIntoStatement(m_session->contextGroupId(),
|
||||
inBreakOnAsyncCall.fromMaybe(false));
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::stepOut() {
|
||||
if (!isPaused()) return Response::Error(kDebuggerNotPaused);
|
||||
if (!isPaused()) return Response::ServerError(kDebuggerNotPaused);
|
||||
m_session->releaseObjectGroup(kBacktraceObjectGroup);
|
||||
m_debugger->stepOutOfFunction(m_session->contextGroupId());
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::pauseOnAsyncCall(
|
||||
std::unique_ptr<protocol::Runtime::StackTraceId> inParentStackTraceId) {
|
||||
// Deprecated, just return OK.
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::setPauseOnExceptions(
|
||||
const String16& stringPauseState) {
|
||||
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
|
||||
if (!enabled()) return Response::ServerError(kDebuggerNotEnabled);
|
||||
v8::debug::ExceptionBreakState pauseState;
|
||||
if (stringPauseState == "none") {
|
||||
pauseState = v8::debug::NoBreakOnException;
|
||||
@ -1083,11 +1091,11 @@ Response V8DebuggerAgentImpl::setPauseOnExceptions(
|
||||
} else if (stringPauseState == "uncaught") {
|
||||
pauseState = v8::debug::BreakOnUncaughtException;
|
||||
} else {
|
||||
return Response::Error("Unknown pause on exceptions mode: " +
|
||||
stringPauseState);
|
||||
return Response::ServerError("Unknown pause on exceptions mode: " +
|
||||
stringPauseState.utf8());
|
||||
}
|
||||
setPauseOnExceptionsImpl(pauseState);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void V8DebuggerAgentImpl::setPauseOnExceptionsImpl(int pauseState) {
|
||||
@ -1105,17 +1113,17 @@ Response V8DebuggerAgentImpl::evaluateOnCallFrame(
|
||||
Maybe<bool> throwOnSideEffect, Maybe<double> timeout,
|
||||
std::unique_ptr<RemoteObject>* result,
|
||||
Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
|
||||
if (!isPaused()) return Response::Error(kDebuggerNotPaused);
|
||||
if (!isPaused()) return Response::ServerError(kDebuggerNotPaused);
|
||||
InjectedScript::CallFrameScope scope(m_session, callFrameId);
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
|
||||
if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole();
|
||||
|
||||
int frameOrdinal = static_cast<int>(scope.frameOrdinal());
|
||||
auto it = v8::debug::StackTraceIterator::Create(m_isolate, frameOrdinal);
|
||||
if (it->Done()) {
|
||||
return Response::Error("Could not find call frame with given id");
|
||||
return Response::ServerError("Could not find call frame with given id");
|
||||
}
|
||||
|
||||
v8::MaybeLocal<v8::Value> maybeResultValue;
|
||||
@ -1123,7 +1131,7 @@ Response V8DebuggerAgentImpl::evaluateOnCallFrame(
|
||||
V8InspectorImpl::EvaluateScope evaluateScope(scope);
|
||||
if (timeout.isJust()) {
|
||||
response = evaluateScope.setTimeout(timeout.fromJust() / 1000.0);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
}
|
||||
maybeResultValue = it->Evaluate(toV8String(m_isolate, expression),
|
||||
throwOnSideEffect.fromMaybe(false));
|
||||
@ -1131,7 +1139,7 @@ Response V8DebuggerAgentImpl::evaluateOnCallFrame(
|
||||
// Re-initialize after running client's code, as it could have destroyed
|
||||
// context or session.
|
||||
response = scope.initialize();
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
|
||||
: WrapMode::kNoPreview;
|
||||
if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
|
||||
@ -1144,20 +1152,20 @@ Response V8DebuggerAgentImpl::setVariableValue(
|
||||
int scopeNumber, const String16& variableName,
|
||||
std::unique_ptr<protocol::Runtime::CallArgument> newValueArgument,
|
||||
const String16& callFrameId) {
|
||||
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
|
||||
if (!isPaused()) return Response::Error(kDebuggerNotPaused);
|
||||
if (!enabled()) return Response::ServerError(kDebuggerNotEnabled);
|
||||
if (!isPaused()) return Response::ServerError(kDebuggerNotPaused);
|
||||
InjectedScript::CallFrameScope scope(m_session, callFrameId);
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
v8::Local<v8::Value> newValue;
|
||||
response = scope.injectedScript()->resolveCallArgument(newValueArgument.get(),
|
||||
&newValue);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
|
||||
int frameOrdinal = static_cast<int>(scope.frameOrdinal());
|
||||
auto it = v8::debug::StackTraceIterator::Create(m_isolate, frameOrdinal);
|
||||
if (it->Done()) {
|
||||
return Response::Error("Could not find call frame with given id");
|
||||
return Response::ServerError("Could not find call frame with given id");
|
||||
}
|
||||
auto scopeIterator = it->GetScopeIterator();
|
||||
while (!scopeIterator->Done() && scopeNumber > 0) {
|
||||
@ -1165,7 +1173,7 @@ Response V8DebuggerAgentImpl::setVariableValue(
|
||||
scopeIterator->Advance();
|
||||
}
|
||||
if (scopeNumber != 0) {
|
||||
return Response::Error("Could not find scope with given number");
|
||||
return Response::ServerError("Could not find scope with given number");
|
||||
}
|
||||
|
||||
if (!scopeIterator->SetVariableValue(toV8String(m_isolate, variableName),
|
||||
@ -1173,40 +1181,40 @@ Response V8DebuggerAgentImpl::setVariableValue(
|
||||
scope.tryCatch().HasCaught()) {
|
||||
return Response::InternalError();
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::setReturnValue(
|
||||
std::unique_ptr<protocol::Runtime::CallArgument> protocolNewValue) {
|
||||
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
|
||||
if (!isPaused()) return Response::Error(kDebuggerNotPaused);
|
||||
if (!enabled()) return Response::ServerError(kDebuggerNotEnabled);
|
||||
if (!isPaused()) return Response::ServerError(kDebuggerNotPaused);
|
||||
v8::HandleScope handleScope(m_isolate);
|
||||
auto iterator = v8::debug::StackTraceIterator::Create(m_isolate);
|
||||
if (iterator->Done()) {
|
||||
return Response::Error("Could not find top call frame");
|
||||
return Response::ServerError("Could not find top call frame");
|
||||
}
|
||||
if (iterator->GetReturnValue().IsEmpty()) {
|
||||
return Response::Error(
|
||||
return Response::ServerError(
|
||||
"Could not update return value at non-return position");
|
||||
}
|
||||
InjectedScript::ContextScope scope(m_session, iterator->GetContextId());
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
v8::Local<v8::Value> newValue;
|
||||
response = scope.injectedScript()->resolveCallArgument(protocolNewValue.get(),
|
||||
&newValue);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
v8::debug::SetReturnValue(m_isolate, newValue);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::setAsyncCallStackDepth(int depth) {
|
||||
if (!enabled() && !m_session->runtimeAgent()->enabled()) {
|
||||
return Response::Error(kDebuggerNotEnabled);
|
||||
return Response::ServerError(kDebuggerNotEnabled);
|
||||
}
|
||||
m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, depth);
|
||||
m_debugger->setAsyncCallStackDepth(this, depth);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::setBlackboxPatterns(
|
||||
@ -1215,7 +1223,7 @@ Response V8DebuggerAgentImpl::setBlackboxPatterns(
|
||||
m_blackboxPattern = nullptr;
|
||||
resetBlackboxedStateCache();
|
||||
m_state->remove(DebuggerAgentState::blackboxPattern);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
String16Builder patternBuilder;
|
||||
@ -1228,19 +1236,20 @@ Response V8DebuggerAgentImpl::setBlackboxPatterns(
|
||||
patternBuilder.append(')');
|
||||
String16 pattern = patternBuilder.toString();
|
||||
Response response = setBlackboxPattern(pattern);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
resetBlackboxedStateCache();
|
||||
m_state->setString(DebuggerAgentState::blackboxPattern, pattern);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::setBlackboxPattern(const String16& pattern) {
|
||||
std::unique_ptr<V8Regex> regex(new V8Regex(
|
||||
m_inspector, pattern, true /** caseSensitive */, false /** multiline */));
|
||||
if (!regex->isValid())
|
||||
return Response::Error("Pattern parser error: " + regex->errorMessage());
|
||||
return Response::ServerError("Pattern parser error: " +
|
||||
regex->errorMessage().utf8());
|
||||
m_blackboxPattern = std::move(regex);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void V8DebuggerAgentImpl::resetBlackboxedStateCache() {
|
||||
@ -1255,12 +1264,12 @@ Response V8DebuggerAgentImpl::setBlackboxedRanges(
|
||||
inPositions) {
|
||||
auto it = m_scripts.find(scriptId);
|
||||
if (it == m_scripts.end())
|
||||
return Response::Error("No script with passed id.");
|
||||
return Response::ServerError("No script with passed id.");
|
||||
|
||||
if (inPositions->empty()) {
|
||||
m_blackboxedPositions.erase(scriptId);
|
||||
it->second->resetBlackboxedStateCache();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, int>> positions;
|
||||
@ -1268,9 +1277,10 @@ Response V8DebuggerAgentImpl::setBlackboxedRanges(
|
||||
for (const std::unique_ptr<protocol::Debugger::ScriptPosition>& position :
|
||||
*inPositions) {
|
||||
if (position->getLineNumber() < 0)
|
||||
return Response::Error("Position missing 'line' or 'line' < 0.");
|
||||
return Response::ServerError("Position missing 'line' or 'line' < 0.");
|
||||
if (position->getColumnNumber() < 0)
|
||||
return Response::Error("Position missing 'column' or 'column' < 0.");
|
||||
return Response::ServerError(
|
||||
"Position missing 'column' or 'column' < 0.");
|
||||
positions.push_back(
|
||||
std::make_pair(position->getLineNumber(), position->getColumnNumber()));
|
||||
}
|
||||
@ -1280,20 +1290,20 @@ Response V8DebuggerAgentImpl::setBlackboxedRanges(
|
||||
if (positions[i - 1].first == positions[i].first &&
|
||||
positions[i - 1].second < positions[i].second)
|
||||
continue;
|
||||
return Response::Error(
|
||||
return Response::ServerError(
|
||||
"Input positions array is not sorted or contains duplicate values.");
|
||||
}
|
||||
|
||||
m_blackboxedPositions[scriptId] = positions;
|
||||
it->second->resetBlackboxedStateCache();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::currentCallFrames(
|
||||
std::unique_ptr<Array<CallFrame>>* result) {
|
||||
if (!isPaused()) {
|
||||
*result = std::make_unique<Array<CallFrame>>();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
v8::HandleScope handles(m_isolate);
|
||||
*result = std::make_unique<Array<CallFrame>>();
|
||||
@ -1312,7 +1322,7 @@ Response V8DebuggerAgentImpl::currentCallFrames(
|
||||
auto scopeIterator = iterator->GetScopeIterator();
|
||||
Response res =
|
||||
buildScopes(m_isolate, scopeIterator.get(), injectedScript, &scopes);
|
||||
if (!res.isSuccess()) return res;
|
||||
if (!res.IsSuccess()) return res;
|
||||
|
||||
std::unique_ptr<RemoteObject> protocolReceiver;
|
||||
if (injectedScript) {
|
||||
@ -1321,7 +1331,7 @@ Response V8DebuggerAgentImpl::currentCallFrames(
|
||||
res =
|
||||
injectedScript->wrapObject(receiver, kBacktraceObjectGroup,
|
||||
WrapMode::kNoPreview, &protocolReceiver);
|
||||
if (!res.isSuccess()) return res;
|
||||
if (!res.IsSuccess()) return res;
|
||||
}
|
||||
}
|
||||
if (!protocolReceiver) {
|
||||
@ -1371,12 +1381,12 @@ Response V8DebuggerAgentImpl::currentCallFrames(
|
||||
std::unique_ptr<RemoteObject> value;
|
||||
res = injectedScript->wrapObject(returnValue, kBacktraceObjectGroup,
|
||||
WrapMode::kNoPreview, &value);
|
||||
if (!res.isSuccess()) return res;
|
||||
if (!res.IsSuccess()) return res;
|
||||
frame->setReturnValue(std::move(value));
|
||||
}
|
||||
(*result)->emplace_back(std::move(frame));
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
std::unique_ptr<protocol::Runtime::StackTrace>
|
||||
@ -1678,7 +1688,7 @@ void V8DebuggerAgentImpl::didPause(
|
||||
|
||||
std::unique_ptr<Array<CallFrame>> protocolCallFrames;
|
||||
Response response = currentCallFrames(&protocolCallFrames);
|
||||
if (!response.isSuccess())
|
||||
if (!response.IsSuccess())
|
||||
protocolCallFrames = std::make_unique<Array<CallFrame>>();
|
||||
|
||||
m_frontend.paused(std::move(protocolCallFrames), breakReason,
|
||||
|
@ -339,8 +339,8 @@ void V8Debugger::terminateExecution(
|
||||
std::unique_ptr<TerminateExecutionCallback> callback) {
|
||||
if (m_terminateExecutionCallback) {
|
||||
if (callback) {
|
||||
callback->sendFailure(
|
||||
Response::Error("There is current termination request in progress"));
|
||||
callback->sendFailure(Response::ServerError(
|
||||
"There is current termination request in progress"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -394,9 +394,9 @@ Response V8Debugger::continueToLocation(
|
||||
}
|
||||
continueProgram(targetContextGroupId);
|
||||
// TODO(kozyatinskiy): Return actual line and column number.
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
} else {
|
||||
return Response::Error("Cannot continue to specified location");
|
||||
return Response::ServerError("Cannot continue to specified location");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ void V8HeapProfilerAgentImpl::restore() {
|
||||
|
||||
Response V8HeapProfilerAgentImpl::collectGarbage() {
|
||||
m_isolate->LowMemoryNotification();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8HeapProfilerAgentImpl::startTrackingHeapObjects(
|
||||
@ -183,7 +183,7 @@ Response V8HeapProfilerAgentImpl::startTrackingHeapObjects(
|
||||
m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled,
|
||||
allocationTrackingEnabled);
|
||||
startTrackingHeapObjectsInternal(allocationTrackingEnabled);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8HeapProfilerAgentImpl::stopTrackingHeapObjects(
|
||||
@ -192,12 +192,12 @@ Response V8HeapProfilerAgentImpl::stopTrackingHeapObjects(
|
||||
takeHeapSnapshot(std::move(reportProgress),
|
||||
std::move(treatGlobalObjectsAsRoots));
|
||||
stopTrackingHeapObjectsInternal();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8HeapProfilerAgentImpl::enable() {
|
||||
m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, true);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8HeapProfilerAgentImpl::disable() {
|
||||
@ -209,13 +209,13 @@ Response V8HeapProfilerAgentImpl::disable() {
|
||||
}
|
||||
m_isolate->GetHeapProfiler()->ClearObjectIds();
|
||||
m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, false);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8HeapProfilerAgentImpl::takeHeapSnapshot(
|
||||
Maybe<bool> reportProgress, Maybe<bool> treatGlobalObjectsAsRoots) {
|
||||
v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler();
|
||||
if (!profiler) return Response::Error("Cannot access v8 heap profiler");
|
||||
if (!profiler) return Response::ServerError("Cannot access v8 heap profiler");
|
||||
std::unique_ptr<HeapSnapshotProgress> progress;
|
||||
if (reportProgress.fromMaybe(false))
|
||||
progress.reset(new HeapSnapshotProgress(&m_frontend));
|
||||
@ -223,11 +223,11 @@ Response V8HeapProfilerAgentImpl::takeHeapSnapshot(
|
||||
GlobalObjectNameResolver resolver(m_session);
|
||||
const v8::HeapSnapshot* snapshot = profiler->TakeHeapSnapshot(
|
||||
progress.get(), &resolver, treatGlobalObjectsAsRoots.fromMaybe(true));
|
||||
if (!snapshot) return Response::Error("Failed to take heap snapshot");
|
||||
if (!snapshot) return Response::ServerError("Failed to take heap snapshot");
|
||||
HeapSnapshotOutputStream stream(&m_frontend);
|
||||
snapshot->Serialize(&stream);
|
||||
const_cast<v8::HeapSnapshot*>(snapshot)->Delete();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8HeapProfilerAgentImpl::getObjectByHeapObjectId(
|
||||
@ -235,36 +235,38 @@ Response V8HeapProfilerAgentImpl::getObjectByHeapObjectId(
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>* result) {
|
||||
bool ok;
|
||||
int id = heapSnapshotObjectId.toInteger(&ok);
|
||||
if (!ok) return Response::Error("Invalid heap snapshot object id");
|
||||
if (!ok) return Response::ServerError("Invalid heap snapshot object id");
|
||||
|
||||
v8::HandleScope handles(m_isolate);
|
||||
v8::Local<v8::Object> heapObject = objectByHeapObjectId(m_isolate, id);
|
||||
if (heapObject.IsEmpty()) return Response::Error("Object is not available");
|
||||
if (heapObject.IsEmpty())
|
||||
return Response::ServerError("Object is not available");
|
||||
|
||||
if (!m_session->inspector()->client()->isInspectableHeapObject(heapObject))
|
||||
return Response::Error("Object is not available");
|
||||
return Response::ServerError("Object is not available");
|
||||
|
||||
*result = m_session->wrapObject(heapObject->CreationContext(), heapObject,
|
||||
objectGroup.fromMaybe(""), false);
|
||||
if (!*result) return Response::Error("Object is not available");
|
||||
return Response::OK();
|
||||
if (!*result) return Response::ServerError("Object is not available");
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8HeapProfilerAgentImpl::addInspectedHeapObject(
|
||||
const String16& inspectedHeapObjectId) {
|
||||
bool ok;
|
||||
int id = inspectedHeapObjectId.toInteger(&ok);
|
||||
if (!ok) return Response::Error("Invalid heap snapshot object id");
|
||||
if (!ok) return Response::ServerError("Invalid heap snapshot object id");
|
||||
|
||||
v8::HandleScope handles(m_isolate);
|
||||
v8::Local<v8::Object> heapObject = objectByHeapObjectId(m_isolate, id);
|
||||
if (heapObject.IsEmpty()) return Response::Error("Object is not available");
|
||||
if (heapObject.IsEmpty())
|
||||
return Response::ServerError("Object is not available");
|
||||
|
||||
if (!m_session->inspector()->client()->isInspectableHeapObject(heapObject))
|
||||
return Response::Error("Object is not available");
|
||||
return Response::ServerError("Object is not available");
|
||||
m_session->addInspectedObject(
|
||||
std::unique_ptr<InspectableHeapObject>(new InspectableHeapObject(id)));
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8HeapProfilerAgentImpl::getHeapObjectId(
|
||||
@ -274,12 +276,12 @@ Response V8HeapProfilerAgentImpl::getHeapObjectId(
|
||||
v8::Local<v8::Context> context;
|
||||
Response response =
|
||||
m_session->unwrapObject(objectId, &value, &context, nullptr);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
if (value->IsUndefined()) return Response::InternalError();
|
||||
|
||||
v8::SnapshotObjectId id = m_isolate->GetHeapProfiler()->GetObjectId(value);
|
||||
*heapSnapshotObjectId = String16::fromInteger(static_cast<size_t>(id));
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void V8HeapProfilerAgentImpl::requestHeapStatsUpdate() {
|
||||
@ -320,7 +322,7 @@ void V8HeapProfilerAgentImpl::stopTrackingHeapObjectsInternal() {
|
||||
Response V8HeapProfilerAgentImpl::startSampling(
|
||||
Maybe<double> samplingInterval) {
|
||||
v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler();
|
||||
if (!profiler) return Response::Error("Cannot access v8 heap profiler");
|
||||
if (!profiler) return Response::ServerError("Cannot access v8 heap profiler");
|
||||
const unsigned defaultSamplingInterval = 1 << 15;
|
||||
double samplingIntervalValue =
|
||||
samplingInterval.fromMaybe(defaultSamplingInterval);
|
||||
@ -331,7 +333,7 @@ Response V8HeapProfilerAgentImpl::startSampling(
|
||||
profiler->StartSamplingHeapProfiler(
|
||||
static_cast<uint64_t>(samplingIntervalValue), 128,
|
||||
v8::HeapProfiler::kSamplingForceGC);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -367,7 +369,7 @@ buildSampingHeapProfileNode(v8::Isolate* isolate,
|
||||
Response V8HeapProfilerAgentImpl::stopSampling(
|
||||
std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfile>* profile) {
|
||||
Response result = getSamplingProfile(profile);
|
||||
if (result.isSuccess()) {
|
||||
if (result.IsSuccess()) {
|
||||
m_isolate->GetHeapProfiler()->StopSamplingHeapProfiler();
|
||||
m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled,
|
||||
false);
|
||||
@ -383,7 +385,7 @@ Response V8HeapProfilerAgentImpl::getSamplingProfile(
|
||||
std::unique_ptr<v8::AllocationProfile> v8Profile(
|
||||
profiler->GetAllocationProfile());
|
||||
if (!v8Profile)
|
||||
return Response::Error("V8 sampling heap profiler was not started.");
|
||||
return Response::ServerError("V8 sampling heap profiler was not started.");
|
||||
v8::AllocationProfile::Node* root = v8Profile->GetRootNode();
|
||||
auto samples = std::make_unique<
|
||||
protocol::Array<protocol::HeapProfiler::SamplingHeapProfileSample>>();
|
||||
@ -399,7 +401,7 @@ Response V8HeapProfilerAgentImpl::getSamplingProfile(
|
||||
.setHead(buildSampingHeapProfileNode(m_isolate, root))
|
||||
.setSamples(std::move(samples))
|
||||
.build();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
} // namespace v8_inspector
|
||||
|
@ -467,12 +467,12 @@ class V8InspectorImpl::EvaluateScope::TerminateTask : public v8::Task {
|
||||
|
||||
protocol::Response V8InspectorImpl::EvaluateScope::setTimeout(double timeout) {
|
||||
if (m_isolate->IsExecutionTerminating()) {
|
||||
return protocol::Response::Error("Execution was terminated");
|
||||
return protocol::Response::ServerError("Execution was terminated");
|
||||
}
|
||||
m_cancelToken.reset(new CancelToken());
|
||||
v8::debug::GetCurrentPlatform()->CallDelayedOnWorkerThread(
|
||||
std::make_unique<TerminateTask>(m_isolate, m_cancelToken), timeout);
|
||||
return protocol::Response::OK();
|
||||
return protocol::Response::Success();
|
||||
}
|
||||
|
||||
} // namespace v8_inspector
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "src/inspector/v8-inspector-session-impl.h"
|
||||
|
||||
#include "../../third_party/inspector_protocol/crdtp/cbor.h"
|
||||
#include "../../third_party/inspector_protocol/crdtp/dispatch.h"
|
||||
#include "../../third_party/inspector_protocol/crdtp/json.h"
|
||||
#include "src/base/logging.h"
|
||||
#include "src/base/macros.h"
|
||||
@ -184,23 +185,24 @@ std::unique_ptr<StringBuffer> V8InspectorSessionImpl::serializeForFrontend(
|
||||
return StringBufferFrom(std::move(string16));
|
||||
}
|
||||
|
||||
void V8InspectorSessionImpl::sendProtocolResponse(
|
||||
void V8InspectorSessionImpl::SendProtocolResponse(
|
||||
int callId, std::unique_ptr<protocol::Serializable> message) {
|
||||
m_channel->sendResponse(callId, serializeForFrontend(std::move(message)));
|
||||
}
|
||||
|
||||
void V8InspectorSessionImpl::sendProtocolNotification(
|
||||
void V8InspectorSessionImpl::SendProtocolNotification(
|
||||
std::unique_ptr<protocol::Serializable> message) {
|
||||
m_channel->sendNotification(serializeForFrontend(std::move(message)));
|
||||
}
|
||||
|
||||
void V8InspectorSessionImpl::fallThrough(int callId, const String16& method,
|
||||
void V8InspectorSessionImpl::FallThrough(int callId,
|
||||
const v8_crdtp::span<uint8_t> method,
|
||||
v8_crdtp::span<uint8_t> message) {
|
||||
// There's no other layer to handle the command.
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void V8InspectorSessionImpl::flushProtocolNotifications() {
|
||||
void V8InspectorSessionImpl::FlushProtocolNotifications() {
|
||||
m_channel->flushProtocolNotifications();
|
||||
}
|
||||
|
||||
@ -224,14 +226,15 @@ Response V8InspectorSessionImpl::findInjectedScript(
|
||||
injectedScript = nullptr;
|
||||
InspectedContext* context =
|
||||
m_inspector->getContext(m_contextGroupId, contextId);
|
||||
if (!context) return Response::Error("Cannot find context with specified id");
|
||||
if (!context)
|
||||
return Response::ServerError("Cannot find context with specified id");
|
||||
injectedScript = context->getInjectedScript(m_sessionId);
|
||||
if (!injectedScript) {
|
||||
injectedScript = context->createInjectedScript(m_sessionId);
|
||||
if (m_customObjectFormatterEnabled)
|
||||
injectedScript->setCustomObjectFormatterEnabled(true);
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8InspectorSessionImpl::findInjectedScript(
|
||||
@ -259,8 +262,11 @@ bool V8InspectorSessionImpl::unwrapObject(
|
||||
String16 objectGroupString;
|
||||
Response response = unwrapObject(toString16(objectId), object, context,
|
||||
objectGroup ? &objectGroupString : nullptr);
|
||||
if (!response.isSuccess()) {
|
||||
if (error) *error = StringBufferFrom(response.errorMessage());
|
||||
if (response.IsError()) {
|
||||
if (error) {
|
||||
const std::string& msg = response.Message();
|
||||
*error = StringBufferFrom(String16::fromUTF8(msg.data(), msg.size()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (objectGroup)
|
||||
@ -274,15 +280,15 @@ Response V8InspectorSessionImpl::unwrapObject(const String16& objectId,
|
||||
String16* objectGroup) {
|
||||
std::unique_ptr<RemoteObjectId> remoteId;
|
||||
Response response = RemoteObjectId::parse(objectId, &remoteId);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
InjectedScript* injectedScript = nullptr;
|
||||
response = findInjectedScript(remoteId.get(), injectedScript);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
response = injectedScript->findObject(*remoteId, object);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
*context = injectedScript->context()->context();
|
||||
if (objectGroup) *objectGroup = injectedScript->objectGroupName(*remoteId);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
std::unique_ptr<protocol::Runtime::API::RemoteObject>
|
||||
@ -349,19 +355,29 @@ void V8InspectorSessionImpl::dispatchProtocolMessage(
|
||||
} else {
|
||||
// We're ignoring the return value of the conversion function
|
||||
// intentionally. It means the |parsed_message| below will be nullptr.
|
||||
ConvertToCBOR(message, &converted_cbor);
|
||||
auto status = ConvertToCBOR(message, &converted_cbor);
|
||||
if (!status.ok()) {
|
||||
m_channel->sendNotification(
|
||||
serializeForFrontend(v8_crdtp::CreateErrorNotification(
|
||||
v8_crdtp::DispatchResponse::ParseError(status.ToASCIIString()))));
|
||||
return;
|
||||
}
|
||||
cbor = SpanFrom(converted_cbor);
|
||||
}
|
||||
int callId;
|
||||
std::unique_ptr<protocol::Value> parsed_message =
|
||||
protocol::Value::parseBinary(cbor.data(), cbor.size());
|
||||
String16 method;
|
||||
if (m_dispatcher.parseCommand(parsed_message.get(), &callId, &method)) {
|
||||
// Pass empty string instead of the actual message to save on a conversion.
|
||||
// We're allowed to do so because fall-through is not implemented.
|
||||
m_dispatcher.dispatch(callId, method, std::move(parsed_message),
|
||||
v8_crdtp::span<uint8_t>());
|
||||
v8_crdtp::Dispatchable dispatchable(cbor);
|
||||
if (!dispatchable.ok()) {
|
||||
if (dispatchable.HasCallId()) {
|
||||
m_channel->sendNotification(serializeForFrontend(
|
||||
v8_crdtp::CreateErrorNotification(dispatchable.DispatchError())));
|
||||
} else {
|
||||
m_channel->sendResponse(
|
||||
dispatchable.CallId(),
|
||||
serializeForFrontend(v8_crdtp::CreateErrorResponse(
|
||||
dispatchable.CallId(), dispatchable.DispatchError())));
|
||||
}
|
||||
return;
|
||||
}
|
||||
m_dispatcher.Dispatch(dispatchable).Run();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> V8InspectorSessionImpl::state() {
|
||||
|
@ -100,13 +100,13 @@ class V8InspectorSessionImpl : public V8InspectorSession,
|
||||
protocol::DictionaryValue* agentState(const String16& name);
|
||||
|
||||
// protocol::FrontendChannel implementation.
|
||||
void sendProtocolResponse(
|
||||
void SendProtocolResponse(
|
||||
int callId, std::unique_ptr<protocol::Serializable> message) override;
|
||||
void sendProtocolNotification(
|
||||
void SendProtocolNotification(
|
||||
std::unique_ptr<protocol::Serializable> message) override;
|
||||
void fallThrough(int callId, const String16& method,
|
||||
void FallThrough(int callId, v8_crdtp::span<uint8_t> method,
|
||||
v8_crdtp::span<uint8_t> message) override;
|
||||
void flushProtocolNotifications() override;
|
||||
void FlushProtocolNotifications() override;
|
||||
|
||||
std::unique_ptr<StringBuffer> serializeForFrontend(
|
||||
std::unique_ptr<protocol::Serializable> message);
|
||||
|
@ -220,14 +220,14 @@ void V8ProfilerAgentImpl::consoleProfileEnd(const String16& title) {
|
||||
}
|
||||
|
||||
Response V8ProfilerAgentImpl::enable() {
|
||||
if (m_enabled) return Response::OK();
|
||||
if (m_enabled) return Response::Success();
|
||||
m_enabled = true;
|
||||
m_state->setBoolean(ProfilerAgentState::profilerEnabled, true);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8ProfilerAgentImpl::disable() {
|
||||
if (!m_enabled) return Response::OK();
|
||||
if (!m_enabled) return Response::Success();
|
||||
for (size_t i = m_startedProfiles.size(); i > 0; --i)
|
||||
stopProfiling(m_startedProfiles[i - 1].m_id, false);
|
||||
m_startedProfiles.clear();
|
||||
@ -236,15 +236,16 @@ Response V8ProfilerAgentImpl::disable() {
|
||||
DCHECK(!m_profiler);
|
||||
m_enabled = false;
|
||||
m_state->setBoolean(ProfilerAgentState::profilerEnabled, false);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8ProfilerAgentImpl::setSamplingInterval(int interval) {
|
||||
if (m_profiler) {
|
||||
return Response::Error("Cannot change sampling interval when profiling.");
|
||||
return Response::ServerError(
|
||||
"Cannot change sampling interval when profiling.");
|
||||
}
|
||||
m_state->setInteger(ProfilerAgentState::samplingInterval, interval);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void V8ProfilerAgentImpl::restore() {
|
||||
@ -272,36 +273,36 @@ void V8ProfilerAgentImpl::restore() {
|
||||
}
|
||||
|
||||
Response V8ProfilerAgentImpl::start() {
|
||||
if (m_recordingCPUProfile) return Response::OK();
|
||||
if (!m_enabled) return Response::Error("Profiler is not enabled");
|
||||
if (m_recordingCPUProfile) return Response::Success();
|
||||
if (!m_enabled) return Response::ServerError("Profiler is not enabled");
|
||||
m_recordingCPUProfile = true;
|
||||
m_frontendInitiatedProfileId = nextProfileId();
|
||||
startProfiling(m_frontendInitiatedProfileId);
|
||||
m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, true);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8ProfilerAgentImpl::stop(
|
||||
std::unique_ptr<protocol::Profiler::Profile>* profile) {
|
||||
if (!m_recordingCPUProfile) {
|
||||
return Response::Error("No recording profiles found");
|
||||
return Response::ServerError("No recording profiles found");
|
||||
}
|
||||
m_recordingCPUProfile = false;
|
||||
std::unique_ptr<protocol::Profiler::Profile> cpuProfile =
|
||||
stopProfiling(m_frontendInitiatedProfileId, !!profile);
|
||||
if (profile) {
|
||||
*profile = std::move(cpuProfile);
|
||||
if (!profile->get()) return Response::Error("Profile is not found");
|
||||
if (!profile->get()) return Response::ServerError("Profile is not found");
|
||||
}
|
||||
m_frontendInitiatedProfileId = String16();
|
||||
m_state->setBoolean(ProfilerAgentState::userInitiatedProfiling, false);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8ProfilerAgentImpl::startPreciseCoverage(
|
||||
Maybe<bool> callCount, Maybe<bool> detailed,
|
||||
Maybe<bool> allowTriggeredUpdates, double* out_timestamp) {
|
||||
if (!m_enabled) return Response::Error("Profiler is not enabled");
|
||||
if (!m_enabled) return Response::ServerError("Profiler is not enabled");
|
||||
*out_timestamp =
|
||||
v8::base::TimeTicks::HighResolutionNow().since_origin().InSecondsF();
|
||||
bool callCountValue = callCount.fromMaybe(false);
|
||||
@ -324,17 +325,17 @@ Response V8ProfilerAgentImpl::startPreciseCoverage(
|
||||
? (detailedValue ? Mode::kBlockCount : Mode::kPreciseCount)
|
||||
: (detailedValue ? Mode::kBlockBinary : Mode::kPreciseBinary);
|
||||
C::SelectMode(m_isolate, mode);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8ProfilerAgentImpl::stopPreciseCoverage() {
|
||||
if (!m_enabled) return Response::Error("Profiler is not enabled");
|
||||
if (!m_enabled) return Response::ServerError("Profiler is not enabled");
|
||||
m_state->setBoolean(ProfilerAgentState::preciseCoverageStarted, false);
|
||||
m_state->setBoolean(ProfilerAgentState::preciseCoverageCallCount, false);
|
||||
m_state->setBoolean(ProfilerAgentState::preciseCoverageDetailed, false);
|
||||
v8::debug::Coverage::SelectMode(m_isolate,
|
||||
v8::debug::CoverageMode::kBestEffort);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -402,7 +403,7 @@ Response coverageToProtocol(
|
||||
.build());
|
||||
}
|
||||
*out_result = std::move(result);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
@ -412,7 +413,7 @@ Response V8ProfilerAgentImpl::takePreciseCoverage(
|
||||
double* out_timestamp) {
|
||||
if (!m_state->booleanProperty(ProfilerAgentState::preciseCoverageStarted,
|
||||
false)) {
|
||||
return Response::Error("Precise coverage has not been started.");
|
||||
return Response::ServerError("Precise coverage has not been started.");
|
||||
}
|
||||
v8::HandleScope handle_scope(m_isolate);
|
||||
v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(m_isolate);
|
||||
@ -500,14 +501,14 @@ Response V8ProfilerAgentImpl::startTypeProfile() {
|
||||
m_state->setBoolean(ProfilerAgentState::typeProfileStarted, true);
|
||||
v8::debug::TypeProfile::SelectMode(m_isolate,
|
||||
v8::debug::TypeProfileMode::kCollect);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8ProfilerAgentImpl::stopTypeProfile() {
|
||||
m_state->setBoolean(ProfilerAgentState::typeProfileStarted, false);
|
||||
v8::debug::TypeProfile::SelectMode(m_isolate,
|
||||
v8::debug::TypeProfileMode::kNone);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8ProfilerAgentImpl::takeTypeProfile(
|
||||
@ -515,37 +516,38 @@ Response V8ProfilerAgentImpl::takeTypeProfile(
|
||||
out_result) {
|
||||
if (!m_state->booleanProperty(ProfilerAgentState::typeProfileStarted,
|
||||
false)) {
|
||||
return Response::Error("Type profile has not been started.");
|
||||
return Response::ServerError("Type profile has not been started.");
|
||||
}
|
||||
v8::HandleScope handle_scope(m_isolate);
|
||||
v8::debug::TypeProfile type_profile =
|
||||
v8::debug::TypeProfile::Collect(m_isolate);
|
||||
*out_result = typeProfileToProtocol(m_session->inspector(), type_profile);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8ProfilerAgentImpl::enableRuntimeCallStats() {
|
||||
if (m_counters)
|
||||
return Response::Error("RuntimeCallStats collection already enabled.");
|
||||
return Response::ServerError(
|
||||
"RuntimeCallStats collection already enabled.");
|
||||
|
||||
if (V8Inspector* inspector = v8::debug::GetInspector(m_isolate))
|
||||
m_counters = inspector->enableCounters();
|
||||
else
|
||||
return Response::Error("No inspector found.");
|
||||
return Response::ServerError("No inspector found.");
|
||||
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8ProfilerAgentImpl::disableRuntimeCallStats() {
|
||||
if (m_counters) m_counters.reset();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8ProfilerAgentImpl::getRuntimeCallStats(
|
||||
std::unique_ptr<protocol::Array<protocol::Profiler::CounterInfo>>*
|
||||
out_result) {
|
||||
if (!m_counters)
|
||||
return Response::Error("RuntimeCallStats collection is not enabled.");
|
||||
return Response::ServerError("RuntimeCallStats collection is not enabled.");
|
||||
|
||||
*out_result =
|
||||
std::make_unique<protocol::Array<protocol::Profiler::CounterInfo>>();
|
||||
@ -559,7 +561,7 @@ Response V8ProfilerAgentImpl::getRuntimeCallStats(
|
||||
.build());
|
||||
}
|
||||
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
String16 V8ProfilerAgentImpl::nextProfileId() {
|
||||
|
@ -99,7 +99,7 @@ bool wrapEvaluateResultAsync(InjectedScript* injectedScript,
|
||||
Response response = injectedScript->wrapEvaluateResult(
|
||||
maybeResultValue, tryCatch, objectGroup, wrapMode, &result,
|
||||
&exceptionDetails);
|
||||
if (response.isSuccess()) {
|
||||
if (response.IsSuccess()) {
|
||||
callback->sendSuccess(std::move(result), std::move(exceptionDetails));
|
||||
return true;
|
||||
}
|
||||
@ -128,7 +128,7 @@ void innerCallFunctionOn(
|
||||
v8::Local<v8::Value> argumentValue;
|
||||
Response response = scope.injectedScript()->resolveCallArgument(
|
||||
(*arguments)[i].get(), &argumentValue);
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -154,7 +154,7 @@ void innerCallFunctionOn(
|
||||
// Re-initialize after running client's code, as it could have destroyed
|
||||
// context or session.
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -169,8 +169,8 @@ void innerCallFunctionOn(
|
||||
v8::Local<v8::Value> functionValue;
|
||||
if (!maybeFunctionValue.ToLocal(&functionValue) ||
|
||||
!functionValue->IsFunction()) {
|
||||
callback->sendFailure(
|
||||
Response::Error("Given expression does not evaluate to a function"));
|
||||
callback->sendFailure(Response::ServerError(
|
||||
"Given expression does not evaluate to a function"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@ void innerCallFunctionOn(
|
||||
// Re-initialize after running client's code, as it could have destroyed
|
||||
// context or session.
|
||||
response = scope.initialize();
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -211,10 +211,10 @@ Response ensureContext(V8InspectorImpl* inspector, int contextGroupId,
|
||||
v8::Local<v8::Context> defaultContext =
|
||||
inspector->client()->ensureDefaultContextInGroup(contextGroupId);
|
||||
if (defaultContext.IsEmpty())
|
||||
return Response::Error("Cannot find default execution context");
|
||||
return Response::ServerError("Cannot find default execution context");
|
||||
*contextId = InspectedContext::contextId(defaultContext);
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -243,14 +243,14 @@ void V8RuntimeAgentImpl::evaluate(
|
||||
int contextId = 0;
|
||||
Response response = ensureContext(m_inspector, m_session->contextGroupId(),
|
||||
std::move(executionContextId), &contextId);
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
|
||||
InjectedScript::ContextScope scope(m_session, contextId);
|
||||
response = scope.initialize();
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -269,7 +269,7 @@ void V8RuntimeAgentImpl::evaluate(
|
||||
V8InspectorImpl::EvaluateScope evaluateScope(scope);
|
||||
if (timeout.isJust()) {
|
||||
response = evaluateScope.setTimeout(timeout.fromJust() / 1000.0);
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -292,7 +292,7 @@ void V8RuntimeAgentImpl::evaluate(
|
||||
// Re-initialize after running client's code, as it could have destroyed
|
||||
// context or session.
|
||||
response = scope.initialize();
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -320,13 +320,13 @@ void V8RuntimeAgentImpl::awaitPromise(
|
||||
std::unique_ptr<AwaitPromiseCallback> callback) {
|
||||
InjectedScript::ObjectScope scope(m_session, promiseObjectId);
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
if (!scope.object()->IsPromise()) {
|
||||
callback->sendFailure(
|
||||
Response::Error("Could not find promise with given id"));
|
||||
Response::ServerError("Could not find promise with given id"));
|
||||
return;
|
||||
}
|
||||
WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
|
||||
@ -346,12 +346,12 @@ void V8RuntimeAgentImpl::callFunctionOn(
|
||||
Maybe<int> executionContextId, Maybe<String16> objectGroup,
|
||||
std::unique_ptr<CallFunctionOnCallback> callback) {
|
||||
if (objectId.isJust() && executionContextId.isJust()) {
|
||||
callback->sendFailure(Response::Error(
|
||||
callback->sendFailure(Response::ServerError(
|
||||
"ObjectId must not be specified together with executionContextId"));
|
||||
return;
|
||||
}
|
||||
if (!objectId.isJust() && !executionContextId.isJust()) {
|
||||
callback->sendFailure(Response::Error(
|
||||
callback->sendFailure(Response::ServerError(
|
||||
"Either ObjectId or executionContextId must be specified"));
|
||||
return;
|
||||
}
|
||||
@ -361,7 +361,7 @@ void V8RuntimeAgentImpl::callFunctionOn(
|
||||
if (objectId.isJust()) {
|
||||
InjectedScript::ObjectScope scope(m_session, objectId.fromJust());
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -377,13 +377,13 @@ void V8RuntimeAgentImpl::callFunctionOn(
|
||||
Response response =
|
||||
ensureContext(m_inspector, m_session->contextGroupId(),
|
||||
std::move(executionContextId.fromJust()), &contextId);
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
InjectedScript::ContextScope scope(m_session, contextId);
|
||||
response = scope.initialize();
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -410,13 +410,13 @@ Response V8RuntimeAgentImpl::getProperties(
|
||||
|
||||
InjectedScript::ObjectScope scope(m_session, objectId);
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
|
||||
scope.ignoreExceptionsAndMuteConsole();
|
||||
v8::MicrotasksScope microtasks_scope(m_inspector->isolate(),
|
||||
v8::MicrotasksScope::kRunMicrotasks);
|
||||
if (!scope.object()->IsObject())
|
||||
return Response::Error("Value with given id is not an object");
|
||||
return Response::ServerError("Value with given id is not an object");
|
||||
|
||||
v8::Local<v8::Object> object = scope.object().As<v8::Object>();
|
||||
response = scope.injectedScript()->getProperties(
|
||||
@ -425,9 +425,9 @@ Response V8RuntimeAgentImpl::getProperties(
|
||||
generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
|
||||
: WrapMode::kNoPreview,
|
||||
result, exceptionDetails);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
if (exceptionDetails->isJust() || accessorPropertiesOnly.fromMaybe(false))
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
std::unique_ptr<protocol::Array<InternalPropertyDescriptor>>
|
||||
internalPropertiesProtocolArray;
|
||||
std::unique_ptr<protocol::Array<PrivatePropertyDescriptor>>
|
||||
@ -435,68 +435,69 @@ Response V8RuntimeAgentImpl::getProperties(
|
||||
response = scope.injectedScript()->getInternalAndPrivateProperties(
|
||||
object, scope.objectGroupName(), &internalPropertiesProtocolArray,
|
||||
&privatePropertiesProtocolArray);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
if (!internalPropertiesProtocolArray->empty())
|
||||
*internalProperties = std::move(internalPropertiesProtocolArray);
|
||||
if (!privatePropertiesProtocolArray->empty())
|
||||
*privateProperties = std::move(privatePropertiesProtocolArray);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8RuntimeAgentImpl::releaseObject(const String16& objectId) {
|
||||
InjectedScript::ObjectScope scope(m_session, objectId);
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
scope.injectedScript()->releaseObject(objectId);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8RuntimeAgentImpl::releaseObjectGroup(const String16& objectGroup) {
|
||||
m_session->releaseObjectGroup(objectGroup);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8RuntimeAgentImpl::runIfWaitingForDebugger() {
|
||||
m_inspector->client()->runIfWaitingForDebugger(m_session->contextGroupId());
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8RuntimeAgentImpl::setCustomObjectFormatterEnabled(bool enabled) {
|
||||
m_state->setBoolean(V8RuntimeAgentImplState::customObjectFormatterEnabled,
|
||||
enabled);
|
||||
if (!m_enabled) return Response::Error("Runtime agent is not enabled");
|
||||
if (!m_enabled) return Response::ServerError("Runtime agent is not enabled");
|
||||
m_session->setCustomObjectFormatterEnabled(enabled);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8RuntimeAgentImpl::setMaxCallStackSizeToCapture(int size) {
|
||||
if (size < 0) {
|
||||
return Response::Error("maxCallStackSizeToCapture should be non-negative");
|
||||
return Response::ServerError(
|
||||
"maxCallStackSizeToCapture should be non-negative");
|
||||
}
|
||||
V8StackTraceImpl::maxCallStackSizeToCapture = size;
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8RuntimeAgentImpl::discardConsoleEntries() {
|
||||
V8ConsoleMessageStorage* storage =
|
||||
m_inspector->ensureConsoleMessageStorage(m_session->contextGroupId());
|
||||
storage->clear();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8RuntimeAgentImpl::compileScript(
|
||||
const String16& expression, const String16& sourceURL, bool persistScript,
|
||||
Maybe<int> executionContextId, Maybe<String16>* scriptId,
|
||||
Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
|
||||
if (!m_enabled) return Response::Error("Runtime agent is not enabled");
|
||||
if (!m_enabled) return Response::ServerError("Runtime agent is not enabled");
|
||||
|
||||
int contextId = 0;
|
||||
Response response = ensureContext(m_inspector, m_session->contextGroupId(),
|
||||
std::move(executionContextId), &contextId);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
InjectedScript::ContextScope scope(m_session, contextId);
|
||||
response = scope.initialize();
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
|
||||
if (!persistScript) m_inspector->debugger()->muteScriptParsedEvents();
|
||||
v8::Local<v8::Script> script;
|
||||
@ -507,14 +508,14 @@ Response V8RuntimeAgentImpl::compileScript(
|
||||
if (scope.tryCatch().HasCaught()) {
|
||||
response = scope.injectedScript()->createExceptionDetails(
|
||||
scope.tryCatch(), String16(), exceptionDetails);
|
||||
if (!response.isSuccess()) return response;
|
||||
return Response::OK();
|
||||
if (!response.IsSuccess()) return response;
|
||||
return Response::Success();
|
||||
} else {
|
||||
return Response::Error("Script compilation failed");
|
||||
return Response::ServerError("Script compilation failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (!persistScript) return Response::OK();
|
||||
if (!persistScript) return Response::Success();
|
||||
|
||||
String16 scriptValueId =
|
||||
String16::fromInteger(script->GetUnboundScript()->GetId());
|
||||
@ -522,7 +523,7 @@ Response V8RuntimeAgentImpl::compileScript(
|
||||
new v8::Global<v8::Script>(m_inspector->isolate(), script));
|
||||
m_compiledScripts[scriptValueId] = std::move(global);
|
||||
*scriptId = scriptValueId;
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void V8RuntimeAgentImpl::runScript(
|
||||
@ -532,27 +533,28 @@ void V8RuntimeAgentImpl::runScript(
|
||||
Maybe<bool> generatePreview, Maybe<bool> awaitPromise,
|
||||
std::unique_ptr<RunScriptCallback> callback) {
|
||||
if (!m_enabled) {
|
||||
callback->sendFailure(Response::Error("Runtime agent is not enabled"));
|
||||
callback->sendFailure(
|
||||
Response::ServerError("Runtime agent is not enabled"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = m_compiledScripts.find(scriptId);
|
||||
if (it == m_compiledScripts.end()) {
|
||||
callback->sendFailure(Response::Error("No script with given id"));
|
||||
callback->sendFailure(Response::ServerError("No script with given id"));
|
||||
return;
|
||||
}
|
||||
|
||||
int contextId = 0;
|
||||
Response response = ensureContext(m_inspector, m_session->contextGroupId(),
|
||||
std::move(executionContextId), &contextId);
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
|
||||
InjectedScript::ContextScope scope(m_session, contextId);
|
||||
response = scope.initialize();
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -563,7 +565,7 @@ void V8RuntimeAgentImpl::runScript(
|
||||
m_compiledScripts.erase(it);
|
||||
v8::Local<v8::Script> script = scriptWrapper->Get(m_inspector->isolate());
|
||||
if (script.IsEmpty()) {
|
||||
callback->sendFailure(Response::Error("Script execution failed"));
|
||||
callback->sendFailure(Response::ServerError("Script execution failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -579,7 +581,7 @@ void V8RuntimeAgentImpl::runScript(
|
||||
// Re-initialize after running client's code, as it could have destroyed
|
||||
// context or session.
|
||||
response = scope.initialize();
|
||||
if (!response.isSuccess()) {
|
||||
if (!response.IsSuccess()) {
|
||||
callback->sendFailure(response);
|
||||
return;
|
||||
}
|
||||
@ -604,9 +606,9 @@ Response V8RuntimeAgentImpl::queryObjects(
|
||||
std::unique_ptr<protocol::Runtime::RemoteObject>* objects) {
|
||||
InjectedScript::ObjectScope scope(m_session, prototypeObjectId);
|
||||
Response response = scope.initialize();
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
if (!scope.object()->IsObject()) {
|
||||
return Response::Error("Prototype should be instance of Object");
|
||||
return Response::ServerError("Prototype should be instance of Object");
|
||||
}
|
||||
v8::Local<v8::Array> resultArray = m_inspector->debugger()->queryObjects(
|
||||
scope.context(), v8::Local<v8::Object>::Cast(scope.object()));
|
||||
@ -621,11 +623,11 @@ Response V8RuntimeAgentImpl::globalLexicalScopeNames(
|
||||
int contextId = 0;
|
||||
Response response = ensureContext(m_inspector, m_session->contextGroupId(),
|
||||
std::move(executionContextId), &contextId);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
|
||||
InjectedScript::ContextScope scope(m_session, contextId);
|
||||
response = scope.initialize();
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
|
||||
v8::PersistentValueVector<v8::String> names(m_inspector->isolate());
|
||||
v8::debug::GlobalLexicalScopeNames(scope.context(), &names);
|
||||
@ -634,14 +636,14 @@ Response V8RuntimeAgentImpl::globalLexicalScopeNames(
|
||||
(*outNames)->emplace_back(
|
||||
toProtocolString(m_inspector->isolate(), names.Get(i)));
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8RuntimeAgentImpl::getIsolateId(String16* outIsolateId) {
|
||||
char buf[40];
|
||||
std::snprintf(buf, sizeof(buf), "%" PRIx64, m_inspector->isolateId());
|
||||
*outIsolateId = buf;
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8RuntimeAgentImpl::getHeapUsage(double* out_usedSize,
|
||||
@ -650,7 +652,7 @@ Response V8RuntimeAgentImpl::getHeapUsage(double* out_usedSize,
|
||||
m_inspector->isolate()->GetHeapStatistics(&stats);
|
||||
*out_usedSize = stats.used_heap_size();
|
||||
*out_totalSize = stats.total_heap_size();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void V8RuntimeAgentImpl::terminateExecution(
|
||||
@ -666,25 +668,25 @@ Response V8RuntimeAgentImpl::addBinding(const String16& name,
|
||||
}
|
||||
protocol::DictionaryValue* bindings =
|
||||
m_state->getObject(V8RuntimeAgentImplState::bindings);
|
||||
if (bindings->booleanProperty(name, false)) return Response::OK();
|
||||
if (bindings->booleanProperty(name, false)) return Response::Success();
|
||||
if (executionContextId.isJust()) {
|
||||
int contextId = executionContextId.fromJust();
|
||||
InspectedContext* context =
|
||||
m_inspector->getContext(m_session->contextGroupId(), contextId);
|
||||
if (!context) {
|
||||
return Response::Error(
|
||||
return Response::ServerError(
|
||||
"Cannot find execution context with given executionContextId");
|
||||
}
|
||||
addBinding(context, name);
|
||||
// false means that we should not add this binding later.
|
||||
bindings->setBoolean(name, false);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
bindings->setBoolean(name, true);
|
||||
m_inspector->forEachContext(
|
||||
m_session->contextGroupId(),
|
||||
[&name, this](InspectedContext* context) { addBinding(context, name); });
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void V8RuntimeAgentImpl::bindingCallback(
|
||||
@ -731,9 +733,9 @@ void V8RuntimeAgentImpl::addBinding(InspectedContext* context,
|
||||
Response V8RuntimeAgentImpl::removeBinding(const String16& name) {
|
||||
protocol::DictionaryValue* bindings =
|
||||
m_state->getObject(V8RuntimeAgentImplState::bindings);
|
||||
if (!bindings) return Response::OK();
|
||||
if (!bindings) return Response::Success();
|
||||
bindings->remove(name);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void V8RuntimeAgentImpl::bindingCalled(const String16& name,
|
||||
@ -771,7 +773,7 @@ void V8RuntimeAgentImpl::restore() {
|
||||
}
|
||||
|
||||
Response V8RuntimeAgentImpl::enable() {
|
||||
if (m_enabled) return Response::OK();
|
||||
if (m_enabled) return Response::Success();
|
||||
m_inspector->client()->beginEnsureAllContextsInGroup(
|
||||
m_session->contextGroupId());
|
||||
m_enabled = true;
|
||||
@ -783,11 +785,11 @@ Response V8RuntimeAgentImpl::enable() {
|
||||
for (const auto& message : storage->messages()) {
|
||||
if (!reportMessage(message.get(), false)) break;
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
Response V8RuntimeAgentImpl::disable() {
|
||||
if (!m_enabled) return Response::OK();
|
||||
if (!m_enabled) return Response::Success();
|
||||
m_enabled = false;
|
||||
m_state->setBoolean(V8RuntimeAgentImplState::runtimeEnabled, false);
|
||||
m_state->remove(V8RuntimeAgentImplState::bindings);
|
||||
@ -799,7 +801,7 @@ Response V8RuntimeAgentImpl::disable() {
|
||||
if (m_session->debuggerAgent() && !m_session->debuggerAgent()->enabled()) {
|
||||
m_session->debuggerAgent()->setAsyncCallStackDepth(0);
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void V8RuntimeAgentImpl::reset() {
|
||||
|
@ -21,7 +21,7 @@ Response V8SchemaAgentImpl::getDomains(
|
||||
*result =
|
||||
std::make_unique<std::vector<std::unique_ptr<protocol::Schema::Domain>>>(
|
||||
m_session->supportedDomainsImpl());
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
} // namespace v8_inspector
|
||||
|
@ -42,17 +42,18 @@ V8InternalValueType v8InternalValueTypeFrom(v8::Local<v8::Context> context,
|
||||
Response toProtocolValue(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Value> value, int maxDepth,
|
||||
std::unique_ptr<protocol::Value>* result) {
|
||||
if (!maxDepth) return Response::Error("Object reference chain is too long");
|
||||
if (!maxDepth)
|
||||
return Response::ServerError("Object reference chain is too long");
|
||||
maxDepth--;
|
||||
|
||||
if (value->IsNull() || value->IsUndefined()) {
|
||||
*result = protocol::Value::null();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
if (value->IsBoolean()) {
|
||||
*result =
|
||||
protocol::FundamentalValue::create(value.As<v8::Boolean>()->Value());
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
if (value->IsNumber()) {
|
||||
double doubleValue = value.As<v8::Number>()->Value();
|
||||
@ -62,16 +63,16 @@ Response toProtocolValue(v8::Local<v8::Context> context,
|
||||
int intValue = static_cast<int>(doubleValue);
|
||||
if (intValue == doubleValue) {
|
||||
*result = protocol::FundamentalValue::create(intValue);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
}
|
||||
*result = protocol::FundamentalValue::create(doubleValue);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
if (value->IsString()) {
|
||||
*result = protocol::StringValue::create(
|
||||
toProtocolString(context->GetIsolate(), value.As<v8::String>()));
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
if (value->IsArray()) {
|
||||
v8::Local<v8::Array> array = value.As<v8::Array>();
|
||||
@ -84,11 +85,11 @@ Response toProtocolValue(v8::Local<v8::Context> context,
|
||||
return Response::InternalError();
|
||||
std::unique_ptr<protocol::Value> element;
|
||||
Response response = toProtocolValue(context, value, maxDepth, &element);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
inspectorArray->pushValue(std::move(element));
|
||||
}
|
||||
*result = std::move(inspectorArray);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
if (value->IsObject()) {
|
||||
std::unique_ptr<protocol::DictionaryValue> jsonObject =
|
||||
@ -119,21 +120,21 @@ Response toProtocolValue(v8::Local<v8::Context> context,
|
||||
std::unique_ptr<protocol::Value> propertyValue;
|
||||
Response response =
|
||||
toProtocolValue(context, property, maxDepth, &propertyValue);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
jsonObject->setValue(
|
||||
toProtocolString(context->GetIsolate(), propertyName),
|
||||
std::move(propertyValue));
|
||||
}
|
||||
*result = std::move(jsonObject);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
return Response::Error("Object couldn't be returned by value");
|
||||
return Response::ServerError("Object couldn't be returned by value");
|
||||
}
|
||||
|
||||
Response toProtocolValue(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Value> value,
|
||||
std::unique_ptr<protocol::Value>* result) {
|
||||
if (value->IsUndefined()) return Response::OK();
|
||||
if (value->IsUndefined()) return Response::Success();
|
||||
return toProtocolValue(context, value, 1000, result);
|
||||
}
|
||||
|
||||
@ -361,7 +362,7 @@ class PrimitiveValueMirror final : public ValueMirror {
|
||||
.build();
|
||||
if (m_value->IsNull())
|
||||
(*result)->setSubtype(RemoteObject::SubtypeEnum::Null);
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void buildEntryPreview(
|
||||
@ -416,7 +417,7 @@ class NumberMirror final : public ValueMirror {
|
||||
} else {
|
||||
(*result)->setValue(protocol::FundamentalValue::create(m_value->Value()));
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
void buildPropertyPreview(
|
||||
v8::Local<v8::Context> context, const String16& name,
|
||||
@ -470,7 +471,7 @@ class BigIntMirror final : public ValueMirror {
|
||||
.setUnserializableValue(description)
|
||||
.setDescription(description)
|
||||
.build();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void buildPropertyPreview(v8::Local<v8::Context> context,
|
||||
@ -513,13 +514,13 @@ class SymbolMirror final : public ValueMirror {
|
||||
v8::Local<v8::Context> context, WrapMode mode,
|
||||
std::unique_ptr<RemoteObject>* result) const override {
|
||||
if (mode == WrapMode::kForceValue) {
|
||||
return Response::Error("Object couldn't be returned by value");
|
||||
return Response::ServerError("Object couldn't be returned by value");
|
||||
}
|
||||
*result = RemoteObject::create()
|
||||
.setType(RemoteObject::TypeEnum::Symbol)
|
||||
.setDescription(descriptionForSymbol(context, m_symbol))
|
||||
.build();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void buildPropertyPreview(v8::Local<v8::Context> context,
|
||||
@ -576,7 +577,7 @@ class LocationMirror final : public ValueMirror {
|
||||
.setDescription("Object")
|
||||
.setValue(std::move(location))
|
||||
.build();
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
v8::Local<v8::Value> v8Value() const override { return m_value; }
|
||||
|
||||
@ -620,7 +621,7 @@ class FunctionMirror final : public ValueMirror {
|
||||
if (mode == WrapMode::kForceValue) {
|
||||
std::unique_ptr<protocol::Value> protocolValue;
|
||||
Response response = toProtocolValue(context, m_value, &protocolValue);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
*result = RemoteObject::create()
|
||||
.setType(RemoteObject::TypeEnum::Function)
|
||||
.setValue(std::move(protocolValue))
|
||||
@ -633,7 +634,7 @@ class FunctionMirror final : public ValueMirror {
|
||||
.setDescription(descriptionForFunction(context, m_value))
|
||||
.build();
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void buildPropertyPreview(
|
||||
@ -881,7 +882,7 @@ class ObjectMirror final : public ValueMirror {
|
||||
if (mode == WrapMode::kForceValue) {
|
||||
std::unique_ptr<protocol::Value> protocolValue;
|
||||
Response response = toProtocolValue(context, m_value, &protocolValue);
|
||||
if (!response.isSuccess()) return response;
|
||||
if (!response.IsSuccess()) return response;
|
||||
*result = RemoteObject::create()
|
||||
.setType(RemoteObject::TypeEnum::Object)
|
||||
.setValue(std::move(protocolValue))
|
||||
@ -904,7 +905,7 @@ class ObjectMirror final : public ValueMirror {
|
||||
(*result)->setPreview(std::move(previewValue));
|
||||
}
|
||||
}
|
||||
return Response::OK();
|
||||
return Response::Success();
|
||||
}
|
||||
|
||||
void buildObjectPreview(
|
||||
|
6
third_party/inspector_protocol/BUILD.gn
vendored
6
third_party/inspector_protocol/BUILD.gn
vendored
@ -14,9 +14,12 @@ v8_source_set("crdtp") {
|
||||
sources = [
|
||||
"crdtp/cbor.cc",
|
||||
"crdtp/cbor.h",
|
||||
"crdtp/dispatch.cc",
|
||||
"crdtp/dispatch.h",
|
||||
"crdtp/error_support.cc",
|
||||
"crdtp/error_support.h",
|
||||
"crdtp/export.h",
|
||||
"crdtp/find_by_first.h",
|
||||
"crdtp/glue.h",
|
||||
"crdtp/json.cc",
|
||||
"crdtp/json.h",
|
||||
@ -24,6 +27,7 @@ v8_source_set("crdtp") {
|
||||
"crdtp/serializable.cc",
|
||||
"crdtp/serializable.h",
|
||||
"crdtp/serializer_traits.h",
|
||||
"crdtp/span.cc",
|
||||
"crdtp/span.h",
|
||||
"crdtp/status.cc",
|
||||
"crdtp/status.h",
|
||||
@ -47,7 +51,9 @@ v8_source_set("crdtp_platform") {
|
||||
v8_source_set("crdtp_test") {
|
||||
sources = [
|
||||
"crdtp/cbor_test.cc",
|
||||
"crdtp/dispatch_test.cc",
|
||||
"crdtp/error_support_test.cc",
|
||||
"crdtp/find_by_first_test.cc",
|
||||
"crdtp/glue_test.cc",
|
||||
"crdtp/json_test.cc",
|
||||
"crdtp/serializable_test.cc",
|
||||
|
2
third_party/inspector_protocol/README.v8
vendored
2
third_party/inspector_protocol/README.v8
vendored
@ -2,7 +2,7 @@ Name: inspector protocol
|
||||
Short Name: inspector_protocol
|
||||
URL: https://chromium.googlesource.com/deps/inspector_protocol/
|
||||
Version: 0
|
||||
Revision: 81ef742ba3587767fc08652d299df9e9b7051407
|
||||
Revision: c69cdc36200992d21a17bf4e5c2f3a95b8860ddf
|
||||
License: BSD
|
||||
License File: LICENSE
|
||||
Security Critical: no
|
||||
|
@ -658,19 +658,16 @@ def main():
|
||||
"Values_h.template",
|
||||
"Object_h.template",
|
||||
"ValueConversions_h.template",
|
||||
"DispatcherBase_h.template",
|
||||
]
|
||||
|
||||
protocol_cpp_templates = [
|
||||
"Protocol_cpp.template",
|
||||
"Values_cpp.template",
|
||||
"Object_cpp.template",
|
||||
"DispatcherBase_cpp.template",
|
||||
]
|
||||
|
||||
forward_h_templates = [
|
||||
"Forward_h.template",
|
||||
"FrontendChannel_h.template",
|
||||
]
|
||||
|
||||
base_string_adapter_h_templates = [
|
||||
|
576
third_party/inspector_protocol/crdtp/dispatch.cc
vendored
Normal file
576
third_party/inspector_protocol/crdtp/dispatch.cc
vendored
Normal file
@ -0,0 +1,576 @@
|
||||
// Copyright 2020 The Chromium 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 "dispatch.h"
|
||||
|
||||
#include <cassert>
|
||||
#include "cbor.h"
|
||||
#include "error_support.h"
|
||||
#include "find_by_first.h"
|
||||
#include "frontend_channel.h"
|
||||
|
||||
namespace v8_crdtp {
|
||||
// =============================================================================
|
||||
// DispatchResponse - Error status and chaining / fall through
|
||||
// =============================================================================
|
||||
|
||||
// static
|
||||
DispatchResponse DispatchResponse::Success() {
|
||||
DispatchResponse result;
|
||||
result.code_ = DispatchCode::SUCCESS;
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
DispatchResponse DispatchResponse::FallThrough() {
|
||||
DispatchResponse result;
|
||||
result.code_ = DispatchCode::FALL_THROUGH;
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
DispatchResponse DispatchResponse::ParseError(std::string message) {
|
||||
DispatchResponse result;
|
||||
result.code_ = DispatchCode::PARSE_ERROR;
|
||||
result.message_ = std::move(message);
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
DispatchResponse DispatchResponse::InvalidRequest(std::string message) {
|
||||
DispatchResponse result;
|
||||
result.code_ = DispatchCode::INVALID_REQUEST;
|
||||
result.message_ = std::move(message);
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
DispatchResponse DispatchResponse::MethodNotFound(std::string message) {
|
||||
DispatchResponse result;
|
||||
result.code_ = DispatchCode::METHOD_NOT_FOUND;
|
||||
result.message_ = std::move(message);
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
DispatchResponse DispatchResponse::InvalidParams(std::string message) {
|
||||
DispatchResponse result;
|
||||
result.code_ = DispatchCode::INVALID_PARAMS;
|
||||
result.message_ = std::move(message);
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
DispatchResponse DispatchResponse::InternalError() {
|
||||
DispatchResponse result;
|
||||
result.code_ = DispatchCode::INTERNAL_ERROR;
|
||||
result.message_ = "Internal error";
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
DispatchResponse DispatchResponse::ServerError(std::string message) {
|
||||
DispatchResponse result;
|
||||
result.code_ = DispatchCode::SERVER_ERROR;
|
||||
result.message_ = std::move(message);
|
||||
return result;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Dispatchable - a shallow parser for CBOR encoded DevTools messages
|
||||
// =============================================================================
|
||||
namespace {
|
||||
constexpr size_t kEncodedEnvelopeHeaderSize = 1 + 1 + sizeof(uint32_t);
|
||||
} // namespace
|
||||
|
||||
Dispatchable::Dispatchable(span<uint8_t> serialized) : serialized_(serialized) {
|
||||
Status s = cbor::CheckCBORMessage(serialized);
|
||||
if (!s.ok()) {
|
||||
status_ = {Error::MESSAGE_MUST_BE_AN_OBJECT, s.pos};
|
||||
return;
|
||||
}
|
||||
cbor::CBORTokenizer tokenizer(serialized);
|
||||
if (tokenizer.TokenTag() == cbor::CBORTokenTag::ERROR_VALUE) {
|
||||
status_ = tokenizer.Status();
|
||||
return;
|
||||
}
|
||||
|
||||
// We checked for the envelope start byte above, so the tokenizer
|
||||
// must agree here, since it's not an error.
|
||||
assert(tokenizer.TokenTag() == cbor::CBORTokenTag::ENVELOPE);
|
||||
|
||||
// Before we enter the envelope, we save the position that we
|
||||
// expect to see after we're done parsing the envelope contents.
|
||||
// This way we can compare and produce an error if the contents
|
||||
// didn't fit exactly into the envelope length.
|
||||
const size_t pos_past_envelope = tokenizer.Status().pos +
|
||||
kEncodedEnvelopeHeaderSize +
|
||||
tokenizer.GetEnvelopeContents().size();
|
||||
tokenizer.EnterEnvelope();
|
||||
if (tokenizer.TokenTag() == cbor::CBORTokenTag::ERROR_VALUE) {
|
||||
status_ = tokenizer.Status();
|
||||
return;
|
||||
}
|
||||
if (tokenizer.TokenTag() != cbor::CBORTokenTag::MAP_START) {
|
||||
status_ = {Error::MESSAGE_MUST_BE_AN_OBJECT, tokenizer.Status().pos};
|
||||
return;
|
||||
}
|
||||
assert(tokenizer.TokenTag() == cbor::CBORTokenTag::MAP_START);
|
||||
tokenizer.Next(); // Now we should be pointed at the map key.
|
||||
while (tokenizer.TokenTag() != cbor::CBORTokenTag::STOP) {
|
||||
switch (tokenizer.TokenTag()) {
|
||||
case cbor::CBORTokenTag::DONE:
|
||||
status_ =
|
||||
Status{Error::CBOR_UNEXPECTED_EOF_IN_MAP, tokenizer.Status().pos};
|
||||
return;
|
||||
case cbor::CBORTokenTag::ERROR_VALUE:
|
||||
status_ = tokenizer.Status();
|
||||
return;
|
||||
case cbor::CBORTokenTag::STRING8:
|
||||
if (!MaybeParseProperty(&tokenizer))
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
// We require the top-level keys to be UTF8 (US-ASCII in practice).
|
||||
status_ = Status{Error::CBOR_INVALID_MAP_KEY, tokenizer.Status().pos};
|
||||
return;
|
||||
}
|
||||
}
|
||||
tokenizer.Next();
|
||||
if (!has_call_id_) {
|
||||
status_ = Status{Error::MESSAGE_MUST_HAVE_INTEGER_ID_PROPERTY,
|
||||
tokenizer.Status().pos};
|
||||
return;
|
||||
}
|
||||
if (method_.empty()) {
|
||||
status_ = Status{Error::MESSAGE_MUST_HAVE_STRING_METHOD_PROPERTY,
|
||||
tokenizer.Status().pos};
|
||||
return;
|
||||
}
|
||||
// The contents of the envelope parsed OK, now check that we're at
|
||||
// the expected position.
|
||||
if (pos_past_envelope != tokenizer.Status().pos) {
|
||||
status_ = Status{Error::CBOR_ENVELOPE_CONTENTS_LENGTH_MISMATCH,
|
||||
tokenizer.Status().pos};
|
||||
return;
|
||||
}
|
||||
if (tokenizer.TokenTag() != cbor::CBORTokenTag::DONE) {
|
||||
status_ = Status{Error::CBOR_TRAILING_JUNK, tokenizer.Status().pos};
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool Dispatchable::ok() const {
|
||||
return status_.ok();
|
||||
}
|
||||
|
||||
DispatchResponse Dispatchable::DispatchError() const {
|
||||
// TODO(johannes): Replace with DCHECK / similar?
|
||||
if (status_.ok())
|
||||
return DispatchResponse::Success();
|
||||
|
||||
if (status_.IsMessageError())
|
||||
return DispatchResponse::InvalidRequest(status_.Message());
|
||||
return DispatchResponse::ParseError(status_.ToASCIIString());
|
||||
}
|
||||
|
||||
bool Dispatchable::MaybeParseProperty(cbor::CBORTokenizer* tokenizer) {
|
||||
span<uint8_t> property_name = tokenizer->GetString8();
|
||||
if (SpanEquals(SpanFrom("id"), property_name))
|
||||
return MaybeParseCallId(tokenizer);
|
||||
if (SpanEquals(SpanFrom("method"), property_name))
|
||||
return MaybeParseMethod(tokenizer);
|
||||
if (SpanEquals(SpanFrom("params"), property_name))
|
||||
return MaybeParseParams(tokenizer);
|
||||
if (SpanEquals(SpanFrom("sessionId"), property_name))
|
||||
return MaybeParseSessionId(tokenizer);
|
||||
status_ =
|
||||
Status{Error::MESSAGE_HAS_UNKNOWN_PROPERTY, tokenizer->Status().pos};
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Dispatchable::MaybeParseCallId(cbor::CBORTokenizer* tokenizer) {
|
||||
if (has_call_id_) {
|
||||
status_ = Status{Error::CBOR_DUPLICATE_MAP_KEY, tokenizer->Status().pos};
|
||||
return false;
|
||||
}
|
||||
tokenizer->Next();
|
||||
if (tokenizer->TokenTag() != cbor::CBORTokenTag::INT32) {
|
||||
status_ = Status{Error::MESSAGE_MUST_HAVE_INTEGER_ID_PROPERTY,
|
||||
tokenizer->Status().pos};
|
||||
return false;
|
||||
}
|
||||
call_id_ = tokenizer->GetInt32();
|
||||
has_call_id_ = true;
|
||||
tokenizer->Next();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Dispatchable::MaybeParseMethod(cbor::CBORTokenizer* tokenizer) {
|
||||
if (!method_.empty()) {
|
||||
status_ = Status{Error::CBOR_DUPLICATE_MAP_KEY, tokenizer->Status().pos};
|
||||
return false;
|
||||
}
|
||||
tokenizer->Next();
|
||||
if (tokenizer->TokenTag() != cbor::CBORTokenTag::STRING8) {
|
||||
status_ = Status{Error::MESSAGE_MUST_HAVE_STRING_METHOD_PROPERTY,
|
||||
tokenizer->Status().pos};
|
||||
return false;
|
||||
}
|
||||
method_ = tokenizer->GetString8();
|
||||
tokenizer->Next();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Dispatchable::MaybeParseParams(cbor::CBORTokenizer* tokenizer) {
|
||||
if (params_seen_) {
|
||||
status_ = Status{Error::CBOR_DUPLICATE_MAP_KEY, tokenizer->Status().pos};
|
||||
return false;
|
||||
}
|
||||
params_seen_ = true;
|
||||
tokenizer->Next();
|
||||
if (tokenizer->TokenTag() == cbor::CBORTokenTag::NULL_VALUE) {
|
||||
tokenizer->Next();
|
||||
return true;
|
||||
}
|
||||
if (tokenizer->TokenTag() != cbor::CBORTokenTag::ENVELOPE) {
|
||||
status_ = Status{Error::MESSAGE_MAY_HAVE_OBJECT_PARAMS_PROPERTY,
|
||||
tokenizer->Status().pos};
|
||||
return false;
|
||||
}
|
||||
params_ = tokenizer->GetEnvelope();
|
||||
tokenizer->Next();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Dispatchable::MaybeParseSessionId(cbor::CBORTokenizer* tokenizer) {
|
||||
if (!session_id_.empty()) {
|
||||
status_ = Status{Error::CBOR_DUPLICATE_MAP_KEY, tokenizer->Status().pos};
|
||||
return false;
|
||||
}
|
||||
tokenizer->Next();
|
||||
if (tokenizer->TokenTag() != cbor::CBORTokenTag::STRING8) {
|
||||
status_ = Status{Error::MESSAGE_MAY_HAVE_STRING_SESSION_ID_PROPERTY,
|
||||
tokenizer->Status().pos};
|
||||
return false;
|
||||
}
|
||||
session_id_ = tokenizer->GetString8();
|
||||
tokenizer->Next();
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class ProtocolError : public Serializable {
|
||||
public:
|
||||
explicit ProtocolError(DispatchResponse dispatch_response)
|
||||
: dispatch_response_(std::move(dispatch_response)) {}
|
||||
|
||||
void AppendSerialized(std::vector<uint8_t>* out) const override {
|
||||
Status status;
|
||||
std::unique_ptr<ParserHandler> encoder = cbor::NewCBOREncoder(out, &status);
|
||||
encoder->HandleMapBegin();
|
||||
if (has_call_id_) {
|
||||
encoder->HandleString8(SpanFrom("id"));
|
||||
encoder->HandleInt32(call_id_);
|
||||
}
|
||||
encoder->HandleString8(SpanFrom("error"));
|
||||
encoder->HandleMapBegin();
|
||||
encoder->HandleString8(SpanFrom("code"));
|
||||
encoder->HandleInt32(static_cast<int32_t>(dispatch_response_.Code()));
|
||||
encoder->HandleString8(SpanFrom("message"));
|
||||
encoder->HandleString8(SpanFrom(dispatch_response_.Message()));
|
||||
if (!data_.empty()) {
|
||||
encoder->HandleString8(SpanFrom("data"));
|
||||
encoder->HandleString8(SpanFrom(data_));
|
||||
}
|
||||
encoder->HandleMapEnd();
|
||||
encoder->HandleMapEnd();
|
||||
assert(status.ok());
|
||||
}
|
||||
|
||||
void SetCallId(int call_id) {
|
||||
has_call_id_ = true;
|
||||
call_id_ = call_id;
|
||||
}
|
||||
void SetData(std::string data) { data_ = std::move(data); }
|
||||
|
||||
private:
|
||||
const DispatchResponse dispatch_response_;
|
||||
std::string data_;
|
||||
int call_id_ = 0;
|
||||
bool has_call_id_ = false;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// =============================================================================
|
||||
// Helpers for creating protocol cresponses and notifications.
|
||||
// =============================================================================
|
||||
|
||||
std::unique_ptr<Serializable> CreateErrorResponse(
|
||||
int call_id,
|
||||
DispatchResponse dispatch_response,
|
||||
const ErrorSupport* errors) {
|
||||
auto protocol_error =
|
||||
std::make_unique<ProtocolError>(std::move(dispatch_response));
|
||||
protocol_error->SetCallId(call_id);
|
||||
if (errors && !errors->Errors().empty()) {
|
||||
protocol_error->SetData(
|
||||
std::string(errors->Errors().begin(), errors->Errors().end()));
|
||||
}
|
||||
return protocol_error;
|
||||
}
|
||||
|
||||
std::unique_ptr<Serializable> CreateErrorNotification(
|
||||
DispatchResponse dispatch_response) {
|
||||
return std::make_unique<ProtocolError>(std::move(dispatch_response));
|
||||
}
|
||||
|
||||
namespace {
|
||||
class Response : public Serializable {
|
||||
public:
|
||||
Response(int call_id, std::unique_ptr<Serializable> params)
|
||||
: call_id_(call_id), params_(std::move(params)) {}
|
||||
|
||||
void AppendSerialized(std::vector<uint8_t>* out) const override {
|
||||
Status status;
|
||||
std::unique_ptr<ParserHandler> encoder = cbor::NewCBOREncoder(out, &status);
|
||||
encoder->HandleMapBegin();
|
||||
encoder->HandleString8(SpanFrom("id"));
|
||||
encoder->HandleInt32(call_id_);
|
||||
encoder->HandleString8(SpanFrom("result"));
|
||||
if (params_) {
|
||||
params_->AppendSerialized(out);
|
||||
} else {
|
||||
encoder->HandleMapBegin();
|
||||
encoder->HandleMapEnd();
|
||||
}
|
||||
encoder->HandleMapEnd();
|
||||
assert(status.ok());
|
||||
}
|
||||
|
||||
private:
|
||||
const int call_id_;
|
||||
std::unique_ptr<Serializable> params_;
|
||||
};
|
||||
|
||||
class Notification : public Serializable {
|
||||
public:
|
||||
Notification(const char* method, std::unique_ptr<Serializable> params)
|
||||
: method_(method), params_(std::move(params)) {}
|
||||
|
||||
void AppendSerialized(std::vector<uint8_t>* out) const override {
|
||||
Status status;
|
||||
std::unique_ptr<ParserHandler> encoder = cbor::NewCBOREncoder(out, &status);
|
||||
encoder->HandleMapBegin();
|
||||
encoder->HandleString8(SpanFrom("method"));
|
||||
encoder->HandleString8(SpanFrom(method_));
|
||||
encoder->HandleString8(SpanFrom("params"));
|
||||
if (params_) {
|
||||
params_->AppendSerialized(out);
|
||||
} else {
|
||||
encoder->HandleMapBegin();
|
||||
encoder->HandleMapEnd();
|
||||
}
|
||||
encoder->HandleMapEnd();
|
||||
assert(status.ok());
|
||||
}
|
||||
|
||||
private:
|
||||
const char* method_;
|
||||
std::unique_ptr<Serializable> params_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<Serializable> CreateResponse(
|
||||
int call_id,
|
||||
std::unique_ptr<Serializable> params) {
|
||||
return std::make_unique<Response>(call_id, std::move(params));
|
||||
}
|
||||
|
||||
std::unique_ptr<Serializable> CreateNotification(
|
||||
const char* method,
|
||||
std::unique_ptr<Serializable> params) {
|
||||
return std::make_unique<Notification>(method, std::move(params));
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// DomainDispatcher - Dispatching betwen protocol methods within a domain.
|
||||
// =============================================================================
|
||||
DomainDispatcher::WeakPtr::WeakPtr(DomainDispatcher* dispatcher)
|
||||
: dispatcher_(dispatcher) {}
|
||||
|
||||
DomainDispatcher::WeakPtr::~WeakPtr() {
|
||||
if (dispatcher_)
|
||||
dispatcher_->weak_ptrs_.erase(this);
|
||||
}
|
||||
|
||||
DomainDispatcher::Callback::~Callback() = default;
|
||||
|
||||
void DomainDispatcher::Callback::dispose() {
|
||||
backend_impl_ = nullptr;
|
||||
}
|
||||
|
||||
DomainDispatcher::Callback::Callback(
|
||||
std::unique_ptr<DomainDispatcher::WeakPtr> backend_impl,
|
||||
int call_id,
|
||||
span<uint8_t> method,
|
||||
span<uint8_t> message)
|
||||
: backend_impl_(std::move(backend_impl)),
|
||||
call_id_(call_id),
|
||||
method_(method),
|
||||
message_(message.begin(), message.end()) {}
|
||||
|
||||
void DomainDispatcher::Callback::sendIfActive(
|
||||
std::unique_ptr<Serializable> partialMessage,
|
||||
const DispatchResponse& response) {
|
||||
if (!backend_impl_ || !backend_impl_->get())
|
||||
return;
|
||||
backend_impl_->get()->sendResponse(call_id_, response,
|
||||
std::move(partialMessage));
|
||||
backend_impl_ = nullptr;
|
||||
}
|
||||
|
||||
void DomainDispatcher::Callback::fallThroughIfActive() {
|
||||
if (!backend_impl_ || !backend_impl_->get())
|
||||
return;
|
||||
backend_impl_->get()->channel()->FallThrough(call_id_, method_,
|
||||
SpanFrom(message_));
|
||||
backend_impl_ = nullptr;
|
||||
}
|
||||
|
||||
DomainDispatcher::DomainDispatcher(FrontendChannel* frontendChannel)
|
||||
: frontend_channel_(frontendChannel) {}
|
||||
|
||||
DomainDispatcher::~DomainDispatcher() {
|
||||
clearFrontend();
|
||||
}
|
||||
|
||||
void DomainDispatcher::sendResponse(int call_id,
|
||||
const DispatchResponse& response,
|
||||
std::unique_ptr<Serializable> result) {
|
||||
if (!frontend_channel_)
|
||||
return;
|
||||
std::unique_ptr<Serializable> serializable;
|
||||
if (response.IsError()) {
|
||||
serializable = CreateErrorResponse(call_id, response);
|
||||
} else {
|
||||
serializable = CreateResponse(call_id, std::move(result));
|
||||
}
|
||||
frontend_channel_->SendProtocolResponse(call_id, std::move(serializable));
|
||||
}
|
||||
|
||||
bool DomainDispatcher::MaybeReportInvalidParams(
|
||||
const Dispatchable& dispatchable,
|
||||
const ErrorSupport& errors) {
|
||||
if (errors.Errors().empty())
|
||||
return false;
|
||||
if (frontend_channel_) {
|
||||
frontend_channel_->SendProtocolResponse(
|
||||
dispatchable.CallId(),
|
||||
CreateErrorResponse(
|
||||
dispatchable.CallId(),
|
||||
DispatchResponse::InvalidParams("Invalid parameters"), &errors));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DomainDispatcher::clearFrontend() {
|
||||
frontend_channel_ = nullptr;
|
||||
for (auto& weak : weak_ptrs_)
|
||||
weak->dispose();
|
||||
weak_ptrs_.clear();
|
||||
}
|
||||
|
||||
std::unique_ptr<DomainDispatcher::WeakPtr> DomainDispatcher::weakPtr() {
|
||||
auto weak = std::make_unique<DomainDispatcher::WeakPtr>(this);
|
||||
weak_ptrs_.insert(weak.get());
|
||||
return weak;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// UberDispatcher - dispatches between domains (backends).
|
||||
// =============================================================================
|
||||
UberDispatcher::DispatchResult::DispatchResult(bool method_found,
|
||||
std::function<void()> runnable)
|
||||
: method_found_(method_found), runnable_(runnable) {}
|
||||
|
||||
void UberDispatcher::DispatchResult::Run() {
|
||||
if (!runnable_)
|
||||
return;
|
||||
runnable_();
|
||||
runnable_ = nullptr;
|
||||
}
|
||||
|
||||
UberDispatcher::UberDispatcher(FrontendChannel* frontend_channel)
|
||||
: frontend_channel_(frontend_channel) {
|
||||
assert(frontend_channel);
|
||||
}
|
||||
|
||||
UberDispatcher::~UberDispatcher() = default;
|
||||
|
||||
constexpr size_t kNotFound = std::numeric_limits<size_t>::max();
|
||||
|
||||
namespace {
|
||||
size_t DotIdx(span<uint8_t> method) {
|
||||
const void* p = memchr(method.data(), '.', method.size());
|
||||
return p ? reinterpret_cast<const uint8_t*>(p) - method.data() : kNotFound;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UberDispatcher::DispatchResult UberDispatcher::Dispatch(
|
||||
const Dispatchable& dispatchable) const {
|
||||
span<uint8_t> method = FindByFirst(redirects_, dispatchable.Method(),
|
||||
/*default_value=*/dispatchable.Method());
|
||||
size_t dot_idx = DotIdx(method);
|
||||
if (dot_idx != kNotFound) {
|
||||
span<uint8_t> domain = method.subspan(0, dot_idx);
|
||||
span<uint8_t> command = method.subspan(dot_idx + 1);
|
||||
DomainDispatcher* dispatcher = FindByFirst(dispatchers_, domain);
|
||||
if (dispatcher) {
|
||||
std::function<void(const Dispatchable&)> dispatched =
|
||||
dispatcher->Dispatch(command);
|
||||
if (dispatched) {
|
||||
return DispatchResult(
|
||||
true, [dispatchable, dispatched = std::move(dispatched)]() {
|
||||
dispatched(dispatchable);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return DispatchResult(false, [this, dispatchable]() {
|
||||
frontend_channel_->SendProtocolResponse(
|
||||
dispatchable.CallId(),
|
||||
CreateErrorResponse(dispatchable.CallId(),
|
||||
DispatchResponse::MethodNotFound(
|
||||
"'" +
|
||||
std::string(dispatchable.Method().begin(),
|
||||
dispatchable.Method().end()) +
|
||||
"' wasn't found")));
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct FirstLessThan {
|
||||
bool operator()(const std::pair<span<uint8_t>, T>& left,
|
||||
const std::pair<span<uint8_t>, T>& right) {
|
||||
return SpanLessThan(left.first, right.first);
|
||||
}
|
||||
};
|
||||
|
||||
void UberDispatcher::WireBackend(
|
||||
span<uint8_t> domain,
|
||||
const std::vector<std::pair<span<uint8_t>, span<uint8_t>>>&
|
||||
sorted_redirects,
|
||||
std::unique_ptr<DomainDispatcher> dispatcher) {
|
||||
auto it = redirects_.insert(redirects_.end(), sorted_redirects.begin(),
|
||||
sorted_redirects.end());
|
||||
std::inplace_merge(redirects_.begin(), it, redirects_.end(),
|
||||
FirstLessThan<span<uint8_t>>());
|
||||
auto jt = dispatchers_.insert(dispatchers_.end(),
|
||||
std::make_pair(domain, std::move(dispatcher)));
|
||||
std::inplace_merge(dispatchers_.begin(), jt, dispatchers_.end(),
|
||||
FirstLessThan<std::unique_ptr<DomainDispatcher>>());
|
||||
}
|
||||
|
||||
} // namespace v8_crdtp
|
311
third_party/inspector_protocol/crdtp/dispatch.h
vendored
Normal file
311
third_party/inspector_protocol/crdtp/dispatch.h
vendored
Normal file
@ -0,0 +1,311 @@
|
||||
// Copyright 2020 The Chromium 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_CRDTP_DISPATCH_H_
|
||||
#define V8_CRDTP_DISPATCH_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include "export.h"
|
||||
#include "serializable.h"
|
||||
#include "span.h"
|
||||
#include "status.h"
|
||||
|
||||
namespace v8_crdtp {
|
||||
class FrontendChannel;
|
||||
class ErrorSupport;
|
||||
namespace cbor {
|
||||
class CBORTokenizer;
|
||||
} // namespace cbor
|
||||
|
||||
// =============================================================================
|
||||
// DispatchResponse - Error status and chaining / fall through
|
||||
// =============================================================================
|
||||
enum class DispatchCode {
|
||||
SUCCESS = 1,
|
||||
FALL_THROUGH = 2,
|
||||
// For historical reasons, these error codes correspond to commonly used
|
||||
// XMLRPC codes (e.g. see METHOD_NOT_FOUND in
|
||||
// https://github.com/python/cpython/blob/master/Lib/xmlrpc/client.py).
|
||||
PARSE_ERROR = -32700,
|
||||
INVALID_REQUEST = -32600,
|
||||
METHOD_NOT_FOUND = -32601,
|
||||
INVALID_PARAMS = -32602,
|
||||
INTERNAL_ERROR = -32603,
|
||||
SERVER_ERROR = -32000,
|
||||
};
|
||||
|
||||
// Information returned by command handlers. Usually returned after command
|
||||
// execution attempts.
|
||||
class DispatchResponse {
|
||||
public:
|
||||
const std::string& Message() const { return message_; }
|
||||
|
||||
DispatchCode Code() const { return code_; }
|
||||
|
||||
bool IsSuccess() const { return code_ == DispatchCode::SUCCESS; }
|
||||
bool IsFallThrough() const { return code_ == DispatchCode::FALL_THROUGH; }
|
||||
bool IsError() const { return code_ < DispatchCode::SUCCESS; }
|
||||
|
||||
static DispatchResponse Success();
|
||||
static DispatchResponse FallThrough();
|
||||
|
||||
// Indicates that a message could not be parsed. E.g., malformed JSON.
|
||||
static DispatchResponse ParseError(std::string message);
|
||||
|
||||
// Indicates that a request is lacking required top-level properties
|
||||
// ('id', 'method'), has top-level properties of the wrong type, or has
|
||||
// unknown top-level properties.
|
||||
static DispatchResponse InvalidRequest(std::string message);
|
||||
|
||||
// Indicates that a protocol method such as "Page.bringToFront" could not be
|
||||
// dispatched because it's not known to the (domain) dispatcher.
|
||||
static DispatchResponse MethodNotFound(std::string message);
|
||||
|
||||
// Indicates that the params sent to a domain handler are invalid.
|
||||
static DispatchResponse InvalidParams(std::string message);
|
||||
|
||||
// Used for application level errors, e.g. within protocol agents.
|
||||
static DispatchResponse InternalError();
|
||||
|
||||
// Used for application level errors, e.g. within protocol agents.
|
||||
static DispatchResponse ServerError(std::string message);
|
||||
|
||||
private:
|
||||
DispatchResponse() = default;
|
||||
DispatchCode code_;
|
||||
std::string message_;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// Dispatchable - a shallow parser for CBOR encoded DevTools messages
|
||||
// =============================================================================
|
||||
|
||||
// This parser extracts only the known top-level fields from a CBOR encoded map;
|
||||
// method, id, sessionId, and params.
|
||||
class Dispatchable {
|
||||
public:
|
||||
// This constructor parses the |serialized| message. If successful,
|
||||
// |ok()| will yield |true|, and |Method()|, |SessionId()|, |CallId()|,
|
||||
// |Params()| can be used to access, the extracted contents. Otherwise,
|
||||
// |ok()| will yield |false|, and |DispatchError()| can be
|
||||
// used to send a response or notification to the client.
|
||||
explicit Dispatchable(span<uint8_t> serialized);
|
||||
|
||||
// The serialized message that we just parsed.
|
||||
span<uint8_t> Serialized() const { return serialized_; }
|
||||
|
||||
// Yields true if parsing was successful. This is cheaper than calling
|
||||
// ::DispatchError().
|
||||
bool ok() const;
|
||||
|
||||
// If !ok(), returns a DispatchResponse with appropriate code and error
|
||||
// which can be sent to the client as a response or notification.
|
||||
DispatchResponse DispatchError() const;
|
||||
|
||||
// Top level field: the command to be executed, fully qualified by
|
||||
// domain. E.g. "Page.createIsolatedWorld".
|
||||
span<uint8_t> Method() const { return method_; }
|
||||
// Used to identify protocol connections attached to a specific
|
||||
// target. See Target.attachToTarget, Target.setAutoAttach.
|
||||
span<uint8_t> SessionId() const { return session_id_; }
|
||||
// The call id, a sequence number that's used in responses to indicate
|
||||
// the request to which the response belongs.
|
||||
int32_t CallId() const { return call_id_; }
|
||||
bool HasCallId() const { return has_call_id_; }
|
||||
// The payload of the request in CBOR format. The |Dispatchable| parser does
|
||||
// not parse into this; it only provides access to its raw contents here.
|
||||
span<uint8_t> Params() const { return params_; }
|
||||
|
||||
private:
|
||||
bool MaybeParseProperty(cbor::CBORTokenizer* tokenizer);
|
||||
bool MaybeParseCallId(cbor::CBORTokenizer* tokenizer);
|
||||
bool MaybeParseMethod(cbor::CBORTokenizer* tokenizer);
|
||||
bool MaybeParseParams(cbor::CBORTokenizer* tokenizer);
|
||||
bool MaybeParseSessionId(cbor::CBORTokenizer* tokenizer);
|
||||
|
||||
span<uint8_t> serialized_;
|
||||
|
||||
Status status_;
|
||||
|
||||
bool has_call_id_ = false;
|
||||
int32_t call_id_;
|
||||
span<uint8_t> method_;
|
||||
bool params_seen_ = false;
|
||||
span<uint8_t> params_;
|
||||
span<uint8_t> session_id_;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// Helpers for creating protocol cresponses and notifications.
|
||||
// =============================================================================
|
||||
|
||||
// The resulting notifications can be sent to a protocol client,
|
||||
// usually via a FrontendChannel (see frontend_channel.h).
|
||||
|
||||
std::unique_ptr<Serializable> CreateErrorResponse(
|
||||
int callId,
|
||||
DispatchResponse dispatch_response,
|
||||
const ErrorSupport* errors = nullptr);
|
||||
|
||||
std::unique_ptr<Serializable> CreateErrorNotification(
|
||||
DispatchResponse dispatch_response);
|
||||
|
||||
std::unique_ptr<Serializable> CreateResponse(
|
||||
int callId,
|
||||
std::unique_ptr<Serializable> params);
|
||||
|
||||
std::unique_ptr<Serializable> CreateNotification(
|
||||
const char* method,
|
||||
std::unique_ptr<Serializable> params = nullptr);
|
||||
|
||||
// =============================================================================
|
||||
// DomainDispatcher - Dispatching betwen protocol methods within a domain.
|
||||
// =============================================================================
|
||||
|
||||
// This class is subclassed by |DomainDispatcherImpl|, which we generate per
|
||||
// DevTools domain. It contains routines called from the generated code,
|
||||
// e.g. ::MaybeReportInvalidParams, which are optimized for small code size.
|
||||
// The most important method is ::Dispatch, which implements method dispatch
|
||||
// by command name lookup.
|
||||
class DomainDispatcher {
|
||||
public:
|
||||
class WeakPtr {
|
||||
public:
|
||||
explicit WeakPtr(DomainDispatcher*);
|
||||
~WeakPtr();
|
||||
DomainDispatcher* get() { return dispatcher_; }
|
||||
void dispose() { dispatcher_ = nullptr; }
|
||||
|
||||
private:
|
||||
DomainDispatcher* dispatcher_;
|
||||
};
|
||||
|
||||
class Callback {
|
||||
public:
|
||||
virtual ~Callback();
|
||||
void dispose();
|
||||
|
||||
protected:
|
||||
// |method| must point at static storage (a C++ string literal in practice).
|
||||
Callback(std::unique_ptr<WeakPtr> backend_impl,
|
||||
int call_id,
|
||||
span<uint8_t> method,
|
||||
span<uint8_t> message);
|
||||
|
||||
void sendIfActive(std::unique_ptr<Serializable> partialMessage,
|
||||
const DispatchResponse& response);
|
||||
void fallThroughIfActive();
|
||||
|
||||
private:
|
||||
std::unique_ptr<WeakPtr> backend_impl_;
|
||||
int call_id_;
|
||||
// Subclasses of this class are instantiated from generated code which
|
||||
// passes a string literal for the method name to the constructor. So the
|
||||
// storage for |method| is the binary of the running process.
|
||||
span<uint8_t> method_;
|
||||
std::vector<uint8_t> message_;
|
||||
};
|
||||
|
||||
explicit DomainDispatcher(FrontendChannel*);
|
||||
virtual ~DomainDispatcher();
|
||||
|
||||
// Given a |command_name| without domain qualification, looks up the
|
||||
// corresponding method. If the method is not found, returns nullptr.
|
||||
// Otherwise, Returns a closure that will parse the provided
|
||||
// Dispatchable.params() to a protocol object and execute the
|
||||
// apprpropriate method. If the parsing fails it will issue an
|
||||
// error response on the frontend channel, otherwise it will execute the
|
||||
// command.
|
||||
virtual std::function<void(const Dispatchable&)> Dispatch(
|
||||
span<uint8_t> command_name) = 0;
|
||||
|
||||
// Sends a response to the client via the channel.
|
||||
void sendResponse(int call_id,
|
||||
const DispatchResponse&,
|
||||
std::unique_ptr<Serializable> result = nullptr);
|
||||
|
||||
// Returns true if |errors| contains errors *and* reports these errors
|
||||
// as a response on the frontend channel. Called from generated code,
|
||||
// optimized for code size of the callee.
|
||||
bool MaybeReportInvalidParams(const Dispatchable& dispatchable,
|
||||
const ErrorSupport& errors);
|
||||
|
||||
FrontendChannel* channel() { return frontend_channel_; }
|
||||
|
||||
void clearFrontend();
|
||||
|
||||
std::unique_ptr<WeakPtr> weakPtr();
|
||||
|
||||
private:
|
||||
FrontendChannel* frontend_channel_;
|
||||
std::unordered_set<WeakPtr*> weak_ptrs_;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// UberDispatcher - dispatches between domains (backends).
|
||||
// =============================================================================
|
||||
class UberDispatcher {
|
||||
public:
|
||||
// Return type for ::Dispatch.
|
||||
class DispatchResult {
|
||||
public:
|
||||
DispatchResult(bool method_found, std::function<void()> runnable);
|
||||
|
||||
// Indicates whether the method was found, that is, it could be dispatched
|
||||
// to a backend registered with this dispatcher.
|
||||
bool MethodFound() const { return method_found_; }
|
||||
|
||||
// Runs the dispatched result. This will send the appropriate error
|
||||
// responses if the method wasn't found or if something went wrong during
|
||||
// parameter parsing.
|
||||
void Run();
|
||||
|
||||
private:
|
||||
bool method_found_;
|
||||
std::function<void()> runnable_;
|
||||
};
|
||||
|
||||
// |frontend_hannel| can't be nullptr.
|
||||
explicit UberDispatcher(FrontendChannel* frontend_channel);
|
||||
virtual ~UberDispatcher();
|
||||
|
||||
// Dispatches the provided |dispatchable| considering all redirects and domain
|
||||
// handlers registered with this uber dispatcher. Also see |DispatchResult|.
|
||||
// |dispatchable.ok()| must hold - callers must check this separately and
|
||||
// deal with errors.
|
||||
DispatchResult Dispatch(const Dispatchable& dispatchable) const;
|
||||
|
||||
// Invoked from generated code for wiring domain backends; that is,
|
||||
// connecting domain handlers to an uber dispatcher.
|
||||
// See <domain-namespace>::Dispatcher::Wire(UberDispatcher*,Backend*).
|
||||
FrontendChannel* channel() const {
|
||||
assert(frontend_channel_);
|
||||
return frontend_channel_;
|
||||
}
|
||||
|
||||
// Invoked from generated code for wiring domain backends; that is,
|
||||
// connecting domain handlers to an uber dispatcher.
|
||||
// See <domain-namespace>::Dispatcher::Wire(UberDispatcher*,Backend*).
|
||||
void WireBackend(span<uint8_t> domain,
|
||||
const std::vector<std::pair<span<uint8_t>, span<uint8_t>>>&,
|
||||
std::unique_ptr<DomainDispatcher> dispatcher);
|
||||
|
||||
private:
|
||||
DomainDispatcher* findDispatcher(span<uint8_t> method);
|
||||
FrontendChannel* const frontend_channel_;
|
||||
// Pairs of ascii strings of the form ("Domain1.method1","Domain2.method2")
|
||||
// indicating that the first element of each pair redirects to the second.
|
||||
// Sorted by first element.
|
||||
std::vector<std::pair<span<uint8_t>, span<uint8_t>>> redirects_;
|
||||
// Domain dispatcher instances, sorted by their domain name.
|
||||
std::vector<std::pair<span<uint8_t>, std::unique_ptr<DomainDispatcher>>>
|
||||
dispatchers_;
|
||||
};
|
||||
} // namespace v8_crdtp
|
||||
|
||||
#endif // V8_CRDTP_DISPATCH_H_
|
445
third_party/inspector_protocol/crdtp/dispatch_test.cc
vendored
Normal file
445
third_party/inspector_protocol/crdtp/dispatch_test.cc
vendored
Normal file
@ -0,0 +1,445 @@
|
||||
// Copyright 2020 The Chromium 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 <vector>
|
||||
|
||||
#include "cbor.h"
|
||||
#include "dispatch.h"
|
||||
#include "error_support.h"
|
||||
#include "frontend_channel.h"
|
||||
#include "json.h"
|
||||
#include "test_platform.h"
|
||||
|
||||
namespace v8_crdtp {
|
||||
// =============================================================================
|
||||
// DispatchResponse - Error status and chaining / fall through
|
||||
// =============================================================================
|
||||
TEST(DispatchResponseTest, OK) {
|
||||
EXPECT_EQ(DispatchCode::SUCCESS, DispatchResponse::Success().Code());
|
||||
EXPECT_TRUE(DispatchResponse::Success().IsSuccess());
|
||||
}
|
||||
|
||||
TEST(DispatchResponseTest, ServerError) {
|
||||
DispatchResponse error = DispatchResponse::ServerError("Oops!");
|
||||
EXPECT_FALSE(error.IsSuccess());
|
||||
EXPECT_EQ(DispatchCode::SERVER_ERROR, error.Code());
|
||||
EXPECT_EQ("Oops!", error.Message());
|
||||
}
|
||||
|
||||
TEST(DispatchResponseTest, InternalError) {
|
||||
DispatchResponse error = DispatchResponse::InternalError();
|
||||
EXPECT_FALSE(error.IsSuccess());
|
||||
EXPECT_EQ(DispatchCode::INTERNAL_ERROR, error.Code());
|
||||
EXPECT_EQ("Internal error", error.Message());
|
||||
}
|
||||
|
||||
TEST(DispatchResponseTest, InvalidParams) {
|
||||
DispatchResponse error = DispatchResponse::InvalidParams("too cool");
|
||||
EXPECT_FALSE(error.IsSuccess());
|
||||
EXPECT_EQ(DispatchCode::INVALID_PARAMS, error.Code());
|
||||
EXPECT_EQ("too cool", error.Message());
|
||||
}
|
||||
|
||||
TEST(DispatchResponseTest, FallThrough) {
|
||||
DispatchResponse error = DispatchResponse::FallThrough();
|
||||
EXPECT_FALSE(error.IsSuccess());
|
||||
EXPECT_TRUE(error.IsFallThrough());
|
||||
EXPECT_EQ(DispatchCode::FALL_THROUGH, error.Code());
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Dispatchable - a shallow parser for CBOR encoded DevTools messages
|
||||
// =============================================================================
|
||||
TEST(DispatchableTest, MessageMustBeAnObject) {
|
||||
// Provide no input whatsoever.
|
||||
span<uint8_t> empty_span;
|
||||
Dispatchable empty(empty_span);
|
||||
EXPECT_FALSE(empty.ok());
|
||||
EXPECT_EQ(DispatchCode::INVALID_REQUEST, empty.DispatchError().Code());
|
||||
EXPECT_EQ("Message must be an object", empty.DispatchError().Message());
|
||||
}
|
||||
|
||||
TEST(DispatchableTest, MessageMustHaveIntegerIdProperty) {
|
||||
// Construct an empty map inside of an envelope.
|
||||
std::vector<uint8_t> cbor;
|
||||
ASSERT_TRUE(json::ConvertJSONToCBOR(SpanFrom("{}"), &cbor).ok());
|
||||
Dispatchable dispatchable(SpanFrom(cbor));
|
||||
EXPECT_FALSE(dispatchable.ok());
|
||||
EXPECT_FALSE(dispatchable.HasCallId());
|
||||
EXPECT_EQ(DispatchCode::INVALID_REQUEST, dispatchable.DispatchError().Code());
|
||||
EXPECT_EQ("Message must have integer 'id' property",
|
||||
dispatchable.DispatchError().Message());
|
||||
}
|
||||
|
||||
TEST(DispatchableTest, MessageMustHaveIntegerIdProperty_IncorrectType) {
|
||||
// This time we set the id property, but fail to make it an int32.
|
||||
std::vector<uint8_t> cbor;
|
||||
ASSERT_TRUE(
|
||||
json::ConvertJSONToCBOR(SpanFrom("{\"id\":\"foo\"}"), &cbor).ok());
|
||||
Dispatchable dispatchable(SpanFrom(cbor));
|
||||
EXPECT_FALSE(dispatchable.ok());
|
||||
EXPECT_FALSE(dispatchable.HasCallId());
|
||||
EXPECT_EQ(DispatchCode::INVALID_REQUEST, dispatchable.DispatchError().Code());
|
||||
EXPECT_EQ("Message must have integer 'id' property",
|
||||
dispatchable.DispatchError().Message());
|
||||
}
|
||||
|
||||
TEST(DispatchableTest, MessageMustHaveStringMethodProperty) {
|
||||
// This time we set the id property, but not the method property.
|
||||
std::vector<uint8_t> cbor;
|
||||
ASSERT_TRUE(json::ConvertJSONToCBOR(SpanFrom("{\"id\":42}"), &cbor).ok());
|
||||
Dispatchable dispatchable(SpanFrom(cbor));
|
||||
EXPECT_FALSE(dispatchable.ok());
|
||||
EXPECT_TRUE(dispatchable.HasCallId());
|
||||
EXPECT_EQ(DispatchCode::INVALID_REQUEST, dispatchable.DispatchError().Code());
|
||||
EXPECT_EQ("Message must have string 'method' property",
|
||||
dispatchable.DispatchError().Message());
|
||||
}
|
||||
|
||||
TEST(DispatchableTest, MessageMustHaveStringMethodProperty_IncorrectType) {
|
||||
// This time we set the method property, but fail to make it a string.
|
||||
std::vector<uint8_t> cbor;
|
||||
ASSERT_TRUE(
|
||||
json::ConvertJSONToCBOR(SpanFrom("{\"id\":42,\"method\":42}"), &cbor)
|
||||
.ok());
|
||||
Dispatchable dispatchable(SpanFrom(cbor));
|
||||
EXPECT_FALSE(dispatchable.ok());
|
||||
EXPECT_TRUE(dispatchable.HasCallId());
|
||||
EXPECT_EQ(DispatchCode::INVALID_REQUEST, dispatchable.DispatchError().Code());
|
||||
EXPECT_EQ("Message must have string 'method' property",
|
||||
dispatchable.DispatchError().Message());
|
||||
}
|
||||
|
||||
TEST(DispatchableTest, MessageMayHaveStringSessionIdProperty) {
|
||||
// This time, the session id is an int but it should be a string. Method and
|
||||
// call id are present.
|
||||
std::vector<uint8_t> cbor;
|
||||
ASSERT_TRUE(json::ConvertJSONToCBOR(
|
||||
SpanFrom("{\"id\":42,\"method\":\"Foo.executeBar\","
|
||||
"\"sessionId\":42" // int32 is wrong type
|
||||
"}"),
|
||||
&cbor)
|
||||
.ok());
|
||||
Dispatchable dispatchable(SpanFrom(cbor));
|
||||
EXPECT_FALSE(dispatchable.ok());
|
||||
EXPECT_TRUE(dispatchable.HasCallId());
|
||||
EXPECT_EQ(DispatchCode::INVALID_REQUEST, dispatchable.DispatchError().Code());
|
||||
EXPECT_EQ("Message may have string 'sessionId' property",
|
||||
dispatchable.DispatchError().Message());
|
||||
}
|
||||
|
||||
TEST(DispatchableTest, MessageMayHaveObjectParamsProperty) {
|
||||
// This time, we fail to use the correct type for the params property.
|
||||
std::vector<uint8_t> cbor;
|
||||
ASSERT_TRUE(json::ConvertJSONToCBOR(
|
||||
SpanFrom("{\"id\":42,\"method\":\"Foo.executeBar\","
|
||||
"\"params\":42" // int32 is wrong type
|
||||
"}"),
|
||||
&cbor)
|
||||
.ok());
|
||||
Dispatchable dispatchable(SpanFrom(cbor));
|
||||
EXPECT_FALSE(dispatchable.ok());
|
||||
EXPECT_TRUE(dispatchable.HasCallId());
|
||||
EXPECT_EQ(DispatchCode::INVALID_REQUEST, dispatchable.DispatchError().Code());
|
||||
EXPECT_EQ("Message may have object 'params' property",
|
||||
dispatchable.DispatchError().Message());
|
||||
}
|
||||
|
||||
TEST(DispatchableTest, MessageWithUnknownProperty) {
|
||||
// This time we set the 'unknown' property, so we are told what's allowed.
|
||||
std::vector<uint8_t> cbor;
|
||||
ASSERT_TRUE(
|
||||
json::ConvertJSONToCBOR(SpanFrom("{\"id\":42,\"unknown\":42}"), &cbor)
|
||||
.ok());
|
||||
Dispatchable dispatchable(SpanFrom(cbor));
|
||||
EXPECT_FALSE(dispatchable.ok());
|
||||
EXPECT_TRUE(dispatchable.HasCallId());
|
||||
EXPECT_EQ(DispatchCode::INVALID_REQUEST, dispatchable.DispatchError().Code());
|
||||
EXPECT_EQ(
|
||||
"Message has property other than 'id', 'method', 'sessionId', 'params'",
|
||||
dispatchable.DispatchError().Message());
|
||||
}
|
||||
|
||||
TEST(DispatchableTest, DuplicateMapKey) {
|
||||
for (const std::string& json :
|
||||
{"{\"id\":42,\"id\":42}", "{\"params\":null,\"params\":null}",
|
||||
"{\"method\":\"foo\",\"method\":\"foo\"}",
|
||||
"{\"sessionId\":\"42\",\"sessionId\":\"42\"}"}) {
|
||||
SCOPED_TRACE("json = " + json);
|
||||
std::vector<uint8_t> cbor;
|
||||
ASSERT_TRUE(json::ConvertJSONToCBOR(SpanFrom(json), &cbor).ok());
|
||||
Dispatchable dispatchable(SpanFrom(cbor));
|
||||
EXPECT_FALSE(dispatchable.ok());
|
||||
EXPECT_EQ(DispatchCode::PARSE_ERROR, dispatchable.DispatchError().Code());
|
||||
EXPECT_THAT(dispatchable.DispatchError().Message(),
|
||||
testing::StartsWith("CBOR: duplicate map key at position "));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DispatchableTest, ValidMessageParsesOK_NoParams) {
|
||||
for (const std::string& json :
|
||||
{"{\"id\":42,\"method\":\"Foo.executeBar\",\"sessionId\":"
|
||||
"\"f421ssvaz4\"}",
|
||||
"{\"id\":42,\"method\":\"Foo.executeBar\",\"sessionId\":\"f421ssvaz4\","
|
||||
"\"params\":null}"}) {
|
||||
SCOPED_TRACE("json = " + json);
|
||||
std::vector<uint8_t> cbor;
|
||||
ASSERT_TRUE(json::ConvertJSONToCBOR(SpanFrom(json), &cbor).ok());
|
||||
Dispatchable dispatchable(SpanFrom(cbor));
|
||||
EXPECT_TRUE(dispatchable.ok());
|
||||
EXPECT_TRUE(dispatchable.HasCallId());
|
||||
EXPECT_EQ(42, dispatchable.CallId());
|
||||
EXPECT_EQ("Foo.executeBar", std::string(dispatchable.Method().begin(),
|
||||
dispatchable.Method().end()));
|
||||
EXPECT_EQ("f421ssvaz4", std::string(dispatchable.SessionId().begin(),
|
||||
dispatchable.SessionId().end()));
|
||||
EXPECT_TRUE(dispatchable.Params().empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DispatchableTest, ValidMessageParsesOK_WithParams) {
|
||||
std::vector<uint8_t> cbor;
|
||||
cbor::EnvelopeEncoder envelope;
|
||||
envelope.EncodeStart(&cbor);
|
||||
cbor.push_back(cbor::EncodeIndefiniteLengthMapStart());
|
||||
cbor::EncodeString8(SpanFrom("id"), &cbor);
|
||||
cbor::EncodeInt32(42, &cbor);
|
||||
cbor::EncodeString8(SpanFrom("method"), &cbor);
|
||||
cbor::EncodeString8(SpanFrom("Foo.executeBar"), &cbor);
|
||||
cbor::EncodeString8(SpanFrom("params"), &cbor);
|
||||
cbor::EnvelopeEncoder params_envelope;
|
||||
params_envelope.EncodeStart(&cbor);
|
||||
// The |Dispatchable| class does not parse into the "params" envelope,
|
||||
// so we can stick anything into there for the purpose of this test.
|
||||
// For convenience, we use a String8.
|
||||
cbor::EncodeString8(SpanFrom("params payload"), &cbor);
|
||||
params_envelope.EncodeStop(&cbor);
|
||||
cbor::EncodeString8(SpanFrom("sessionId"), &cbor);
|
||||
cbor::EncodeString8(SpanFrom("f421ssvaz4"), &cbor);
|
||||
cbor.push_back(cbor::EncodeStop());
|
||||
envelope.EncodeStop(&cbor);
|
||||
Dispatchable dispatchable(SpanFrom(cbor));
|
||||
EXPECT_TRUE(dispatchable.ok());
|
||||
EXPECT_TRUE(dispatchable.HasCallId());
|
||||
EXPECT_EQ(42, dispatchable.CallId());
|
||||
EXPECT_EQ("Foo.executeBar", std::string(dispatchable.Method().begin(),
|
||||
dispatchable.Method().end()));
|
||||
EXPECT_EQ("f421ssvaz4", std::string(dispatchable.SessionId().begin(),
|
||||
dispatchable.SessionId().end()));
|
||||
cbor::CBORTokenizer params_tokenizer(dispatchable.Params());
|
||||
ASSERT_EQ(cbor::CBORTokenTag::ENVELOPE, params_tokenizer.TokenTag());
|
||||
params_tokenizer.EnterEnvelope();
|
||||
ASSERT_EQ(cbor::CBORTokenTag::STRING8, params_tokenizer.TokenTag());
|
||||
EXPECT_EQ("params payload", std::string(params_tokenizer.GetString8().begin(),
|
||||
params_tokenizer.GetString8().end()));
|
||||
}
|
||||
|
||||
TEST(DispatchableTest, FaultyCBORTrailingJunk) {
|
||||
// In addition to the higher level parsing errors, we also catch CBOR
|
||||
// structural corruption. E.g., in this case, the message would be
|
||||
// OK but has some extra trailing bytes.
|
||||
std::vector<uint8_t> cbor;
|
||||
cbor::EnvelopeEncoder envelope;
|
||||
envelope.EncodeStart(&cbor);
|
||||
cbor.push_back(cbor::EncodeIndefiniteLengthMapStart());
|
||||
cbor::EncodeString8(SpanFrom("id"), &cbor);
|
||||
cbor::EncodeInt32(42, &cbor);
|
||||
cbor::EncodeString8(SpanFrom("method"), &cbor);
|
||||
cbor::EncodeString8(SpanFrom("Foo.executeBar"), &cbor);
|
||||
cbor::EncodeString8(SpanFrom("sessionId"), &cbor);
|
||||
cbor::EncodeString8(SpanFrom("f421ssvaz4"), &cbor);
|
||||
cbor.push_back(cbor::EncodeStop());
|
||||
envelope.EncodeStop(&cbor);
|
||||
size_t trailing_junk_pos = cbor.size();
|
||||
cbor.push_back('t');
|
||||
cbor.push_back('r');
|
||||
cbor.push_back('a');
|
||||
cbor.push_back('i');
|
||||
cbor.push_back('l');
|
||||
Dispatchable dispatchable(SpanFrom(cbor));
|
||||
EXPECT_FALSE(dispatchable.ok());
|
||||
EXPECT_EQ(DispatchCode::PARSE_ERROR, dispatchable.DispatchError().Code());
|
||||
EXPECT_EQ(56u, trailing_junk_pos);
|
||||
EXPECT_EQ("CBOR: trailing junk at position 56",
|
||||
dispatchable.DispatchError().Message());
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Helpers for creating protocol cresponses and notifications.
|
||||
// =============================================================================
|
||||
TEST(CreateErrorResponseTest, SmokeTest) {
|
||||
ErrorSupport errors;
|
||||
errors.Push();
|
||||
errors.SetName("foo");
|
||||
errors.Push();
|
||||
errors.SetName("bar");
|
||||
errors.AddError("expected a string");
|
||||
errors.SetName("baz");
|
||||
errors.AddError("expected a surprise");
|
||||
auto serializable = CreateErrorResponse(
|
||||
42, DispatchResponse::InvalidParams("invalid params message"), &errors);
|
||||
std::string json;
|
||||
auto status =
|
||||
json::ConvertCBORToJSON(SpanFrom(serializable->Serialize()), &json);
|
||||
ASSERT_TRUE(status.ok());
|
||||
EXPECT_EQ(
|
||||
"{\"id\":42,\"error\":"
|
||||
"{\"code\":-32602,"
|
||||
"\"message\":\"invalid params message\","
|
||||
"\"data\":\"foo.bar: expected a string; "
|
||||
"foo.baz: expected a surprise\"}}",
|
||||
json);
|
||||
}
|
||||
|
||||
TEST(CreateErrorNotificationTest, SmokeTest) {
|
||||
auto serializable =
|
||||
CreateErrorNotification(DispatchResponse::InvalidRequest("oops!"));
|
||||
std::string json;
|
||||
auto status =
|
||||
json::ConvertCBORToJSON(SpanFrom(serializable->Serialize()), &json);
|
||||
ASSERT_TRUE(status.ok());
|
||||
EXPECT_EQ("{\"error\":{\"code\":-32600,\"message\":\"oops!\"}}", json);
|
||||
}
|
||||
|
||||
TEST(CreateResponseTest, SmokeTest) {
|
||||
auto serializable = CreateResponse(42, nullptr);
|
||||
std::string json;
|
||||
auto status =
|
||||
json::ConvertCBORToJSON(SpanFrom(serializable->Serialize()), &json);
|
||||
ASSERT_TRUE(status.ok());
|
||||
EXPECT_EQ("{\"id\":42,\"result\":{}}", json);
|
||||
}
|
||||
|
||||
TEST(CreateNotificationTest, SmokeTest) {
|
||||
auto serializable = CreateNotification("Foo.bar");
|
||||
std::string json;
|
||||
auto status =
|
||||
json::ConvertCBORToJSON(SpanFrom(serializable->Serialize()), &json);
|
||||
ASSERT_TRUE(status.ok());
|
||||
EXPECT_EQ("{\"method\":\"Foo.bar\",\"params\":{}}", json);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// UberDispatcher - dispatches between domains (backends).
|
||||
// =============================================================================
|
||||
class TestChannel : public FrontendChannel {
|
||||
public:
|
||||
std::string JSON() const {
|
||||
std::string json;
|
||||
json::ConvertCBORToJSON(SpanFrom(cbor_), &json);
|
||||
return json;
|
||||
}
|
||||
|
||||
private:
|
||||
void SendProtocolResponse(int call_id,
|
||||
std::unique_ptr<Serializable> message) override {
|
||||
cbor_ = message->Serialize();
|
||||
}
|
||||
|
||||
void SendProtocolNotification(
|
||||
std::unique_ptr<Serializable> message) override {
|
||||
cbor_ = message->Serialize();
|
||||
}
|
||||
|
||||
void FallThrough(int call_id,
|
||||
span<uint8_t> method,
|
||||
span<uint8_t> message) override {}
|
||||
|
||||
void FlushProtocolNotifications() override {}
|
||||
|
||||
std::vector<uint8_t> cbor_;
|
||||
};
|
||||
|
||||
TEST(UberDispatcherTest, MethodNotFound) {
|
||||
// No domain dispatchers are registered, so unsuprisingly, we'll get a method
|
||||
// not found error and can see that DispatchResult::MethodFound() yields
|
||||
// false.
|
||||
TestChannel channel;
|
||||
UberDispatcher dispatcher(&channel);
|
||||
std::vector<uint8_t> message;
|
||||
json::ConvertJSONToCBOR(SpanFrom("{\"id\":42,\"method\":\"Foo.bar\"}"),
|
||||
&message);
|
||||
Dispatchable dispatchable(SpanFrom(message));
|
||||
ASSERT_TRUE(dispatchable.ok());
|
||||
UberDispatcher::DispatchResult dispatched = dispatcher.Dispatch(dispatchable);
|
||||
EXPECT_FALSE(dispatched.MethodFound());
|
||||
dispatched.Run();
|
||||
EXPECT_EQ(
|
||||
"{\"id\":42,\"error\":"
|
||||
"{\"code\":-32601,\"message\":\"'Foo.bar' wasn't found\"}}",
|
||||
channel.JSON());
|
||||
}
|
||||
|
||||
// A domain dispatcher which captured dispatched and executed commands in fields
|
||||
// for testing.
|
||||
class TestDomain : public DomainDispatcher {
|
||||
public:
|
||||
explicit TestDomain(FrontendChannel* channel) : DomainDispatcher(channel) {}
|
||||
|
||||
std::function<void(const Dispatchable&)> Dispatch(
|
||||
span<uint8_t> command_name) override {
|
||||
dispatched_commands_.push_back(
|
||||
std::string(command_name.begin(), command_name.end()));
|
||||
return [this](const Dispatchable& dispatchable) {
|
||||
executed_commands_.push_back(dispatchable.CallId());
|
||||
};
|
||||
}
|
||||
|
||||
// Command names of the dispatched commands.
|
||||
std::vector<std::string> DispatchedCommands() const {
|
||||
return dispatched_commands_;
|
||||
}
|
||||
|
||||
// Call ids of the executed commands.
|
||||
std::vector<int32_t> ExecutedCommands() const { return executed_commands_; }
|
||||
|
||||
private:
|
||||
std::vector<std::string> dispatched_commands_;
|
||||
std::vector<int32_t> executed_commands_;
|
||||
};
|
||||
|
||||
TEST(UberDispatcherTest, DispatchingToDomainWithRedirects) {
|
||||
// This time, we register two domain dispatchers (Foo and Bar) and issue one
|
||||
// command 'Foo.execute' which executes on Foo and one command 'Foo.redirect'
|
||||
// which executes as 'Bar.redirected'.
|
||||
TestChannel channel;
|
||||
UberDispatcher dispatcher(&channel);
|
||||
auto foo_dispatcher = std::make_unique<TestDomain>(&channel);
|
||||
TestDomain* foo = foo_dispatcher.get();
|
||||
auto bar_dispatcher = std::make_unique<TestDomain>(&channel);
|
||||
TestDomain* bar = bar_dispatcher.get();
|
||||
|
||||
dispatcher.WireBackend(
|
||||
SpanFrom("Foo"), {{SpanFrom("Foo.redirect"), SpanFrom("Bar.redirected")}},
|
||||
std::move(foo_dispatcher));
|
||||
dispatcher.WireBackend(SpanFrom("Bar"), {}, std::move(bar_dispatcher));
|
||||
|
||||
{
|
||||
std::vector<uint8_t> message;
|
||||
json::ConvertJSONToCBOR(SpanFrom("{\"id\":42,\"method\":\"Foo.execute\"}"),
|
||||
&message);
|
||||
Dispatchable dispatchable(SpanFrom(message));
|
||||
ASSERT_TRUE(dispatchable.ok());
|
||||
UberDispatcher::DispatchResult dispatched =
|
||||
dispatcher.Dispatch(dispatchable);
|
||||
EXPECT_TRUE(dispatched.MethodFound());
|
||||
dispatched.Run();
|
||||
}
|
||||
{
|
||||
std::vector<uint8_t> message;
|
||||
json::ConvertJSONToCBOR(SpanFrom("{\"id\":43,\"method\":\"Foo.redirect\"}"),
|
||||
&message);
|
||||
Dispatchable dispatchable(SpanFrom(message));
|
||||
ASSERT_TRUE(dispatchable.ok());
|
||||
UberDispatcher::DispatchResult dispatched =
|
||||
dispatcher.Dispatch(dispatchable);
|
||||
EXPECT_TRUE(dispatched.MethodFound());
|
||||
dispatched.Run();
|
||||
}
|
||||
EXPECT_THAT(foo->DispatchedCommands(), testing::ElementsAre("execute"));
|
||||
EXPECT_THAT(foo->ExecutedCommands(), testing::ElementsAre(42));
|
||||
EXPECT_THAT(bar->DispatchedCommands(), testing::ElementsAre("redirected"));
|
||||
EXPECT_THAT(bar->ExecutedCommands(), testing::ElementsAre(43));
|
||||
}
|
||||
} // namespace v8_crdtp
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "export.h"
|
||||
#include "span.h"
|
||||
|
||||
|
58
third_party/inspector_protocol/crdtp/find_by_first.h
vendored
Normal file
58
third_party/inspector_protocol/crdtp/find_by_first.h
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2020 The Chromium 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_CRDTP_FIND_BY_FIRST_H_
|
||||
#define V8_CRDTP_FIND_BY_FIRST_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "export.h"
|
||||
#include "span.h"
|
||||
|
||||
namespace v8_crdtp {
|
||||
// =============================================================================
|
||||
// FindByFirst - Retrieval from a sorted vector that's keyed by span<uint8_t>.
|
||||
// =============================================================================
|
||||
|
||||
// Given a vector of pairs sorted by the first element of each pair, find
|
||||
// the corresponding value given a key to be compared to the first element.
|
||||
// Together with std::inplace_merge and pre-sorting or std::sort, this can
|
||||
// be used to implement a minimalistic equivalent of Chromium's flat_map.
|
||||
|
||||
// In this variant, the template parameter |T| is a value type and a
|
||||
// |default_value| is provided.
|
||||
template <typename T>
|
||||
T FindByFirst(const std::vector<std::pair<span<uint8_t>, T>>& sorted_by_first,
|
||||
span<uint8_t> key,
|
||||
T default_value) {
|
||||
auto it = std::lower_bound(
|
||||
sorted_by_first.begin(), sorted_by_first.end(), key,
|
||||
[](const std::pair<span<uint8_t>, T>& left, span<uint8_t> right) {
|
||||
return SpanLessThan(left.first, right);
|
||||
});
|
||||
return (it != sorted_by_first.end() && SpanEquals(it->first, key))
|
||||
? it->second
|
||||
: default_value;
|
||||
}
|
||||
|
||||
// In this variant, the template parameter |T| is a class or struct that's
|
||||
// instantiated in std::unique_ptr, and we return either a T* or a nullptr.
|
||||
template <typename T>
|
||||
T* FindByFirst(const std::vector<std::pair<span<uint8_t>, std::unique_ptr<T>>>&
|
||||
sorted_by_first,
|
||||
span<uint8_t> key) {
|
||||
auto it = std::lower_bound(
|
||||
sorted_by_first.begin(), sorted_by_first.end(), key,
|
||||
[](const std::pair<span<uint8_t>, std::unique_ptr<T>>& left,
|
||||
span<uint8_t> right) { return SpanLessThan(left.first, right); });
|
||||
return (it != sorted_by_first.end() && SpanEquals(it->first, key))
|
||||
? it->second.get()
|
||||
: nullptr;
|
||||
}
|
||||
} // namespace v8_crdtp
|
||||
|
||||
#endif // V8_CRDTP_FIND_BY_FIRST_H_
|
76
third_party/inspector_protocol/crdtp/find_by_first_test.cc
vendored
Normal file
76
third_party/inspector_protocol/crdtp/find_by_first_test.cc
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright 2020 The Chromium 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 <string>
|
||||
|
||||
#include "find_by_first.h"
|
||||
#include "test_platform.h"
|
||||
|
||||
namespace v8_crdtp {
|
||||
// =============================================================================
|
||||
// FindByFirst - Efficient retrieval from a sorted vector.
|
||||
// =============================================================================
|
||||
TEST(FindByFirst, SpanBySpan) {
|
||||
std::vector<std::pair<span<uint8_t>, span<uint8_t>>> sorted_span_by_span = {
|
||||
{SpanFrom("foo1"), SpanFrom("bar1")},
|
||||
{SpanFrom("foo2"), SpanFrom("bar2")},
|
||||
{SpanFrom("foo3"), SpanFrom("bar3")},
|
||||
};
|
||||
{
|
||||
auto result = FindByFirst(sorted_span_by_span, SpanFrom("foo1"),
|
||||
SpanFrom("not_found"));
|
||||
EXPECT_EQ("bar1", std::string(result.begin(), result.end()));
|
||||
}
|
||||
{
|
||||
auto result = FindByFirst(sorted_span_by_span, SpanFrom("foo3"),
|
||||
SpanFrom("not_found"));
|
||||
EXPECT_EQ("bar3", std::string(result.begin(), result.end()));
|
||||
}
|
||||
{
|
||||
auto result = FindByFirst(sorted_span_by_span, SpanFrom("baz"),
|
||||
SpanFrom("not_found"));
|
||||
EXPECT_EQ("not_found", std::string(result.begin(), result.end()));
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
class TestObject {
|
||||
public:
|
||||
explicit TestObject(const std::string& message) : message_(message) {}
|
||||
|
||||
const std::string& message() const { return message_; }
|
||||
|
||||
private:
|
||||
std::string message_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(FindByFirst, ObjectBySpan) {
|
||||
std::vector<std::pair<span<uint8_t>, std::unique_ptr<TestObject>>>
|
||||
sorted_object_by_span;
|
||||
sorted_object_by_span.push_back(
|
||||
std::make_pair(SpanFrom("foo1"), std::make_unique<TestObject>("bar1")));
|
||||
sorted_object_by_span.push_back(
|
||||
std::make_pair(SpanFrom("foo2"), std::make_unique<TestObject>("bar2")));
|
||||
sorted_object_by_span.push_back(
|
||||
std::make_pair(SpanFrom("foo3"), std::make_unique<TestObject>("bar3")));
|
||||
{
|
||||
TestObject* result =
|
||||
FindByFirst<TestObject>(sorted_object_by_span, SpanFrom("foo1"));
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ("bar1", result->message());
|
||||
}
|
||||
{
|
||||
TestObject* result =
|
||||
FindByFirst<TestObject>(sorted_object_by_span, SpanFrom("foo3"));
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ("bar3", result->message());
|
||||
}
|
||||
{
|
||||
TestObject* result =
|
||||
FindByFirst<TestObject>(sorted_object_by_span, SpanFrom("baz"));
|
||||
ASSERT_FALSE(result);
|
||||
}
|
||||
}
|
||||
} // namespace v8_crdtp
|
47
third_party/inspector_protocol/crdtp/frontend_channel.h
vendored
Normal file
47
third_party/inspector_protocol/crdtp/frontend_channel.h
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2020 The Chromium 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_CRDTP_FRONTEND_CHANNEL_H_
|
||||
#define V8_CRDTP_FRONTEND_CHANNEL_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include "export.h"
|
||||
#include "serializable.h"
|
||||
#include "span.h"
|
||||
|
||||
namespace v8_crdtp {
|
||||
// =============================================================================
|
||||
// FrontendChannel - For sending notifications and responses to protocol clients
|
||||
// =============================================================================
|
||||
class FrontendChannel {
|
||||
public:
|
||||
virtual ~FrontendChannel() = default;
|
||||
|
||||
// Sends protocol responses and notifications. The |call_id| parameter is
|
||||
// seemingly redundant because it's also included in the message, but
|
||||
// responses may be sent from an untrusted source to a trusted process (e.g.
|
||||
// from Chromium's renderer (blink) to the browser process), which needs
|
||||
// to be able to match the response to an earlier request without parsing the
|
||||
// messsage.
|
||||
virtual void SendProtocolResponse(int call_id,
|
||||
std::unique_ptr<Serializable> message) = 0;
|
||||
virtual void SendProtocolNotification(
|
||||
std::unique_ptr<Serializable> message) = 0;
|
||||
|
||||
// FallThrough indicates that |message| should be handled in another layer.
|
||||
// Usually this means the layer responding to the message didn't handle it,
|
||||
// but in some cases messages are handled by multiple layers (e.g. both
|
||||
// the embedder and the content layer in Chromium).
|
||||
virtual void FallThrough(int call_id,
|
||||
span<uint8_t> method,
|
||||
span<uint8_t> message) = 0;
|
||||
|
||||
// Session implementations may queue notifications for performance or
|
||||
// other considerations; this is a hook for domain handlers to manually flush.
|
||||
virtual void FlushProtocolNotifications() = 0;
|
||||
};
|
||||
} // namespace v8_crdtp
|
||||
|
||||
#endif // V8_CRDTP_FRONTEND_CHANNEL_H_
|
1
third_party/inspector_protocol/crdtp/json.h
vendored
1
third_party/inspector_protocol/crdtp/json.h
vendored
@ -6,6 +6,7 @@
|
||||
#define V8_CRDTP_JSON_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "export.h"
|
||||
#include "parser_handler.h"
|
||||
|
||||
|
@ -14,4 +14,23 @@ std::vector<uint8_t> Serializable::Serialize() const {
|
||||
AppendSerialized(&out);
|
||||
return out;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class PreSerialized : public Serializable {
|
||||
public:
|
||||
explicit PreSerialized(std::vector<uint8_t> bytes) : bytes_(bytes) {}
|
||||
|
||||
void AppendSerialized(std::vector<uint8_t>* out) const override {
|
||||
out->insert(out->end(), bytes_.begin(), bytes_.end());
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> bytes_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
std::unique_ptr<Serializable> Serializable::From(std::vector<uint8_t> bytes) {
|
||||
return std::make_unique<PreSerialized>(std::move(bytes));
|
||||
}
|
||||
} // namespace v8_crdtp
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define V8_CRDTP_SERIALIZABLE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "export.h"
|
||||
|
||||
@ -13,7 +14,6 @@ namespace v8_crdtp {
|
||||
// =============================================================================
|
||||
// Serializable - An object to be emitted as a sequence of bytes.
|
||||
// =============================================================================
|
||||
|
||||
class Serializable {
|
||||
public:
|
||||
// Convenience: Invokes |AppendSerialized| on an empty vector.
|
||||
@ -22,6 +22,10 @@ class Serializable {
|
||||
virtual void AppendSerialized(std::vector<uint8_t>* out) const = 0;
|
||||
|
||||
virtual ~Serializable() = default;
|
||||
|
||||
// Wraps a vector of |bytes| into a Serializable for situations in which we
|
||||
// eagerly serialize a structure.
|
||||
static std::unique_ptr<Serializable> From(std::vector<uint8_t> bytes);
|
||||
};
|
||||
} // namespace v8_crdtp
|
||||
|
||||
|
24
third_party/inspector_protocol/crdtp/span.cc
vendored
Normal file
24
third_party/inspector_protocol/crdtp/span.cc
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2020 The Chromium 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 "span.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace v8_crdtp {
|
||||
|
||||
bool SpanLessThan(span<uint8_t> x, span<uint8_t> y) noexcept {
|
||||
auto min_size = std::min(x.size(), y.size());
|
||||
const int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size);
|
||||
return (r < 0) || (r == 0 && x.size() < y.size());
|
||||
}
|
||||
|
||||
bool SpanEquals(span<uint8_t> x, span<uint8_t> y) noexcept {
|
||||
auto len = x.size();
|
||||
if (len != y.size())
|
||||
return false;
|
||||
return x.data() == y.data() || len == 0 ||
|
||||
std::memcmp(x.data(), y.data(), len) == 0;
|
||||
}
|
||||
} // namespace v8_crdtp
|
24
third_party/inspector_protocol/crdtp/span.h
vendored
24
third_party/inspector_protocol/crdtp/span.h
vendored
@ -5,11 +5,11 @@
|
||||
#ifndef V8_CRDTP_SPAN_H_
|
||||
#define V8_CRDTP_SPAN_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "export.h"
|
||||
|
||||
namespace v8_crdtp {
|
||||
// =============================================================================
|
||||
@ -76,19 +76,15 @@ inline span<typename C::value_type> SpanFrom(const C& v) {
|
||||
|
||||
// Less than / equality comparison functions for sorting / searching for byte
|
||||
// spans. These are similar to absl::string_view's < and == operators.
|
||||
constexpr inline bool SpanLessThan(span<uint8_t> x, span<uint8_t> y) noexcept {
|
||||
auto min_size = std::min(x.size(), y.size());
|
||||
const int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size);
|
||||
return (r < 0) || (r == 0 && x.size() < y.size());
|
||||
}
|
||||
bool SpanLessThan(span<uint8_t> x, span<uint8_t> y) noexcept;
|
||||
|
||||
constexpr inline bool SpanEquals(span<uint8_t> x, span<uint8_t> y) noexcept {
|
||||
auto len = x.size();
|
||||
if (len != y.size())
|
||||
return false;
|
||||
return x.data() == y.data() || len == 0 ||
|
||||
std::memcmp(x.data(), y.data(), len) == 0;
|
||||
}
|
||||
bool SpanEquals(span<uint8_t> x, span<uint8_t> y) noexcept;
|
||||
|
||||
struct SpanLt {
|
||||
bool operator()(span<uint8_t> l, span<uint8_t> r) const {
|
||||
return SpanLessThan(l, r);
|
||||
}
|
||||
};
|
||||
} // namespace v8_crdtp
|
||||
|
||||
#endif // V8_CRDTP_SPAN_H_
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "span.h"
|
||||
#include "test_platform.h"
|
||||
@ -13,7 +12,6 @@ namespace v8_crdtp {
|
||||
// =============================================================================
|
||||
// span - sequence of bytes
|
||||
// =============================================================================
|
||||
|
||||
template <typename T>
|
||||
class SpanTest : public ::testing::Test {};
|
||||
|
||||
@ -108,41 +106,4 @@ TEST(SpanComparisons, ByteWiseLexicographicalOrder) {
|
||||
EXPECT_FALSE(SpanLessThan(SpanFrom(msg), SpanFrom(lesser_msg)));
|
||||
EXPECT_FALSE(SpanEquals(SpanFrom(msg), SpanFrom(lesser_msg)));
|
||||
}
|
||||
|
||||
// TODO(johannes): The following shows how the span can be used in an
|
||||
// std::unordered_map as a key. Once we have a production usage, we'll move
|
||||
// SpanHash, SpanEq, SpanHasher into the header.
|
||||
|
||||
// A simple hash code, inspired by http://stackoverflow.com/q/1646807.
|
||||
constexpr inline size_t SpanHash(span<uint8_t> s) noexcept {
|
||||
size_t hash = 17;
|
||||
for (uint8_t c : s)
|
||||
hash = 31 * hash + c;
|
||||
return hash;
|
||||
}
|
||||
|
||||
// Structs for making std::unordered_map with std::span<uint8_t> keys.
|
||||
struct SpanEq {
|
||||
constexpr inline bool operator()(span<uint8_t> l, span<uint8_t> r) const {
|
||||
return SpanEquals(l, r);
|
||||
}
|
||||
};
|
||||
|
||||
struct SpanHasher {
|
||||
constexpr inline size_t operator()(span<uint8_t> s) const {
|
||||
return SpanHash(s);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(SpanHasherAndSpanEq, SpanAsKeyInUnorderedMap) {
|
||||
// A very simple smoke test for unordered_map, storing three key/value pairs.
|
||||
std::unordered_map<span<uint8_t>, int32_t, SpanHasher, SpanEq> a_map;
|
||||
a_map[SpanFrom("foo")] = 1;
|
||||
a_map[SpanFrom("bar")] = 2;
|
||||
a_map[SpanFrom("baz")] = 3;
|
||||
EXPECT_EQ(3u, a_map.size());
|
||||
EXPECT_EQ(1, a_map[SpanFrom("foo")]);
|
||||
EXPECT_EQ(2, a_map[SpanFrom("bar")]);
|
||||
EXPECT_EQ(3, a_map[SpanFrom("baz")]);
|
||||
}
|
||||
} // namespace v8_crdtp
|
||||
|
106
third_party/inspector_protocol/crdtp/status.cc
vendored
106
third_party/inspector_protocol/crdtp/status.cc
vendored
@ -9,100 +9,118 @@ namespace v8_crdtp {
|
||||
// Status and Error codes
|
||||
// =============================================================================
|
||||
|
||||
std::string Status::ToASCIIString() const {
|
||||
std::string Status::Message() const {
|
||||
switch (error) {
|
||||
case Error::OK:
|
||||
return "OK";
|
||||
case Error::JSON_PARSER_UNPROCESSED_INPUT_REMAINS:
|
||||
return ToASCIIString("JSON: unprocessed input remains");
|
||||
return "JSON: unprocessed input remains";
|
||||
case Error::JSON_PARSER_STACK_LIMIT_EXCEEDED:
|
||||
return ToASCIIString("JSON: stack limit exceeded");
|
||||
return "JSON: stack limit exceeded";
|
||||
case Error::JSON_PARSER_NO_INPUT:
|
||||
return ToASCIIString("JSON: no input");
|
||||
return "JSON: no input";
|
||||
case Error::JSON_PARSER_INVALID_TOKEN:
|
||||
return ToASCIIString("JSON: invalid token");
|
||||
return "JSON: invalid token";
|
||||
case Error::JSON_PARSER_INVALID_NUMBER:
|
||||
return ToASCIIString("JSON: invalid number");
|
||||
return "JSON: invalid number";
|
||||
case Error::JSON_PARSER_INVALID_STRING:
|
||||
return ToASCIIString("JSON: invalid string");
|
||||
return "JSON: invalid string";
|
||||
case Error::JSON_PARSER_UNEXPECTED_ARRAY_END:
|
||||
return ToASCIIString("JSON: unexpected array end");
|
||||
return "JSON: unexpected array end";
|
||||
case Error::JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED:
|
||||
return ToASCIIString("JSON: comma or array end expected");
|
||||
return "JSON: comma or array end expected";
|
||||
case Error::JSON_PARSER_STRING_LITERAL_EXPECTED:
|
||||
return ToASCIIString("JSON: string literal expected");
|
||||
return "JSON: string literal expected";
|
||||
case Error::JSON_PARSER_COLON_EXPECTED:
|
||||
return ToASCIIString("JSON: colon expected");
|
||||
return "JSON: colon expected";
|
||||
case Error::JSON_PARSER_UNEXPECTED_MAP_END:
|
||||
return ToASCIIString("JSON: unexpected map end");
|
||||
return "JSON: unexpected map end";
|
||||
case Error::JSON_PARSER_COMMA_OR_MAP_END_EXPECTED:
|
||||
return ToASCIIString("JSON: comma or map end expected");
|
||||
return "JSON: comma or map end expected";
|
||||
case Error::JSON_PARSER_VALUE_EXPECTED:
|
||||
return ToASCIIString("JSON: value expected");
|
||||
return "JSON: value expected";
|
||||
|
||||
case Error::CBOR_INVALID_INT32:
|
||||
return ToASCIIString("CBOR: invalid int32");
|
||||
return "CBOR: invalid int32";
|
||||
case Error::CBOR_INVALID_DOUBLE:
|
||||
return ToASCIIString("CBOR: invalid double");
|
||||
return "CBOR: invalid double";
|
||||
case Error::CBOR_INVALID_ENVELOPE:
|
||||
return ToASCIIString("CBOR: invalid envelope");
|
||||
return "CBOR: invalid envelope";
|
||||
case Error::CBOR_ENVELOPE_CONTENTS_LENGTH_MISMATCH:
|
||||
return ToASCIIString("CBOR: envelope contents length mismatch");
|
||||
return "CBOR: envelope contents length mismatch";
|
||||
case Error::CBOR_MAP_OR_ARRAY_EXPECTED_IN_ENVELOPE:
|
||||
return ToASCIIString("CBOR: map or array expected in envelope");
|
||||
return "CBOR: map or array expected in envelope";
|
||||
case Error::CBOR_INVALID_STRING8:
|
||||
return ToASCIIString("CBOR: invalid string8");
|
||||
return "CBOR: invalid string8";
|
||||
case Error::CBOR_INVALID_STRING16:
|
||||
return ToASCIIString("CBOR: invalid string16");
|
||||
return "CBOR: invalid string16";
|
||||
case Error::CBOR_INVALID_BINARY:
|
||||
return ToASCIIString("CBOR: invalid binary");
|
||||
return "CBOR: invalid binary";
|
||||
case Error::CBOR_UNSUPPORTED_VALUE:
|
||||
return ToASCIIString("CBOR: unsupported value");
|
||||
return "CBOR: unsupported value";
|
||||
case Error::CBOR_NO_INPUT:
|
||||
return ToASCIIString("CBOR: no input");
|
||||
return "CBOR: no input";
|
||||
case Error::CBOR_INVALID_START_BYTE:
|
||||
return ToASCIIString("CBOR: invalid start byte");
|
||||
return "CBOR: invalid start byte";
|
||||
case Error::CBOR_UNEXPECTED_EOF_EXPECTED_VALUE:
|
||||
return ToASCIIString("CBOR: unexpected eof expected value");
|
||||
return "CBOR: unexpected eof expected value";
|
||||
case Error::CBOR_UNEXPECTED_EOF_IN_ARRAY:
|
||||
return ToASCIIString("CBOR: unexpected eof in array");
|
||||
return "CBOR: unexpected eof in array";
|
||||
case Error::CBOR_UNEXPECTED_EOF_IN_MAP:
|
||||
return ToASCIIString("CBOR: unexpected eof in map");
|
||||
return "CBOR: unexpected eof in map";
|
||||
case Error::CBOR_INVALID_MAP_KEY:
|
||||
return ToASCIIString("CBOR: invalid map key");
|
||||
return "CBOR: invalid map key";
|
||||
case Error::CBOR_DUPLICATE_MAP_KEY:
|
||||
return "CBOR: duplicate map key";
|
||||
case Error::CBOR_STACK_LIMIT_EXCEEDED:
|
||||
return ToASCIIString("CBOR: stack limit exceeded");
|
||||
return "CBOR: stack limit exceeded";
|
||||
case Error::CBOR_TRAILING_JUNK:
|
||||
return ToASCIIString("CBOR: trailing junk");
|
||||
return "CBOR: trailing junk";
|
||||
case Error::CBOR_MAP_START_EXPECTED:
|
||||
return ToASCIIString("CBOR: map start expected");
|
||||
return "CBOR: map start expected";
|
||||
case Error::CBOR_MAP_STOP_EXPECTED:
|
||||
return ToASCIIString("CBOR: map stop expected");
|
||||
return "CBOR: map stop expected";
|
||||
case Error::CBOR_ARRAY_START_EXPECTED:
|
||||
return ToASCIIString("CBOR: array start expected");
|
||||
return "CBOR: array start expected";
|
||||
case Error::CBOR_ENVELOPE_SIZE_LIMIT_EXCEEDED:
|
||||
return ToASCIIString("CBOR: envelope size limit exceeded");
|
||||
return "CBOR: envelope size limit exceeded";
|
||||
|
||||
case Error::MESSAGE_MUST_BE_AN_OBJECT:
|
||||
return "Message must be an object";
|
||||
case Error::MESSAGE_MUST_HAVE_INTEGER_ID_PROPERTY:
|
||||
return "Message must have integer 'id' property";
|
||||
case Error::MESSAGE_MUST_HAVE_STRING_METHOD_PROPERTY:
|
||||
return "Message must have string 'method' property";
|
||||
case Error::MESSAGE_MAY_HAVE_STRING_SESSION_ID_PROPERTY:
|
||||
return "Message may have string 'sessionId' property";
|
||||
case Error::MESSAGE_MAY_HAVE_OBJECT_PARAMS_PROPERTY:
|
||||
return "Message may have object 'params' property";
|
||||
case Error::MESSAGE_HAS_UNKNOWN_PROPERTY:
|
||||
return "Message has property other than "
|
||||
"'id', 'method', 'sessionId', 'params'";
|
||||
|
||||
case Error::BINDINGS_MANDATORY_FIELD_MISSING:
|
||||
return ToASCIIString("BINDINGS: mandatory field missing");
|
||||
return "BINDINGS: mandatory field missing";
|
||||
case Error::BINDINGS_BOOL_VALUE_EXPECTED:
|
||||
return ToASCIIString("BINDINGS: bool value expected");
|
||||
return "BINDINGS: bool value expected";
|
||||
case Error::BINDINGS_INT32_VALUE_EXPECTED:
|
||||
return ToASCIIString("BINDINGS: int32 value expected");
|
||||
return "BINDINGS: int32 value expected";
|
||||
case Error::BINDINGS_DOUBLE_VALUE_EXPECTED:
|
||||
return ToASCIIString("BINDINGS: double value expected");
|
||||
return "BINDINGS: double value expected";
|
||||
case Error::BINDINGS_STRING_VALUE_EXPECTED:
|
||||
return ToASCIIString("BINDINGS: string value expected");
|
||||
return "BINDINGS: string value expected";
|
||||
case Error::BINDINGS_STRING8_VALUE_EXPECTED:
|
||||
return ToASCIIString("BINDINGS: string8 value expected");
|
||||
return "BINDINGS: string8 value expected";
|
||||
case Error::BINDINGS_BINARY_VALUE_EXPECTED:
|
||||
return ToASCIIString("BINDINGS: binary value expected");
|
||||
return "BINDINGS: binary value expected";
|
||||
}
|
||||
// Some compilers can't figure out that we can't get here.
|
||||
return "INVALID ERROR CODE";
|
||||
}
|
||||
|
||||
std::string Status::ToASCIIString(const char* msg) const {
|
||||
return std::string(msg) + " at position " + std::to_string(pos);
|
||||
std::string Status::ToASCIIString() const {
|
||||
if (ok())
|
||||
return "OK";
|
||||
return Message() + " at position " + std::to_string(pos);
|
||||
}
|
||||
} // namespace v8_crdtp
|
||||
|
58
third_party/inspector_protocol/crdtp/status.h
vendored
58
third_party/inspector_protocol/crdtp/status.h
vendored
@ -18,7 +18,9 @@ namespace v8_crdtp {
|
||||
|
||||
enum class Error {
|
||||
OK = 0,
|
||||
// JSON parsing errors - json_parser.{h,cc}.
|
||||
|
||||
// JSON parsing errors; checked when parsing / converting from JSON.
|
||||
// See json.{h,cc}.
|
||||
JSON_PARSER_UNPROCESSED_INPUT_REMAINS = 0x01,
|
||||
JSON_PARSER_STACK_LIMIT_EXCEEDED = 0x02,
|
||||
JSON_PARSER_NO_INPUT = 0x03,
|
||||
@ -33,6 +35,7 @@ enum class Error {
|
||||
JSON_PARSER_COMMA_OR_MAP_END_EXPECTED = 0x0c,
|
||||
JSON_PARSER_VALUE_EXPECTED = 0x0d,
|
||||
|
||||
// CBOR parsing errors; checked when parsing / converting from CBOR.
|
||||
CBOR_INVALID_INT32 = 0x0e,
|
||||
CBOR_INVALID_DOUBLE = 0x0f,
|
||||
CBOR_INVALID_ENVELOPE = 0x10,
|
||||
@ -48,20 +51,31 @@ enum class Error {
|
||||
CBOR_UNEXPECTED_EOF_IN_ARRAY = 0x1a,
|
||||
CBOR_UNEXPECTED_EOF_IN_MAP = 0x1b,
|
||||
CBOR_INVALID_MAP_KEY = 0x1c,
|
||||
CBOR_STACK_LIMIT_EXCEEDED = 0x1d,
|
||||
CBOR_TRAILING_JUNK = 0x1e,
|
||||
CBOR_MAP_START_EXPECTED = 0x1f,
|
||||
CBOR_MAP_STOP_EXPECTED = 0x20,
|
||||
CBOR_ARRAY_START_EXPECTED = 0x21,
|
||||
CBOR_ENVELOPE_SIZE_LIMIT_EXCEEDED = 0x22,
|
||||
CBOR_DUPLICATE_MAP_KEY = 0x1d,
|
||||
CBOR_STACK_LIMIT_EXCEEDED = 0x1e,
|
||||
CBOR_TRAILING_JUNK = 0x1f,
|
||||
CBOR_MAP_START_EXPECTED = 0x20,
|
||||
CBOR_MAP_STOP_EXPECTED = 0x21,
|
||||
CBOR_ARRAY_START_EXPECTED = 0x22,
|
||||
CBOR_ENVELOPE_SIZE_LIMIT_EXCEEDED = 0x23,
|
||||
|
||||
BINDINGS_MANDATORY_FIELD_MISSING = 0x23,
|
||||
BINDINGS_BOOL_VALUE_EXPECTED = 0x24,
|
||||
BINDINGS_INT32_VALUE_EXPECTED = 0x25,
|
||||
BINDINGS_DOUBLE_VALUE_EXPECTED = 0x26,
|
||||
BINDINGS_STRING_VALUE_EXPECTED = 0x27,
|
||||
BINDINGS_STRING8_VALUE_EXPECTED = 0x28,
|
||||
BINDINGS_BINARY_VALUE_EXPECTED = 0x29,
|
||||
// Message errors are constraints we place on protocol messages coming
|
||||
// from a protocol client; these are checked in crdtp::Dispatchable
|
||||
// (see dispatch.h) as it performs a shallow parse.
|
||||
MESSAGE_MUST_BE_AN_OBJECT = 0x24,
|
||||
MESSAGE_MUST_HAVE_INTEGER_ID_PROPERTY = 0x25,
|
||||
MESSAGE_MUST_HAVE_STRING_METHOD_PROPERTY = 0x26,
|
||||
MESSAGE_MAY_HAVE_STRING_SESSION_ID_PROPERTY = 0x27,
|
||||
MESSAGE_MAY_HAVE_OBJECT_PARAMS_PROPERTY = 0x28,
|
||||
MESSAGE_HAS_UNKNOWN_PROPERTY = 0x29,
|
||||
|
||||
BINDINGS_MANDATORY_FIELD_MISSING = 0x30,
|
||||
BINDINGS_BOOL_VALUE_EXPECTED = 0x31,
|
||||
BINDINGS_INT32_VALUE_EXPECTED = 0x32,
|
||||
BINDINGS_DOUBLE_VALUE_EXPECTED = 0x33,
|
||||
BINDINGS_STRING_VALUE_EXPECTED = 0x34,
|
||||
BINDINGS_STRING8_VALUE_EXPECTED = 0x35,
|
||||
BINDINGS_BINARY_VALUE_EXPECTED = 0x36,
|
||||
};
|
||||
|
||||
// A status value with position that can be copied. The default status
|
||||
@ -76,12 +90,18 @@ struct Status {
|
||||
Status(Error error, size_t pos) : error(error), pos(pos) {}
|
||||
Status() = default;
|
||||
|
||||
// Returns a 7 bit US-ASCII string, either "OK" or an error message
|
||||
// that includes the position.
|
||||
std::string ToASCIIString() const;
|
||||
bool IsMessageError() const {
|
||||
return error >= Error::MESSAGE_MUST_BE_AN_OBJECT &&
|
||||
error <= Error::MESSAGE_HAS_UNKNOWN_PROPERTY;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string ToASCIIString(const char* msg) const;
|
||||
// Returns 7 bit US-ASCII string, either "OK" or an error message without
|
||||
// position.
|
||||
std::string Message() const;
|
||||
|
||||
// Returns a 7 bit US-ASCII string, either "OK" or an error message that
|
||||
// includes the position.
|
||||
std::string ToASCIIString() const;
|
||||
};
|
||||
} // namespace v8_crdtp
|
||||
|
||||
|
@ -33,10 +33,7 @@ template("inspector_protocol_generate") {
|
||||
invoker.config_file,
|
||||
"$inspector_protocol_dir/lib/base_string_adapter_cc.template",
|
||||
"$inspector_protocol_dir/lib/base_string_adapter_h.template",
|
||||
"$inspector_protocol_dir/lib/DispatcherBase_cpp.template",
|
||||
"$inspector_protocol_dir/lib/DispatcherBase_h.template",
|
||||
"$inspector_protocol_dir/lib/Forward_h.template",
|
||||
"$inspector_protocol_dir/lib/FrontendChannel_h.template",
|
||||
"$inspector_protocol_dir/lib/Object_cpp.template",
|
||||
"$inspector_protocol_dir/lib/Object_h.template",
|
||||
"$inspector_protocol_dir/lib/Protocol_cpp.template",
|
||||
@ -56,6 +53,7 @@ template("inspector_protocol_generate") {
|
||||
"--jinja_dir",
|
||||
rebase_path("//third_party/", root_build_dir), # jinja is in chromium's
|
||||
# third_party
|
||||
|
||||
"--output_base",
|
||||
rebase_path(invoker.out_dir, root_build_dir),
|
||||
"--config",
|
||||
|
@ -1,357 +0,0 @@
|
||||
// This file is generated by DispatcherBase_cpp.template.
|
||||
|
||||
// Copyright 2016 The Chromium 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 "DispatcherBase.h"
|
||||
//#include "Parser.h"
|
||||
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
namespace {{namespace}} {
|
||||
{% endfor %}
|
||||
|
||||
// static
|
||||
DispatchResponse DispatchResponse::OK()
|
||||
{
|
||||
DispatchResponse result;
|
||||
result.m_status = kSuccess;
|
||||
result.m_errorCode = kParseError;
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
DispatchResponse DispatchResponse::Error(const String& error)
|
||||
{
|
||||
DispatchResponse result;
|
||||
result.m_status = kError;
|
||||
result.m_errorCode = kServerError;
|
||||
result.m_errorMessage = error;
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
DispatchResponse DispatchResponse::InternalError()
|
||||
{
|
||||
DispatchResponse result;
|
||||
result.m_status = kError;
|
||||
result.m_errorCode = kInternalError;
|
||||
result.m_errorMessage = "Internal error";
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
DispatchResponse DispatchResponse::InvalidParams(const String& error)
|
||||
{
|
||||
DispatchResponse result;
|
||||
result.m_status = kError;
|
||||
result.m_errorCode = kInvalidParams;
|
||||
result.m_errorMessage = error;
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
DispatchResponse DispatchResponse::FallThrough()
|
||||
{
|
||||
DispatchResponse result;
|
||||
result.m_status = kFallThrough;
|
||||
result.m_errorCode = kParseError;
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
const char DispatcherBase::kInvalidParamsString[] = "Invalid parameters";
|
||||
|
||||
DispatcherBase::WeakPtr::WeakPtr(DispatcherBase* dispatcher) : m_dispatcher(dispatcher) { }
|
||||
|
||||
DispatcherBase::WeakPtr::~WeakPtr()
|
||||
{
|
||||
if (m_dispatcher)
|
||||
m_dispatcher->m_weakPtrs.erase(this);
|
||||
}
|
||||
|
||||
DispatcherBase::Callback::Callback(std::unique_ptr<DispatcherBase::WeakPtr> backendImpl, int callId, const String& method, {{config.crdtp.namespace}}::span<uint8_t> message)
|
||||
: m_backendImpl(std::move(backendImpl))
|
||||
, m_callId(callId)
|
||||
, m_method(method)
|
||||
, m_message(message.begin(), message.end()) { }
|
||||
|
||||
DispatcherBase::Callback::~Callback() = default;
|
||||
|
||||
void DispatcherBase::Callback::dispose()
|
||||
{
|
||||
m_backendImpl = nullptr;
|
||||
}
|
||||
|
||||
void DispatcherBase::Callback::sendIfActive(std::unique_ptr<protocol::DictionaryValue> partialMessage, const DispatchResponse& response)
|
||||
{
|
||||
if (!m_backendImpl || !m_backendImpl->get())
|
||||
return;
|
||||
m_backendImpl->get()->sendResponse(m_callId, response, std::move(partialMessage));
|
||||
m_backendImpl = nullptr;
|
||||
}
|
||||
|
||||
void DispatcherBase::Callback::fallThroughIfActive()
|
||||
{
|
||||
if (!m_backendImpl || !m_backendImpl->get())
|
||||
return;
|
||||
m_backendImpl->get()->channel()->fallThrough(m_callId, m_method, {{config.crdtp.namespace}}::SpanFrom(m_message));
|
||||
m_backendImpl = nullptr;
|
||||
}
|
||||
|
||||
DispatcherBase::DispatcherBase(FrontendChannel* frontendChannel)
|
||||
: m_frontendChannel(frontendChannel) { }
|
||||
|
||||
DispatcherBase::~DispatcherBase()
|
||||
{
|
||||
clearFrontend();
|
||||
}
|
||||
|
||||
void DispatcherBase::sendResponse(int callId, const DispatchResponse& response, std::unique_ptr<protocol::DictionaryValue> result)
|
||||
{
|
||||
if (!m_frontendChannel)
|
||||
return;
|
||||
if (response.status() == DispatchResponse::kError) {
|
||||
reportProtocolError(callId, response.errorCode(), response.errorMessage(), nullptr);
|
||||
return;
|
||||
}
|
||||
m_frontendChannel->sendProtocolResponse(callId, InternalResponse::createResponse(callId, std::move(result)));
|
||||
}
|
||||
|
||||
void DispatcherBase::sendResponse(int callId, const DispatchResponse& response)
|
||||
{
|
||||
sendResponse(callId, response, DictionaryValue::create());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class ProtocolError : public Serializable {
|
||||
public:
|
||||
static std::unique_ptr<ProtocolError> createErrorResponse(int callId, DispatchResponse::ErrorCode code, const String& errorMessage, ErrorSupport* errors)
|
||||
{
|
||||
std::unique_ptr<ProtocolError> protocolError(new ProtocolError(code, errorMessage));
|
||||
protocolError->m_callId = callId;
|
||||
protocolError->m_hasCallId = true;
|
||||
if (errors && !errors->Errors().empty()) {
|
||||
protocolError->m_data =
|
||||
StringUtil::fromUTF8(errors->Errors().data(), errors->Errors().size());
|
||||
}
|
||||
return protocolError;
|
||||
}
|
||||
|
||||
static std::unique_ptr<ProtocolError> createErrorNotification(DispatchResponse::ErrorCode code, const String& errorMessage)
|
||||
{
|
||||
return std::unique_ptr<ProtocolError>(new ProtocolError(code, errorMessage));
|
||||
}
|
||||
|
||||
void AppendSerialized(std::vector<uint8_t>* out) const override
|
||||
{
|
||||
toDictionary()->AppendSerialized(out);
|
||||
}
|
||||
|
||||
~ProtocolError() override {}
|
||||
|
||||
private:
|
||||
ProtocolError(DispatchResponse::ErrorCode code, const String& errorMessage)
|
||||
: m_code(code)
|
||||
, m_errorMessage(errorMessage)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<DictionaryValue> toDictionary() const {
|
||||
std::unique_ptr<protocol::DictionaryValue> error = DictionaryValue::create();
|
||||
error->setInteger("code", m_code);
|
||||
error->setString("message", m_errorMessage);
|
||||
if (m_data.length())
|
||||
error->setString("data", m_data);
|
||||
std::unique_ptr<protocol::DictionaryValue> message = DictionaryValue::create();
|
||||
message->setObject("error", std::move(error));
|
||||
if (m_hasCallId)
|
||||
message->setInteger("id", m_callId);
|
||||
return message;
|
||||
}
|
||||
|
||||
DispatchResponse::ErrorCode m_code;
|
||||
String m_errorMessage;
|
||||
String m_data;
|
||||
int m_callId = 0;
|
||||
bool m_hasCallId = false;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static void reportProtocolErrorTo(FrontendChannel* frontendChannel, int callId, DispatchResponse::ErrorCode code, const String& errorMessage, ErrorSupport* errors)
|
||||
{
|
||||
if (frontendChannel)
|
||||
frontendChannel->sendProtocolResponse(callId, ProtocolError::createErrorResponse(callId, code, errorMessage, errors));
|
||||
}
|
||||
|
||||
static void reportProtocolErrorTo(FrontendChannel* frontendChannel, DispatchResponse::ErrorCode code, const String& errorMessage)
|
||||
{
|
||||
if (frontendChannel)
|
||||
frontendChannel->sendProtocolNotification(ProtocolError::createErrorNotification(code, errorMessage));
|
||||
}
|
||||
|
||||
void DispatcherBase::reportProtocolError(int callId, DispatchResponse::ErrorCode code, const String& errorMessage, ErrorSupport* errors)
|
||||
{
|
||||
reportProtocolErrorTo(m_frontendChannel, callId, code, errorMessage, errors);
|
||||
}
|
||||
|
||||
void DispatcherBase::clearFrontend()
|
||||
{
|
||||
m_frontendChannel = nullptr;
|
||||
for (auto& weak : m_weakPtrs)
|
||||
weak->dispose();
|
||||
m_weakPtrs.clear();
|
||||
}
|
||||
|
||||
std::unique_ptr<DispatcherBase::WeakPtr> DispatcherBase::weakPtr()
|
||||
{
|
||||
std::unique_ptr<DispatcherBase::WeakPtr> weak(new DispatcherBase::WeakPtr(this));
|
||||
m_weakPtrs.insert(weak.get());
|
||||
return weak;
|
||||
}
|
||||
|
||||
UberDispatcher::UberDispatcher(FrontendChannel* frontendChannel)
|
||||
: m_frontendChannel(frontendChannel) { }
|
||||
|
||||
void UberDispatcher::registerBackend(const String& name, std::unique_ptr<protocol::DispatcherBase> dispatcher)
|
||||
{
|
||||
m_dispatchers[name] = std::move(dispatcher);
|
||||
}
|
||||
|
||||
void UberDispatcher::setupRedirects(const std::unordered_map<String, String>& redirects)
|
||||
{
|
||||
for (const auto& pair : redirects)
|
||||
m_redirects[pair.first] = pair.second;
|
||||
}
|
||||
|
||||
bool UberDispatcher::parseCommand(Value* parsedMessage, int* outCallId, String* outMethod) {
|
||||
if (!parsedMessage) {
|
||||
reportProtocolErrorTo(m_frontendChannel, DispatchResponse::kParseError, "Message must be a valid JSON");
|
||||
return false;
|
||||
}
|
||||
protocol::DictionaryValue* messageObject = DictionaryValue::cast(parsedMessage);
|
||||
if (!messageObject) {
|
||||
reportProtocolErrorTo(m_frontendChannel, DispatchResponse::kInvalidRequest, "Message must be an object");
|
||||
return false;
|
||||
}
|
||||
|
||||
int callId = 0;
|
||||
protocol::Value* callIdValue = messageObject->get("id");
|
||||
bool success = callIdValue && callIdValue->asInteger(&callId);
|
||||
if (!success) {
|
||||
reportProtocolErrorTo(m_frontendChannel, DispatchResponse::kInvalidRequest, "Message must have integer 'id' property");
|
||||
return false;
|
||||
}
|
||||
if (outCallId)
|
||||
*outCallId = callId;
|
||||
|
||||
protocol::Value* methodValue = messageObject->get("method");
|
||||
String method;
|
||||
success = methodValue && methodValue->asString(&method);
|
||||
if (!success) {
|
||||
reportProtocolErrorTo(m_frontendChannel, callId, DispatchResponse::kInvalidRequest, "Message must have string 'method' property", nullptr);
|
||||
return false;
|
||||
}
|
||||
if (outMethod)
|
||||
*outMethod = method;
|
||||
return true;
|
||||
}
|
||||
|
||||
protocol::DispatcherBase* UberDispatcher::findDispatcher(const String& method) {
|
||||
size_t dotIndex = StringUtil::find(method, ".");
|
||||
if (dotIndex == StringUtil::kNotFound)
|
||||
return nullptr;
|
||||
String domain = StringUtil::substring(method, 0, dotIndex);
|
||||
auto it = m_dispatchers.find(domain);
|
||||
if (it == m_dispatchers.end())
|
||||
return nullptr;
|
||||
if (!it->second->canDispatch(method))
|
||||
return nullptr;
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
bool UberDispatcher::canDispatch(const String& in_method)
|
||||
{
|
||||
String method = in_method;
|
||||
auto redirectIt = m_redirects.find(method);
|
||||
if (redirectIt != m_redirects.end())
|
||||
method = redirectIt->second;
|
||||
return !!findDispatcher(method);
|
||||
}
|
||||
|
||||
void UberDispatcher::dispatch(int callId, const String& in_method, std::unique_ptr<Value> parsedMessage, {{config.crdtp.namespace}}::span<uint8_t> rawMessage)
|
||||
{
|
||||
String method = in_method;
|
||||
auto redirectIt = m_redirects.find(method);
|
||||
if (redirectIt != m_redirects.end())
|
||||
method = redirectIt->second;
|
||||
protocol::DispatcherBase* dispatcher = findDispatcher(method);
|
||||
if (!dispatcher) {
|
||||
reportProtocolErrorTo(m_frontendChannel, callId, DispatchResponse::kMethodNotFound, "'" + method + "' wasn't found", nullptr);
|
||||
return;
|
||||
}
|
||||
std::unique_ptr<protocol::DictionaryValue> messageObject = DictionaryValue::cast(std::move(parsedMessage));
|
||||
dispatcher->dispatch(callId, method, rawMessage, std::move(messageObject));
|
||||
}
|
||||
|
||||
UberDispatcher::~UberDispatcher() = default;
|
||||
|
||||
// static
|
||||
std::unique_ptr<Serializable> InternalResponse::createResponse(int callId, std::unique_ptr<Serializable> params)
|
||||
{
|
||||
return std::unique_ptr<Serializable>(new InternalResponse(callId, nullptr, std::move(params)));
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<Serializable> InternalResponse::createNotification(const char* method, std::unique_ptr<Serializable> params)
|
||||
{
|
||||
return std::unique_ptr<Serializable>(new InternalResponse(0, method, std::move(params)));
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<Serializable> InternalResponse::createErrorResponse(int callId, DispatchResponse::ErrorCode code, const String& message)
|
||||
{
|
||||
return ProtocolError::createErrorResponse(callId, code, message, nullptr);
|
||||
}
|
||||
|
||||
void InternalResponse::AppendSerialized(std::vector<uint8_t>* out) const
|
||||
{
|
||||
using {{config.crdtp.namespace}}::cbor::NewCBOREncoder;
|
||||
using {{config.crdtp.namespace}}::ParserHandler;
|
||||
using {{config.crdtp.namespace}}::Status;
|
||||
using {{config.crdtp.namespace}}::SpanFrom;
|
||||
|
||||
Status status;
|
||||
std::unique_ptr<ParserHandler> encoder = NewCBOREncoder(out, &status);
|
||||
encoder->HandleMapBegin();
|
||||
if (m_method) {
|
||||
encoder->HandleString8(SpanFrom("method"));
|
||||
encoder->HandleString8(SpanFrom(m_method));
|
||||
encoder->HandleString8(SpanFrom("params"));
|
||||
} else {
|
||||
encoder->HandleString8(SpanFrom("id"));
|
||||
encoder->HandleInt32(m_callId);
|
||||
encoder->HandleString8(SpanFrom("result"));
|
||||
}
|
||||
if (m_params) {
|
||||
m_params->AppendSerialized(out);
|
||||
} else {
|
||||
encoder->HandleMapBegin();
|
||||
encoder->HandleMapEnd();
|
||||
}
|
||||
encoder->HandleMapEnd();
|
||||
DCHECK(status.ok());
|
||||
}
|
||||
|
||||
InternalResponse::InternalResponse(int callId, const char* method, std::unique_ptr<Serializable> params)
|
||||
: m_callId(callId)
|
||||
, m_method(method)
|
||||
, m_params(params ? std::move(params) : nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
} // namespace {{namespace}}
|
||||
{% endfor %}
|
@ -1,153 +0,0 @@
|
||||
// This file is generated by DispatcherBase_h.template.
|
||||
|
||||
// Copyright 2016 The Chromium 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 {{"_".join(config.protocol.namespace)}}_DispatcherBase_h
|
||||
#define {{"_".join(config.protocol.namespace)}}_DispatcherBase_h
|
||||
|
||||
//#include "Forward.h"
|
||||
//#include "ErrorSupport.h"
|
||||
//#include "Values.h"
|
||||
|
||||
#include "{{config.crdtp.dir}}/span.h"
|
||||
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
namespace {{namespace}} {
|
||||
{% endfor %}
|
||||
|
||||
class WeakPtr;
|
||||
|
||||
class {{config.lib.export_macro}} DispatchResponse {
|
||||
public:
|
||||
enum Status {
|
||||
kSuccess = 0,
|
||||
kError = 1,
|
||||
kFallThrough = 2,
|
||||
};
|
||||
|
||||
// For historical reasons, these error codes correspond to commonly used
|
||||
// XMLRPC codes (e.g. see METHOD_NOT_FOUND in
|
||||
// https://github.com/python/cpython/blob/master/Lib/xmlrpc/client.py).
|
||||
enum ErrorCode {
|
||||
kParseError = -32700,
|
||||
kInvalidRequest = -32600,
|
||||
kMethodNotFound = -32601,
|
||||
kInvalidParams = -32602,
|
||||
kInternalError = -32603,
|
||||
kServerError = -32000,
|
||||
};
|
||||
|
||||
Status status() const { return m_status; }
|
||||
const String& errorMessage() const { return m_errorMessage; }
|
||||
ErrorCode errorCode() const { return m_errorCode; }
|
||||
bool isSuccess() const { return m_status == kSuccess; }
|
||||
|
||||
static DispatchResponse OK();
|
||||
static DispatchResponse Error(const String&);
|
||||
static DispatchResponse InternalError();
|
||||
static DispatchResponse InvalidParams(const String&);
|
||||
static DispatchResponse FallThrough();
|
||||
|
||||
private:
|
||||
Status m_status;
|
||||
String m_errorMessage;
|
||||
ErrorCode m_errorCode;
|
||||
};
|
||||
|
||||
class {{config.lib.export_macro}} DispatcherBase {
|
||||
PROTOCOL_DISALLOW_COPY(DispatcherBase);
|
||||
public:
|
||||
static const char kInvalidParamsString[];
|
||||
class {{config.lib.export_macro}} WeakPtr {
|
||||
public:
|
||||
explicit WeakPtr(DispatcherBase*);
|
||||
~WeakPtr();
|
||||
DispatcherBase* get() { return m_dispatcher; }
|
||||
void dispose() { m_dispatcher = nullptr; }
|
||||
|
||||
private:
|
||||
DispatcherBase* m_dispatcher;
|
||||
};
|
||||
|
||||
class {{config.lib.export_macro}} Callback {
|
||||
public:
|
||||
Callback(std::unique_ptr<WeakPtr> backendImpl, int callId, const String& method, {{config.crdtp.namespace}}::span<uint8_t> message);
|
||||
virtual ~Callback();
|
||||
void dispose();
|
||||
|
||||
protected:
|
||||
void sendIfActive(std::unique_ptr<protocol::DictionaryValue> partialMessage, const DispatchResponse& response);
|
||||
void fallThroughIfActive();
|
||||
|
||||
private:
|
||||
std::unique_ptr<WeakPtr> m_backendImpl;
|
||||
int m_callId;
|
||||
String m_method;
|
||||
std::vector<uint8_t> m_message;
|
||||
};
|
||||
|
||||
explicit DispatcherBase(FrontendChannel*);
|
||||
virtual ~DispatcherBase();
|
||||
|
||||
virtual bool canDispatch(const String& method) = 0;
|
||||
virtual void dispatch(int callId, const String& method, {{config.crdtp.namespace}}::span<uint8_t> rawMessage, std::unique_ptr<protocol::DictionaryValue> messageObject) = 0;
|
||||
FrontendChannel* channel() { return m_frontendChannel; }
|
||||
|
||||
void sendResponse(int callId, const DispatchResponse&, std::unique_ptr<protocol::DictionaryValue> result);
|
||||
void sendResponse(int callId, const DispatchResponse&);
|
||||
|
||||
void reportProtocolError(int callId, DispatchResponse::ErrorCode, const String& errorMessage, ErrorSupport* errors);
|
||||
void clearFrontend();
|
||||
|
||||
std::unique_ptr<WeakPtr> weakPtr();
|
||||
|
||||
private:
|
||||
FrontendChannel* m_frontendChannel;
|
||||
std::unordered_set<WeakPtr*> m_weakPtrs;
|
||||
};
|
||||
|
||||
class {{config.lib.export_macro}} UberDispatcher {
|
||||
PROTOCOL_DISALLOW_COPY(UberDispatcher);
|
||||
public:
|
||||
explicit UberDispatcher(FrontendChannel*);
|
||||
void registerBackend(const String& name, std::unique_ptr<protocol::DispatcherBase>);
|
||||
void setupRedirects(const std::unordered_map<String, String>&);
|
||||
bool parseCommand(Value* message, int* callId, String* method);
|
||||
bool canDispatch(const String& method);
|
||||
void dispatch(int callId, const String& method, std::unique_ptr<Value> message, {{config.crdtp.namespace}}::span<uint8_t> rawMessage);
|
||||
FrontendChannel* channel() { return m_frontendChannel; }
|
||||
virtual ~UberDispatcher();
|
||||
|
||||
private:
|
||||
protocol::DispatcherBase* findDispatcher(const String& method);
|
||||
FrontendChannel* m_frontendChannel;
|
||||
std::unordered_map<String, String> m_redirects;
|
||||
std::unordered_map<String, std::unique_ptr<protocol::DispatcherBase>> m_dispatchers;
|
||||
};
|
||||
|
||||
class InternalResponse : public Serializable {
|
||||
PROTOCOL_DISALLOW_COPY(InternalResponse);
|
||||
public:
|
||||
static std::unique_ptr<Serializable> createResponse(int callId, std::unique_ptr<Serializable> params);
|
||||
static std::unique_ptr<Serializable> createNotification(const char* method, std::unique_ptr<Serializable> params = nullptr);
|
||||
static std::unique_ptr<Serializable> createErrorResponse(int callId, DispatchResponse::ErrorCode code, const String& message);
|
||||
|
||||
void AppendSerialized(std::vector<uint8_t>* out) const override;
|
||||
|
||||
~InternalResponse() override {}
|
||||
|
||||
private:
|
||||
InternalResponse(int callId, const char* method, std::unique_ptr<Serializable> params);
|
||||
|
||||
int m_callId;
|
||||
const char* m_method = nullptr;
|
||||
std::unique_ptr<Serializable> m_params;
|
||||
};
|
||||
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
} // namespace {{namespace}}
|
||||
{% endfor %}
|
||||
|
||||
#endif // !defined({{"_".join(config.protocol.namespace)}}_DispatcherBase_h)
|
@ -19,6 +19,8 @@
|
||||
#include <unordered_set>
|
||||
|
||||
#include "{{config.crdtp.dir}}/error_support.h"
|
||||
#include "{{config.crdtp.dir}}/dispatch.h"
|
||||
#include "{{config.crdtp.dir}}/frontend_channel.h"
|
||||
#include "{{config.crdtp.dir}}/glue.h"
|
||||
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
@ -26,15 +28,18 @@ namespace {{namespace}} {
|
||||
{% endfor %}
|
||||
|
||||
class DictionaryValue;
|
||||
class DispatchResponse;
|
||||
using DispatchResponse = {{config.crdtp.namespace}}::DispatchResponse;
|
||||
using ErrorSupport = {{config.crdtp.namespace}}::ErrorSupport;
|
||||
using Serializable = {{config.crdtp.namespace}}::Serializable;
|
||||
using FrontendChannel = {{config.crdtp.namespace}}::FrontendChannel;
|
||||
using DomainDispatcher = {{config.crdtp.namespace}}::DomainDispatcher;
|
||||
using UberDispatcher = {{config.crdtp.namespace}}::UberDispatcher;
|
||||
class FundamentalValue;
|
||||
class ListValue;
|
||||
class Object;
|
||||
using Response = DispatchResponse;
|
||||
class SerializedValue;
|
||||
class StringValue;
|
||||
class UberDispatcher;
|
||||
class Value;
|
||||
|
||||
namespace detail {
|
||||
|
@ -1,33 +0,0 @@
|
||||
// This file is generated by FrontendChannel_h.template.
|
||||
|
||||
// Copyright 2016 The Chromium 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 {{"_".join(config.protocol.namespace)}}_FrontendChannel_h
|
||||
#define {{"_".join(config.protocol.namespace)}}_FrontendChannel_h
|
||||
|
||||
#include "{{config.crdtp.dir}}/serializable.h"
|
||||
#include "{{config.crdtp.dir}}/span.h"
|
||||
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
namespace {{namespace}} {
|
||||
{% endfor %}
|
||||
|
||||
using {{config.crdtp.namespace}}::Serializable;
|
||||
|
||||
class {{config.lib.export_macro}} FrontendChannel {
|
||||
public:
|
||||
virtual ~FrontendChannel() { }
|
||||
virtual void sendProtocolResponse(int callId, std::unique_ptr<Serializable> message) = 0;
|
||||
virtual void sendProtocolNotification(std::unique_ptr<Serializable> message) = 0;
|
||||
|
||||
virtual void fallThrough(int callId, const String& method, {{config.crdtp.namespace}}::span<uint8_t> message) = 0;
|
||||
virtual void flushProtocolNotifications() = 0;
|
||||
};
|
||||
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
} // namespace {{namespace}}
|
||||
{% endfor %}
|
||||
|
||||
#endif // !defined({{"_".join(config.protocol.namespace)}}_FrontendChannel_h)
|
@ -34,17 +34,6 @@ using String = std::string;
|
||||
|
||||
class {{config.lib.export_macro}} StringUtil {
|
||||
public:
|
||||
static String substring(const String& s, unsigned pos, unsigned len) {
|
||||
return s.substr(pos, len);
|
||||
}
|
||||
static size_t find(const String& s, const char* needle) {
|
||||
return s.find(needle);
|
||||
}
|
||||
static size_t find(const String& s, const String& needle) {
|
||||
return s.find(needle);
|
||||
}
|
||||
static const size_t kNotFound = static_cast<size_t>(-1);
|
||||
|
||||
static String fromUTF8(const uint8_t* data, size_t length) {
|
||||
return std::string(reinterpret_cast<const char*>(data), length);
|
||||
}
|
||||
|
8
third_party/inspector_protocol/roll.py
vendored
8
third_party/inspector_protocol/roll.py
vendored
@ -21,9 +21,16 @@ FILES_TO_SYNC = [
|
||||
'crdtp/cbor.cc',
|
||||
'crdtp/cbor.h',
|
||||
'crdtp/cbor_test.cc',
|
||||
'crdtp/dispatch.h',
|
||||
'crdtp/dispatch.cc',
|
||||
'crdtp/dispatch_test.cc',
|
||||
'crdtp/error_support.cc',
|
||||
'crdtp/error_support.h',
|
||||
'crdtp/error_support_test.cc',
|
||||
'crdtp/export_template.h',
|
||||
'crdtp/find_by_first.h',
|
||||
'crdtp/find_by_first_test.cc',
|
||||
'crdtp/frontend_channel.h',
|
||||
'crdtp/glue.h',
|
||||
'crdtp/glue_test.cc',
|
||||
'crdtp/json.cc',
|
||||
@ -36,6 +43,7 @@ FILES_TO_SYNC = [
|
||||
'crdtp/serializable_test.cc',
|
||||
'crdtp/serializer_traits.h',
|
||||
'crdtp/serializer_traits_test.cc',
|
||||
'crdtp/span.cc',
|
||||
'crdtp/span.h',
|
||||
'crdtp/span_test.cc',
|
||||
'crdtp/status.cc',
|
||||
|
@ -9,7 +9,9 @@
|
||||
#include {{format_include(config.protocol.package, "Protocol")}}
|
||||
|
||||
#include "{{config.crdtp.dir}}/cbor.h"
|
||||
#include "{{config.crdtp.dir}}/find_by_first.h"
|
||||
#include "{{config.crdtp.dir}}/serializer_traits.h"
|
||||
#include "{{config.crdtp.dir}}/span.h"
|
||||
|
||||
{% for namespace in config.protocol.namespace %}
|
||||
namespace {{namespace}} {
|
||||
@ -169,7 +171,7 @@ void Frontend::{{event.name | to_method_case}}(
|
||||
{%- endif %} {{parameter.name}}{%- if not loop.last -%}, {% endif -%}
|
||||
{% endfor -%})
|
||||
{
|
||||
if (!m_frontendChannel)
|
||||
if (!frontend_channel_)
|
||||
return;
|
||||
{% if event.parameters %}
|
||||
std::unique_ptr<{{event.name | to_title_case}}Notification> messageData = {{event.name | to_title_case}}Notification::{{"create" | to_method_case}}()
|
||||
@ -185,69 +187,79 @@ void Frontend::{{event.name | to_method_case}}(
|
||||
messageData->{{"set" | to_method_case}}{{parameter.name | to_title_case}}(std::move({{parameter.name}}).takeJust());
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
m_frontendChannel->sendProtocolNotification(InternalResponse::createNotification("{{domain.domain}}.{{event.name}}", std::move(messageData)));
|
||||
frontend_channel_->SendProtocolNotification({{config.crdtp.namespace}}::CreateNotification("{{domain.domain}}.{{event.name}}", std::move(messageData)));
|
||||
{% else %}
|
||||
m_frontendChannel->sendProtocolNotification(InternalResponse::createNotification("{{domain.domain}}.{{event.name}}"));
|
||||
frontend_channel_->SendProtocolNotification({{config.crdtp.namespace}}::CreateNotification("{{domain.domain}}.{{event.name}}"));
|
||||
{% endif %}
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
void Frontend::flush()
|
||||
{
|
||||
m_frontendChannel->flushProtocolNotifications();
|
||||
frontend_channel_->FlushProtocolNotifications();
|
||||
}
|
||||
|
||||
void Frontend::sendRawNotification(std::unique_ptr<Serializable> notification)
|
||||
{
|
||||
m_frontendChannel->sendProtocolNotification(std::move(notification));
|
||||
frontend_channel_->SendProtocolNotification(std::move(notification));
|
||||
}
|
||||
|
||||
// --------------------- Dispatcher.
|
||||
|
||||
class DispatcherImpl : public protocol::DispatcherBase {
|
||||
class DomainDispatcherImpl : public protocol::DomainDispatcher {
|
||||
public:
|
||||
DispatcherImpl(FrontendChannel* frontendChannel, Backend* backend)
|
||||
: DispatcherBase(frontendChannel)
|
||||
, m_backend(backend) {
|
||||
{% for command in domain.commands %}
|
||||
{% if "redirect" in command %}
|
||||
m_redirects["{{domain.domain}}.{{command.name}}"] = "{{command.redirect}}.{{command.name}}";
|
||||
{% continue %}
|
||||
{% endif %}
|
||||
{% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %}
|
||||
m_dispatchMap["{{domain.domain}}.{{command.name}}"] = &DispatcherImpl::{{command.name}};
|
||||
{% endfor %}
|
||||
}
|
||||
~DispatcherImpl() override { }
|
||||
bool canDispatch(const String& method) override;
|
||||
void dispatch(int callId, const String& method, {{config.crdtp.namespace}}::span<uint8_t> message, std::unique_ptr<protocol::DictionaryValue> messageObject) override;
|
||||
std::unordered_map<String, String>& redirects() { return m_redirects; }
|
||||
DomainDispatcherImpl(FrontendChannel* frontendChannel, Backend* backend)
|
||||
: DomainDispatcher(frontendChannel)
|
||||
, m_backend(backend) {}
|
||||
~DomainDispatcherImpl() override { }
|
||||
|
||||
protected:
|
||||
using CallHandler = void (DispatcherImpl::*)(int callId, const String& method, {{config.crdtp.namespace}}::span<uint8_t> message, std::unique_ptr<DictionaryValue> messageObject, ErrorSupport* errors);
|
||||
using DispatchMap = std::unordered_map<String, CallHandler>;
|
||||
DispatchMap m_dispatchMap;
|
||||
std::unordered_map<String, String> m_redirects;
|
||||
using CallHandler = void (DomainDispatcherImpl::*)(const {{config.crdtp.namespace}}::Dispatchable& dispatchable, DictionaryValue* params, ErrorSupport* errors);
|
||||
|
||||
std::function<void(const {{config.crdtp.namespace}}::Dispatchable&)> Dispatch({{config.crdtp.namespace}}::span<uint8_t> command_name) override;
|
||||
|
||||
{% for command in domain.commands %}
|
||||
{% if "redirect" in command %}{% continue %}{% endif %}
|
||||
{% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %}
|
||||
void {{command.name}}(int callId, const String& method, {{config.crdtp.namespace}}::span<uint8_t> message, std::unique_ptr<DictionaryValue> requestMessageObject, ErrorSupport*);
|
||||
void {{command.name}}(const {{config.crdtp.namespace}}::Dispatchable& dispatchable, DictionaryValue* params, ErrorSupport* errors);
|
||||
{% endfor %}
|
||||
|
||||
protected:
|
||||
Backend* m_backend;
|
||||
};
|
||||
|
||||
bool DispatcherImpl::canDispatch(const String& method) {
|
||||
return m_dispatchMap.find(method) != m_dispatchMap.end();
|
||||
namespace {
|
||||
// This helper method with a static map of command methods (instance methods
|
||||
// of DomainDispatcherImpl declared just above) by their name is used immediately below,
|
||||
// in the DomainDispatcherImpl::Dispatch method.
|
||||
DomainDispatcherImpl::CallHandler CommandByName({{config.crdtp.namespace}}::span<uint8_t> command_name) {
|
||||
static auto* commands = [](){
|
||||
auto* commands = new std::vector<std::pair<{{config.crdtp.namespace}}::span<uint8_t>,
|
||||
DomainDispatcherImpl::CallHandler>>{
|
||||
{% for command in domain.commands|sort(attribute="name",case_sensitive=True) %}
|
||||
{% if "redirect" in command %}{% continue %}{% endif %}
|
||||
{% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %}
|
||||
{
|
||||
{{config.crdtp.namespace}}::SpanFrom("{{command.name}}"),
|
||||
&DomainDispatcherImpl::{{command.name}}
|
||||
},
|
||||
{% endfor %}
|
||||
};
|
||||
return commands;
|
||||
}();
|
||||
return {{config.crdtp.namespace}}::FindByFirst<DomainDispatcherImpl::CallHandler>(*commands, command_name, nullptr);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void DispatcherImpl::dispatch(int callId, const String& method, {{config.crdtp.namespace}}::span<uint8_t> message, std::unique_ptr<protocol::DictionaryValue> messageObject)
|
||||
{
|
||||
std::unordered_map<String, CallHandler>::iterator it = m_dispatchMap.find(method);
|
||||
DCHECK(it != m_dispatchMap.end());
|
||||
protocol::ErrorSupport errors;
|
||||
(this->*(it->second))(callId, method, message, std::move(messageObject), &errors);
|
||||
std::function<void(const {{config.crdtp.namespace}}::Dispatchable&)> DomainDispatcherImpl::Dispatch({{config.crdtp.namespace}}::span<uint8_t> command_name) {
|
||||
CallHandler handler = CommandByName(command_name);
|
||||
if (!handler) return nullptr;
|
||||
return [this, handler](const {{config.crdtp.namespace}}::Dispatchable& dispatchable){
|
||||
std::unique_ptr<DictionaryValue> params =
|
||||
DictionaryValue::cast(protocol::Value::parseBinary(dispatchable.Params().data(),
|
||||
dispatchable.Params().size()));
|
||||
ErrorSupport errors;
|
||||
errors.Push();
|
||||
(this->*handler)(dispatchable, params.get(), &errors);
|
||||
};
|
||||
}
|
||||
|
||||
{% for command in domain.commands %}
|
||||
@ -256,10 +268,11 @@ void DispatcherImpl::dispatch(int callId, const String& method, {{config.crdtp.n
|
||||
{% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %}
|
||||
{% if protocol.is_async_command(domain.domain, command.name) %}
|
||||
|
||||
class {{command_name_title}}CallbackImpl : public Backend::{{command_name_title}}Callback, public DispatcherBase::Callback {
|
||||
class {{command_name_title}}CallbackImpl : public Backend::{{command_name_title}}Callback, public DomainDispatcher::Callback {
|
||||
public:
|
||||
{{command_name_title}}CallbackImpl(std::unique_ptr<DispatcherBase::WeakPtr> backendImpl, int callId, const String& method, {{config.crdtp.namespace}}::span<uint8_t> message)
|
||||
: DispatcherBase::Callback(std::move(backendImpl), callId, method, message) { }
|
||||
{{command_name_title}}CallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, int callId, {{config.crdtp.namespace}}::span<uint8_t> message)
|
||||
: DomainDispatcher::Callback(std::move(backendImpl), callId,
|
||||
{{config.crdtp.namespace}}::SpanFrom("{{domain.domain}}.{{command.name}}"), message) { }
|
||||
|
||||
void sendSuccess(
|
||||
{%- for parameter in command.returns -%}
|
||||
@ -271,16 +284,16 @@ public:
|
||||
{%- if not loop.last -%}, {% endif -%}
|
||||
{%- endfor -%}) override
|
||||
{
|
||||
std::unique_ptr<protocol::DictionaryValue> resultObject = DictionaryValue::create();
|
||||
{% for parameter in command.returns %}
|
||||
{% if "optional" in parameter %}
|
||||
if ({{parameter.name}}.isJust())
|
||||
resultObject->setValue("{{parameter.name}}", ValueConversions<{{protocol.resolve_type(parameter).raw_type}}>::toValue({{parameter.name}}.fromJust()));
|
||||
{% else %}
|
||||
resultObject->setValue("{{parameter.name}}", ValueConversions<{{protocol.resolve_type(parameter).raw_type}}>::toValue({{protocol.resolve_type(parameter).to_raw_type % parameter.name}}));
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
sendIfActive(std::move(resultObject), DispatchResponse::OK());
|
||||
std::vector<uint8_t> result_buffer;
|
||||
{{config.crdtp.namespace}}::cbor::EnvelopeEncoder envelope_encoder;
|
||||
envelope_encoder.EncodeStart(&result_buffer);
|
||||
result_buffer.push_back({{config.crdtp.namespace}}::cbor::EncodeIndefiniteLengthMapStart());
|
||||
{% for parameter in command.returns %}
|
||||
{{config.crdtp.namespace}}::SerializeField({{config.crdtp.namespace}}::SpanFrom("{{parameter.name}}"), {{parameter.name}}, &result_buffer);
|
||||
{% endfor %}
|
||||
result_buffer.push_back({{config.crdtp.namespace}}::cbor::EncodeStop());
|
||||
envelope_encoder.EncodeStop(&result_buffer);
|
||||
sendIfActive({{config.crdtp.namespace}}::Serializable::From(std::move(result_buffer)), DispatchResponse::Success());
|
||||
}
|
||||
|
||||
void fallThrough() override
|
||||
@ -290,21 +303,19 @@ public:
|
||||
|
||||
void sendFailure(const DispatchResponse& response) override
|
||||
{
|
||||
DCHECK(response.status() == DispatchResponse::kError);
|
||||
DCHECK(response.IsError());
|
||||
sendIfActive(nullptr, response);
|
||||
}
|
||||
};
|
||||
{% endif %}
|
||||
|
||||
void DispatcherImpl::{{command.name}}(int callId, const String& method, {{config.crdtp.namespace}}::span<uint8_t> message, std::unique_ptr<DictionaryValue> requestMessageObject, ErrorSupport* errors)
|
||||
void DomainDispatcherImpl::{{command.name}}(const {{config.crdtp.namespace}}::Dispatchable& dispatchable, DictionaryValue* params, ErrorSupport* errors)
|
||||
{
|
||||
{% if "parameters" in command %}
|
||||
// Prepare input parameters.
|
||||
protocol::DictionaryValue* object = DictionaryValue::cast(requestMessageObject->get("params"));
|
||||
errors->Push();
|
||||
{% for parameter in command.parameters %}
|
||||
{% set parameter_type = protocol.resolve_type(parameter) %}
|
||||
protocol::Value* {{parameter.name}}Value = object ? object->get("{{parameter.name}}") : nullptr;
|
||||
protocol::Value* {{parameter.name}}Value = params ? params->get("{{parameter.name}}") : nullptr;
|
||||
{% if parameter.optional %}
|
||||
Maybe<{{parameter_type.raw_type}}> in_{{parameter.name}};
|
||||
if ({{parameter.name}}Value) {
|
||||
@ -316,11 +327,7 @@ void DispatcherImpl::{{command.name}}(int callId, const String& method, {{config
|
||||
{{parameter_type.type}} in_{{parameter.name}} = ValueConversions<{{parameter_type.raw_type}}>::fromValue({{parameter.name}}Value, errors);
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
errors->Pop();
|
||||
if (!errors->Errors().empty()) {
|
||||
reportProtocolError(callId, DispatchResponse::kInvalidParams, kInvalidParamsString, errors);
|
||||
return;
|
||||
}
|
||||
if (MaybeReportInvalidParams(dispatchable, *errors)) return;
|
||||
{% endif %}
|
||||
{% if "returns" in command and not protocol.is_async_command(domain.domain, command.name) %}
|
||||
// Declare output parameters.
|
||||
@ -334,7 +341,7 @@ void DispatcherImpl::{{command.name}}(int callId, const String& method, {{config
|
||||
{% endif %}
|
||||
|
||||
{% if not protocol.is_async_command(domain.domain, command.name) %}
|
||||
std::unique_ptr<DispatcherBase::WeakPtr> weak = weakPtr();
|
||||
std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
|
||||
DispatchResponse response = m_backend->{{command.name | to_method_case}}(
|
||||
{%- for parameter in command.parameters -%}
|
||||
{%- if not loop.first -%}, {% endif -%}
|
||||
@ -350,31 +357,31 @@ void DispatcherImpl::{{command.name}}(int callId, const String& method, {{config
|
||||
&out_{{parameter.name}}
|
||||
{%- endfor %}
|
||||
{% endif %});
|
||||
if (response.status() == DispatchResponse::kFallThrough) {
|
||||
channel()->fallThrough(callId, method, message);
|
||||
if (response.IsFallThrough()) {
|
||||
channel()->FallThrough(dispatchable.CallId(), {{config.crdtp.namespace}}::SpanFrom("{{domain.domain}}.{{command.name}}"), dispatchable.Serialized());
|
||||
return;
|
||||
}
|
||||
{% if "returns" in command %}
|
||||
std::unique_ptr<protocol::DictionaryValue> result = DictionaryValue::create();
|
||||
if (response.status() == DispatchResponse::kSuccess) {
|
||||
{% for parameter in command.returns %}
|
||||
{% if "optional" in parameter %}
|
||||
if (out_{{parameter.name}}.isJust())
|
||||
result->setValue("{{parameter.name}}", ValueConversions<{{protocol.resolve_type(parameter).raw_type}}>::toValue(out_{{parameter.name}}.fromJust()));
|
||||
{% else %}
|
||||
result->setValue("{{parameter.name}}", ValueConversions<{{protocol.resolve_type(parameter).raw_type}}>::toValue({{protocol.resolve_type(parameter).to_raw_type % ("out_" + parameter.name)}}));
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
if (weak->get())
|
||||
weak->get()->sendResponse(callId, response, std::move(result));
|
||||
if (weak->get()) {
|
||||
std::vector<uint8_t> result;
|
||||
if (response.IsSuccess()) {
|
||||
{{config.crdtp.namespace}}::cbor::EnvelopeEncoder envelope_encoder;
|
||||
envelope_encoder.EncodeStart(&result);
|
||||
result.push_back({{config.crdtp.namespace}}::cbor::EncodeIndefiniteLengthMapStart());
|
||||
{% for parameter in command.returns %}
|
||||
{{config.crdtp.namespace}}::SerializeField({{config.crdtp.namespace}}::SpanFrom("{{parameter.name}}"), out_{{parameter.name}}, &result);
|
||||
{% endfor %}
|
||||
result.push_back({{config.crdtp.namespace}}::cbor::EncodeStop());
|
||||
envelope_encoder.EncodeStop(&result);
|
||||
}
|
||||
weak->get()->sendResponse(dispatchable.CallId(), response, {{config.crdtp.namespace}}::Serializable::From(std::move(result)));
|
||||
}
|
||||
{% else %}
|
||||
if (weak->get())
|
||||
weak->get()->sendResponse(callId, response);
|
||||
weak->get()->sendResponse(dispatchable.CallId(), response);
|
||||
{% endif %}
|
||||
return;
|
||||
{% else %}
|
||||
std::unique_ptr<{{command_name_title}}CallbackImpl> callback(new {{command.name | to_title_case}}CallbackImpl(weakPtr(), callId, method, message));
|
||||
m_backend->{{command.name | to_method_case}}(
|
||||
{%- for property in command.parameters -%}
|
||||
{%- if not loop.first -%}, {% endif -%}
|
||||
@ -385,18 +392,34 @@ void DispatcherImpl::{{command.name}}(int callId, const String& method, {{config
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- if command.parameters -%}, {% endif -%}
|
||||
std::move(callback));
|
||||
return;
|
||||
std::make_unique<{{command_name_title}}CallbackImpl>(weakPtr(), dispatchable.CallId(), dispatchable.Serialized()));
|
||||
{% endif %}
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
namespace {
|
||||
// This helper method (with a static map of redirects) is used from Dispatcher::wire
|
||||
// immediately below.
|
||||
const std::vector<std::pair<{{config.crdtp.namespace}}::span<uint8_t>, {{config.crdtp.namespace}}::span<uint8_t>>>& SortedRedirects() {
|
||||
static auto* redirects = [](){
|
||||
auto* redirects = new std::vector<std::pair<{{config.crdtp.namespace}}::span<uint8_t>, {{config.crdtp.namespace}}::span<uint8_t>>>{
|
||||
{% for command in domain.commands|sort(attribute="name",case_sensitive=True) %}
|
||||
{% if "redirect" in command %}
|
||||
{ {{config.crdtp.namespace}}::SpanFrom("{{domain.domain}}.{{command.name}}"), {{config.crdtp.namespace}}::SpanFrom("{{command.redirect}}.{{command.name}}") },
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
};
|
||||
return redirects;
|
||||
}();
|
||||
return *redirects;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
void Dispatcher::wire(UberDispatcher* uber, Backend* backend)
|
||||
{
|
||||
std::unique_ptr<DispatcherImpl> dispatcher(new DispatcherImpl(uber->channel(), backend));
|
||||
uber->setupRedirects(dispatcher->redirects());
|
||||
uber->registerBackend("{{domain.domain}}", std::move(dispatcher));
|
||||
auto dispatcher = std::make_unique<DomainDispatcherImpl>(uber->channel(), backend);
|
||||
uber->WireBackend({{config.crdtp.namespace}}::SpanFrom("{{domain.domain}}"), SortedRedirects(), std::move(dispatcher));
|
||||
}
|
||||
|
||||
} // {{domain.domain}}
|
||||
|
@ -239,7 +239,7 @@ public:
|
||||
{% if protocol.generate_disable(domain) %}
|
||||
virtual DispatchResponse {{"disable" | to_method_case}}()
|
||||
{
|
||||
return DispatchResponse::OK();
|
||||
return DispatchResponse::Success();
|
||||
}
|
||||
{% endif %}
|
||||
};
|
||||
@ -248,7 +248,7 @@ public:
|
||||
|
||||
class {{config.protocol.export_macro}} Frontend {
|
||||
public:
|
||||
explicit Frontend(FrontendChannel* frontendChannel) : m_frontendChannel(frontendChannel) { }
|
||||
explicit Frontend(FrontendChannel* frontend_channel) : frontend_channel_(frontend_channel) {}
|
||||
{% for event in domain.events %}
|
||||
{% if not protocol.generate_event(domain.domain, event.name) %}{% continue %}{% endif %}
|
||||
void {{event.name | to_method_case}}(
|
||||
@ -262,10 +262,10 @@ public:
|
||||
);
|
||||
{% endfor %}
|
||||
|
||||
void flush();
|
||||
void sendRawNotification(std::unique_ptr<Serializable>);
|
||||
private:
|
||||
FrontendChannel* m_frontendChannel;
|
||||
void flush();
|
||||
void sendRawNotification(std::unique_ptr<Serializable>);
|
||||
private:
|
||||
FrontendChannel* frontend_channel_;
|
||||
};
|
||||
|
||||
// ------------- Dispatcher.
|
||||
|
Loading…
Reference in New Issue
Block a user