| Index: content/browser/debugger/extension_ports_remote_service.cc
|
| diff --git a/content/browser/debugger/extension_ports_remote_service.cc b/content/browser/debugger/extension_ports_remote_service.cc
|
| deleted file mode 100644
|
| index 14e840ad3cbee360a6d81d69f0a4389e5da031b9..0000000000000000000000000000000000000000
|
| --- a/content/browser/debugger/extension_ports_remote_service.cc
|
| +++ /dev/null
|
| @@ -1,385 +0,0 @@
|
| -// 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.
|
| -
|
| -// Implementation of the ExtensionPortsRemoteService.
|
| -
|
| -// Inspired significantly from debugger_remote_service
|
| -// and ../automation/extension_port_container.
|
| -
|
| -#include "content/browser/debugger/extension_ports_remote_service.h"
|
| -
|
| -#include "base/json/json_reader.h"
|
| -#include "base/json/json_writer.h"
|
| -#include "base/message_loop.h"
|
| -#include "base/string_number_conversions.h"
|
| -#include "base/values.h"
|
| -#include "chrome/browser/browser_process.h"
|
| -#include "chrome/browser/profiles/profile_manager.h"
|
| -#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
|
| -#include "chrome/common/extensions/extension_messages.h"
|
| -#include "content/browser/debugger/devtools_manager.h"
|
| -#include "content/browser/debugger/devtools_protocol_handler.h"
|
| -#include "content/browser/debugger/devtools_remote_message.h"
|
| -#include "content/browser/debugger/inspectable_tab_proxy.h"
|
| -#include "content/browser/tab_contents/tab_contents.h"
|
| -#include "content/common/devtools_messages.h"
|
| -
|
| -namespace {
|
| -
|
| -// Protocol is as follows:
|
| -//
|
| -// From external client:
|
| -// {"command": "connect",
|
| -// "data": {
|
| -// "extensionId": "<extension_id string>",
|
| -// "channelName": "<port name string>", (optional)
|
| -// "tabId": <numerical tab ID> (optional)
|
| -// }
|
| -// }
|
| -// To connect to a background page or tool strip, the tabId should be omitted.
|
| -// Tab IDs can be enumerated with the list_tabs DevToolsService command.
|
| -//
|
| -// Response:
|
| -// {"command": "connect",
|
| -// "result": 0, (assuming success)
|
| -// "data": {
|
| -// "portId": <numerical port ID>
|
| -// }
|
| -// }
|
| -//
|
| -// Posting a message from external client:
|
| -// Put the target message port ID in the devtools destination field.
|
| -// {"command": "postMessage",
|
| -// "data": <message body - arbitrary JSON>
|
| -// }
|
| -// Response:
|
| -// {"command": "postMessage",
|
| -// "result": 0 (Assuming success)
|
| -// }
|
| -// Note this is a confirmation from the devtools protocol layer, not
|
| -// a response from the extension.
|
| -//
|
| -// Message from an extension to the external client:
|
| -// The message port ID is in the devtools destination field.
|
| -// {"command": "onMessage",
|
| -// "result": 0, (Always 0)
|
| -// "data": <message body - arbitrary JSON>
|
| -// }
|
| -//
|
| -// The "disconnect" command from the external client, and
|
| -// "onDisconnect" notification from the ExtensionMessageService, are
|
| -// similar: with the message port ID in the destination field, but no
|
| -// "data" field in this case.
|
| -
|
| -// Commands:
|
| -const char kConnect[] = "connect";
|
| -const char kDisconnect[] = "disconnect";
|
| -const char kPostMessage[] = "postMessage";
|
| -// Events:
|
| -const char kOnMessage[] = "onMessage";
|
| -const char kOnDisconnect[] = "onDisconnect";
|
| -
|
| -// Constants for the JSON message fields.
|
| -// The type is wstring because the constant is used to get a
|
| -// DictionaryValue field (which requires a wide string).
|
| -
|
| -// Mandatory.
|
| -const char kCommandKey[] = "command";
|
| -
|
| -// Always present in messages sent to the external client.
|
| -const char kResultKey[] = "result";
|
| -
|
| -// Field for command-specific parameters. Not strictly necessary, but
|
| -// makes it more similar to the remote debugger protocol, which should
|
| -// allow easier reuse of client code.
|
| -const char kDataKey[] = "data";
|
| -
|
| -// Fields within the "data" dictionary:
|
| -
|
| -// Required for "connect":
|
| -const char kExtensionIdKey[] = "extensionId";
|
| -// Optional in "connect":
|
| -const char kChannelNameKey[] = "channelName";
|
| -const char kTabIdKey[] = "tabId";
|
| -
|
| -// Present under "data" in replies to a successful "connect" .
|
| -const char kPortIdKey[] = "portId";
|
| -
|
| -} // namespace
|
| -
|
| -const std::string ExtensionPortsRemoteService::kToolName = "ExtensionPorts";
|
| -
|
| -ExtensionPortsRemoteService::ExtensionPortsRemoteService(
|
| - DevToolsProtocolHandler* delegate)
|
| - : delegate_(delegate), service_(NULL) {
|
| - // We need an ExtensionMessageService instance. It hangs off of
|
| - // |profile|. But we do not have a particular tab or RenderViewHost
|
| - // as context. I'll just use the first active profile not in
|
| - // incognito mode. But this is probably not the right way.
|
| - ProfileManager* profile_manager = g_browser_process->profile_manager();
|
| - if (!profile_manager) {
|
| - LOG(WARNING) << "No profile manager for ExtensionPortsRemoteService";
|
| - return;
|
| - }
|
| -
|
| - std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
|
| - for (size_t i = 0; i < profiles.size(); ++i) {
|
| - if (!profiles[i]->IsOffTheRecord()) {
|
| - service_ = profiles[i]->GetExtensionMessageService();
|
| - break;
|
| - }
|
| - }
|
| - if (!service_)
|
| - LOG(WARNING) << "No usable profile for ExtensionPortsRemoteService";
|
| -}
|
| -
|
| -ExtensionPortsRemoteService::~ExtensionPortsRemoteService() {
|
| -}
|
| -
|
| -void ExtensionPortsRemoteService::HandleMessage(
|
| - const DevToolsRemoteMessage& message) {
|
| - DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
|
| - const std::string destinationString = 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);
|
| -
|
| - if (!service_) {
|
| - // This happens if we failed to obtain an ExtensionMessageService
|
| - // during initialization.
|
| - NOTREACHED();
|
| - response.SetInteger(kResultKey, RESULT_NO_SERVICE);
|
| - SendResponse(response, message.tool(), message.destination());
|
| - return;
|
| - }
|
| -
|
| - int destination = -1;
|
| - if (!destinationString.empty())
|
| - base::StringToInt(destinationString, &destination);
|
| -
|
| - if (command == kConnect) {
|
| - if (destination != -1) // destination should be empty for this command.
|
| - response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND);
|
| - else
|
| - ConnectCommand(content, &response);
|
| - } else if (command == kDisconnect) {
|
| - if (destination == -1) // Destination required for this command.
|
| - response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND);
|
| - else
|
| - DisconnectCommand(destination, &response);
|
| - } else if (command == kPostMessage) {
|
| - if (destination == -1) // Destination required for this command.
|
| - response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND);
|
| - else
|
| - PostMessageCommand(destination, content, &response);
|
| - } else {
|
| - // Unknown command
|
| - NOTREACHED();
|
| - response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND);
|
| - }
|
| - SendResponse(response, message.tool(), message.destination());
|
| -}
|
| -
|
| -void ExtensionPortsRemoteService::OnConnectionLost() {
|
| - VLOG(1) << "OnConnectionLost";
|
| - DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
|
| - DCHECK(service_);
|
| - for (PortIdSet::iterator it = openPortIds_.begin();
|
| - it != openPortIds_.end();
|
| - ++it)
|
| - service_->CloseChannel(*it);
|
| - openPortIds_.clear();
|
| -}
|
| -
|
| -void ExtensionPortsRemoteService::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());
|
| -}
|
| -
|
| -bool ExtensionPortsRemoteService::Send(IPC::Message *message) {
|
| - DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
|
| -
|
| - IPC_BEGIN_MESSAGE_MAP(ExtensionPortsRemoteService, *message)
|
| - IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnExtensionMessageInvoke)
|
| - IPC_MESSAGE_UNHANDLED_ERROR()
|
| - IPC_END_MESSAGE_MAP()
|
| -
|
| - delete message;
|
| - return true;
|
| -}
|
| -
|
| -void ExtensionPortsRemoteService::OnExtensionMessageInvoke(
|
| - const std::string& extension_id,
|
| - const std::string& function_name,
|
| - const ListValue& args,
|
| - const GURL& event_url) {
|
| - if (function_name == ExtensionMessageService::kDispatchOnMessage) {
|
| - DCHECK_EQ(args.GetSize(), 2u);
|
| - std::string message;
|
| - int port_id;
|
| - if (args.GetString(0, &message) && args.GetInteger(1, &port_id))
|
| - OnExtensionMessage(message, port_id);
|
| - } else if (function_name == ExtensionMessageService::kDispatchOnDisconnect) {
|
| - DCHECK_EQ(args.GetSize(), 1u);
|
| - int port_id;
|
| - if (args.GetInteger(0, &port_id))
|
| - OnExtensionPortDisconnected(port_id);
|
| - } else if (function_name == ExtensionMessageService::kDispatchOnConnect) {
|
| - // There is no way for this service to be addressed and receive
|
| - // connections.
|
| - NOTREACHED() << function_name << " shouldn't be called.";
|
| - } else {
|
| - NOTREACHED() << function_name << " shouldn't be called.";
|
| - }
|
| -}
|
| -
|
| -void ExtensionPortsRemoteService::OnExtensionMessage(
|
| - const std::string& message, int port_id) {
|
| - VLOG(1) << "Message event: from port " << port_id << ", < " << message << ">";
|
| - // Transpose the information into a JSON message for the external client.
|
| - DictionaryValue content;
|
| - content.SetString(kCommandKey, kOnMessage);
|
| - content.SetInteger(kResultKey, RESULT_OK);
|
| - // Turn the stringified message body back into JSON.
|
| - Value* data = base::JSONReader::Read(message, false);
|
| - if (!data) {
|
| - NOTREACHED();
|
| - return;
|
| - }
|
| - content.Set(kDataKey, data);
|
| - SendResponse(content, kToolName, base::IntToString(port_id));
|
| -}
|
| -
|
| -void ExtensionPortsRemoteService::OnExtensionPortDisconnected(int port_id) {
|
| - VLOG(1) << "Disconnect event for port " << port_id;
|
| - openPortIds_.erase(port_id);
|
| - DictionaryValue content;
|
| - content.SetString(kCommandKey, kOnDisconnect);
|
| - content.SetInteger(kResultKey, RESULT_OK);
|
| - SendResponse(content, kToolName, base::IntToString(port_id));
|
| -}
|
| -
|
| -void ExtensionPortsRemoteService::ConnectCommand(
|
| - DictionaryValue* content, DictionaryValue* response) {
|
| - // Parse out the parameters.
|
| - DictionaryValue* data;
|
| - if (!content->GetDictionary(kDataKey, &data)) {
|
| - response->SetInteger(kResultKey, RESULT_PARAMETER_ERROR);
|
| - return;
|
| - }
|
| - std::string extension_id;
|
| - if (!data->GetString(kExtensionIdKey, &extension_id)) {
|
| - response->SetInteger(kResultKey, RESULT_PARAMETER_ERROR);
|
| - return;
|
| - }
|
| - std::string channel_name = "";
|
| - data->GetString(kChannelNameKey, &channel_name); // optional.
|
| - int tab_id = -1;
|
| - data->GetInteger(kTabIdKey, &tab_id); // optional.
|
| - int port_id;
|
| - if (tab_id != -1) { // Resolve the tab ID.
|
| - const InspectableTabProxy::TabMap& tab_map =
|
| - delegate_->inspectable_tab_proxy()->tab_map();
|
| - InspectableTabProxy::TabMap::const_iterator it = tab_map.find(tab_id);
|
| - TabContents* tab_contents = NULL;
|
| - if (it != tab_map.end())
|
| - tab_contents = it->second->tab_contents();
|
| - if (!tab_contents) {
|
| - VLOG(1) << "tab not found: " << tab_id;
|
| - response->SetInteger(kResultKey, RESULT_TAB_NOT_FOUND);
|
| - return;
|
| - }
|
| - // Ask the ExtensionMessageService to open the channel.
|
| - VLOG(1) << "Connect: extension_id <" << extension_id
|
| - << ">, channel_name <" << channel_name
|
| - << ">, tab " << tab_id;
|
| - DCHECK(service_);
|
| - port_id = service_->OpenSpecialChannelToTab(
|
| - extension_id, channel_name, tab_contents, this);
|
| - } else { // no tab: channel to an extension' background page / toolstrip.
|
| - // Ask the ExtensionMessageService to open the channel.
|
| - VLOG(1) << "Connect: extension_id <" << extension_id
|
| - << ">, channel_name <" << channel_name << ">";
|
| - DCHECK(service_);
|
| - port_id = service_->OpenSpecialChannelToExtension(
|
| - extension_id, channel_name, "null", this);
|
| - }
|
| - if (port_id == -1) {
|
| - // Failure: probably the extension ID doesn't exist.
|
| - VLOG(1) << "Connect failed";
|
| - response->SetInteger(kResultKey, RESULT_CONNECT_FAILED);
|
| - return;
|
| - }
|
| - VLOG(1) << "Connected: port " << port_id;
|
| - openPortIds_.insert(port_id);
|
| - // Reply to external client with the port ID assigned to the new channel.
|
| - DictionaryValue* reply_data = new DictionaryValue();
|
| - reply_data->SetInteger(kPortIdKey, port_id);
|
| - response->Set(kDataKey, reply_data);
|
| - response->SetInteger(kResultKey, RESULT_OK);
|
| -}
|
| -
|
| -void ExtensionPortsRemoteService::DisconnectCommand(
|
| - int port_id, DictionaryValue* response) {
|
| - VLOG(1) << "Disconnect port " << port_id;
|
| - PortIdSet::iterator portEntry = openPortIds_.find(port_id);
|
| - if (portEntry == openPortIds_.end()) { // unknown port ID.
|
| - VLOG(1) << "unknown port: " << port_id;
|
| - response->SetInteger(kResultKey, RESULT_UNKNOWN_PORT);
|
| - return;
|
| - }
|
| - DCHECK(service_);
|
| - service_->CloseChannel(port_id);
|
| - openPortIds_.erase(portEntry);
|
| - response->SetInteger(kResultKey, RESULT_OK);
|
| -}
|
| -
|
| -void ExtensionPortsRemoteService::PostMessageCommand(
|
| - int port_id, DictionaryValue* content, DictionaryValue* response) {
|
| - Value* data;
|
| - if (!content->Get(kDataKey, &data)) {
|
| - response->SetInteger(kResultKey, RESULT_PARAMETER_ERROR);
|
| - return;
|
| - }
|
| - std::string message;
|
| - // Stringified the JSON message body.
|
| - base::JSONWriter::Write(data, false, &message);
|
| - VLOG(1) << "postMessage: port " << port_id
|
| - << ", message: <" << message << ">";
|
| - PortIdSet::iterator portEntry = openPortIds_.find(port_id);
|
| - if (portEntry == openPortIds_.end()) { // Unknown port ID.
|
| - VLOG(1) << "unknown port: " << port_id;
|
| - response->SetInteger(kResultKey, RESULT_UNKNOWN_PORT);
|
| - return;
|
| - }
|
| - // Post the message through the ExtensionMessageService.
|
| - DCHECK(service_);
|
| - service_->PostMessageFromRenderer(port_id, message);
|
| - // Confirm to the external client that we sent its message.
|
| - response->SetInteger(kResultKey, RESULT_OK);
|
| -}
|
|
|