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 "libcef/browser/devtools/devtools_manager_delegate.h"
6
7 #include <stdint.h>
8
9 #include <vector>
10
11 #include "base/atomicops.h"
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/files/file_path.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "build/build_config.h"
20 #include "cef/grit/cef_resources.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/devtools_agent_host.h"
23 #include "content/public/browser/devtools_frontend_host.h"
24 #include "content/public/browser/devtools_socket_factory.h"
25 #include "content/public/browser/favicon_status.h"
26 #include "content/public/browser/navigation_entry.h"
27 #include "content/public/browser/render_view_host.h"
28 #include "content/public/browser/web_contents.h"
29 #include "content/public/common/content_switches.h"
30 #include "content/public/common/url_constants.h"
31 #include "content/public/common/user_agent.h"
32 #include "net/base/net_errors.h"
33 #include "net/log/net_log_source.h"
34 #include "net/socket/tcp_server_socket.h"
35 #include "ui/base/resource/resource_bundle.h"
36
37 namespace {
38
39 const int kBackLog = 10;
40
41 class TCPServerSocketFactory : public content::DevToolsSocketFactory {
42 public:
TCPServerSocketFactory(const std::string & address,uint16_t port)43 TCPServerSocketFactory(const std::string& address, uint16_t port)
44 : address_(address), port_(port) {}
45
46 TCPServerSocketFactory(const TCPServerSocketFactory&) = delete;
47 TCPServerSocketFactory& operator=(const TCPServerSocketFactory&) = delete;
48
49 private:
50 // content::DevToolsSocketFactory.
CreateForHttpServer()51 std::unique_ptr<net::ServerSocket> CreateForHttpServer() override {
52 std::unique_ptr<net::ServerSocket> socket(
53 new net::TCPServerSocket(nullptr, net::NetLogSource()));
54 if (socket->ListenWithAddressAndPort(address_, port_, kBackLog) != net::OK)
55 return std::unique_ptr<net::ServerSocket>();
56 return socket;
57 }
58
CreateForTethering(std::string * out_name)59 std::unique_ptr<net::ServerSocket> CreateForTethering(
60 std::string* out_name) override {
61 return nullptr;
62 }
63
64 std::string address_;
65 uint16_t port_;
66 };
67
CreateSocketFactory()68 std::unique_ptr<content::DevToolsSocketFactory> CreateSocketFactory() {
69 const base::CommandLine& command_line =
70 *base::CommandLine::ForCurrentProcess();
71 // See if the user specified a port on the command line. Specifying 0 would
72 // result in the selection of an ephemeral port but that doesn't make sense
73 // for CEF where the URL is otherwise undiscoverable. Also, don't allow
74 // binding of ports between 0 and 1024 exclusive because they're normally
75 // restricted to root on Posix-based systems.
76 uint16_t port = 0;
77 if (command_line.HasSwitch(switches::kRemoteDebuggingPort)) {
78 int temp_port;
79 std::string port_str =
80 command_line.GetSwitchValueASCII(switches::kRemoteDebuggingPort);
81 if (base::StringToInt(port_str, &temp_port) && temp_port >= 1024 &&
82 temp_port < 65535) {
83 port = static_cast<uint16_t>(temp_port);
84 } else {
85 DLOG(WARNING) << "Invalid http debugger port number " << temp_port;
86 }
87 }
88 if (port == 0)
89 return nullptr;
90 return std::unique_ptr<content::DevToolsSocketFactory>(
91 new TCPServerSocketFactory("127.0.0.1", port));
92 }
93
94 } // namespace
95
96 // CefDevToolsManagerDelegate ----------------------------------------------
97
98 // static
StartHttpHandler(content::BrowserContext * browser_context)99 void CefDevToolsManagerDelegate::StartHttpHandler(
100 content::BrowserContext* browser_context) {
101 std::unique_ptr<content::DevToolsSocketFactory> socket_factory =
102 CreateSocketFactory();
103 if (!socket_factory)
104 return;
105 content::DevToolsAgentHost::StartRemoteDebuggingServer(
106 std::move(socket_factory), browser_context->GetPath(), base::FilePath());
107
108 const base::CommandLine& command_line =
109 *base::CommandLine::ForCurrentProcess();
110 if (command_line.HasSwitch(switches::kRemoteDebuggingPipe)) {
111 content::DevToolsAgentHost::StartRemoteDebuggingPipeHandler(
112 base::OnceClosure());
113 }
114 }
115
116 // static
StopHttpHandler()117 void CefDevToolsManagerDelegate::StopHttpHandler() {
118 // This is a no-op if the server was never started.
119 content::DevToolsAgentHost::StopRemoteDebuggingServer();
120 }
121
CefDevToolsManagerDelegate()122 CefDevToolsManagerDelegate::CefDevToolsManagerDelegate() {}
123
~CefDevToolsManagerDelegate()124 CefDevToolsManagerDelegate::~CefDevToolsManagerDelegate() {}
125
126 scoped_refptr<content::DevToolsAgentHost>
CreateNewTarget(const GURL & url)127 CefDevToolsManagerDelegate::CreateNewTarget(const GURL& url) {
128 // This is reached when the user selects "Open link in new tab" from the
129 // DevTools interface.
130 // TODO(cef): Consider exposing new API to support this.
131 return nullptr;
132 }
133
GetDiscoveryPageHTML()134 std::string CefDevToolsManagerDelegate::GetDiscoveryPageHTML() {
135 return ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
136 IDR_CEF_DEVTOOLS_DISCOVERY_PAGE);
137 }
138
HasBundledFrontendResources()139 bool CefDevToolsManagerDelegate::HasBundledFrontendResources() {
140 return true;
141 }
142