blob: 9acec23bd6f887de811d8c039a141d7269b11ecf [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
[email protected]ff31a8a2011-03-30 14:13:599#include <map>
[email protected]91ba3312011-03-17 20:39:2210#include <set>
11
[email protected]2fefdb32013-02-26 14:28:1012#include "base/command_line.h"
[email protected]ff31a8a2011-03-30 14:13:5913#include "base/json/json_reader.h"
[email protected]91ba3312011-03-17 20:39:2214#include "base/json/json_writer.h"
[email protected]752960d2012-07-23 19:06:1115#include "base/memory/scoped_ptr.h"
[email protected]3b63f8f42011-03-28 01:54:1516#include "base/memory/singleton.h"
[email protected]4edaf7ec2014-05-07 13:54:1517#include "base/scoped_observer.h"
[email protected]06d503f2013-10-29 17:29:3718#include "base/stl_util.h"
[email protected]3ea1b182013-02-08 22:38:4119#include "base/strings/string_number_conversions.h"
[email protected]135cb802013-06-09 16:44:2020#include "base/strings/utf_string_conversions.h"
[email protected]91ba3312011-03-17 20:39:2221#include "base/values.h"
[email protected]49a01e642013-07-12 00:29:4522#include "chrome/browser/chrome_notification_types.h"
[email protected]06d503f2013-10-29 17:29:3723#include "chrome/browser/devtools/devtools_target_impl.h"
[email protected]1eb8f2f2012-07-12 02:04:4924#include "chrome/browser/extensions/api/debugger/debugger_api_constants.h"
[email protected]2fefdb32013-02-26 14:28:1025#include "chrome/browser/extensions/extension_service.h"
[email protected]ac84431b2011-09-27 17:26:1126#include "chrome/browser/extensions/extension_tab_util.h"
[email protected]4a8adfa02013-03-19 22:37:4627#include "chrome/browser/infobars/infobar_service.h"
[email protected]91ba3312011-03-17 20:39:2228#include "chrome/browser/profiles/profile.h"
[email protected]863f70a2012-01-27 02:05:5029#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
[email protected]2fefdb32013-02-26 14:28:1030#include "chrome/common/chrome_switches.h"
[email protected]af39f002014-08-22 10:18:1831#include "chrome/grit/generated_resources.h"
[email protected]f9b21602014-05-22 00:53:1232#include "components/infobars/core/confirm_infobar_delegate.h"
[email protected]051655ad2014-04-18 15:09:4133#include "components/infobars/core/infobar.h"
[email protected]98f66112012-12-25 12:59:3634#include "content/public/browser/devtools_agent_host.h"
[email protected]be3577e2013-06-26 21:42:3335#include "content/public/browser/devtools_http_handler.h"
[email protected]1c3bd202011-12-23 05:48:2436#include "content/public/browser/notification_service.h"
[email protected]ad50def52011-10-19 23:17:0737#include "content/public/browser/notification_source.h"
[email protected]2fefdb32013-02-26 14:28:1038#include "content/public/browser/render_process_host.h"
[email protected]9c1662b2012-03-06 15:44:3339#include "content/public/browser/render_view_host.h"
[email protected]2fefdb32013-02-26 14:28:1040#include "content/public/browser/render_widget_host.h"
[email protected]ef9572e2012-01-04 22:14:1241#include "content/public/browser/web_contents.h"
[email protected]744c2a22012-03-15 18:42:0442#include "content/public/common/content_client.h"
[email protected]3b366ae2013-05-17 21:16:5843#include "content/public/common/url_utils.h"
[email protected]34423532013-11-21 18:13:1044#include "extensions/browser/event_router.h"
[email protected]22401dc2014-03-21 01:38:5745#include "extensions/browser/extension_host.h"
[email protected]4edaf7ec2014-05-07 13:54:1546#include "extensions/browser/extension_registry.h"
47#include "extensions/browser/extension_registry_observer.h"
[email protected]684a212a2014-06-27 17:14:5048#include "extensions/common/constants.h"
[email protected]e9f541a2012-11-19 21:52:3149#include "extensions/common/error_utils.h"
[email protected]e4452d32013-11-15 23:07:4150#include "extensions/common/extension.h"
[email protected]684a212a2014-06-27 17:14:5051#include "extensions/common/manifest_constants.h"
52#include "extensions/common/permissions/permissions_data.h"
53#include "extensions/common/switches.h"
[email protected]c99c7662011-12-23 12:05:3754#include "ui/base/l10n/l10n_util.h"
[email protected]91ba3312011-03-17 20:39:2255
[email protected]0e12d7d2011-12-01 16:21:4456using content::DevToolsAgentHost;
[email protected]be3577e2013-06-26 21:42:3357using content::DevToolsHttpHandler;
[email protected]2fefdb32013-02-26 14:28:1058using content::RenderProcessHost;
59using content::RenderViewHost;
60using 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;
[email protected]49c71ac2013-05-03 01:36:2272
73// ExtensionDevToolsClientHost ------------------------------------------------
74
[email protected]b50452f2014-08-18 12:31:4475class ExtensionDevToolsClientHost : public content::DevToolsAgentHostClient,
[email protected]d32a92652014-05-09 11:06:1576 public content::NotificationObserver,
77 public ExtensionRegistryObserver {
[email protected]91ba3312011-03-17 20:39:2278 public:
[email protected]051655ad2014-04-18 15:09:4179 ExtensionDevToolsClientHost(Profile* profile,
80 DevToolsAgentHost* agent_host,
81 const std::string& extension_id,
82 const std::string& extension_name,
83 const Debuggee& debuggee,
84 infobars::InfoBar* infobar);
[email protected]91ba3312011-03-17 20:39:2285
dchengae36a4a2014-10-21 12:36:3686 ~ExtensionDevToolsClientHost() override;
[email protected]91ba3312011-03-17 20:39:2287
[email protected]ac3851f2013-04-05 15:51:5988 const std::string& extension_id() { return extension_id_; }
[email protected]b50452f2014-08-18 12:31:4489 DevToolsAgentHost* agent_host() { return agent_host_.get(); }
[email protected]91ba3312011-03-17 20:39:2290 void Close();
[email protected]4636c832013-01-11 02:10:1191 void SendMessageToBackend(DebuggerSendCommandFunction* function,
[email protected]ac310102011-04-08 14:08:3392 const std::string& method,
[email protected]752960d2012-07-23 19:06:1193 SendCommand::Params::CommandParams* command_params);
[email protected]91ba3312011-03-17 20:39:2294
[email protected]b3b26072012-11-02 11:20:5195 // Marks connection as to-be-terminated by the user.
[email protected]87d8a632012-09-20 13:40:3996 void MarkAsDismissed();
97
[email protected]b50452f2014-08-18 12:31:4498 // DevToolsAgentHostClient interface.
dchengae36a4a2014-10-21 12:36:3699 void AgentHostClosed(DevToolsAgentHost* agent_host,
100 bool replaced_with_another_client) override;
101 void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
102 const std::string& message) override;
[email protected]91ba3312011-03-17 20:39:22103
104 private:
[email protected]c99c7662011-12-23 12:05:37105 void SendDetachedEvent();
106
[email protected]6c2381d2011-10-19 02:52:53107 // content::NotificationObserver implementation.
dchengae36a4a2014-10-21 12:36:36108 void Observe(int type,
109 const content::NotificationSource& source,
110 const content::NotificationDetails& details) override;
[email protected]91ba3312011-03-17 20:39:22111
[email protected]d32a92652014-05-09 11:06:15112 // ExtensionRegistryObserver implementation.
dchengae36a4a2014-10-21 12:36:36113 void OnExtensionUnloaded(content::BrowserContext* browser_context,
114 const Extension* extension,
115 UnloadedExtensionInfo::Reason reason) override;
[email protected]4edaf7ec2014-05-07 13:54:15116
[email protected]ac3851f2013-04-05 15:51:59117 Profile* profile_;
118 scoped_refptr<DevToolsAgentHost> agent_host_;
[email protected]91ba3312011-03-17 20:39:22119 std::string extension_id_;
[email protected]2fefdb32013-02-26 14:28:10120 Debuggee debuggee_;
[email protected]6c2381d2011-10-19 02:52:53121 content::NotificationRegistrar registrar_;
[email protected]ff31a8a2011-03-30 14:13:59122 int last_request_id_;
[email protected]4636c832013-01-11 02:10:11123 typedef std::map<int, scoped_refptr<DebuggerSendCommandFunction> >
[email protected]ff31a8a2011-03-30 14:13:59124 PendingRequests;
125 PendingRequests pending_requests_;
[email protected]051655ad2014-04-18 15:09:41126 infobars::InfoBar* infobar_;
rdevlin.cronin00f1fc22015-04-06 17:19:18127 api::debugger::DetachReason detach_reason_;
[email protected]91ba3312011-03-17 20:39:22128
[email protected]4edaf7ec2014-05-07 13:54:15129 // Listen to extension unloaded notification.
[email protected]d32a92652014-05-09 11:06:15130 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
[email protected]4edaf7ec2014-05-07 13:54:15131 extension_registry_observer_;
132
[email protected]91ba3312011-03-17 20:39:22133 DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsClientHost);
134};
135
[email protected]19bcf9d2013-07-18 22:00:59136// The member function declarations come after the other class declarations, so
137// they can call members on them.
138
139
140namespace {
141
142// Helpers --------------------------------------------------------------------
143
144void CopyDebuggee(Debuggee* dst, const Debuggee& src) {
145 if (src.tab_id)
146 dst->tab_id.reset(new int(*src.tab_id));
147 if (src.extension_id)
148 dst->extension_id.reset(new std::string(*src.extension_id));
149 if (src.target_id)
150 dst->target_id.reset(new std::string(*src.target_id));
151}
152
[email protected]49c71ac2013-05-03 01:36:22153
154// ExtensionDevToolsInfoBarDelegate -------------------------------------------
155
[email protected]da0ade72013-04-30 01:02:53156class ExtensionDevToolsInfoBarDelegate : public ConfirmInfoBarDelegate {
157 public:
[email protected]39308cb2013-12-06 03:01:48158 // Creates an extension dev tools infobar and delegate and adds the infobar to
159 // the InfoBarService associated with |rvh|. Returns the infobar if it was
[email protected]19bcf9d2013-07-18 22:00:59160 // successfully added.
[email protected]b3f957e62014-08-08 10:09:02161 static infobars::InfoBar* Create(WebContents* web_contents,
[email protected]051655ad2014-04-18 15:09:41162 const std::string& client_name);
[email protected]da0ade72013-04-30 01:02:53163
[email protected]28b05ef02013-07-10 22:28:32164 void set_client_host(ExtensionDevToolsClientHost* client_host) {
165 client_host_ = client_host;
166 }
[email protected]da0ade72013-04-30 01:02:53167
168 private:
[email protected]39308cb2013-12-06 03:01:48169 explicit ExtensionDevToolsInfoBarDelegate(const std::string& client_name);
dchengae36a4a2014-10-21 12:36:36170 ~ExtensionDevToolsInfoBarDelegate() override;
[email protected]da0ade72013-04-30 01:02:53171
172 // ConfirmInfoBarDelegate:
dchengae36a4a2014-10-21 12:36:36173 Type GetInfoBarType() const override;
pkastingbdbf3b12015-02-24 00:18:27174 void InfoBarDismissed() override;
dchengae36a4a2014-10-21 12:36:36175 bool ShouldExpireInternal(const NavigationDetails& details) const override;
176 base::string16 GetMessageText() const override;
177 int GetButtons() const override;
178 bool Cancel() override;
[email protected]da0ade72013-04-30 01:02:53179
180 std::string client_name_;
181 ExtensionDevToolsClientHost* client_host_;
[email protected]49c71ac2013-05-03 01:36:22182
[email protected]da0ade72013-04-30 01:02:53183 DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsInfoBarDelegate);
184};
185
186// static
[email protected]051655ad2014-04-18 15:09:41187infobars::InfoBar* ExtensionDevToolsInfoBarDelegate::Create(
[email protected]b3f957e62014-08-08 10:09:02188 WebContents* web_contents,
[email protected]da0ade72013-04-30 01:02:53189 const std::string& client_name) {
[email protected]da0ade72013-04-30 01:02:53190 if (!web_contents)
191 return NULL;
192
193 InfoBarService* infobar_service =
194 InfoBarService::FromWebContents(web_contents);
195 if (!infobar_service)
196 return NULL;
197
sdefresne316da452014-12-22 17:30:59198 return infobar_service->AddInfoBar(
199 infobar_service->CreateConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
[email protected]39308cb2013-12-06 03:01:48200 new ExtensionDevToolsInfoBarDelegate(client_name))));
[email protected]da0ade72013-04-30 01:02:53201}
202
[email protected]da0ade72013-04-30 01:02:53203ExtensionDevToolsInfoBarDelegate::ExtensionDevToolsInfoBarDelegate(
[email protected]da0ade72013-04-30 01:02:53204 const std::string& client_name)
[email protected]39308cb2013-12-06 03:01:48205 : ConfirmInfoBarDelegate(),
[email protected]da0ade72013-04-30 01:02:53206 client_name_(client_name),
207 client_host_(NULL) {
208}
209
210ExtensionDevToolsInfoBarDelegate::~ExtensionDevToolsInfoBarDelegate() {
211}
212
[email protected]051655ad2014-04-18 15:09:41213infobars::InfoBarDelegate::Type
214ExtensionDevToolsInfoBarDelegate::GetInfoBarType() const {
[email protected]da0ade72013-04-30 01:02:53215 return WARNING_TYPE;
216}
217
pkastingbdbf3b12015-02-24 00:18:27218void ExtensionDevToolsInfoBarDelegate::InfoBarDismissed() {
219 if (client_host_)
220 client_host_->MarkAsDismissed();
221}
222
[email protected]da0ade72013-04-30 01:02:53223bool ExtensionDevToolsInfoBarDelegate::ShouldExpireInternal(
[email protected]5daf1d92014-04-04 15:52:13224 const NavigationDetails& details) const {
[email protected]da0ade72013-04-30 01:02:53225 return false;
226}
227
[email protected]6a72a632013-12-12 22:22:00228base::string16 ExtensionDevToolsInfoBarDelegate::GetMessageText() const {
[email protected]da0ade72013-04-30 01:02:53229 return l10n_util::GetStringFUTF16(IDS_DEV_TOOLS_INFOBAR_LABEL,
[email protected]04338722013-12-24 23:18:05230 base::UTF8ToUTF16(client_name_));
[email protected]da0ade72013-04-30 01:02:53231}
232
[email protected]d5a4c9ef2013-04-30 03:05:24233int ExtensionDevToolsInfoBarDelegate::GetButtons() const {
234 return BUTTON_CANCEL;
[email protected]da0ade72013-04-30 01:02:53235}
236
237bool ExtensionDevToolsInfoBarDelegate::Cancel() {
[email protected]19bcf9d2013-07-18 22:00:59238 InfoBarDismissed();
[email protected]da0ade72013-04-30 01:02:53239 return true;
240}
241
[email protected]49c71ac2013-05-03 01:36:22242
[email protected]49c71ac2013-05-03 01:36:22243// AttachedClientHosts --------------------------------------------------------
244
[email protected]91ba3312011-03-17 20:39:22245class AttachedClientHosts {
246 public:
[email protected]49c71ac2013-05-03 01:36:22247 AttachedClientHosts();
[email protected]28b05ef02013-07-10 22:28:32248 ~AttachedClientHosts();
[email protected]91ba3312011-03-17 20:39:22249
[email protected]28b05ef02013-07-10 22:28:32250 // Returns the singleton instance of this class.
[email protected]49c71ac2013-05-03 01:36:22251 static AttachedClientHosts* GetInstance();
[email protected]91ba3312011-03-17 20:39:22252
[email protected]49c71ac2013-05-03 01:36:22253 void Add(ExtensionDevToolsClientHost* client_host);
254 void Remove(ExtensionDevToolsClientHost* client_host);
[email protected]ac3851f2013-04-05 15:51:59255 ExtensionDevToolsClientHost* Lookup(DevToolsAgentHost* agent_host,
[email protected]49c71ac2013-05-03 01:36:22256 const std::string& extension_id);
[email protected]91ba3312011-03-17 20:39:22257
258 private:
[email protected]28b05ef02013-07-10 22:28:32259 typedef std::set<ExtensionDevToolsClientHost*> ClientHosts;
260 ClientHosts client_hosts_;
[email protected]49c71ac2013-05-03 01:36:22261
262 DISALLOW_COPY_AND_ASSIGN(AttachedClientHosts);
[email protected]91ba3312011-03-17 20:39:22263};
264
[email protected]49c71ac2013-05-03 01:36:22265AttachedClientHosts::AttachedClientHosts() {
266}
267
[email protected]28b05ef02013-07-10 22:28:32268AttachedClientHosts::~AttachedClientHosts() {
269}
[email protected]19bcf9d2013-07-18 22:00:59270
[email protected]49c71ac2013-05-03 01:36:22271// static
272AttachedClientHosts* AttachedClientHosts::GetInstance() {
273 return Singleton<AttachedClientHosts>::get();
274}
275
276void AttachedClientHosts::Add(ExtensionDevToolsClientHost* client_host) {
277 client_hosts_.insert(client_host);
278}
279
280void AttachedClientHosts::Remove(ExtensionDevToolsClientHost* client_host) {
281 client_hosts_.erase(client_host);
282}
283
284ExtensionDevToolsClientHost* AttachedClientHosts::Lookup(
285 DevToolsAgentHost* agent_host,
286 const std::string& extension_id) {
[email protected]28b05ef02013-07-10 22:28:32287 for (ClientHosts::iterator it = client_hosts_.begin();
[email protected]49c71ac2013-05-03 01:36:22288 it != client_hosts_.end(); ++it) {
289 ExtensionDevToolsClientHost* client_host = *it;
[email protected]b50452f2014-08-18 12:31:44290 if (client_host->agent_host() == agent_host &&
[email protected]49c71ac2013-05-03 01:36:22291 client_host->extension_id() == extension_id)
292 return client_host;
293 }
294 return NULL;
295}
296
[email protected]91ba3312011-03-17 20:39:22297} // namespace
298
[email protected]49c71ac2013-05-03 01:36:22299
300// ExtensionDevToolsClientHost ------------------------------------------------
301
[email protected]91ba3312011-03-17 20:39:22302ExtensionDevToolsClientHost::ExtensionDevToolsClientHost(
[email protected]ac3851f2013-04-05 15:51:59303 Profile* profile,
304 DevToolsAgentHost* agent_host,
[email protected]91ba3312011-03-17 20:39:22305 const std::string& extension_id,
[email protected]c99c7662011-12-23 12:05:37306 const std::string& extension_name,
[email protected]56cc38042013-04-03 04:42:47307 const Debuggee& debuggee,
[email protected]051655ad2014-04-18 15:09:41308 infobars::InfoBar* infobar)
[email protected]ac3851f2013-04-05 15:51:59309 : profile_(profile),
310 agent_host_(agent_host),
[email protected]91ba3312011-03-17 20:39:22311 extension_id_(extension_id),
[email protected]c99c7662011-12-23 12:05:37312 last_request_id_(0),
[email protected]97efae62013-07-18 22:08:14313 infobar_(infobar),
rdevlin.cronin00f1fc22015-04-06 17:19:18314 detach_reason_(api::debugger::DETACH_REASON_TARGET_CLOSED),
[email protected]4edaf7ec2014-05-07 13:54:15315 extension_registry_observer_(this) {
[email protected]28b05ef02013-07-10 22:28:32316 CopyDebuggee(&debuggee_, debuggee);
[email protected]2fefdb32013-02-26 14:28:10317
[email protected]91ba3312011-03-17 20:39:22318 AttachedClientHosts::GetInstance()->Add(this);
319
[email protected]4edaf7ec2014-05-07 13:54:15320 // ExtensionRegistryObserver listen extension unloaded and detach debugger
321 // from there.
[email protected]d32a92652014-05-09 11:06:15322 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
[email protected]91ba3312011-03-17 20:39:22323
[email protected]02ff8ad2013-04-12 13:54:35324 // RVH-based agents disconnect from their clients when the app is terminating
325 // but shared worker-based agents do not.
326 // Disconnect explicitly to make sure that |this| observer is not leaked.
327 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
328 content::NotificationService::AllSources());
329
[email protected]91ba3312011-03-17 20:39:22330 // Attach to debugger and tell it we are ready.
[email protected]b50452f2014-08-18 12:31:44331 agent_host_->AttachClient(this);
[email protected]c99c7662011-12-23 12:05:37332
[email protected]97efae62013-07-18 22:08:14333 if (infobar_) {
[email protected]39308cb2013-12-06 03:01:48334 static_cast<ExtensionDevToolsInfoBarDelegate*>(
335 infobar_->delegate())->set_client_host(this);
[email protected]33fb3202013-04-25 00:20:49336 registrar_.Add(
[email protected]b3f957e62014-08-08 10:09:02337 this,
338 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
339 content::Source<InfoBarService>(
340 InfoBarService::FromWebContents(agent_host_->GetWebContents())));
[email protected]bde11602012-05-04 19:05:42341 }
[email protected]91ba3312011-03-17 20:39:22342}
343
344ExtensionDevToolsClientHost::~ExtensionDevToolsClientHost() {
[email protected]bde11602012-05-04 19:05:42345 // Ensure calling RemoveInfoBar() below won't result in Observe() trying to
346 // Close() us.
347 registrar_.RemoveAll();
348
[email protected]97efae62013-07-18 22:08:14349 if (infobar_) {
[email protected]39308cb2013-12-06 03:01:48350 static_cast<ExtensionDevToolsInfoBarDelegate*>(
351 infobar_->delegate())->set_client_host(NULL);
[email protected]b3f957e62014-08-08 10:09:02352 InfoBarService* infobar_service =
353 InfoBarService::FromWebContents(agent_host_->GetWebContents());
[email protected]b44f1d32014-04-10 13:53:26354 infobar_service->RemoveInfoBar(infobar_);
[email protected]c99c7662011-12-23 12:05:37355 }
[email protected]91ba3312011-03-17 20:39:22356 AttachedClientHosts::GetInstance()->Remove(this);
357}
358
[email protected]b50452f2014-08-18 12:31:44359// DevToolsAgentHostClient implementation.
360void ExtensionDevToolsClientHost::AgentHostClosed(
361 DevToolsAgentHost* agent_host, bool replaced_with_another_client) {
362 DCHECK(agent_host == agent_host_.get());
363 if (replaced_with_another_client)
rdevlin.cronin00f1fc22015-04-06 17:19:18364 detach_reason_ = api::debugger::DETACH_REASON_REPLACED_WITH_DEVTOOLS;
[email protected]c99c7662011-12-23 12:05:37365 SendDetachedEvent();
[email protected]91ba3312011-03-17 20:39:22366 delete this;
367}
368
[email protected]91ba3312011-03-17 20:39:22369void ExtensionDevToolsClientHost::Close() {
[email protected]b50452f2014-08-18 12:31:44370 agent_host_->DetachClient();
[email protected]91ba3312011-03-17 20:39:22371 delete this;
372}
373
374void ExtensionDevToolsClientHost::SendMessageToBackend(
[email protected]4636c832013-01-11 02:10:11375 DebuggerSendCommandFunction* function,
[email protected]ac310102011-04-08 14:08:33376 const std::string& method,
[email protected]752960d2012-07-23 19:06:11377 SendCommand::Params::CommandParams* command_params) {
[email protected]aeca23f2013-06-21 22:34:41378 base::DictionaryValue protocol_request;
[email protected]ff31a8a2011-03-30 14:13:59379 int request_id = ++last_request_id_;
380 pending_requests_[request_id] = function;
[email protected]ac310102011-04-08 14:08:33381 protocol_request.SetInteger("id", request_id);
382 protocol_request.SetString("method", method);
[email protected]752960d2012-07-23 19:06:11383 if (command_params) {
384 protocol_request.Set("params",
385 command_params->additional_properties.DeepCopy());
386 }
[email protected]ff31a8a2011-03-30 14:13:59387
388 std::string json_args;
[email protected]4abb4602012-03-16 01:59:55389 base::JSONWriter::Write(&protocol_request, &json_args);
[email protected]b50452f2014-08-18 12:31:44390 agent_host_->DispatchProtocolMessage(json_args);
[email protected]91ba3312011-03-17 20:39:22391}
392
[email protected]87d8a632012-09-20 13:40:39393void ExtensionDevToolsClientHost::MarkAsDismissed() {
rdevlin.cronin00f1fc22015-04-06 17:19:18394 detach_reason_ = api::debugger::DETACH_REASON_CANCELED_BY_USER;
[email protected]87d8a632012-09-20 13:40:39395}
396
[email protected]c99c7662011-12-23 12:05:37397void ExtensionDevToolsClientHost::SendDetachedEvent() {
[email protected]d32a92652014-05-09 11:06:15398 if (!EventRouter::Get(profile_))
[email protected]ac3851f2013-04-05 15:51:59399 return;
400
401 scoped_ptr<base::ListValue> args(OnDetach::Create(debuggee_,
402 detach_reason_));
[email protected]d32a92652014-05-09 11:06:15403 scoped_ptr<Event> event(new Event(OnDetach::kEventName, args.Pass()));
[email protected]45fd94172013-11-13 03:29:52404 event->restrict_to_browser_context = profile_;
[email protected]d32a92652014-05-09 11:06:15405 EventRouter::Get(profile_)
[email protected]9b4483202014-04-18 10:26:40406 ->DispatchEventToExtension(extension_id_, event.Pass());
[email protected]c99c7662011-12-23 12:05:37407}
408
[email protected]4edaf7ec2014-05-07 13:54:15409void ExtensionDevToolsClientHost::OnExtensionUnloaded(
410 content::BrowserContext* browser_context,
[email protected]d32a92652014-05-09 11:06:15411 const Extension* extension,
412 UnloadedExtensionInfo::Reason reason) {
[email protected]4edaf7ec2014-05-07 13:54:15413 if (extension->id() == extension_id_)
414 Close();
415}
416
[email protected]91ba3312011-03-17 20:39:22417void ExtensionDevToolsClientHost::Observe(
[email protected]432115822011-07-10 15:52:27418 int type,
[email protected]6c2381d2011-10-19 02:52:53419 const content::NotificationSource& source,
420 const content::NotificationDetails& details) {
[email protected]4edaf7ec2014-05-07 13:54:15421 switch (type) {
422 case chrome::NOTIFICATION_APP_TERMINATING:
[email protected]02ff8ad2013-04-12 13:54:35423 Close();
[email protected]4edaf7ec2014-05-07 13:54:15424 break;
425 case chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED:
426 if (content::Details<infobars::InfoBar::RemovedDetails>(details)->first ==
427 infobar_) {
428 infobar_ = NULL;
429 SendDetachedEvent();
430 Close();
431 }
432 break;
433 default:
434 NOTREACHED();
[email protected]bde11602012-05-04 19:05:42435 }
[email protected]91ba3312011-03-17 20:39:22436}
437
[email protected]b50452f2014-08-18 12:31:44438void ExtensionDevToolsClientHost::DispatchProtocolMessage(
439 DevToolsAgentHost* agent_host, const std::string& message) {
440 DCHECK(agent_host == agent_host_.get());
[email protected]d32a92652014-05-09 11:06:15441 if (!EventRouter::Get(profile_))
[email protected]ff31a8a2011-03-30 14:13:59442 return;
[email protected]91ba3312011-03-17 20:39:22443
[email protected]5bcdd99d2013-12-23 18:28:30444 scoped_ptr<base::Value> result(base::JSONReader::Read(message));
445 if (!result->IsType(base::Value::TYPE_DICTIONARY))
[email protected]ff31a8a2011-03-30 14:13:59446 return;
[email protected]aeca23f2013-06-21 22:34:41447 base::DictionaryValue* dictionary =
448 static_cast<base::DictionaryValue*>(result.get());
[email protected]ff31a8a2011-03-30 14:13:59449
[email protected]ac310102011-04-08 14:08:33450 int id;
451 if (!dictionary->GetInteger("id", &id)) {
452 std::string method_name;
453 if (!dictionary->GetString("method", &method_name))
[email protected]7d713ec2011-04-01 14:22:02454 return;
455
[email protected]752960d2012-07-23 19:06:11456 OnEvent::Params params;
[email protected]aeca23f2013-06-21 22:34:41457 base::DictionaryValue* params_value;
[email protected]752960d2012-07-23 19:06:11458 if (dictionary->GetDictionary("params", &params_value))
459 params.additional_properties.Swap(params_value);
460
[email protected]5bcdd99d2013-12-23 18:28:30461 scoped_ptr<base::ListValue> args(
462 OnEvent::Create(debuggee_, method_name, params));
[email protected]d32a92652014-05-09 11:06:15463 scoped_ptr<Event> event(new Event(OnEvent::kEventName, args.Pass()));
[email protected]45fd94172013-11-13 03:29:52464 event->restrict_to_browser_context = profile_;
[email protected]d32a92652014-05-09 11:06:15465 EventRouter::Get(profile_)
[email protected]9b4483202014-04-18 10:26:40466 ->DispatchEventToExtension(extension_id_, event.Pass());
[email protected]ac310102011-04-08 14:08:33467 } else {
[email protected]dc24976f2013-06-02 21:15:09468 DebuggerSendCommandFunction* function = pending_requests_[id].get();
[email protected]ac310102011-04-08 14:08:33469 if (!function)
470 return;
471
472 function->SendResponseBody(dictionary);
473 pending_requests_.erase(id);
[email protected]91ba3312011-03-17 20:39:22474 }
475}
476
[email protected]49c71ac2013-05-03 01:36:22477
478// DebuggerFunction -----------------------------------------------------------
479
[email protected]91ba3312011-03-17 20:39:22480DebuggerFunction::DebuggerFunction()
[email protected]19bcf9d2013-07-18 22:00:59481 : client_host_(NULL) {
[email protected]ac3851f2013-04-05 15:51:59482}
483
484DebuggerFunction::~DebuggerFunction() {
[email protected]91ba3312011-03-17 20:39:22485}
486
[email protected]2fefdb32013-02-26 14:28:10487void DebuggerFunction::FormatErrorMessage(const std::string& format) {
[email protected]56cc38042013-04-03 04:42:47488 if (debuggee_.tab_id)
489 error_ = ErrorUtils::FormatErrorMessage(
490 format, keys::kTabTargetType, base::IntToString(*debuggee_.tab_id));
491 else if (debuggee_.extension_id)
492 error_ = ErrorUtils::FormatErrorMessage(
493 format, keys::kBackgroundPageTargetType, *debuggee_.extension_id);
494 else
495 error_ = ErrorUtils::FormatErrorMessage(
496 format, keys::kOpaqueTargetType, *debuggee_.target_id);
[email protected]2fefdb32013-02-26 14:28:10497}
498
[email protected]ac3851f2013-04-05 15:51:59499bool DebuggerFunction::InitAgentHost() {
[email protected]2fefdb32013-02-26 14:28:10500 if (debuggee_.tab_id) {
501 WebContents* web_contents = NULL;
[email protected]d32a92652014-05-09 11:06:15502 bool result = ExtensionTabUtil::GetTabById(*debuggee_.tab_id,
503 GetProfile(),
504 include_incognito(),
505 NULL,
506 NULL,
507 &web_contents,
508 NULL);
[email protected]56cc38042013-04-03 04:42:47509 if (result && web_contents) {
[email protected]684a212a2014-06-27 17:14:50510 // TODO(rdevlin.cronin) This should definitely be GetLastCommittedURL().
511 GURL url = web_contents->GetVisibleURL();
[email protected]eba8f7d2014-07-28 22:09:23512 if (PermissionsData::IsRestrictedUrl(url, url, extension(), &error_))
[email protected]56cc38042013-04-03 04:42:47513 return false;
[email protected]02a67fd2014-03-28 15:29:55514 agent_host_ = DevToolsAgentHost::GetOrCreateFor(web_contents);
[email protected]2fefdb32013-02-26 14:28:10515 }
[email protected]56cc38042013-04-03 04:42:47516 } else if (debuggee_.extension_id) {
[email protected]d32a92652014-05-09 11:06:15517 ExtensionHost* extension_host =
reillyg0ea3fa902014-10-28 15:30:23518 ProcessManager::Get(GetProfile())
[email protected]21a40082013-10-28 21:19:23519 ->GetBackgroundHostForExtension(*debuggee_.extension_id);
[email protected]56cc38042013-04-03 04:42:47520 if (extension_host) {
[email protected]684a212a2014-06-27 17:14:50521 if (PermissionsData::IsRestrictedUrl(extension_host->GetURL(),
522 extension_host->GetURL(),
[email protected]eba8f7d2014-07-28 22:09:23523 extension(),
[email protected]684a212a2014-06-27 17:14:50524 &error_)) {
525 return false;
526 }
[email protected]b3f957e62014-08-08 10:09:02527 agent_host_ =
528 DevToolsAgentHost::GetOrCreateFor(extension_host->host_contents());
[email protected]30e246b2013-03-28 17:08:48529 }
[email protected]56cc38042013-04-03 04:42:47530 } else if (debuggee_.target_id) {
[email protected]ac3851f2013-04-05 15:51:59531 agent_host_ = DevToolsAgentHost::GetForId(*debuggee_.target_id);
rob409bf9d62015-02-10 23:37:07532 if (agent_host_.get()) {
533 if (PermissionsData::IsRestrictedUrl(agent_host_->GetURL(),
534 agent_host_->GetURL(),
535 extension(),
536 &error_)) {
537 agent_host_ = nullptr;
538 return false;
539 }
540 }
[email protected]56cc38042013-04-03 04:42:47541 } else {
542 error_ = keys::kInvalidTargetError;
[email protected]4e023cd2013-03-28 15:04:12543 return false;
544 }
[email protected]30e246b2013-03-28 17:08:48545
[email protected]dc24976f2013-06-02 21:15:09546 if (!agent_host_.get()) {
[email protected]56cc38042013-04-03 04:42:47547 FormatErrorMessage(keys::kNoTargetError);
548 return false;
549 }
550 return true;
[email protected]91ba3312011-03-17 20:39:22551}
552
[email protected]c7580b62011-10-26 08:46:30553bool DebuggerFunction::InitClientHost() {
[email protected]ac3851f2013-04-05 15:51:59554 if (!InitAgentHost())
[email protected]91ba3312011-03-17 20:39:22555 return false;
556
[email protected]eba8f7d2014-07-28 22:09:23557 client_host_ = AttachedClientHosts::GetInstance()->Lookup(agent_host_.get(),
558 extension()->id());
[email protected]91ba3312011-03-17 20:39:22559
[email protected]ac3851f2013-04-05 15:51:59560 if (!client_host_) {
[email protected]2fefdb32013-02-26 14:28:10561 FormatErrorMessage(keys::kNotAttachedError);
[email protected]91ba3312011-03-17 20:39:22562 return false;
563 }
564 return true;
565}
566
[email protected]49c71ac2013-05-03 01:36:22567
568// DebuggerAttachFunction -----------------------------------------------------
569
[email protected]28b05ef02013-07-10 22:28:32570DebuggerAttachFunction::DebuggerAttachFunction() {
571}
[email protected]91ba3312011-03-17 20:39:22572
[email protected]28b05ef02013-07-10 22:28:32573DebuggerAttachFunction::~DebuggerAttachFunction() {
574}
[email protected]91ba3312011-03-17 20:39:22575
[email protected]a0c91a9f2014-05-03 03:41:43576bool DebuggerAttachFunction::RunAsync() {
[email protected]752960d2012-07-23 19:06:11577 scoped_ptr<Attach::Params> params(Attach::Params::Create(*args_));
578 EXTENSION_FUNCTION_VALIDATE(params.get());
579
[email protected]28b05ef02013-07-10 22:28:32580 CopyDebuggee(&debuggee_, params->target);
[email protected]ac3851f2013-04-05 15:51:59581 if (!InitAgentHost())
[email protected]91ba3312011-03-17 20:39:22582 return false;
583
[email protected]be3577e2013-06-26 21:42:33584 if (!DevToolsHttpHandler::IsSupportedProtocolVersion(
585 params->required_version)) {
[email protected]e9f541a2012-11-19 21:52:31586 error_ = ErrorUtils::FormatErrorMessage(
[email protected]c7580b62011-10-26 08:46:30587 keys::kProtocolVersionNotSupportedError,
[email protected]752960d2012-07-23 19:06:11588 params->required_version);
[email protected]c7580b62011-10-26 08:46:30589 return false;
590 }
591
[email protected]ac3851f2013-04-05 15:51:59592 if (agent_host_->IsAttached()) {
[email protected]2fefdb32013-02-26 14:28:10593 FormatErrorMessage(keys::kAlreadyAttachedError);
[email protected]91ba3312011-03-17 20:39:22594 return false;
595 }
596
[email protected]051655ad2014-04-18 15:09:41597 infobars::InfoBar* infobar = NULL;
avi3ef9ec9e2014-12-22 22:50:17598 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
599 ::switches::kSilentDebuggerExtensionAPI)) {
[email protected]56cc38042013-04-03 04:42:47600 // Do not attach to the target if for any reason the infobar cannot be shown
601 // for this WebContents instance.
[email protected]9f0fc9dc2013-07-24 21:31:56602 infobar = ExtensionDevToolsInfoBarDelegate::Create(
[email protected]b3f957e62014-08-08 10:09:02603 agent_host_->GetWebContents(), extension()->name());
[email protected]9f0fc9dc2013-07-24 21:31:56604 if (!infobar) {
[email protected]56cc38042013-04-03 04:42:47605 error_ = ErrorUtils::FormatErrorMessage(
606 keys::kSilentDebuggingRequired,
[email protected]684a212a2014-06-27 17:14:50607 ::switches::kSilentDebuggerExtensionAPI);
[email protected]56cc38042013-04-03 04:42:47608 return false;
609 }
610 }
611
[email protected]21a40082013-10-28 21:19:23612 new ExtensionDevToolsClientHost(GetProfile(),
613 agent_host_.get(),
[email protected]eba8f7d2014-07-28 22:09:23614 extension()->id(),
615 extension()->name(),
[email protected]21a40082013-10-28 21:19:23616 debuggee_,
617 infobar);
[email protected]ff31a8a2011-03-30 14:13:59618 SendResponse(true);
[email protected]91ba3312011-03-17 20:39:22619 return true;
620}
621
[email protected]49c71ac2013-05-03 01:36:22622
623// DebuggerDetachFunction -----------------------------------------------------
624
[email protected]28b05ef02013-07-10 22:28:32625DebuggerDetachFunction::DebuggerDetachFunction() {
626}
[email protected]91ba3312011-03-17 20:39:22627
[email protected]28b05ef02013-07-10 22:28:32628DebuggerDetachFunction::~DebuggerDetachFunction() {
629}
[email protected]91ba3312011-03-17 20:39:22630
[email protected]a0c91a9f2014-05-03 03:41:43631bool DebuggerDetachFunction::RunAsync() {
[email protected]752960d2012-07-23 19:06:11632 scoped_ptr<Detach::Params> params(Detach::Params::Create(*args_));
633 EXTENSION_FUNCTION_VALIDATE(params.get());
634
[email protected]28b05ef02013-07-10 22:28:32635 CopyDebuggee(&debuggee_, params->target);
[email protected]c7580b62011-10-26 08:46:30636 if (!InitClientHost())
[email protected]91ba3312011-03-17 20:39:22637 return false;
638
639 client_host_->Close();
[email protected]ff31a8a2011-03-30 14:13:59640 SendResponse(true);
[email protected]91ba3312011-03-17 20:39:22641 return true;
642}
643
[email protected]49c71ac2013-05-03 01:36:22644
645// DebuggerSendCommandFunction ------------------------------------------------
646
[email protected]28b05ef02013-07-10 22:28:32647DebuggerSendCommandFunction::DebuggerSendCommandFunction() {
648}
[email protected]91ba3312011-03-17 20:39:22649
[email protected]28b05ef02013-07-10 22:28:32650DebuggerSendCommandFunction::~DebuggerSendCommandFunction() {
651}
[email protected]91ba3312011-03-17 20:39:22652
[email protected]a0c91a9f2014-05-03 03:41:43653bool DebuggerSendCommandFunction::RunAsync() {
[email protected]752960d2012-07-23 19:06:11654 scoped_ptr<SendCommand::Params> params(SendCommand::Params::Create(*args_));
655 EXTENSION_FUNCTION_VALIDATE(params.get());
[email protected]91ba3312011-03-17 20:39:22656
[email protected]28b05ef02013-07-10 22:28:32657 CopyDebuggee(&debuggee_, params->target);
[email protected]c7580b62011-10-26 08:46:30658 if (!InitClientHost())
[email protected]91ba3312011-03-17 20:39:22659 return false;
660
[email protected]752960d2012-07-23 19:06:11661 client_host_->SendMessageToBackend(this, params->method,
662 params->command_params.get());
[email protected]91ba3312011-03-17 20:39:22663 return true;
664}
[email protected]ff31a8a2011-03-30 14:13:59665
[email protected]4636c832013-01-11 02:10:11666void DebuggerSendCommandFunction::SendResponseBody(
[email protected]aeca23f2013-06-21 22:34:41667 base::DictionaryValue* response) {
[email protected]5bcdd99d2013-12-23 18:28:30668 base::Value* error_body;
[email protected]752960d2012-07-23 19:06:11669 if (response->Get("error", &error_body)) {
[email protected]4abb4602012-03-16 01:59:55670 base::JSONWriter::Write(error_body, &error_);
[email protected]ff31a8a2011-03-30 14:13:59671 SendResponse(false);
672 return;
673 }
674
[email protected]aeca23f2013-06-21 22:34:41675 base::DictionaryValue* result_body;
[email protected]752960d2012-07-23 19:06:11676 SendCommand::Results::Result result;
677 if (response->GetDictionary("result", &result_body))
678 result.additional_properties.Swap(result_body);
679
680 results_ = SendCommand::Results::Create(result);
[email protected]ff31a8a2011-03-30 14:13:59681 SendResponse(true);
682}
[email protected]56cc38042013-04-03 04:42:47683
[email protected]49c71ac2013-05-03 01:36:22684
685// DebuggerGetTargetsFunction -------------------------------------------------
686
[email protected]28b05ef02013-07-10 22:28:32687namespace {
[email protected]56cc38042013-04-03 04:42:47688
[email protected]28b05ef02013-07-10 22:28:32689const char kTargetIdField[] = "id";
690const char kTargetTypeField[] = "type";
691const char kTargetTitleField[] = "title";
692const char kTargetAttachedField[] = "attached";
693const char kTargetUrlField[] = "url";
694const char kTargetFaviconUrlField[] = "faviconUrl";
695const char kTargetTypePage[] = "page";
696const char kTargetTypeBackgroundPage[] = "background_page";
697const char kTargetTypeWorker[] = "worker";
[email protected]f80e0be62013-07-17 14:17:23698const char kTargetTypeOther[] = "other";
699const char kTargetTabIdField[] = "tabId";
700const char kTargetExtensionIdField[] = "extensionId";
[email protected]28b05ef02013-07-10 22:28:32701
[email protected]06d503f2013-10-29 17:29:37702base::Value* SerializeTarget(const DevToolsTargetImpl& target) {
[email protected]28b05ef02013-07-10 22:28:32703 base::DictionaryValue* dictionary = new base::DictionaryValue();
704
[email protected]06d503f2013-10-29 17:29:37705 dictionary->SetString(kTargetIdField, target.GetId());
706 dictionary->SetString(kTargetTitleField, target.GetTitle());
707 dictionary->SetBoolean(kTargetAttachedField, target.IsAttached());
[email protected]657d2732014-05-07 10:09:51708 dictionary->SetString(kTargetUrlField, target.GetURL().spec());
[email protected]28b05ef02013-07-10 22:28:32709
[email protected]06d503f2013-10-29 17:29:37710 std::string type = target.GetType();
711 if (type == kTargetTypePage) {
712 dictionary->SetInteger(kTargetTabIdField, target.GetTabId());
713 } else if (type == kTargetTypeBackgroundPage) {
714 dictionary->SetString(kTargetExtensionIdField, target.GetExtensionId());
715 } else if (type != kTargetTypeWorker) {
716 // DevToolsTargetImpl may support more types than the debugger API.
717 type = kTargetTypeOther;
[email protected]28b05ef02013-07-10 22:28:32718 }
[email protected]06d503f2013-10-29 17:29:37719 dictionary->SetString(kTargetTypeField, type);
[email protected]28b05ef02013-07-10 22:28:32720
[email protected]657d2732014-05-07 10:09:51721 GURL favicon_url = target.GetFaviconURL();
[email protected]06d503f2013-10-29 17:29:37722 if (favicon_url.is_valid())
723 dictionary->SetString(kTargetFaviconUrlField, favicon_url.spec());
[email protected]28b05ef02013-07-10 22:28:32724
725 return dictionary;
726}
727
[email protected]4edaf7ec2014-05-07 13:54:15728} // namespace
[email protected]28b05ef02013-07-10 22:28:32729
730DebuggerGetTargetsFunction::DebuggerGetTargetsFunction() {
731}
732
733DebuggerGetTargetsFunction::~DebuggerGetTargetsFunction() {
734}
[email protected]56cc38042013-04-03 04:42:47735
[email protected]a0c91a9f2014-05-03 03:41:43736bool DebuggerGetTargetsFunction::RunAsync() {
[email protected]06d503f2013-10-29 17:29:37737 DevToolsTargetImpl::EnumerateAllTargets(
738 base::Bind(&DebuggerGetTargetsFunction::SendTargetList, this));
[email protected]56cc38042013-04-03 04:42:47739 return true;
740}
[email protected]ac3851f2013-04-05 15:51:59741
[email protected]fe38b1e2013-10-02 23:43:34742void DebuggerGetTargetsFunction::SendTargetList(
[email protected]06d503f2013-10-29 17:29:37743 const std::vector<DevToolsTargetImpl*>& target_list) {
744 scoped_ptr<base::ListValue> result(new base::ListValue());
745 for (size_t i = 0; i < target_list.size(); ++i)
746 result->Append(SerializeTarget(*target_list[i]));
747 STLDeleteContainerPointers(target_list.begin(), target_list.end());
748 SetResult(result.release());
[email protected]ac3851f2013-04-05 15:51:59749 SendResponse(true);
750}
[email protected]d32a92652014-05-09 11:06:15751
752} // namespace extensions