blob: f67a111a255f9130a496ff5a1c202601f81fc0bf [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2013 The Chromium Authors
[email protected]ee75b8992012-01-27 07:53:572// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
vkuzkokovcbabd582014-11-06 13:53:545#include "content/shell/browser/shell_devtools_manager_delegate.h"
[email protected]ee75b8992012-01-27 07:53:576
avi66a07722015-12-25 23:38:127#include <stdint.h>
8
[email protected]90e6c5412013-04-16 22:45:259#include <vector>
10
pfeldmanf7c18d0242016-09-08 19:54:2611#include "base/atomicops.h"
[email protected]90e6c5412013-04-16 22:45:2512#include "base/command_line.h"
Weizhong Xiaa10850f2024-04-24 18:53:0013#include "base/containers/contains.h"
[email protected]0e60fce2014-06-04 22:27:2014#include "base/files/file_path.h"
Avi Drissmanadac21992023-01-11 23:46:3915#include "base/functional/bind.h"
16#include "base/functional/callback.h"
[email protected]90e6c5412013-04-16 22:45:2517#include "base/strings/string_number_conversions.h"
[email protected]852b34ba2013-10-03 16:29:0618#include "base/strings/utf_string_conversions.h"
avi66a07722015-12-25 23:38:1219#include "build/build_config.h"
yzshen6051dfd32015-10-20 19:23:2520#include "content/public/browser/browser_context.h"
[email protected]852b34ba2013-10-03 16:29:0621#include "content/public/browser/devtools_agent_host.h"
Johannes Henkel9d14e4b82020-01-28 01:29:4122#include "content/public/browser/devtools_agent_host_client_channel.h"
pfeldmanf1a16942016-09-02 21:28:0023#include "content/public/browser/devtools_socket_factory.h"
[email protected]852b34ba2013-10-03 16:29:0624#include "content/public/browser/favicon_status.h"
25#include "content/public/browser/navigation_entry.h"
26#include "content/public/browser/render_view_host.h"
[email protected]eb040992012-10-10 16:56:0027#include "content/public/browser/web_contents.h"
[email protected]90e6c5412013-04-16 22:45:2528#include "content/public/common/content_switches.h"
[email protected]eb040992012-10-10 16:56:0029#include "content/public/common/url_constants.h"
[email protected]efd2c3f2014-03-11 09:57:2530#include "content/public/common/user_agent.h"
Weizhong Xiaa10850f2024-04-24 18:53:0031#include "content/shell/browser/protocol/shell_devtools_session.h"
[email protected]de7d61ff2013-08-20 11:30:4132#include "content/shell/browser/shell.h"
dgozman102fee92015-04-20 15:45:4633#include "content/shell/common/shell_content_client.h"
dgozman4547460932017-06-22 03:04:3634#include "content/shell/common/shell_switches.h"
thakisda47dac2017-02-27 14:35:3035#include "content/shell/grit/shell_resources.h"
vkuzkokov79426762015-01-13 08:03:0036#include "net/base/net_errors.h"
mikecironef22f9812016-10-04 03:40:1937#include "net/log/net_log_source.h"
byungchul38c3ae72014-08-25 23:27:4638#include "net/socket/tcp_server_socket.h"
[email protected]ee75b8992012-01-27 07:53:5739#include "ui/base/resource/resource_bundle.h"
40
Xiaohan Wangbd084422022-01-15 18:47:5141#if BUILDFLAG(IS_ANDROID)
[email protected]ed6635e2012-10-27 00:44:0942#include "content/public/browser/android/devtools_auth.h"
byungchul38c3ae72014-08-25 23:27:4643#include "net/socket/unix_domain_server_socket_posix.h"
[email protected]90e6c5412013-04-16 22:45:2544#endif
[email protected]ed6635e2012-10-27 00:44:0945
vkuzkokovcbabd582014-11-06 13:53:5446namespace content {
[email protected]852b34ba2013-10-03 16:29:0647
[email protected]ed6635e2012-10-27 00:44:0948namespace {
[email protected]90e6c5412013-04-16 22:45:2549
vkuzkokov79426762015-01-13 08:03:0050const int kBackLog = 10;
51
pfeldmanf7c18d0242016-09-08 19:54:2652base::subtle::Atomic32 g_last_used_port;
53
Xiaohan Wangbd084422022-01-15 18:47:5154#if BUILDFLAG(IS_ANDROID)
pfeldmanf1a16942016-09-02 21:28:0055class UnixDomainServerSocketFactory : public content::DevToolsSocketFactory {
byungchul38c3ae72014-08-25 23:27:4656 public:
57 explicit UnixDomainServerSocketFactory(const std::string& socket_name)
vkuzkokov79426762015-01-13 08:03:0058 : socket_name_(socket_name) {}
byungchul38c3ae72014-08-25 23:27:4659
Peter Boström9b036532021-10-28 23:37:2860 UnixDomainServerSocketFactory(const UnixDomainServerSocketFactory&) = delete;
61 UnixDomainServerSocketFactory& operator=(
62 const UnixDomainServerSocketFactory&) = delete;
63
byungchul38c3ae72014-08-25 23:27:4664 private:
pfeldmanf1a16942016-09-02 21:28:0065 // content::DevToolsSocketFactory.
dcheng6003e0b2016-04-09 18:42:3466 std::unique_ptr<net::ServerSocket> CreateForHttpServer() override {
67 std::unique_ptr<net::UnixDomainServerSocket> socket(
danakjc988f0be2019-05-17 20:48:0168 new net::UnixDomainServerSocket(
69 base::BindRepeating(&CanUserConnectToDevTools),
70 true /* use_abstract_namespace */));
tfarinaa7b245d2016-02-02 02:03:4971 if (socket->BindAndListen(socket_name_, kBackLog) != net::OK)
Lei Zhangdf291f62021-04-14 17:23:4472 return nullptr;
vkuzkokov79426762015-01-13 08:03:0073
tfarinaa7b245d2016-02-02 02:03:4974 return std::move(socket);
byungchul38c3ae72014-08-25 23:27:4675 }
76
pfeldmanf1a16942016-09-02 21:28:0077 std::unique_ptr<net::ServerSocket> CreateForTethering(
78 std::string* out_name) override {
79 return nullptr;
80 }
81
vkuzkokov79426762015-01-13 08:03:0082 std::string socket_name_;
byungchul38c3ae72014-08-25 23:27:4683};
84#else
pfeldmanf1a16942016-09-02 21:28:0085class TCPServerSocketFactory : public content::DevToolsSocketFactory {
byungchul38c3ae72014-08-25 23:27:4686 public:
avi66a07722015-12-25 23:38:1287 TCPServerSocketFactory(const std::string& address, uint16_t port)
88 : address_(address), port_(port) {}
byungchul38c3ae72014-08-25 23:27:4689
Peter Boström9b036532021-10-28 23:37:2890 TCPServerSocketFactory(const TCPServerSocketFactory&) = delete;
91 TCPServerSocketFactory& operator=(const TCPServerSocketFactory&) = delete;
92
byungchul38c3ae72014-08-25 23:27:4693 private:
pfeldmanf1a16942016-09-02 21:28:0094 // content::DevToolsSocketFactory.
dcheng6003e0b2016-04-09 18:42:3495 std::unique_ptr<net::ServerSocket> CreateForHttpServer() override {
96 std::unique_ptr<net::ServerSocket> socket(
mikecironef22f9812016-10-04 03:40:1997 new net::TCPServerSocket(nullptr, net::NetLogSource()));
vkuzkokov79426762015-01-13 08:03:0098 if (socket->ListenWithAddressAndPort(address_, port_, kBackLog) != net::OK)
Lei Zhangdf291f62021-04-14 17:23:4499 return nullptr;
vkuzkokov79426762015-01-13 08:03:00100
pfeldmanf7c18d0242016-09-08 19:54:26101 net::IPEndPoint endpoint;
102 if (socket->GetLocalAddress(&endpoint) == net::OK)
103 base::subtle::NoBarrier_Store(&g_last_used_port, endpoint.port());
104
vkuzkokov79426762015-01-13 08:03:00105 return socket;
byungchul38c3ae72014-08-25 23:27:46106 }
107
pfeldmanf1a16942016-09-02 21:28:00108 std::unique_ptr<net::ServerSocket> CreateForTethering(
109 std::string* out_name) override {
110 return nullptr;
111 }
112
vkuzkokov79426762015-01-13 08:03:00113 std::string address_;
avi66a07722015-12-25 23:38:12114 uint16_t port_;
byungchul38c3ae72014-08-25 23:27:46115};
116#endif
117
pfeldmanf1a16942016-09-02 21:28:00118std::unique_ptr<content::DevToolsSocketFactory> CreateSocketFactory() {
avi83883c82014-12-23 00:08:49119 const base::CommandLine& command_line =
120 *base::CommandLine::ForCurrentProcess();
Xiaohan Wangbd084422022-01-15 18:47:51121#if BUILDFLAG(IS_ANDROID)
[email protected]90e6c5412013-04-16 22:45:25122 std::string socket_name = "content_shell_devtools_remote";
123 if (command_line.HasSwitch(switches::kRemoteDebuggingSocketName)) {
124 socket_name = command_line.GetSwitchValueASCII(
125 switches::kRemoteDebuggingSocketName);
126 }
pfeldmanf1a16942016-09-02 21:28:00127 return std::unique_ptr<content::DevToolsSocketFactory>(
byungchul38c3ae72014-08-25 23:27:46128 new UnixDomainServerSocketFactory(socket_name));
[email protected]90e6c5412013-04-16 22:45:25129#else
130 // See if the user specified a port on the command line (useful for
131 // automation). If not, use an ephemeral port by specifying 0.
avi66a07722015-12-25 23:38:12132 uint16_t port = 0;
[email protected]90e6c5412013-04-16 22:45:25133 if (command_line.HasSwitch(switches::kRemoteDebuggingPort)) {
134 int temp_port;
135 std::string port_str =
136 command_line.GetSwitchValueASCII(switches::kRemoteDebuggingPort);
137 if (base::StringToInt(port_str, &temp_port) &&
yzshen6051dfd32015-10-20 19:23:25138 temp_port >= 0 && temp_port < 65535) {
avi66a07722015-12-25 23:38:12139 port = static_cast<uint16_t>(temp_port);
[email protected]90e6c5412013-04-16 22:45:25140 } else {
141 DLOG(WARNING) << "Invalid http debugger port number " << temp_port;
142 }
143 }
Tiago Vignattia293c2c2023-03-28 20:31:04144 // By default listen to incoming DevTools connections on localhost.
145 std::string address_str = net::IPAddress::IPv4Localhost().ToString();
146 if (command_line.HasSwitch(switches::kRemoteDebuggingAddress)) {
147 net::IPAddress address;
148 address_str =
149 command_line.GetSwitchValueASCII(switches::kRemoteDebuggingAddress);
150 if (!address.AssignFromIPLiteral(address_str)) {
151 DLOG(WARNING) << "Invalid devtools server address: " << address_str;
152 }
153 }
pfeldmanf1a16942016-09-02 21:28:00154 return std::unique_ptr<content::DevToolsSocketFactory>(
Tiago Vignattia293c2c2023-03-28 20:31:04155 new TCPServerSocketFactory(address_str, port));
[email protected]ed6635e2012-10-27 00:44:09156#endif
[email protected]90e6c5412013-04-16 22:45:25157}
[email protected]852b34ba2013-10-03 16:29:06158
pfeldman10628762016-09-08 07:59:26159} // namespace
vkuzkokovcbabd582014-11-06 13:53:54160
dgozman252e18d2014-09-22 12:40:06161// ShellDevToolsManagerDelegate ----------------------------------------------
162
vkuzkokovcbabd582014-11-06 13:53:54163// static
pfeldmanf7c18d0242016-09-08 19:54:26164int ShellDevToolsManagerDelegate::GetHttpHandlerPort() {
165 return base::subtle::NoBarrier_Load(&g_last_used_port);
166}
167
168// static
pfeldman10628762016-09-08 07:59:26169void ShellDevToolsManagerDelegate::StartHttpHandler(
vkuzkokovcbabd582014-11-06 13:53:54170 BrowserContext* browser_context) {
171 std::string frontend_url;
pfeldman10628762016-09-08 07:59:26172 DevToolsAgentHost::StartRemoteDebuggingServer(
Pavel Feldmanc8a484b52018-02-07 21:07:32173 CreateSocketFactory(), browser_context->GetPath(), base::FilePath());
Pavel Feldman2b11e2352017-10-25 05:24:01174
175 const base::CommandLine& command_line =
176 *base::CommandLine::ForCurrentProcess();
177 if (command_line.HasSwitch(switches::kRemoteDebuggingPipe))
Dmitry Gozman8bbf58d2020-11-13 22:48:26178 DevToolsAgentHost::StartRemoteDebuggingPipeHandler(base::OnceClosure());
vkuzkokovcbabd582014-11-06 13:53:54179}
180
pfeldman10628762016-09-08 07:59:26181// static
182void ShellDevToolsManagerDelegate::StopHttpHandler() {
183 DevToolsAgentHost::StopRemoteDebuggingServer();
184}
185
Pavel Feldman43f56b7c2016-08-30 00:04:35186ShellDevToolsManagerDelegate::ShellDevToolsManagerDelegate(
187 BrowserContext* browser_context)
188 : browser_context_(browser_context) {
dgozman252e18d2014-09-22 12:40:06189}
190
191ShellDevToolsManagerDelegate::~ShellDevToolsManagerDelegate() {
192}
193
Andrey Lushnikov36299bc2018-08-23 22:09:54194BrowserContext* ShellDevToolsManagerDelegate::GetDefaultBrowserContext() {
195 return browser_context_;
196}
197
Andrey Lushnikovdf1651982018-09-14 19:00:37198void ShellDevToolsManagerDelegate::ClientAttached(
Johannes Henkel9d14e4b82020-01-28 01:29:41199 content::DevToolsAgentHostClientChannel* channel) {
Andrey Lushnikovdf1651982018-09-14 19:00:37200 // Make sure we don't receive notifications twice for the same client.
Weizhong Xiaa10850f2024-04-24 18:53:00201 CHECK(!base::Contains(sessions_, channel));
202 sessions_.emplace(
203 channel,
204 std::make_unique<shell::protocol::ShellDevToolsSession>(
205 base::raw_ref<BrowserContext>::from_ptr(browser_context_), channel));
Andrey Lushnikovdf1651982018-09-14 19:00:37206}
207
208void ShellDevToolsManagerDelegate::ClientDetached(
Johannes Henkel9d14e4b82020-01-28 01:29:41209 content::DevToolsAgentHostClientChannel* channel) {
Weizhong Xiaa10850f2024-04-24 18:53:00210 sessions_.erase(channel);
211}
212
213void ShellDevToolsManagerDelegate::HandleCommand(
214 content::DevToolsAgentHostClientChannel* channel,
215 base::span<const uint8_t> message,
216 NotHandledCallback callback) {
217 auto& session = sessions_.at(channel);
218 session->HandleCommand(message, std::move(callback));
Andrey Lushnikovdf1651982018-09-14 19:00:37219}
220
Danil Somsikovd5b36842022-12-16 11:24:50221scoped_refptr<DevToolsAgentHost> ShellDevToolsManagerDelegate::CreateNewTarget(
222 const GURL& url,
Danil Somsikovdaa9772bb2023-08-03 10:02:10223 content::DevToolsManagerDelegate::TargetType target_type) {
danakj24577b12020-05-13 22:38:18224 Shell* shell = Shell::CreateNewWindow(browser_context_, url, nullptr,
225 Shell::GetShellDefaultSize());
Danil Somsikovdaa9772bb2023-08-03 10:02:10226 return target_type == content::DevToolsManagerDelegate::kTab
227 ? DevToolsAgentHost::GetOrCreateForTab(shell->web_contents())
228 : DevToolsAgentHost::GetOrCreateFor(shell->web_contents());
Pavel Feldman43f56b7c2016-08-30 00:04:35229}
230
pfeldman10628762016-09-08 07:59:26231std::string ShellDevToolsManagerDelegate::GetDiscoveryPageHTML() {
Tiago Vignatti9bbb4a52023-04-06 22:05:57232#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
pfeldman10628762016-09-08 07:59:26233 return std::string();
234#else
Kristian Kirsb9e270512020-07-08 15:21:20235 return ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
236 IDR_CONTENT_SHELL_DEVTOOLS_DISCOVERY_PAGE);
pfeldman10628762016-09-08 07:59:26237#endif
238}
239
Pavel Feldmanc8a484b52018-02-07 21:07:32240bool ShellDevToolsManagerDelegate::HasBundledFrontendResources() {
Tiago Vignatti9bbb4a52023-04-06 22:05:57241#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
Pavel Feldmanc8a484b52018-02-07 21:07:32242 return false;
Nico Weber2771b0f2021-08-16 17:16:24243#else
Pavel Feldmanc8a484b52018-02-07 21:07:32244 return true;
Nico Weber2771b0f2021-08-16 17:16:24245#endif
pfeldman10628762016-09-08 07:59:26246}
247
[email protected]ee75b8992012-01-27 07:53:57248} // namespace content