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", &params_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