blob: 2fbf3b6387f4b4661eaec8abfbe7686a2f86bfd8 [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"
Weizhong Xiaa10850f2024-04-24 18:53:0030#include "content/shell/browser/protocol/shell_devtools_session.h"
[email protected]de7d61ff2013-08-20 11:30:4131#include "content/shell/browser/shell.h"
dgozman102fee92015-04-20 15:45:4632#include "content/shell/common/shell_content_client.h"
dgozman4547460932017-06-22 03:04:3633#include "content/shell/common/shell_switches.h"
thakisda47dac2017-02-27 14:35:3034#include "content/shell/grit/shell_resources.h"
vkuzkokov79426762015-01-13 08:03:0035#include "net/base/net_errors.h"
mikecironef22f9812016-10-04 03:40:1936#include "net/log/net_log_source.h"
byungchul38c3ae72014-08-25 23:27:4637#include "net/socket/tcp_server_socket.h"
[email protected]ee75b8992012-01-27 07:53:5738#include "ui/base/resource/resource_bundle.h"
39
Xiaohan Wangbd084422022-01-15 18:47:5140#if BUILDFLAG(IS_ANDROID)
[email protected]ed6635e2012-10-27 00:44:0941#include "content/public/browser/android/devtools_auth.h"
byungchul38c3ae72014-08-25 23:27:4642#include "net/socket/unix_domain_server_socket_posix.h"
[email protected]90e6c5412013-04-16 22:45:2543#endif
[email protected]ed6635e2012-10-27 00:44:0944
vkuzkokovcbabd582014-11-06 13:53:5445namespace content {
[email protected]852b34ba2013-10-03 16:29:0646
[email protected]ed6635e2012-10-27 00:44:0947namespace {
[email protected]90e6c5412013-04-16 22:45:2548
vkuzkokov79426762015-01-13 08:03:0049const int kBackLog = 10;
50
pfeldmanf7c18d0242016-09-08 19:54:2651base::subtle::Atomic32 g_last_used_port;
52
Xiaohan Wangbd084422022-01-15 18:47:5153#if BUILDFLAG(IS_ANDROID)
pfeldmanf1a16942016-09-02 21:28:0054class UnixDomainServerSocketFactory : public content::DevToolsSocketFactory {
byungchul38c3ae72014-08-25 23:27:4655 public:
56 explicit UnixDomainServerSocketFactory(const std::string& socket_name)
vkuzkokov79426762015-01-13 08:03:0057 : socket_name_(socket_name) {}
byungchul38c3ae72014-08-25 23:27:4658
Peter Boström9b036532021-10-28 23:37:2859 UnixDomainServerSocketFactory(const UnixDomainServerSocketFactory&) = delete;
60 UnixDomainServerSocketFactory& operator=(
61 const UnixDomainServerSocketFactory&) = delete;
62
byungchul38c3ae72014-08-25 23:27:4663 private:
pfeldmanf1a16942016-09-02 21:28:0064 // content::DevToolsSocketFactory.
dcheng6003e0b2016-04-09 18:42:3465 std::unique_ptr<net::ServerSocket> CreateForHttpServer() override {
66 std::unique_ptr<net::UnixDomainServerSocket> socket(
danakjc988f0be2019-05-17 20:48:0167 new net::UnixDomainServerSocket(
68 base::BindRepeating(&CanUserConnectToDevTools),
69 true /* use_abstract_namespace */));
tfarinaa7b245d2016-02-02 02:03:4970 if (socket->BindAndListen(socket_name_, kBackLog) != net::OK)
Lei Zhangdf291f62021-04-14 17:23:4471 return nullptr;
vkuzkokov79426762015-01-13 08:03:0072
tfarinaa7b245d2016-02-02 02:03:4973 return std::move(socket);
byungchul38c3ae72014-08-25 23:27:4674 }
75
pfeldmanf1a16942016-09-02 21:28:0076 std::unique_ptr<net::ServerSocket> CreateForTethering(
77 std::string* out_name) override {
78 return nullptr;
79 }
80
vkuzkokov79426762015-01-13 08:03:0081 std::string socket_name_;
byungchul38c3ae72014-08-25 23:27:4682};
83#else
pfeldmanf1a16942016-09-02 21:28:0084class TCPServerSocketFactory : public content::DevToolsSocketFactory {
byungchul38c3ae72014-08-25 23:27:4685 public:
avi66a07722015-12-25 23:38:1286 TCPServerSocketFactory(const std::string& address, uint16_t port)
87 : address_(address), port_(port) {}
byungchul38c3ae72014-08-25 23:27:4688
Peter Boström9b036532021-10-28 23:37:2889 TCPServerSocketFactory(const TCPServerSocketFactory&) = delete;
90 TCPServerSocketFactory& operator=(const TCPServerSocketFactory&) = delete;
91
byungchul38c3ae72014-08-25 23:27:4692 private:
pfeldmanf1a16942016-09-02 21:28:0093 // content::DevToolsSocketFactory.
dcheng6003e0b2016-04-09 18:42:3494 std::unique_ptr<net::ServerSocket> CreateForHttpServer() override {
95 std::unique_ptr<net::ServerSocket> socket(
mikecironef22f9812016-10-04 03:40:1996 new net::TCPServerSocket(nullptr, net::NetLogSource()));
vkuzkokov79426762015-01-13 08:03:0097 if (socket->ListenWithAddressAndPort(address_, port_, kBackLog) != net::OK)
Lei Zhangdf291f62021-04-14 17:23:4498 return nullptr;
vkuzkokov79426762015-01-13 08:03:0099
pfeldmanf7c18d0242016-09-08 19:54:26100 net::IPEndPoint endpoint;
101 if (socket->GetLocalAddress(&endpoint) == net::OK)
102 base::subtle::NoBarrier_Store(&g_last_used_port, endpoint.port());
103
vkuzkokov79426762015-01-13 08:03:00104 return socket;
byungchul38c3ae72014-08-25 23:27:46105 }
106
pfeldmanf1a16942016-09-02 21:28:00107 std::unique_ptr<net::ServerSocket> CreateForTethering(
108 std::string* out_name) override {
109 return nullptr;
110 }
111
vkuzkokov79426762015-01-13 08:03:00112 std::string address_;
avi66a07722015-12-25 23:38:12113 uint16_t port_;
byungchul38c3ae72014-08-25 23:27:46114};
115#endif
116
pfeldmanf1a16942016-09-02 21:28:00117std::unique_ptr<content::DevToolsSocketFactory> CreateSocketFactory() {
avi83883c82014-12-23 00:08:49118 const base::CommandLine& command_line =
119 *base::CommandLine::ForCurrentProcess();
Xiaohan Wangbd084422022-01-15 18:47:51120#if BUILDFLAG(IS_ANDROID)
[email protected]90e6c5412013-04-16 22:45:25121 std::string socket_name = "content_shell_devtools_remote";
122 if (command_line.HasSwitch(switches::kRemoteDebuggingSocketName)) {
123 socket_name = command_line.GetSwitchValueASCII(
124 switches::kRemoteDebuggingSocketName);
125 }
pfeldmanf1a16942016-09-02 21:28:00126 return std::unique_ptr<content::DevToolsSocketFactory>(
byungchul38c3ae72014-08-25 23:27:46127 new UnixDomainServerSocketFactory(socket_name));
[email protected]90e6c5412013-04-16 22:45:25128#else
129 // See if the user specified a port on the command line (useful for
130 // automation). If not, use an ephemeral port by specifying 0.
avi66a07722015-12-25 23:38:12131 uint16_t port = 0;
[email protected]90e6c5412013-04-16 22:45:25132 if (command_line.HasSwitch(switches::kRemoteDebuggingPort)) {
133 int temp_port;
134 std::string port_str =
135 command_line.GetSwitchValueASCII(switches::kRemoteDebuggingPort);
136 if (base::StringToInt(port_str, &temp_port) &&
yzshen6051dfd32015-10-20 19:23:25137 temp_port >= 0 && temp_port < 65535) {
avi66a07722015-12-25 23:38:12138 port = static_cast<uint16_t>(temp_port);
[email protected]90e6c5412013-04-16 22:45:25139 } else {
140 DLOG(WARNING) << "Invalid http debugger port number " << temp_port;
141 }
142 }
Tiago Vignattia293c2c2023-03-28 20:31:04143 // By default listen to incoming DevTools connections on localhost.
144 std::string address_str = net::IPAddress::IPv4Localhost().ToString();
145 if (command_line.HasSwitch(switches::kRemoteDebuggingAddress)) {
146 net::IPAddress address;
147 address_str =
148 command_line.GetSwitchValueASCII(switches::kRemoteDebuggingAddress);
149 if (!address.AssignFromIPLiteral(address_str)) {
150 DLOG(WARNING) << "Invalid devtools server address: " << address_str;
151 }
152 }
pfeldmanf1a16942016-09-02 21:28:00153 return std::unique_ptr<content::DevToolsSocketFactory>(
Tiago Vignattia293c2c2023-03-28 20:31:04154 new TCPServerSocketFactory(address_str, port));
[email protected]ed6635e2012-10-27 00:44:09155#endif
[email protected]90e6c5412013-04-16 22:45:25156}
[email protected]852b34ba2013-10-03 16:29:06157
pfeldman10628762016-09-08 07:59:26158} // namespace
vkuzkokovcbabd582014-11-06 13:53:54159
dgozman252e18d2014-09-22 12:40:06160// ShellDevToolsManagerDelegate ----------------------------------------------
161
vkuzkokovcbabd582014-11-06 13:53:54162// static
pfeldmanf7c18d0242016-09-08 19:54:26163int ShellDevToolsManagerDelegate::GetHttpHandlerPort() {
164 return base::subtle::NoBarrier_Load(&g_last_used_port);
165}
166
167// static
pfeldman10628762016-09-08 07:59:26168void ShellDevToolsManagerDelegate::StartHttpHandler(
vkuzkokovcbabd582014-11-06 13:53:54169 BrowserContext* browser_context) {
170 std::string frontend_url;
pfeldman10628762016-09-08 07:59:26171 DevToolsAgentHost::StartRemoteDebuggingServer(
Pavel Feldmanc8a484b52018-02-07 21:07:32172 CreateSocketFactory(), browser_context->GetPath(), base::FilePath());
Pavel Feldman2b11e2352017-10-25 05:24:01173
174 const base::CommandLine& command_line =
175 *base::CommandLine::ForCurrentProcess();
176 if (command_line.HasSwitch(switches::kRemoteDebuggingPipe))
Dmitry Gozman8bbf58d2020-11-13 22:48:26177 DevToolsAgentHost::StartRemoteDebuggingPipeHandler(base::OnceClosure());
vkuzkokovcbabd582014-11-06 13:53:54178}
179
pfeldman10628762016-09-08 07:59:26180// static
181void ShellDevToolsManagerDelegate::StopHttpHandler() {
182 DevToolsAgentHost::StopRemoteDebuggingServer();
183}
184
Pavel Feldman43f56b7c2016-08-30 00:04:35185ShellDevToolsManagerDelegate::ShellDevToolsManagerDelegate(
186 BrowserContext* browser_context)
187 : browser_context_(browser_context) {
dgozman252e18d2014-09-22 12:40:06188}
189
190ShellDevToolsManagerDelegate::~ShellDevToolsManagerDelegate() {
191}
192
Andrey Lushnikov36299bc2018-08-23 22:09:54193BrowserContext* ShellDevToolsManagerDelegate::GetDefaultBrowserContext() {
194 return browser_context_;
195}
196
Andrey Lushnikovdf1651982018-09-14 19:00:37197void ShellDevToolsManagerDelegate::ClientAttached(
Johannes Henkel9d14e4b82020-01-28 01:29:41198 content::DevToolsAgentHostClientChannel* channel) {
Andrey Lushnikovdf1651982018-09-14 19:00:37199 // Make sure we don't receive notifications twice for the same client.
Weizhong Xiaa10850f2024-04-24 18:53:00200 CHECK(!base::Contains(sessions_, channel));
201 sessions_.emplace(
202 channel,
203 std::make_unique<shell::protocol::ShellDevToolsSession>(
204 base::raw_ref<BrowserContext>::from_ptr(browser_context_), channel));
Andrey Lushnikovdf1651982018-09-14 19:00:37205}
206
207void ShellDevToolsManagerDelegate::ClientDetached(
Johannes Henkel9d14e4b82020-01-28 01:29:41208 content::DevToolsAgentHostClientChannel* channel) {
Weizhong Xiaa10850f2024-04-24 18:53:00209 sessions_.erase(channel);
210}
211
212void ShellDevToolsManagerDelegate::HandleCommand(
213 content::DevToolsAgentHostClientChannel* channel,
214 base::span<const uint8_t> message,
215 NotHandledCallback callback) {
216 auto& session = sessions_.at(channel);
217 session->HandleCommand(message, std::move(callback));
Andrey Lushnikovdf1651982018-09-14 19:00:37218}
219
Danil Somsikovd5b36842022-12-16 11:24:50220scoped_refptr<DevToolsAgentHost> ShellDevToolsManagerDelegate::CreateNewTarget(
221 const GURL& url,
Michael Thiessen08b5aad2025-03-14 08:27:22222 content::DevToolsManagerDelegate::TargetType target_type,
223 bool new_window) {
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