15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implements the Chrome Extensions Debugger API. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/debugger/debugger_api.h" 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <map> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set> 1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/command_line.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_reader.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_writer.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/memory/singleton.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/scoped_observer.h" 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/stl_util.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/string_number_conversions.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/utf_string_conversions.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chrome_notification_types.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/devtools/devtools_target_impl.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/debugger/debugger_api_constants.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h" 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_tab_util.h" 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/infobars/infobar_service.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/grit/generated_resources.h" 3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "components/infobars/core/confirm_infobar_delegate.h" 3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "components/infobars/core/infobar.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/devtools_agent_host.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/devtools_http_handler.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_widget_host.h" 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/web_contents.h" 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/content_client.h" 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/common/url_utils.h" 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/browser/event_router.h" 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "extensions/browser/extension_host.h" 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "extensions/browser/extension_registry.h" 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "extensions/browser/extension_registry_observer.h" 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "extensions/browser/extension_system.h" 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "extensions/common/constants.h" 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "extensions/common/error_utils.h" 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "extensions/common/extension.h" 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "extensions/common/manifest_constants.h" 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "extensions/common/permissions/permissions_data.h" 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "extensions/common/switches.h" 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using content::DevToolsAgentHost; 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using content::DevToolsHttpHandler; 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using content::RenderProcessHost; 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using content::RenderViewHost; 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using content::RenderWidgetHost; 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using content::WebContents; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace keys = debugger_api_constants; 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace Attach = extensions::api::debugger::Attach; 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace Detach = extensions::api::debugger::Detach; 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace OnDetach = extensions::api::debugger::OnDetach; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace OnEvent = extensions::api::debugger::OnEvent; 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace SendCommand = extensions::api::debugger::SendCommand; 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ExtensionRegistry; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ExtensionDevToolsClientHost ------------------------------------------------ 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ExtensionDevToolsClientHost : public content::DevToolsAgentHostClient, 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public content::NotificationObserver, 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public ExtensionRegistryObserver { 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionDevToolsClientHost(Profile* profile, 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DevToolsAgentHost* agent_host, 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_name, 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const Debuggee& debuggee, 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) infobars::InfoBar* infobar); 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual ~ExtensionDevToolsClientHost(); 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& extension_id() { return extension_id_; } 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DevToolsAgentHost* agent_host() { return agent_host_.get(); } 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void Close(); 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void SendMessageToBackend(DebuggerSendCommandFunction* function, 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& method, 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SendCommand::Params::CommandParams* command_params); 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Marks connection as to-be-terminated by the user. 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void MarkAsDismissed(); 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DevToolsAgentHostClient interface. 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void AgentHostClosed( 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DevToolsAgentHost* agent_host, 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool replaced_with_another_client) OVERRIDE; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void DispatchProtocolMessage( 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DevToolsAgentHost* agent_host, 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& message) OVERRIDE; 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) void SendDetachedEvent(); 10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // content::NotificationObserver implementation. 11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) virtual void Observe(int type, 11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const content::NotificationSource& source, 11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const content::NotificationDetails& details) OVERRIDE; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // ExtensionRegistryObserver implementation. 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void OnExtensionUnloaded( 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::BrowserContext* browser_context, 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const Extension* extension, 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnloadedExtensionInfo::Reason reason) OVERRIDE; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile_; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<DevToolsAgentHost> agent_host_; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string extension_id_; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Debuggee debuggee_; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationRegistrar registrar_; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int last_request_id_; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef std::map<int, scoped_refptr<DebuggerSendCommandFunction> > 12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PendingRequests; 12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) PendingRequests pending_requests_; 13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) infobars::InfoBar* infobar_; 13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) OnDetach::Reason detach_reason_; 132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Listen to extension unloaded notification. 134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> 135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) extension_registry_observer_; 136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsClientHost); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// The member function declarations come after the other class declarations, so 14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// they can call members on them. 142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Helpers -------------------------------------------------------------------- 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void CopyDebuggee(Debuggee* dst, const Debuggee& src) { 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (src.tab_id) 150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) dst->tab_id.reset(new int(*src.tab_id)); 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (src.extension_id) 152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) dst->extension_id.reset(new std::string(*src.extension_id)); 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (src.target_id) 154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) dst->target_id.reset(new std::string(*src.target_id)); 155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ExtensionDevToolsInfoBarDelegate ------------------------------------------- 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ExtensionDevToolsInfoBarDelegate : public ConfirmInfoBarDelegate { 161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Creates an extension dev tools infobar and delegate and adds the infobar to 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the InfoBarService associated with |rvh|. Returns the infobar if it was 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // successfully added. 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static infobars::InfoBar* Create(WebContents* web_contents, 166b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) const std::string& client_name); 167b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void set_client_host(ExtensionDevToolsClientHost* client_host) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_host_ = client_host; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit ExtensionDevToolsInfoBarDelegate(const std::string& client_name); 174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual ~ExtensionDevToolsInfoBarDelegate(); 175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // ConfirmInfoBarDelegate: 177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void InfoBarDismissed() OVERRIDE; 178b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) virtual Type GetInfoBarType() const OVERRIDE; 179b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) virtual bool ShouldExpireInternal( 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const NavigationDetails& details) const OVERRIDE; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual base::string16 GetMessageText() const OVERRIDE; 182b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) virtual int GetButtons() const OVERRIDE; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual bool Cancel() OVERRIDE; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string client_name_; 186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ExtensionDevToolsClientHost* client_host_; 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsInfoBarDelegate); 189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)infobars::InfoBar* ExtensionDevToolsInfoBarDelegate::Create( 193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) WebContents* web_contents, 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& client_name) { 195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!web_contents) 196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return NULL; 197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) InfoBarService* infobar_service = 199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) InfoBarService::FromWebContents(web_contents); 200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!infobar_service) 201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return NULL; 202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar( 20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) scoped_ptr<ConfirmInfoBarDelegate>( 205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) new ExtensionDevToolsInfoBarDelegate(client_name)))); 206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ExtensionDevToolsInfoBarDelegate::ExtensionDevToolsInfoBarDelegate( 209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& client_name) 210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : ConfirmInfoBarDelegate(), 211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) client_name_(client_name), 212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) client_host_(NULL) { 213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ExtensionDevToolsInfoBarDelegate::~ExtensionDevToolsInfoBarDelegate() { 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionDevToolsInfoBarDelegate::InfoBarDismissed() { 21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (client_host_) 22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) client_host_->MarkAsDismissed(); 22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)infobars::InfoBarDelegate::Type 22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)ExtensionDevToolsInfoBarDelegate::GetInfoBarType() const { 22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return WARNING_TYPE; 22690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 22790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 22890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool ExtensionDevToolsInfoBarDelegate::ShouldExpireInternal( 22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const NavigationDetails& details) const { 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::string16 ExtensionDevToolsInfoBarDelegate::GetMessageText() const { 234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return l10n_util::GetStringFUTF16(IDS_DEV_TOOLS_INFOBAR_LABEL, 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::UTF8ToUTF16(client_name_)); 236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int ExtensionDevToolsInfoBarDelegate::GetButtons() const { 239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return BUTTON_CANCEL; 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ExtensionDevToolsInfoBarDelegate::Cancel() { 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) InfoBarDismissed(); 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 24790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// AttachedClientHosts -------------------------------------------------------- 249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class AttachedClientHosts { 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AttachedClientHosts(); 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ~AttachedClientHosts(); 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Returns the singleton instance of this class. 256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) static AttachedClientHosts* GetInstance(); 257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void Add(ExtensionDevToolsClientHost* client_host); 259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void Remove(ExtensionDevToolsClientHost* client_host); 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ExtensionDevToolsClientHost* Lookup(DevToolsAgentHost* agent_host, 261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& extension_id); 262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) typedef std::set<ExtensionDevToolsClientHost*> ClientHosts; 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ClientHosts client_hosts_; 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(AttachedClientHosts); 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AttachedClientHosts::AttachedClientHosts() { 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)AttachedClientHosts::~AttachedClientHosts() { 274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static 277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)AttachedClientHosts* AttachedClientHosts::GetInstance() { 27890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return Singleton<AttachedClientHosts>::get(); 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AttachedClientHosts::Add(ExtensionDevToolsClientHost* client_host) { 282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) client_hosts_.insert(client_host); 283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AttachedClientHosts::Remove(ExtensionDevToolsClientHost* client_host) { 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_hosts_.erase(client_host); 287} 288 289ExtensionDevToolsClientHost* AttachedClientHosts::Lookup( 290 DevToolsAgentHost* agent_host, 291 const std::string& extension_id) { 292 for (ClientHosts::iterator it = client_hosts_.begin(); 293 it != client_hosts_.end(); ++it) { 294 ExtensionDevToolsClientHost* client_host = *it; 295 if (client_host->agent_host() == agent_host && 296 client_host->extension_id() == extension_id) 297 return client_host; 298 } 299 return NULL; 300} 301 302} // namespace 303 304 305// ExtensionDevToolsClientHost ------------------------------------------------ 306 307ExtensionDevToolsClientHost::ExtensionDevToolsClientHost( 308 Profile* profile, 309 DevToolsAgentHost* agent_host, 310 const std::string& extension_id, 311 const std::string& extension_name, 312 const Debuggee& debuggee, 313 infobars::InfoBar* infobar) 314 : profile_(profile), 315 agent_host_(agent_host), 316 extension_id_(extension_id), 317 last_request_id_(0), 318 infobar_(infobar), 319 detach_reason_(OnDetach::REASON_TARGET_CLOSED), 320 extension_registry_observer_(this) { 321 CopyDebuggee(&debuggee_, debuggee); 322 323 AttachedClientHosts::GetInstance()->Add(this); 324 325 // ExtensionRegistryObserver listen extension unloaded and detach debugger 326 // from there. 327 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); 328 329 // RVH-based agents disconnect from their clients when the app is terminating 330 // but shared worker-based agents do not. 331 // Disconnect explicitly to make sure that |this| observer is not leaked. 332 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, 333 content::NotificationService::AllSources()); 334 335 // Attach to debugger and tell it we are ready. 336 agent_host_->AttachClient(this); 337 338 if (infobar_) { 339 static_cast<ExtensionDevToolsInfoBarDelegate*>( 340 infobar_->delegate())->set_client_host(this); 341 registrar_.Add( 342 this, 343 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, 344 content::Source<InfoBarService>( 345 InfoBarService::FromWebContents(agent_host_->GetWebContents()))); 346 } 347} 348 349ExtensionDevToolsClientHost::~ExtensionDevToolsClientHost() { 350 // Ensure calling RemoveInfoBar() below won't result in Observe() trying to 351 // Close() us. 352 registrar_.RemoveAll(); 353 354 if (infobar_) { 355 static_cast<ExtensionDevToolsInfoBarDelegate*>( 356 infobar_->delegate())->set_client_host(NULL); 357 InfoBarService* infobar_service = 358 InfoBarService::FromWebContents(agent_host_->GetWebContents()); 359 infobar_service->RemoveInfoBar(infobar_); 360 } 361 AttachedClientHosts::GetInstance()->Remove(this); 362} 363 364// DevToolsAgentHostClient implementation. 365void ExtensionDevToolsClientHost::AgentHostClosed( 366 DevToolsAgentHost* agent_host, bool replaced_with_another_client) { 367 DCHECK(agent_host == agent_host_.get()); 368 if (replaced_with_another_client) 369 detach_reason_ = OnDetach::REASON_REPLACED_WITH_DEVTOOLS; 370 SendDetachedEvent(); 371 delete this; 372} 373 374void ExtensionDevToolsClientHost::Close() { 375 agent_host_->DetachClient(); 376 delete this; 377} 378 379void ExtensionDevToolsClientHost::SendMessageToBackend( 380 DebuggerSendCommandFunction* function, 381 const std::string& method, 382 SendCommand::Params::CommandParams* command_params) { 383 base::DictionaryValue protocol_request; 384 int request_id = ++last_request_id_; 385 pending_requests_[request_id] = function; 386 protocol_request.SetInteger("id", request_id); 387 protocol_request.SetString("method", method); 388 if (command_params) { 389 protocol_request.Set("params", 390 command_params->additional_properties.DeepCopy()); 391 } 392 393 std::string json_args; 394 base::JSONWriter::Write(&protocol_request, &json_args); 395 agent_host_->DispatchProtocolMessage(json_args); 396} 397 398void ExtensionDevToolsClientHost::MarkAsDismissed() { 399 detach_reason_ = OnDetach::REASON_CANCELED_BY_USER; 400} 401 402void ExtensionDevToolsClientHost::SendDetachedEvent() { 403 if (!EventRouter::Get(profile_)) 404 return; 405 406 scoped_ptr<base::ListValue> args(OnDetach::Create(debuggee_, 407 detach_reason_)); 408 scoped_ptr<Event> event(new Event(OnDetach::kEventName, args.Pass())); 409 event->restrict_to_browser_context = profile_; 410 EventRouter::Get(profile_) 411 ->DispatchEventToExtension(extension_id_, event.Pass()); 412} 413 414void ExtensionDevToolsClientHost::OnExtensionUnloaded( 415 content::BrowserContext* browser_context, 416 const Extension* extension, 417 UnloadedExtensionInfo::Reason reason) { 418 if (extension->id() == extension_id_) 419 Close(); 420} 421 422void ExtensionDevToolsClientHost::Observe( 423 int type, 424 const content::NotificationSource& source, 425 const content::NotificationDetails& details) { 426 switch (type) { 427 case chrome::NOTIFICATION_APP_TERMINATING: 428 Close(); 429 break; 430 case chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED: 431 if (content::Details<infobars::InfoBar::RemovedDetails>(details)->first == 432 infobar_) { 433 infobar_ = NULL; 434 SendDetachedEvent(); 435 Close(); 436 } 437 break; 438 default: 439 NOTREACHED(); 440 } 441} 442 443void ExtensionDevToolsClientHost::DispatchProtocolMessage( 444 DevToolsAgentHost* agent_host, const std::string& message) { 445 DCHECK(agent_host == agent_host_.get()); 446 if (!EventRouter::Get(profile_)) 447 return; 448 449 scoped_ptr<base::Value> result(base::JSONReader::Read(message)); 450 if (!result->IsType(base::Value::TYPE_DICTIONARY)) 451 return; 452 base::DictionaryValue* dictionary = 453 static_cast<base::DictionaryValue*>(result.get()); 454 455 int id; 456 if (!dictionary->GetInteger("id", &id)) { 457 std::string method_name; 458 if (!dictionary->GetString("method", &method_name)) 459 return; 460 461 OnEvent::Params params; 462 base::DictionaryValue* params_value; 463 if (dictionary->GetDictionary("params", ¶ms_value)) 464 params.additional_properties.Swap(params_value); 465 466 scoped_ptr<base::ListValue> args( 467 OnEvent::Create(debuggee_, method_name, params)); 468 scoped_ptr<Event> event(new Event(OnEvent::kEventName, args.Pass())); 469 event->restrict_to_browser_context = profile_; 470 EventRouter::Get(profile_) 471 ->DispatchEventToExtension(extension_id_, event.Pass()); 472 } else { 473 DebuggerSendCommandFunction* function = pending_requests_[id].get(); 474 if (!function) 475 return; 476 477 function->SendResponseBody(dictionary); 478 pending_requests_.erase(id); 479 } 480} 481 482 483// DebuggerFunction ----------------------------------------------------------- 484 485DebuggerFunction::DebuggerFunction() 486 : client_host_(NULL) { 487} 488 489DebuggerFunction::~DebuggerFunction() { 490} 491 492void DebuggerFunction::FormatErrorMessage(const std::string& format) { 493 if (debuggee_.tab_id) 494 error_ = ErrorUtils::FormatErrorMessage( 495 format, keys::kTabTargetType, base::IntToString(*debuggee_.tab_id)); 496 else if (debuggee_.extension_id) 497 error_ = ErrorUtils::FormatErrorMessage( 498 format, keys::kBackgroundPageTargetType, *debuggee_.extension_id); 499 else 500 error_ = ErrorUtils::FormatErrorMessage( 501 format, keys::kOpaqueTargetType, *debuggee_.target_id); 502} 503 504bool DebuggerFunction::InitAgentHost() { 505 if (debuggee_.tab_id) { 506 WebContents* web_contents = NULL; 507 bool result = ExtensionTabUtil::GetTabById(*debuggee_.tab_id, 508 GetProfile(), 509 include_incognito(), 510 NULL, 511 NULL, 512 &web_contents, 513 NULL); 514 if (result && web_contents) { 515 // TODO(rdevlin.cronin) This should definitely be GetLastCommittedURL(). 516 GURL url = web_contents->GetVisibleURL(); 517 if (PermissionsData::IsRestrictedUrl(url, url, extension(), &error_)) 518 return false; 519 agent_host_ = DevToolsAgentHost::GetOrCreateFor(web_contents); 520 } 521 } else if (debuggee_.extension_id) { 522 ExtensionHost* extension_host = 523 ExtensionSystem::Get(GetProfile()) 524 ->process_manager() 525 ->GetBackgroundHostForExtension(*debuggee_.extension_id); 526 if (extension_host) { 527 if (PermissionsData::IsRestrictedUrl(extension_host->GetURL(), 528 extension_host->GetURL(), 529 extension(), 530 &error_)) { 531 return false; 532 } 533 agent_host_ = 534 DevToolsAgentHost::GetOrCreateFor(extension_host->host_contents()); 535 } 536 } else if (debuggee_.target_id) { 537 agent_host_ = DevToolsAgentHost::GetForId(*debuggee_.target_id); 538 } else { 539 error_ = keys::kInvalidTargetError; 540 return false; 541 } 542 543 if (!agent_host_.get()) { 544 FormatErrorMessage(keys::kNoTargetError); 545 return false; 546 } 547 return true; 548} 549 550bool DebuggerFunction::InitClientHost() { 551 if (!InitAgentHost()) 552 return false; 553 554 client_host_ = AttachedClientHosts::GetInstance()->Lookup(agent_host_.get(), 555 extension()->id()); 556 557 if (!client_host_) { 558 FormatErrorMessage(keys::kNotAttachedError); 559 return false; 560 } 561 return true; 562} 563 564 565// DebuggerAttachFunction ----------------------------------------------------- 566 567DebuggerAttachFunction::DebuggerAttachFunction() { 568} 569 570DebuggerAttachFunction::~DebuggerAttachFunction() { 571} 572 573bool DebuggerAttachFunction::RunAsync() { 574 scoped_ptr<Attach::Params> params(Attach::Params::Create(*args_)); 575 EXTENSION_FUNCTION_VALIDATE(params.get()); 576 577 CopyDebuggee(&debuggee_, params->target); 578 if (!InitAgentHost()) 579 return false; 580 581 if (!DevToolsHttpHandler::IsSupportedProtocolVersion( 582 params->required_version)) { 583 error_ = ErrorUtils::FormatErrorMessage( 584 keys::kProtocolVersionNotSupportedError, 585 params->required_version); 586 return false; 587 } 588 589 if (agent_host_->IsAttached()) { 590 FormatErrorMessage(keys::kAlreadyAttachedError); 591 return false; 592 } 593 594 infobars::InfoBar* infobar = NULL; 595 if (!CommandLine::ForCurrentProcess()-> 596 HasSwitch(::switches::kSilentDebuggerExtensionAPI)) { 597 // Do not attach to the target if for any reason the infobar cannot be shown 598 // for this WebContents instance. 599 infobar = ExtensionDevToolsInfoBarDelegate::Create( 600 agent_host_->GetWebContents(), extension()->name()); 601 if (!infobar) { 602 error_ = ErrorUtils::FormatErrorMessage( 603 keys::kSilentDebuggingRequired, 604 ::switches::kSilentDebuggerExtensionAPI); 605 return false; 606 } 607 } 608 609 new ExtensionDevToolsClientHost(GetProfile(), 610 agent_host_.get(), 611 extension()->id(), 612 extension()->name(), 613 debuggee_, 614 infobar); 615 SendResponse(true); 616 return true; 617} 618 619 620// DebuggerDetachFunction ----------------------------------------------------- 621 622DebuggerDetachFunction::DebuggerDetachFunction() { 623} 624 625DebuggerDetachFunction::~DebuggerDetachFunction() { 626} 627 628bool DebuggerDetachFunction::RunAsync() { 629 scoped_ptr<Detach::Params> params(Detach::Params::Create(*args_)); 630 EXTENSION_FUNCTION_VALIDATE(params.get()); 631 632 CopyDebuggee(&debuggee_, params->target); 633 if (!InitClientHost()) 634 return false; 635 636 client_host_->Close(); 637 SendResponse(true); 638 return true; 639} 640 641 642// DebuggerSendCommandFunction ------------------------------------------------ 643 644DebuggerSendCommandFunction::DebuggerSendCommandFunction() { 645} 646 647DebuggerSendCommandFunction::~DebuggerSendCommandFunction() { 648} 649 650bool DebuggerSendCommandFunction::RunAsync() { 651 scoped_ptr<SendCommand::Params> params(SendCommand::Params::Create(*args_)); 652 EXTENSION_FUNCTION_VALIDATE(params.get()); 653 654 CopyDebuggee(&debuggee_, params->target); 655 if (!InitClientHost()) 656 return false; 657 658 client_host_->SendMessageToBackend(this, params->method, 659 params->command_params.get()); 660 return true; 661} 662 663void DebuggerSendCommandFunction::SendResponseBody( 664 base::DictionaryValue* response) { 665 base::Value* error_body; 666 if (response->Get("error", &error_body)) { 667 base::JSONWriter::Write(error_body, &error_); 668 SendResponse(false); 669 return; 670 } 671 672 base::DictionaryValue* result_body; 673 SendCommand::Results::Result result; 674 if (response->GetDictionary("result", &result_body)) 675 result.additional_properties.Swap(result_body); 676 677 results_ = SendCommand::Results::Create(result); 678 SendResponse(true); 679} 680 681 682// DebuggerGetTargetsFunction ------------------------------------------------- 683 684namespace { 685 686const char kTargetIdField[] = "id"; 687const char kTargetTypeField[] = "type"; 688const char kTargetTitleField[] = "title"; 689const char kTargetAttachedField[] = "attached"; 690const char kTargetUrlField[] = "url"; 691const char kTargetFaviconUrlField[] = "faviconUrl"; 692const char kTargetTypePage[] = "page"; 693const char kTargetTypeBackgroundPage[] = "background_page"; 694const char kTargetTypeWorker[] = "worker"; 695const char kTargetTypeOther[] = "other"; 696const char kTargetTabIdField[] = "tabId"; 697const char kTargetExtensionIdField[] = "extensionId"; 698 699base::Value* SerializeTarget(const DevToolsTargetImpl& target) { 700 base::DictionaryValue* dictionary = new base::DictionaryValue(); 701 702 dictionary->SetString(kTargetIdField, target.GetId()); 703 dictionary->SetString(kTargetTitleField, target.GetTitle()); 704 dictionary->SetBoolean(kTargetAttachedField, target.IsAttached()); 705 dictionary->SetString(kTargetUrlField, target.GetURL().spec()); 706 707 std::string type = target.GetType(); 708 if (type == kTargetTypePage) { 709 dictionary->SetInteger(kTargetTabIdField, target.GetTabId()); 710 } else if (type == kTargetTypeBackgroundPage) { 711 dictionary->SetString(kTargetExtensionIdField, target.GetExtensionId()); 712 } else if (type != kTargetTypeWorker) { 713 // DevToolsTargetImpl may support more types than the debugger API. 714 type = kTargetTypeOther; 715 } 716 dictionary->SetString(kTargetTypeField, type); 717 718 GURL favicon_url = target.GetFaviconURL(); 719 if (favicon_url.is_valid()) 720 dictionary->SetString(kTargetFaviconUrlField, favicon_url.spec()); 721 722 return dictionary; 723} 724 725} // namespace 726 727DebuggerGetTargetsFunction::DebuggerGetTargetsFunction() { 728} 729 730DebuggerGetTargetsFunction::~DebuggerGetTargetsFunction() { 731} 732 733bool DebuggerGetTargetsFunction::RunAsync() { 734 DevToolsTargetImpl::EnumerateAllTargets( 735 base::Bind(&DebuggerGetTargetsFunction::SendTargetList, this)); 736 return true; 737} 738 739void DebuggerGetTargetsFunction::SendTargetList( 740 const std::vector<DevToolsTargetImpl*>& target_list) { 741 scoped_ptr<base::ListValue> result(new base::ListValue()); 742 for (size_t i = 0; i < target_list.size(); ++i) 743 result->Append(SerializeTarget(*target_list[i])); 744 STLDeleteContainerPointers(target_list.begin(), target_list.end()); 745 SetResult(result.release()); 746 SendResponse(true); 747} 748 749} // namespace extensions 750