blob: 4e4693f5e1650fb6de0424a9df187939dba79fc6 [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
Sebastien Marchandf1349f52019-01-25 03:16:4116#include "base/bind.h"
[email protected]2fefdb32013-02-26 14:28:1017#include "base/command_line.h"
[email protected]ff31a8a2011-03-30 14:13:5918#include "base/json/json_reader.h"
[email protected]91ba3312011-03-17 20:39:2219#include "base/json/json_writer.h"
dgozmand06efdf2015-08-27 02:28:3820#include "base/lazy_instance.h"
avia2f4804a2015-12-24 23:11:1321#include "base/macros.h"
[email protected]3b63f8f42011-03-28 01:54:1522#include "base/memory/singleton.h"
Sigurdur Asgeirsson2c442dc2021-03-25 13:41:2023#include "base/scoped_observation.h"
[email protected]3ea1b182013-02-08 22:38:4124#include "base/strings/string_number_conversions.h"
Eric Seckler8652dcd52018-09-20 10:42:2825#include "base/task/post_task.h"
[email protected]91ba3312011-03-17 20:39:2226#include "base/values.h"
[email protected]49a01e642013-07-12 00:29:4527#include "chrome/browser/chrome_notification_types.h"
pfeldmana9e7dda2016-08-26 14:35:1728#include "chrome/browser/devtools/chrome_devtools_manager_delegate.h"
[email protected]1eb8f2f2012-07-12 02:04:4929#include "chrome/browser/extensions/api/debugger/debugger_api_constants.h"
Peter Kastingcd8f7252020-05-09 01:43:5930#include "chrome/browser/extensions/api/debugger/extension_dev_tools_infobar_delegate.h"
[email protected]2fefdb32013-02-26 14:28:1031#include "chrome/browser/extensions/extension_service.h"
[email protected]ac84431b2011-09-27 17:26:1132#include "chrome/browser/extensions/extension_tab_util.h"
Devlin Cronin4dafc3172018-06-22 23:16:3133#include "chrome/browser/extensions/extension_util.h"
[email protected]91ba3312011-03-17 20:39:2234#include "chrome/browser/profiles/profile.h"
dgozmand06efdf2015-08-27 02:28:3835#include "chrome/browser/ui/browser.h"
[email protected]863f70a2012-01-27 02:05:5036#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
[email protected]2fefdb32013-02-26 14:28:1037#include "chrome/common/chrome_switches.h"
Eric Seckler8652dcd52018-09-20 10:42:2838#include "content/public/browser/browser_task_traits.h"
dgozmancb088d02015-04-28 11:57:4539#include "content/public/browser/browser_thread.h"
[email protected]98f66112012-12-25 12:59:3640#include "content/public/browser/devtools_agent_host.h"
[email protected]1c3bd202011-12-23 05:48:2441#include "content/public/browser/notification_service.h"
[email protected]ad50def52011-10-19 23:17:0742#include "content/public/browser/notification_source.h"
[email protected]2fefdb32013-02-26 14:28:1043#include "content/public/browser/render_process_host.h"
[email protected]2fefdb32013-02-26 14:28:1044#include "content/public/browser/render_widget_host.h"
[email protected]ef9572e2012-01-04 22:14:1245#include "content/public/browser/web_contents.h"
[email protected]744c2a22012-03-15 18:42:0446#include "content/public/common/content_client.h"
Dmitry Gozman00ba04e2018-09-18 00:39:2747#include "content/public/common/url_constants.h"
[email protected]3b366ae2013-05-17 21:16:5848#include "content/public/common/url_utils.h"
[email protected]34423532013-11-21 18:13:1049#include "extensions/browser/event_router.h"
[email protected]22401dc2014-03-21 01:38:5750#include "extensions/browser/extension_host.h"
[email protected]4edaf7ec2014-05-07 13:54:1551#include "extensions/browser/extension_registry.h"
52#include "extensions/browser/extension_registry_observer.h"
[email protected]684a212a2014-06-27 17:14:5053#include "extensions/common/constants.h"
[email protected]e9f541a2012-11-19 21:52:3154#include "extensions/common/error_utils.h"
[email protected]e4452d32013-11-15 23:07:4155#include "extensions/common/extension.h"
[email protected]684a212a2014-06-27 17:14:5056#include "extensions/common/manifest_constants.h"
57#include "extensions/common/permissions/permissions_data.h"
58#include "extensions/common/switches.h"
[email protected]91ba3312011-03-17 20:39:2259
[email protected]0e12d7d2011-12-01 16:21:4460using content::DevToolsAgentHost;
[email protected]2fefdb32013-02-26 14:28:1061using content::RenderProcessHost;
[email protected]2fefdb32013-02-26 14:28:1062using content::RenderWidgetHost;
[email protected]7320a44e2012-05-22 17:01:1163using content::WebContents;
[email protected]0e12d7d2011-12-01 16:21:4464
[email protected]752960d2012-07-23 19:06:1165namespace Attach = extensions::api::debugger::Attach;
66namespace Detach = extensions::api::debugger::Detach;
67namespace OnDetach = extensions::api::debugger::OnDetach;
68namespace OnEvent = extensions::api::debugger::OnEvent;
69namespace SendCommand = extensions::api::debugger::SendCommand;
[email protected]ef9572e2012-01-04 22:14:1270
[email protected]4edaf7ec2014-05-07 13:54:1571namespace extensions {
72class ExtensionRegistry;
dgozmand06efdf2015-08-27 02:28:3873class ExtensionDevToolsClientHost;
[email protected]19bcf9d2013-07-18 22:00:5974
75namespace {
76
77// Helpers --------------------------------------------------------------------
78
79void CopyDebuggee(Debuggee* dst, const Debuggee& src) {
80 if (src.tab_id)
Peter Boström924f8032021-04-02 20:36:0281 dst->tab_id = std::make_unique<int>(*src.tab_id);
[email protected]19bcf9d2013-07-18 22:00:5982 if (src.extension_id)
Peter Boström924f8032021-04-02 20:36:0283 dst->extension_id = std::make_unique<std::string>(*src.extension_id);
[email protected]19bcf9d2013-07-18 22:00:5984 if (src.target_id)
Peter Boström924f8032021-04-02 20:36:0285 dst->target_id = std::make_unique<std::string>(*src.target_id);
[email protected]19bcf9d2013-07-18 22:00:5986}
87
Devlin Cronin4dafc3172018-06-22 23:16:3188// Returns true if the given |Extension| is allowed to attach to the specified
89// |url|.
Andrey Kosyakovfa3dd0b2020-09-19 06:02:0590bool ExtensionMayAttachToURL(const Extension& extension,
Devlin Cronin4dafc3172018-06-22 23:16:3191 const GURL& url,
92 Profile* profile,
93 std::string* error) {
Andrey Kosyakov54f4c4a2020-11-03 03:34:5694 // Allow the extension to attach to about:blank and empty URLs.
95 if (url.is_empty() || url == "about:")
96 return true;
97
Dmitry Gozman00ba04e2018-09-18 00:39:2798 if (url == content::kUnreachableWebDataURL)
99 return true;
100
Devlin Cronin4dafc3172018-06-22 23:16:31101 // NOTE: The `debugger` permission implies all URLs access (and indicates
102 // such to the user), so we don't check explicit page access. However, we
103 // still need to check if it's an otherwise-restricted URL.
104 if (extension.permissions_data()->IsRestrictedUrl(url, error))
105 return false;
106
Solomon Kinard3565a342021-04-07 22:29:27107 // Policy blocked hosts supersede the `debugger` permission.
108 if (extension.permissions_data()->IsPolicyBlockedHost(url))
109 return false;
110
Devlin Cronin4dafc3172018-06-22 23:16:31111 if (url.SchemeIsFile() && !util::AllowFileAccess(extension.id(), profile)) {
112 *error = debugger_api_constants::kRestrictedError;
113 return false;
114 }
115
116 return true;
117}
118
Andrey Kosyakovad5d2522020-01-07 22:42:49119constexpr char kBrowserTargetId[] = "browser";
120
121constexpr char kPerfettoUIExtensionId[] = "lfmkphfpdbjijhpomgecfikhfohaoine";
122
123bool ExtensionMayAttachToBrowser(const Extension& extension) {
124 return extension.id() == kPerfettoUIExtensionId;
125}
126
Andrey Kosyakovfa3dd0b2020-09-19 06:02:05127bool ExtensionMayAttachToWebContents(const Extension& extension,
128 WebContents& web_contents,
129 Profile* profile,
130 std::string* error) {
131 // This is *not* redundant to the checks below, as
132 // web_contents.GetLastCommittedURL() may be different from
133 // web_contents.GetMainFrame()->GetLastCommittedURL(), with the
134 // former being a 'virtual' URL as obtained from NavigationEntry.
135 if (!ExtensionMayAttachToURL(extension, web_contents.GetLastCommittedURL(),
136 profile, error)) {
137 return false;
138 }
139
140 for (content::RenderFrameHost* rfh : web_contents.GetAllFrames()) {
141 if (!ExtensionMayAttachToURL(extension, rfh->GetLastCommittedURL(), profile,
142 error))
143 return false;
144 }
145 return true;
146}
147
148bool ExtensionMayAttachToAgentHost(const Extension& extension,
149 DevToolsAgentHost& agent_host,
150 Profile* profile,
151 std::string* error) {
152 if (WebContents* wc = agent_host.GetWebContents())
153 return ExtensionMayAttachToWebContents(extension, *wc, profile, error);
154
155 return ExtensionMayAttachToURL(extension, agent_host.GetURL(), profile,
156 error);
157}
158
[email protected]91ba3312011-03-17 20:39:22159} // namespace
160
dgozmand06efdf2015-08-27 02:28:38161// ExtensionDevToolsClientHost ------------------------------------------------
162
163using AttachedClientHosts = std::set<ExtensionDevToolsClientHost*>;
164base::LazyInstance<AttachedClientHosts>::Leaky g_attached_client_hosts =
165 LAZY_INSTANCE_INITIALIZER;
166
167class ExtensionDevToolsClientHost : public content::DevToolsAgentHostClient,
168 public content::NotificationObserver,
169 public ExtensionRegistryObserver {
170 public:
171 ExtensionDevToolsClientHost(Profile* profile,
172 DevToolsAgentHost* agent_host,
Devlin Cronin4dafc3172018-06-22 23:16:31173 scoped_refptr<const Extension> extension,
dgozmand06efdf2015-08-27 02:28:38174 const Debuggee& debuggee);
175
Peter Boström53c6c5952021-09-17 09:41:26176 ExtensionDevToolsClientHost(const ExtensionDevToolsClientHost&) = delete;
177 ExtensionDevToolsClientHost& operator=(const ExtensionDevToolsClientHost&) =
178 delete;
179
dgozmand06efdf2015-08-27 02:28:38180 ~ExtensionDevToolsClientHost() override;
181
Dmitry Gozman2aec794f2018-03-05 20:27:54182 bool Attach();
Devlin Cronin4dafc3172018-06-22 23:16:31183 const std::string& extension_id() { return extension_->id(); }
dgozmand06efdf2015-08-27 02:28:38184 DevToolsAgentHost* agent_host() { return agent_host_.get(); }
Dmitry Gozman2aec794f2018-03-05 20:27:54185 void RespondDetachedToPendingRequests();
dgozmand06efdf2015-08-27 02:28:38186 void Close();
187 void SendMessageToBackend(DebuggerSendCommandFunction* function,
188 const std::string& method,
189 SendCommand::Params::CommandParams* command_params);
190
191 // Closes connection as terminated by the user.
Peter Kasting0cdd929e2020-05-08 04:26:32192 void InfoBarDestroyed();
dgozmand06efdf2015-08-27 02:28:38193
194 // DevToolsAgentHostClient interface.
Pavel Feldmana344d932017-10-31 20:24:52195 void AgentHostClosed(DevToolsAgentHost* agent_host) override;
dgozmand06efdf2015-08-27 02:28:38196 void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
Johannes Henkel21e194012019-12-20 03:23:17197 base::span<const uint8_t> message) override;
Andrey Kosyakov0788b1d2019-12-10 04:28:11198 bool MayAttachToURL(const GURL& url, bool is_webui) override;
Dmitry Gozman2731b562018-09-10 23:19:02199 bool MayAttachToBrowser() override;
Dmitry Gozmana3023d22019-02-26 22:11:27200 bool MayReadLocalFiles() override;
201 bool MayWriteLocalFiles() override;
dgozmand06efdf2015-08-27 02:28:38202
203 private:
204 using PendingRequests =
205 std::map<int, scoped_refptr<DebuggerSendCommandFunction>>;
206
207 void SendDetachedEvent();
208
209 // content::NotificationObserver implementation.
210 void Observe(int type,
211 const content::NotificationSource& source,
212 const content::NotificationDetails& details) override;
213
214 // ExtensionRegistryObserver implementation.
215 void OnExtensionUnloaded(content::BrowserContext* browser_context,
216 const Extension* extension,
limasdf0deef2042017-05-03 19:17:17217 UnloadedExtensionReason reason) override;
dgozmand06efdf2015-08-27 02:28:38218
219 Profile* profile_;
220 scoped_refptr<DevToolsAgentHost> agent_host_;
Devlin Cronin4dafc3172018-06-22 23:16:31221 scoped_refptr<const Extension> extension_;
dgozmand06efdf2015-08-27 02:28:38222 Debuggee debuggee_;
223 content::NotificationRegistrar registrar_;
Peter Kasting0cdd929e2020-05-08 04:26:32224 int last_request_id_ = 0;
dgozmand06efdf2015-08-27 02:28:38225 PendingRequests pending_requests_;
Peter Kasting7ba9440c2020-11-22 01:49:02226 base::CallbackListSubscription subscription_;
Peter Kasting0cdd929e2020-05-08 04:26:32227 api::debugger::DetachReason detach_reason_ =
228 api::debugger::DETACH_REASON_TARGET_CLOSED;
dgozmand06efdf2015-08-27 02:28:38229
230 // Listen to extension unloaded notification.
Sigurdur Asgeirsson2c442dc2021-03-25 13:41:20231 base::ScopedObservation<ExtensionRegistry, ExtensionRegistryObserver>
232 extension_registry_observation_{this};
dgozmand06efdf2015-08-27 02:28:38233};
[email protected]49c71ac2013-05-03 01:36:22234
[email protected]91ba3312011-03-17 20:39:22235ExtensionDevToolsClientHost::ExtensionDevToolsClientHost(
[email protected]ac3851f2013-04-05 15:51:59236 Profile* profile,
237 DevToolsAgentHost* agent_host,
Devlin Cronin4dafc3172018-06-22 23:16:31238 scoped_refptr<const Extension> extension,
dgozmand06efdf2015-08-27 02:28:38239 const Debuggee& debuggee)
[email protected]ac3851f2013-04-05 15:51:59240 : profile_(profile),
241 agent_host_(agent_host),
Peter Kasting0cdd929e2020-05-08 04:26:32242 extension_(std::move(extension)) {
[email protected]28b05ef02013-07-10 22:28:32243 CopyDebuggee(&debuggee_, debuggee);
[email protected]2fefdb32013-02-26 14:28:10244
dgozmand06efdf2015-08-27 02:28:38245 g_attached_client_hosts.Get().insert(this);
[email protected]91ba3312011-03-17 20:39:22246
[email protected]4edaf7ec2014-05-07 13:54:15247 // ExtensionRegistryObserver listen extension unloaded and detach debugger
248 // from there.
Sigurdur Asgeirsson2c442dc2021-03-25 13:41:20249 extension_registry_observation_.Observe(ExtensionRegistry::Get(profile_));
[email protected]91ba3312011-03-17 20:39:22250
[email protected]02ff8ad2013-04-12 13:54:35251 // RVH-based agents disconnect from their clients when the app is terminating
252 // but shared worker-based agents do not.
253 // Disconnect explicitly to make sure that |this| observer is not leaked.
254 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
255 content::NotificationService::AllSources());
Dmitry Gozman2aec794f2018-03-05 20:27:54256}
[email protected]02ff8ad2013-04-12 13:54:35257
Dmitry Gozman2aec794f2018-03-05 20:27:54258bool ExtensionDevToolsClientHost::Attach() {
[email protected]91ba3312011-03-17 20:39:22259 // Attach to debugger and tell it we are ready.
Dmitry Gozman2731b562018-09-10 23:19:02260 if (!agent_host_->AttachClient(this))
Dmitry Gozman2aec794f2018-03-05 20:27:54261 return false;
[email protected]c99c7662011-12-23 12:05:37262
pfeldmanc64e1a62017-02-24 01:22:50263 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
dgozmand06efdf2015-08-27 02:28:38264 ::switches::kSilentDebuggerExtensionAPI)) {
Dmitry Gozman2aec794f2018-03-05 20:27:54265 return true;
[email protected]bde11602012-05-04 19:05:42266 }
pfeldmanc64e1a62017-02-24 01:22:50267
268 // We allow policy-installed extensions to circumvent the normal
269 // infobar warning. See crbug.com/693621.
Devlin Cronin4dafc3172018-06-22 23:16:31270 if (Manifest::IsPolicyLocation(extension_->location()))
Dmitry Gozman2aec794f2018-03-05 20:27:54271 return true;
pfeldmanc64e1a62017-02-24 01:22:50272
Peter Kasting8aa2b2b92020-05-09 01:36:55273 subscription_ = ExtensionDevToolsInfoBarDelegate::Create(
Peter Kasting03ec380a2020-05-08 08:03:56274 extension_id(), extension_->name(),
Peter Kasting0cdd929e2020-05-08 04:26:32275 base::BindOnce(&ExtensionDevToolsClientHost::InfoBarDestroyed,
276 base::Unretained(this)));
Dmitry Gozman2aec794f2018-03-05 20:27:54277 return true;
[email protected]91ba3312011-03-17 20:39:22278}
279
280ExtensionDevToolsClientHost::~ExtensionDevToolsClientHost() {
Ghazale Hosseinabadi301cdb42020-10-02 20:16:57281 ExtensionDevToolsInfoBarDelegate::NotifyExtensionDetached(extension_id());
dgozmand06efdf2015-08-27 02:28:38282 g_attached_client_hosts.Get().erase(this);
[email protected]91ba3312011-03-17 20:39:22283}
284
[email protected]b50452f2014-08-18 12:31:44285// DevToolsAgentHostClient implementation.
286void ExtensionDevToolsClientHost::AgentHostClosed(
Pavel Feldmana344d932017-10-31 20:24:52287 DevToolsAgentHost* agent_host) {
[email protected]b50452f2014-08-18 12:31:44288 DCHECK(agent_host == agent_host_.get());
Dmitry Gozman2aec794f2018-03-05 20:27:54289 RespondDetachedToPendingRequests();
[email protected]c99c7662011-12-23 12:05:37290 SendDetachedEvent();
[email protected]91ba3312011-03-17 20:39:22291 delete this;
292}
293
[email protected]91ba3312011-03-17 20:39:22294void ExtensionDevToolsClientHost::Close() {
pfeldmanfb8e7472016-06-08 21:13:37295 agent_host_->DetachClient(this);
[email protected]91ba3312011-03-17 20:39:22296 delete this;
297}
298
299void ExtensionDevToolsClientHost::SendMessageToBackend(
[email protected]4636c832013-01-11 02:10:11300 DebuggerSendCommandFunction* function,
[email protected]ac310102011-04-08 14:08:33301 const std::string& method,
[email protected]752960d2012-07-23 19:06:11302 SendCommand::Params::CommandParams* command_params) {
[email protected]aeca23f2013-06-21 22:34:41303 base::DictionaryValue protocol_request;
[email protected]ff31a8a2011-03-30 14:13:59304 int request_id = ++last_request_id_;
305 pending_requests_[request_id] = function;
[email protected]ac310102011-04-08 14:08:33306 protocol_request.SetInteger("id", request_id);
307 protocol_request.SetString("method", method);
[email protected]752960d2012-07-23 19:06:11308 if (command_params) {
Song Fangzhen06c83d52021-06-24 03:51:27309 protocol_request.SetKey("params",
310 command_params->additional_properties.Clone());
[email protected]752960d2012-07-23 19:06:11311 }
[email protected]ff31a8a2011-03-30 14:13:59312
Johannes Henkel21e194012019-12-20 03:23:17313 std::string json;
314 base::JSONWriter::Write(protocol_request, &json);
315
316 agent_host_->DispatchProtocolMessage(this,
317 base::as_bytes(base::make_span(json)));
[email protected]91ba3312011-03-17 20:39:22318}
319
Peter Kasting0cdd929e2020-05-08 04:26:32320void ExtensionDevToolsClientHost::InfoBarDestroyed() {
rdevlin.cronin00f1fc22015-04-06 17:19:18321 detach_reason_ = api::debugger::DETACH_REASON_CANCELED_BY_USER;
Dmitry Gozman2aec794f2018-03-05 20:27:54322 RespondDetachedToPendingRequests();
dgozmand06efdf2015-08-27 02:28:38323 SendDetachedEvent();
324 Close();
[email protected]87d8a632012-09-20 13:40:39325}
326
Dmitry Gozman2aec794f2018-03-05 20:27:54327void ExtensionDevToolsClientHost::RespondDetachedToPendingRequests() {
328 for (const auto& it : pending_requests_)
329 it.second->SendDetachedError();
330 pending_requests_.clear();
331}
332
[email protected]c99c7662011-12-23 12:05:37333void ExtensionDevToolsClientHost::SendDetachedEvent() {
[email protected]d32a92652014-05-09 11:06:15334 if (!EventRouter::Get(profile_))
[email protected]ac3851f2013-04-05 15:51:59335 return;
336
Lei Zhang1f3ec9792021-05-18 00:00:28337 auto args(OnDetach::Create(debuggee_, detach_reason_));
lazyboy59155a42017-05-24 22:23:35338 auto event =
Jinho Bangb5216cec2018-01-17 19:43:11339 std::make_unique<Event>(events::DEBUGGER_ON_DETACH, OnDetach::kEventName,
lazyboy59155a42017-05-24 22:23:35340 std::move(args), profile_);
Devlin Cronin4dafc3172018-06-22 23:16:31341 EventRouter::Get(profile_)->DispatchEventToExtension(extension_id(),
342 std::move(event));
[email protected]c99c7662011-12-23 12:05:37343}
344
[email protected]4edaf7ec2014-05-07 13:54:15345void ExtensionDevToolsClientHost::OnExtensionUnloaded(
346 content::BrowserContext* browser_context,
[email protected]d32a92652014-05-09 11:06:15347 const Extension* extension,
limasdf0deef2042017-05-03 19:17:17348 UnloadedExtensionReason reason) {
Devlin Cronin4dafc3172018-06-22 23:16:31349 if (extension->id() == extension_id())
[email protected]4edaf7ec2014-05-07 13:54:15350 Close();
351}
352
[email protected]91ba3312011-03-17 20:39:22353void ExtensionDevToolsClientHost::Observe(
[email protected]432115822011-07-10 15:52:27354 int type,
[email protected]6c2381d2011-10-19 02:52:53355 const content::NotificationSource& source,
356 const content::NotificationDetails& details) {
dgozmand06efdf2015-08-27 02:28:38357 DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
358 Close();
[email protected]91ba3312011-03-17 20:39:22359}
360
[email protected]b50452f2014-08-18 12:31:44361void ExtensionDevToolsClientHost::DispatchProtocolMessage(
Johannes Henkel21e194012019-12-20 03:23:17362 DevToolsAgentHost* agent_host,
363 base::span<const uint8_t> message) {
[email protected]b50452f2014-08-18 12:31:44364 DCHECK(agent_host == agent_host_.get());
[email protected]d32a92652014-05-09 11:06:15365 if (!EventRouter::Get(profile_))
[email protected]ff31a8a2011-03-30 14:13:59366 return;
[email protected]91ba3312011-03-17 20:39:22367
Johannes Henkel21e194012019-12-20 03:23:17368 base::StringPiece message_str(reinterpret_cast<const char*>(message.data()),
369 message.size());
Lei Zhang582ecd12019-02-13 20:28:54370 std::unique_ptr<base::Value> result = base::JSONReader::ReadDeprecated(
Johannes Henkel21e194012019-12-20 03:23:17371 message_str, base::JSON_REPLACE_INVALID_CHARACTERS);
Joey Arhar34f1026e2019-01-16 06:07:43372 if (!result || !result->is_dict()) {
Johannes Henkel21e194012019-12-20 03:23:17373 LOG(ERROR) << "Tried to send invalid message to extension: " << message_str;
[email protected]ff31a8a2011-03-30 14:13:59374 return;
Joey Arhar34f1026e2019-01-16 06:07:43375 }
[email protected]aeca23f2013-06-21 22:34:41376 base::DictionaryValue* dictionary =
377 static_cast<base::DictionaryValue*>(result.get());
[email protected]ff31a8a2011-03-30 14:13:59378
[email protected]ac310102011-04-08 14:08:33379 int id;
380 if (!dictionary->GetInteger("id", &id)) {
381 std::string method_name;
382 if (!dictionary->GetString("method", &method_name))
[email protected]7d713ec2011-04-01 14:22:02383 return;
384
[email protected]752960d2012-07-23 19:06:11385 OnEvent::Params params;
[email protected]aeca23f2013-06-21 22:34:41386 base::DictionaryValue* params_value;
[email protected]752960d2012-07-23 19:06:11387 if (dictionary->GetDictionary("params", &params_value))
388 params.additional_properties.Swap(params_value);
389
Lei Zhang1f3ec9792021-05-18 00:00:28390 auto args(OnEvent::Create(debuggee_, method_name, params));
lazyboy59155a42017-05-24 22:23:35391 auto event =
Jinho Bangb5216cec2018-01-17 19:43:11392 std::make_unique<Event>(events::DEBUGGER_ON_EVENT, OnEvent::kEventName,
lazyboy59155a42017-05-24 22:23:35393 std::move(args), profile_);
Devlin Cronin4dafc3172018-06-22 23:16:31394 EventRouter::Get(profile_)->DispatchEventToExtension(extension_id(),
395 std::move(event));
[email protected]ac310102011-04-08 14:08:33396 } else {
Anand K. Mistryd3d86f52020-03-03 23:23:33397 auto it = pending_requests_.find(id);
398 if (it == pending_requests_.end())
[email protected]ac310102011-04-08 14:08:33399 return;
400
Anand K. Mistryd3d86f52020-03-03 23:23:33401 it->second->SendResponseBody(dictionary);
402 pending_requests_.erase(it);
[email protected]91ba3312011-03-17 20:39:22403 }
404}
405
Andrey Kosyakov0788b1d2019-12-10 04:28:11406bool ExtensionDevToolsClientHost::MayAttachToURL(const GURL& url,
407 bool is_webui) {
Devlin Cronin4dafc3172018-06-22 23:16:31408 if (is_webui)
409 return false;
Devlin Cronin4dafc3172018-06-22 23:16:31410 std::string error;
Andrey Kosyakov1ca6a4e2020-11-02 19:26:33411 if (!ExtensionMayAttachToURL(*extension_, url, profile_, &error))
412 return false;
413 // For nested URLs, make sure ExtensionMayAttachToURL() allows both
414 // the outer and the inner URLs.
415 if (url.inner_url() && !ExtensionMayAttachToURL(*extension_, *url.inner_url(),
416 profile_, &error)) {
417 return false;
418 }
419 return true;
Devlin Cronin4dafc3172018-06-22 23:16:31420}
[email protected]49c71ac2013-05-03 01:36:22421
Dmitry Gozman2731b562018-09-10 23:19:02422bool ExtensionDevToolsClientHost::MayAttachToBrowser() {
Andrey Kosyakovad5d2522020-01-07 22:42:49423 return ExtensionMayAttachToBrowser(*extension_);
Dmitry Gozman2731b562018-09-10 23:19:02424}
425
Dmitry Gozmana3023d22019-02-26 22:11:27426bool ExtensionDevToolsClientHost::MayReadLocalFiles() {
427 return util::AllowFileAccess(extension_->id(), profile_);
428}
429
430bool ExtensionDevToolsClientHost::MayWriteLocalFiles() {
Dmitry Gozmanc71d8042018-10-09 18:40:45431 return false;
432}
433
[email protected]49c71ac2013-05-03 01:36:22434// DebuggerFunction -----------------------------------------------------------
435
Lukasz Anforowiczc695e532020-06-09 02:09:45436DebuggerFunction::DebuggerFunction() : client_host_(nullptr) {}
[email protected]ac3851f2013-04-05 15:51:59437
Anand K. Mistryd3d86f52020-03-03 23:23:33438DebuggerFunction::~DebuggerFunction() = default;
[email protected]91ba3312011-03-17 20:39:22439
Anand K. Mistryd3d86f52020-03-03 23:23:33440std::string DebuggerFunction::FormatErrorMessage(const std::string& format) {
441 if (debuggee_.tab_id) {
442 return ErrorUtils::FormatErrorMessage(
oscarjohansson77164012018-06-11 07:00:11443 format, debugger_api_constants::kTabTargetType,
Raul Tambrefff51b752019-02-04 13:09:47444 base::NumberToString(*debuggee_.tab_id));
Anand K. Mistryd3d86f52020-03-03 23:23:33445 }
446 if (debuggee_.extension_id) {
447 return ErrorUtils::FormatErrorMessage(
oscarjohansson77164012018-06-11 07:00:11448 format, debugger_api_constants::kBackgroundPageTargetType,
449 *debuggee_.extension_id);
Anand K. Mistryd3d86f52020-03-03 23:23:33450 }
451
452 return ErrorUtils::FormatErrorMessage(
453 format, debugger_api_constants::kOpaqueTargetType, *debuggee_.target_id);
[email protected]2fefdb32013-02-26 14:28:10454}
455
Anand K. Mistryd3d86f52020-03-03 23:23:33456bool DebuggerFunction::InitAgentHost(std::string* error) {
[email protected]2fefdb32013-02-26 14:28:10457 if (debuggee_.tab_id) {
Istiaque Ahmed406b9182019-07-26 06:28:33458 WebContents* web_contents = nullptr;
Anand K. Mistryd3d86f52020-03-03 23:23:33459 bool result = ExtensionTabUtil::GetTabById(
460 *debuggee_.tab_id, browser_context(), include_incognito_information(),
461 &web_contents);
[email protected]56cc38042013-04-03 04:42:47462 if (result && web_contents) {
Andrey Kosyakovfa3dd0b2020-09-19 06:02:05463 if (!ExtensionMayAttachToWebContents(
464 *extension(), *web_contents,
Devlin Cronin6ac77aa2020-08-05 03:57:37465 Profile::FromBrowserContext(browser_context()), error)) {
[email protected]56cc38042013-04-03 04:42:47466 return false;
Anand K. Mistryd3d86f52020-03-03 23:23:33467 }
Devlin Cronin4dafc3172018-06-22 23:16:31468
[email protected]02a67fd2014-03-28 15:29:55469 agent_host_ = DevToolsAgentHost::GetOrCreateFor(web_contents);
[email protected]2fefdb32013-02-26 14:28:10470 }
[email protected]56cc38042013-04-03 04:42:47471 } else if (debuggee_.extension_id) {
[email protected]d32a92652014-05-09 11:06:15472 ExtensionHost* extension_host =
Anand K. Mistryd3d86f52020-03-03 23:23:33473 ProcessManager::Get(browser_context())
[email protected]21a40082013-10-28 21:19:23474 ->GetBackgroundHostForExtension(*debuggee_.extension_id);
[email protected]56cc38042013-04-03 04:42:47475 if (extension_host) {
Solomon Kinard3565a342021-04-07 22:29:27476 const GURL& url = extension_host->GetLastCommittedURL();
477 if (extension()->permissions_data()->IsRestrictedUrl(url, error) ||
478 extension()->permissions_data()->IsPolicyBlockedHost(url)) {
[email protected]684a212a2014-06-27 17:14:50479 return false;
480 }
[email protected]b3f957e62014-08-08 10:09:02481 agent_host_ =
482 DevToolsAgentHost::GetOrCreateFor(extension_host->host_contents());
[email protected]30e246b2013-03-28 17:08:48483 }
[email protected]56cc38042013-04-03 04:42:47484 } else if (debuggee_.target_id) {
Andrey Kosyakovfa3dd0b2020-09-19 06:02:05485 scoped_refptr<DevToolsAgentHost> agent_host =
486 DevToolsAgentHost::GetForId(*debuggee_.target_id);
487 if (agent_host) {
488 if (!ExtensionMayAttachToAgentHost(
489 *extension(), *agent_host,
490 Profile::FromBrowserContext(browser_context()), error)) {
rob409bf9d62015-02-10 23:37:07491 return false;
492 }
Andrey Kosyakovfa3dd0b2020-09-19 06:02:05493 agent_host_ = std::move(agent_host);
Andrey Kosyakovad5d2522020-01-07 22:42:49494 } else if (*debuggee_.target_id == kBrowserTargetId &&
495 ExtensionMayAttachToBrowser(*extension())) {
496 // TODO(caseq): get rid of the below code, browser agent host should
497 // really be a singleton.
498 // Re-use existing browser agent hosts.
499 const std::string& extension_id = extension()->id();
500 AttachedClientHosts& hosts = g_attached_client_hosts.Get();
501 auto it = std::find_if(
502 hosts.begin(), hosts.end(),
503 [&extension_id](ExtensionDevToolsClientHost* client_host) {
504 return client_host->extension_id() == extension_id &&
505 client_host->agent_host() &&
506 client_host->agent_host()->GetType() ==
507 DevToolsAgentHost::kTypeBrowser;
508 });
509 agent_host_ = it != hosts.end()
510 ? (*it)->agent_host()
511 : DevToolsAgentHost::CreateForBrowser(
512 nullptr /* tethering_task_runner */,
513 DevToolsAgentHost::CreateServerSocketCallback());
rob409bf9d62015-02-10 23:37:07514 }
[email protected]56cc38042013-04-03 04:42:47515 } else {
Anand K. Mistryd3d86f52020-03-03 23:23:33516 *error = debugger_api_constants::kInvalidTargetError;
[email protected]4e023cd2013-03-28 15:04:12517 return false;
518 }
[email protected]30e246b2013-03-28 17:08:48519
[email protected]dc24976f2013-06-02 21:15:09520 if (!agent_host_.get()) {
Anand K. Mistryd3d86f52020-03-03 23:23:33521 *error = FormatErrorMessage(debugger_api_constants::kNoTargetError);
[email protected]56cc38042013-04-03 04:42:47522 return false;
523 }
524 return true;
[email protected]91ba3312011-03-17 20:39:22525}
526
Anand K. Mistryd3d86f52020-03-03 23:23:33527bool DebuggerFunction::InitClientHost(std::string* error) {
528 if (!InitAgentHost(error))
[email protected]91ba3312011-03-17 20:39:22529 return false;
530
Dmitry Gozmaned41e022017-08-24 20:12:10531 client_host_ = FindClientHost();
532 if (!client_host_) {
Anand K. Mistryd3d86f52020-03-03 23:23:33533 *error = FormatErrorMessage(debugger_api_constants::kNotAttachedError);
Dmitry Gozmaned41e022017-08-24 20:12:10534 return false;
535 }
536
537 return true;
538}
539
540ExtensionDevToolsClientHost* DebuggerFunction::FindClientHost() {
541 if (!agent_host_.get())
542 return nullptr;
543
dgozmand06efdf2015-08-27 02:28:38544 const std::string& extension_id = extension()->id();
545 DevToolsAgentHost* agent_host = agent_host_.get();
546 AttachedClientHosts& hosts = g_attached_client_hosts.Get();
jdoerrie9be0b2b2018-10-05 10:10:05547 auto it = std::find_if(
dgozmand06efdf2015-08-27 02:28:38548 hosts.begin(), hosts.end(),
549 [&agent_host, &extension_id](ExtensionDevToolsClientHost* client_host) {
550 return client_host->agent_host() == agent_host &&
551 client_host->extension_id() == extension_id;
552 });
[email protected]91ba3312011-03-17 20:39:22553
Dmitry Gozmaned41e022017-08-24 20:12:10554 return it == hosts.end() ? nullptr : *it;
[email protected]91ba3312011-03-17 20:39:22555}
556
[email protected]49c71ac2013-05-03 01:36:22557// DebuggerAttachFunction -----------------------------------------------------
558
Anand K. Mistryd3d86f52020-03-03 23:23:33559DebuggerAttachFunction::DebuggerAttachFunction() = default;
[email protected]91ba3312011-03-17 20:39:22560
Anand K. Mistryd3d86f52020-03-03 23:23:33561DebuggerAttachFunction::~DebuggerAttachFunction() = default;
[email protected]91ba3312011-03-17 20:39:22562
Anand K. Mistryd3d86f52020-03-03 23:23:33563ExtensionFunction::ResponseAction DebuggerAttachFunction::Run() {
Alex Turnera6dba252021-08-18 01:29:05564 std::unique_ptr<Attach::Params> params(Attach::Params::Create(args()));
[email protected]752960d2012-07-23 19:06:11565 EXTENSION_FUNCTION_VALIDATE(params.get());
566
[email protected]28b05ef02013-07-10 22:28:32567 CopyDebuggee(&debuggee_, params->target);
Anand K. Mistryd3d86f52020-03-03 23:23:33568 std::string error;
569 if (!InitAgentHost(&error))
Devlin Cronin12b407642020-04-24 20:24:22570 return RespondNow(Error(std::move(error)));
[email protected]91ba3312011-03-17 20:39:22571
dgozman102fee92015-04-20 15:45:46572 if (!DevToolsAgentHost::IsSupportedProtocolVersion(
[email protected]be3577e2013-06-26 21:42:33573 params->required_version)) {
Anand K. Mistryd3d86f52020-03-03 23:23:33574 return RespondNow(Error(ErrorUtils::FormatErrorMessage(
oscarjohansson77164012018-06-11 07:00:11575 debugger_api_constants::kProtocolVersionNotSupportedError,
Anand K. Mistryd3d86f52020-03-03 23:23:33576 params->required_version)));
[email protected]c7580b62011-10-26 08:46:30577 }
578
Dmitry Gozmaned41e022017-08-24 20:12:10579 if (FindClientHost()) {
Anand K. Mistryd3d86f52020-03-03 23:23:33580 return RespondNow(Error(
581 FormatErrorMessage(debugger_api_constants::kAlreadyAttachedError)));
[email protected]91ba3312011-03-17 20:39:22582 }
583
Dmitry Gozman2aec794f2018-03-05 20:27:54584 auto host = std::make_unique<ExtensionDevToolsClientHost>(
Anand K. Mistryd3d86f52020-03-03 23:23:33585 Profile::FromBrowserContext(browser_context()), agent_host_.get(),
586 extension(), debuggee_);
Dmitry Gozman2aec794f2018-03-05 20:27:54587
588 if (!host->Attach()) {
Anand K. Mistryd3d86f52020-03-03 23:23:33589 return RespondNow(Error(debugger_api_constants::kRestrictedError));
Dmitry Gozman2aec794f2018-03-05 20:27:54590 }
591
592 host.release(); // An attached client host manages its own lifetime.
Anand K. Mistryd3d86f52020-03-03 23:23:33593 return RespondNow(NoArguments());
[email protected]91ba3312011-03-17 20:39:22594}
595
[email protected]49c71ac2013-05-03 01:36:22596// DebuggerDetachFunction -----------------------------------------------------
597
Anand K. Mistryd3d86f52020-03-03 23:23:33598DebuggerDetachFunction::DebuggerDetachFunction() = default;
[email protected]91ba3312011-03-17 20:39:22599
Anand K. Mistryd3d86f52020-03-03 23:23:33600DebuggerDetachFunction::~DebuggerDetachFunction() = default;
[email protected]91ba3312011-03-17 20:39:22601
Anand K. Mistryd3d86f52020-03-03 23:23:33602ExtensionFunction::ResponseAction DebuggerDetachFunction::Run() {
Alex Turnera6dba252021-08-18 01:29:05603 std::unique_ptr<Detach::Params> params(Detach::Params::Create(args()));
[email protected]752960d2012-07-23 19:06:11604 EXTENSION_FUNCTION_VALIDATE(params.get());
605
[email protected]28b05ef02013-07-10 22:28:32606 CopyDebuggee(&debuggee_, params->target);
Anand K. Mistryd3d86f52020-03-03 23:23:33607 std::string error;
608 if (!InitClientHost(&error))
Devlin Cronin12b407642020-04-24 20:24:22609 return RespondNow(Error(std::move(error)));
[email protected]91ba3312011-03-17 20:39:22610
Dmitry Gozman2aec794f2018-03-05 20:27:54611 client_host_->RespondDetachedToPendingRequests();
[email protected]91ba3312011-03-17 20:39:22612 client_host_->Close();
Anand K. Mistryd3d86f52020-03-03 23:23:33613 return RespondNow(NoArguments());
[email protected]91ba3312011-03-17 20:39:22614}
615
[email protected]49c71ac2013-05-03 01:36:22616// DebuggerSendCommandFunction ------------------------------------------------
617
Anand K. Mistryd3d86f52020-03-03 23:23:33618DebuggerSendCommandFunction::DebuggerSendCommandFunction() = default;
[email protected]91ba3312011-03-17 20:39:22619
Anand K. Mistryd3d86f52020-03-03 23:23:33620DebuggerSendCommandFunction::~DebuggerSendCommandFunction() = default;
[email protected]91ba3312011-03-17 20:39:22621
Anand K. Mistryd3d86f52020-03-03 23:23:33622ExtensionFunction::ResponseAction DebuggerSendCommandFunction::Run() {
dchengc963c7142016-04-08 03:55:22623 std::unique_ptr<SendCommand::Params> params(
Alex Turnera6dba252021-08-18 01:29:05624 SendCommand::Params::Create(args()));
[email protected]752960d2012-07-23 19:06:11625 EXTENSION_FUNCTION_VALIDATE(params.get());
[email protected]91ba3312011-03-17 20:39:22626
[email protected]28b05ef02013-07-10 22:28:32627 CopyDebuggee(&debuggee_, params->target);
Anand K. Mistryd3d86f52020-03-03 23:23:33628 std::string error;
629 if (!InitClientHost(&error))
Devlin Cronin12b407642020-04-24 20:24:22630 return RespondNow(Error(std::move(error)));
[email protected]91ba3312011-03-17 20:39:22631
[email protected]752960d2012-07-23 19:06:11632 client_host_->SendMessageToBackend(this, params->method,
633 params->command_params.get());
Anand K. Mistryd3d86f52020-03-03 23:23:33634 if (did_respond())
635 return AlreadyResponded();
636 return RespondLater();
[email protected]91ba3312011-03-17 20:39:22637}
[email protected]ff31a8a2011-03-30 14:13:59638
[email protected]4636c832013-01-11 02:10:11639void DebuggerSendCommandFunction::SendResponseBody(
[email protected]aeca23f2013-06-21 22:34:41640 base::DictionaryValue* response) {
[email protected]5bcdd99d2013-12-23 18:28:30641 base::Value* error_body;
[email protected]752960d2012-07-23 19:06:11642 if (response->Get("error", &error_body)) {
Anand K. Mistryd3d86f52020-03-03 23:23:33643 std::string error;
644 base::JSONWriter::Write(*error_body, &error);
Devlin Cronin12b407642020-04-24 20:24:22645 Respond(Error(std::move(error)));
[email protected]ff31a8a2011-03-30 14:13:59646 return;
647 }
648
[email protected]aeca23f2013-06-21 22:34:41649 base::DictionaryValue* result_body;
[email protected]752960d2012-07-23 19:06:11650 SendCommand::Results::Result result;
651 if (response->GetDictionary("result", &result_body))
652 result.additional_properties.Swap(result_body);
653
Anand K. Mistryd3d86f52020-03-03 23:23:33654 Respond(ArgumentList(SendCommand::Results::Create(result)));
[email protected]ff31a8a2011-03-30 14:13:59655}
[email protected]56cc38042013-04-03 04:42:47656
Dmitry Gozman2aec794f2018-03-05 20:27:54657void DebuggerSendCommandFunction::SendDetachedError() {
Anand K. Mistryd3d86f52020-03-03 23:23:33658 Respond(Error(debugger_api_constants::kDetachedWhileHandlingError));
Dmitry Gozman2aec794f2018-03-05 20:27:54659}
[email protected]49c71ac2013-05-03 01:36:22660
661// DebuggerGetTargetsFunction -------------------------------------------------
662
[email protected]28b05ef02013-07-10 22:28:32663namespace {
[email protected]56cc38042013-04-03 04:42:47664
[email protected]28b05ef02013-07-10 22:28:32665const char kTargetIdField[] = "id";
666const char kTargetTypeField[] = "type";
667const char kTargetTitleField[] = "title";
668const char kTargetAttachedField[] = "attached";
669const char kTargetUrlField[] = "url";
670const char kTargetFaviconUrlField[] = "faviconUrl";
[email protected]f80e0be62013-07-17 14:17:23671const char kTargetTabIdField[] = "tabId";
672const char kTargetExtensionIdField[] = "extensionId";
Dmitry Gozman2731b562018-09-10 23:19:02673const char kTargetTypePage[] = "page";
674const char kTargetTypeBackgroundPage[] = "background_page";
pfeldmana9e7dda2016-08-26 14:35:17675const char kTargetTypeWorker[] = "worker";
Dmitry Gozman2731b562018-09-10 23:19:02676const char kTargetTypeOther[] = "other";
[email protected]28b05ef02013-07-10 22:28:32677
dchengf19502002016-09-14 15:18:18678std::unique_ptr<base::DictionaryValue> SerializeTarget(
679 scoped_refptr<DevToolsAgentHost> host) {
680 std::unique_ptr<base::DictionaryValue> dictionary(
681 new base::DictionaryValue());
pfeldmana9e7dda2016-08-26 14:35:17682 dictionary->SetString(kTargetIdField, host->GetId());
683 dictionary->SetString(kTargetTitleField, host->GetTitle());
684 dictionary->SetBoolean(kTargetAttachedField, host->IsAttached());
685 dictionary->SetString(kTargetUrlField, host->GetURL().spec());
[email protected]28b05ef02013-07-10 22:28:32686
pfeldmana9e7dda2016-08-26 14:35:17687 std::string type = host->GetType();
Dmitry Gozman2731b562018-09-10 23:19:02688 std::string target_type = kTargetTypeOther;
pfeldmana9e7dda2016-08-26 14:35:17689 if (type == DevToolsAgentHost::kTypePage) {
690 int tab_id =
691 extensions::ExtensionTabUtil::GetTabId(host->GetWebContents());
692 dictionary->SetInteger(kTargetTabIdField, tab_id);
Dmitry Gozman2731b562018-09-10 23:19:02693 target_type = kTargetTypePage;
pfeldmana9e7dda2016-08-26 14:35:17694 } else if (type == ChromeDevToolsManagerDelegate::kTypeBackgroundPage) {
695 dictionary->SetString(kTargetExtensionIdField, host->GetURL().host());
Dmitry Gozman2731b562018-09-10 23:19:02696 target_type = kTargetTypeBackgroundPage;
697 } else if (type == DevToolsAgentHost::kTypeServiceWorker ||
698 type == DevToolsAgentHost::kTypeSharedWorker) {
699 target_type = kTargetTypeWorker;
[email protected]28b05ef02013-07-10 22:28:32700 }
pfeldmana9e7dda2016-08-26 14:35:17701
Dmitry Gozman2731b562018-09-10 23:19:02702 dictionary->SetString(kTargetTypeField, target_type);
[email protected]28b05ef02013-07-10 22:28:32703
pfeldmana9e7dda2016-08-26 14:35:17704 GURL favicon_url = host->GetFaviconURL();
[email protected]06d503f2013-10-29 17:29:37705 if (favicon_url.is_valid())
706 dictionary->SetString(kTargetFaviconUrlField, favicon_url.spec());
[email protected]28b05ef02013-07-10 22:28:32707
708 return dictionary;
709}
710
[email protected]4edaf7ec2014-05-07 13:54:15711} // namespace
[email protected]28b05ef02013-07-10 22:28:32712
Anand K. Mistryd3d86f52020-03-03 23:23:33713DebuggerGetTargetsFunction::DebuggerGetTargetsFunction() = default;
[email protected]28b05ef02013-07-10 22:28:32714
Anand K. Mistryd3d86f52020-03-03 23:23:33715DebuggerGetTargetsFunction::~DebuggerGetTargetsFunction() = default;
[email protected]56cc38042013-04-03 04:42:47716
Anand K. Mistryd3d86f52020-03-03 23:23:33717ExtensionFunction::ResponseAction DebuggerGetTargetsFunction::Run() {
pfeldmanbc5d7882016-08-26 18:55:46718 content::DevToolsAgentHost::List list = DevToolsAgentHost::GetOrCreateAll();
dchengc963c7142016-04-08 03:55:22719 std::unique_ptr<base::ListValue> result(new base::ListValue());
Anand K. Mistryd3d86f52020-03-03 23:23:33720 for (size_t i = 0; i < list.size(); ++i)
721 result->Append(SerializeTarget(list[i]));
722
Lei Zhang27a55092020-10-23 22:07:05723 return RespondNow(
724 OneArgument(base::Value::FromUniquePtrValue(std::move(result))));
[email protected]ac3851f2013-04-05 15:51:59725}
[email protected]d32a92652014-05-09 11:06:15726
727} // namespace extensions