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