Commit ada1e2d7 authored by alexclarke's avatar alexclarke Committed by Commit bot

Pipe the devTools FrameId from blink into the browser for headless

Headless chrome needs this information because we wish to know
which frames resources came from.

BUG=715541
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_site_isolation

Review-Url: https://codereview.chromium.org/2830753004
Cr-Commit-Position: refs/heads/master@{#468932}
parent e43e4863
......@@ -21,7 +21,9 @@
#include "content/browser/devtools/service_worker_devtools_manager.h"
#include "content/browser/devtools/shared_worker_devtools_agent_host.h"
#include "content/browser/devtools/shared_worker_devtools_manager.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/loader/netlog_observer.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
......@@ -57,6 +59,24 @@ bool DevToolsAgentHost::IsSupportedProtocolVersion(const std::string& version) {
return version == "1.0" || version == "1.1" || version == "1.2";
}
// static
std::string DevToolsAgentHost::GetUntrustedDevToolsFrameIdForFrameTreeNodeId(
int process_id,
int frame_tree_node_id) {
FrameTreeNode* frame_tree_node =
FrameTreeNode::GloballyFindByID(frame_tree_node_id);
if (!frame_tree_node)
return "";
// Make sure |process_id| hasn't changed.
RenderFrameHostImpl* render_frame_host_impl =
frame_tree_node->current_frame_host();
if (!render_frame_host_impl ||
render_frame_host_impl->GetProcess()->GetID() != process_id) {
return "";
}
return render_frame_host_impl->untrusted_devtools_frame_id();
}
// static
DevToolsAgentHost::List DevToolsAgentHost::GetOrCreateAll() {
List result;
......
......@@ -841,6 +841,7 @@ bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) {
IPC_MESSAGE_HANDLER(FrameHostMsg_FocusedNodeChanged, OnFocusedNodeChanged)
IPC_MESSAGE_HANDLER(FrameHostMsg_SetHasReceivedUserGesture,
OnSetHasReceivedUserGesture)
IPC_MESSAGE_HANDLER(FrameHostMsg_SetDevToolsFrameId, OnSetDevToolsFrameId)
#if BUILDFLAG(USE_EXTERNAL_POPUP_MENU)
IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
IPC_MESSAGE_HANDLER(FrameHostMsg_HidePopup, OnHidePopup)
......@@ -2467,6 +2468,11 @@ void RenderFrameHostImpl::OnSetHasReceivedUserGesture() {
frame_tree_node_->OnSetHasReceivedUserGesture();
}
void RenderFrameHostImpl::OnSetDevToolsFrameId(
const std::string& devtools_frame_id) {
untrusted_devtools_frame_id_ = devtools_frame_id;
}
#if BUILDFLAG(USE_EXTERNAL_POPUP_MENU)
void RenderFrameHostImpl::OnShowPopup(
const FrameHostMsg_ShowPopup_Params& params) {
......
......@@ -617,6 +617,13 @@ class CONTENT_EXPORT RenderFrameHostImpl
return has_focused_editable_element_;
}
// This value is sent from the renderer and shouldn't be trusted.
// TODO(alexclarke): Remove once there is a solution for stable frame IDs. See
// crbug.com/715541
const std::string& untrusted_devtools_frame_id() const {
return untrusted_devtools_frame_id_;
}
// Cancels any blocked request for the frame and its subframes.
void CancelBlockedRequestsForFrame();
......@@ -782,6 +789,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
void OnFocusedNodeChanged(bool is_editable_element,
const gfx::Rect& bounds_in_frame_widget);
void OnSetHasReceivedUserGesture();
void OnSetDevToolsFrameId(const std::string& devtools_frame_id);
#if BUILDFLAG(USE_EXTERNAL_POPUP_MENU)
void OnShowPopup(const FrameHostMsg_ShowPopup_Params& params);
......@@ -1203,6 +1211,11 @@ class CONTENT_EXPORT RenderFrameHostImpl
// have created one yet.
base::Optional<base::UnguessableToken> overlay_routing_token_;
// This value is sent from the renderer and shouldn't be trusted.
// TODO(alexclarke): Remove once there is a solution for stable frame IDs. See
// crbug.com/715541
std::string untrusted_devtools_frame_id_;
// NOTE: This must be the last member.
base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_;
......
......@@ -1430,6 +1430,10 @@ IPC_MESSAGE_ROUTED1(FrameHostMsg_VisibilityChanged, bool /* visible */)
// propagated to any remote frames.
IPC_MESSAGE_ROUTED0(FrameHostMsg_SetHasReceivedUserGesture)
// Used to tell the browser what the DevTools FrameId is. Needed by Headless
// Chrome.
IPC_MESSAGE_ROUTED1(FrameHostMsg_SetDevToolsFrameId, std::string)
// Used to tell the parent that the user right clicked on an area of the
// content area, and a context menu should be shown for it. The params
// object contains information about the node(s) that were selected when the
......
......@@ -52,6 +52,15 @@ class CONTENT_EXPORT DevToolsAgentHost
// Returns whether particular version of DevTools protocol is supported.
static bool IsSupportedProtocolVersion(const std::string& version);
// Returns the DevTools FrameId for the given pair of |process_id| and
// |frame_tree_node_id|. This is sent by the renderer and shouldn't be fully
// trusted.
// TODO(alexclarke): Remove once there is a solution for stable frame IDs. See
// crbug.com/715541
static std::string GetUntrustedDevToolsFrameIdForFrameTreeNodeId(
int process_id,
int frame_tree_node_id);
// Returns DevToolsAgentHost with a given |id| or nullptr of it doesn't exist.
static scoped_refptr<DevToolsAgentHost> GetForId(const std::string& id);
......
......@@ -3362,6 +3362,12 @@ void RenderFrameImpl::SetHasReceivedUserGesture() {
Send(new FrameHostMsg_SetHasReceivedUserGesture(routing_id_));
}
void RenderFrameImpl::SetDevToolsFrameId(
const blink::WebString& devtools_frame_id) {
Send(new FrameHostMsg_SetDevToolsFrameId(routing_id_,
devtools_frame_id.Utf8()));
}
bool RenderFrameImpl::ShouldReportDetailedMessageForSource(
const blink::WebString& source) {
return GetContentClient()->renderer()->ShouldReportDetailedMessageForSource(
......
......@@ -553,6 +553,7 @@ class CONTENT_EXPORT RenderFrameImpl
const blink::WebVector<blink::WebString>& stopped_matching_selectors)
override;
void SetHasReceivedUserGesture() override;
void SetDevToolsFrameId(const blink::WebString& devtools_frame_id) override;
bool ShouldReportDetailedMessageForSource(
const blink::WebString& source) override;
void DidAddMessageToConsole(const blink::WebConsoleMessage& message,
......
......@@ -454,6 +454,7 @@ if (is_mac) {
test("headless_browsertests") {
sources = [
"lib/embedder_mojo_browsertest.cc",
"lib/frame_id_browsertest.cc",
"lib/headless_browser_browsertest.cc",
"lib/headless_browser_context_browsertest.cc",
"lib/headless_devtools_client_browsertest.cc",
......
......@@ -146,6 +146,32 @@ HeadlessBrowserContextImpl::GetAllWebContents() {
return result;
}
void HeadlessBrowserContextImpl::SetFrameTreeNodeId(int render_process_id,
int render_frame_routing_id,
int frame_tree_node_id) {
base::AutoLock lock(frame_tree_node_map_lock_);
frame_tree_node_map_[std::make_pair(
render_process_id, render_frame_routing_id)] = frame_tree_node_id;
}
void HeadlessBrowserContextImpl::RemoveFrameTreeNode(
int render_process_id,
int render_frame_routing_id) {
base::AutoLock lock(frame_tree_node_map_lock_);
frame_tree_node_map_.erase(
std::make_pair(render_process_id, render_frame_routing_id));
}
int HeadlessBrowserContextImpl::GetFrameTreeNodeId(int render_process_id,
int render_frame_id) const {
base::AutoLock lock(frame_tree_node_map_lock_);
const auto& find_it = frame_tree_node_map_.find(
std::make_pair(render_process_id, render_frame_id));
if (find_it == frame_tree_node_map_.end())
return -1;
return find_it->second;
}
void HeadlessBrowserContextImpl::Close() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
browser_->DestroyBrowserContext(this);
......
......@@ -45,6 +45,12 @@ class HeadlessBrowserContextImpl : public HeadlessBrowserContext,
void Close() override;
const std::string& Id() const override;
void SetFrameTreeNodeId(int render_process_id,
int render_frame_routing_id,
int frame_tree_node_id);
void RemoveFrameTreeNode(int render_process_id, int render_frame_routing_id);
// BrowserContext implementation:
std::unique_ptr<content::ZoomLevelDelegate> CreateZoomLevelDelegate(
const base::FilePath& partition_path) override;
......@@ -81,6 +87,10 @@ class HeadlessBrowserContextImpl : public HeadlessBrowserContext,
HeadlessBrowserImpl* browser() const;
const HeadlessBrowserContextOptions* options() const;
// Returns the FrameTreeNode id for the corresponding RenderFrameHost or -1
// if it can't be found. Can be called on any thread.
int GetFrameTreeNodeId(int render_process_id, int render_frame_id) const;
private:
HeadlessBrowserContextImpl(
HeadlessBrowserImpl* browser,
......@@ -98,6 +108,13 @@ class HeadlessBrowserContextImpl : public HeadlessBrowserContext,
std::unordered_map<std::string, std::unique_ptr<HeadlessWebContents>>
web_contents_map_;
// Guards |frame_tree_node_map_| from being concurrently written on the UI
// thread and read on the IO thread.
// TODO(alexclarke): Remove if we can add FrameTreeNode ID to
// URLRequestUserData. See https://crbug.com/715541
mutable base::Lock frame_tree_node_map_lock_;
std::map<std::pair<int, int>, int> frame_tree_node_map_;
std::unique_ptr<content::PermissionManager> permission_manager_;
std::string id_;
......
......@@ -216,6 +216,10 @@ void HeadlessWebContentsImpl::RenderFrameCreated(
browser()->BrowserMainThread());
}
browser_context_->SetFrameTreeNodeId(render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID(),
render_frame_host->GetFrameTreeNodeId());
std::string devtools_agent_host_id =
content::DevToolsAgentHost::GetOrCreateFor(render_frame_host)->GetId();
render_frame_host_to_devtools_agent_host_id_[render_frame_host] =
......@@ -226,6 +230,10 @@ void HeadlessWebContentsImpl::RenderFrameCreated(
void HeadlessWebContentsImpl::RenderFrameDeleted(
content::RenderFrameHost* render_frame_host) {
browser_context_->RemoveFrameTreeNode(
render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID());
auto find_it =
render_frame_host_to_devtools_agent_host_id_.find(render_frame_host);
if (find_it == render_frame_host_to_devtools_agent_host_id_.end())
......@@ -246,6 +254,19 @@ bool HeadlessWebContentsImpl::GetFrameTreeNodeIdForDevToolsAgentHostId(
return true;
}
std::string
HeadlessWebContentsImpl::GetUntrustedDevToolsFrameIdForFrameTreeNodeId(
int process_id,
int frame_tree_node_id) const {
return content::DevToolsAgentHost::
GetUntrustedDevToolsFrameIdForFrameTreeNodeId(process_id,
frame_tree_node_id);
}
int HeadlessWebContentsImpl::GetMainFrameRenderProcessId() const {
return web_contents()->GetMainFrame()->GetProcess()->GetID();
}
bool HeadlessWebContentsImpl::OpenURL(const GURL& url) {
if (!url.is_valid())
return false;
......
......@@ -100,6 +100,14 @@ class HEADLESS_EXPORT HeadlessWebContentsImpl
return window_tree_host_.get();
}
// Returns the devtools frame id corresponding to the |frame_tree_node_id|, if
// any. Note this relies on an IPC sent from blink during navigation.
std::string GetUntrustedDevToolsFrameIdForFrameTreeNodeId(
int process_id,
int frame_tree_node_id) const;
int GetMainFrameRenderProcessId() const;
private:
// Takes ownership of |web_contents|.
HeadlessWebContentsImpl(content::WebContents* web_contents,
......@@ -121,6 +129,8 @@ class HEADLESS_EXPORT HeadlessWebContentsImpl
std::unique_ptr<HeadlessTabSocketImpl> headless_tab_socket_;
HeadlessBrowserContextImpl* browser_context_; // Not owned.
// TODO(alexclarke): With OOPIF there may be more than one renderer, we need
// to fix this. See crbug.com/715924
content::RenderProcessHost* render_process_host_; // Not owned.
using ObserverMap =
......
// Copyright 2017 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 "base/bind.h"
#include "base/run_loop.h"
#include "content/public/test/browser_test.h"
#include "headless/lib/browser/headless_browser_context_impl.h"
#include "headless/lib/browser/headless_web_contents_impl.h"
#include "headless/public/devtools/domains/network.h"
#include "headless/public/devtools/domains/page.h"
#include "headless/public/headless_devtools_client.h"
#include "headless/public/util/expedited_dispatcher.h"
#include "headless/public/util/generic_url_request_job.h"
#include "headless/public/util/url_fetcher.h"
#include "headless/test/headless_browser_test.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request_job_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using testing::ContainerEq;
namespace headless {
namespace {
class TestProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
public:
explicit TestProtocolHandler(
scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner)
: test_delegate_(new TestDelegate(this)),
dispatcher_(new ExpeditedDispatcher(io_thread_task_runner)),
headless_browser_context_(nullptr) {}
~TestProtocolHandler() override {}
void SetHeadlessBrowserContext(
HeadlessBrowserContext* headless_browser_context) {
headless_browser_context_ = headless_browser_context;
}
struct Response {
Response() {}
Response(const std::string& body, const std::string& mime_type)
: data("HTTP/1.1 200 OK\r\nContent-Type: " + mime_type + "\r\n\r\n" +
body) {}
std::string data;
};
void InsertResponse(const std::string& url, const Response& response) {
response_map_[url] = response;
}
const Response* GetResponse(const std::string& url) const {
std::map<std::string, Response>::const_iterator find_it =
response_map_.find(url);
if (find_it == response_map_.end())
return nullptr;
return &find_it->second;
}
class MockURLFetcher : public URLFetcher {
public:
explicit MockURLFetcher(const TestProtocolHandler* protocol_handler)
: protocol_handler_(protocol_handler) {}
~MockURLFetcher() override {}
// URLFetcher implementation:
void StartFetch(const GURL& url,
const std::string& method,
const std::string& post_data,
const net::HttpRequestHeaders& request_headers,
ResultListener* result_listener) override {
EXPECT_EQ("GET", method);
const Response* response = protocol_handler_->GetResponse(url.spec());
if (!response)
result_listener->OnFetchStartError(net::ERR_FILE_NOT_FOUND);
result_listener->OnFetchCompleteExtractHeaders(
url, response->data.c_str(), response->data.size());
}
private:
const TestProtocolHandler* protocol_handler_;
DISALLOW_COPY_AND_ASSIGN(MockURLFetcher);
};
class TestDelegate : public GenericURLRequestJob::Delegate {
public:
explicit TestDelegate(TestProtocolHandler* protocol_handler)
: protocol_handler_(protocol_handler) {}
~TestDelegate() override {}
// GenericURLRequestJob::Delegate implementation:
void OnPendingRequest(PendingRequest* pending_request) override {
const Request* request = pending_request->GetRequest();
std::string url = request->GetURLRequest()->url().spec();
int frame_tree_node_id = request->GetFrameTreeNodeId();
DCHECK_NE(frame_tree_node_id, -1);
protocol_handler_->url_to_frame_tree_node_id_[url] = frame_tree_node_id;
pending_request->AllowRequest();
}
void OnResourceLoadFailed(const Request* request,
net::Error error) override {}
void OnResourceLoadComplete(
const Request* request,
const GURL& final_url,
scoped_refptr<net::HttpResponseHeaders> response_headers,
const char* body,
size_t body_size) override {}
private:
TestProtocolHandler* protocol_handler_; // NOT OWNED
scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_;
DISALLOW_COPY_AND_ASSIGN(TestDelegate);
};
// net::URLRequestJobFactory::ProtocolHandler implementation::
net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const override {
return new GenericURLRequestJob(
request, network_delegate, dispatcher_.get(),
base::MakeUnique<MockURLFetcher>(this), test_delegate_.get(),
headless_browser_context_);
}
std::map<std::string, int> url_to_frame_tree_node_id_;
private:
std::unique_ptr<TestDelegate> test_delegate_;
std::unique_ptr<ExpeditedDispatcher> dispatcher_;
std::map<std::string, Response> response_map_;
HeadlessBrowserContext* headless_browser_context_;
DISALLOW_COPY_AND_ASSIGN(TestProtocolHandler);
};
const char* kIndexHtml = R"(
<html>
<head><link rel="stylesheet" type="text/css" href="style1.css"></head>
<body>
<div class="red">Main frame</div>
<iframe src="iframe1.html"></iframe>
<iframe src="iframe2.html"></iframe>
</body>
</html>)";
const char* kIFrame1 = R"(
<html>
<head><link rel="stylesheet" type="text/css" href="style2.css"></head>
<body>
<div class="green">IFrame 1</div>
</body>
</html>)";
const char* kIFrame2 = R"(
<html>
<head><link rel="stylesheet" type="text/css" href="style3.css"></head>
<body>
<div class="blue">IFrame 1</div>
</body>
</html>)";
const char* kStyle1Css = R"(
.red {
color: #f00
} )";
const char* kStyle2Css = R"(
.green {
color: #0f0
} )";
const char* kStyle3Css = R"(
.blue {
color: #00f
} )";
} // namespace
class FrameIdTest : public HeadlessAsyncDevTooledBrowserTest,
public network::Observer,
public page::Observer {
public:
void RunDevTooledTest() override {
http_handler_->SetHeadlessBrowserContext(browser_context_);
EXPECT_TRUE(embedded_test_server()->Start());
devtools_client_->GetNetwork()->AddObserver(this);
devtools_client_->GetNetwork()->Enable();
devtools_client_->GetPage()->AddObserver(this);
base::RunLoop run_loop;
devtools_client_->GetPage()->Enable(run_loop.QuitClosure());
base::MessageLoop::ScopedNestableTaskAllower nest_loop(
base::MessageLoop::current());
run_loop.Run();
devtools_client_->GetPage()->Navigate("http://foo.com/index.html");
}
ProtocolHandlerMap GetProtocolHandlers() override {
ProtocolHandlerMap protocol_handlers;
std::unique_ptr<TestProtocolHandler> http_handler(
new TestProtocolHandler(browser()->BrowserIOThread()));
http_handler_ = http_handler.get();
http_handler_->InsertResponse("http://foo.com/index.html",
{kIndexHtml, "text/html"});
http_handler_->InsertResponse("http://foo.com/iframe1.html",
{kIFrame1, "text/html"});
http_handler_->InsertResponse("http://foo.com/iframe2.html",
{kIFrame2, "text/html"});
http_handler_->InsertResponse("http://foo.com/style1.css",
{kStyle1Css, "text/css"});
http_handler_->InsertResponse("http://foo.com/style2.css",
{kStyle2Css, "text/css"});
http_handler_->InsertResponse("http://foo.com/style3.css",
{kStyle3Css, "text/css"});
protocol_handlers[url::kHttpScheme] = std::move(http_handler);
return protocol_handlers;
}
// network::Observer implementation:
void OnRequestWillBeSent(
const network::RequestWillBeSentParams& params) override {
url_to_frame_id_[params.GetRequest()->GetUrl()] = params.GetFrameId();
}
// page::Observer implementation:
void OnLoadEventFired(const page::LoadEventFiredParams& params) override {
std::map<std::string, std::string> protocol_handler_url_to_frame_id_;
for (const auto& pair : http_handler_->url_to_frame_tree_node_id_) {
HeadlessWebContentsImpl* headless_web_contents_impl =
static_cast<HeadlessWebContentsImpl*>(web_contents_);
// TODO(alexclarke): This will probably break with OOPIF, fix this.
// See https://bugs.chromium.org/p/chromium/issues/detail?id=715924
protocol_handler_url_to_frame_id_[pair.first] =
headless_web_contents_impl
->GetUntrustedDevToolsFrameIdForFrameTreeNodeId(
headless_web_contents_impl->GetMainFrameRenderProcessId(),
pair.second);
}
EXPECT_THAT(url_to_frame_id_, protocol_handler_url_to_frame_id_);
EXPECT_EQ(6u, url_to_frame_id_.size());
FinishAsynchronousTest();
}
private:
std::map<std::string, std::string> url_to_frame_id_;
TestProtocolHandler* http_handler_; // NOT OWNED
};
HEADLESS_ASYNC_DEVTOOLED_TEST_F(FrameIdTest);
} // namespace headless
......@@ -83,8 +83,9 @@ class HEADLESS_EXPORT HeadlessWebContents {
// Returns the headless tab socket for JS -> C++ if one was created.
virtual HeadlessTabSocket* GetHeadlessTabSocket() const = 0;
// Returns the frame tree node id associated with the |devtools_agent_host_id|
// Returns the FrameTreeNode Id associated with the |devtools_agent_host_id|
// if any.
// TODO(alexclarke): Remove this, it doesn't work as expected.
virtual bool GetFrameTreeNodeIdForDevToolsAgentHostId(
const std::string& devtools_agent_host_id,
int* frame_tree_node_id) const = 0;
......
......@@ -12,6 +12,8 @@
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/browser/web_contents.h"
#include "headless/lib/browser/headless_browser_context_impl.h"
#include "headless/public/headless_browser_context.h"
#include "headless/public/util/url_request_dispatcher.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
......@@ -42,13 +44,15 @@ GenericURLRequestJob::GenericURLRequestJob(
net::NetworkDelegate* network_delegate,
URLRequestDispatcher* url_request_dispatcher,
std::unique_ptr<URLFetcher> url_fetcher,
Delegate* delegate)
Delegate* delegate,
HeadlessBrowserContext* headless_browser_context)
: ManagedDispatchURLRequestJob(request,
network_delegate,
url_request_dispatcher),
url_fetcher_(std::move(url_fetcher)),
origin_task_runner_(base::ThreadTaskRunnerHandle::Get()),
delegate_(delegate),
headless_browser_context_(headless_browser_context),
request_resource_info_(
content::ResourceRequestInfo::ForRequest(request_)),
request_id_(next_request_id_++),
......@@ -197,11 +201,18 @@ int GenericURLRequestJob::GetFrameTreeNodeId() const {
// URLRequestUserData will be set for all renderer initiated resource
// requests, but not for browser side navigations.
int render_process_id;
int render_frame_id;
int render_frame_routing_id;
if (content::ResourceRequestInfo::GetRenderFrameForRequest(
request_, &render_process_id, &render_frame_id)) {
request_, &render_process_id, &render_frame_routing_id) &&
render_process_id != -1) {
if (headless_browser_context_) {
return static_cast<HeadlessBrowserContextImpl*>(headless_browser_context_)
->GetFrameTreeNodeId(render_process_id, render_frame_routing_id);
}
// TODO(alexclarke): Remove this.
content::RenderFrameHost* render_frame_host =
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
content::RenderFrameHost::FromID(render_process_id,
render_frame_routing_id);
DCHECK(render_frame_host);
return render_frame_host->GetFrameTreeNodeId();
}
......
......@@ -31,6 +31,7 @@ class ResourceRequestInfo;
namespace headless {
class HeadlessBrowserContext;
class URLRequestDispatcher;
// Wrapper around net::URLRequest with helpers to access select metadata.
......@@ -154,11 +155,14 @@ class HEADLESS_EXPORT GenericURLRequestJob
// NOTE |url_request_dispatcher| and |delegate| must outlive the
// GenericURLRequestJob.
GenericURLRequestJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate,
URLRequestDispatcher* url_request_dispatcher,
std::unique_ptr<URLFetcher> url_fetcher,
Delegate* delegate);
// TODO(alexclarke): Remove the default parameter.
GenericURLRequestJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
URLRequestDispatcher* url_request_dispatcher,
std::unique_ptr<URLFetcher> url_fetcher,
Delegate* delegate,
HeadlessBrowserContext* headless_browser_context = nullptr);
~GenericURLRequestJob() override;
// net::URLRequestJob implementation:
......@@ -212,6 +216,7 @@ class HEADLESS_EXPORT GenericURLRequestJob
scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
std::unique_ptr<MockResponseData> mock_response_;
Delegate* delegate_; // Not owned.
HeadlessBrowserContext* headless_browser_context_; // Not owned.
const content::ResourceRequestInfo* request_resource_info_; // Not owned.
const char* body_ = nullptr; // Not owned.
size_t body_size_ = 0;
......
......@@ -323,6 +323,8 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
virtual void SetHasReceivedUserGesture(bool received_previously) {}
virtual void SetDevToolsFrameId(const String& devtools_frame_id) {}
virtual void AbortClientNavigation() {}
virtual TextCheckerClient& GetTextCheckerClient() const = 0;
......
......@@ -38,6 +38,7 @@
#include "core/dom/Document.h"
#include "core/frame/FrameView.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/LocalFrameClient.h"
#include "core/frame/Settings.h"
#include "core/frame/VisualViewport.h"
#include "core/html/HTMLFrameOwnerElement.h"
......@@ -380,6 +381,11 @@ Response InspectorPageAgent::enable() {
enabled_ = true;
state_->setBoolean(PageAgentState::kPageAgentEnabled, true);
instrumenting_agents_->addInspectorPageAgent(this);
// Tell the browser the ids for all existing frames.
for (LocalFrame* frame : *inspected_frames_) {
frame->Client()->SetDevToolsFrameId(FrameId(frame));
}
return Response::OK();
}
......@@ -674,8 +680,10 @@ void InspectorPageAgent::FrameAttachedToParent(LocalFrame* frame) {
parent_frame = 0;
std::unique_ptr<SourceLocation> location =
SourceLocation::CaptureWithFullStackTrace();
String frame_id = FrameId(frame);
frame->Client()->SetDevToolsFrameId(frame_id);
GetFrontend()->frameAttached(
FrameId(frame), FrameId(ToLocalFrame(parent_frame)),
frame_id, FrameId(ToLocalFrame(parent_frame)),
location ? location->BuildInspectorObject() : nullptr);
}
......
......@@ -988,6 +988,11 @@ void LocalFrameClientImpl::SetHasReceivedUserGesture(bool received_previously) {
autofill_client->UserGestureObserved();
}
void LocalFrameClientImpl::SetDevToolsFrameId(const String& devtools_frame_id) {
if (web_frame_->Client())
web_frame_->Client()->SetDevToolsFrameId(devtools_frame_id);
}
void LocalFrameClientImpl::AbortClientNavigation() {
if (web_frame_->Client())
web_frame_->Client()->AbortClientNavigation();
......
......@@ -218,6 +218,8 @@ class LocalFrameClientImpl final : public LocalFrameClient {
void SetHasReceivedUserGesture(bool received_previously) override;
void SetDevToolsFrameId(const String& devtools_frame_id) override;
void AbortClientNavigation() override;
TextCheckerClient& GetTextCheckerClient() const override;
......
......@@ -270,6 +270,9 @@ class BLINK_EXPORT WebFrameClient {
// Called the first time this frame is the target of a user gesture.
virtual void SetHasReceivedUserGesture() {}
// Notification of the devtools id for this frame.
virtual void SetDevToolsFrameId(const blink::WebString& devtools_frame_id) {}
// Console messages ----------------------------------------------------
// Whether or not we should report a detailed message for the given source.
......
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