Commit 6b0d1e43 authored by Stephane Zermatten's avatar Stephane Zermatten Committed by Commit Bot

Forward error information from devtools to the server.

This change is meant to provide extra information to debug
UNEXPECTED_JS_ERROR and UNEXPECTED_ERROR we get from time to time in
production.

Bug: b/139791239
Change-Id: I74b4d284a70e9a4082ce64b493f1fdd6c0a7488a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1771910
Commit-Queue: Stephane Zermatten <szermatt@chromium.org>
Reviewed-by: default avatarMathias Carlen <mcarlen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#693063}
parent 16e76d33
......@@ -46,7 +46,9 @@ void Domain::RegisterEventHandlersIfNeeded() {
{% for command in domain.commands %}
{% set class_name = 'ExperimentalDomain' if command.experimental else 'Domain' %}
{% set method_name = command.name | sanitize_literal | to_title_case %}
void {{class_name}}::{{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback) {
void {{class_name}}::{{method_name}}(
std::unique_ptr<{{method_name}}Params> params,
base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)> callback) {
dispatcher_->SendMessage("{{domain.domain}}.{{command.name}}", params->Serialize(), base::BindOnce(&Domain::Handle{{method_name}}Response, std::move(callback)));
}
{# Generate convenience methods that take the required parameters directly. #}
......@@ -64,7 +66,7 @@ void {{class_name}}::{{method_name}}({##}
{% endfor %}
{% if command.get("parameters", []) and not command.parameters[0].get("optional", False) %}, {% endif %}{# -#}
{% if command.get("returns", []) -%}
base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback{##}
base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)> callback{##}
{% else -%}
base::OnceClosure callback{##}
{% endif %}) {
......@@ -99,18 +101,22 @@ void {{class_name}}::{{method_name}}(std::unique_ptr<{{method_name}}Params> para
{% set method_name = command.name | sanitize_literal | to_title_case %}
// static
void Domain::Handle{{method_name}}Response(base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback, const base::Value& response) {
void Domain::Handle{{method_name}}Response(
base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)> callback,
const MessageDispatcher::ReplyStatus& reply_status,
const base::Value& response) {
if (callback.is_null())
return;
// This is an error response.
if (response.is_none()) {
std::move(callback).Run(nullptr);
std::move(callback).Run(reply_status, nullptr);
return;
}
ErrorReporter errors;
std::unique_ptr<{{method_name}}Result> result = {{method_name}}Result::Parse(response, &errors);
DCHECK(!errors.HasErrors()) << errors.ToString();
std::move(callback).Run(std::move(result));
std::move(callback).Run(reply_status, std::move(result));
}
{% endfor %}
{% if "events" in domain %}
......
......@@ -23,7 +23,7 @@
{% if command.description %}
// {{ command.description.replace('\n', '\n // ') }}
{% endif %}
void {{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback = base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)>());
void {{method_name}}(std::unique_ptr<{{method_name}}Params> params, base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)> callback = base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)>());
{# Generate convenience methods that take the required parameters directly. #}
{# Don't generate these for experimental commands. #}
{% if "parameters" in command and not command.experimental %}
......@@ -37,7 +37,7 @@
{% endfor %}
{% if command.get("parameters", []) and not command.parameters[0].get("optional", False) %}, {% endif %}{# -#}
{% if command.get("returns", []) -%}
base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback = base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)>(){##}
base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)> callback = base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)>(){##}
{% else -%}
base::OnceClosure callback = base::OnceClosure(){##}
{% endif %});
......@@ -108,7 +108,10 @@ class Domain {
{% for command in domain.commands %}
{% if not "returns" in command %}{% continue %}{% endif %}
{% set method_name = command.name | sanitize_literal | to_title_case %}
static void Handle{{method_name}}Response(base::OnceCallback<void(std::unique_ptr<{{method_name}}Result>)> callback, const base::Value& response);
static void Handle{{method_name}}Response(
base::OnceCallback<void(const MessageDispatcher::ReplyStatus&, std::unique_ptr<{{method_name}}Result>)> callback,
const MessageDispatcher::ReplyStatus& reply_status,
const base::Value& response);
{% endfor %}
{# Generate event dispatchers. #}
......
......@@ -56,7 +56,7 @@ network::Domain* DevtoolsClient::GetNetwork() {
void DevtoolsClient::SendMessage(
const char* method,
std::unique_ptr<base::Value> params,
base::OnceCallback<void(const base::Value&)> callback) {
base::OnceCallback<void(const ReplyStatus&, const base::Value&)> callback) {
SendMessageWithParams(method, std::move(params), std::move(callback));
}
......@@ -132,6 +132,7 @@ bool DevtoolsClient::DispatchMessageReply(
pending_messages_.erase(it);
if (!callback.callback_with_result.is_null()) {
const base::DictionaryValue* result_dict;
ReplyStatus status;
if (message_dict.GetDictionary("result", &result_dict)) {
if (browser_main_thread_) {
browser_main_thread_->PostTask(
......@@ -139,22 +140,24 @@ bool DevtoolsClient::DispatchMessageReply(
base::BindOnce(
&DevtoolsClient::DispatchMessageReplyWithResultTask,
weak_ptr_factory_.GetWeakPtr(), std::move(owning_message),
std::move(callback.callback_with_result), result_dict));
std::move(callback.callback_with_result), status, result_dict));
} else {
std::move(callback.callback_with_result).Run(*result_dict);
std::move(callback.callback_with_result).Run(status, *result_dict);
}
} else if (message_dict.GetDictionary("error", &result_dict)) {
auto null_value = std::make_unique<base::Value>();
DLOG(ERROR) << "Error in method call result: " << *result_dict;
FillReplyStatusFromErrorDict(&status, *result_dict);
if (browser_main_thread_) {
browser_main_thread_->PostTask(
FROM_HERE,
base::BindOnce(
&DevtoolsClient::DispatchMessageReplyWithResultTask,
weak_ptr_factory_.GetWeakPtr(), std::move(null_value),
std::move(callback.callback_with_result), null_value.get()));
base::BindOnce(&DevtoolsClient::DispatchMessageReplyWithResultTask,
weak_ptr_factory_.GetWeakPtr(),
std::move(null_value),
std::move(callback.callback_with_result), status,
null_value.get()));
} else {
std::move(callback.callback_with_result).Run(*null_value);
std::move(callback.callback_with_result).Run(status, *null_value);
}
} else {
NOTREACHED() << "Reply has neither result nor error";
......@@ -180,9 +183,10 @@ bool DevtoolsClient::DispatchMessageReply(
void DevtoolsClient::DispatchMessageReplyWithResultTask(
std::unique_ptr<base::Value> owning_message,
base::OnceCallback<void(const base::Value&)> callback,
base::OnceCallback<void(const ReplyStatus&, const base::Value&)> callback,
const ReplyStatus& reply_status,
const base::Value* result_dict) {
std::move(callback).Run(*result_dict);
std::move(callback).Run(reply_status, *result_dict);
}
bool DevtoolsClient::DispatchEvent(std::unique_ptr<base::Value> owning_message,
......@@ -227,6 +231,24 @@ void DevtoolsClient::DispatchEventTask(
event_handler->Run(*result_dict);
}
void DevtoolsClient::FillReplyStatusFromErrorDict(
ReplyStatus* status,
const base::DictionaryValue& error_dict) {
const base::Value* code;
if (error_dict.Get("code", &code) && code->is_int()) {
status->error_code = code->GetInt();
} else {
status->error_code = -1; // unknown error code
}
const base::Value* message;
if (error_dict.Get("message", &message) && message->is_string()) {
status->error_message = message->GetString();
} else {
status->error_message = "unknown";
}
}
void DevtoolsClient::AgentHostClosed(content::DevToolsAgentHost* agent_host) {
// Agent host is not expected to be closed when this object is alive.
renderer_crashed_ = true;
......@@ -240,7 +262,7 @@ DevtoolsClient::Callback::Callback(base::OnceClosure callback)
: callback(std::move(callback)) {}
DevtoolsClient::Callback::Callback(
base::OnceCallback<void(const base::Value&)> callback)
base::OnceCallback<void(const ReplyStatus&, const base::Value&)> callback)
: callback_with_result(std::move(callback)) {}
DevtoolsClient::Callback::~Callback() = default;
......
......@@ -44,7 +44,8 @@ class DevtoolsClient : public MessageDispatcher,
void SendMessage(
const char* method,
std::unique_ptr<base::Value> params,
base::OnceCallback<void(const base::Value&)> callback) override;
base::OnceCallback<void(const ReplyStatus&, const base::Value&)> callback)
override;
void SendMessage(const char* method,
std::unique_ptr<base::Value> params,
base::OnceClosure callback) override;
......@@ -64,13 +65,15 @@ class DevtoolsClient : public MessageDispatcher,
Callback();
Callback(Callback&& other);
explicit Callback(base::OnceClosure callback);
explicit Callback(base::OnceCallback<void(const base::Value&)> callback);
explicit Callback(base::OnceCallback<void(const ReplyStatus&,
const base::Value&)> callback);
~Callback();
Callback& operator=(Callback&& other);
base::OnceClosure callback;
base::OnceCallback<void(const base::Value&)> callback_with_result;
base::OnceCallback<void(const ReplyStatus&, const base::Value&)>
callback_with_result;
};
template <typename CallbackType>
......@@ -81,7 +84,8 @@ class DevtoolsClient : public MessageDispatcher,
const base::DictionaryValue& message_dict);
void DispatchMessageReplyWithResultTask(
std::unique_ptr<base::Value> owning_message,
base::OnceCallback<void(const base::Value&)> callback,
base::OnceCallback<void(const ReplyStatus&, const base::Value&)> callback,
const ReplyStatus& reply_status,
const base::Value* result_dict);
bool DispatchEvent(std::unique_ptr<base::Value> owning_message,
const base::DictionaryValue& message_dict);
......@@ -91,6 +95,8 @@ class DevtoolsClient : public MessageDispatcher,
void DispatchEventTask(std::unique_ptr<base::Value> owning_message,
const EventHandler* event_handler,
const base::DictionaryValue* result_dict);
void FillReplyStatusFromErrorDict(ReplyStatus* status,
const base::DictionaryValue& error_dict);
scoped_refptr<content::DevToolsAgentHost> agent_host_;
scoped_refptr<base::SequencedTaskRunner> browser_main_thread_;
......
......@@ -22,10 +22,24 @@ namespace autofill_assistant {
// An internal interface for sending DevTools messages from the domain agents.
class MessageDispatcher {
public:
// Status of a SendMessage operation.
struct ReplyStatus {
// Error codes, as a number, -1 if error code is unknown.
//
// Possible values are listed on:
// src/third_party/inspector_protocol/lib/DispatcherBase_h.template
long error_code = 0;
std::string error_message;
bool is_ok() const { return error_code == 0; }
};
virtual void SendMessage(
const char* method,
std::unique_ptr<base::Value> params,
base::OnceCallback<void(const base::Value&)> callback) = 0;
base::OnceCallback<void(const ReplyStatus&, const base::Value&)>
callback) = 0;
virtual void SendMessage(const char* method,
std::unique_ptr<base::Value> params,
base::OnceClosure callback) = 0;
......
......@@ -565,6 +565,12 @@ message UnexpectedErrorInfoProto {
// JavaScript exception column number, within the js snippet that was sent to
// devtools runtime by the client, if reporting a JavaScript error.
optional int32 js_exception_column_number = 5;
// Error code returned by devtools, if any. 0 is considered a success.
optional int32 devtools_error_code = 6;
// Error message returned by devtools, if any.
optional string devtools_error_message = 7;
}
// Message to report autofill related errors for debugging purposes.
......
......@@ -148,8 +148,10 @@ void ElementFinder::SendResult(const ClientStatus& status) {
}
void ElementFinder::OnGetDocumentElement(
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::EvaluateResult> result) {
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
DVLOG(1) << __func__ << " Failed to get document root element.";
SendResult(status);
......@@ -218,6 +220,7 @@ void ElementFinder::RecursiveFindElement(const std::string& object_id,
void ElementFinder::OnQuerySelectorAll(
size_t index,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
if (!result) {
// It is possible for a document element to already exist, but not be
......@@ -229,7 +232,8 @@ void ElementFinder::OnQuerySelectorAll(
SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
return;
}
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
DVLOG(1) << __func__ << ": Failed to query selector " << index << " of "
<< selector_;
......@@ -282,10 +286,11 @@ void ElementFinder::OnQuerySelectorAll(
void ElementFinder::OnDescribeNodeForPseudoElement(
dom::PseudoType pseudo_type,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::DescribeNodeResult> result) {
if (!result || !result->GetNode()) {
DVLOG(1) << __func__ << " Failed to describe the node for pseudo element.";
SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
SendResult(UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
return;
}
......@@ -310,6 +315,7 @@ void ElementFinder::OnDescribeNodeForPseudoElement(
}
void ElementFinder::OnResolveNodeForPseudoElement(
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::ResolveNodeResult> result) {
if (result && result->GetObject() && result->GetObject()->HasObjectId()) {
element_result_->object_id = result->GetObject()->GetObjectId();
......@@ -320,10 +326,11 @@ void ElementFinder::OnResolveNodeForPseudoElement(
void ElementFinder::OnDescribeNode(
const std::string& object_id,
size_t index,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::DescribeNodeResult> result) {
if (!result || !result->GetNode()) {
DVLOG(1) << __func__ << " Failed to describe the node.";
SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
SendResult(UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
return;
}
......@@ -354,7 +361,8 @@ void ElementFinder::OnDescribeNode(
frame_name, node->GetContentDocument()->GetDocumentURL());
if (!element_result_->container_frame_host) {
DVLOG(1) << __func__ << " Failed to find corresponding owner frame.";
SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
SendResult(
UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
return;
}
} else if (node->HasFrameId()) {
......@@ -385,10 +393,11 @@ void ElementFinder::OnDescribeNode(
void ElementFinder::OnResolveNode(
size_t index,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::ResolveNodeResult> result) {
if (!result || !result->GetObject() || !result->GetObject()->HasObjectId()) {
DVLOG(1) << __func__ << " Failed to resolve object id from backend id.";
SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
SendResult(UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
return;
}
......@@ -410,4 +419,4 @@ content::RenderFrameHost* ElementFinder::FindCorrespondingRenderFrameHost(
return ret_frame;
}
} // namespace autofill_assistant
\ No newline at end of file
} // namespace autofill_assistant
......@@ -14,6 +14,7 @@
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
#include "components/autofill_assistant/browser/devtools/devtools_client.h"
#include "components/autofill_assistant/browser/selector.h"
#include "components/autofill_assistant/browser/web/web_controller_worker.h"
......@@ -61,20 +62,26 @@ class ElementFinder : public WebControllerWorker {
private:
void SendResult(const ClientStatus& status);
void OnGetDocumentElement(std::unique_ptr<runtime::EvaluateResult> result);
void OnGetDocumentElement(const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::EvaluateResult> result);
void RecursiveFindElement(const std::string& object_id, size_t index);
void OnQuerySelectorAll(
size_t index,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnDescribeNodeForPseudoElement(
dom::PseudoType pseudo_type,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::DescribeNodeResult> result);
void OnResolveNodeForPseudoElement(
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::ResolveNodeResult> result);
void OnDescribeNode(const std::string& object_id,
size_t index,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::DescribeNodeResult> result);
void OnResolveNode(size_t index,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::ResolveNodeResult> result);
content::RenderFrameHost* FindCorrespondingRenderFrameHost(
std::string name,
......
......@@ -69,6 +69,7 @@ void ElementPositionGetter::GetAndWaitBoxModelStable() {
}
void ElementPositionGetter::OnGetBoxModelForStableCheck(
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::GetBoxModelResult> result) {
if (!result || !result->GetModel() || !result->GetModel()->GetContent()) {
DVLOG(1) << __func__ << " Failed to get box model.";
......@@ -137,8 +138,10 @@ void ElementPositionGetter::OnGetBoxModelForStableCheck(
}
void ElementPositionGetter::OnScrollIntoView(
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
DVLOG(1) << __func__ << " Failed to scroll the element: " << status;
OnError();
......@@ -165,4 +168,4 @@ void ElementPositionGetter::OnError() {
}
}
} // namespace autofill_assistant
\ No newline at end of file
} // namespace autofill_assistant
......@@ -14,6 +14,7 @@
#include "components/autofill_assistant/browser/client_settings.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
#include "components/autofill_assistant/browser/devtools/devtools_client.h"
#include "components/autofill_assistant/browser/selector.h"
#include "components/autofill_assistant/browser/web/web_controller_worker.h"
......@@ -22,7 +23,6 @@ class RenderFrameHost;
} // namespace content
namespace autofill_assistant {
class DevtoolsClient;
// Worker class to get an element's position in viewport coordinates when it is
// stable and the frame it belongs to has finished its visual update.
......@@ -49,8 +49,10 @@ class ElementPositionGetter : public WebControllerWorker {
void OnVisualStateUpdatedCallback(bool success);
void GetAndWaitBoxModelStable();
void OnGetBoxModelForStableCheck(
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<dom::GetBoxModelResult> result);
void OnScrollIntoView(std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnScrollIntoView(const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnResult(int x, int y);
void OnError();
......@@ -78,4 +80,4 @@ class ElementPositionGetter : public WebControllerWorker {
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_POSITION_GETTER_H_
\ No newline at end of file
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_POSITION_GETTER_H_
......@@ -229,8 +229,10 @@ void AppendWaitForDocumentReadyStateFunction(std::string* out) {
template <typename T>
void OnWaitForDocumentReadyState(
base::OnceCallback<void(const ClientStatus&, DocumentReadyState)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<T> result) {
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
DVLOG_IF(1, !status.ok())
<< __func__ << " Failed to get document ready state.";
int ready_state;
......@@ -340,8 +342,10 @@ void WebController::OnScrollIntoView(
std::unique_ptr<ElementFinder::Result> target_element,
base::OnceCallback<void(const ClientStatus&)> callback,
ClickAction::ClickType click_type,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
DVLOG(1) << __func__ << " Failed to scroll the element.";
std::move(callback).Run(status);
......@@ -378,8 +382,10 @@ void WebController::OnScrollIntoView(
void WebController::OnClickJS(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
DVLOG(1) << __func__ << " Failed to click (javascript) the element.";
}
......@@ -436,11 +442,13 @@ void WebController::OnDispatchPressMouseEvent(
base::OnceCallback<void(const ClientStatus&)> callback,
int x,
int y,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<input::DispatchMouseEventResult> result) {
if (!result) {
DVLOG(1) << __func__
<< " Failed to dispatch mouse left button pressed event.";
std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__));
std::move(callback).Run(
UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
return;
}
......@@ -458,16 +466,25 @@ void WebController::OnDispatchPressMouseEvent(
void WebController::OnDispatchReleaseMouseEvent(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<input::DispatchMouseEventResult> result) {
if (!result) {
DVLOG(1) << __func__ << " Failed to dispatch release mouse event.";
std::move(callback).Run(
UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
return;
}
std::move(callback).Run(OkClientStatus());
}
void WebController::OnDispatchTouchEventStart(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<input::DispatchTouchEventResult> result) {
if (!result) {
DVLOG(1) << __func__ << " Failed to dispatch touch start event.";
std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__));
std::move(callback).Run(
UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
return;
}
......@@ -484,8 +501,14 @@ void WebController::OnDispatchTouchEventStart(
void WebController::OnDispatchTouchEventEnd(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<input::DispatchTouchEventResult> result) {
DCHECK(result);
if (!result) {
DVLOG(1) << __func__ << " Failed to dispatch touch end event.";
std::move(callback).Run(
UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
return;
}
std::move(callback).Run(OkClientStatus());
}
......@@ -522,9 +545,10 @@ void WebController::WaitForWindowHeightChange(
void WebController::OnWaitForWindowHeightChange(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::EvaluateResult> result) {
std::move(callback).Run(
CheckJavaScriptResult(result.get(), __FILE__, __LINE__));
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__));
}
void WebController::GetDocumentReadyState(
......@@ -672,8 +696,10 @@ void WebController::OnWaitDocumentToBecomeInteractiveForFocusElement(
void WebController::OnFocusElement(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
DVLOG_IF(1, !status.ok()) << __func__ << " Failed to focus on element.";
std::move(callback).Run(status);
}
......@@ -728,8 +754,7 @@ void WebController::OnGetFormAndFieldDataForFillingForm(
const autofill::FormFieldData& form_field) {
if (form_data.fields.empty()) {
DVLOG(1) << __func__ << " Failed to get form data to fill form.";
std::move(callback).Run(
UnexpectedErrorStatus(__FILE__, __LINE__)); // unexpected
std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__));
return;
}
......@@ -737,8 +762,7 @@ void WebController::OnGetFormAndFieldDataForFillingForm(
ContentAutofillDriver::GetForRenderFrameHost(container_frame_host);
if (!driver) {
DVLOG(1) << __func__ << " Failed to get the autofill driver.";
std::move(callback).Run(
UnexpectedErrorStatus(__FILE__, __LINE__)); // unexpected
std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__));
return;
}
......@@ -812,8 +836,10 @@ void WebController::OnFindElementForSelectOption(
void WebController::OnSelectOption(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
DVLOG(1) << __func__ << " Failed to select option.";
std::move(callback).Run(status);
......@@ -821,7 +847,8 @@ void WebController::OnSelectOption(
}
bool found;
if (!SafeGetBool(result->GetResult(), &found)) {
std::move(callback).Run(UnexpectedErrorStatus(__FILE__, __LINE__));
std::move(callback).Run(
UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
return;
}
if (!found) {
......@@ -870,8 +897,10 @@ void WebController::OnFindElementForHighlightElement(
void WebController::OnHighlightElement(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
DVLOG_IF(1, !status.ok()) << __func__ << " Failed to highlight element.";
std::move(callback).Run(status);
}
......@@ -921,9 +950,11 @@ void WebController::OnFindElementForGetFieldValue(
void WebController::OnGetValueAttribute(
base::OnceCallback<void(bool, const std::string&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
std::string value;
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
// Read the result returned from Javascript code.
DVLOG_IF(1, !status.ok())
<< __func__ << "Failed to get attribute value: " << status;
......@@ -1090,9 +1121,10 @@ void WebController::OnFindElementForSetFieldValue(
void WebController::OnSetValueAttribute(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
std::move(callback).Run(
CheckJavaScriptResult(result.get(), __FILE__, __LINE__));
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__));
}
void WebController::SetAttribute(
......@@ -1149,9 +1181,10 @@ void WebController::OnFindElementForSetAttribute(
void WebController::OnSetAttribute(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
std::move(callback).Run(
CheckJavaScriptResult(result.get(), __FILE__, __LINE__));
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__));
}
void WebController::SendKeyboardInput(
......@@ -1219,8 +1252,10 @@ void WebController::GetVisualViewport(
void WebController::OnGetVisualViewport(
base::OnceCallback<void(bool, const RectF&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::EvaluateResult> result) {
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok() || !result->GetResult()->HasValue() ||
!result->GetResult()->GetValue()->is_list() ||
result->GetResult()->GetValue()->GetList().size() != 4u) {
......@@ -1282,8 +1317,10 @@ void WebController::OnFindElementForPosition(
void WebController::OnGetElementPositionResult(
base::OnceCallback<void(bool, const RectF&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok() || !result->GetResult()->HasValue() ||
!result->GetResult()->GetValue()->is_list() ||
result->GetResult()->GetValue()->GetList().size() != 4u) {
......@@ -1327,8 +1364,10 @@ void WebController::OnFindElementForGetOuterHtml(
void WebController::OnGetOuterHtml(
base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
DVLOG(2) << __func__ << " Failed to get HTML content for GetOuterHtml";
std::move(callback).Run(status, "");
......@@ -1358,8 +1397,10 @@ void WebController::OnWaitForDocumentToBecomeInteractive(
int remaining_rounds,
std::string object_id,
base::OnceCallback<void(bool)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
ClientStatus status =
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok() || remaining_rounds <= 0) {
DVLOG(1) << __func__
<< " Failed to wait for the document to become interactive with "
......
......@@ -237,10 +237,12 @@ class WebController {
ClickAction::ClickType click_type,
base::OnceCallback<void(const ClientStatus&)> callback);
void OnClickJS(base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnScrollIntoView(std::unique_ptr<ElementFinder::Result> target_element,
base::OnceCallback<void(const ClientStatus&)> callback,
ClickAction::ClickType click_type,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void TapOrClickOnCoordinates(
ElementPositionGetter* getter_to_release,
......@@ -253,21 +255,26 @@ class WebController {
base::OnceCallback<void(const ClientStatus&)> callback,
int x,
int y,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<input::DispatchMouseEventResult> result);
void OnDispatchReleaseMouseEvent(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<input::DispatchMouseEventResult> result);
void OnDispatchTouchEventStart(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<input::DispatchTouchEventResult> result);
void OnDispatchTouchEventEnd(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<input::DispatchTouchEventResult> result);
void OnFindElementForCheck(base::OnceCallback<void(bool)> callback,
const ClientStatus& status,
std::unique_ptr<ElementFinder::Result> result);
void OnWaitForWindowHeightChange(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::EvaluateResult> result);
// Find the element given by |selector|. If multiple elements match
......@@ -303,6 +310,7 @@ class WebController {
std::unique_ptr<ElementFinder::Result> target_element,
bool result);
void OnFocusElement(base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForSelectOption(
const std::string& selected_option,
......@@ -310,6 +318,7 @@ class WebController {
const ClientStatus& status,
std::unique_ptr<ElementFinder::Result> element_result);
void OnSelectOption(base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForHighlightElement(
base::OnceCallback<void(const ClientStatus&)> callback,
......@@ -317,6 +326,7 @@ class WebController {
std::unique_ptr<ElementFinder::Result> element_result);
void OnHighlightElement(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForGetFieldValue(
base::OnceCallback<void(bool, const std::string&)> callback,
......@@ -324,6 +334,7 @@ class WebController {
std::unique_ptr<ElementFinder::Result> element_result);
void OnGetValueAttribute(
base::OnceCallback<void(bool, const std::string&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void InternalSetFieldValue(
const Selector& selector,
......@@ -358,6 +369,7 @@ class WebController {
const ClientStatus& status,
std::unique_ptr<ElementFinder::Result> element_result);
void OnSetAttribute(base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForSendKeyboardInput(
const Selector& selector,
......@@ -373,6 +385,7 @@ class WebController {
std::unique_ptr<ElementFinder::Result> element_result);
void OnSetValueAttribute(
base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForGetOuterHtml(
base::OnceCallback<void(const ClientStatus&, const std::string&)>
......@@ -381,6 +394,7 @@ class WebController {
std::unique_ptr<ElementFinder::Result> element_result);
void OnGetOuterHtml(base::OnceCallback<void(const ClientStatus&,
const std::string&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForPosition(
base::OnceCallback<void(bool, const RectF&)> callback,
......@@ -388,9 +402,11 @@ class WebController {
std::unique_ptr<ElementFinder::Result> result);
void OnGetVisualViewport(
base::OnceCallback<void(bool, const RectF&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::EvaluateResult> result);
void OnGetElementPositionResult(
base::OnceCallback<void(bool, const RectF&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
// Creates a new instance of DispatchKeyEventParams for the specified type and
......@@ -410,6 +426,7 @@ class WebController {
int remaining_rounds,
std::string object_id,
base::OnceCallback<void(bool)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForWaitForDocumentReadyState(
DocumentReadyState min_ready_state,
......
......@@ -14,14 +14,28 @@ ClientStatus UnexpectedErrorStatus(const std::string& file, int line) {
return status;
}
ClientStatus JavaScriptErrorStatus(const std::string& file,
int line,
const runtime::ExceptionDetails* exception) {
ClientStatus status(UNEXPECTED_JS_ERROR);
auto* info = status.mutable_details()->mutable_unexpected_error_info();
info->set_source_file(file);
info->set_source_line_number(line);
ClientStatus UnexpectedDevtoolsErrorStatus(
const DevtoolsClient::ReplyStatus& reply_status,
const std::string& file,
int line) {
ClientStatus status = UnexpectedErrorStatus(file, line);
if (!reply_status.is_ok()) {
auto* info = status.mutable_details()->mutable_unexpected_error_info();
info->set_devtools_error_code(reply_status.error_code);
info->set_devtools_error_message(reply_status.error_message);
}
return status;
}
ClientStatus JavaScriptErrorStatus(
const DevtoolsClient::ReplyStatus& reply_status,
const std::string& file,
int line,
const runtime::ExceptionDetails* exception) {
ClientStatus status = UnexpectedDevtoolsErrorStatus(reply_status, file, line);
status.set_proto_status(UNEXPECTED_JS_ERROR);
if (exception) {
auto* info = status.mutable_details()->mutable_unexpected_error_info();
if (exception->HasException() &&
exception->GetException()->HasClassName()) {
info->set_js_exception_classname(
......@@ -67,4 +81,4 @@ bool SafeGetBool(const runtime::RemoteObject* result, bool* out) {
return false;
}
} // namespace autofill_assistant
\ No newline at end of file
} // namespace autofill_assistant
......@@ -8,30 +8,48 @@
#include <string>
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
#include "components/autofill_assistant/browser/devtools/devtools_client.h"
namespace autofill_assistant {
// Builds a ClientStatus appropriate for an unexpected error.
//
// This should only be used in situations where getting an error cannot be
// anything but a bug in the client.
// anything but a bug in the client and no devtools ReplyStatus is available.
ClientStatus UnexpectedErrorStatus(const std::string& file, int line);
// Builds a ClientStatus appropriate for an unexpected error in a devtools
// response.
//
// This should only be used in situations where getting an error cannot be
// anything but a bug in the client.
ClientStatus UnexpectedDevtoolsErrorStatus(
const DevtoolsClient::ReplyStatus& reply_status,
const std::string& file,
int line);
// Builds a ClientStatus appropriate for a JavaScript error.
ClientStatus JavaScriptErrorStatus(const std::string& file,
int line,
const runtime::ExceptionDetails* exception);
ClientStatus JavaScriptErrorStatus(
const DevtoolsClient::ReplyStatus& reply_status,
const std::string& file,
int line,
const runtime::ExceptionDetails* exception);
// Makes sure that the given EvaluateResult exists, is successful and contains a
// result.
template <typename T>
ClientStatus CheckJavaScriptResult(T* result, const char* file, int line) {
ClientStatus CheckJavaScriptResult(
const DevtoolsClient::ReplyStatus& reply_status,
T* result,
const char* file,
int line) {
if (!result)
return JavaScriptErrorStatus(file, line, nullptr);
return JavaScriptErrorStatus(reply_status, file, line, nullptr);
if (result->HasExceptionDetails())
return JavaScriptErrorStatus(file, line, result->GetExceptionDetails());
return JavaScriptErrorStatus(reply_status, file, line,
result->GetExceptionDetails());
if (!result->GetResult())
return JavaScriptErrorStatus(file, line, nullptr);
return JavaScriptErrorStatus(reply_status, file, line, nullptr);
return OkClientStatus();
}
......@@ -49,4 +67,4 @@ bool SafeGetBool(const runtime::RemoteObject* result, bool* out);
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_UTIL_H_
\ No newline at end of file
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_UTIL_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment