Commit 029bd2f8 authored by Pavel Feldman's avatar Pavel Feldman Committed by Commit Bot

DevTools: introduce Page.navigate(frameId).

Change-Id: I8e7854752054f0e4ac1c88fe9b9ec5e9e9547876
Reviewed-on: https://chromium-review.googlesource.com/885422
Commit-Queue: Pavel Feldman <pfeldman@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#532140}
parent 617c1708
......@@ -2119,73 +2119,6 @@ class SitePerProcessDevToolsProtocolTest : public DevToolsProtocolTest {
}
};
IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsProtocolTest, TargetNoDiscovery) {
std::string temp;
std::string target_id;
std::unique_ptr<base::DictionaryValue> command_params;
std::unique_ptr<base::DictionaryValue> params;
GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
NavigateToURLBlockUntilNavigationsComplete(shell(), main_url, 1);
// It is safe to obtain the root frame tree node here, as it doesn't change.
FrameTreeNode* root =
static_cast<WebContentsImpl*>(shell()->web_contents())->
GetFrameTree()->root();
// Load cross-site page into iframe.
GURL::Replacements replace_host;
GURL cross_site_url(embedded_test_server()->GetURL("/title1.html"));
replace_host.SetHostStr("foo.com");
cross_site_url = cross_site_url.ReplaceComponents(replace_host);
NavigateFrameToURL(root->child_at(0), cross_site_url);
// Enable auto-attach.
Attach();
command_params.reset(new base::DictionaryValue());
command_params->SetBoolean("autoAttach", true);
command_params->SetBoolean("waitForDebuggerOnStart", false);
SendCommand("Target.setAutoAttach", std::move(command_params), true);
EXPECT_TRUE(notifications_.empty());
command_params.reset(new base::DictionaryValue());
command_params->SetBoolean("value", true);
SendCommand("Target.setAttachToFrames", std::move(command_params), false);
params = WaitForNotification("Target.attachedToTarget", true);
std::string session_id;
EXPECT_TRUE(params->GetString("sessionId", &session_id));
EXPECT_TRUE(params->GetString("targetInfo.targetId", &target_id));
EXPECT_TRUE(params->GetString("targetInfo.type", &temp));
EXPECT_EQ("iframe", temp);
// Load same-site page into iframe.
FrameTreeNode* child = root->child_at(0);
GURL http_url(embedded_test_server()->GetURL("/title1.html"));
NavigateFrameToURL(child, http_url);
params = WaitForNotification("Target.detachedFromTarget", true);
EXPECT_TRUE(params->GetString("targetId", &temp));
EXPECT_EQ(target_id, temp);
EXPECT_TRUE(params->GetString("sessionId", &temp));
EXPECT_EQ(session_id, temp);
// Navigate back to cross-site iframe.
NavigateFrameToURL(root->child_at(0), cross_site_url);
params = WaitForNotification("Target.attachedToTarget", true);
EXPECT_TRUE(params->GetString("sessionId", &session_id));
EXPECT_TRUE(params->GetString("targetInfo.targetId", &target_id));
EXPECT_TRUE(params->GetString("targetInfo.type", &temp));
EXPECT_EQ("iframe", temp);
// Disable auto-attach.
command_params.reset(new base::DictionaryValue());
command_params->SetBoolean("autoAttach", false);
command_params->SetBoolean("waitForDebuggerOnStart", false);
SendCommand("Target.setAutoAttach", std::move(command_params), false);
params = WaitForNotification("Target.detachedFromTarget", true);
EXPECT_TRUE(params->GetString("targetId", &temp));
EXPECT_EQ(target_id, temp);
EXPECT_TRUE(params->GetString("sessionId", &temp));
EXPECT_EQ(session_id, temp);
}
IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SetAndGetCookies) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL test_url = embedded_test_server()->GetURL("/title1.html");
......
......@@ -27,6 +27,7 @@
#include "content/browser/devtools/protocol/devtools_download_manager_helper.h"
#include "content/browser/devtools/protocol/emulation_handler.h"
#include "content/browser/frame_host/navigation_request.h"
#include "content/browser/frame_host/navigator.h"
#include "content/browser/manifest/manifest_manager_host.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
......@@ -286,6 +287,7 @@ Response PageHandler::Disable() {
}
download_manager_delegate_ = nullptr;
navigate_callbacks_.clear();
return Response::FallThrough();
}
......@@ -323,6 +325,7 @@ Response PageHandler::Reload(Maybe<bool> bypassCache,
void PageHandler::Navigate(const std::string& url,
Maybe<std::string> referrer,
Maybe<std::string> maybe_transition_type,
Maybe<std::string> frame_id,
std::unique_ptr<NavigateCallback> callback) {
GURL gurl(url);
if (!gurl.is_valid()) {
......@@ -330,8 +333,7 @@ void PageHandler::Navigate(const std::string& url,
return;
}
WebContentsImpl* web_contents = GetWebContents();
if (!web_contents) {
if (!host_) {
callback->sendFailure(Response::InternalError());
return;
}
......@@ -364,43 +366,64 @@ void PageHandler::Navigate(const std::string& url,
else
type = ui::PAGE_TRANSITION_TYPED;
web_contents->GetController().LoadURL(
gurl,
Referrer(GURL(referrer.fromMaybe("")), blink::kWebReferrerPolicyDefault),
type, std::string());
std::string frame_id =
web_contents->GetMainFrame()->GetDevToolsFrameToken().ToString();
if (navigate_callback_) {
FrameTreeNode* frame_tree_node = nullptr;
std::string out_frame_id = frame_id.fromMaybe(
host_->frame_tree_node()->devtools_frame_token().ToString());
FrameTreeNode* root = host_->frame_tree_node();
if (root->devtools_frame_token().ToString() == out_frame_id) {
frame_tree_node = root;
} else {
for (FrameTreeNode* node : root->frame_tree()->SubtreeNodes(root)) {
if (node->devtools_frame_token().ToString() == out_frame_id) {
frame_tree_node = node;
break;
}
}
}
if (!frame_tree_node) {
callback->sendFailure(Response::Error("No frame with given id found"));
return;
}
NavigationController::LoadURLParams params(gurl);
params.referrer =
Referrer(GURL(referrer.fromMaybe("")), blink::kWebReferrerPolicyDefault);
params.transition_type = type;
params.frame_tree_node_id = frame_tree_node->frame_tree_node_id();
frame_tree_node->navigator()->GetController()->LoadURLWithParams(params);
base::UnguessableToken frame_token = frame_tree_node->devtools_frame_token();
auto navigate_callback = navigate_callbacks_.find(frame_token);
if (navigate_callback != navigate_callbacks_.end()) {
std::string error_string = net::ErrorToString(net::ERR_ABORTED);
navigate_callback_->sendSuccess(frame_id, Maybe<std::string>(),
Maybe<std::string>(error_string));
navigate_callback->second->sendSuccess(out_frame_id, Maybe<std::string>(),
Maybe<std::string>(error_string));
}
if (frame_tree_node->navigation_request()) {
navigate_callbacks_[frame_token] = std::move(callback);
} else {
callback->sendSuccess(out_frame_id, Maybe<std::string>(),
Maybe<std::string>());
}
if (web_contents->GetMainFrame()->frame_tree_node()->navigation_request())
navigate_callback_ = std::move(callback);
else
callback->sendSuccess(frame_id, Maybe<std::string>(), Maybe<std::string>());
}
void PageHandler::NavigationReset(NavigationRequest* navigation_request) {
if (!navigate_callback_)
auto navigate_callback = navigate_callbacks_.find(
navigation_request->frame_tree_node()->devtools_frame_token());
if (navigate_callback == navigate_callbacks_.end())
return;
WebContentsImpl* web_contents = GetWebContents();
if (!web_contents) {
navigate_callback_->sendFailure(Response::InternalError());
return;
}
std::string frame_id =
web_contents->GetMainFrame()->GetDevToolsFrameToken().ToString();
navigation_request->frame_tree_node()->devtools_frame_token().ToString();
bool success = navigation_request->net_error() != net::OK;
std::string error_string =
net::ErrorToString(navigation_request->net_error());
navigate_callback_->sendSuccess(
navigate_callback->second->sendSuccess(
frame_id,
Maybe<std::string>(
navigation_request->devtools_navigation_token().ToString()),
success ? Maybe<std::string>(error_string) : Maybe<std::string>());
navigate_callback_.reset();
navigate_callbacks_.erase(navigate_callback);
}
static const char* TransitionTypeName(ui::PageTransition type) {
......
......@@ -30,6 +30,10 @@
class SkBitmap;
namespace base {
class UnguessableToken;
}
namespace gfx {
class Image;
} // namespace gfx
......@@ -90,6 +94,7 @@ class PageHandler : public DevToolsDomainHandler,
void Navigate(const std::string& url,
Maybe<std::string> referrer,
Maybe<std::string> transition_type,
Maybe<std::string> frame_id,
std::unique_ptr<NavigateCallback> callback) override;
Response StopLoading() override;
......@@ -194,7 +199,8 @@ class PageHandler : public DevToolsDomainHandler,
NotificationRegistrar registrar_;
JavaScriptDialogCallback pending_dialog_;
scoped_refptr<DevToolsDownloadManagerDelegate> download_manager_delegate_;
std::unique_ptr<NavigateCallback> navigate_callback_;
base::flat_map<base::UnguessableToken, std::unique_ptr<NavigateCallback>>
navigate_callbacks_;
base::WeakPtrFactory<PageHandler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PageHandler);
......
......@@ -170,16 +170,26 @@ void RenderFrameDevToolsAgentHost::AddAllAgentHosts(
// static
void RenderFrameDevToolsAgentHost::OnResetNavigationRequest(
NavigationRequest* navigation_request) {
RenderFrameDevToolsAgentHost* agent_host =
FindAgentHost(navigation_request->frame_tree_node());
if (!agent_host)
return;
// Communicate network error to own agent host only.
if (navigation_request->net_error() != net::OK) {
for (auto* network : protocol::NetworkHandler::ForAgentHost(agent_host))
network->NavigationFailed(navigation_request);
RenderFrameDevToolsAgentHost* agent_host =
FindAgentHost(navigation_request->frame_tree_node());
if (agent_host) {
for (auto* network : protocol::NetworkHandler::ForAgentHost(agent_host))
network->NavigationFailed(navigation_request);
}
}
// Traverse frame chain all the way to the top and report to all
// page handlers that the navigation completed.
for (FrameTreeNode* node = navigation_request->frame_tree_node(); node;
node = node->parent()) {
RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(node);
if (!agent_host)
continue;
for (auto* page : protocol::PageHandler::ForAgentHost(agent_host))
page->NavigationReset(navigation_request);
}
for (auto* page : protocol::PageHandler::ForAgentHost(agent_host))
page->NavigationReset(navigation_request);
}
// static
......
<html>
<title>site_per_process_main</title>
<head></head>
<body>
<iframe id="test"></iframe>
<iframe id="child-2" src="http://devtools.oopif.test:8000/inspector-protocol/resources/iframe.html"></iframe>
</body>
</html>
Tests oopif discovery.
Enabling auto-discovery...
Got auto-attached.
Navigating to in-process iframe...
Session id should match: true
Target id should match: true
Navigating back to out-of-process iframe...
Target ids should match: true
Session id should match: true
Target id should match: true
(async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank(`Tests oopif discovery.`);
await dp.Page.enable();
dp.Page.navigate({url: testRunner.url('../resources/site_per_process_main.html')});
await dp.Page.onceLoadEventFired();
testRunner.log('Enabling auto-discovery...');
await dp.Target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: false});
dp.Target.setAttachToFrames({value: true});
let attachedEvent = (await dp.Target.onceAttachedToTarget()).params;
testRunner.log('Got auto-attached.');
let frameId = attachedEvent.targetInfo.targetId;
testRunner.log('Navigating to in-process iframe...');
let navigatePromise = dp.Page.navigate({frameId, url: testRunner.url('../resources/iframe.html')});
let detachedPromise = dp.Target.onceDetachedFromTarget();
await Promise.all([navigatePromise, detachedPromise]);
let detachedEvent = (await detachedPromise).params;
testRunner.log('Session id should match: ' + (attachedEvent.sessionId === detachedEvent.sessionId));
testRunner.log('Target id should match: ' + (attachedEvent.targetInfo.targetId === detachedEvent.targetId));
testRunner.log('Navigating back to out-of-process iframe...');
dp.Page.navigate({frameId, url: 'http://devtools.oopif.test:8000/inspector-protocol/resources/iframe.html'});
let attachedEvent2 = (await dp.Target.onceAttachedToTarget()).params;
testRunner.log('Target ids should match: ' + (attachedEvent.targetInfo.targetId === attachedEvent2.targetInfo.targetId));
dp.Target.setAutoAttach({autoAttach: false, waitForDebuggerOnStart: false});
let detachedEvent2 = (await dp.Target.onceDetachedFromTarget()).params;
testRunner.log('Session id should match: ' + (attachedEvent2.sessionId === detachedEvent2.sessionId));
testRunner.log('Target id should match: ' + (attachedEvent2.targetInfo.targetId === detachedEvent2.targetId));
testRunner.completeTest();
})
......@@ -9992,6 +9992,12 @@
"description": "Intended transition type.",
"optional": true,
"$ref": "TransitionType"
},
{
"name": "frameId",
"description": "Frame id to navigate, if not specified navigates the top frame.",
"optional": true,
"$ref": "FrameId"
}
],
"returns": [
......
......@@ -4569,6 +4569,8 @@ domain Page
optional string referrer
# Intended transition type.
optional TransitionType transitionType
# Frame id to navigate, if not specified navigates the top frame.
optional FrameId frameId
returns
# Frame id that has navigated (or failed to navigate)
FrameId frameId
......
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