Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / api / debugger / debugger_api.cc
blob757950305bc701fcc1d5f089bf985a5369db29bb
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Implements the Chrome Extensions Debugger API.
7 #include "chrome/browser/extensions/api/debugger/debugger_api.h"
9 #include <map>
10 #include <set>
12 #include "base/command_line.h"
13 #include "base/json/json_reader.h"
14 #include "base/json/json_writer.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/memory/singleton.h"
17 #include "base/scoped_observer.h"
18 #include "base/stl_util.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/values.h"
22 #include "chrome/browser/chrome_notification_types.h"
23 #include "chrome/browser/devtools/devtools_target_impl.h"
24 #include "chrome/browser/extensions/api/debugger/debugger_api_constants.h"
25 #include "chrome/browser/extensions/extension_service.h"
26 #include "chrome/browser/extensions/extension_tab_util.h"
27 #include "chrome/browser/infobars/infobar_service.h"
28 #include "chrome/browser/profiles/profile.h"
29 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/grit/generated_resources.h"
32 #include "components/infobars/core/confirm_infobar_delegate.h"
33 #include "components/infobars/core/infobar.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/devtools_agent_host.h"
36 #include "content/public/browser/notification_service.h"
37 #include "content/public/browser/notification_source.h"
38 #include "content/public/browser/render_process_host.h"
39 #include "content/public/browser/render_view_host.h"
40 #include "content/public/browser/render_widget_host.h"
41 #include "content/public/browser/web_contents.h"
42 #include "content/public/common/content_client.h"
43 #include "content/public/common/url_utils.h"
44 #include "extensions/browser/event_router.h"
45 #include "extensions/browser/extension_host.h"
46 #include "extensions/browser/extension_registry.h"
47 #include "extensions/browser/extension_registry_observer.h"
48 #include "extensions/common/constants.h"
49 #include "extensions/common/error_utils.h"
50 #include "extensions/common/extension.h"
51 #include "extensions/common/manifest_constants.h"
52 #include "extensions/common/permissions/permissions_data.h"
53 #include "extensions/common/switches.h"
54 #include "ui/base/l10n/l10n_util.h"
56 using content::DevToolsAgentHost;
57 using content::RenderProcessHost;
58 using content::RenderViewHost;
59 using content::RenderWidgetHost;
60 using content::WebContents;
62 namespace keys = debugger_api_constants;
63 namespace Attach = extensions::api::debugger::Attach;
64 namespace Detach = extensions::api::debugger::Detach;
65 namespace OnDetach = extensions::api::debugger::OnDetach;
66 namespace OnEvent = extensions::api::debugger::OnEvent;
67 namespace SendCommand = extensions::api::debugger::SendCommand;
69 namespace extensions {
70 class ExtensionRegistry;
72 // ExtensionDevToolsClientHost ------------------------------------------------
74 class ExtensionDevToolsClientHost : public content::DevToolsAgentHostClient,
75 public content::NotificationObserver,
76 public ExtensionRegistryObserver {
77 public:
78 ExtensionDevToolsClientHost(Profile* profile,
79 DevToolsAgentHost* agent_host,
80 const std::string& extension_id,
81 const std::string& extension_name,
82 const Debuggee& debuggee,
83 infobars::InfoBar* infobar);
85 ~ExtensionDevToolsClientHost() override;
87 const std::string& extension_id() { return extension_id_; }
88 DevToolsAgentHost* agent_host() { return agent_host_.get(); }
89 void Close();
90 void SendMessageToBackend(DebuggerSendCommandFunction* function,
91 const std::string& method,
92 SendCommand::Params::CommandParams* command_params);
94 // Marks connection as to-be-terminated by the user.
95 void MarkAsDismissed();
97 // DevToolsAgentHostClient interface.
98 void AgentHostClosed(DevToolsAgentHost* agent_host,
99 bool replaced_with_another_client) override;
100 void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
101 const std::string& message) override;
103 private:
104 void SendDetachedEvent();
106 // content::NotificationObserver implementation.
107 void Observe(int type,
108 const content::NotificationSource& source,
109 const content::NotificationDetails& details) override;
111 // ExtensionRegistryObserver implementation.
112 void OnExtensionUnloaded(content::BrowserContext* browser_context,
113 const Extension* extension,
114 UnloadedExtensionInfo::Reason reason) override;
116 Profile* profile_;
117 scoped_refptr<DevToolsAgentHost> agent_host_;
118 std::string extension_id_;
119 Debuggee debuggee_;
120 content::NotificationRegistrar registrar_;
121 int last_request_id_;
122 typedef std::map<int, scoped_refptr<DebuggerSendCommandFunction> >
123 PendingRequests;
124 PendingRequests pending_requests_;
125 infobars::InfoBar* infobar_;
126 api::debugger::DetachReason detach_reason_;
128 // Listen to extension unloaded notification.
129 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
130 extension_registry_observer_;
132 DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsClientHost);
135 // The member function declarations come after the other class declarations, so
136 // they can call members on them.
139 namespace {
141 // Helpers --------------------------------------------------------------------
143 void CopyDebuggee(Debuggee* dst, const Debuggee& src) {
144 if (src.tab_id)
145 dst->tab_id.reset(new int(*src.tab_id));
146 if (src.extension_id)
147 dst->extension_id.reset(new std::string(*src.extension_id));
148 if (src.target_id)
149 dst->target_id.reset(new std::string(*src.target_id));
153 // ExtensionDevToolsInfoBarDelegate -------------------------------------------
155 class ExtensionDevToolsInfoBarDelegate : public ConfirmInfoBarDelegate {
156 public:
157 // Creates an extension dev tools infobar and delegate and adds the infobar to
158 // the InfoBarService associated with |rvh|. Returns the infobar if it was
159 // successfully added.
160 static infobars::InfoBar* Create(WebContents* web_contents,
161 const std::string& client_name);
163 void set_client_host(ExtensionDevToolsClientHost* client_host) {
164 client_host_ = client_host;
167 private:
168 explicit ExtensionDevToolsInfoBarDelegate(const std::string& client_name);
169 ~ExtensionDevToolsInfoBarDelegate() override;
171 // ConfirmInfoBarDelegate:
172 Type GetInfoBarType() const override;
173 bool ShouldExpire(const NavigationDetails& details) const override;
174 void InfoBarDismissed() override;
175 base::string16 GetMessageText() const override;
176 int GetButtons() const override;
177 bool Cancel() override;
179 std::string client_name_;
180 ExtensionDevToolsClientHost* client_host_;
182 DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsInfoBarDelegate);
185 // static
186 infobars::InfoBar* ExtensionDevToolsInfoBarDelegate::Create(
187 WebContents* web_contents,
188 const std::string& client_name) {
189 if (!web_contents)
190 return NULL;
192 InfoBarService* infobar_service =
193 InfoBarService::FromWebContents(web_contents);
194 if (!infobar_service)
195 return NULL;
197 return infobar_service->AddInfoBar(
198 infobar_service->CreateConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
199 new ExtensionDevToolsInfoBarDelegate(client_name))));
202 ExtensionDevToolsInfoBarDelegate::ExtensionDevToolsInfoBarDelegate(
203 const std::string& client_name)
204 : ConfirmInfoBarDelegate(),
205 client_name_(client_name),
206 client_host_(NULL) {
209 ExtensionDevToolsInfoBarDelegate::~ExtensionDevToolsInfoBarDelegate() {
212 infobars::InfoBarDelegate::Type
213 ExtensionDevToolsInfoBarDelegate::GetInfoBarType() const {
214 return WARNING_TYPE;
217 bool ExtensionDevToolsInfoBarDelegate::ShouldExpire(
218 const NavigationDetails& details) const {
219 return false;
222 void ExtensionDevToolsInfoBarDelegate::InfoBarDismissed() {
223 if (client_host_)
224 client_host_->MarkAsDismissed();
227 base::string16 ExtensionDevToolsInfoBarDelegate::GetMessageText() const {
228 return l10n_util::GetStringFUTF16(IDS_DEV_TOOLS_INFOBAR_LABEL,
229 base::UTF8ToUTF16(client_name_));
232 int ExtensionDevToolsInfoBarDelegate::GetButtons() const {
233 return BUTTON_CANCEL;
236 bool ExtensionDevToolsInfoBarDelegate::Cancel() {
237 InfoBarDismissed();
238 return true;
242 // AttachedClientHosts --------------------------------------------------------
244 class AttachedClientHosts {
245 public:
246 AttachedClientHosts();
247 ~AttachedClientHosts();
249 // Returns the singleton instance of this class.
250 static AttachedClientHosts* GetInstance();
252 void Add(ExtensionDevToolsClientHost* client_host);
253 void Remove(ExtensionDevToolsClientHost* client_host);
254 ExtensionDevToolsClientHost* Lookup(DevToolsAgentHost* agent_host,
255 const std::string& extension_id);
257 private:
258 typedef std::set<ExtensionDevToolsClientHost*> ClientHosts;
259 ClientHosts client_hosts_;
261 DISALLOW_COPY_AND_ASSIGN(AttachedClientHosts);
264 AttachedClientHosts::AttachedClientHosts() {
267 AttachedClientHosts::~AttachedClientHosts() {
270 // static
271 AttachedClientHosts* AttachedClientHosts::GetInstance() {
272 return Singleton<AttachedClientHosts>::get();
275 void AttachedClientHosts::Add(ExtensionDevToolsClientHost* client_host) {
276 client_hosts_.insert(client_host);
279 void AttachedClientHosts::Remove(ExtensionDevToolsClientHost* client_host) {
280 client_hosts_.erase(client_host);
283 ExtensionDevToolsClientHost* AttachedClientHosts::Lookup(
284 DevToolsAgentHost* agent_host,
285 const std::string& extension_id) {
286 for (ClientHosts::iterator it = client_hosts_.begin();
287 it != client_hosts_.end(); ++it) {
288 ExtensionDevToolsClientHost* client_host = *it;
289 if (client_host->agent_host() == agent_host &&
290 client_host->extension_id() == extension_id)
291 return client_host;
293 return NULL;
296 } // namespace
299 // ExtensionDevToolsClientHost ------------------------------------------------
301 ExtensionDevToolsClientHost::ExtensionDevToolsClientHost(
302 Profile* profile,
303 DevToolsAgentHost* agent_host,
304 const std::string& extension_id,
305 const std::string& extension_name,
306 const Debuggee& debuggee,
307 infobars::InfoBar* infobar)
308 : profile_(profile),
309 agent_host_(agent_host),
310 extension_id_(extension_id),
311 last_request_id_(0),
312 infobar_(infobar),
313 detach_reason_(api::debugger::DETACH_REASON_TARGET_CLOSED),
314 extension_registry_observer_(this) {
315 CopyDebuggee(&debuggee_, debuggee);
317 AttachedClientHosts::GetInstance()->Add(this);
319 // ExtensionRegistryObserver listen extension unloaded and detach debugger
320 // from there.
321 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
323 // RVH-based agents disconnect from their clients when the app is terminating
324 // but shared worker-based agents do not.
325 // Disconnect explicitly to make sure that |this| observer is not leaked.
326 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
327 content::NotificationService::AllSources());
329 // Attach to debugger and tell it we are ready.
330 agent_host_->AttachClient(this);
332 if (infobar_) {
333 static_cast<ExtensionDevToolsInfoBarDelegate*>(
334 infobar_->delegate())->set_client_host(this);
335 registrar_.Add(
336 this,
337 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
338 content::Source<InfoBarService>(
339 InfoBarService::FromWebContents(agent_host_->GetWebContents())));
343 ExtensionDevToolsClientHost::~ExtensionDevToolsClientHost() {
344 // Ensure calling RemoveInfoBar() below won't result in Observe() trying to
345 // Close() us.
346 registrar_.RemoveAll();
348 if (infobar_) {
349 static_cast<ExtensionDevToolsInfoBarDelegate*>(
350 infobar_->delegate())->set_client_host(NULL);
351 InfoBarService* infobar_service =
352 InfoBarService::FromWebContents(agent_host_->GetWebContents());
353 infobar_service->RemoveInfoBar(infobar_);
355 AttachedClientHosts::GetInstance()->Remove(this);
358 // DevToolsAgentHostClient implementation.
359 void ExtensionDevToolsClientHost::AgentHostClosed(
360 DevToolsAgentHost* agent_host, bool replaced_with_another_client) {
361 DCHECK(agent_host == agent_host_.get());
362 if (replaced_with_another_client)
363 detach_reason_ = api::debugger::DETACH_REASON_REPLACED_WITH_DEVTOOLS;
364 SendDetachedEvent();
365 delete this;
368 void ExtensionDevToolsClientHost::Close() {
369 agent_host_->DetachClient();
370 delete this;
373 void ExtensionDevToolsClientHost::SendMessageToBackend(
374 DebuggerSendCommandFunction* function,
375 const std::string& method,
376 SendCommand::Params::CommandParams* command_params) {
377 base::DictionaryValue protocol_request;
378 int request_id = ++last_request_id_;
379 pending_requests_[request_id] = function;
380 protocol_request.SetInteger("id", request_id);
381 protocol_request.SetString("method", method);
382 if (command_params) {
383 protocol_request.Set("params",
384 command_params->additional_properties.DeepCopy());
387 std::string json_args;
388 base::JSONWriter::Write(protocol_request, &json_args);
389 agent_host_->DispatchProtocolMessage(json_args);
392 void ExtensionDevToolsClientHost::MarkAsDismissed() {
393 detach_reason_ = api::debugger::DETACH_REASON_CANCELED_BY_USER;
396 void ExtensionDevToolsClientHost::SendDetachedEvent() {
397 if (!EventRouter::Get(profile_))
398 return;
400 scoped_ptr<base::ListValue> args(OnDetach::Create(debuggee_,
401 detach_reason_));
402 scoped_ptr<Event> event(
403 new Event(events::DEBUGGER_ON_DETACH, OnDetach::kEventName, args.Pass()));
404 event->restrict_to_browser_context = profile_;
405 EventRouter::Get(profile_)
406 ->DispatchEventToExtension(extension_id_, event.Pass());
409 void ExtensionDevToolsClientHost::OnExtensionUnloaded(
410 content::BrowserContext* browser_context,
411 const Extension* extension,
412 UnloadedExtensionInfo::Reason reason) {
413 if (extension->id() == extension_id_)
414 Close();
417 void ExtensionDevToolsClientHost::Observe(
418 int type,
419 const content::NotificationSource& source,
420 const content::NotificationDetails& details) {
421 switch (type) {
422 case chrome::NOTIFICATION_APP_TERMINATING:
423 Close();
424 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();
432 break;
433 default:
434 NOTREACHED();
438 void ExtensionDevToolsClientHost::DispatchProtocolMessage(
439 DevToolsAgentHost* agent_host, const std::string& message) {
440 DCHECK(agent_host == agent_host_.get());
441 if (!EventRouter::Get(profile_))
442 return;
444 scoped_ptr<base::Value> result = base::JSONReader::Read(message);
445 if (!result->IsType(base::Value::TYPE_DICTIONARY))
446 return;
447 base::DictionaryValue* dictionary =
448 static_cast<base::DictionaryValue*>(result.get());
450 int id;
451 if (!dictionary->GetInteger("id", &id)) {
452 std::string method_name;
453 if (!dictionary->GetString("method", &method_name))
454 return;
456 OnEvent::Params params;
457 base::DictionaryValue* params_value;
458 if (dictionary->GetDictionary("params", &params_value))
459 params.additional_properties.Swap(params_value);
461 scoped_ptr<base::ListValue> args(
462 OnEvent::Create(debuggee_, method_name, params));
463 scoped_ptr<Event> event(
464 new Event(events::DEBUGGER_ON_EVENT, OnEvent::kEventName, args.Pass()));
465 event->restrict_to_browser_context = profile_;
466 EventRouter::Get(profile_)
467 ->DispatchEventToExtension(extension_id_, event.Pass());
468 } else {
469 DebuggerSendCommandFunction* function = pending_requests_[id].get();
470 if (!function)
471 return;
473 function->SendResponseBody(dictionary);
474 pending_requests_.erase(id);
479 // DebuggerFunction -----------------------------------------------------------
481 DebuggerFunction::DebuggerFunction()
482 : client_host_(NULL) {
485 DebuggerFunction::~DebuggerFunction() {
488 void DebuggerFunction::FormatErrorMessage(const std::string& format) {
489 if (debuggee_.tab_id)
490 error_ = ErrorUtils::FormatErrorMessage(
491 format, keys::kTabTargetType, base::IntToString(*debuggee_.tab_id));
492 else if (debuggee_.extension_id)
493 error_ = ErrorUtils::FormatErrorMessage(
494 format, keys::kBackgroundPageTargetType, *debuggee_.extension_id);
495 else
496 error_ = ErrorUtils::FormatErrorMessage(
497 format, keys::kOpaqueTargetType, *debuggee_.target_id);
500 bool DebuggerFunction::InitAgentHost() {
501 if (debuggee_.tab_id) {
502 WebContents* web_contents = NULL;
503 bool result = ExtensionTabUtil::GetTabById(*debuggee_.tab_id,
504 GetProfile(),
505 include_incognito(),
506 NULL,
507 NULL,
508 &web_contents,
509 NULL);
510 if (result && web_contents) {
511 // TODO(rdevlin.cronin) This should definitely be GetLastCommittedURL().
512 GURL url = web_contents->GetVisibleURL();
513 if (PermissionsData::IsRestrictedUrl(url, extension(), &error_))
514 return false;
515 agent_host_ = DevToolsAgentHost::GetOrCreateFor(web_contents);
517 } else if (debuggee_.extension_id) {
518 ExtensionHost* extension_host =
519 ProcessManager::Get(GetProfile())
520 ->GetBackgroundHostForExtension(*debuggee_.extension_id);
521 if (extension_host) {
522 if (PermissionsData::IsRestrictedUrl(extension_host->GetURL(),
523 extension(),
524 &error_)) {
525 return false;
527 agent_host_ =
528 DevToolsAgentHost::GetOrCreateFor(extension_host->host_contents());
530 } else if (debuggee_.target_id) {
531 agent_host_ = DevToolsAgentHost::GetForId(*debuggee_.target_id);
532 if (agent_host_.get()) {
533 if (PermissionsData::IsRestrictedUrl(agent_host_->GetURL(),
534 extension(),
535 &error_)) {
536 agent_host_ = nullptr;
537 return false;
540 } else {
541 error_ = keys::kInvalidTargetError;
542 return false;
545 if (!agent_host_.get()) {
546 FormatErrorMessage(keys::kNoTargetError);
547 return false;
549 return true;
552 bool DebuggerFunction::InitClientHost() {
553 if (!InitAgentHost())
554 return false;
556 client_host_ = AttachedClientHosts::GetInstance()->Lookup(agent_host_.get(),
557 extension()->id());
559 if (!client_host_) {
560 FormatErrorMessage(keys::kNotAttachedError);
561 return false;
563 return true;
567 // DebuggerAttachFunction -----------------------------------------------------
569 DebuggerAttachFunction::DebuggerAttachFunction() {
572 DebuggerAttachFunction::~DebuggerAttachFunction() {
575 bool DebuggerAttachFunction::RunAsync() {
576 scoped_ptr<Attach::Params> params(Attach::Params::Create(*args_));
577 EXTENSION_FUNCTION_VALIDATE(params.get());
579 CopyDebuggee(&debuggee_, params->target);
580 if (!InitAgentHost())
581 return false;
583 if (!DevToolsAgentHost::IsSupportedProtocolVersion(
584 params->required_version)) {
585 error_ = ErrorUtils::FormatErrorMessage(
586 keys::kProtocolVersionNotSupportedError,
587 params->required_version);
588 return false;
591 if (agent_host_->IsAttached()) {
592 FormatErrorMessage(keys::kAlreadyAttachedError);
593 return false;
596 infobars::InfoBar* infobar = NULL;
597 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
598 ::switches::kSilentDebuggerExtensionAPI)) {
599 // Do not attach to the target if for any reason the infobar cannot be shown
600 // for this WebContents instance.
601 infobar = ExtensionDevToolsInfoBarDelegate::Create(
602 agent_host_->GetWebContents(), extension()->name());
603 if (!infobar) {
604 error_ = ErrorUtils::FormatErrorMessage(
605 keys::kSilentDebuggingRequired,
606 ::switches::kSilentDebuggerExtensionAPI);
607 return false;
611 new ExtensionDevToolsClientHost(GetProfile(),
612 agent_host_.get(),
613 extension()->id(),
614 extension()->name(),
615 debuggee_,
616 infobar);
617 SendResponse(true);
618 return true;
622 // DebuggerDetachFunction -----------------------------------------------------
624 DebuggerDetachFunction::DebuggerDetachFunction() {
627 DebuggerDetachFunction::~DebuggerDetachFunction() {
630 bool DebuggerDetachFunction::RunAsync() {
631 scoped_ptr<Detach::Params> params(Detach::Params::Create(*args_));
632 EXTENSION_FUNCTION_VALIDATE(params.get());
634 CopyDebuggee(&debuggee_, params->target);
635 if (!InitClientHost())
636 return false;
638 client_host_->Close();
639 SendResponse(true);
640 return true;
644 // DebuggerSendCommandFunction ------------------------------------------------
646 DebuggerSendCommandFunction::DebuggerSendCommandFunction() {
649 DebuggerSendCommandFunction::~DebuggerSendCommandFunction() {
652 bool DebuggerSendCommandFunction::RunAsync() {
653 scoped_ptr<SendCommand::Params> params(SendCommand::Params::Create(*args_));
654 EXTENSION_FUNCTION_VALIDATE(params.get());
656 CopyDebuggee(&debuggee_, params->target);
657 if (!InitClientHost())
658 return false;
660 client_host_->SendMessageToBackend(this, params->method,
661 params->command_params.get());
662 return true;
665 void DebuggerSendCommandFunction::SendResponseBody(
666 base::DictionaryValue* response) {
667 base::Value* error_body;
668 if (response->Get("error", &error_body)) {
669 base::JSONWriter::Write(*error_body, &error_);
670 SendResponse(false);
671 return;
674 base::DictionaryValue* result_body;
675 SendCommand::Results::Result result;
676 if (response->GetDictionary("result", &result_body))
677 result.additional_properties.Swap(result_body);
679 results_ = SendCommand::Results::Create(result);
680 SendResponse(true);
684 // DebuggerGetTargetsFunction -------------------------------------------------
686 namespace {
688 const char kTargetIdField[] = "id";
689 const char kTargetTypeField[] = "type";
690 const char kTargetTitleField[] = "title";
691 const char kTargetAttachedField[] = "attached";
692 const char kTargetUrlField[] = "url";
693 const char kTargetFaviconUrlField[] = "faviconUrl";
694 const char kTargetTypePage[] = "page";
695 const char kTargetTypeBackgroundPage[] = "background_page";
696 const char kTargetTypeWorker[] = "worker";
697 const char kTargetTypeOther[] = "other";
698 const char kTargetTabIdField[] = "tabId";
699 const char kTargetExtensionIdField[] = "extensionId";
701 base::Value* SerializeTarget(const DevToolsTargetImpl& target) {
702 base::DictionaryValue* dictionary = new base::DictionaryValue();
704 dictionary->SetString(kTargetIdField, target.GetId());
705 dictionary->SetString(kTargetTitleField, target.GetTitle());
706 dictionary->SetBoolean(kTargetAttachedField, target.IsAttached());
707 dictionary->SetString(kTargetUrlField, target.GetURL().spec());
709 std::string type = target.GetType();
710 if (type == kTargetTypePage) {
711 dictionary->SetInteger(kTargetTabIdField, target.GetTabId());
712 } else if (type == kTargetTypeBackgroundPage) {
713 dictionary->SetString(kTargetExtensionIdField, target.GetExtensionId());
714 } else if (type != kTargetTypeWorker) {
715 // DevToolsTargetImpl may support more types than the debugger API.
716 type = kTargetTypeOther;
718 dictionary->SetString(kTargetTypeField, type);
720 GURL favicon_url = target.GetFaviconURL();
721 if (favicon_url.is_valid())
722 dictionary->SetString(kTargetFaviconUrlField, favicon_url.spec());
724 return dictionary;
727 } // namespace
729 DebuggerGetTargetsFunction::DebuggerGetTargetsFunction() {
732 DebuggerGetTargetsFunction::~DebuggerGetTargetsFunction() {
735 bool DebuggerGetTargetsFunction::RunAsync() {
736 std::vector<DevToolsTargetImpl*> list = DevToolsTargetImpl::EnumerateAll();
737 content::BrowserThread::PostTask(
738 content::BrowserThread::UI,
739 FROM_HERE,
740 base::Bind(&DebuggerGetTargetsFunction::SendTargetList, this, list));
741 return true;
744 void DebuggerGetTargetsFunction::SendTargetList(
745 const std::vector<DevToolsTargetImpl*>& target_list) {
746 scoped_ptr<base::ListValue> result(new base::ListValue());
747 for (size_t i = 0; i < target_list.size(); ++i)
748 result->Append(SerializeTarget(*target_list[i]));
749 STLDeleteContainerPointers(target_list.begin(), target_list.end());
750 SetResult(result.release());
751 SendResponse(true);
754 } // namespace extensions