1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Implementation of the ExtensionPortsRemoteService. 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Inspired significantly from debugger_remote_service 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// and ../automation/extension_port_container. 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/debugger/extension_ports_remote_service.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/json/json_reader.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/json/json_writer.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h" 153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/values.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/debugger/devtools_manager.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/debugger/devtools_protocol_handler.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/debugger/devtools_remote_message.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/debugger/inspectable_tab_proxy.h" 2221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile_manager.h" 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/devtools_messages.h" 24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/extensions/extension_messages.h" 25dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h" 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Protocol is as follows: 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// From external client: 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// {"command": "connect", 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "data": { 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "extensionId": "<extension_id string>", 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "channelName": "<port name string>", (optional) 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "tabId": <numerical tab ID> (optional) 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// } 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// } 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// To connect to a background page or tool strip, the tabId should be omitted. 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Tab IDs can be enumerated with the list_tabs DevToolsService command. 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Response: 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// {"command": "connect", 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "result": 0, (assuming success) 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "data": { 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "portId": <numerical port ID> 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// } 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// } 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Posting a message from external client: 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Put the target message port ID in the devtools destination field. 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// {"command": "postMessage", 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "data": <message body - arbitrary JSON> 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// } 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Response: 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// {"command": "postMessage", 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "result": 0 (Assuming success) 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// } 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Note this is a confirmation from the devtools protocol layer, not 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// a response from the extension. 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Message from an extension to the external client: 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The message port ID is in the devtools destination field. 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// {"command": "onMessage", 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "result": 0, (Always 0) 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "data": <message body - arbitrary JSON> 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// } 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The "disconnect" command from the external client, and 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "onDisconnect" notification from the ExtensionMessageService, are 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// similar: with the message port ID in the destination field, but no 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// "data" field in this case. 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Commands: 753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kConnect[] = "connect"; 763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kDisconnect[] = "disconnect"; 773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kPostMessage[] = "postMessage"; 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Events: 793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kOnMessage[] = "onMessage"; 803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kOnDisconnect[] = "onDisconnect"; 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Constants for the JSON message fields. 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The type is wstring because the constant is used to get a 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DictionaryValue field (which requires a wide string). 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Mandatory. 873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kCommandKey[] = "command"; 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Always present in messages sent to the external client. 903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kResultKey[] = "result"; 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Field for command-specific parameters. Not strictly necessary, but 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// makes it more similar to the remote debugger protocol, which should 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// allow easier reuse of client code. 953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kDataKey[] = "data"; 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Fields within the "data" dictionary: 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Required for "connect": 1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kExtensionIdKey[] = "extensionId"; 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Optional in "connect": 1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kChannelNameKey[] = "channelName"; 1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kTabIdKey[] = "tabId"; 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Present under "data" in replies to a successful "connect" . 1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char kPortIdKey[] = "portId"; 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst std::string ExtensionPortsRemoteService::kToolName = "ExtensionPorts"; 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExtensionPortsRemoteService::ExtensionPortsRemoteService( 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DevToolsProtocolHandler* delegate) 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : delegate_(delegate), service_(NULL) { 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need an ExtensionMessageService instance. It hangs off of 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |profile|. But we do not have a particular tab or RenderViewHost 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // as context. I'll just use the first active profile not in 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // incognito mode. But this is probably not the right way. 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ProfileManager* profile_manager = g_browser_process->profile_manager(); 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!profile_manager) { 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "No profile manager for ExtensionPortsRemoteService"; 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles()); 126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (size_t i = 0; i < profiles.size(); ++i) { 127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!profiles[i]->IsOffTheRecord()) { 128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen service_ = profiles[i]->GetExtensionMessageService(); 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!service_) 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(WARNING) << "No usable profile for ExtensionPortsRemoteService"; 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExtensionPortsRemoteService::~ExtensionPortsRemoteService() { 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPortsRemoteService::HandleMessage( 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const DevToolsRemoteMessage& message) { 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string destinationString = message.destination(); 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<Value> request(base::JSONReader::Read(message.content(), true)); 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (request.get() == NULL) { 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Bad JSON 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DictionaryValue* content; 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!request->IsType(Value::TYPE_DICTIONARY)) { 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); // Broken protocol :( 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch content = static_cast<DictionaryValue*>(request.get()); 1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!content->HasKey(kCommandKey)) { 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); // Broken protocol :( 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string command; 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DictionaryValue response; 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick content->GetString(kCommandKey, &command); 1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response.SetString(kCommandKey, command); 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!service_) { 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This happens if we failed to obtain an ExtensionMessageService 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // during initialization. 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response.SetInteger(kResultKey, RESULT_NO_SERVICE); 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SendResponse(response, message.tool(), message.destination()); 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int destination = -1; 175dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!destinationString.empty()) 1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick base::StringToInt(destinationString, &destination); 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (command == kConnect) { 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (destination != -1) // destination should be empty for this command. 1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND); 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ConnectCommand(content, &response); 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (command == kDisconnect) { 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (destination == -1) // Destination required for this command. 1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND); 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DisconnectCommand(destination, &response); 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (command == kPostMessage) { 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (destination == -1) // Destination required for this command. 1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND); 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PostMessageCommand(destination, content, &response); 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Unknown command 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response.SetInteger(kResultKey, RESULT_UNKNOWN_COMMAND); 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SendResponse(response, message.tool(), message.destination()); 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPortsRemoteService::OnConnectionLost() { 202731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "OnConnectionLost"; 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(service_); 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (PortIdSet::iterator it = openPortIds_.begin(); 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch it != openPortIds_.end(); 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++it) 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch service_->CloseChannel(*it); 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch openPortIds_.clear(); 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPortsRemoteService::SendResponse( 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const Value& response, const std::string& tool, 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& destination) { 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string response_content; 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::JSONWriter::Write(&response, false, &response_content); 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<DevToolsRemoteMessage> response_message( 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DevToolsRemoteMessageBuilder::instance().Create( 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tool, destination, response_content)); 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delegate_->Send(*response_message.get()); 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExtensionPortsRemoteService::Send(IPC::Message *message) { 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IPC_BEGIN_MESSAGE_MAP(ExtensionPortsRemoteService, *message) 227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnExtensionMessageInvoke) 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IPC_MESSAGE_UNHANDLED_ERROR() 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IPC_END_MESSAGE_MAP() 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete message; 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPortsRemoteService::OnExtensionMessageInvoke( 236731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const std::string& extension_id, 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& function_name, 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const ListValue& args, 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& event_url) { 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (function_name == ExtensionMessageService::kDispatchOnMessage) { 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_EQ(args.GetSize(), 2u); 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string message; 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int port_id; 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (args.GetString(0, &message) && args.GetInteger(1, &port_id)) 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OnExtensionMessage(message, port_id); 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (function_name == ExtensionMessageService::kDispatchOnDisconnect) { 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_EQ(args.GetSize(), 1u); 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int port_id; 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (args.GetInteger(0, &port_id)) 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OnExtensionPortDisconnected(port_id); 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (function_name == ExtensionMessageService::kDispatchOnConnect) { 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // There is no way for this service to be addressed and receive 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // connections. 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << function_name << " shouldn't be called."; 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << function_name << " shouldn't be called."; 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPortsRemoteService::OnExtensionMessage( 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& message, int port_id) { 262731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Message event: from port " << port_id << ", < " << message << ">"; 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Transpose the information into a JSON message for the external client. 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DictionaryValue content; 2653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick content.SetString(kCommandKey, kOnMessage); 2663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick content.SetInteger(kResultKey, RESULT_OK); 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Turn the stringified message body back into JSON. 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Value* data = base::JSONReader::Read(message, false); 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!data) { 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 2733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick content.Set(kDataKey, data); 2743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SendResponse(content, kToolName, base::IntToString(port_id)); 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPortsRemoteService::OnExtensionPortDisconnected(int port_id) { 278731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Disconnect event for port " << port_id; 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch openPortIds_.erase(port_id); 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DictionaryValue content; 2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick content.SetString(kCommandKey, kOnDisconnect); 2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick content.SetInteger(kResultKey, RESULT_OK); 2833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick SendResponse(content, kToolName, base::IntToString(port_id)); 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPortsRemoteService::ConnectCommand( 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DictionaryValue* content, DictionaryValue* response) { 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Parse out the parameters. 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DictionaryValue* data; 2903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!content->GetDictionary(kDataKey, &data)) { 2913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response->SetInteger(kResultKey, RESULT_PARAMETER_ERROR); 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string extension_id; 2953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!data->GetString(kExtensionIdKey, &extension_id)) { 2963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response->SetInteger(kResultKey, RESULT_PARAMETER_ERROR); 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string channel_name = ""; 3003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick data->GetString(kChannelNameKey, &channel_name); // optional. 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int tab_id = -1; 3023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick data->GetInteger(kTabIdKey, &tab_id); // optional. 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int port_id; 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_id != -1) { // Resolve the tab ID. 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const InspectableTabProxy::ControllersMap& navcon_map = 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delegate_->inspectable_tab_proxy()->controllers_map(); 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InspectableTabProxy::ControllersMap::const_iterator it = 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch navcon_map.find(tab_id); 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabContents* tab_contents = NULL; 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (it != navcon_map.end()) 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents = it->second->tab_contents(); 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!tab_contents) { 313731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "tab not found: " << tab_id; 3143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response->SetInteger(kResultKey, RESULT_TAB_NOT_FOUND); 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ask the ExtensionMessageService to open the channel. 318731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Connect: extension_id <" << extension_id 319731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick << ">, channel_name <" << channel_name 320731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick << ">, tab " << tab_id; 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(service_); 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch port_id = service_->OpenSpecialChannelToTab( 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_id, channel_name, tab_contents, this); 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { // no tab: channel to an extension' background page / toolstrip. 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ask the ExtensionMessageService to open the channel. 326731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Connect: extension_id <" << extension_id 327731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick << ">, channel_name <" << channel_name << ">"; 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(service_); 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch port_id = service_->OpenSpecialChannelToExtension( 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_id, channel_name, "null", this); 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (port_id == -1) { 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Failure: probably the extension ID doesn't exist. 334731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Connect failed"; 3353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response->SetInteger(kResultKey, RESULT_CONNECT_FAILED); 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 338731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Connected: port " << port_id; 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch openPortIds_.insert(port_id); 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Reply to external client with the port ID assigned to the new channel. 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DictionaryValue* reply_data = new DictionaryValue(); 3423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick reply_data->SetInteger(kPortIdKey, port_id); 3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response->Set(kDataKey, reply_data); 3443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response->SetInteger(kResultKey, RESULT_OK); 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPortsRemoteService::DisconnectCommand( 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int port_id, DictionaryValue* response) { 349731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "Disconnect port " << port_id; 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PortIdSet::iterator portEntry = openPortIds_.find(port_id); 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (portEntry == openPortIds_.end()) { // unknown port ID. 352731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "unknown port: " << port_id; 3533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response->SetInteger(kResultKey, RESULT_UNKNOWN_PORT); 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(service_); 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch service_->CloseChannel(port_id); 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch openPortIds_.erase(portEntry); 3593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response->SetInteger(kResultKey, RESULT_OK); 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPortsRemoteService::PostMessageCommand( 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int port_id, DictionaryValue* content, DictionaryValue* response) { 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Value* data; 3653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!content->Get(kDataKey, &data)) { 3663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response->SetInteger(kResultKey, RESULT_PARAMETER_ERROR); 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string message; 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Stringified the JSON message body. 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::JSONWriter::Write(data, false, &message); 372731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "postMessage: port " << port_id 373731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick << ", message: <" << message << ">"; 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PortIdSet::iterator portEntry = openPortIds_.find(port_id); 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (portEntry == openPortIds_.end()) { // Unknown port ID. 376731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "unknown port: " << port_id; 3773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response->SetInteger(kResultKey, RESULT_UNKNOWN_PORT); 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Post the message through the ExtensionMessageService. 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(service_); 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch service_->PostMessageFromRenderer(port_id, message); 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Confirm to the external client that we sent its message. 3843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick response->SetInteger(kResultKey, RESULT_OK); 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 386