Home | History | Annotate | Download | only in browser
      1 // Copyright 2013 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.
      4 
      5 #include "content/shell/browser/shell_devtools_delegate.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/command_line.h"
     11 #include "base/files/file_path.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "base/strings/stringprintf.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "content/public/browser/devtools_agent_host.h"
     16 #include "content/public/browser/devtools_http_handler.h"
     17 #include "content/public/browser/devtools_target.h"
     18 #include "content/public/browser/favicon_status.h"
     19 #include "content/public/browser/navigation_entry.h"
     20 #include "content/public/browser/render_view_host.h"
     21 #include "content/public/browser/web_contents.h"
     22 #include "content/public/common/content_switches.h"
     23 #include "content/public/common/url_constants.h"
     24 #include "content/public/common/user_agent.h"
     25 #include "content/shell/browser/shell.h"
     26 #include "grit/shell_resources.h"
     27 #include "net/socket/tcp_server_socket.h"
     28 #include "ui/base/resource/resource_bundle.h"
     29 
     30 #if defined(OS_ANDROID)
     31 #include "content/public/browser/android/devtools_auth.h"
     32 #include "net/socket/unix_domain_server_socket_posix.h"
     33 #endif
     34 
     35 using content::DevToolsAgentHost;
     36 using content::RenderViewHost;
     37 using content::WebContents;
     38 
     39 namespace {
     40 
     41 #if defined(OS_ANDROID)
     42 const char kFrontEndURL[] =
     43     "http://chrome-devtools-frontend.appspot.com/serve_rev/%s/devtools.html";
     44 #endif
     45 const char kTargetTypePage[] = "page";
     46 const char kTargetTypeServiceWorker[] = "service_worker";
     47 const char kTargetTypeOther[] = "other";
     48 
     49 #if defined(OS_ANDROID)
     50 class UnixDomainServerSocketFactory
     51     : public content::DevToolsHttpHandler::ServerSocketFactory {
     52  public:
     53   explicit UnixDomainServerSocketFactory(const std::string& socket_name)
     54       : content::DevToolsHttpHandler::ServerSocketFactory(socket_name, 0, 1) {}
     55 
     56  private:
     57   // content::DevToolsHttpHandler::ServerSocketFactory.
     58   virtual scoped_ptr<net::ServerSocket> Create() const OVERRIDE {
     59     return scoped_ptr<net::ServerSocket>(
     60         new net::UnixDomainServerSocket(
     61             base::Bind(&content::CanUserConnectToDevTools),
     62             true /* use_abstract_namespace */));
     63   }
     64 
     65   DISALLOW_COPY_AND_ASSIGN(UnixDomainServerSocketFactory);
     66 };
     67 #else
     68 class TCPServerSocketFactory
     69     : public content::DevToolsHttpHandler::ServerSocketFactory {
     70  public:
     71   TCPServerSocketFactory(const std::string& address, int port, int backlog)
     72       : content::DevToolsHttpHandler::ServerSocketFactory(
     73             address, port, backlog) {}
     74 
     75  private:
     76   // content::DevToolsHttpHandler::ServerSocketFactory.
     77   virtual scoped_ptr<net::ServerSocket> Create() const OVERRIDE {
     78     return scoped_ptr<net::ServerSocket>(
     79         new net::TCPServerSocket(NULL, net::NetLog::Source()));
     80   }
     81 
     82   DISALLOW_COPY_AND_ASSIGN(TCPServerSocketFactory);
     83 };
     84 #endif
     85 
     86 scoped_ptr<content::DevToolsHttpHandler::ServerSocketFactory>
     87 CreateSocketFactory() {
     88   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
     89 #if defined(OS_ANDROID)
     90   std::string socket_name = "content_shell_devtools_remote";
     91   if (command_line.HasSwitch(switches::kRemoteDebuggingSocketName)) {
     92     socket_name = command_line.GetSwitchValueASCII(
     93         switches::kRemoteDebuggingSocketName);
     94   }
     95   return scoped_ptr<content::DevToolsHttpHandler::ServerSocketFactory>(
     96       new UnixDomainServerSocketFactory(socket_name));
     97 #else
     98   // See if the user specified a port on the command line (useful for
     99   // automation). If not, use an ephemeral port by specifying 0.
    100   int port = 0;
    101   if (command_line.HasSwitch(switches::kRemoteDebuggingPort)) {
    102     int temp_port;
    103     std::string port_str =
    104         command_line.GetSwitchValueASCII(switches::kRemoteDebuggingPort);
    105     if (base::StringToInt(port_str, &temp_port) &&
    106         temp_port > 0 && temp_port < 65535) {
    107       port = temp_port;
    108     } else {
    109       DLOG(WARNING) << "Invalid http debugger port number " << temp_port;
    110     }
    111   }
    112   return scoped_ptr<content::DevToolsHttpHandler::ServerSocketFactory>(
    113       new TCPServerSocketFactory("127.0.0.1", port, 1));
    114 #endif
    115 }
    116 
    117 class Target : public content::DevToolsTarget {
    118  public:
    119   explicit Target(scoped_refptr<DevToolsAgentHost> agent_host);
    120 
    121   virtual std::string GetId() const OVERRIDE { return agent_host_->GetId(); }
    122   virtual std::string GetParentId() const OVERRIDE { return std::string(); }
    123   virtual std::string GetType() const OVERRIDE {
    124     switch (agent_host_->GetType()) {
    125       case DevToolsAgentHost::TYPE_WEB_CONTENTS:
    126         return kTargetTypePage;
    127       case DevToolsAgentHost::TYPE_SERVICE_WORKER:
    128         return kTargetTypeServiceWorker;
    129       default:
    130         break;
    131     }
    132     return kTargetTypeOther;
    133   }
    134   virtual std::string GetTitle() const OVERRIDE {
    135     return agent_host_->GetTitle();
    136   }
    137   virtual std::string GetDescription() const OVERRIDE { return std::string(); }
    138   virtual GURL GetURL() const OVERRIDE { return agent_host_->GetURL(); }
    139   virtual GURL GetFaviconURL() const OVERRIDE { return favicon_url_; }
    140   virtual base::TimeTicks GetLastActivityTime() const OVERRIDE {
    141     return last_activity_time_;
    142   }
    143   virtual bool IsAttached() const OVERRIDE {
    144     return agent_host_->IsAttached();
    145   }
    146   virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE {
    147     return agent_host_;
    148   }
    149   virtual bool Activate() const OVERRIDE;
    150   virtual bool Close() const OVERRIDE;
    151 
    152  private:
    153   scoped_refptr<DevToolsAgentHost> agent_host_;
    154   GURL favicon_url_;
    155   base::TimeTicks last_activity_time_;
    156 };
    157 
    158 Target::Target(scoped_refptr<DevToolsAgentHost> agent_host)
    159     : agent_host_(agent_host) {
    160   if (WebContents* web_contents = agent_host_->GetWebContents()) {
    161     content::NavigationController& controller = web_contents->GetController();
    162     content::NavigationEntry* entry = controller.GetActiveEntry();
    163     if (entry != NULL && entry->GetURL().is_valid())
    164       favicon_url_ = entry->GetFavicon().url;
    165     last_activity_time_ = web_contents->GetLastActiveTime();
    166   }
    167 }
    168 
    169 bool Target::Activate() const {
    170   return agent_host_->Activate();
    171 }
    172 
    173 bool Target::Close() const {
    174   return agent_host_->Close();
    175 }
    176 
    177 }  // namespace
    178 
    179 namespace content {
    180 
    181 // ShellDevToolsDelegate ----------------------------------------------------
    182 
    183 ShellDevToolsDelegate::ShellDevToolsDelegate(BrowserContext* browser_context)
    184     : browser_context_(browser_context) {
    185   std::string frontend_url;
    186 #if defined(OS_ANDROID)
    187   frontend_url = base::StringPrintf(kFrontEndURL, GetWebKitRevision().c_str());
    188 #endif
    189   devtools_http_handler_ =
    190       DevToolsHttpHandler::Start(CreateSocketFactory(), frontend_url, this,
    191                                  base::FilePath());
    192 }
    193 
    194 ShellDevToolsDelegate::~ShellDevToolsDelegate() {
    195 }
    196 
    197 void ShellDevToolsDelegate::Stop() {
    198   // The call below destroys this.
    199   devtools_http_handler_->Stop();
    200 }
    201 
    202 std::string ShellDevToolsDelegate::GetDiscoveryPageHTML() {
    203 #if defined(OS_ANDROID)
    204   return std::string();
    205 #else
    206   return ResourceBundle::GetSharedInstance().GetRawDataResource(
    207       IDR_CONTENT_SHELL_DEVTOOLS_DISCOVERY_PAGE).as_string();
    208 #endif
    209 }
    210 
    211 bool ShellDevToolsDelegate::BundlesFrontendResources() {
    212 #if defined(OS_ANDROID)
    213   return false;
    214 #else
    215   return true;
    216 #endif
    217 }
    218 
    219 base::FilePath ShellDevToolsDelegate::GetDebugFrontendDir() {
    220   return base::FilePath();
    221 }
    222 
    223 scoped_ptr<net::StreamListenSocket>
    224 ShellDevToolsDelegate::CreateSocketForTethering(
    225     net::StreamListenSocket::Delegate* delegate,
    226     std::string* name) {
    227   return scoped_ptr<net::StreamListenSocket>();
    228 }
    229 
    230 // ShellDevToolsManagerDelegate ----------------------------------------------
    231 
    232 ShellDevToolsManagerDelegate::ShellDevToolsManagerDelegate(
    233     BrowserContext* browser_context)
    234     : browser_context_(browser_context) {
    235 }
    236 
    237 ShellDevToolsManagerDelegate::~ShellDevToolsManagerDelegate() {
    238 }
    239 
    240 base::DictionaryValue* ShellDevToolsManagerDelegate::HandleCommand(
    241     DevToolsAgentHost* agent_host,
    242     base::DictionaryValue* command) {
    243   return NULL;
    244 }
    245 
    246 std::string ShellDevToolsManagerDelegate::GetPageThumbnailData(
    247     const GURL& url) {
    248   return std::string();
    249 }
    250 
    251 scoped_ptr<DevToolsTarget>
    252 ShellDevToolsManagerDelegate::CreateNewTarget(const GURL& url) {
    253   Shell* shell = Shell::CreateNewWindow(browser_context_,
    254                                         url,
    255                                         NULL,
    256                                         MSG_ROUTING_NONE,
    257                                         gfx::Size());
    258   return scoped_ptr<DevToolsTarget>(
    259       new Target(DevToolsAgentHost::GetOrCreateFor(shell->web_contents())));
    260 }
    261 
    262 void ShellDevToolsManagerDelegate::EnumerateTargets(TargetCallback callback) {
    263   TargetList targets;
    264   content::DevToolsAgentHost::List agents =
    265       content::DevToolsAgentHost::GetOrCreateAll();
    266   for (content::DevToolsAgentHost::List::iterator it = agents.begin();
    267        it != agents.end(); ++it) {
    268     targets.push_back(new Target(*it));
    269   }
    270   callback.Run(targets);
    271 }
    272 
    273 }  // namespace content
    274