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.
5 #include "content/shell/browser/shell_devtools_delegate.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"
30 #if defined(OS_ANDROID)
31 #include "content/public/browser/android/devtools_auth.h"
32 #include "net/socket/unix_domain_server_socket_posix.h"
35 using content::DevToolsAgentHost
;
36 using content::RenderViewHost
;
37 using content::WebContents
;
41 #if defined(OS_ANDROID)
42 const char kFrontEndURL
[] =
43 "http://chrome-devtools-frontend.appspot.com/serve_rev/%s/devtools.html";
45 const char kTargetTypePage
[] = "page";
46 const char kTargetTypeServiceWorker
[] = "service_worker";
47 const char kTargetTypeOther
[] = "other";
49 #if defined(OS_ANDROID)
50 class UnixDomainServerSocketFactory
51 : public content::DevToolsHttpHandler::ServerSocketFactory
{
53 explicit UnixDomainServerSocketFactory(const std::string
& socket_name
)
54 : content::DevToolsHttpHandler::ServerSocketFactory(socket_name
, 0, 1) {}
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 */));
65 DISALLOW_COPY_AND_ASSIGN(UnixDomainServerSocketFactory
);
68 class TCPServerSocketFactory
69 : public content::DevToolsHttpHandler::ServerSocketFactory
{
71 TCPServerSocketFactory(const std::string
& address
, int port
, int backlog
)
72 : content::DevToolsHttpHandler::ServerSocketFactory(
73 address
, port
, backlog
) {}
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()));
82 DISALLOW_COPY_AND_ASSIGN(TCPServerSocketFactory
);
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
);
95 return scoped_ptr
<content::DevToolsHttpHandler::ServerSocketFactory
>(
96 new UnixDomainServerSocketFactory(socket_name
));
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.
101 if (command_line
.HasSwitch(switches::kRemoteDebuggingPort
)) {
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) {
109 DLOG(WARNING
) << "Invalid http debugger port number " << temp_port
;
112 return scoped_ptr
<content::DevToolsHttpHandler::ServerSocketFactory
>(
113 new TCPServerSocketFactory("127.0.0.1", port
, 1));
117 class Target
: public content::DevToolsTarget
{
119 explicit Target(scoped_refptr
<DevToolsAgentHost
> agent_host
);
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
;
132 return kTargetTypeOther
;
134 virtual std::string
GetTitle() const OVERRIDE
{
135 return agent_host_
->GetTitle();
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_
;
143 virtual bool IsAttached() const OVERRIDE
{
144 return agent_host_
->IsAttached();
146 virtual scoped_refptr
<DevToolsAgentHost
> GetAgentHost() const OVERRIDE
{
149 virtual bool Activate() const OVERRIDE
;
150 virtual bool Close() const OVERRIDE
;
153 scoped_refptr
<DevToolsAgentHost
> agent_host_
;
155 base::TimeTicks last_activity_time_
;
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();
169 bool Target::Activate() const {
170 return agent_host_
->Activate();
173 bool Target::Close() const {
174 return agent_host_
->Close();
181 ShellDevToolsDelegate::ShellDevToolsDelegate(BrowserContext
* browser_context
)
182 : browser_context_(browser_context
) {
183 std::string frontend_url
;
184 #if defined(OS_ANDROID)
185 frontend_url
= base::StringPrintf(kFrontEndURL
, GetWebKitRevision().c_str());
187 devtools_http_handler_
=
188 DevToolsHttpHandler::Start(CreateSocketFactory(), frontend_url
, this,
192 ShellDevToolsDelegate::~ShellDevToolsDelegate() {
195 void ShellDevToolsDelegate::Stop() {
196 // The call below destroys this.
197 devtools_http_handler_
->Stop();
200 std::string
ShellDevToolsDelegate::GetDiscoveryPageHTML() {
201 #if defined(OS_ANDROID)
202 return std::string();
204 return ResourceBundle::GetSharedInstance().GetRawDataResource(
205 IDR_CONTENT_SHELL_DEVTOOLS_DISCOVERY_PAGE
).as_string();
209 bool ShellDevToolsDelegate::BundlesFrontendResources() {
210 #if defined(OS_ANDROID)
217 base::FilePath
ShellDevToolsDelegate::GetDebugFrontendDir() {
218 return base::FilePath();
221 std::string
ShellDevToolsDelegate::GetPageThumbnailData(const GURL
& url
) {
222 return std::string();
225 scoped_ptr
<DevToolsTarget
>
226 ShellDevToolsDelegate::CreateNewTarget(const GURL
& url
) {
227 Shell
* shell
= Shell::CreateNewWindow(browser_context_
,
232 return scoped_ptr
<DevToolsTarget
>(
233 new Target(DevToolsAgentHost::GetOrCreateFor(shell
->web_contents())));
236 void ShellDevToolsDelegate::EnumerateTargets(TargetCallback callback
) {
238 content::DevToolsAgentHost::List agents
=
239 content::DevToolsAgentHost::GetOrCreateAll();
240 for (content::DevToolsAgentHost::List::iterator it
= agents
.begin();
241 it
!= agents
.end(); ++it
) {
242 targets
.push_back(new Target(*it
));
244 callback
.Run(targets
);
247 scoped_ptr
<net::StreamListenSocket
>
248 ShellDevToolsDelegate::CreateSocketForTethering(
249 net::StreamListenSocket::Delegate
* delegate
,
251 return scoped_ptr
<net::StreamListenSocket
>();
254 } // namespace content