blob: 849602a866f5d651f08bad2ec73080efd7a3a260 [file] [log] [blame]
[email protected]9f76c1e2012-03-05 15:15:581// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]91ba3312011-03-17 20:39:222// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Implements the Chrome Extensions Debugger API.
6
[email protected]1eb8f2f2012-07-12 02:04:497#include "chrome/browser/extensions/api/debugger/debugger_api.h"
[email protected]91ba3312011-03-17 20:39:228
avia2f4804a2015-12-24 23:11:139#include <stddef.h>
dchengc963c7142016-04-08 03:55:2210
[email protected]ff31a8a2011-03-30 14:13:5911#include <map>
dchengc963c7142016-04-08 03:55:2212#include <memory>
[email protected]91ba3312011-03-17 20:39:2213#include <set>
dcheng1fc00f12015-12-26 22:18:0314#include <utility>
[email protected]91ba3312011-03-17 20:39:2215
[email protected]2fefdb32013-02-26 14:28:1016#include "base/command_line.h"
[email protected]ff31a8a2011-03-30 14:13:5917#include "base/json/json_reader.h"
[email protected]91ba3312011-03-17 20:39:2218#include "base/json/json_writer.h"
dgozmand06efdf2015-08-27 02:28:3819#include "base/lazy_instance.h"
avia2f4804a2015-12-24 23:11:1320#include "base/macros.h"
[email protected]3b63f8f42011-03-28 01:54:1521#include "base/memory/singleton.h"
[email protected]4edaf7ec2014-05-07 13:54:1522#include "base/scoped_observer.h"
[email protected]06d503f2013-10-29 17:29:3723#include "base/stl_util.h"
[email protected]3ea1b182013-02-08 22:38:4124#include "base/strings/string_number_conversions.h"
[email protected]91ba3312011-03-17 20:39:2225#include "base/values.h"
[email protected]49a01e642013-07-12 00:29:4526#include "chrome/browser/chrome_notification_types.h"
pfeldmana9e7dda2016-08-26 14:35:1727#include "chrome/browser/devtools/chrome_devtools_manager_delegate.h"
[email protected]1eb8f2f2012-07-12 02:04:4928#include "chrome/browser/extensions/api/debugger/debugger_api_constants.h"
Peter Kasting37db76f82018-01-06 02:39:1629#include "chrome/browser/extensions/api/debugger/extension_dev_tools_infobar.h"
[email protected]2fefdb32013-02-26 14:28:1030#include "chrome/browser/extensions/extension_service.h"
[email protected]ac84431b2011-09-27 17:26:1131#include "chrome/browser/extensions/extension_tab_util.h"
[email protected]4a8adfa02013-03-19 22:37:4632#include "chrome/browser/infobars/infobar_service.h"
[email protected]91ba3312011-03-17 20:39:2233#include "chrome/browser/profiles/profile.h"
dgozmand06efdf2015-08-27 02:28:3834#include "chrome/browser/ui/browser.h"
[email protected]863f70a2012-01-27 02:05:5035#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
[email protected]2fefdb32013-02-26 14:28:1036#include "chrome/common/chrome_switches.h"
[email protected]051655ad2014-04-18 15:09:4137#include "components/infobars/core/infobar.h"
dgozmancb088d02015-04-28 11:57:4538#include "content/public/browser/browser_thread.h"
[email protected]98f66112012-12-25 12:59:3639#include "content/public/browser/devtools_agent_host.h"
[email protected]1c3bd202011-12-23 05:48:2440#include "content/public/browser/notification_service.h"
[email protected]ad50def52011-10-19 23:17:0741#include "content/public/browser/notification_source.h"
[email protected]2fefdb32013-02-26 14:28:1042#include "content/public/browser/render_process_host.h"
[email protected]2fefdb32013-02-26 14:28:1043#include "content/public/browser/render_widget_host.h"
[email protected]ef9572e2012-01-04 22:14:1244#include "content/public/browser/web_contents.h"
[email protected]744c2a22012-03-15 18:42:0445#include "content/public/common/content_client.h"
[email protected]3b366ae2013-05-17 21:16:5846#include "content/public/common/url_utils.h"
[email protected]34423532013-11-21 18:13:1047#include "extensions/browser/event_router.h"
[email protected]22401dc2014-03-21 01:38:5748#include "extensions/browser/extension_host.h"
[email protected]4edaf7ec2014-05-07 13:54:1549#include "extensions/browser/extension_registry.h"
50#include "extensions/browser/extension_registry_observer.h"
[email protected]684a212a2014-06-27 17:14:5051#include "extensions/common/constants.h"
[email protected]e9f541a2012-11-19 21:52:3152#include "extensions/common/error_utils.h"
[email protected]e4452d32013-11-15 23:07:4153#include "extensions/common/extension.h"
[email protected]684a212a2014-06-27 17:14:5054#include "extensions/common/manifest_constants.h"
55#include "extensions/common/permissions/permissions_data.h"
56#include "extensions/common/switches.h"
[email protected]91ba3312011-03-17 20:39:2257
[email protected]0e12d7d2011-12-01 16:21:4458using content::DevToolsAgentHost;
[email protected]2fefdb32013-02-26 14:28:1059using content::RenderProcessHost;
[email protected]2fefdb32013-02-26 14:28:1060using content::RenderWidgetHost;
[email protected]7320a44e2012-05-22 17:01:1161using content::WebContents;
[email protected]0e12d7d2011-12-01 16:21:4462
[email protected]1eb8f2f2012-07-12 02:04:4963namespace keys = debugger_api_constants;
[email protected]752960d2012-07-23 19:06:1164namespace Attach = extensions::api::debugger::Attach;
65namespace Detach = extensions::api::debugger::Detach;
66namespace OnDetach = extensions::api::debugger::OnDetach;
67namespace OnEvent = extensions::api::debugger::OnEvent;
68namespace SendCommand = extensions::api::debugger::SendCommand;
[email protected]ef9572e2012-01-04 22:14:1269
[email protected]4edaf7ec2014-05-07 13:54:1570namespace extensions {
71class ExtensionRegistry;
dgozmand06efdf2015-08-27 02:28:3872class ExtensionDevToolsClientHost;
[email protected]19bcf9d2013-07-18 22:00:5973
74namespace {
75
76// Helpers --------------------------------------------------------------------
77
78void CopyDebuggee(Debuggee* dst, const Debuggee& src) {
79 if (src.tab_id)
80 dst->tab_id.reset(new int(*src.tab_id));
81 if (src.extension_id)
82 dst->extension_id.reset(new std::string(*src.extension_id));
83 if (src.target_id)
84 dst->target_id.reset(new std::string(*src.target_id));
85}
86
[email protected]91ba3312011-03-17 20:39:2287} // namespace
88
dgozmand06efdf2015-08-27 02:28:3889// ExtensionDevToolsClientHost ------------------------------------------------
90
91using AttachedClientHosts = std::set<ExtensionDevToolsClientHost*>;
92base::LazyInstance<AttachedClientHosts>::Leaky g_attached_client_hosts =
93 LAZY_INSTANCE_INITIALIZER;
94
95class ExtensionDevToolsClientHost : public content::DevToolsAgentHostClient,
96 public content::NotificationObserver,
97 public ExtensionRegistryObserver {
98 public:
99 ExtensionDevToolsClientHost(Profile* profile,
100 DevToolsAgentHost* agent_host,
101 const std::string& extension_id,
102 const std::string& extension_name,
103 const Debuggee& debuggee);
104
105 ~ExtensionDevToolsClientHost() override;
106
Dmitry Gozman2aec794f2018-03-05 20:27:54107 bool Attach();
dgozmand06efdf2015-08-27 02:28:38108 const std::string& extension_id() { return extension_id_; }
109 DevToolsAgentHost* agent_host() { return agent_host_.get(); }
Dmitry Gozman2aec794f2018-03-05 20:27:54110 void RespondDetachedToPendingRequests();
dgozmand06efdf2015-08-27 02:28:38111 void Close();
112 void SendMessageToBackend(DebuggerSendCommandFunction* function,
113 const std::string& method,
114 SendCommand::Params::CommandParams* command_params);
115
116 // Closes connection as terminated by the user.
117 void InfoBarDismissed();
118
119 // DevToolsAgentHostClient interface.
Pavel Feldmana344d932017-10-31 20:24:52120 void AgentHostClosed(DevToolsAgentHost* agent_host) override;
dgozmand06efdf2015-08-27 02:28:38121 void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
122 const std::string& message) override;
123
124 private:
125 using PendingRequests =
126 std::map<int, scoped_refptr<DebuggerSendCommandFunction>>;
127
128 void SendDetachedEvent();
129
130 // content::NotificationObserver implementation.
131 void Observe(int type,
132 const content::NotificationSource& source,
133 const content::NotificationDetails& details) override;
134
135 // ExtensionRegistryObserver implementation.
136 void OnExtensionUnloaded(content::BrowserContext* browser_context,
137 const Extension* extension,
limasdf0deef2042017-05-03 19:17:17138 UnloadedExtensionReason reason) override;
dgozmand06efdf2015-08-27 02:28:38139
140 Profile* profile_;
141 scoped_refptr<DevToolsAgentHost> agent_host_;
142 std::string extension_id_;
Dmitry Gozman2aec794f2018-03-05 20:27:54143 std::string extension_name_;
dgozmand06efdf2015-08-27 02:28:38144 Debuggee debuggee_;
145 content::NotificationRegistrar registrar_;
146 int last_request_id_;
147 PendingRequests pending_requests_;
dgozman798856d2015-11-19 02:27:22148 ExtensionDevToolsInfoBar* infobar_;
dgozmand06efdf2015-08-27 02:28:38149 api::debugger::DetachReason detach_reason_;
150
151 // Listen to extension unloaded notification.
152 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
153 extension_registry_observer_;
154
155 DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsClientHost);
156};
[email protected]49c71ac2013-05-03 01:36:22157
[email protected]91ba3312011-03-17 20:39:22158ExtensionDevToolsClientHost::ExtensionDevToolsClientHost(
[email protected]ac3851f2013-04-05 15:51:59159 Profile* profile,
160 DevToolsAgentHost* agent_host,
[email protected]91ba3312011-03-17 20:39:22161 const std::string& extension_id,
[email protected]c99c7662011-12-23 12:05:37162 const std::string& extension_name,
dgozmand06efdf2015-08-27 02:28:38163 const Debuggee& debuggee)
[email protected]ac3851f2013-04-05 15:51:59164 : profile_(profile),
165 agent_host_(agent_host),
[email protected]91ba3312011-03-17 20:39:22166 extension_id_(extension_id),
Dmitry Gozman2aec794f2018-03-05 20:27:54167 extension_name_(extension_name),
[email protected]c99c7662011-12-23 12:05:37168 last_request_id_(0),
dgozman798856d2015-11-19 02:27:22169 infobar_(nullptr),
rdevlin.cronin00f1fc22015-04-06 17:19:18170 detach_reason_(api::debugger::DETACH_REASON_TARGET_CLOSED),
[email protected]4edaf7ec2014-05-07 13:54:15171 extension_registry_observer_(this) {
[email protected]28b05ef02013-07-10 22:28:32172 CopyDebuggee(&debuggee_, debuggee);
[email protected]2fefdb32013-02-26 14:28:10173
dgozmand06efdf2015-08-27 02:28:38174 g_attached_client_hosts.Get().insert(this);
[email protected]91ba3312011-03-17 20:39:22175
[email protected]4edaf7ec2014-05-07 13:54:15176 // ExtensionRegistryObserver listen extension unloaded and detach debugger
177 // from there.
[email protected]d32a92652014-05-09 11:06:15178 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
[email protected]91ba3312011-03-17 20:39:22179
[email protected]02ff8ad2013-04-12 13:54:35180 // RVH-based agents disconnect from their clients when the app is terminating
181 // but shared worker-based agents do not.
182 // Disconnect explicitly to make sure that |this| observer is not leaked.
183 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
184 content::NotificationService::AllSources());
Dmitry Gozman2aec794f2018-03-05 20:27:54185}
[email protected]02ff8ad2013-04-12 13:54:35186
Dmitry Gozman2aec794f2018-03-05 20:27:54187bool ExtensionDevToolsClientHost::Attach() {
[email protected]91ba3312011-03-17 20:39:22188 // Attach to debugger and tell it we are ready.
Dmitry Gozman2aec794f2018-03-05 20:27:54189 if (!agent_host_->AttachRestrictedClient(this))
190 return false;
[email protected]c99c7662011-12-23 12:05:37191
pfeldmanc64e1a62017-02-24 01:22:50192 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
dgozmand06efdf2015-08-27 02:28:38193 ::switches::kSilentDebuggerExtensionAPI)) {
Dmitry Gozman2aec794f2018-03-05 20:27:54194 return true;
[email protected]bde11602012-05-04 19:05:42195 }
pfeldmanc64e1a62017-02-24 01:22:50196
197 // We allow policy-installed extensions to circumvent the normal
198 // infobar warning. See crbug.com/693621.
199 const Extension* extension =
Dmitry Gozman2aec794f2018-03-05 20:27:54200 ExtensionRegistry::Get(profile_)->enabled_extensions().GetByID(
201 extension_id_);
202 // TODO(dgozman): null-checking |extension| below is sketchy.
203 // We probably should not allow debugging in this case. Or maybe
204 // it's never null?
pfeldmanc64e1a62017-02-24 01:22:50205 if (extension && Manifest::IsPolicyLocation(extension->location()))
Dmitry Gozman2aec794f2018-03-05 20:27:54206 return true;
pfeldmanc64e1a62017-02-24 01:22:50207
208 infobar_ = ExtensionDevToolsInfoBar::Create(
Dmitry Gozman2aec794f2018-03-05 20:27:54209 extension_id_, extension_name_, this,
pfeldmanc64e1a62017-02-24 01:22:50210 base::Bind(&ExtensionDevToolsClientHost::InfoBarDismissed,
211 base::Unretained(this)));
Dmitry Gozman2aec794f2018-03-05 20:27:54212 return true;
[email protected]91ba3312011-03-17 20:39:22213}
214
215ExtensionDevToolsClientHost::~ExtensionDevToolsClientHost() {
pfeldmand3a885c2015-10-22 23:28:26216 if (infobar_)
dgozman798856d2015-11-19 02:27:22217 infobar_->Remove(this);
dgozmand06efdf2015-08-27 02:28:38218 g_attached_client_hosts.Get().erase(this);
[email protected]91ba3312011-03-17 20:39:22219}
220
[email protected]b50452f2014-08-18 12:31:44221// DevToolsAgentHostClient implementation.
222void ExtensionDevToolsClientHost::AgentHostClosed(
Pavel Feldmana344d932017-10-31 20:24:52223 DevToolsAgentHost* agent_host) {
[email protected]b50452f2014-08-18 12:31:44224 DCHECK(agent_host == agent_host_.get());
Dmitry Gozman2aec794f2018-03-05 20:27:54225 RespondDetachedToPendingRequests();
[email protected]c99c7662011-12-23 12:05:37226 SendDetachedEvent();
[email protected]91ba3312011-03-17 20:39:22227 delete this;
228}
229
[email protected]91ba3312011-03-17 20:39:22230void ExtensionDevToolsClientHost::Close() {
pfeldmanfb8e7472016-06-08 21:13:37231 agent_host_->DetachClient(this);
[email protected]91ba3312011-03-17 20:39:22232 delete this;
233}
234
235void ExtensionDevToolsClientHost::SendMessageToBackend(
[email protected]4636c832013-01-11 02:10:11236 DebuggerSendCommandFunction* function,
[email protected]ac310102011-04-08 14:08:33237 const std::string& method,
[email protected]752960d2012-07-23 19:06:11238 SendCommand::Params::CommandParams* command_params) {
[email protected]aeca23f2013-06-21 22:34:41239 base::DictionaryValue protocol_request;
[email protected]ff31a8a2011-03-30 14:13:59240 int request_id = ++last_request_id_;
241 pending_requests_[request_id] = function;
[email protected]ac310102011-04-08 14:08:33242 protocol_request.SetInteger("id", request_id);
243 protocol_request.SetString("method", method);
[email protected]752960d2012-07-23 19:06:11244 if (command_params) {
vabr9984ea62017-04-10 11:33:49245 protocol_request.Set(
246 "params", command_params->additional_properties.CreateDeepCopy());
[email protected]752960d2012-07-23 19:06:11247 }
[email protected]ff31a8a2011-03-30 14:13:59248
249 std::string json_args;
estade8d046462015-05-16 01:02:34250 base::JSONWriter::Write(protocol_request, &json_args);
pfeldmanfb8e7472016-06-08 21:13:37251 agent_host_->DispatchProtocolMessage(this, json_args);
[email protected]91ba3312011-03-17 20:39:22252}
253
dgozmand06efdf2015-08-27 02:28:38254void ExtensionDevToolsClientHost::InfoBarDismissed() {
rdevlin.cronin00f1fc22015-04-06 17:19:18255 detach_reason_ = api::debugger::DETACH_REASON_CANCELED_BY_USER;
Dmitry Gozman2aec794f2018-03-05 20:27:54256 RespondDetachedToPendingRequests();
dgozmand06efdf2015-08-27 02:28:38257 SendDetachedEvent();
258 Close();
[email protected]87d8a632012-09-20 13:40:39259}
260
Dmitry Gozman2aec794f2018-03-05 20:27:54261void ExtensionDevToolsClientHost::RespondDetachedToPendingRequests() {
262 for (const auto& it : pending_requests_)
263 it.second->SendDetachedError();
264 pending_requests_.clear();
265}
266
[email protected]c99c7662011-12-23 12:05:37267void ExtensionDevToolsClientHost::SendDetachedEvent() {
[email protected]d32a92652014-05-09 11:06:15268 if (!EventRouter::Get(profile_))
[email protected]ac3851f2013-04-05 15:51:59269 return;
270
dchengc963c7142016-04-08 03:55:22271 std::unique_ptr<base::ListValue> args(
272 OnDetach::Create(debuggee_, detach_reason_));
lazyboy59155a42017-05-24 22:23:35273 auto event =
Jinho Bangb5216cec2018-01-17 19:43:11274 std::make_unique<Event>(events::DEBUGGER_ON_DETACH, OnDetach::kEventName,
lazyboy59155a42017-05-24 22:23:35275 std::move(args), profile_);
[email protected]d32a92652014-05-09 11:06:15276 EventRouter::Get(profile_)
dcheng1fc00f12015-12-26 22:18:03277 ->DispatchEventToExtension(extension_id_, std::move(event));
[email protected]c99c7662011-12-23 12:05:37278}
279
[email protected]4edaf7ec2014-05-07 13:54:15280void ExtensionDevToolsClientHost::OnExtensionUnloaded(
281 content::BrowserContext* browser_context,
[email protected]d32a92652014-05-09 11:06:15282 const Extension* extension,
limasdf0deef2042017-05-03 19:17:17283 UnloadedExtensionReason reason) {
[email protected]4edaf7ec2014-05-07 13:54:15284 if (extension->id() == extension_id_)
285 Close();
286}
287
[email protected]91ba3312011-03-17 20:39:22288void ExtensionDevToolsClientHost::Observe(
[email protected]432115822011-07-10 15:52:27289 int type,
[email protected]6c2381d2011-10-19 02:52:53290 const content::NotificationSource& source,
291 const content::NotificationDetails& details) {
dgozmand06efdf2015-08-27 02:28:38292 DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
293 Close();
[email protected]91ba3312011-03-17 20:39:22294}
295
[email protected]b50452f2014-08-18 12:31:44296void ExtensionDevToolsClientHost::DispatchProtocolMessage(
297 DevToolsAgentHost* agent_host, const std::string& message) {
298 DCHECK(agent_host == agent_host_.get());
[email protected]d32a92652014-05-09 11:06:15299 if (!EventRouter::Get(profile_))
[email protected]ff31a8a2011-03-30 14:13:59300 return;
[email protected]91ba3312011-03-17 20:39:22301
dchengc963c7142016-04-08 03:55:22302 std::unique_ptr<base::Value> result = base::JSONReader::Read(message);
jdoerrie1f536b22017-10-23 17:15:11303 if (!result || !result->is_dict())
[email protected]ff31a8a2011-03-30 14:13:59304 return;
[email protected]aeca23f2013-06-21 22:34:41305 base::DictionaryValue* dictionary =
306 static_cast<base::DictionaryValue*>(result.get());
[email protected]ff31a8a2011-03-30 14:13:59307
[email protected]ac310102011-04-08 14:08:33308 int id;
309 if (!dictionary->GetInteger("id", &id)) {
310 std::string method_name;
311 if (!dictionary->GetString("method", &method_name))
[email protected]7d713ec2011-04-01 14:22:02312 return;
313
[email protected]752960d2012-07-23 19:06:11314 OnEvent::Params params;
[email protected]aeca23f2013-06-21 22:34:41315 base::DictionaryValue* params_value;
[email protected]752960d2012-07-23 19:06:11316 if (dictionary->GetDictionary("params", &params_value))
317 params.additional_properties.Swap(params_value);
318
dchengc963c7142016-04-08 03:55:22319 std::unique_ptr<base::ListValue> args(
[email protected]5bcdd99d2013-12-23 18:28:30320 OnEvent::Create(debuggee_, method_name, params));
lazyboy59155a42017-05-24 22:23:35321 auto event =
Jinho Bangb5216cec2018-01-17 19:43:11322 std::make_unique<Event>(events::DEBUGGER_ON_EVENT, OnEvent::kEventName,
lazyboy59155a42017-05-24 22:23:35323 std::move(args), profile_);
[email protected]d32a92652014-05-09 11:06:15324 EventRouter::Get(profile_)
dcheng1fc00f12015-12-26 22:18:03325 ->DispatchEventToExtension(extension_id_, std::move(event));
[email protected]ac310102011-04-08 14:08:33326 } else {
[email protected]dc24976f2013-06-02 21:15:09327 DebuggerSendCommandFunction* function = pending_requests_[id].get();
[email protected]ac310102011-04-08 14:08:33328 if (!function)
329 return;
330
331 function->SendResponseBody(dictionary);
332 pending_requests_.erase(id);
[email protected]91ba3312011-03-17 20:39:22333 }
334}
335
[email protected]49c71ac2013-05-03 01:36:22336
337// DebuggerFunction -----------------------------------------------------------
338
[email protected]91ba3312011-03-17 20:39:22339DebuggerFunction::DebuggerFunction()
[email protected]19bcf9d2013-07-18 22:00:59340 : client_host_(NULL) {
[email protected]ac3851f2013-04-05 15:51:59341}
342
343DebuggerFunction::~DebuggerFunction() {
[email protected]91ba3312011-03-17 20:39:22344}
345
[email protected]2fefdb32013-02-26 14:28:10346void DebuggerFunction::FormatErrorMessage(const std::string& format) {
[email protected]56cc38042013-04-03 04:42:47347 if (debuggee_.tab_id)
348 error_ = ErrorUtils::FormatErrorMessage(
349 format, keys::kTabTargetType, base::IntToString(*debuggee_.tab_id));
350 else if (debuggee_.extension_id)
351 error_ = ErrorUtils::FormatErrorMessage(
352 format, keys::kBackgroundPageTargetType, *debuggee_.extension_id);
353 else
354 error_ = ErrorUtils::FormatErrorMessage(
355 format, keys::kOpaqueTargetType, *debuggee_.target_id);
[email protected]2fefdb32013-02-26 14:28:10356}
357
[email protected]ac3851f2013-04-05 15:51:59358bool DebuggerFunction::InitAgentHost() {
[email protected]2fefdb32013-02-26 14:28:10359 if (debuggee_.tab_id) {
360 WebContents* web_contents = NULL;
[email protected]d32a92652014-05-09 11:06:15361 bool result = ExtensionTabUtil::GetTabById(*debuggee_.tab_id,
362 GetProfile(),
363 include_incognito(),
364 NULL,
365 NULL,
366 &web_contents,
367 NULL);
[email protected]56cc38042013-04-03 04:42:47368 if (result && web_contents) {
[email protected]684a212a2014-06-27 17:14:50369 // TODO(rdevlin.cronin) This should definitely be GetLastCommittedURL().
370 GURL url = web_contents->GetVisibleURL();
rdevlin.croninf994d1e2015-06-03 22:28:19371 if (PermissionsData::IsRestrictedUrl(url, extension(), &error_))
[email protected]56cc38042013-04-03 04:42:47372 return false;
[email protected]02a67fd2014-03-28 15:29:55373 agent_host_ = DevToolsAgentHost::GetOrCreateFor(web_contents);
[email protected]2fefdb32013-02-26 14:28:10374 }
[email protected]56cc38042013-04-03 04:42:47375 } else if (debuggee_.extension_id) {
[email protected]d32a92652014-05-09 11:06:15376 ExtensionHost* extension_host =
reillyg0ea3fa902014-10-28 15:30:23377 ProcessManager::Get(GetProfile())
[email protected]21a40082013-10-28 21:19:23378 ->GetBackgroundHostForExtension(*debuggee_.extension_id);
[email protected]56cc38042013-04-03 04:42:47379 if (extension_host) {
[email protected]684a212a2014-06-27 17:14:50380 if (PermissionsData::IsRestrictedUrl(extension_host->GetURL(),
[email protected]eba8f7d2014-07-28 22:09:23381 extension(),
[email protected]684a212a2014-06-27 17:14:50382 &error_)) {
383 return false;
384 }
[email protected]b3f957e62014-08-08 10:09:02385 agent_host_ =
386 DevToolsAgentHost::GetOrCreateFor(extension_host->host_contents());
[email protected]30e246b2013-03-28 17:08:48387 }
[email protected]56cc38042013-04-03 04:42:47388 } else if (debuggee_.target_id) {
[email protected]ac3851f2013-04-05 15:51:59389 agent_host_ = DevToolsAgentHost::GetForId(*debuggee_.target_id);
rob409bf9d62015-02-10 23:37:07390 if (agent_host_.get()) {
391 if (PermissionsData::IsRestrictedUrl(agent_host_->GetURL(),
rob409bf9d62015-02-10 23:37:07392 extension(),
393 &error_)) {
394 agent_host_ = nullptr;
395 return false;
396 }
397 }
[email protected]56cc38042013-04-03 04:42:47398 } else {
399 error_ = keys::kInvalidTargetError;
[email protected]4e023cd2013-03-28 15:04:12400 return false;
401 }
[email protected]30e246b2013-03-28 17:08:48402
[email protected]dc24976f2013-06-02 21:15:09403 if (!agent_host_.get()) {
[email protected]56cc38042013-04-03 04:42:47404 FormatErrorMessage(keys::kNoTargetError);
405 return false;
406 }
407 return true;
[email protected]91ba3312011-03-17 20:39:22408}
409
[email protected]c7580b62011-10-26 08:46:30410bool DebuggerFunction::InitClientHost() {
[email protected]ac3851f2013-04-05 15:51:59411 if (!InitAgentHost())
[email protected]91ba3312011-03-17 20:39:22412 return false;
413
Dmitry Gozmaned41e022017-08-24 20:12:10414 client_host_ = FindClientHost();
415 if (!client_host_) {
416 FormatErrorMessage(keys::kNotAttachedError);
417 return false;
418 }
419
420 return true;
421}
422
423ExtensionDevToolsClientHost* DebuggerFunction::FindClientHost() {
424 if (!agent_host_.get())
425 return nullptr;
426
dgozmand06efdf2015-08-27 02:28:38427 const std::string& extension_id = extension()->id();
428 DevToolsAgentHost* agent_host = agent_host_.get();
429 AttachedClientHosts& hosts = g_attached_client_hosts.Get();
430 AttachedClientHosts::iterator it = std::find_if(
431 hosts.begin(), hosts.end(),
432 [&agent_host, &extension_id](ExtensionDevToolsClientHost* client_host) {
433 return client_host->agent_host() == agent_host &&
434 client_host->extension_id() == extension_id;
435 });
[email protected]91ba3312011-03-17 20:39:22436
Dmitry Gozmaned41e022017-08-24 20:12:10437 return it == hosts.end() ? nullptr : *it;
[email protected]91ba3312011-03-17 20:39:22438}
439
[email protected]49c71ac2013-05-03 01:36:22440// DebuggerAttachFunction -----------------------------------------------------
441
[email protected]28b05ef02013-07-10 22:28:32442DebuggerAttachFunction::DebuggerAttachFunction() {
443}
[email protected]91ba3312011-03-17 20:39:22444
[email protected]28b05ef02013-07-10 22:28:32445DebuggerAttachFunction::~DebuggerAttachFunction() {
446}
[email protected]91ba3312011-03-17 20:39:22447
[email protected]a0c91a9f2014-05-03 03:41:43448bool DebuggerAttachFunction::RunAsync() {
dchengc963c7142016-04-08 03:55:22449 std::unique_ptr<Attach::Params> params(Attach::Params::Create(*args_));
[email protected]752960d2012-07-23 19:06:11450 EXTENSION_FUNCTION_VALIDATE(params.get());
451
[email protected]28b05ef02013-07-10 22:28:32452 CopyDebuggee(&debuggee_, params->target);
[email protected]ac3851f2013-04-05 15:51:59453 if (!InitAgentHost())
[email protected]91ba3312011-03-17 20:39:22454 return false;
455
dgozman102fee92015-04-20 15:45:46456 if (!DevToolsAgentHost::IsSupportedProtocolVersion(
[email protected]be3577e2013-06-26 21:42:33457 params->required_version)) {
[email protected]e9f541a2012-11-19 21:52:31458 error_ = ErrorUtils::FormatErrorMessage(
[email protected]c7580b62011-10-26 08:46:30459 keys::kProtocolVersionNotSupportedError,
[email protected]752960d2012-07-23 19:06:11460 params->required_version);
[email protected]c7580b62011-10-26 08:46:30461 return false;
462 }
463
Dmitry Gozmaned41e022017-08-24 20:12:10464 if (FindClientHost()) {
[email protected]2fefdb32013-02-26 14:28:10465 FormatErrorMessage(keys::kAlreadyAttachedError);
[email protected]91ba3312011-03-17 20:39:22466 return false;
467 }
468
Dmitry Gozman2aec794f2018-03-05 20:27:54469 auto host = std::make_unique<ExtensionDevToolsClientHost>(
470 GetProfile(), agent_host_.get(), extension()->id(), extension()->name(),
471 debuggee_);
472
473 if (!host->Attach()) {
474 FormatErrorMessage(keys::kRestrictedError);
475 return false;
476 }
477
478 host.release(); // An attached client host manages its own lifetime.
[email protected]ff31a8a2011-03-30 14:13:59479 SendResponse(true);
[email protected]91ba3312011-03-17 20:39:22480 return true;
481}
482
[email protected]49c71ac2013-05-03 01:36:22483
484// DebuggerDetachFunction -----------------------------------------------------
485
[email protected]28b05ef02013-07-10 22:28:32486DebuggerDetachFunction::DebuggerDetachFunction() {
487}
[email protected]91ba3312011-03-17 20:39:22488
[email protected]28b05ef02013-07-10 22:28:32489DebuggerDetachFunction::~DebuggerDetachFunction() {
490}
[email protected]91ba3312011-03-17 20:39:22491
[email protected]a0c91a9f2014-05-03 03:41:43492bool DebuggerDetachFunction::RunAsync() {
dchengc963c7142016-04-08 03:55:22493 std::unique_ptr<Detach::Params> params(Detach::Params::Create(*args_));
[email protected]752960d2012-07-23 19:06:11494 EXTENSION_FUNCTION_VALIDATE(params.get());
495
[email protected]28b05ef02013-07-10 22:28:32496 CopyDebuggee(&debuggee_, params->target);
[email protected]c7580b62011-10-26 08:46:30497 if (!InitClientHost())
[email protected]91ba3312011-03-17 20:39:22498 return false;
499
Dmitry Gozman2aec794f2018-03-05 20:27:54500 client_host_->RespondDetachedToPendingRequests();
[email protected]91ba3312011-03-17 20:39:22501 client_host_->Close();
[email protected]ff31a8a2011-03-30 14:13:59502 SendResponse(true);
[email protected]91ba3312011-03-17 20:39:22503 return true;
504}
505
[email protected]49c71ac2013-05-03 01:36:22506
507// DebuggerSendCommandFunction ------------------------------------------------
508
[email protected]28b05ef02013-07-10 22:28:32509DebuggerSendCommandFunction::DebuggerSendCommandFunction() {
510}
[email protected]91ba3312011-03-17 20:39:22511
[email protected]28b05ef02013-07-10 22:28:32512DebuggerSendCommandFunction::~DebuggerSendCommandFunction() {
513}
[email protected]91ba3312011-03-17 20:39:22514
[email protected]a0c91a9f2014-05-03 03:41:43515bool DebuggerSendCommandFunction::RunAsync() {
dchengc963c7142016-04-08 03:55:22516 std::unique_ptr<SendCommand::Params> params(
517 SendCommand::Params::Create(*args_));
[email protected]752960d2012-07-23 19:06:11518 EXTENSION_FUNCTION_VALIDATE(params.get());
[email protected]91ba3312011-03-17 20:39:22519
[email protected]28b05ef02013-07-10 22:28:32520 CopyDebuggee(&debuggee_, params->target);
[email protected]c7580b62011-10-26 08:46:30521 if (!InitClientHost())
[email protected]91ba3312011-03-17 20:39:22522 return false;
523
[email protected]752960d2012-07-23 19:06:11524 client_host_->SendMessageToBackend(this, params->method,
525 params->command_params.get());
[email protected]91ba3312011-03-17 20:39:22526 return true;
527}
[email protected]ff31a8a2011-03-30 14:13:59528
[email protected]4636c832013-01-11 02:10:11529void DebuggerSendCommandFunction::SendResponseBody(
[email protected]aeca23f2013-06-21 22:34:41530 base::DictionaryValue* response) {
[email protected]5bcdd99d2013-12-23 18:28:30531 base::Value* error_body;
[email protected]752960d2012-07-23 19:06:11532 if (response->Get("error", &error_body)) {
estade8d046462015-05-16 01:02:34533 base::JSONWriter::Write(*error_body, &error_);
[email protected]ff31a8a2011-03-30 14:13:59534 SendResponse(false);
535 return;
536 }
537
[email protected]aeca23f2013-06-21 22:34:41538 base::DictionaryValue* result_body;
[email protected]752960d2012-07-23 19:06:11539 SendCommand::Results::Result result;
540 if (response->GetDictionary("result", &result_body))
541 result.additional_properties.Swap(result_body);
542
543 results_ = SendCommand::Results::Create(result);
[email protected]ff31a8a2011-03-30 14:13:59544 SendResponse(true);
545}
[email protected]56cc38042013-04-03 04:42:47546
Dmitry Gozman2aec794f2018-03-05 20:27:54547void DebuggerSendCommandFunction::SendDetachedError() {
548 error_ = keys::kDetachedWhileHandlingError;
549 SendResponse(false);
550}
[email protected]49c71ac2013-05-03 01:36:22551
552// DebuggerGetTargetsFunction -------------------------------------------------
553
[email protected]28b05ef02013-07-10 22:28:32554namespace {
[email protected]56cc38042013-04-03 04:42:47555
[email protected]28b05ef02013-07-10 22:28:32556const char kTargetIdField[] = "id";
557const char kTargetTypeField[] = "type";
558const char kTargetTitleField[] = "title";
559const char kTargetAttachedField[] = "attached";
560const char kTargetUrlField[] = "url";
561const char kTargetFaviconUrlField[] = "faviconUrl";
[email protected]f80e0be62013-07-17 14:17:23562const char kTargetTabIdField[] = "tabId";
563const char kTargetExtensionIdField[] = "extensionId";
pfeldmana9e7dda2016-08-26 14:35:17564const char kTargetTypeWorker[] = "worker";
[email protected]28b05ef02013-07-10 22:28:32565
dchengf19502002016-09-14 15:18:18566std::unique_ptr<base::DictionaryValue> SerializeTarget(
567 scoped_refptr<DevToolsAgentHost> host) {
568 std::unique_ptr<base::DictionaryValue> dictionary(
569 new base::DictionaryValue());
pfeldmana9e7dda2016-08-26 14:35:17570 dictionary->SetString(kTargetIdField, host->GetId());
571 dictionary->SetString(kTargetTitleField, host->GetTitle());
572 dictionary->SetBoolean(kTargetAttachedField, host->IsAttached());
573 dictionary->SetString(kTargetUrlField, host->GetURL().spec());
[email protected]28b05ef02013-07-10 22:28:32574
pfeldmana9e7dda2016-08-26 14:35:17575 std::string type = host->GetType();
576 if (type == DevToolsAgentHost::kTypePage) {
577 int tab_id =
578 extensions::ExtensionTabUtil::GetTabId(host->GetWebContents());
579 dictionary->SetInteger(kTargetTabIdField, tab_id);
580 } else if (type == ChromeDevToolsManagerDelegate::kTypeBackgroundPage) {
581 dictionary->SetString(kTargetExtensionIdField, host->GetURL().host());
[email protected]28b05ef02013-07-10 22:28:32582 }
pfeldmana9e7dda2016-08-26 14:35:17583
584 if (type == DevToolsAgentHost::kTypeServiceWorker ||
585 type == DevToolsAgentHost::kTypeSharedWorker) {
586 type = kTargetTypeWorker;
587 }
588
[email protected]06d503f2013-10-29 17:29:37589 dictionary->SetString(kTargetTypeField, type);
[email protected]28b05ef02013-07-10 22:28:32590
pfeldmana9e7dda2016-08-26 14:35:17591 GURL favicon_url = host->GetFaviconURL();
[email protected]06d503f2013-10-29 17:29:37592 if (favicon_url.is_valid())
593 dictionary->SetString(kTargetFaviconUrlField, favicon_url.spec());
[email protected]28b05ef02013-07-10 22:28:32594
595 return dictionary;
596}
597
[email protected]4edaf7ec2014-05-07 13:54:15598} // namespace
[email protected]28b05ef02013-07-10 22:28:32599
600DebuggerGetTargetsFunction::DebuggerGetTargetsFunction() {
601}
602
603DebuggerGetTargetsFunction::~DebuggerGetTargetsFunction() {
604}
[email protected]56cc38042013-04-03 04:42:47605
[email protected]a0c91a9f2014-05-03 03:41:43606bool DebuggerGetTargetsFunction::RunAsync() {
pfeldmanbc5d7882016-08-26 18:55:46607 content::DevToolsAgentHost::List list = DevToolsAgentHost::GetOrCreateAll();
dgozmancb088d02015-04-28 11:57:45608 content::BrowserThread::PostTask(
tzik8d880ee2017-04-20 19:46:24609 content::BrowserThread::UI, FROM_HERE,
610 base::BindOnce(&DebuggerGetTargetsFunction::SendTargetList, this, list));
[email protected]56cc38042013-04-03 04:42:47611 return true;
612}
[email protected]ac3851f2013-04-05 15:51:59613
[email protected]fe38b1e2013-10-02 23:43:34614void DebuggerGetTargetsFunction::SendTargetList(
pfeldmanbc5d7882016-08-26 18:55:46615 const content::DevToolsAgentHost::List& target_list) {
dchengc963c7142016-04-08 03:55:22616 std::unique_ptr<base::ListValue> result(new base::ListValue());
[email protected]06d503f2013-10-29 17:29:37617 for (size_t i = 0; i < target_list.size(); ++i)
pfeldmanbc5d7882016-08-26 18:55:46618 result->Append(SerializeTarget(target_list[i]));
dcheng85f24da2016-05-20 22:20:26619 SetResult(std::move(result));
[email protected]ac3851f2013-04-05 15:51:59620 SendResponse(true);
621}
[email protected]d32a92652014-05-09 11:06:15622
623} // namespace extensions