summaryrefslogtreecommitdiffstats
path: root/chrome/browser/debugger/debugger_remote_service.cc
diff options
context:
space:
mode:
authorpfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-20 11:38:03 +0000
committerpfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-20 11:38:03 +0000
commit0639cfd4ed40aa9450c5781c86d6b47af8396220 (patch)
tree486f82e04cd53623ffb67ae7932523bde70b118f /chrome/browser/debugger/debugger_remote_service.cc
parentd641b6e4c2ebf556cb42818e7b3470329baf170c (diff)
downloadchromium_src-0639cfd4ed40aa9450c5781c86d6b47af8396220.zip
chromium_src-0639cfd4ed40aa9450c5781c86d6b47af8396220.tar.gz
chromium_src-0639cfd4ed40aa9450c5781c86d6b47af8396220.tar.bz2
DevTools: bulk move of legacy protocol back to chrome/.
Review URL: http://codereview.chromium.org/7458015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@93182 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/debugger/debugger_remote_service.cc')
-rw-r--r--chrome/browser/debugger/debugger_remote_service.cc337
1 files changed, 337 insertions, 0 deletions
diff --git a/chrome/browser/debugger/debugger_remote_service.cc b/chrome/browser/debugger/debugger_remote_service.cc
new file mode 100644
index 0000000..a93084f
--- /dev/null
+++ b/chrome/browser/debugger/debugger_remote_service.cc
@@ -0,0 +1,337 @@
+// Copyright (c) 2011 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.
+
+// This file contains implementations of the DebuggerRemoteService methods,
+// defines DebuggerRemoteService and DebuggerRemoteServiceCommand constants.
+
+#include "chrome/browser/debugger/debugger_remote_service.h"
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/stringprintf.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/debugger/devtools_protocol_handler.h"
+#include "chrome/browser/debugger/devtools_remote_message.h"
+#include "chrome/browser/debugger/inspectable_tab_proxy.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
+#include "chrome/common/render_messages.h"
+#include "content/browser/debugger/devtools_manager.h"
+#include "content/browser/renderer_host/render_view_host.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "content/common/devtools_messages.h"
+
+namespace {
+
+// Constants for the "data", "result", and "command" JSON message fields.
+const char kDataKey[] = "data";
+const char kResultKey[] = "result";
+const char kCommandKey[] = "command";
+
+} // namespace
+
+const std::string DebuggerRemoteServiceCommand::kAttach = "attach";
+const std::string DebuggerRemoteServiceCommand::kDetach = "detach";
+const std::string DebuggerRemoteServiceCommand::kDebuggerCommand =
+ "debugger_command";
+const std::string DebuggerRemoteServiceCommand::kEvaluateJavascript =
+ "evaluate_javascript";
+const std::string DebuggerRemoteServiceCommand::kFrameNavigate =
+ "navigated";
+const std::string DebuggerRemoteServiceCommand::kTabClosed =
+ "closed";
+
+const std::string DebuggerRemoteService::kToolName = "V8Debugger";
+
+DebuggerRemoteService::DebuggerRemoteService(DevToolsProtocolHandler* delegate)
+ : delegate_(delegate) {}
+
+DebuggerRemoteService::~DebuggerRemoteService() {}
+
+// This method handles the V8Debugger tool commands which are
+// retrieved from the request "command" field. If an operation result
+// is ready off-hand (synchronously), it is sent back to the remote debugger.
+// Otherwise the corresponding response is received through IPC from the
+// V8 debugger via DevToolsClientHost.
+void DebuggerRemoteService::HandleMessage(
+ const DevToolsRemoteMessage& message) {
+ const std::string destination = message.destination();
+ scoped_ptr<Value> request(base::JSONReader::Read(message.content(), true));
+ if (request.get() == NULL) {
+ // Bad JSON
+ NOTREACHED();
+ return;
+ }
+ DictionaryValue* content;
+ if (!request->IsType(Value::TYPE_DICTIONARY)) {
+ NOTREACHED(); // Broken protocol :(
+ return;
+ }
+ content = static_cast<DictionaryValue*>(request.get());
+ if (!content->HasKey(kCommandKey)) {
+ NOTREACHED(); // Broken protocol :(
+ return;
+ }
+ std::string command;
+ DictionaryValue response;
+
+ content->GetString(kCommandKey, &command);
+ response.SetString(kCommandKey, command);
+ bool send_response = true;
+ if (destination.empty()) {
+ // Unknown command (bad format?)
+ NOTREACHED();
+ response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND);
+ SendResponse(response, message.tool(), message.destination());
+ return;
+ }
+ int32 tab_uid = -1;
+ base::StringToInt(destination, &tab_uid);
+
+ if (command == DebuggerRemoteServiceCommand::kAttach) {
+ // TODO(apavlov): handle 0 for a new tab
+ response.SetString(kCommandKey, DebuggerRemoteServiceCommand::kAttach);
+ AttachToTab(destination, &response);
+ } else if (command == DebuggerRemoteServiceCommand::kDetach) {
+ response.SetString(kCommandKey, DebuggerRemoteServiceCommand::kDetach);
+ DetachFromTab(destination, &response);
+ } else if (command == DebuggerRemoteServiceCommand::kDebuggerCommand) {
+ send_response = DispatchDebuggerCommand(tab_uid, content, &response);
+ } else if (command == DebuggerRemoteServiceCommand::kEvaluateJavascript) {
+ send_response = DispatchEvaluateJavascript(tab_uid, content, &response);
+ } else {
+ // Unknown command
+ NOTREACHED();
+ response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND);
+ }
+
+ if (send_response) {
+ SendResponse(response, message.tool(), message.destination());
+ }
+}
+
+void DebuggerRemoteService::OnConnectionLost() {
+ delegate_->inspectable_tab_proxy()->OnRemoteDebuggerDetached();
+}
+
+// Sends a JSON response to the remote debugger using |response| as content,
+// |tool| and |destination| as the respective header values.
+void DebuggerRemoteService::SendResponse(const Value& response,
+ const std::string& tool,
+ const std::string& destination) {
+ std::string response_content;
+ base::JSONWriter::Write(&response, false, &response_content);
+ scoped_ptr<DevToolsRemoteMessage> response_message(
+ DevToolsRemoteMessageBuilder::instance().Create(tool,
+ destination,
+ response_content));
+ delegate_->Send(*response_message.get());
+}
+
+// Gets a TabContents instance corresponding to the |tab_uid| using the
+// InspectableTabProxy controllers map, or NULL if none found.
+TabContents* DebuggerRemoteService::ToTabContents(int32 tab_uid) {
+ const InspectableTabProxy::TabMap& tab_map =
+ delegate_->inspectable_tab_proxy()->tab_map();
+ InspectableTabProxy::TabMap::const_iterator it = tab_map.find(tab_uid);
+ if (it != tab_map.end()) {
+ TabContents* tab_contents = it->second->tab_contents();
+ if (tab_contents == NULL) {
+ return NULL;
+ } else {
+ return tab_contents;
+ }
+ } else {
+ return NULL;
+ }
+}
+
+// Gets invoked from a DevToolsClientHost callback whenever
+// a message from the V8 VM debugger corresponding to |tab_id| is received.
+// Composes a Chrome Developer Tools Protocol JSON response and sends it
+// to the remote debugger.
+void DebuggerRemoteService::DebuggerOutput(int32 tab_uid,
+ const std::string& message) {
+ std::string content = StringPrintf(
+ "{\"command\":\"%s\",\"result\":%s,\"data\":%s}",
+ DebuggerRemoteServiceCommand::kDebuggerCommand.c_str(),
+ base::IntToString(RESULT_OK).c_str(),
+ message.c_str());
+ scoped_ptr<DevToolsRemoteMessage> response_message(
+ DevToolsRemoteMessageBuilder::instance().Create(
+ kToolName,
+ base::IntToString(tab_uid),
+ content));
+ delegate_->Send(*(response_message.get()));
+}
+
+// Gets invoked from a DevToolsClientHost callback whenever
+// a tab corresponding to |tab_id| changes its URL. |url| is the new
+// URL of the tab (may be the same as the previous one if the tab is reloaded).
+// Sends the corresponding message to the remote debugger.
+void DebuggerRemoteService::FrameNavigate(int32 tab_uid,
+ const std::string& url) {
+ DictionaryValue value;
+ value.SetString(kCommandKey, DebuggerRemoteServiceCommand::kFrameNavigate);
+ value.SetInteger(kResultKey, RESULT_OK);
+ value.SetString(kDataKey, url);
+ SendResponse(value, kToolName, base::IntToString(tab_uid));
+}
+
+// Gets invoked from a DevToolsClientHost callback whenever
+// a tab corresponding to |tab_id| gets closed.
+// Sends the corresponding message to the remote debugger.
+void DebuggerRemoteService::TabClosed(int32 tab_id) {
+ DictionaryValue value;
+ value.SetString(kCommandKey, DebuggerRemoteServiceCommand::kTabClosed);
+ value.SetInteger(kResultKey, RESULT_OK);
+ SendResponse(value, kToolName, base::IntToString(tab_id));
+}
+
+// Attaches a remote debugger to the target tab specified by |destination|
+// by posting the DevToolsAgentMsg_Attach message and sends a response
+// to the remote debugger immediately.
+void DebuggerRemoteService::AttachToTab(const std::string& destination,
+ DictionaryValue* response) {
+ int32 tab_uid = -1;
+ base::StringToInt(destination, &tab_uid);
+ if (tab_uid < 0) {
+ // Bad tab_uid received from remote debugger (perhaps NaN)
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
+ return;
+ }
+ if (tab_uid == 0) { // single tab_uid
+ // We've been asked to open a new tab with URL
+ // TODO(apavlov): implement
+ NOTIMPLEMENTED();
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
+ return;
+ }
+ TabContents* tab_contents = ToTabContents(tab_uid);
+ if (tab_contents == NULL) {
+ // No active tab contents with tab_uid
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
+ return;
+ }
+ RenderViewHost* target_host = tab_contents->render_view_host();
+ DevToolsClientHost* client_host =
+ delegate_->inspectable_tab_proxy()->ClientHostForTabId(tab_uid);
+ if (client_host == NULL) {
+ client_host =
+ delegate_->inspectable_tab_proxy()->NewClientHost(tab_uid, this);
+ DevToolsManager* manager = DevToolsManager::GetInstance();
+ if (manager != NULL) {
+ manager->RegisterDevToolsClientHostFor(target_host, client_host);
+ response->SetInteger(kResultKey, RESULT_OK);
+ } else {
+ response->SetInteger(kResultKey, RESULT_DEBUGGER_ERROR);
+ }
+ } else {
+ // DevToolsClientHost for this tab is already registered
+ response->SetInteger(kResultKey, RESULT_ILLEGAL_TAB_STATE);
+ }
+}
+
+// Detaches a remote debugger from the target tab specified by |destination|
+// by posting the DevToolsAgentMsg_Detach message and sends a response
+// to the remote debugger immediately.
+void DebuggerRemoteService::DetachFromTab(const std::string& destination,
+ DictionaryValue* response) {
+ int32 tab_uid = -1;
+ base::StringToInt(destination, &tab_uid);
+ if (tab_uid == -1) {
+ // Bad tab_uid received from remote debugger (NaN)
+ if (response != NULL) {
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
+ }
+ return;
+ }
+ int result_code;
+ DevToolsClientHostImpl* client_host =
+ delegate_->inspectable_tab_proxy()->ClientHostForTabId(tab_uid);
+ if (client_host != NULL) {
+ client_host->CloseImpl();
+ result_code = RESULT_OK;
+ } else {
+ // No client host registered for |tab_uid|.
+ result_code = RESULT_UNKNOWN_TAB;
+ }
+ if (response != NULL) {
+ response->SetInteger(kResultKey, result_code);
+ }
+}
+
+// Sends a V8 debugger command to the target tab V8 debugger.
+// Does not send back a response (which is received asynchronously
+// through IPC) unless an error occurs before the command has actually
+// been sent.
+bool DebuggerRemoteService::DispatchDebuggerCommand(int tab_uid,
+ DictionaryValue* content,
+ DictionaryValue* response) {
+ if (tab_uid == -1) {
+ // Invalid tab_uid from remote debugger (perhaps NaN)
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
+ return true;
+ }
+ DevToolsManager* manager = DevToolsManager::GetInstance();
+ if (manager == NULL) {
+ response->SetInteger(kResultKey, RESULT_DEBUGGER_ERROR);
+ return true;
+ }
+ TabContents* tab_contents = ToTabContents(tab_uid);
+ if (tab_contents == NULL) {
+ // Unknown tab_uid from remote debugger
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
+ return true;
+ }
+ DevToolsClientHost* client_host =
+ manager->GetDevToolsClientHostFor(tab_contents->render_view_host());
+ if (client_host == NULL) {
+ // tab_uid is not being debugged (Attach has not been invoked)
+ response->SetInteger(kResultKey, RESULT_ILLEGAL_TAB_STATE);
+ return true;
+ }
+ std::string v8_command;
+ DictionaryValue* v8_command_value;
+ content->GetDictionary(kDataKey, &v8_command_value);
+ base::JSONWriter::Write(v8_command_value, false, &v8_command);
+ manager->ForwardToDevToolsAgent(
+ client_host, DevToolsAgentMsg_DebuggerCommand(MSG_ROUTING_NONE,
+ v8_command));
+ // Do not send the response right now, as the JSON will be received from
+ // the V8 debugger asynchronously.
+ return false;
+}
+
+// Sends the immediate "evaluate Javascript" command to the V8 debugger.
+// The evaluation result is not sent back to the client as this command
+// is in fact needed to invoke processing of queued debugger commands.
+bool DebuggerRemoteService::DispatchEvaluateJavascript(
+ int tab_uid,
+ DictionaryValue* content,
+ DictionaryValue* response) {
+ if (tab_uid == -1) {
+ // Invalid tab_uid from remote debugger (perhaps NaN)
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
+ return true;
+ }
+ TabContents* tab_contents = ToTabContents(tab_uid);
+ if (tab_contents == NULL) {
+ // Unknown tab_uid from remote debugger
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
+ return true;
+ }
+ RenderViewHost* render_view_host = tab_contents->render_view_host();
+ if (render_view_host == NULL) {
+ // No RenderViewHost
+ response->SetInteger(kResultKey, RESULT_UNKNOWN_TAB);
+ return true;
+ }
+ std::string javascript;
+ content->GetString(kDataKey, &javascript);
+ render_view_host->ExecuteJavascriptInWebFrame(string16(),
+ UTF8ToUTF16(javascript));
+ return false;
+}