Commit 347f6990 authored by Fabrice de Gans-Riberi's avatar Fabrice de Gans-Riberi Committed by Commit Bot

[fuchsia] Add support for remote_debugging_port in CreateContextParams.

* Implement Frame.GetRemoteDebuggingPort.
* Move all remote debugging handling in the Context process to
  WebEngineRemoteDebugging.
* Change the debug DevTools behavior to not fallback on attempting to
  listen on IPv6 localhost in case of failure on IPv4 localhost.
* Refactor the GetDevToolsListFromPort() test utility out of
  WebEngineDebugIntegrationTest to be shared with
  WebEngineIntegrationTest.
* Fix a potential issue when the DevTools service fails to start and
  the debug DevTools listeners were not notified. In ContextImpl, the
  OnDevToolsPortReady() callback was only called when the DevTools
  service opened. It is now systematically called during browser
  process start-up and |devtools_port_received_| keeps track of that
  call in ContextImpl, rather than assuming a 0 value for
  |devtools_port_| means the service start was never requested.

Bug: 973268
Change-Id: I58d15c0656ebe1adfe6c254e4aefc0c7bfd54176
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1670441Reviewed-by: default avatarDirk Pranke <dpranke@chromium.org>
Reviewed-by: default avatarSergey Ulanov <sergeyu@chromium.org>
Commit-Queue: Fabrice de Gans-Riberi <fdegans@chromium.org>
Cr-Commit-Position: refs/heads/master@{#676208}
parent 5d9df7f2
...@@ -1007,7 +1007,7 @@ _BANNED_CPP_FUNCTIONS = ( ...@@ -1007,7 +1007,7 @@ _BANNED_CPP_FUNCTIONS = (
r'.*_ios\.(cc|h)$', r'.*_ios\.(cc|h)$',
r'^net[\\/].*\.(cc|h)$', r'^net[\\/].*\.(cc|h)$',
r'.*[\\/]tools[\\/].*\.(cc|h)$', r'.*[\\/]tools[\\/].*\.(cc|h)$',
r'^fuchsia/engine/web_engine_debug_integration_test\.cc$', r'^fuchsia/engine/test_devtools_list_fetcher\.cc$',
), ),
), ),
( (
......
...@@ -117,12 +117,12 @@ component("web_engine_core") { ...@@ -117,12 +117,12 @@ component("web_engine_core") {
"browser/web_engine_content_browser_client.h", "browser/web_engine_content_browser_client.h",
"browser/web_engine_devtools_manager_delegate.cc", "browser/web_engine_devtools_manager_delegate.cc",
"browser/web_engine_devtools_manager_delegate.h", "browser/web_engine_devtools_manager_delegate.h",
"browser/web_engine_devtools_socket_factory.cc",
"browser/web_engine_devtools_socket_factory.h",
"browser/web_engine_net_log.cc", "browser/web_engine_net_log.cc",
"browser/web_engine_net_log.h", "browser/web_engine_net_log.h",
"browser/web_engine_permission_manager.cc", "browser/web_engine_permission_manager.cc",
"browser/web_engine_permission_manager.h", "browser/web_engine_permission_manager.h",
"browser/web_engine_remote_debugging.cc",
"browser/web_engine_remote_debugging.h",
"browser/web_engine_screen.cc", "browser/web_engine_screen.cc",
"browser/web_engine_screen.h", "browser/web_engine_screen.h",
"browser/web_engine_url_request_context_getter.cc", "browser/web_engine_url_request_context_getter.cc",
...@@ -245,6 +245,8 @@ test("web_engine_integration_tests") { ...@@ -245,6 +245,8 @@ test("web_engine_integration_tests") {
sources = [ sources = [
"test_debug_listener.cc", "test_debug_listener.cc",
"test_debug_listener.h", "test_debug_listener.h",
"test_devtools_list_fetcher.cc",
"test_devtools_list_fetcher.h",
"web_engine_debug_integration_test.cc", "web_engine_debug_integration_test.cc",
"web_engine_integration_test.cc", "web_engine_integration_test.cc",
] ]
......
...@@ -9,32 +9,13 @@ ...@@ -9,32 +9,13 @@
#include <utility> #include <utility>
#include "base/fuchsia/fuchsia_logging.h" #include "base/fuchsia/fuchsia_logging.h"
#include "base/strings/string_tokenizer.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "fuchsia/engine/browser/frame_impl.h" #include "fuchsia/engine/browser/frame_impl.h"
#include "fuchsia/engine/browser/web_engine_browser_context.h" #include "fuchsia/engine/browser/web_engine_browser_context.h"
#include "fuchsia/engine/common.h" #include "fuchsia/engine/common.h"
ContextImpl::ContextImpl(content::BrowserContext* browser_context) ContextImpl::ContextImpl(content::BrowserContext* browser_context)
: browser_context_(browser_context) { : browser_context_(browser_context) {}
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
kRemoteDebuggerHandles)) {
std::string handle_ids_str =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
kRemoteDebuggerHandles);
// Extract individual handle IDs from the comma-separated list.
base::StringTokenizer tokenizer(handle_ids_str, ",");
while (tokenizer.GetNext()) {
uint32_t handle_id = 0;
if (!base::StringToUint(tokenizer.token(), &handle_id))
continue;
fidl::InterfacePtr<fuchsia::web::DevToolsPerContextListener> listener;
listener.Bind(zx::channel(zx_take_startup_handle(handle_id)));
devtools_listeners_.AddInterfacePtr(std::move(listener));
}
}
}
ContextImpl::~ContextImpl() = default; ContextImpl::~ContextImpl() = default;
...@@ -47,17 +28,8 @@ bool ContextImpl::IsJavaScriptInjectionAllowed() { ...@@ -47,17 +28,8 @@ bool ContextImpl::IsJavaScriptInjectionAllowed() {
return allow_javascript_injection_; return allow_javascript_injection_;
} }
void ContextImpl::OnDevToolsPortReady() { void ContextImpl::OnDebugDevToolsPortReady() {
if (devtools_port_ == 0 || devtools_listeners_notified_) web_engine_remote_debugging_.OnDebugDevToolsPortReady();
return;
for (auto& listener : devtools_listeners_.ptrs()) {
listener->get()->OnHttpPortOpen(devtools_port_);
}
devtools_listeners_notified_ = true;
}
void ContextImpl::OnDevToolsPortOpened(uint16_t port) {
devtools_port_ = port;
} }
void ContextImpl::CreateFrame( void ContextImpl::CreateFrame(
...@@ -70,6 +42,11 @@ void ContextImpl::CreateFrame( ...@@ -70,6 +42,11 @@ void ContextImpl::CreateFrame(
std::move(frame))); std::move(frame)));
} }
void ContextImpl::GetRemoteDebuggingPort(
GetRemoteDebuggingPortCallback callback) {
web_engine_remote_debugging_.GetRemoteDebuggingPort(std::move(callback));
}
FrameImpl* ContextImpl::GetFrameImplForTest(fuchsia::web::FramePtr* frame_ptr) { FrameImpl* ContextImpl::GetFrameImplForTest(fuchsia::web::FramePtr* frame_ptr) {
DCHECK(frame_ptr); DCHECK(frame_ptr);
......
...@@ -6,12 +6,12 @@ ...@@ -6,12 +6,12 @@
#define FUCHSIA_ENGINE_BROWSER_CONTEXT_IMPL_H_ #define FUCHSIA_ENGINE_BROWSER_CONTEXT_IMPL_H_
#include <fuchsia/web/cpp/fidl.h> #include <fuchsia/web/cpp/fidl.h>
#include <lib/fidl/cpp/interface_ptr_set.h>
#include <memory> #include <memory>
#include <set> #include <set>
#include "base/containers/unique_ptr_adapters.h" #include "base/containers/unique_ptr_adapters.h"
#include "base/macros.h" #include "base/macros.h"
#include "fuchsia/engine/browser/web_engine_remote_debugging.h"
#include "fuchsia/engine/web_engine_export.h" #include "fuchsia/engine/web_engine_export.h"
namespace content { namespace content {
...@@ -42,15 +42,13 @@ class WEB_ENGINE_EXPORT ContextImpl : public fuchsia::web::Context { ...@@ -42,15 +42,13 @@ class WEB_ENGINE_EXPORT ContextImpl : public fuchsia::web::Context {
bool IsJavaScriptInjectionAllowed(); bool IsJavaScriptInjectionAllowed();
// Called by Frames to signal a document has been loaded and signal to the // Called by Frames to signal a document has been loaded and signal to the
// |devtools_listeners_| that they can now successfully connect ChromeDriver // debug listeners in |web_engine_remote_debugging_| that they can now
// on |devtools_port_|. // successfully connect ChromeDriver.
void OnDevToolsPortReady(); void OnDebugDevToolsPortReady();
// Signals the DevTools debugging port has been opened.
void OnDevToolsPortOpened(uint16_t port);
// fuchsia::web::Context implementation. // fuchsia::web::Context implementation.
void CreateFrame(fidl::InterfaceRequest<fuchsia::web::Frame> frame) override; void CreateFrame(fidl::InterfaceRequest<fuchsia::web::Frame> frame) override;
void GetRemoteDebuggingPort(GetRemoteDebuggingPortCallback callback) override;
// Gets the underlying FrameImpl service object associated with a connected // Gets the underlying FrameImpl service object associated with a connected
// |frame_ptr| client. // |frame_ptr| client.
...@@ -67,10 +65,7 @@ class WEB_ENGINE_EXPORT ContextImpl : public fuchsia::web::Context { ...@@ -67,10 +65,7 @@ class WEB_ENGINE_EXPORT ContextImpl : public fuchsia::web::Context {
// destruction when this ContextImpl is destroyed. // destruction when this ContextImpl is destroyed.
std::set<std::unique_ptr<FrameImpl>, base::UniquePtrComparator> frames_; std::set<std::unique_ptr<FrameImpl>, base::UniquePtrComparator> frames_;
fidl::InterfacePtrSet<fuchsia::web::DevToolsPerContextListener> WebEngineRemoteDebugging web_engine_remote_debugging_;
devtools_listeners_;
bool devtools_listeners_notified_ = false;
uint16_t devtools_port_ = 0;
DISALLOW_COPY_AND_ASSIGN(ContextImpl); DISALLOW_COPY_AND_ASSIGN(ContextImpl);
}; };
......
...@@ -580,5 +580,5 @@ void FrameImpl::ReadyToCommitNavigation( ...@@ -580,5 +580,5 @@ void FrameImpl::ReadyToCommitNavigation(
void FrameImpl::DidFinishLoad(content::RenderFrameHost* render_frame_host, void FrameImpl::DidFinishLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url) { const GURL& validated_url) {
context_->OnDevToolsPortReady(); context_->OnDebugDevToolsPortReady();
} }
...@@ -8,15 +8,12 @@ ...@@ -8,15 +8,12 @@
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/fuchsia/fuchsia_logging.h" #include "base/fuchsia/fuchsia_logging.h"
#include "base/logging.h" #include "base/logging.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
#include "content/public/common/main_function_params.h" #include "content/public/common/main_function_params.h"
#include "fuchsia/engine/browser/context_impl.h" #include "fuchsia/engine/browser/context_impl.h"
#include "fuchsia/engine/browser/web_engine_browser_context.h" #include "fuchsia/engine/browser/web_engine_browser_context.h"
#include "fuchsia/engine/browser/web_engine_devtools_socket_factory.h"
#include "fuchsia/engine/browser/web_engine_screen.h" #include "fuchsia/engine/browser/web_engine_screen.h"
#include "fuchsia/engine/common.h" #include "fuchsia/engine/common.h"
#include "ui/aura/screen_ozone.h" #include "ui/aura/screen_ozone.h"
...@@ -54,16 +51,6 @@ void WebEngineBrowserMainParts::PreMainMessageLoopRun() { ...@@ -54,16 +51,6 @@ void WebEngineBrowserMainParts::PreMainMessageLoopRun() {
context_binding_ = std::make_unique<fidl::Binding<fuchsia::web::Context>>( context_binding_ = std::make_unique<fidl::Binding<fuchsia::web::Context>>(
context_service_.get(), std::move(request_)); context_service_.get(), std::move(request_));
// Start the remote debugging server.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
kRemoteDebuggerHandles)) {
content::DevToolsAgentHost::StartRemoteDebuggingServer(
std::make_unique<WebEngineDevToolsSocketFactory>(
base::BindRepeating(&ContextImpl::OnDevToolsPortOpened,
base::Unretained(context_service_.get()))),
browser_context_->GetPath(), base::FilePath());
}
// Quit the browser main loop when the Context connection is dropped. // Quit the browser main loop when the Context connection is dropped.
context_binding_->set_error_handler([this](zx_status_t status) { context_binding_->set_error_handler([this](zx_status_t status) {
ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status) ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
...@@ -103,11 +90,6 @@ void WebEngineBrowserMainParts::PostMainMessageLoopRun() { ...@@ -103,11 +90,6 @@ void WebEngineBrowserMainParts::PostMainMessageLoopRun() {
DCHECK(!context_service_); DCHECK(!context_service_);
DCHECK(!context_binding_->is_bound()); DCHECK(!context_binding_->is_bound());
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
kRemoteDebuggerHandles)) {
content::DevToolsAgentHost::StopRemoteDebuggingServer();
}
// These resources must be freed while a MessageLoop is still available, so // These resources must be freed while a MessageLoop is still available, so
// that they may post cleanup tasks during teardown. // that they may post cleanup tasks during teardown.
// NOTE: Please destroy objects in the reverse order of their creation. // NOTE: Please destroy objects in the reverse order of their creation.
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "fuchsia/engine/browser/web_engine_devtools_socket_factory.h"
#include "fuchsia/engine/browser/web_engine_browser_context.h"
#include "net/base/net_errors.h"
#include "net/socket/tcp_server_socket.h"
namespace {
const int kTcpListenBackLog = 5;
} // namespace
WebEngineDevToolsSocketFactory::WebEngineDevToolsSocketFactory(
OnPortOpenedCallback callback)
: callback_(std::move(callback)) {}
WebEngineDevToolsSocketFactory::~WebEngineDevToolsSocketFactory() = default;
std::unique_ptr<net::ServerSocket>
WebEngineDevToolsSocketFactory::CreateForHttpServer() {
std::unique_ptr<net::ServerSocket> socket(
new net::TCPServerSocket(nullptr, net::NetLogSource()));
if (socket->Listen(net::IPEndPoint(net::IPAddress::IPv4Localhost(), 0),
kTcpListenBackLog) == net::OK) {
net::IPEndPoint end_point;
socket->GetLocalAddress(&end_point);
callback_.Run(end_point.port());
return socket;
}
int error = socket->Listen(
net::IPEndPoint(net::IPAddress::IPv6Localhost(), 0), kTcpListenBackLog);
if (error == net::OK) {
net::IPEndPoint end_point;
socket->GetLocalAddress(&end_point);
callback_.Run(end_point.port());
return socket;
}
LOG(WARNING) << "Failed to start the HTTP debugger service. "
<< net::ErrorToString(error);
return nullptr;
}
std::unique_ptr<net::ServerSocket>
WebEngineDevToolsSocketFactory::CreateForTethering(std::string* out_name) {
return nullptr;
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FUCHSIA_ENGINE_BROWSER_WEB_ENGINE_DEVTOOLS_SOCKET_FACTORY_H_
#define FUCHSIA_ENGINE_BROWSER_WEB_ENGINE_DEVTOOLS_SOCKET_FACTORY_H_
#include "base/callback.h"
#include "content/public/browser/devtools_socket_factory.h"
class WebEngineDevToolsSocketFactory : public content::DevToolsSocketFactory {
public:
using OnPortOpenedCallback = base::RepeatingCallback<void(uint16_t)>;
explicit WebEngineDevToolsSocketFactory(OnPortOpenedCallback callback);
~WebEngineDevToolsSocketFactory() override;
// content::DevToolsSocketFactory implementation.
std::unique_ptr<net::ServerSocket> CreateForHttpServer() override;
std::unique_ptr<net::ServerSocket> CreateForTethering(
std::string* out_name) override;
private:
OnPortOpenedCallback callback_;
DISALLOW_COPY_AND_ASSIGN(WebEngineDevToolsSocketFactory);
};
#endif // FUCHSIA_ENGINE_BROWSER_WEB_ENGINE_DEVTOOLS_SOCKET_FACTORY_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "fuchsia/engine/browser/web_engine_remote_debugging.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_tokenizer.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_socket_factory.h"
#include "content/public/common/content_switches.h"
#include "fuchsia/engine/browser/web_engine_browser_context.h"
#include "fuchsia/engine/common.h"
#include "net/base/net_errors.h"
#include "net/base/port_util.h"
#include "net/socket/tcp_server_socket.h"
namespace {
class WebEngineDevToolsSocketFactory : public content::DevToolsSocketFactory {
public:
WebEngineDevToolsSocketFactory(
WebEngineRemoteDebugging::OnListenCallback on_listen_callback,
uint16_t port,
bool for_fidl_debug_api)
: on_listen_callback_(std::move(on_listen_callback)),
port_(port),
for_fidl_debug_api_(for_fidl_debug_api) {}
~WebEngineDevToolsSocketFactory() override = default;
// content::DevToolsSocketFactory implementation.
std::unique_ptr<net::ServerSocket> CreateForHttpServer() override {
const int kTcpListenBackLog = 5;
std::unique_ptr<net::ServerSocket> socket(
new net::TCPServerSocket(nullptr, net::NetLogSource()));
// When set from the fuchsia.web.Debug API, remote debugging only listens on
// IPv4 localhost, not IPv6.
net::IPEndPoint ip_end_point(for_fidl_debug_api_
? net::IPAddress::IPv4Localhost()
: net::IPAddress::IPv6AllZeros(),
port_);
int error = socket->Listen(ip_end_point, kTcpListenBackLog);
if (error != net::OK) {
LOG(WARNING) << "Failed to start the HTTP debugger service. "
<< net::ErrorToString(error);
std::move(on_listen_callback_).Run(0);
return nullptr;
}
net::IPEndPoint end_point;
socket->GetLocalAddress(&end_point);
std::move(on_listen_callback_).Run(end_point.port());
return socket;
}
std::unique_ptr<net::ServerSocket> CreateForTethering(
std::string* out_name) override {
return nullptr;
}
private:
WebEngineRemoteDebugging::OnListenCallback on_listen_callback_;
const uint16_t port_;
const bool for_fidl_debug_api_;
DISALLOW_COPY_AND_ASSIGN(WebEngineDevToolsSocketFactory);
};
} // namespace
WebEngineRemoteDebugging::WebEngineRemoteDebugging() {
const base::FilePath kDisableActivePortOutputDirectory;
const base::FilePath kDisableDebugOutput;
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kRemoteDebuggingPort)) {
// Set up DevTools to listen on all network routes on the command-line
// provided port.
base::StringPiece command_line_port_value =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kRemoteDebuggingPort);
int parsed_port = 0;
// The command-line option can only be provided by the ContextProvider
// process, it should not fail to parse to an int.
DCHECK(base::StringToInt(command_line_port_value, &parsed_port));
if (parsed_port != 0 &&
(!net::IsPortValid(parsed_port) || net::IsWellKnownPort(parsed_port))) {
LOG(WARNING) << "Invalid HTTP debugger service port number "
<< command_line_port_value;
OnRemoteDebuggingServiceStatusChanged(0);
return;
}
content::DevToolsAgentHost::StartRemoteDebuggingServer(
std::make_unique<WebEngineDevToolsSocketFactory>(
base::BindOnce(&WebEngineRemoteDebugging::
OnRemoteDebuggingServiceStatusChanged,
base::Unretained(this)),
parsed_port, false),
kDisableActivePortOutputDirectory, kDisableDebugOutput);
remote_debugging_enabled_ = true;
} else if (base::CommandLine::ForCurrentProcess()->HasSwitch(
kRemoteDebuggerHandles)) {
// Set up DevTools to listen on localhost on an ephemeral port when
// enabled from the fuchsia.web.Debug API.
content::DevToolsAgentHost::StartRemoteDebuggingServer(
std::make_unique<WebEngineDevToolsSocketFactory>(
base::BindOnce(&WebEngineRemoteDebugging::
OnRemoteDebuggingServiceStatusChanged,
base::Unretained(this)),
0, true),
kDisableActivePortOutputDirectory, kDisableDebugOutput);
remote_debugging_enabled_ = true;
// Initialize the Debug devtools listeners.
debug_devtools_listeners_.emplace();
std::string handle_ids_str =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
kRemoteDebuggerHandles);
// Extract individual handle IDs from the comma-separated list.
base::StringTokenizer tokenizer(handle_ids_str, ",");
while (tokenizer.GetNext()) {
uint32_t handle_id = 0;
if (!base::StringToUint(tokenizer.token(), &handle_id))
continue;
fidl::InterfacePtr<fuchsia::web::DevToolsPerContextListener> listener;
listener.Bind(zx::channel(zx_take_startup_handle(handle_id)));
debug_devtools_listeners_->AddInterfacePtr(std::move(listener));
}
} else {
OnRemoteDebuggingServiceStatusChanged(0);
}
}
void WebEngineRemoteDebugging::OnDebugDevToolsPortReady() {
// The DevTools service should have been opened before a Frame navigated.
DCHECK(devtools_port_received_);
if (debug_devtools_listeners_notified_)
return;
debug_devtools_listeners_notified_ = true;
if (!debug_devtools_listeners_)
return;
if (devtools_port_ == 0) {
// The DevTools service failed to open. Close the listeners.
debug_devtools_listeners_->CloseAll();
} else {
for (auto& listener : debug_devtools_listeners_->ptrs()) {
listener->get()->OnHttpPortOpen(devtools_port_);
}
}
}
void WebEngineRemoteDebugging::GetRemoteDebuggingPort(
GetRemoteDebuggingPortCallback callback) {
pending_callbacks_.push_back(std::move(callback));
MaybeSendRemoteDebuggingCallbacks();
}
WebEngineRemoteDebugging::~WebEngineRemoteDebugging() {
if (remote_debugging_enabled_)
content::DevToolsAgentHost::StopRemoteDebuggingServer();
}
void WebEngineRemoteDebugging::OnRemoteDebuggingServiceStatusChanged(
uint16_t port) {
DCHECK(!devtools_port_received_);
devtools_port_ = port;
devtools_port_received_ = true;
MaybeSendRemoteDebuggingCallbacks();
}
void WebEngineRemoteDebugging::MaybeSendRemoteDebuggingCallbacks() {
if (!devtools_port_received_)
return;
std::vector<GetRemoteDebuggingPortCallback> pending_callbacks =
std::move(pending_callbacks_);
// Signal the pending callbacks and clear the vector.
std::for_each(
pending_callbacks.begin(), pending_callbacks.end(),
[this](GetRemoteDebuggingPortCallback& callback) {
fuchsia::web::Context_GetRemoteDebuggingPort_Result result;
// Do not send the port in case the service was opened for debugging
// and not via CreateContextParams argument.
if (debug_devtools_listeners_ || devtools_port_ == 0) {
result.set_err(
fuchsia::web::ContextError::REMOTE_DEBUGGING_PORT_NOT_OPENED);
} else {
fuchsia::web::Context_GetRemoteDebuggingPort_Response response;
response.port = devtools_port_;
result.set_response(std::move(response));
}
callback(std::move(result));
});
pending_callbacks.clear();
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FUCHSIA_ENGINE_BROWSER_WEB_ENGINE_REMOTE_DEBUGGING_H_
#define FUCHSIA_ENGINE_BROWSER_WEB_ENGINE_REMOTE_DEBUGGING_H_
#include <fuchsia/web/cpp/fidl.h>
#include <lib/fidl/cpp/interface_ptr_set.h>
#include "base/callback.h"
#include "base/optional.h"
// Initializes the DevTools service with the information provided on the
// command line.
class WebEngineRemoteDebugging {
public:
using OnListenCallback = base::OnceCallback<void(uint16_t port)>;
using GetRemoteDebuggingPortCallback =
fuchsia::web::Context::GetRemoteDebuggingPortCallback;
WebEngineRemoteDebugging();
~WebEngineRemoteDebugging();
// Called by the Context to signal a document has been loaded and signal to
// the |debug_devtools_listeners_| that they can now successfully connect
// ChromeDriver on |devtools_port_|.
void OnDebugDevToolsPortReady();
// Actual implementation of the Context.GetRemoteDebuggingPort() FIDL API.
void GetRemoteDebuggingPort(GetRemoteDebuggingPortCallback callback);
private:
// Signals the remote debugging service status changed. |port| will be set to
// 0 if the service was not open or failed to open.
void OnRemoteDebuggingServiceStatusChanged(uint16_t port);
void MaybeSendRemoteDebuggingCallbacks();
// Set to true if remote debugging was enabled.
bool remote_debugging_enabled_ = false;
// The remote debugging port, 0 if not set or the service failed to open.
uint16_t devtools_port_ = 0;
// Set to true once OnRemoteDebuggingServiceStatusChanged() has been called.
// Must only be set once.
bool devtools_port_received_ = false;
// Pending callbacks for the GetRemoteDebuggingPort() API.
std::vector<GetRemoteDebuggingPortCallback> pending_callbacks_;
// If remote debugging is enabled via the fuchsia.web.Debug API, holds the
// Debug listeners.
base::Optional<
fidl::InterfacePtrSet<fuchsia::web::DevToolsPerContextListener>>
debug_devtools_listeners_;
// Set to true once the |debug_devtools_listeners_| have been notified.
bool debug_devtools_listeners_notified_ = false;
DISALLOW_COPY_AND_ASSIGN(WebEngineRemoteDebugging);
};
#endif // FUCHSIA_ENGINE_BROWSER_WEB_ENGINE_REMOTE_DEBUGGING_H_
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "base/process/launch.h" #include "base/process/launch.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "content/public/common/content_switches.h"
#include "fuchsia/engine/common.h" #include "fuchsia/engine/common.h"
#include "net/http/http_util.h" #include "net/http/http_util.h"
#include "services/service_manager/sandbox/fuchsia/sandbox_policy_fuchsia.h" #include "services/service_manager/sandbox/fuchsia/sandbox_policy_fuchsia.h"
...@@ -153,10 +154,14 @@ void ContextProviderImpl::Create( ...@@ -153,10 +154,14 @@ void ContextProviderImpl::Create(
launch_options.job_handle = job.get(); launch_options.job_handle = job.get();
base::CommandLine launch_command = *base::CommandLine::ForCurrentProcess(); base::CommandLine launch_command = *base::CommandLine::ForCurrentProcess();
// Connect DevTools listeners to the new Context process.
std::vector<zx::channel> devtools_listener_channels; std::vector<zx::channel> devtools_listener_channels;
if (devtools_listeners_.size() != 0) {
if (params.has_remote_debugging_port()) {
launch_command.AppendSwitchNative(
switches::kRemoteDebuggingPort,
base::NumberToString(params.remote_debugging_port()));
} else if (devtools_listeners_.size() != 0) {
// Connect DevTools listeners to the new Context process.
std::vector<std::string> handles_ids; std::vector<std::string> handles_ids;
for (auto& devtools_listener : devtools_listeners_.ptrs()) { for (auto& devtools_listener : devtools_listeners_.ptrs()) {
fidl::InterfaceHandle<fuchsia::web::DevToolsPerContextListener> fidl::InterfaceHandle<fuchsia::web::DevToolsPerContextListener>
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "fuchsia/engine/test_devtools_list_fetcher.h"
#include "base/callback.h"
#include "base/json/json_reader.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/http/http_status_code.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_test_util.h"
namespace {
// Utility class to get the JSON value of the list URL for a DevTools service on
// localhost.
class DevToolsListFetcher : public net::URLFetcherDelegate {
public:
DevToolsListFetcher() {
request_context_getter_ =
base::MakeRefCounted<net::TestURLRequestContextGetter>(
base::ThreadTaskRunnerHandle::Get());
}
~DevToolsListFetcher() override = default;
base::Value GetDevToolsListFromPort(uint16_t port) {
std::string url = base::StringPrintf("http://127.0.0.1:%d/json/list", port);
std::unique_ptr<net::URLFetcher> fetcher = net::URLFetcher::Create(
GURL(url), net::URLFetcher::GET, this, TRAFFIC_ANNOTATION_FOR_TESTS);
fetcher->SetRequestContext(request_context_getter_.get());
fetcher->Start();
base::RunLoop run_loop;
on_url_fetch_complete_ack_ = run_loop.QuitClosure();
run_loop.Run();
if (fetcher->GetStatus().status() != net::URLRequestStatus::SUCCESS)
return base::Value();
if (fetcher->GetResponseCode() != net::HTTP_OK)
return base::Value();
std::string result;
if (!fetcher->GetResponseAsString(&result))
return base::Value();
return base::JSONReader::Read(result).value_or(base::Value());
}
private:
// fuchsia::web::URLFetcherDelegate implementation.
void OnURLFetchComplete(const net::URLFetcher* source) override {
DCHECK(on_url_fetch_complete_ack_);
std::move(on_url_fetch_complete_ack_).Run();
}
scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
base::OnceClosure on_url_fetch_complete_ack_;
DISALLOW_COPY_AND_ASSIGN(DevToolsListFetcher);
};
} // namespace
base::Value GetDevToolsListFromPort(uint16_t port) {
DevToolsListFetcher devtools_fetcher;
return devtools_fetcher.GetDevToolsListFromPort(port);
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FUCHSIA_ENGINE_TEST_DEVTOOLS_LIST_FETCHER_H_
#define FUCHSIA_ENGINE_TEST_DEVTOOLS_LIST_FETCHER_H_
#include "base/values.h"
// Returns the JSON value of the list URL for the DevTools service listening
// on port |port| on localhost. Returns an empty value on error.
base::Value GetDevToolsListFromPort(uint16_t port);
#endif // FUCHSIA_ENGINE_TEST_DEVTOOLS_LIST_FETCHER_H_
...@@ -9,19 +9,14 @@ ...@@ -9,19 +9,14 @@
#include "base/files/file_enumerator.h" #include "base/files/file_enumerator.h"
#include "base/fuchsia/file_utils.h" #include "base/fuchsia/file_utils.h"
#include "base/fuchsia/service_directory_client.h" #include "base/fuchsia/service_directory_client.h"
#include "base/json/json_reader.h"
#include "base/macros.h" #include "base/macros.h"
#include "fuchsia/base/fit_adapter.h" #include "fuchsia/base/fit_adapter.h"
#include "fuchsia/base/frame_test_util.h" #include "fuchsia/base/frame_test_util.h"
#include "fuchsia/base/result_receiver.h" #include "fuchsia/base/result_receiver.h"
#include "fuchsia/base/test_navigation_listener.h" #include "fuchsia/base/test_navigation_listener.h"
#include "fuchsia/engine/test_debug_listener.h" #include "fuchsia/engine/test_debug_listener.h"
#include "net/http/http_status_code.h" #include "fuchsia/engine/test_devtools_list_fetcher.h"
#include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace { namespace {
...@@ -30,8 +25,7 @@ const char kTestServerRoot[] = FILE_PATH_LITERAL("fuchsia/engine/test/data"); ...@@ -30,8 +25,7 @@ const char kTestServerRoot[] = FILE_PATH_LITERAL("fuchsia/engine/test/data");
} // namespace } // namespace
class WebEngineDebugIntegrationTest : public testing::Test, class WebEngineDebugIntegrationTest : public testing::Test {
public net::URLFetcherDelegate {
public: public:
WebEngineDebugIntegrationTest() WebEngineDebugIntegrationTest()
: dev_tools_listener_binding_(&dev_tools_listener_) {} : dev_tools_listener_binding_(&dev_tools_listener_) {}
...@@ -64,10 +58,6 @@ class WebEngineDebugIntegrationTest : public testing::Test, ...@@ -64,10 +58,6 @@ class WebEngineDebugIntegrationTest : public testing::Test,
// callback so the listener will have been added after this call returns. // callback so the listener will have been added after this call returns.
debug_->EnableDevTools(dev_tools_listener_binding_.NewBinding()); debug_->EnableDevTools(dev_tools_listener_binding_.NewBinding());
request_context_getter_ =
base::MakeRefCounted<net::TestURLRequestContextGetter>(
message_loop_.task_runner());
test_server_.ServeFilesFromSourceDirectory(kTestServerRoot); test_server_.ServeFilesFromSourceDirectory(kTestServerRoot);
ASSERT_TRUE(test_server_.Start()); ASSERT_TRUE(test_server_.Start());
} }
...@@ -89,53 +79,18 @@ class WebEngineDebugIntegrationTest : public testing::Test, ...@@ -89,53 +79,18 @@ class WebEngineDebugIntegrationTest : public testing::Test,
web_context.NewRequest()); web_context.NewRequest());
web_context.set_error_handler([](zx_status_t status) { ADD_FAILURE(); }); web_context.set_error_handler([](zx_status_t status) { ADD_FAILURE(); });
fuchsia::web::FramePtr web_frame;
web_context->CreateFrame(web_frame.NewRequest());
web_frame.set_error_handler([](zx_status_t status) { ADD_FAILURE(); });
fuchsia::web::NavigationControllerPtr nav_controller;
web_frame->GetNavigationController(nav_controller.NewRequest());
nav_controller.set_error_handler([](zx_status_t status) { ADD_FAILURE(); });
base::RunLoop run_loop; base::RunLoop run_loop;
cr_fuchsia::ResultReceiver<fuchsia::web::NavigationState> result( cr_fuchsia::ResultReceiver<
run_loop.QuitClosure()); fuchsia::web::Context_GetRemoteDebuggingPort_Result>
nav_controller->GetVisibleEntry( port_receiver(run_loop.QuitClosure());
cr_fuchsia::CallbackToFitFunction(result.GetReceiveCallback())); web_context->GetRemoteDebuggingPort(
cr_fuchsia::CallbackToFitFunction(port_receiver.GetReceiveCallback()));
run_loop.Run(); run_loop.Run();
// Sanity check, the NavigationState should be empty at this point. // Sanity check.
ASSERT_TRUE(result->IsEmpty()); ASSERT_TRUE(port_receiver->is_err());
} ASSERT_EQ(port_receiver->err(),
fuchsia::web::ContextError::REMOTE_DEBUGGING_PORT_NOT_OPENED);
base::Value GetDevToolsListFromPort(uint16_t port) {
std::string url = base::StringPrintf("http://127.0.0.1:%d/json/list", port);
std::unique_ptr<net::URLFetcher> fetcher = net::URLFetcher::Create(
GURL(url), net::URLFetcher::GET, this, TRAFFIC_ANNOTATION_FOR_TESTS);
fetcher->SetRequestContext(request_context_getter_.get());
fetcher->Start();
base::RunLoop run_loop;
on_url_fetch_complete_ack_ = run_loop.QuitClosure();
run_loop.Run();
if (fetcher->GetStatus().status() != net::URLRequestStatus::SUCCESS)
return base::Value();
if (fetcher->GetResponseCode() != net::HTTP_OK)
return base::Value();
std::string result;
if (!fetcher->GetResponseAsString(&result))
return base::Value();
return base::JSONReader::Read(result).value_or(base::Value());
}
// fuchsia::web::URLFetcherDelegate implementation.
void OnURLFetchComplete(const net::URLFetcher* source) override {
if (on_url_fetch_complete_ack_)
std::move(on_url_fetch_complete_ack_).Run();
} }
base::MessageLoopForIO message_loop_; base::MessageLoopForIO message_loop_;
...@@ -146,7 +101,6 @@ class WebEngineDebugIntegrationTest : public testing::Test, ...@@ -146,7 +101,6 @@ class WebEngineDebugIntegrationTest : public testing::Test,
fuchsia::web::ContextProviderPtr web_context_provider_; fuchsia::web::ContextProviderPtr web_context_provider_;
fuchsia::web::DebugSyncPtr debug_; fuchsia::web::DebugSyncPtr debug_;
scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
base::OnceClosure on_url_fetch_complete_ack_; base::OnceClosure on_url_fetch_complete_ack_;
net::EmbeddedTestServer test_server_; net::EmbeddedTestServer test_server_;
...@@ -280,4 +234,4 @@ TEST_F(WebEngineDebugIntegrationTest, MultipleDebugClients) { ...@@ -280,4 +234,4 @@ TEST_F(WebEngineDebugIntegrationTest, MultipleDebugClients) {
frame_data2.context.Unbind(); frame_data2.context.Unbind();
dev_tools_listener_.RunUntilNumberOfPortsIs(0); dev_tools_listener_.RunUntilNumberOfPortsIs(0);
dev_tools_listener2.RunUntilNumberOfPortsIs(0); dev_tools_listener2.RunUntilNumberOfPortsIs(0);
} }
\ No newline at end of file
...@@ -6,11 +6,15 @@ ...@@ -6,11 +6,15 @@
#include <lib/fidl/cpp/binding.h> #include <lib/fidl/cpp/binding.h>
#include "base/fuchsia/file_utils.h" #include "base/fuchsia/file_utils.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/service_directory_client.h" #include "base/fuchsia/service_directory_client.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "fuchsia/base/fit_adapter.h"
#include "fuchsia/base/frame_test_util.h" #include "fuchsia/base/frame_test_util.h"
#include "fuchsia/base/result_receiver.h"
#include "fuchsia/base/test_navigation_listener.h" #include "fuchsia/base/test_navigation_listener.h"
#include "fuchsia/engine/test_devtools_list_fetcher.h"
#include "net/http/http_request_headers.h" #include "net/http/http_request_headers.h"
#include "net/test/embedded_test_server/default_handlers.h" #include "net/test/embedded_test_server/default_handlers.h"
#include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/embedded_test_server.h"
...@@ -187,3 +191,60 @@ TEST_F(WebEngineIntegrationTest, InvalidUserAgent) { ...@@ -187,3 +191,60 @@ TEST_F(WebEngineIntegrationTest, InvalidUserAgent) {
CreateContextAndExpectError(std::move(create_params), ZX_ERR_INVALID_ARGS); CreateContextAndExpectError(std::move(create_params), ZX_ERR_INVALID_ARGS);
} }
} }
// Check the remote_debugging_port parameter in CreateContextParams properly
// opens the DevTools service in the created Context.
// Check Context.GetRemoteDebuggingPort() API is not blocking.
TEST_F(WebEngineIntegrationTest, RemoteDebuggingPort) {
fuchsia::web::CreateContextParams create_params;
auto directory = base::fuchsia::OpenDirectory(
base::FilePath(base::fuchsia::kServiceDirectoryPath));
ASSERT_TRUE(directory.is_valid());
create_params.set_service_directory(std::move(directory));
create_params.set_remote_debugging_port(0);
// Create Context, Frame and NavigationController.
fuchsia::web::ContextPtr web_context;
web_context_provider_->Create(std::move(create_params),
web_context.NewRequest());
web_context.set_error_handler([](zx_status_t status) { ADD_FAILURE(); });
// Get the remote debugging port early, to ensure this is not blocking.
base::RunLoop run_loop;
cr_fuchsia::ResultReceiver<
fuchsia::web::Context_GetRemoteDebuggingPort_Result>
port_receiver(run_loop.QuitClosure());
web_context->GetRemoteDebuggingPort(
cr_fuchsia::CallbackToFitFunction(port_receiver.GetReceiveCallback()));
run_loop.Run();
ASSERT_TRUE(port_receiver->is_response());
uint16_t remote_debugging_port = port_receiver->response().port;
ASSERT_TRUE(remote_debugging_port != 0);
fuchsia::web::FramePtr web_frame;
web_context->CreateFrame(web_frame.NewRequest());
web_frame.set_error_handler([](zx_status_t status) { ADD_FAILURE(); });
fuchsia::web::NavigationControllerPtr nav_controller;
web_frame->GetNavigationController(nav_controller.NewRequest());
nav_controller.set_error_handler([](zx_status_t status) { ADD_FAILURE(); });
cr_fuchsia::TestNavigationListener navigation_listener;
fidl::Binding<fuchsia::web::NavigationEventListener> listener_binding(
&navigation_listener);
web_frame->SetNavigationEventListener(listener_binding.NewBinding());
GURL url = embedded_test_server_.GetURL("/defaultresponse");
ASSERT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse(
nav_controller.get(), fuchsia::web::LoadUrlParams(), url.spec()));
navigation_listener.RunUntilUrlEquals(url);
base::Value devtools_list = GetDevToolsListFromPort(remote_debugging_port);
ASSERT_TRUE(devtools_list.is_list());
EXPECT_EQ(devtools_list.GetList().size(), 1u);
base::Value* devtools_url = devtools_list.GetList()[0].FindPath("url");
ASSERT_TRUE(devtools_url->is_string());
EXPECT_EQ(devtools_url->GetString(), url);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment